|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
/*! AlphabetSearch for DataTables v1.0.0
|
|
|
|
|
/*! AlphabetSearch for DataTables v1.1.0
|
|
|
|
|
* 2014 SpryMedia Ltd - datatables.net/license
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
@ -6,16 +6,17 @@
|
|
|
|
|
* @summary AlphabetSearch
|
|
|
|
|
* @description Show an set of alphabet buttons alongside a table providing
|
|
|
|
|
* search input options
|
|
|
|
|
* @version 1.0.0
|
|
|
|
|
* @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(){
|
|
|
|
|
|
|
|
|
@ -23,7 +24,7 @@
|
|
|
|
|
// Search function
|
|
|
|
|
$.fn.dataTable.Api.register( 'alphabetSearch()', function ( searchTerm ) {
|
|
|
|
|
this.iterator( 'table', function ( context ) {
|
|
|
|
|
context.alphabetSearch = searchTerm;
|
|
|
|
|
context.alphabetSearch.letter = searchTerm;
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
return this;
|
|
|
|
@ -34,7 +35,8 @@ $.fn.dataTable.Api.register( 'alphabetSearch.recalc()', function ( searchTerm )
|
|
|
|
|
this.iterator( 'table', function ( context ) {
|
|
|
|
|
draw(
|
|
|
|
|
new $.fn.dataTable.Api( context ),
|
|
|
|
|
$('div.alphabet', this.table().container())
|
|
|
|
|
$('div.alphabet', this.table().container()),
|
|
|
|
|
context
|
|
|
|
|
);
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
@ -45,18 +47,81 @@ $.fn.dataTable.Api.register( 'alphabetSearch.recalc()', function ( searchTerm )
|
|
|
|
|
// Search plug-in
|
|
|
|
|
$.fn.dataTable.ext.search.push( function ( context, searchData ) {
|
|
|
|
|
// Ensure that there is a search applied to this table before running it
|
|
|
|
|
if ( ! context.alphabetSearch ) {
|
|
|
|
|
if ( ! context.alphabetSearch.letterSearch ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( searchData[0].charAt(0) === context.alphabetSearch ) {
|
|
|
|
|
return true;
|
|
|
|
|
var letter = searchData[context.alphabetSearch.column]
|
|
|
|
|
.toString()
|
|
|
|
|
.replace(/<.*?>/g, '')
|
|
|
|
|
.charAt(0).toUpperCase();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(context.alphabetSearch.letterSearch !== '#'){
|
|
|
|
|
if ( letter === context.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 ( context, 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 !== context.alphabetSearch.column){
|
|
|
|
|
context.alphabetSearch.pass = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var data = this.api().column( col, { order: 'index' } ).data().map( function (value, index) {
|
|
|
|
|
// If sorting by alphabetized column
|
|
|
|
|
return (order_col === context.alphabetSearch.column)
|
|
|
|
|
? (
|
|
|
|
|
// If first pass
|
|
|
|
|
( !context.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 === context.alphabetSearch.column){
|
|
|
|
|
// If pass is not defined, set it to 0
|
|
|
|
|
if(!context.alphabetSearchPass){ context.alphabetSearch.pass = 0; }
|
|
|
|
|
// Increment pass counter and reset it to 0 if it's a second pass
|
|
|
|
|
context.alphabetSearch.pass = (context.alphabetSearch.pass + 1) % 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Private support methods
|
|
|
|
|
function bin ( data ) {
|
|
|
|
|
var letter, bins = {};
|
|
|
|
@ -67,6 +132,8 @@ function bin ( data ) {
|
|
|
|
|
.replace(/<.*?>/g, '')
|
|
|
|
|
.charAt(0).toUpperCase();
|
|
|
|
|
|
|
|
|
|
if(/\d/.test(letter)){ letter = '#'; }
|
|
|
|
|
|
|
|
|
|
if ( bins[letter] ) {
|
|
|
|
|
bins[letter]++;
|
|
|
|
|
}
|
|
|
|
@ -78,33 +145,67 @@ function bin ( data ) {
|
|
|
|
|
return bins;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function draw ( table, alphabet )
|
|
|
|
|
function draw ( table, alphabet, context )
|
|
|
|
|
{
|
|
|
|
|
alphabet.empty();
|
|
|
|
|
alphabet.append( 'Search: ' );
|
|
|
|
|
alphabet.append( context.oLanguage.alphabetSearch.infoDisplay + ': ' );
|
|
|
|
|
|
|
|
|
|
var columnData = table.column(0).data();
|
|
|
|
|
var columnData = table.column(context.alphabetSearch.column, { search: 'applied' } ).data();
|
|
|
|
|
var bins = bin( columnData );
|
|
|
|
|
|
|
|
|
|
$('<span class="clear active"/>')
|
|
|
|
|
$('<span class="alphabet-clear' + ((!context.alphabetSearch.letter) ? ' active' : '') + '"/>')
|
|
|
|
|
.data( 'letter', '' )
|
|
|
|
|
.data( 'match-count', columnData.length )
|
|
|
|
|
.html( 'None' )
|
|
|
|
|
.html( context.oLanguage.alphabetSearch.infoAll )
|
|
|
|
|
.appendTo( alphabet );
|
|
|
|
|
|
|
|
|
|
for ( var i=0 ; i<26 ; i++ ) {
|
|
|
|
|
var letter = String.fromCharCode( 65 + i );
|
|
|
|
|
for ( var i=0 ; i<context.oLanguage.alphabetSearch.alphabet.length ; i++ ) {
|
|
|
|
|
var letter = context.oLanguage.alphabetSearch.alphabet[i];
|
|
|
|
|
|
|
|
|
|
$('<span/>')
|
|
|
|
|
.data( 'letter', letter )
|
|
|
|
|
.data( 'match-count', bins[letter] || 0 )
|
|
|
|
|
.addClass( ! bins[letter] ? 'empty' : '' )
|
|
|
|
|
.html( letter )
|
|
|
|
|
.addClass(
|
|
|
|
|
(! bins[letter] ? 'empty' : '')
|
|
|
|
|
+ ((context.alphabetSearch.letter === letter) ? ' active' : '')
|
|
|
|
|
)
|
|
|
|
|
.html(
|
|
|
|
|
(letter === '#') ? '0-9' : letter
|
|
|
|
|
)
|
|
|
|
|
.appendTo( alphabet );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$('<div class="alphabetInfo"></div>')
|
|
|
|
|
$('<div class="alphabet_info"></div>')
|
|
|
|
|
.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(context.alphabetSearch.letter){
|
|
|
|
|
// Apply filtering by letter
|
|
|
|
|
context.alphabetSearch.letterSearch = context.alphabetSearch.letter;
|
|
|
|
|
|
|
|
|
|
// Redraw table
|
|
|
|
|
table.draw();
|
|
|
|
|
|
|
|
|
|
// Remove filtering by letter
|
|
|
|
|
context.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, context) {
|
|
|
|
|
var api = new $.fn.dataTable.Api( context );
|
|
|
|
|
|
|
|
|
|
// Redraw alphabet panel
|
|
|
|
|
api.alphabetSearch.recalc();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -112,7 +213,76 @@ $.fn.dataTable.AlphabetSearch = function ( context ) {
|
|
|
|
|
var table = new $.fn.dataTable.Api( context );
|
|
|
|
|
var alphabet = $('<div class="alphabet"/>');
|
|
|
|
|
|
|
|
|
|
draw( table, alphabet );
|
|
|
|
|
// Language
|
|
|
|
|
context.oLanguage.alphabetSearch =
|
|
|
|
|
$.extend(
|
|
|
|
|
{
|
|
|
|
|
'alphabet': '#ABCDEFGHIJKLMNOPQRSTUVXYZ',
|
|
|
|
|
'infoDisplay': 'Display',
|
|
|
|
|
'infoAll': 'All'
|
|
|
|
|
},
|
|
|
|
|
((context.oLanguage.alphabetSearch)
|
|
|
|
|
? context.oLanguage.alphabetSearch
|
|
|
|
|
: {}
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
// Convert alphabet to uppercase
|
|
|
|
|
context.oLanguage.alphabetSearch.alphabet.toUpperCase();
|
|
|
|
|
|
|
|
|
|
context.alphabetSearch =
|
|
|
|
|
$.extend(
|
|
|
|
|
{
|
|
|
|
|
column: 0
|
|
|
|
|
},
|
|
|
|
|
$.isPlainObject(context.oInit.alphabetSearch) ? context.oInit.alphabetSearch : {},
|
|
|
|
|
{
|
|
|
|
|
letter: '',
|
|
|
|
|
letterSearch: '',
|
|
|
|
|
pass: 0
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Set required "orderDataType" ("sSortDataType") for a column
|
|
|
|
|
if(context.alphabetSearch.column >= 0 && context.alphabetSearch.column < context.aoColumns.length){
|
|
|
|
|
context.aoColumns[context.alphabetSearch.column].sSortDataType = 'alphabetSearch';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add column containing names to a list of columns
|
|
|
|
|
// where ordering will be always applied to the table
|
|
|
|
|
if( context.hasOwnProperty('aaSortingFixed')
|
|
|
|
|
&& typeof context.aaSortingFixed === 'object' )
|
|
|
|
|
{
|
|
|
|
|
if( $.isArray(context.aaSortingFixed) ){
|
|
|
|
|
if( context.aaSortingFixed.length && !$.isArray( context.aaSortingFixed[0] ) ) {
|
|
|
|
|
// 1D array
|
|
|
|
|
context.aaSortingFixed = [[context.alphabetSearch.column, 'asc'], context.aaSortingFixed];
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// 2D array
|
|
|
|
|
context.aaSortingFixed.unshift([context.alphabetSearch.column, 'asc']);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if( !context.aaSortingFixed.hasOwnProperty('pre') ){
|
|
|
|
|
context.aaSortingFixed.pre = [];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( context.aaSortingFixed.pre.length && !$.isArray( context.aaSortingFixed.pre[0] ) ) {
|
|
|
|
|
// 1D array
|
|
|
|
|
context.aaSortingFixed.pre = [[context.alphabetSearch.column, 'asc'], context.aaSortingFixed.pre];
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// 2D array
|
|
|
|
|
context.aaSortingFixed.pre.unshift([context.alphabetSearch.column, 'asc']);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
context.aaSortingFixed = [context.alphabetSearch.column, 'asc'];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw( table, alphabet, context );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Trigger a search
|
|
|
|
|
alphabet.on( 'click', 'span', function () {
|
|
|
|
@ -128,7 +298,7 @@ $.fn.dataTable.AlphabetSearch = function ( context ) {
|
|
|
|
|
alphabet
|
|
|
|
|
.on( 'mouseenter', 'span', function () {
|
|
|
|
|
alphabet
|
|
|
|
|
.find('div.alphabetInfo')
|
|
|
|
|
.find('div.alphabet_info')
|
|
|
|
|
.css( {
|
|
|
|
|
opacity: 1,
|
|
|
|
|
left: $(this).position().left,
|
|
|
|
@ -138,10 +308,41 @@ $.fn.dataTable.AlphabetSearch = function ( context ) {
|
|
|
|
|
} )
|
|
|
|
|
.on( 'mouseleave', 'span', function () {
|
|
|
|
|
alphabet
|
|
|
|
|
.find('div.alphabetInfo')
|
|
|
|
|
.find('div.alphabet_info')
|
|
|
|
|
.css('opacity', 0);
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
table.on('draw', function (e, context) {
|
|
|
|
|
var api = new $.fn.dataTable.Api( context );
|
|
|
|
|
|
|
|
|
|
// 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(context.alphabetSearch.column, { page: 'current' }).data().each(function (name, index){
|
|
|
|
|
var group = name.charAt(0).toUpperCase();
|
|
|
|
|
|
|
|
|
|
if (group_last !== group) {
|
|
|
|
|
$(rows).eq(index).before(
|
|
|
|
|
'<tr class="alphabet_group"><td colspan="' + col_total + '">' + group + '</td></tr>'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
group_last = group;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// If there are no rows found and letter is selected
|
|
|
|
|
if(!rows.length && context.alphabetSearch){
|
|
|
|
|
var letter = (context.alphabetSearch.letter === '#') ? '0-9' : context.alphabetSearch.letter;
|
|
|
|
|
|
|
|
|
|
$(api.table().body()).prepend(
|
|
|
|
|
'<tr class="alphabet_group"><td colspan="' + col_total + '">' + letter + '</td></tr>'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// API method to get the alphabet container node
|
|
|
|
|
this.node = function () {
|
|
|
|
|
return alphabet;
|
|
|
|
@ -162,4 +363,3 @@ $.fn.dataTable.ext.feature.push( {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}());
|
|
|
|
|
|
|
|
|
|