mirror of
https://github.com/Mottie/tablesorter.git
synced 2024-11-15 23:54:22 +00:00
parent
a79f3417ce
commit
449b985c60
155
dist/js/jquery.tablesorter.combined.js
vendored
155
dist/js/jquery.tablesorter.combined.js
vendored
@ -1,4 +1,4 @@
|
||||
/*! tablesorter (FORK) - updated 06-10-2015 (v2.22.1)*/
|
||||
/*! tablesorter (FORK) - updated 06-12-2015 (v2.22.1)*/
|
||||
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
|
||||
(function(factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
@ -2648,6 +2648,66 @@ ts.filter = {
|
||||
// data.index = column index; table = table element ( DOM )
|
||||
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
|
||||
types: {
|
||||
or : function( c, data, vars ) {
|
||||
if ( /\|/.test( data.iFilter ) || ts.filter.regex.orSplit.test( data.filter ) ) {
|
||||
var indx, filterMatched, txt, query, regex,
|
||||
// duplicate data but split filter
|
||||
data2 = $.extend( {}, data ),
|
||||
index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
filter = data.filter.split( ts.filter.regex.orSplit ),
|
||||
iFilter = data.iFilter.split( ts.filter.regex.orSplit ),
|
||||
len = filter.length;
|
||||
for ( indx = 0; indx < len; indx++ ) {
|
||||
data2.nestedFilters = true;
|
||||
data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
||||
data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
||||
query = '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
|
||||
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
||||
// filterMatched = data2.filter === '' && indx > 0 ? true
|
||||
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
||||
filterMatched = regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars );
|
||||
if ( filterMatched ) {
|
||||
return filterMatched;
|
||||
}
|
||||
}
|
||||
// may be null from processing types
|
||||
return filterMatched || false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for an AND or && operator ( logical and )
|
||||
and : function( c, data, vars ) {
|
||||
if ( ts.filter.regex.andTest.test( data.filter ) ) {
|
||||
var indx, filterMatched, result, txt, query, regex,
|
||||
// duplicate data but split filter
|
||||
data2 = $.extend( {}, data ),
|
||||
index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
filter = data.filter.split( ts.filter.regex.andSplit ),
|
||||
iFilter = data.iFilter.split( ts.filter.regex.andSplit ),
|
||||
len = filter.length;
|
||||
for ( indx = 0; indx < len; indx++ ) {
|
||||
data2.nestedFilters = true;
|
||||
data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
||||
data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
||||
query = ( '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
|
||||
// replace wild cards since /(a*)/i will match anything
|
||||
.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
|
||||
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
||||
// look for an exact match with the 'and' unless the 'filter-match' class is found
|
||||
result = ( regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars ) );
|
||||
if ( indx === 0 ) {
|
||||
filterMatched = result;
|
||||
} else {
|
||||
filterMatched = filterMatched && result;
|
||||
}
|
||||
}
|
||||
// may be null from processing types
|
||||
return filterMatched || false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for regex
|
||||
regex: function( c, data ) {
|
||||
if ( ts.filter.regex.regex.test( data.filter ) ) {
|
||||
@ -2735,23 +2795,6 @@ ts.filter = {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for an AND or && operator ( logical and )
|
||||
and : function( c, data ) {
|
||||
if ( ts.filter.regex.andTest.test( data.filter ) ) {
|
||||
var index = data.index,
|
||||
parsed = data.parsed[index],
|
||||
query = data.iFilter.split( ts.filter.regex.andSplit ),
|
||||
result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0,
|
||||
indx = query.length - 1;
|
||||
while ( result && indx ) {
|
||||
result = result &&
|
||||
data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0;
|
||||
indx--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
|
||||
range : function( c, data ) {
|
||||
if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
|
||||
@ -2788,24 +2831,20 @@ ts.filter = {
|
||||
},
|
||||
// Look for wild card: ? = single, * = multiple, or | = logical OR
|
||||
wild : function( c, data ) {
|
||||
if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) {
|
||||
if ( /[\?\*\|]/.test( data.iFilter ) ) {
|
||||
var index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ),
|
||||
query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
|
||||
query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
|
||||
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
||||
if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) {
|
||||
// show all results while using filter match. Fixes #727
|
||||
if ( query[ query.length - 1 ] === '|' ) {
|
||||
query += '*';
|
||||
}
|
||||
query = data.anyMatch && $.isArray( data.rowArray ) ?
|
||||
'(' + query + ')' :
|
||||
'^(' + query + ')$';
|
||||
if ( !/\?\*/.test( query ) && data.nestedFilters ) {
|
||||
query = data.isMatch ? query : '^(' + query + ')$';
|
||||
}
|
||||
// parsing the filter may not work properly when using wildcards =/
|
||||
return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) )
|
||||
.test( data.iExact );
|
||||
return new RegExp(
|
||||
query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
|
||||
c.widgetOptions.filter_ignoreCase ? 'i' : ''
|
||||
)
|
||||
.test( data.exact );
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@ -2859,7 +2898,7 @@ ts.filter = {
|
||||
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
|
||||
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
|
||||
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
|
||||
orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ),
|
||||
orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
|
||||
iQuery : new RegExp( val, 'i' ),
|
||||
igQuery : new RegExp( val, 'ig' )
|
||||
});
|
||||
@ -3079,7 +3118,6 @@ ts.filter = {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setDefaults: function( table, c, wo ) {
|
||||
var isArray, saved, indx, col, $filters,
|
||||
// get current ( default ) filters
|
||||
@ -3424,8 +3462,22 @@ ts.filter = {
|
||||
}
|
||||
return columns;
|
||||
},
|
||||
processTypes: function( c, data, vars ) {
|
||||
var ffxn,
|
||||
filterMatched = null,
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ffxn]( c, data, vars );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
return filterMatched;
|
||||
},
|
||||
processRow: function( c, data, vars ) {
|
||||
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch,
|
||||
var columnIndex, hasSelect, result, val, filterMatched,
|
||||
fxn, ffxn, txt,
|
||||
regex = ts.filter.regex,
|
||||
wo = c.widgetOptions,
|
||||
@ -3436,6 +3488,7 @@ ts.filter = {
|
||||
// look for multiple columns '1-3,4-6,8'
|
||||
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
|
||||
data.anyMatch = true;
|
||||
data.isMatch = true;
|
||||
data.rowArray = data.$cells.map( function( i ) {
|
||||
if ( $.inArray( i, columnIndex ) > -1 ) {
|
||||
if ( data.parsed[ i ] ) {
|
||||
@ -3455,16 +3508,10 @@ ts.filter = {
|
||||
data.exact = data.rowArray.join( ' ' );
|
||||
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
|
||||
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
|
||||
filterMatched = null;
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ffxn]( c, data );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vars.excludeMatch = vars.noAnyMatch;
|
||||
filterMatched = ts.filter.processTypes( c, data, vars );
|
||||
|
||||
if ( filterMatched !== null ) {
|
||||
showRow = filterMatched;
|
||||
} else {
|
||||
@ -3491,7 +3538,7 @@ ts.filter = {
|
||||
data.index = columnIndex;
|
||||
|
||||
// filter types to exclude, per column
|
||||
excludeMatch = vars.excludeFilter[ columnIndex ];
|
||||
vars.excludeMatch = vars.excludeFilter[ columnIndex ];
|
||||
|
||||
// ignore if filter is empty or disabled
|
||||
if ( data.filter ) {
|
||||
@ -3505,6 +3552,9 @@ ts.filter = {
|
||||
}
|
||||
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
|
||||
data.exact.toLowerCase() : data.exact;
|
||||
|
||||
data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
|
||||
|
||||
result = showRow; // if showRow is true, show that row
|
||||
|
||||
// in case select filter option has a different value vs text 'a - z|A through Z'
|
||||
@ -3529,13 +3579,12 @@ ts.filter = {
|
||||
// data.filter = case sensitive
|
||||
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
|
||||
fxn = vars.functions[ columnIndex ];
|
||||
$cell = c.$headerIndexed[ columnIndex ];
|
||||
hasSelect = $cell.hasClass( 'filter-select' );
|
||||
hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
|
||||
filterMatched = null;
|
||||
if ( fxn || ( hasSelect && val ) ) {
|
||||
if ( fxn === true || hasSelect ) {
|
||||
// default selector uses exact match unless 'filter-match' class is found
|
||||
filterMatched = $cell.hasClass( 'filter-match' ) ?
|
||||
filterMatched = data.isMatch ?
|
||||
data.iExact.search( data.iFilter ) >= 0 :
|
||||
data.filter === data.exact;
|
||||
} else if ( typeof fxn === 'function' ) {
|
||||
@ -3552,15 +3601,7 @@ ts.filter = {
|
||||
if ( filterMatched === null ) {
|
||||
// cycle through the different filters
|
||||
// filters return a boolean or null if nothing matches
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ ffxn ]( c, data );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
filterMatched = ts.filter.processTypes( c, data, vars );
|
||||
if ( filterMatched !== null ) {
|
||||
result = filterMatched;
|
||||
// Look for match, and add child row data for matching
|
||||
|
6
dist/js/jquery.tablesorter.combined.min.js
vendored
6
dist/js/jquery.tablesorter.combined.min.js
vendored
File diff suppressed because one or more lines are too long
155
dist/js/jquery.tablesorter.widgets.js
vendored
155
dist/js/jquery.tablesorter.widgets.js
vendored
@ -1,4 +1,4 @@
|
||||
/*! tablesorter (FORK) - updated 06-10-2015 (v2.22.1)*/
|
||||
/*! tablesorter (FORK) - updated 06-12-2015 (v2.22.1)*/
|
||||
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
|
||||
(function(factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
@ -470,6 +470,66 @@ ts.filter = {
|
||||
// data.index = column index; table = table element ( DOM )
|
||||
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
|
||||
types: {
|
||||
or : function( c, data, vars ) {
|
||||
if ( /\|/.test( data.iFilter ) || ts.filter.regex.orSplit.test( data.filter ) ) {
|
||||
var indx, filterMatched, txt, query, regex,
|
||||
// duplicate data but split filter
|
||||
data2 = $.extend( {}, data ),
|
||||
index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
filter = data.filter.split( ts.filter.regex.orSplit ),
|
||||
iFilter = data.iFilter.split( ts.filter.regex.orSplit ),
|
||||
len = filter.length;
|
||||
for ( indx = 0; indx < len; indx++ ) {
|
||||
data2.nestedFilters = true;
|
||||
data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
||||
data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
||||
query = '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
|
||||
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
||||
// filterMatched = data2.filter === '' && indx > 0 ? true
|
||||
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
||||
filterMatched = regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars );
|
||||
if ( filterMatched ) {
|
||||
return filterMatched;
|
||||
}
|
||||
}
|
||||
// may be null from processing types
|
||||
return filterMatched || false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for an AND or && operator ( logical and )
|
||||
and : function( c, data, vars ) {
|
||||
if ( ts.filter.regex.andTest.test( data.filter ) ) {
|
||||
var indx, filterMatched, result, txt, query, regex,
|
||||
// duplicate data but split filter
|
||||
data2 = $.extend( {}, data ),
|
||||
index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
filter = data.filter.split( ts.filter.regex.andSplit ),
|
||||
iFilter = data.iFilter.split( ts.filter.regex.andSplit ),
|
||||
len = filter.length;
|
||||
for ( indx = 0; indx < len; indx++ ) {
|
||||
data2.nestedFilters = true;
|
||||
data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
||||
data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
||||
query = ( '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
|
||||
// replace wild cards since /(a*)/i will match anything
|
||||
.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
|
||||
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
||||
// look for an exact match with the 'and' unless the 'filter-match' class is found
|
||||
result = ( regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars ) );
|
||||
if ( indx === 0 ) {
|
||||
filterMatched = result;
|
||||
} else {
|
||||
filterMatched = filterMatched && result;
|
||||
}
|
||||
}
|
||||
// may be null from processing types
|
||||
return filterMatched || false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for regex
|
||||
regex: function( c, data ) {
|
||||
if ( ts.filter.regex.regex.test( data.filter ) ) {
|
||||
@ -557,23 +617,6 @@ ts.filter = {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for an AND or && operator ( logical and )
|
||||
and : function( c, data ) {
|
||||
if ( ts.filter.regex.andTest.test( data.filter ) ) {
|
||||
var index = data.index,
|
||||
parsed = data.parsed[index],
|
||||
query = data.iFilter.split( ts.filter.regex.andSplit ),
|
||||
result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0,
|
||||
indx = query.length - 1;
|
||||
while ( result && indx ) {
|
||||
result = result &&
|
||||
data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0;
|
||||
indx--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
|
||||
range : function( c, data ) {
|
||||
if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
|
||||
@ -610,24 +653,20 @@ ts.filter = {
|
||||
},
|
||||
// Look for wild card: ? = single, * = multiple, or | = logical OR
|
||||
wild : function( c, data ) {
|
||||
if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) {
|
||||
if ( /[\?\*\|]/.test( data.iFilter ) ) {
|
||||
var index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ),
|
||||
query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
|
||||
query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
|
||||
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
||||
if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) {
|
||||
// show all results while using filter match. Fixes #727
|
||||
if ( query[ query.length - 1 ] === '|' ) {
|
||||
query += '*';
|
||||
}
|
||||
query = data.anyMatch && $.isArray( data.rowArray ) ?
|
||||
'(' + query + ')' :
|
||||
'^(' + query + ')$';
|
||||
if ( !/\?\*/.test( query ) && data.nestedFilters ) {
|
||||
query = data.isMatch ? query : '^(' + query + ')$';
|
||||
}
|
||||
// parsing the filter may not work properly when using wildcards =/
|
||||
return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) )
|
||||
.test( data.iExact );
|
||||
return new RegExp(
|
||||
query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
|
||||
c.widgetOptions.filter_ignoreCase ? 'i' : ''
|
||||
)
|
||||
.test( data.exact );
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@ -681,7 +720,7 @@ ts.filter = {
|
||||
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
|
||||
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
|
||||
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
|
||||
orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ),
|
||||
orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
|
||||
iQuery : new RegExp( val, 'i' ),
|
||||
igQuery : new RegExp( val, 'ig' )
|
||||
});
|
||||
@ -901,7 +940,6 @@ ts.filter = {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setDefaults: function( table, c, wo ) {
|
||||
var isArray, saved, indx, col, $filters,
|
||||
// get current ( default ) filters
|
||||
@ -1246,8 +1284,22 @@ ts.filter = {
|
||||
}
|
||||
return columns;
|
||||
},
|
||||
processTypes: function( c, data, vars ) {
|
||||
var ffxn,
|
||||
filterMatched = null,
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ffxn]( c, data, vars );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
return filterMatched;
|
||||
},
|
||||
processRow: function( c, data, vars ) {
|
||||
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch,
|
||||
var columnIndex, hasSelect, result, val, filterMatched,
|
||||
fxn, ffxn, txt,
|
||||
regex = ts.filter.regex,
|
||||
wo = c.widgetOptions,
|
||||
@ -1258,6 +1310,7 @@ ts.filter = {
|
||||
// look for multiple columns '1-3,4-6,8'
|
||||
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
|
||||
data.anyMatch = true;
|
||||
data.isMatch = true;
|
||||
data.rowArray = data.$cells.map( function( i ) {
|
||||
if ( $.inArray( i, columnIndex ) > -1 ) {
|
||||
if ( data.parsed[ i ] ) {
|
||||
@ -1277,16 +1330,10 @@ ts.filter = {
|
||||
data.exact = data.rowArray.join( ' ' );
|
||||
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
|
||||
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
|
||||
filterMatched = null;
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ffxn]( c, data );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vars.excludeMatch = vars.noAnyMatch;
|
||||
filterMatched = ts.filter.processTypes( c, data, vars );
|
||||
|
||||
if ( filterMatched !== null ) {
|
||||
showRow = filterMatched;
|
||||
} else {
|
||||
@ -1313,7 +1360,7 @@ ts.filter = {
|
||||
data.index = columnIndex;
|
||||
|
||||
// filter types to exclude, per column
|
||||
excludeMatch = vars.excludeFilter[ columnIndex ];
|
||||
vars.excludeMatch = vars.excludeFilter[ columnIndex ];
|
||||
|
||||
// ignore if filter is empty or disabled
|
||||
if ( data.filter ) {
|
||||
@ -1327,6 +1374,9 @@ ts.filter = {
|
||||
}
|
||||
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
|
||||
data.exact.toLowerCase() : data.exact;
|
||||
|
||||
data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
|
||||
|
||||
result = showRow; // if showRow is true, show that row
|
||||
|
||||
// in case select filter option has a different value vs text 'a - z|A through Z'
|
||||
@ -1351,13 +1401,12 @@ ts.filter = {
|
||||
// data.filter = case sensitive
|
||||
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
|
||||
fxn = vars.functions[ columnIndex ];
|
||||
$cell = c.$headerIndexed[ columnIndex ];
|
||||
hasSelect = $cell.hasClass( 'filter-select' );
|
||||
hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
|
||||
filterMatched = null;
|
||||
if ( fxn || ( hasSelect && val ) ) {
|
||||
if ( fxn === true || hasSelect ) {
|
||||
// default selector uses exact match unless 'filter-match' class is found
|
||||
filterMatched = $cell.hasClass( 'filter-match' ) ?
|
||||
filterMatched = data.isMatch ?
|
||||
data.iExact.search( data.iFilter ) >= 0 :
|
||||
data.filter === data.exact;
|
||||
} else if ( typeof fxn === 'function' ) {
|
||||
@ -1374,15 +1423,7 @@ ts.filter = {
|
||||
if ( filterMatched === null ) {
|
||||
// cycle through the different filters
|
||||
// filters return a boolean or null if nothing matches
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ ffxn ]( c, data );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
filterMatched = ts.filter.processTypes( c, data, vars );
|
||||
if ( filterMatched !== null ) {
|
||||
result = filterMatched;
|
||||
// Look for match, and add child row data for matching
|
||||
|
6
dist/js/jquery.tablesorter.widgets.min.js
vendored
6
dist/js/jquery.tablesorter.widgets.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/widgets/widget-filter.min.js
vendored
2
dist/js/widgets/widget-filter.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/widgets/widget-sortTbodies.min.js
vendored
2
dist/js/widgets/widget-sortTbodies.min.js
vendored
@ -2,4 +2,4 @@
|
||||
* Requires tablesorter v2.22.2+ and jQuery 1.4+
|
||||
* by Rob Garrison
|
||||
*/
|
||||
!function(a){"use strict";var b=a.tablesorter;b.sortTbodies={init:function(c,d){var e,f,g,h,i,j=c.namespace+"sortTbody",k=c.$table.children("tbody"),l=k.length;for(d.sortTbody_original_serverSideSorting=c.serverSideSorting,d.sortTbody_original_cssInfoBlock=c.cssInfoBlock,c.cssInfoBlock=d.sortTbody_noSort,b.sortTbodies.setTbodies(c,d),e=0;l>e;e++)k.eq(e).attr("data-ts-original-order",e);for(c.$table.unbind("sortBegin updateComplete ".split(" ").join(j+" ")).bind("sortBegin"+j,function(){b.sortTbodies.sorter(c)}).bind("updateComplete"+j,function(){b.sortTbodies.setTbodies(c,d),c.$table.trigger("updateCache",[null,c.$tbodies])}),(a.isEmptyObject(c.parsers)||c.$tbodies.length!==k.length)&&(b.sortTbodies.setTbodies(c,d),c.$table.trigger("updateCache",[null,c.$tbodies])),i=k.children("tr"),l=i.length,e=0;e<c.columns;e++){if(h=0,"numeric"===c.parsers[e].type)for(f=0;l>f;f++)g=b.getParsedText(c,i.eq(f).children()[e],e),h=Math.max(Math.abs(g)||0,h);c.$headerIndexed[e].attr("data-ts-col-max-value",h)}},setTbodies:function(a,b){a.$tbodies=a.$table.children("tbody").not("."+b.sortTbody_noSort)},sorter:function(c){var d=c.$table,e=c.widgetOptions;if(e.sortTbody_busy!==!0){e.sortTbody_busy=!0;var f=d.children("tbody").not("."+e.sortTbody_noSort),g=e.sortTbody_primaryRow||"tr:eq(0)",h=c.sortList||[],i=h.length;i&&(c.serverSideSorting=!e.sortTbody_sortRows,f.sort(function(d,e){var f,j,k,l,m,n,o,p,q,r,s,t,u=c.table,v=c.parsers,w=c.textSorter||"",x=a(d),y=a(e),z=x.find(g).children("td, th"),A=y.find(g).children("td, th");for(f=0;i>f;f++){if(o=h[f][0],p=h[f][1],k=0===p,j=b.getElementText(c,z.eq(o),o),q=v[o].format(j,u,z[o],o),j=b.getElementText(c,A.eq(o),o),r=v[o].format(j,u,A[o],o),c.sortStable&&q===r&&1===i)return x.attr("data-ts-original-order")-y.attr("data-ts-original-order");if(l=/n/i.test(v&&v[o]?v[o].type||"":""),l&&c.strings[o]?(m=c.$headerIndexed[o].attr("data-ts-col-max-value")||1.79e308,l="boolean"==typeof c.string[c.strings[o]]?(k?1:-1)*(c.string[c.strings[o]]?-1:1):c.strings[o]?c.string[c.strings[o]]||0:0,n=c.numberSorter?c.numberSorter(q,r,k,m,u):b["sortNumeric"+(k?"Asc":"Desc")](q,r,l,m,o,u)):(s=k?q:r,t=k?r:q,n="function"==typeof w?w(s,t,k,o,u):"object"==typeof w&&w.hasOwnProperty(o)?w[o](s,t,k,o,u):b["sortNatural"+(k?"Asc":"Desc")](q,r,o,u,c)),n)return n}return x.attr("data-ts-original-order")-y.attr("data-ts-original-order")}),b.sortTbodies.restoreTbodies(c,e,f),e.sortTbody_busy=!1)}},restoreTbodies:function(a,b,c){var d,e,f,g,h,i,j,k,l,m=a.$table,i=!0,k=0;if(m.hide(),c.appendTo(m),e=m.children("tbody"),g=e.length,d=e.filter("."+b.sortTbody_noSort).appendTo(m),h=d.length)for(;i&&h>k;){for(i=!1,j=0;h>j;j++)l=parseInt(d.eq(j).attr("data-ts-original-order"),10),l=l>=g?g:0>l?0:l,l!==d.eq(j).index()&&(i=!0,f=d.eq(j).detach(),l>=g?f.appendTo(m):0===l?f.prependTo(m):f.insertBefore(m.children("tbody:eq("+l+")")));k++}m.show()}},b.addWidget({id:"sortTbody",priority:40,options:{sortTbody_primaryRow:null,sortTbody_sortRows:!1,sortTbody_noSort:"tablesorter-no-sort-tbody"},init:function(a,c,d,e){b.sortTbodies.init(d,e)},remove:function(a,b,c,d){b.$table.unbind("sortBegin updateComplete ".split(" ").join(b.namespace+"sortTbody ")),b.serverSideSorting=c.sortTbody_original_serverSideSorting,b.cssInfoBlock=c.sortTbody_original_cssInfoBlock}})}(jQuery);
|
||||
!function(a){"use strict";var b=a.tablesorter;b.sortTbodies={init:function(c,d){var e,f,g,h,i,j=c.namespace+"sortTbody",k=c.$table.children("tbody"),l=k.length;for(d.sortTbody_original_serverSideSorting=c.serverSideSorting,d.sortTbody_original_cssInfoBlock=c.cssInfoBlock,c.cssInfoBlock=d.sortTbody_noSort,b.sortTbodies.setTbodies(c,d),e=0;l>e;e++)k.eq(e).attr("data-ts-original-order",e);for(c.$table.unbind("sortBegin updateComplete ".split(" ").join(j+" ")).bind("sortBegin"+j,function(){b.sortTbodies.sorter(c)}).bind("updateComplete"+j,function(){b.sortTbodies.setTbodies(c,d),c.$table.trigger("updateCache",[null,c.$tbodies])}),(a.isEmptyObject(c.parsers)||c.$tbodies.length!==k.length)&&(b.sortTbodies.setTbodies(c,d),c.$table.trigger("updateCache",[null,c.$tbodies])),i=k.children("tr"),l=i.length,e=0;e<c.columns;e++){if(h=0,"numeric"===c.parsers[e].type)for(f=0;l>f;f++)g=b.getParsedText(c,i.eq(f).children()[e],e),h=Math.max(Math.abs(g)||0,h);c.$headerIndexed[e].attr("data-ts-col-max-value",h)}},setTbodies:function(a,b){a.$tbodies=a.$table.children("tbody").not("."+b.sortTbody_noSort)},sorter:function(c){var d=c.$table,e=c.widgetOptions;if(e.sortTbody_busy!==!0){e.sortTbody_busy=!0;var f=d.children("tbody").not("."+e.sortTbody_noSort),g=e.sortTbody_primaryRow||"tr:eq(0)",h=c.sortList||[],i=h.length;i&&(c.serverSideSorting=!e.sortTbody_sortRows,f.sort(function(d,e){var f,j,k,l,m,n,o,p,q,r,s,t,u=c.table,v=c.parsers,w=c.textSorter||"",x=a(d),y=a(e),z=x.find(g).children("td, th"),A=y.find(g).children("td, th");for(f=0;i>f;f++){if(o=h[f][0],p=h[f][1],k=0===p,j=b.getElementText(c,z.eq(o),o),q=v[o].format(j,u,z[o],o),j=b.getElementText(c,A.eq(o),o),r=v[o].format(j,u,A[o],o),c.sortStable&&q===r&&1===i)return x.attr("data-ts-original-order")-y.attr("data-ts-original-order");if(l=/n/i.test(v&&v[o]?v[o].type||"":""),l&&c.strings[o]?(m=c.$headerIndexed[o].attr("data-ts-col-max-value")||1.79e308,l="boolean"==typeof c.string[c.strings[o]]?(k?1:-1)*(c.string[c.strings[o]]?-1:1):c.strings[o]?c.string[c.strings[o]]||0:0,n=c.numberSorter?c.numberSorter(q,r,k,m,u):b["sortNumeric"+(k?"Asc":"Desc")](q,r,l,m,o,u)):(s=k?q:r,t=k?r:q,n="function"==typeof w?w(s,t,k,o,u):"object"==typeof w&&w.hasOwnProperty(o)?w[o](s,t,k,o,u):b["sortNatural"+(k?"Asc":"Desc")](q,r,o,u,c)),n)return n}return x.attr("data-ts-original-order")-y.attr("data-ts-original-order")}),b.sortTbodies.restoreTbodies(c,e,f),e.sortTbody_busy=!1)}},restoreTbodies:function(a,b,c){var d,e,f,g,h,i,j,k=a.$table,l=!0,m=0;if(k.hide(),c.appendTo(k),e=k.children("tbody"),g=e.length,d=e.filter("."+b.sortTbody_noSort).appendTo(k),h=d.length)for(;l&&h>m;){for(l=!1,i=0;h>i;i++)j=parseInt(d.eq(i).attr("data-ts-original-order"),10),j=j>=g?g:0>j?0:j,j!==d.eq(i).index()&&(l=!0,f=d.eq(i).detach(),j>=g?f.appendTo(k):0===j?f.prependTo(k):f.insertBefore(k.children("tbody:eq("+j+")")));m++}k.show()}},b.addWidget({id:"sortTbody",priority:40,options:{sortTbody_primaryRow:null,sortTbody_sortRows:!1,sortTbody_noSort:"tablesorter-no-sort-tbody"},init:function(a,c,d,e){b.sortTbodies.init(d,e)},remove:function(a,b,c,d){b.$table.unbind("sortBegin updateComplete ".split(" ").join(b.namespace+"sortTbody ")),b.serverSideSorting=c.sortTbody_original_serverSideSorting,b.cssInfoBlock=c.sortTbody_original_cssInfoBlock}})}(jQuery);
|
@ -225,6 +225,13 @@ $(function(){
|
||||
<h3 id="notes"><a href="#">Notes</a></h3>
|
||||
<div>
|
||||
<ul>
|
||||
<li>In <span class="version">v2.22.2</span>,
|
||||
<ul>
|
||||
<li>The <code>getFilters</code> function will now target the last used filter properly.</li>
|
||||
<li>The <code>selectSource</code> option now ignores parsers if none are set.</li>
|
||||
<li>Added the ability to nest filter types with a logical "OR" or a logical "AND". Try these filters: <button data-filter-column="1">a && !o</button> (<span class="label warning">*NOTE*</span> try this with and without the filter-match class applied), <button data-filter-column="3"><10 or >40</button> or <button data-filter-column="3">>20 && <40</button></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>In <span class="version">v2.22.0</span>
|
||||
<ul>
|
||||
<li>Regex filter searches now cache the created regex object for each query to optimize speed & a regex search now properly uses case-sensitive content.</li>
|
||||
@ -264,7 +271,7 @@ $(function(){
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<li><span class="label label-info">*NOTE*</span> If using a custom theme, make sure to add the class set in the <code>filter_filteredRow</code> option (set to <code>filtered</code> by default) in the css, and set it to <code>display:none</code>. When filtering rows, the filter widget adds the "filtered" class to hide the row; all available themes include this definition.</li>
|
||||
<li><span class="label alert">*NOTE*</span> If using a custom theme, make sure to add the class set in the <code>filter_filteredRow</code> option (set to <code>filtered</code> by default) in the css, and set it to <code>display:none</code>. When filtering rows, the filter widget adds the "filtered" class to hide the row; all available themes include this definition.</li>
|
||||
<li>Hover over the grey bar below the table header to open the filter row. Disable this by setting <code>filter_hideFilters</code> option to <code>false</code>.</li>
|
||||
<li>This widget uses jQuery's <code>.nextUntil()</code> function which is only available is jQuery version 1.4+.</li>
|
||||
<li>This widget <em>does NOT</em> work with tablesorter v2.0.5.</li>
|
||||
@ -272,27 +279,28 @@ $(function(){
|
||||
<table class="tablesorter-blue notes">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:10%">Type <small class="bright">(1)(2)</small></th>
|
||||
<th style="width:40%">Description</th>
|
||||
<th style="width:50%">Examples</th>
|
||||
<th style="width:1%">Priority</th>
|
||||
<th style="width:9%">Type <small class="bright">(1)(2)</small></th>
|
||||
<th style="width:30%">Description</th>
|
||||
<th style="width:60%">Examples</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td class="center">text</td><td>Any text entered in the filter will <strong>match</strong> text found within the column</td><td><code>abc</code> (finds "abc", "abcd", "abcde", etc);<button data-filter-column="1">Aaron</button> (finds "Aaron" and "Philip Aaron Wong")</td></tr>
|
||||
<tr><td class="center"><code>/\d/</code></td><td>Add any regex to the query to use in the query ("mig" flags can be included <code>/\w/mig</code>)</td><td><code>/b[aeiou]g/i</code> (finds "bag", "beg", "BIG", "Bug", etc);<button data-filter-column="1">/r$/</button> (matches text that ends with an "r")</td></tr>
|
||||
<tr><td class="center"><code>< <= >= ></code></td><td>Find alphabetical or numerical values less than or greater than or equal to the filtered query <small class="bright">(2)</small>.</td><td><button data-filter-column="5">>= 10</button> (find values greater than or equal to 10)</td></tr>
|
||||
<tr><td class="center"><code>!</code> or <code>!=</code></td><td>Not operator, or not exactly match. Filter the column with content that <strong>do not</strong> match the query. Include an equal (<code>=</code>), single (<code>'</code>) or double quote (<code>"</code>) to exactly <em>not</em> match a filter (<span class="version">v2.17.1</span>).</td><td><code>!fe</code> (hide rows with "female" in that column, but shows rows with "male");<button data-filter-column="1">!a</button> (find text that doesn't contain an "a");<button data-filter-column="1">!"Bruce"</button> (find content that does not exactly match "Bruce")</td></tr>
|
||||
<tr><td class="center"><code>"</code> or <code>=</code></td><td>To exactly match the search query, add a quote, apostrophe or equal sign to the beginning and/or end of the query</td><td><code>abc"</code> or <code>abc=</code> (exactly match "abc");<button data-filter-column="1">John"</button> or <button data-filter-column="1">John=</button> (exactly match "John")</td></tr>
|
||||
<tr><td class="center"><code> && </code> or <code> AND </code></td><td>Logical "and". Filter the column for content that matches text from either side of the operator.</td><td><code>box && bat</code> (matches a column cell that contains both "box" and "bat");<button data-filter-column="1">Br && c</button> (Find text that contains both "br" and "c")</td></tr>
|
||||
<tr><td class="center"><code> - </code> or <code> to </code></td><td>Find a range of values. Make sure there is a space before and after the dash (or the word "to") <small class="bright">(4)</small>.</td><td><button data-filter-column="3">10 - 30</button> or <button data-filter-column="4">10 to 30</button> (match values between 10 and 30)</td></tr>
|
||||
<tr><td class="center"><code>?</code></td><td>Wildcard for a single, non-space character.</td><td><code>J?n</code> (finds "Jan" and "Jun", but not "Joan");<button data-filter-column="2">a?s</button> (finds "Dumass" and "Evans", but not "McMasters")</td></tr>
|
||||
<tr><td class="center"><code>*</code></td><td>Wildcard for zero or more non-space characters.</td><td><code>B*k</code> (matches "Black" and "Book");<button data-filter-column="2">a*s</button> (matches "Dumass", "Evans" and "McMasters")</td></tr>
|
||||
<tr><td class="center"><code>|</code> or <code> OR </code></td><td>Logical "or" (Vertical bar). Filter the column for content that matches text from either side of the bar <small class="bright">(3)</small>.</td><td><code>box|bat</code> (matches a column cell with either "box" or "bat");<button data-filter-column="1">Alex|Peter</button> (Find text that contains either "Alex" or "Peter")</td></tr>
|
||||
<tr><td class="center"><code>~</code></td><td>Perform a fuzzy search (matches sequential characters) by adding a tilde to the beginning of the query (<span class="version">v2.13.3</span>)</td><td><button data-filter-column="1">~bee</button> (matches "Bruce Lee" and "Brenda Dexter"), or <button data-filter-column="1">~piano</button> (matches "Philip Aaron Wong")</td></tr>
|
||||
<tr><td class="center">1</td><td class="center"><code>|</code> or <code> OR </code></td><td>Logical "or" (Vertical bar). Filter the column for content that matches text from either side of the bar <small class="bright">(3)</small>.</td><td><code>box|bat</code> (matches a column cell with either "box" or "bat");<button data-filter-column="1">Alex|Peter</button> (Find text that contains either "Alex" or "Peter"); <button data-filter-column="3"><10 or >40</button></td></tr>
|
||||
<tr><td class="center">2</td><td class="center"><code> && </code> or <code> AND </code></td><td>Logical "and". Filter the column for content that matches text from either side of the operator.</td><td><code>box && bat</code> (matches a column cell that contains both "box" and "bat"), <button data-filter-column="1">Br && c</button> (Find text that contains both "br" and "c"), <button data-filter-column="3">>20 && <40</button> or <button data-filter-column="1">a and !o</button> (When "filter-match" is set, find content with the letter "a", but not the letter "o")</td></tr>
|
||||
<tr><td class="center">3</td><td class="center"><code>/\d/</code></td><td>Add any regex to the query to use in the query ("mig" flags can be included <code>/\w/mig</code>)</td><td><code>/b[aeiou]g/i</code> (finds "bag", "beg", "BIG", "Bug", etc);<button data-filter-column="1">/r$/</button> (matches text that ends with an "r")</td></tr>
|
||||
<tr><td class="center">4</td><td class="center"><code>< <= >= ></code></td><td>Find alphabetical or numerical values less than or greater than or equal to the filtered query <small class="bright">(2)</small>.</td><td><button data-filter-column="5">>= 10</button> (find values greater than or equal to 10)</td></tr>
|
||||
<tr><td class="center">5</td><td class="center"><code>!</code> or <code>!=</code></td><td>Not operator, or not exactly match. Filter the column with content that <strong>do not</strong> match the query. Include an equal (<code>=</code>), single (<code>'</code>) or double quote (<code>"</code>) to exactly <em>not</em> match a filter (<span class="version">v2.17.1</span>).</td><td><code>!fe</code> (hide rows with "female" in that column, but shows rows with "male");<button data-filter-column="1">!a</button> (find text that doesn't contain an "a");<button data-filter-column="1">!"Bruce"</button> (find content that does not exactly match "Bruce")</td></tr>
|
||||
<tr><td class="center">6</td><td class="center"><code>"</code> or <code>=</code></td><td>To exactly match the search query, add a quote, apostrophe or equal sign to the beginning and/or end of the query</td><td><code>abc"</code> or <code>abc=</code> (exactly match "abc");<button data-filter-column="1">John"</button> or <button data-filter-column="1">John=</button> (exactly match "John")</td></tr>
|
||||
<tr><td class="center">7</td><td class="center"><code> - </code> or <code> to </code></td><td>Find a range of values. Make sure there is a space before and after the dash (or the word "to") <small class="bright">(4)</small>.</td><td><button data-filter-column="3">10 - 30</button> or <button data-filter-column="4">10 to 30</button> (match values between 10 and 30)</td></tr>
|
||||
<tr><td class="center">8</td><td class="center"><code>?</code></td><td>Wildcard for a single, non-space character.</td><td><code>J?n</code> (finds "Jan" and "Jun", but not "Joan");<button data-filter-column="2">a?s</button> (finds "Dumass" and "Evans", but not "McMasters")</td></tr>
|
||||
<tr><td class="center">8</td><td class="center"><code>*</code></td><td>Wildcard for zero or more non-space characters.</td><td><code>B*k</code> (matches "Black" and "Book");<button data-filter-column="2">a*s</button> (matches "Dumass", "Evans" and "McMasters")</td></tr>
|
||||
<tr><td class="center">9</td><td class="center"><code>~</code></td><td>Perform a fuzzy search (matches sequential characters) by adding a tilde to the beginning of the query (<span class="version">v2.13.3</span>)</td><td><button data-filter-column="1">~bee</button> (matches "Bruce Lee" and "Brenda Dexter"), or <button data-filter-column="1">~piano</button> (matches "Philip Aaron Wong")</td></tr>
|
||||
<tr><td class="center">10</td><td class="center">text</td><td>Any text entered in the filter will <strong>match</strong> text found within the column</td><td><code>abc</code> (finds "abc", "abcd", "abcde", etc);<button data-filter-column="1">Aaron</button> (finds "Aaron" and "Philip Aaron Wong")</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<span class="bright">(1)</span> You cannot combine these operators with each other (except for the wildcards).<br>
|
||||
<span class="bright">(2)</span> The filter order (or precendence) of how searches are checked is as follows: <span class="smallcode">regex (<code>/\d/</code>) <strong>></strong> operators (<code>< <= >= ></code>) <strong>></strong> not match (<code>!</code>) <strong>></strong> exact (<code>"</code>) <strong>></strong> and (<code> AND </code>) <strong>></strong> range (<code> - </code>) <strong>></strong> wild/or (<code>?</code>, <code>*</code> and <code> OR </code>) <strong>></strong> fuzzy (<code>~</code>); so an exact match will override "and", "or" and "range" searches </span> (*NOTE* order changed in <span class="version updated">v2.15</span>, operators prioritized before exact; see <a href="https://github.com/Mottie/tablesorter/issues/465">issue #465</a>; order changed again in <span class="version updated">v2.17.1</span> to move "not match" before "exact" and allow for exact not matches; see <a href="https://github.com/Mottie/tablesorter/issues/628">issue #628</a>)<br>
|
||||
<span class="bright">(2)</span> The filter order (or precendence) of how searches are checked in "priority" (first column) order; so an exact match will override "range" searches </span> (*NOTE* order changed in <span class="version updated">v2.15</span>, operators prioritized before exact; see <a href="https://github.com/Mottie/tablesorter/issues/465">issue #465</a>; order changed again in <span class="version updated">v2.17.1</span> to move "not match" before "exact" and allow for exact not matches; see <a href="https://github.com/Mottie/tablesorter/issues/628">issue #628</a>). In <span class="version updated">v2.22.2</span>, the "or" and "and" types can combine any of the other filter types together.<br>
|
||||
<span class="bright">(3)</span> Logical "or" comparisons can now show exact matches (by default; <span class="version">v2.10.1</span>) or just match cell contents.<br>
|
||||
<span class="bright">(4)</span> In tablesorter <span class="version">v2.10</span>, comparisons can be made in date columns (if properly parsed).
|
||||
</li>
|
||||
@ -768,7 +776,14 @@ $.extend($.tablesorter.language, {
|
||||
|
||||
<h1>CSS</h1>
|
||||
<div>
|
||||
<pre class="prettyprint lang-css">/* This css is already contained within each theme file */
|
||||
<pre class="prettyprint lang-css">/* REQUIRED in CUSTOM THEMES!
|
||||
This is the only definition that MUST BE added to any custom themes.
|
||||
This is how rows are hidden by filtering (included in provided themes) */
|
||||
.tablesorter .filtered {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* All of the following css is already contained within each theme file; modify it as desired */
|
||||
/* filter row */
|
||||
.tablesorter-filter-row td {
|
||||
background: #eee;
|
||||
|
@ -483,7 +483,7 @@
|
||||
<li><span class="label label-info">Beta</span> <a href="example-dragtable.html">Dragtable mod</a> - (jQuery UI widget for column reordering [<a href="http://stackoverflow.com/a/27770224/145346">ref</a>]; <span class="version">v2.19.0</span>).</li>
|
||||
<li><span class="results">†</span> Filter widget (<span class="version updated">v2.22.1</span>):
|
||||
<ul>
|
||||
<li><a href="example-widget-filter.html">basic</a> (v2.0.18; <span class="version updated">v2.18.1</span>)</li>
|
||||
<li><a href="example-widget-filter.html">basic</a> (v2.0.18; <span class="version updated">v2.22.2</span>)</li>
|
||||
<li><a href="example-widget-filter-any-match.html">external option (match any column)</a> (<span class="version">v2.13.3</span>; <span class="version updated">v2.22.0</span>)</li>
|
||||
<li><a href="example-widget-filter-external-inputs.html">external inputs</a> (<span class="version">v2.14</span>; <span class="version updated">v2.18.0</span>)</li>
|
||||
<li><a href="example-widget-filter-custom.html">custom</a> (v2.3.6; <span class="version updated">v2.22.0</span>)</li>
|
||||
|
@ -4,7 +4,7 @@
|
||||
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀▀▀▀██
|
||||
█████▀ ▀████▀ ██ ██ ▀████▀ ██ ██ ██ ██ ▀████▀ █████▀ ██ ██ █████▀
|
||||
*/
|
||||
/*! tablesorter (FORK) - updated 06-10-2015 (v2.22.1)*/
|
||||
/*! tablesorter (FORK) - updated 06-12-2015 (v2.22.1)*/
|
||||
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
|
||||
(function(factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
@ -2654,6 +2654,66 @@ ts.filter = {
|
||||
// data.index = column index; table = table element ( DOM )
|
||||
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
|
||||
types: {
|
||||
or : function( c, data, vars ) {
|
||||
if ( /\|/.test( data.iFilter ) || ts.filter.regex.orSplit.test( data.filter ) ) {
|
||||
var indx, filterMatched, txt, query, regex,
|
||||
// duplicate data but split filter
|
||||
data2 = $.extend( {}, data ),
|
||||
index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
filter = data.filter.split( ts.filter.regex.orSplit ),
|
||||
iFilter = data.iFilter.split( ts.filter.regex.orSplit ),
|
||||
len = filter.length;
|
||||
for ( indx = 0; indx < len; indx++ ) {
|
||||
data2.nestedFilters = true;
|
||||
data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
||||
data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
||||
query = '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
|
||||
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
||||
// filterMatched = data2.filter === '' && indx > 0 ? true
|
||||
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
||||
filterMatched = regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars );
|
||||
if ( filterMatched ) {
|
||||
return filterMatched;
|
||||
}
|
||||
}
|
||||
// may be null from processing types
|
||||
return filterMatched || false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for an AND or && operator ( logical and )
|
||||
and : function( c, data, vars ) {
|
||||
if ( ts.filter.regex.andTest.test( data.filter ) ) {
|
||||
var indx, filterMatched, result, txt, query, regex,
|
||||
// duplicate data but split filter
|
||||
data2 = $.extend( {}, data ),
|
||||
index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
filter = data.filter.split( ts.filter.regex.andSplit ),
|
||||
iFilter = data.iFilter.split( ts.filter.regex.andSplit ),
|
||||
len = filter.length;
|
||||
for ( indx = 0; indx < len; indx++ ) {
|
||||
data2.nestedFilters = true;
|
||||
data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
||||
data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
||||
query = ( '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
|
||||
// replace wild cards since /(a*)/i will match anything
|
||||
.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
|
||||
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
||||
// look for an exact match with the 'and' unless the 'filter-match' class is found
|
||||
result = ( regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars ) );
|
||||
if ( indx === 0 ) {
|
||||
filterMatched = result;
|
||||
} else {
|
||||
filterMatched = filterMatched && result;
|
||||
}
|
||||
}
|
||||
// may be null from processing types
|
||||
return filterMatched || false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for regex
|
||||
regex: function( c, data ) {
|
||||
if ( ts.filter.regex.regex.test( data.filter ) ) {
|
||||
@ -2741,23 +2801,6 @@ ts.filter = {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for an AND or && operator ( logical and )
|
||||
and : function( c, data ) {
|
||||
if ( ts.filter.regex.andTest.test( data.filter ) ) {
|
||||
var index = data.index,
|
||||
parsed = data.parsed[index],
|
||||
query = data.iFilter.split( ts.filter.regex.andSplit ),
|
||||
result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0,
|
||||
indx = query.length - 1;
|
||||
while ( result && indx ) {
|
||||
result = result &&
|
||||
data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0;
|
||||
indx--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
|
||||
range : function( c, data ) {
|
||||
if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
|
||||
@ -2794,24 +2837,20 @@ ts.filter = {
|
||||
},
|
||||
// Look for wild card: ? = single, * = multiple, or | = logical OR
|
||||
wild : function( c, data ) {
|
||||
if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) {
|
||||
if ( /[\?\*\|]/.test( data.iFilter ) ) {
|
||||
var index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ),
|
||||
query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
|
||||
query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
|
||||
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
||||
if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) {
|
||||
// show all results while using filter match. Fixes #727
|
||||
if ( query[ query.length - 1 ] === '|' ) {
|
||||
query += '*';
|
||||
}
|
||||
query = data.anyMatch && $.isArray( data.rowArray ) ?
|
||||
'(' + query + ')' :
|
||||
'^(' + query + ')$';
|
||||
if ( !/\?\*/.test( query ) && data.nestedFilters ) {
|
||||
query = data.isMatch ? query : '^(' + query + ')$';
|
||||
}
|
||||
// parsing the filter may not work properly when using wildcards =/
|
||||
return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) )
|
||||
.test( data.iExact );
|
||||
return new RegExp(
|
||||
query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
|
||||
c.widgetOptions.filter_ignoreCase ? 'i' : ''
|
||||
)
|
||||
.test( data.exact );
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@ -2865,7 +2904,7 @@ ts.filter = {
|
||||
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
|
||||
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
|
||||
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
|
||||
orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ),
|
||||
orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
|
||||
iQuery : new RegExp( val, 'i' ),
|
||||
igQuery : new RegExp( val, 'ig' )
|
||||
});
|
||||
@ -3085,7 +3124,6 @@ ts.filter = {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setDefaults: function( table, c, wo ) {
|
||||
var isArray, saved, indx, col, $filters,
|
||||
// get current ( default ) filters
|
||||
@ -3430,8 +3468,22 @@ ts.filter = {
|
||||
}
|
||||
return columns;
|
||||
},
|
||||
processTypes: function( c, data, vars ) {
|
||||
var ffxn,
|
||||
filterMatched = null,
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ffxn]( c, data, vars );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
return filterMatched;
|
||||
},
|
||||
processRow: function( c, data, vars ) {
|
||||
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch,
|
||||
var columnIndex, hasSelect, result, val, filterMatched,
|
||||
fxn, ffxn, txt,
|
||||
regex = ts.filter.regex,
|
||||
wo = c.widgetOptions,
|
||||
@ -3442,6 +3494,7 @@ ts.filter = {
|
||||
// look for multiple columns '1-3,4-6,8'
|
||||
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
|
||||
data.anyMatch = true;
|
||||
data.isMatch = true;
|
||||
data.rowArray = data.$cells.map( function( i ) {
|
||||
if ( $.inArray( i, columnIndex ) > -1 ) {
|
||||
if ( data.parsed[ i ] ) {
|
||||
@ -3461,16 +3514,10 @@ ts.filter = {
|
||||
data.exact = data.rowArray.join( ' ' );
|
||||
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
|
||||
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
|
||||
filterMatched = null;
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ffxn]( c, data );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vars.excludeMatch = vars.noAnyMatch;
|
||||
filterMatched = ts.filter.processTypes( c, data, vars );
|
||||
|
||||
if ( filterMatched !== null ) {
|
||||
showRow = filterMatched;
|
||||
} else {
|
||||
@ -3497,7 +3544,7 @@ ts.filter = {
|
||||
data.index = columnIndex;
|
||||
|
||||
// filter types to exclude, per column
|
||||
excludeMatch = vars.excludeFilter[ columnIndex ];
|
||||
vars.excludeMatch = vars.excludeFilter[ columnIndex ];
|
||||
|
||||
// ignore if filter is empty or disabled
|
||||
if ( data.filter ) {
|
||||
@ -3511,6 +3558,9 @@ ts.filter = {
|
||||
}
|
||||
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
|
||||
data.exact.toLowerCase() : data.exact;
|
||||
|
||||
data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
|
||||
|
||||
result = showRow; // if showRow is true, show that row
|
||||
|
||||
// in case select filter option has a different value vs text 'a - z|A through Z'
|
||||
@ -3535,13 +3585,12 @@ ts.filter = {
|
||||
// data.filter = case sensitive
|
||||
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
|
||||
fxn = vars.functions[ columnIndex ];
|
||||
$cell = c.$headerIndexed[ columnIndex ];
|
||||
hasSelect = $cell.hasClass( 'filter-select' );
|
||||
hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
|
||||
filterMatched = null;
|
||||
if ( fxn || ( hasSelect && val ) ) {
|
||||
if ( fxn === true || hasSelect ) {
|
||||
// default selector uses exact match unless 'filter-match' class is found
|
||||
filterMatched = $cell.hasClass( 'filter-match' ) ?
|
||||
filterMatched = data.isMatch ?
|
||||
data.iExact.search( data.iFilter ) >= 0 :
|
||||
data.filter === data.exact;
|
||||
} else if ( typeof fxn === 'function' ) {
|
||||
@ -3558,15 +3607,7 @@ ts.filter = {
|
||||
if ( filterMatched === null ) {
|
||||
// cycle through the different filters
|
||||
// filters return a boolean or null if nothing matches
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ ffxn ]( c, data );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
filterMatched = ts.filter.processTypes( c, data, vars );
|
||||
if ( filterMatched !== null ) {
|
||||
result = filterMatched;
|
||||
// Look for match, and add child row data for matching
|
||||
|
@ -4,7 +4,7 @@
|
||||
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀▀▀▀██
|
||||
█████▀ ▀████▀ ██ ██ ▀████▀ ██ ██ ██ ██ ▀████▀ █████▀ ██ ██ █████▀
|
||||
*/
|
||||
/*! tablesorter (FORK) - updated 06-10-2015 (v2.22.1)*/
|
||||
/*! tablesorter (FORK) - updated 06-12-2015 (v2.22.1)*/
|
||||
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
|
||||
(function(factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
@ -476,6 +476,66 @@ ts.filter = {
|
||||
// data.index = column index; table = table element ( DOM )
|
||||
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
|
||||
types: {
|
||||
or : function( c, data, vars ) {
|
||||
if ( /\|/.test( data.iFilter ) || ts.filter.regex.orSplit.test( data.filter ) ) {
|
||||
var indx, filterMatched, txt, query, regex,
|
||||
// duplicate data but split filter
|
||||
data2 = $.extend( {}, data ),
|
||||
index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
filter = data.filter.split( ts.filter.regex.orSplit ),
|
||||
iFilter = data.iFilter.split( ts.filter.regex.orSplit ),
|
||||
len = filter.length;
|
||||
for ( indx = 0; indx < len; indx++ ) {
|
||||
data2.nestedFilters = true;
|
||||
data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
||||
data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
||||
query = '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
|
||||
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
||||
// filterMatched = data2.filter === '' && indx > 0 ? true
|
||||
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
||||
filterMatched = regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars );
|
||||
if ( filterMatched ) {
|
||||
return filterMatched;
|
||||
}
|
||||
}
|
||||
// may be null from processing types
|
||||
return filterMatched || false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for an AND or && operator ( logical and )
|
||||
and : function( c, data, vars ) {
|
||||
if ( ts.filter.regex.andTest.test( data.filter ) ) {
|
||||
var indx, filterMatched, result, txt, query, regex,
|
||||
// duplicate data but split filter
|
||||
data2 = $.extend( {}, data ),
|
||||
index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
filter = data.filter.split( ts.filter.regex.andSplit ),
|
||||
iFilter = data.iFilter.split( ts.filter.regex.andSplit ),
|
||||
len = filter.length;
|
||||
for ( indx = 0; indx < len; indx++ ) {
|
||||
data2.nestedFilters = true;
|
||||
data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
||||
data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
||||
query = ( '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
|
||||
// replace wild cards since /(a*)/i will match anything
|
||||
.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
|
||||
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
||||
// look for an exact match with the 'and' unless the 'filter-match' class is found
|
||||
result = ( regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars ) );
|
||||
if ( indx === 0 ) {
|
||||
filterMatched = result;
|
||||
} else {
|
||||
filterMatched = filterMatched && result;
|
||||
}
|
||||
}
|
||||
// may be null from processing types
|
||||
return filterMatched || false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for regex
|
||||
regex: function( c, data ) {
|
||||
if ( ts.filter.regex.regex.test( data.filter ) ) {
|
||||
@ -563,23 +623,6 @@ ts.filter = {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for an AND or && operator ( logical and )
|
||||
and : function( c, data ) {
|
||||
if ( ts.filter.regex.andTest.test( data.filter ) ) {
|
||||
var index = data.index,
|
||||
parsed = data.parsed[index],
|
||||
query = data.iFilter.split( ts.filter.regex.andSplit ),
|
||||
result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0,
|
||||
indx = query.length - 1;
|
||||
while ( result && indx ) {
|
||||
result = result &&
|
||||
data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0;
|
||||
indx--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
|
||||
range : function( c, data ) {
|
||||
if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
|
||||
@ -616,24 +659,20 @@ ts.filter = {
|
||||
},
|
||||
// Look for wild card: ? = single, * = multiple, or | = logical OR
|
||||
wild : function( c, data ) {
|
||||
if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) {
|
||||
if ( /[\?\*\|]/.test( data.iFilter ) ) {
|
||||
var index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ),
|
||||
query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
|
||||
query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
|
||||
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
||||
if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) {
|
||||
// show all results while using filter match. Fixes #727
|
||||
if ( query[ query.length - 1 ] === '|' ) {
|
||||
query += '*';
|
||||
}
|
||||
query = data.anyMatch && $.isArray( data.rowArray ) ?
|
||||
'(' + query + ')' :
|
||||
'^(' + query + ')$';
|
||||
if ( !/\?\*/.test( query ) && data.nestedFilters ) {
|
||||
query = data.isMatch ? query : '^(' + query + ')$';
|
||||
}
|
||||
// parsing the filter may not work properly when using wildcards =/
|
||||
return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) )
|
||||
.test( data.iExact );
|
||||
return new RegExp(
|
||||
query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
|
||||
c.widgetOptions.filter_ignoreCase ? 'i' : ''
|
||||
)
|
||||
.test( data.exact );
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@ -687,7 +726,7 @@ ts.filter = {
|
||||
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
|
||||
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
|
||||
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
|
||||
orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ),
|
||||
orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
|
||||
iQuery : new RegExp( val, 'i' ),
|
||||
igQuery : new RegExp( val, 'ig' )
|
||||
});
|
||||
@ -907,7 +946,6 @@ ts.filter = {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setDefaults: function( table, c, wo ) {
|
||||
var isArray, saved, indx, col, $filters,
|
||||
// get current ( default ) filters
|
||||
@ -1252,8 +1290,22 @@ ts.filter = {
|
||||
}
|
||||
return columns;
|
||||
},
|
||||
processTypes: function( c, data, vars ) {
|
||||
var ffxn,
|
||||
filterMatched = null,
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ffxn]( c, data, vars );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
return filterMatched;
|
||||
},
|
||||
processRow: function( c, data, vars ) {
|
||||
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch,
|
||||
var columnIndex, hasSelect, result, val, filterMatched,
|
||||
fxn, ffxn, txt,
|
||||
regex = ts.filter.regex,
|
||||
wo = c.widgetOptions,
|
||||
@ -1264,6 +1316,7 @@ ts.filter = {
|
||||
// look for multiple columns '1-3,4-6,8'
|
||||
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
|
||||
data.anyMatch = true;
|
||||
data.isMatch = true;
|
||||
data.rowArray = data.$cells.map( function( i ) {
|
||||
if ( $.inArray( i, columnIndex ) > -1 ) {
|
||||
if ( data.parsed[ i ] ) {
|
||||
@ -1283,16 +1336,10 @@ ts.filter = {
|
||||
data.exact = data.rowArray.join( ' ' );
|
||||
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
|
||||
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
|
||||
filterMatched = null;
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ffxn]( c, data );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vars.excludeMatch = vars.noAnyMatch;
|
||||
filterMatched = ts.filter.processTypes( c, data, vars );
|
||||
|
||||
if ( filterMatched !== null ) {
|
||||
showRow = filterMatched;
|
||||
} else {
|
||||
@ -1319,7 +1366,7 @@ ts.filter = {
|
||||
data.index = columnIndex;
|
||||
|
||||
// filter types to exclude, per column
|
||||
excludeMatch = vars.excludeFilter[ columnIndex ];
|
||||
vars.excludeMatch = vars.excludeFilter[ columnIndex ];
|
||||
|
||||
// ignore if filter is empty or disabled
|
||||
if ( data.filter ) {
|
||||
@ -1333,6 +1380,9 @@ ts.filter = {
|
||||
}
|
||||
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
|
||||
data.exact.toLowerCase() : data.exact;
|
||||
|
||||
data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
|
||||
|
||||
result = showRow; // if showRow is true, show that row
|
||||
|
||||
// in case select filter option has a different value vs text 'a - z|A through Z'
|
||||
@ -1357,13 +1407,12 @@ ts.filter = {
|
||||
// data.filter = case sensitive
|
||||
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
|
||||
fxn = vars.functions[ columnIndex ];
|
||||
$cell = c.$headerIndexed[ columnIndex ];
|
||||
hasSelect = $cell.hasClass( 'filter-select' );
|
||||
hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
|
||||
filterMatched = null;
|
||||
if ( fxn || ( hasSelect && val ) ) {
|
||||
if ( fxn === true || hasSelect ) {
|
||||
// default selector uses exact match unless 'filter-match' class is found
|
||||
filterMatched = $cell.hasClass( 'filter-match' ) ?
|
||||
filterMatched = data.isMatch ?
|
||||
data.iExact.search( data.iFilter ) >= 0 :
|
||||
data.filter === data.exact;
|
||||
} else if ( typeof fxn === 'function' ) {
|
||||
@ -1380,15 +1429,7 @@ ts.filter = {
|
||||
if ( filterMatched === null ) {
|
||||
// cycle through the different filters
|
||||
// filters return a boolean or null if nothing matches
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ ffxn ]( c, data );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
filterMatched = ts.filter.processTypes( c, data, vars );
|
||||
if ( filterMatched !== null ) {
|
||||
result = filterMatched;
|
||||
// Look for match, and add child row data for matching
|
||||
|
@ -103,6 +103,66 @@ ts.filter = {
|
||||
// data.index = column index; table = table element ( DOM )
|
||||
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
|
||||
types: {
|
||||
or : function( c, data, vars ) {
|
||||
if ( /\|/.test( data.iFilter ) || ts.filter.regex.orSplit.test( data.filter ) ) {
|
||||
var indx, filterMatched, txt, query, regex,
|
||||
// duplicate data but split filter
|
||||
data2 = $.extend( {}, data ),
|
||||
index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
filter = data.filter.split( ts.filter.regex.orSplit ),
|
||||
iFilter = data.iFilter.split( ts.filter.regex.orSplit ),
|
||||
len = filter.length;
|
||||
for ( indx = 0; indx < len; indx++ ) {
|
||||
data2.nestedFilters = true;
|
||||
data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
||||
data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
||||
query = '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
|
||||
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
||||
// filterMatched = data2.filter === '' && indx > 0 ? true
|
||||
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
||||
filterMatched = regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars );
|
||||
if ( filterMatched ) {
|
||||
return filterMatched;
|
||||
}
|
||||
}
|
||||
// may be null from processing types
|
||||
return filterMatched || false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for an AND or && operator ( logical and )
|
||||
and : function( c, data, vars ) {
|
||||
if ( ts.filter.regex.andTest.test( data.filter ) ) {
|
||||
var indx, filterMatched, result, txt, query, regex,
|
||||
// duplicate data but split filter
|
||||
data2 = $.extend( {}, data ),
|
||||
index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
filter = data.filter.split( ts.filter.regex.andSplit ),
|
||||
iFilter = data.iFilter.split( ts.filter.regex.andSplit ),
|
||||
len = filter.length;
|
||||
for ( indx = 0; indx < len; indx++ ) {
|
||||
data2.nestedFilters = true;
|
||||
data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
||||
data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
||||
query = ( '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
|
||||
// replace wild cards since /(a*)/i will match anything
|
||||
.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
|
||||
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
||||
// look for an exact match with the 'and' unless the 'filter-match' class is found
|
||||
result = ( regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars ) );
|
||||
if ( indx === 0 ) {
|
||||
filterMatched = result;
|
||||
} else {
|
||||
filterMatched = filterMatched && result;
|
||||
}
|
||||
}
|
||||
// may be null from processing types
|
||||
return filterMatched || false;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for regex
|
||||
regex: function( c, data ) {
|
||||
if ( ts.filter.regex.regex.test( data.filter ) ) {
|
||||
@ -190,23 +250,6 @@ ts.filter = {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for an AND or && operator ( logical and )
|
||||
and : function( c, data ) {
|
||||
if ( ts.filter.regex.andTest.test( data.filter ) ) {
|
||||
var index = data.index,
|
||||
parsed = data.parsed[index],
|
||||
query = data.iFilter.split( ts.filter.regex.andSplit ),
|
||||
result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0,
|
||||
indx = query.length - 1;
|
||||
while ( result && indx ) {
|
||||
result = result &&
|
||||
data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0;
|
||||
indx--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
|
||||
range : function( c, data ) {
|
||||
if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
|
||||
@ -243,24 +286,20 @@ ts.filter = {
|
||||
},
|
||||
// Look for wild card: ? = single, * = multiple, or | = logical OR
|
||||
wild : function( c, data ) {
|
||||
if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) {
|
||||
if ( /[\?\*\|]/.test( data.iFilter ) ) {
|
||||
var index = data.index,
|
||||
parsed = data.parsed[ index ],
|
||||
txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ),
|
||||
query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
|
||||
query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
|
||||
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
||||
if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) {
|
||||
// show all results while using filter match. Fixes #727
|
||||
if ( query[ query.length - 1 ] === '|' ) {
|
||||
query += '*';
|
||||
}
|
||||
query = data.anyMatch && $.isArray( data.rowArray ) ?
|
||||
'(' + query + ')' :
|
||||
'^(' + query + ')$';
|
||||
if ( !/\?\*/.test( query ) && data.nestedFilters ) {
|
||||
query = data.isMatch ? query : '^(' + query + ')$';
|
||||
}
|
||||
// parsing the filter may not work properly when using wildcards =/
|
||||
return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) )
|
||||
.test( data.iExact );
|
||||
return new RegExp(
|
||||
query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
|
||||
c.widgetOptions.filter_ignoreCase ? 'i' : ''
|
||||
)
|
||||
.test( data.exact );
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@ -314,7 +353,7 @@ ts.filter = {
|
||||
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
|
||||
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
|
||||
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
|
||||
orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ),
|
||||
orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
|
||||
iQuery : new RegExp( val, 'i' ),
|
||||
igQuery : new RegExp( val, 'ig' )
|
||||
});
|
||||
@ -534,7 +573,6 @@ ts.filter = {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setDefaults: function( table, c, wo ) {
|
||||
var isArray, saved, indx, col, $filters,
|
||||
// get current ( default ) filters
|
||||
@ -879,8 +917,22 @@ ts.filter = {
|
||||
}
|
||||
return columns;
|
||||
},
|
||||
processTypes: function( c, data, vars ) {
|
||||
var ffxn,
|
||||
filterMatched = null,
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ffxn]( c, data, vars );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
return filterMatched;
|
||||
},
|
||||
processRow: function( c, data, vars ) {
|
||||
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch,
|
||||
var columnIndex, hasSelect, result, val, filterMatched,
|
||||
fxn, ffxn, txt,
|
||||
regex = ts.filter.regex,
|
||||
wo = c.widgetOptions,
|
||||
@ -891,6 +943,7 @@ ts.filter = {
|
||||
// look for multiple columns '1-3,4-6,8'
|
||||
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
|
||||
data.anyMatch = true;
|
||||
data.isMatch = true;
|
||||
data.rowArray = data.$cells.map( function( i ) {
|
||||
if ( $.inArray( i, columnIndex ) > -1 ) {
|
||||
if ( data.parsed[ i ] ) {
|
||||
@ -910,16 +963,10 @@ ts.filter = {
|
||||
data.exact = data.rowArray.join( ' ' );
|
||||
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
|
||||
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
|
||||
filterMatched = null;
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ffxn]( c, data );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vars.excludeMatch = vars.noAnyMatch;
|
||||
filterMatched = ts.filter.processTypes( c, data, vars );
|
||||
|
||||
if ( filterMatched !== null ) {
|
||||
showRow = filterMatched;
|
||||
} else {
|
||||
@ -946,7 +993,7 @@ ts.filter = {
|
||||
data.index = columnIndex;
|
||||
|
||||
// filter types to exclude, per column
|
||||
excludeMatch = vars.excludeFilter[ columnIndex ];
|
||||
vars.excludeMatch = vars.excludeFilter[ columnIndex ];
|
||||
|
||||
// ignore if filter is empty or disabled
|
||||
if ( data.filter ) {
|
||||
@ -960,6 +1007,9 @@ ts.filter = {
|
||||
}
|
||||
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
|
||||
data.exact.toLowerCase() : data.exact;
|
||||
|
||||
data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
|
||||
|
||||
result = showRow; // if showRow is true, show that row
|
||||
|
||||
// in case select filter option has a different value vs text 'a - z|A through Z'
|
||||
@ -984,13 +1034,12 @@ ts.filter = {
|
||||
// data.filter = case sensitive
|
||||
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
|
||||
fxn = vars.functions[ columnIndex ];
|
||||
$cell = c.$headerIndexed[ columnIndex ];
|
||||
hasSelect = $cell.hasClass( 'filter-select' );
|
||||
hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
|
||||
filterMatched = null;
|
||||
if ( fxn || ( hasSelect && val ) ) {
|
||||
if ( fxn === true || hasSelect ) {
|
||||
// default selector uses exact match unless 'filter-match' class is found
|
||||
filterMatched = $cell.hasClass( 'filter-match' ) ?
|
||||
filterMatched = data.isMatch ?
|
||||
data.iExact.search( data.iFilter ) >= 0 :
|
||||
data.filter === data.exact;
|
||||
} else if ( typeof fxn === 'function' ) {
|
||||
@ -1007,15 +1056,7 @@ ts.filter = {
|
||||
if ( filterMatched === null ) {
|
||||
// cycle through the different filters
|
||||
// filters return a boolean or null if nothing matches
|
||||
matches = null;
|
||||
for ( ffxn in ts.filter.types ) {
|
||||
if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) {
|
||||
matches = ts.filter.types[ ffxn ]( c, data );
|
||||
if ( matches !== null ) {
|
||||
filterMatched = matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
filterMatched = ts.filter.processTypes( c, data, vars );
|
||||
if ( filterMatched !== null ) {
|
||||
result = filterMatched;
|
||||
// Look for match, and add child row data for matching
|
||||
|
@ -148,7 +148,7 @@ $(function(){
|
||||
wo = this.wo,
|
||||
$table = this.$table,
|
||||
table = this.table;
|
||||
expect(27);
|
||||
expect(31);
|
||||
|
||||
return QUnit.SequentialRunner(
|
||||
function(actions, assertions) {
|
||||
@ -205,6 +205,18 @@ $(function(){
|
||||
).nextTask(
|
||||
function(){ ts.setFilters( table, ['', 'br && cl'], true ); },
|
||||
function(){ assert.cacheCompare( table, 1, ['Brandon Clark'], 'search and match; ensure search filtered gets cleared', true ); }
|
||||
).nextTask(
|
||||
function(){ ts.setFilters( table, ['', 'c* && l && a'], true ); },
|
||||
function(){ assert.cacheCompare( table, 1, ['Brandon Clark', 'Clark'], 'search "c* && l && a"', true ); }
|
||||
).nextTask(
|
||||
function(){ ts.setFilters( table, ['', 'a && !o'], true ); },
|
||||
function(){ assert.cacheCompare( table, 1, ['Clark', 'Alex', 'Brenda Dexter', 'Martha'], 'search "a && !o"', true ); }
|
||||
).nextTask(
|
||||
function(){ ts.setFilters( table, ['', '', '' , '>20 && <40'], true ); },
|
||||
function(){ assert.cacheCompare( table, 3, [25, 28, 33, 24, 22, 25], 'search ">20 && <40"', true ); }
|
||||
).nextTask(
|
||||
function(){ ts.setFilters( table, ['', '', '' , '<10 or >40'], true ); },
|
||||
function(){ assert.cacheCompare( table, 3, [51, 45, 65], 'search "<10 or >40"', true ); }
|
||||
).nextTask(
|
||||
function(){ ts.setFilters( table, ['', 'alex|br*'], true ); },
|
||||
function(){ assert.cacheCompare( table, 1, ['Brandon Clark', 'Bruce', 'Alex', 'Bruce Lee', 'Brenda Dexter'], 'search OR match', true ); }
|
||||
|
Loading…
Reference in New Issue
Block a user