diff --git a/features/alphabetSearch/dataTables.alphabetSearch.css b/features/alphabetSearch/dataTables.alphabetSearch.css new file mode 100644 index 0000000..eaba740 --- /dev/null +++ b/features/alphabetSearch/dataTables.alphabetSearch.css @@ -0,0 +1,43 @@ +div.alphabet { + position: relative; + display: table; + width: 100%; + margin-bottom: 1em; +} + +div.alphabet span { + display: table-cell; + color: #3174c7; + cursor: pointer; + text-align: center; + width: 3.5%; +} + +div.alphabet span:hover { + text-decoration: underline; +} + +div.alphabet span.active { + color: black; +} + +div.alphabet span.empty { + color: red; +} + +div.alphabet_info { + display: block; + position: absolute; + background-color: #111; + border-radius: 3px; + color: white; + top: 2em; + height: 1.8em; + padding-top: 0.4em; + text-align: center; + z-index: 1; +} + +tr.alphabet_group, tr.alphabet_group:hover { + background-color: rgba(0,0,0,0.15) !important; +} diff --git a/features/alphabetSearch/dataTables.alphabetSearch.js b/features/alphabetSearch/dataTables.alphabetSearch.js new file mode 100644 index 0000000..47eea77 --- /dev/null +++ b/features/alphabetSearch/dataTables.alphabetSearch.js @@ -0,0 +1,365 @@ +/*! AlphabetSearch for DataTables v1.1.0 + * 2014 SpryMedia Ltd - datatables.net/license + */ + +/** + * @summary AlphabetSearch + * @description Show an set of alphabet buttons alongside a table providing + * search input options + * @version 1.1.1 + * @file dataTables.alphabetSearch.js + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * @contact www.sprymedia.co.uk/contact + * @copyright Copyright 2014 SpryMedia Ltd. + * + * License MIT - http://datatables.net/license/mit + * + * For more detailed information please see: + * http://datatables.net/blog/2014-09-22 + * http://www.gyrocode.com/articles/jquery-datatables-alphabetical-search + */ +(function(){ + + +// Search function +$.fn.dataTable.Api.register( 'alphabetSearch()', function ( searchTerm ) { + this.iterator( 'table', function ( settings ) { + settings.alphabetSearch.letter = searchTerm; + } ); + + return this; +} ); + +// Recalculate the alphabet display for updated data +$.fn.dataTable.Api.register( 'alphabetSearch.recalc()', function ( searchTerm ) { + this.iterator( 'table', function ( settings ) { + draw( + new $.fn.dataTable.Api( settings ), + $('div.alphabet', this.table().container()), + settings + ); + } ); + + return this; +} ); + + +// Search plug-in +$.fn.dataTable.ext.search.push( function ( settings, searchData ) { + // Ensure that there is a search applied to this table before running it + if ( ! settings.alphabetSearch.letterSearch ) { + return true; + } + + var letter = searchData[settings.alphabetSearch.column] + .toString() + .replace(/<.*?>/g, '') + .charAt(0).toUpperCase(); + + + if(settings.alphabetSearch.letterSearch !== '#'){ + if ( letter === settings.alphabetSearch.letterSearch ) { + return true; + } + } else { + if(/\d/.test(letter)){ + return true; + } + } + + return false; +} ); + + +// Order plug-in +// +// NOTES: If sorting by alphabetized column +// there would be two calls to this method +$.fn.dataTable.ext.order['alphabetSearch'] = function ( settings, col ) +{ + var order_col = this.api().order()[0][0]; + var order_method = this.api().order()[0][1]; + + // If sorting by column other than the one being alphabetized + if(order_col !== settings.alphabetSearch.column){ + settings.alphabetSearch.pass = 0; + } + + var data = this.api().column( col, { order: 'index' } ).data().map( function (value, index) { + // If sorting by alphabetized column + return (order_col === settings.alphabetSearch.column) + ? ( + // If first pass + ( !settings.alphabetSearch.pass ) + // Ignore + ? + '' + // Otherwise, if it's a second pass + : + ( + // If method is ascending sort + ( order_method === 'asc' ) + // Return first letter + ? value.charAt(0) + : String.fromCharCode(65535 - value.charCodeAt(0)) + ) + ) + // Otherwise, if sorting by column other than the one being alphabetized, + // return first letter + : value.charAt(0); + + } ); + + // If sorting by alphabetized column + if(order_col === settings.alphabetSearch.column){ + // If pass is not defined, set it to 0 + if(!settings.alphabetSearchPass){ settings.alphabetSearch.pass = 0; } + // Increment pass counter and reset it to 0 if it's a second pass + settings.alphabetSearch.pass = (settings.alphabetSearch.pass + 1) % 2; + } + + return data; +}; + + +// Private support methods +function bin ( data ) { + var letter, bins = {}; + + for ( var i=0, ien=data.length ; i/g, '') + .charAt(0).toUpperCase(); + + if(/\d/.test(letter)){ letter = '#'; } + + if ( bins[letter] ) { + bins[letter]++; + } + else { + bins[letter] = 1; + } + } + + return bins; +} + +function draw ( table, alphabet, settings ) +{ + alphabet.empty(); + alphabet.append( settings.oLanguage.alphabetSearch.infoDisplay + ': ' ); + + var columnData = table.column(settings.alphabetSearch.column, { search: 'applied' } ).data(); + var bins = bin( columnData ); + + $('') + .data( 'letter', '' ) + .data( 'match-count', columnData.length ) + .html( settings.oLanguage.alphabetSearch.infoAll ) + .appendTo( alphabet ); + + for ( var i=0 ; i') + .data( 'letter', letter ) + .data( 'match-count', bins[letter] || 0 ) + .addClass( + (! bins[letter] ? 'empty' : '') + + ((settings.alphabetSearch.letter === letter) ? ' active' : '') + ) + .html( + (letter === '#') ? '0-9' : letter + ) + .appendTo( alphabet ); + } + + $('
') + .appendTo( alphabet ); + + + // Perform second rendering + // needed to filter search results by letter + // NOTE: Future optimization is needed to avoid rendering twice + // when no search is performed + + // If letter is selected + if(settings.alphabetSearch.letter){ + // Apply filtering by letter + settings.alphabetSearch.letterSearch = settings.alphabetSearch.letter; + + // Redraw table + table.draw(); + + // Remove filtering by letter + settings.alphabetSearch.letterSearch = ''; + } + + // Handle search event here only once + // when alphabet panel has been drawn + // because we are performing two-step rendering + // that could trigger search hanlder when not needed + table.one('search', function (e, settings) { + var api = new $.fn.dataTable.Api( settings ); + + // Redraw alphabet panel + api.alphabetSearch.recalc(); + }); +} + + +$.fn.dataTable.AlphabetSearch = function ( settings ) { + var table = new $.fn.dataTable.Api( settings ); + var alphabet = $('
'); + + // Language + settings.oLanguage.alphabetSearch = + $.extend( + { + 'alphabet': '#ABCDEFGHIJKLMNOPQRSTUVXYZ', + 'infoDisplay': 'Display', + 'infoAll': 'All' + }, + ((settings.oLanguage.alphabetSearch) + ? settings.oLanguage.alphabetSearch + : {} + ) + ); + // Convert alphabet to uppercase + settings.oLanguage.alphabetSearch.alphabet.toUpperCase(); + + settings.alphabetSearch = + $.extend( + { + column: 0 + }, + $.isPlainObject(settings.oInit.alphabetSearch) ? settings.oInit.alphabetSearch : {}, + { + letter: '', + letterSearch: '', + pass: 0 + } + ); + + // Set required "orderDataType" ("sSortDataType") for a column + if(settings.alphabetSearch.column >= 0 && settings.alphabetSearch.column < settings.aoColumns.length){ + settings.aoColumns[settings.alphabetSearch.column].sSortDataType = 'alphabetSearch'; + } + + // Add column containing names to a list of columns + // where ordering will be always applied to the table + if( settings.hasOwnProperty('aaSortingFixed') + && typeof settings.aaSortingFixed === 'object' ) + { + if( $.isArray(settings.aaSortingFixed) ){ + if( settings.aaSortingFixed.length && !$.isArray( settings.aaSortingFixed[0] ) ) { + // 1D array + settings.aaSortingFixed = [[settings.alphabetSearch.column, 'asc'], settings.aaSortingFixed]; + + } else { + // 2D array + settings.aaSortingFixed.unshift([settings.alphabetSearch.column, 'asc']); + } + } else { + if( !settings.aaSortingFixed.hasOwnProperty('pre') ){ + settings.aaSortingFixed.pre = []; + } + + if( settings.aaSortingFixed.pre.length && !$.isArray( settings.aaSortingFixed.pre[0] ) ) { + // 1D array + settings.aaSortingFixed.pre = [[settings.alphabetSearch.column, 'asc'], settings.aaSortingFixed.pre]; + + } else { + // 2D array + settings.aaSortingFixed.pre.unshift([settings.alphabetSearch.column, 'asc']); + } + } + + } else { + settings.aaSortingFixed = [settings.alphabetSearch.column, 'asc']; + } + + + draw( table, alphabet, settings ); + + + // Trigger a search + alphabet.on( 'click', 'span', function () { + alphabet.find( '.active' ).removeClass( 'active' ); + $(this).addClass( 'active' ); + + table + .alphabetSearch( $(this).data('letter') ) + .draw(); + } ); + + // Mouse events to show helper information + alphabet + .on( 'mouseenter', 'span', function () { + alphabet + .find('div.alphabet_info') + .css( { + opacity: 1, + left: $(this).position().left, + width: $(this).width() + } ) + .html( $(this).data('match-count') ); + } ) + .on( 'mouseleave', 'span', function () { + alphabet + .find('div.alphabet_info') + .css('opacity', 0); + } ); + + table.on('draw', function (e, settings) { + var api = new $.fn.dataTable.Api( settings ); + + // Total number of column nodes + var col_total = api.columns().nodes().length; + + var rows = api.rows({ page: 'current' }).nodes(); + var group_last = null; + + api.column(settings.alphabetSearch.column, { page: 'current' }).data().each(function (name, index){ + var group = name.charAt(0).toUpperCase(); + + if (group_last !== group) { + $(rows).eq(index).before( + '' + group + '' + ); + + group_last = group; + } + }); + + // If there are no rows found and letter is selected + if(!rows.length && settings.alphabetSearch){ + var letter = (settings.alphabetSearch.letter === '#') ? '0-9' : settings.alphabetSearch.letter; + + $(api.table().body()).prepend( + '' + letter + '' + ); + } + }); + + // API method to get the alphabet container node + this.node = function () { + return alphabet; + }; +}; + +$.fn.DataTable.AlphabetSearch = $.fn.dataTable.AlphabetSearch; + + +// Register a search plug-in +$.fn.dataTable.ext.feature.push( { + fnInit: function ( settings ) { + var search = new $.fn.dataTable.AlphabetSearch( settings ); + return search.node(); + }, + cFeature: 'A' +} ); + + +}()); diff --git a/features/alphabetSearch/dataTables.alphabetSearch.min.js b/features/alphabetSearch/dataTables.alphabetSearch.min.js new file mode 100644 index 0000000..d7f945e --- /dev/null +++ b/features/alphabetSearch/dataTables.alphabetSearch.min.js @@ -0,0 +1,4 @@ +/*! AlphabetSearch for DataTables v1.1.0 + * 2014 SpryMedia Ltd - datatables.net/license + */ +(function(){$.fn.dataTable.Api.register("alphabetSearch()",function(searchTerm){this.iterator("table",function(settings){settings.alphabetSearch.letter=searchTerm;});return this;});$.fn.dataTable.Api.register("alphabetSearch.recalc()",function(searchTerm){this.iterator("table",function(settings){draw(new $.fn.dataTable.Api(settings),$("div.alphabet",this.table().container()),settings);});return this;});$.fn.dataTable.ext.search.push(function(settings,searchData){if(!settings.alphabetSearch.letterSearch){return true;}var letter=searchData[settings.alphabetSearch.column].toString().replace(/<.*?>/g,"").charAt(0).toUpperCase();if(settings.alphabetSearch.letterSearch!=="#"){if(letter===settings.alphabetSearch.letterSearch){return true;}}else{if(/\d/.test(letter)){return true;}}return false;});$.fn.dataTable.ext.order["alphabetSearch"]=function(settings,col){var order_col=this.api().order()[0][0];var order_method=this.api().order()[0][1];if(order_col!==settings.alphabetSearch.column){settings.alphabetSearch.pass=0;}var data=this.api().column(col,{order:"index"}).data().map(function(value,index){return(order_col===settings.alphabetSearch.column)?((!settings.alphabetSearch.pass)?"":((order_method==="asc")?value.charAt(0):String.fromCharCode(65535-value.charCodeAt(0)))):value.charAt(0);});if(order_col===settings.alphabetSearch.column){if(!settings.alphabetSearchPass){settings.alphabetSearch.pass=0;}settings.alphabetSearch.pass=(settings.alphabetSearch.pass+1)%2;}return data;};function bin(data){var letter,bins={};for(var i=0,ien=data.length;i/g,"").charAt(0).toUpperCase();if(/\d/.test(letter)){letter="#";}if(bins[letter]){bins[letter]++;}else{bins[letter]=1;}}return bins;}function draw(table,alphabet,settings){alphabet.empty();alphabet.append(settings.oLanguage.alphabetSearch.infoDisplay+": ");var columnData=table.column(settings.alphabetSearch.column,{search:"applied"}).data();var bins=bin(columnData);$('').data("letter","").data("match-count",columnData.length).html(settings.oLanguage.alphabetSearch.infoAll).appendTo(alphabet);for(var i=0;i").data("letter",letter).data("match-count",bins[letter]||0).addClass((!bins[letter]?"empty":"")+((settings.alphabetSearch.letter===letter)?" active":"")).html((letter==="#")?"0-9":letter).appendTo(alphabet);}$('
').appendTo(alphabet);if(settings.alphabetSearch.letter){settings.alphabetSearch.letterSearch=settings.alphabetSearch.letter;table.draw();settings.alphabetSearch.letterSearch="";}table.one("search",function(e,settings){var api=new $.fn.dataTable.Api(settings);api.alphabetSearch.recalc();});}$.fn.dataTable.AlphabetSearch=function(settings){var table=new $.fn.dataTable.Api(settings);var alphabet=$('
');settings.oLanguage.alphabetSearch=$.extend({"alphabet":"#ABCDEFGHIJKLMNOPQRSTUVXYZ","infoDisplay":"Display","infoAll":"All"},((settings.oLanguage.alphabetSearch)?settings.oLanguage.alphabetSearch:{}));settings.oLanguage.alphabetSearch.alphabet.toUpperCase();settings.alphabetSearch=$.extend({column:0},$.isPlainObject(settings.oInit.alphabetSearch)?settings.oInit.alphabetSearch:{},{letter:"",letterSearch:"",pass:0});if(settings.alphabetSearch.column>=0&&settings.alphabetSearch.column'+group+"");group_last=group;}});if(!rows.length&&settings.alphabetSearch){var letter=(settings.alphabetSearch.letter==="#")?"0-9":settings.alphabetSearch.letter;$(api.table().body()).prepend(''+letter+"");}});this.node=function(){return alphabet;};};$.fn.DataTable.AlphabetSearch=$.fn.dataTable.AlphabetSearch;$.fn.dataTable.ext.feature.push({fnInit:function(settings){var search=new $.fn.dataTable.AlphabetSearch(settings);return search.node();},cFeature:"A"});}()); \ No newline at end of file