Filter: add nesting of "AND" & "OR" searches. Fixes #891 & #918

This commit is contained in:
Mottie 2015-06-12 20:24:36 -05:00
parent a79f3417ce
commit 449b985c60
12 changed files with 543 additions and 311 deletions

View File

@ -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 ) */ /* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) { (function(factory) {
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
@ -2648,6 +2648,66 @@ ts.filter = {
// data.index = column index; table = table element ( DOM ) // data.index = column index; table = table element ( DOM )
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class ) // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
types: { 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 // Look for regex
regex: function( c, data ) { regex: function( c, data ) {
if ( ts.filter.regex.regex.test( data.filter ) ) { if ( ts.filter.regex.regex.test( data.filter ) ) {
@ -2735,23 +2795,6 @@ ts.filter = {
} }
return null; 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! // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
range : function( c, data ) { range : function( c, data ) {
if ( ts.filter.regex.toTest.test( data.iFilter ) ) { if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
@ -2788,24 +2831,20 @@ ts.filter = {
}, },
// Look for wild card: ? = single, * = multiple, or | = logical OR // Look for wild card: ? = single, * = multiple, or | = logical OR
wild : function( c, data ) { wild : function( c, data ) {
if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) { if ( /[\?\*\|]/.test( data.iFilter ) ) {
var index = data.index, var index = data.index,
parsed = data.parsed[ index ], parsed = data.parsed[ index ],
txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ), query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
// look for an exact match with the 'or' unless the 'filter-match' class is found // look for an exact match with the 'or' unless the 'filter-match' class is found
if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) { if ( !/\?\*/.test( query ) && data.nestedFilters ) {
// show all results while using filter match. Fixes #727 query = data.isMatch ? query : '^(' + query + ')$';
if ( query[ query.length - 1 ] === '|' ) {
query += '*';
}
query = data.anyMatch && $.isArray( data.rowArray ) ?
'(' + query + ')' :
'^(' + query + ')$';
} }
// parsing the filter may not work properly when using wildcards =/ // parsing the filter may not work properly when using wildcards =/
return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) ) return new RegExp(
.test( data.iExact ); query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
c.widgetOptions.filter_ignoreCase ? 'i' : ''
)
.test( data.exact );
} }
return null; return null;
}, },
@ -2859,7 +2898,7 @@ ts.filter = {
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ), toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ), andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ), 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' ), iQuery : new RegExp( val, 'i' ),
igQuery : new RegExp( val, 'ig' ) igQuery : new RegExp( val, 'ig' )
}); });
@ -3079,7 +3118,6 @@ ts.filter = {
} }
} }
}, },
setDefaults: function( table, c, wo ) { setDefaults: function( table, c, wo ) {
var isArray, saved, indx, col, $filters, var isArray, saved, indx, col, $filters,
// get current ( default ) filters // get current ( default ) filters
@ -3424,8 +3462,22 @@ ts.filter = {
} }
return columns; 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 ) { processRow: function( c, data, vars ) {
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch, var columnIndex, hasSelect, result, val, filterMatched,
fxn, ffxn, txt, fxn, ffxn, txt,
regex = ts.filter.regex, regex = ts.filter.regex,
wo = c.widgetOptions, wo = c.widgetOptions,
@ -3436,6 +3488,7 @@ ts.filter = {
// look for multiple columns '1-3,4-6,8' // look for multiple columns '1-3,4-6,8'
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch ); columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
data.anyMatch = true; data.anyMatch = true;
data.isMatch = true;
data.rowArray = data.$cells.map( function( i ) { data.rowArray = data.$cells.map( function( i ) {
if ( $.inArray( i, columnIndex ) > -1 ) { if ( $.inArray( i, columnIndex ) > -1 ) {
if ( data.parsed[ i ] ) { if ( data.parsed[ i ] ) {
@ -3455,16 +3508,10 @@ ts.filter = {
data.exact = data.rowArray.join( ' ' ); data.exact = data.rowArray.join( ' ' );
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact; data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' ); data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
filterMatched = null;
matches = null; vars.excludeMatch = vars.noAnyMatch;
for ( ffxn in ts.filter.types ) { filterMatched = ts.filter.processTypes( c, data, vars );
if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
matches = ts.filter.types[ffxn]( c, data );
if ( matches !== null ) {
filterMatched = matches;
}
}
}
if ( filterMatched !== null ) { if ( filterMatched !== null ) {
showRow = filterMatched; showRow = filterMatched;
} else { } else {
@ -3491,7 +3538,7 @@ ts.filter = {
data.index = columnIndex; data.index = columnIndex;
// filter types to exclude, per column // filter types to exclude, per column
excludeMatch = vars.excludeFilter[ columnIndex ]; vars.excludeMatch = vars.excludeFilter[ columnIndex ];
// ignore if filter is empty or disabled // ignore if filter is empty or disabled
if ( data.filter ) { if ( data.filter ) {
@ -3505,6 +3552,9 @@ ts.filter = {
} }
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ? data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
data.exact.toLowerCase() : data.exact; data.exact.toLowerCase() : data.exact;
data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
result = showRow; // if showRow is true, show that row 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' // 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.filter = case sensitive
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter; data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
fxn = vars.functions[ columnIndex ]; fxn = vars.functions[ columnIndex ];
$cell = c.$headerIndexed[ columnIndex ]; hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
hasSelect = $cell.hasClass( 'filter-select' );
filterMatched = null; filterMatched = null;
if ( fxn || ( hasSelect && val ) ) { if ( fxn || ( hasSelect && val ) ) {
if ( fxn === true || hasSelect ) { if ( fxn === true || hasSelect ) {
// default selector uses exact match unless 'filter-match' class is found // 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.iExact.search( data.iFilter ) >= 0 :
data.filter === data.exact; data.filter === data.exact;
} else if ( typeof fxn === 'function' ) { } else if ( typeof fxn === 'function' ) {
@ -3552,15 +3601,7 @@ ts.filter = {
if ( filterMatched === null ) { if ( filterMatched === null ) {
// cycle through the different filters // cycle through the different filters
// filters return a boolean or null if nothing matches // filters return a boolean or null if nothing matches
matches = null; filterMatched = ts.filter.processTypes( c, data, vars );
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;
}
}
}
if ( filterMatched !== null ) { if ( filterMatched !== null ) {
result = filterMatched; result = filterMatched;
// Look for match, and add child row data for matching // Look for match, and add child row data for matching

File diff suppressed because one or more lines are too long

View File

@ -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 ) */ /* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) { (function(factory) {
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
@ -470,6 +470,66 @@ ts.filter = {
// data.index = column index; table = table element ( DOM ) // data.index = column index; table = table element ( DOM )
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class ) // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
types: { 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 // Look for regex
regex: function( c, data ) { regex: function( c, data ) {
if ( ts.filter.regex.regex.test( data.filter ) ) { if ( ts.filter.regex.regex.test( data.filter ) ) {
@ -557,23 +617,6 @@ ts.filter = {
} }
return null; 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! // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
range : function( c, data ) { range : function( c, data ) {
if ( ts.filter.regex.toTest.test( data.iFilter ) ) { if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
@ -610,24 +653,20 @@ ts.filter = {
}, },
// Look for wild card: ? = single, * = multiple, or | = logical OR // Look for wild card: ? = single, * = multiple, or | = logical OR
wild : function( c, data ) { wild : function( c, data ) {
if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) { if ( /[\?\*\|]/.test( data.iFilter ) ) {
var index = data.index, var index = data.index,
parsed = data.parsed[ index ], parsed = data.parsed[ index ],
txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ), query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
// look for an exact match with the 'or' unless the 'filter-match' class is found // look for an exact match with the 'or' unless the 'filter-match' class is found
if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) { if ( !/\?\*/.test( query ) && data.nestedFilters ) {
// show all results while using filter match. Fixes #727 query = data.isMatch ? query : '^(' + query + ')$';
if ( query[ query.length - 1 ] === '|' ) {
query += '*';
}
query = data.anyMatch && $.isArray( data.rowArray ) ?
'(' + query + ')' :
'^(' + query + ')$';
} }
// parsing the filter may not work properly when using wildcards =/ // parsing the filter may not work properly when using wildcards =/
return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) ) return new RegExp(
.test( data.iExact ); query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
c.widgetOptions.filter_ignoreCase ? 'i' : ''
)
.test( data.exact );
} }
return null; return null;
}, },
@ -681,7 +720,7 @@ ts.filter = {
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ), toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ), andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ), 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' ), iQuery : new RegExp( val, 'i' ),
igQuery : new RegExp( val, 'ig' ) igQuery : new RegExp( val, 'ig' )
}); });
@ -901,7 +940,6 @@ ts.filter = {
} }
} }
}, },
setDefaults: function( table, c, wo ) { setDefaults: function( table, c, wo ) {
var isArray, saved, indx, col, $filters, var isArray, saved, indx, col, $filters,
// get current ( default ) filters // get current ( default ) filters
@ -1246,8 +1284,22 @@ ts.filter = {
} }
return columns; 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 ) { processRow: function( c, data, vars ) {
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch, var columnIndex, hasSelect, result, val, filterMatched,
fxn, ffxn, txt, fxn, ffxn, txt,
regex = ts.filter.regex, regex = ts.filter.regex,
wo = c.widgetOptions, wo = c.widgetOptions,
@ -1258,6 +1310,7 @@ ts.filter = {
// look for multiple columns '1-3,4-6,8' // look for multiple columns '1-3,4-6,8'
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch ); columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
data.anyMatch = true; data.anyMatch = true;
data.isMatch = true;
data.rowArray = data.$cells.map( function( i ) { data.rowArray = data.$cells.map( function( i ) {
if ( $.inArray( i, columnIndex ) > -1 ) { if ( $.inArray( i, columnIndex ) > -1 ) {
if ( data.parsed[ i ] ) { if ( data.parsed[ i ] ) {
@ -1277,16 +1330,10 @@ ts.filter = {
data.exact = data.rowArray.join( ' ' ); data.exact = data.rowArray.join( ' ' );
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact; data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' ); data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
filterMatched = null;
matches = null; vars.excludeMatch = vars.noAnyMatch;
for ( ffxn in ts.filter.types ) { filterMatched = ts.filter.processTypes( c, data, vars );
if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
matches = ts.filter.types[ffxn]( c, data );
if ( matches !== null ) {
filterMatched = matches;
}
}
}
if ( filterMatched !== null ) { if ( filterMatched !== null ) {
showRow = filterMatched; showRow = filterMatched;
} else { } else {
@ -1313,7 +1360,7 @@ ts.filter = {
data.index = columnIndex; data.index = columnIndex;
// filter types to exclude, per column // filter types to exclude, per column
excludeMatch = vars.excludeFilter[ columnIndex ]; vars.excludeMatch = vars.excludeFilter[ columnIndex ];
// ignore if filter is empty or disabled // ignore if filter is empty or disabled
if ( data.filter ) { if ( data.filter ) {
@ -1327,6 +1374,9 @@ ts.filter = {
} }
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ? data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
data.exact.toLowerCase() : data.exact; data.exact.toLowerCase() : data.exact;
data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
result = showRow; // if showRow is true, show that row 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' // 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.filter = case sensitive
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter; data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
fxn = vars.functions[ columnIndex ]; fxn = vars.functions[ columnIndex ];
$cell = c.$headerIndexed[ columnIndex ]; hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
hasSelect = $cell.hasClass( 'filter-select' );
filterMatched = null; filterMatched = null;
if ( fxn || ( hasSelect && val ) ) { if ( fxn || ( hasSelect && val ) ) {
if ( fxn === true || hasSelect ) { if ( fxn === true || hasSelect ) {
// default selector uses exact match unless 'filter-match' class is found // 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.iExact.search( data.iFilter ) >= 0 :
data.filter === data.exact; data.filter === data.exact;
} else if ( typeof fxn === 'function' ) { } else if ( typeof fxn === 'function' ) {
@ -1374,15 +1423,7 @@ ts.filter = {
if ( filterMatched === null ) { if ( filterMatched === null ) {
// cycle through the different filters // cycle through the different filters
// filters return a boolean or null if nothing matches // filters return a boolean or null if nothing matches
matches = null; filterMatched = ts.filter.processTypes( c, data, vars );
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;
}
}
}
if ( filterMatched !== null ) { if ( filterMatched !== null ) {
result = filterMatched; result = filterMatched;
// Look for match, and add child row data for matching // Look for match, and add child row data for matching

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,4 +2,4 @@
* Requires tablesorter v2.22.2+ and jQuery 1.4+ * Requires tablesorter v2.22.2+ and jQuery 1.4+
* by Rob Garrison * 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);

View File

@ -225,6 +225,13 @@ $(function(){
<h3 id="notes"><a href="#">Notes</a></h3> <h3 id="notes"><a href="#">Notes</a></h3>
<div> <div>
<ul> <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">&lt10 or &gt;40</button> or <button data-filter-column="3">&gt;20 && &lt;40</button></li>
</ul>
</li>
<li>In <span class="version">v2.22.0</span> <li>In <span class="version">v2.22.0</span>
<ul> <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> <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> </div>
<ul> <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>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 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> <li>This widget <em>does NOT</em> work with tablesorter v2.0.5.</li>
@ -272,27 +279,28 @@ $(function(){
<table class="tablesorter-blue notes"> <table class="tablesorter-blue notes">
<thead> <thead>
<tr> <tr>
<th style="width:10%">Type <small class="bright">(1)(2)</small></th> <th style="width:1%">Priority</th>
<th style="width:40%">Description</th> <th style="width:9%">Type <small class="bright">(1)(2)</small></th>
<th style="width:50%">Examples</th> <th style="width:30%">Description</th>
<th style="width:60%">Examples</th>
</tr> </tr>
</thead> </thead>
<tbody> <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 &quot;abc&quot;, &quot;abcd&quot;, &quot;abcde&quot;, etc);<button data-filter-column="1">Aaron</button> (finds &quot;Aaron&quot; and &quot;Philip Aaron Wong&quot;)</td></tr> <tr><td class="center">1</td><td class="center"><code>|</code> or <code>&nbsp;OR&nbsp;</code></td><td>Logical &quot;or&quot; (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 &quot;box&quot; or &quot;bat&quot;);<button data-filter-column="1">Alex|Peter</button> (Find text that contains either &quot;Alex&quot; or &quot;Peter&quot;); <button data-filter-column="3">&lt10 or &gt;40</button></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 &quot;bag&quot;, &quot;beg&quot;, &quot;BIG&quot;, &quot;Bug&quot;, etc);<button data-filter-column="1">/r$/</button> (matches text that ends with an &quot;r&quot;)</td></tr> <tr><td class="center">2</td><td class="center"><code>&nbsp;&&&nbsp;</code> or <code>&nbsp;AND&nbsp;</code></td><td>Logical &quot;and&quot;. 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 &quot;box&quot; and &quot;bat&quot;), <button data-filter-column="1">Br && c</button> (Find text that contains both &quot;br&quot; and &quot;c&quot;), <button data-filter-column="3">&gt;20 && &lt;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"><code>&lt; &lt;= &gt;= &gt;</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">&gt;= 10</button> (find values greater than or equal to 10)</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 &quot;bag&quot;, &quot;beg&quot;, &quot;BIG&quot;, &quot;Bug&quot;, etc);<button data-filter-column="1">/r$/</button> (matches text that ends with an &quot;r&quot;)</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>&quot;</code>) to exactly <em>not</em> match a filter (<span class="version">v2.17.1</span>).</td><td><code>!fe</code> (hide rows with &quot;female&quot; in that column, but shows rows with &quot;male&quot;);<button data-filter-column="1">!a</button> (find text that doesn't contain an &quot;a&quot;);<button data-filter-column="1">!"Bruce"</button> (find content that does not exactly match "Bruce")</td></tr> <tr><td class="center">4</td><td class="center"><code>&lt; &lt;= &gt;= &gt;</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">&gt;= 10</button> (find values greater than or equal to 10)</td></tr>
<tr><td class="center"><code>&quot;</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&quot;</code> or <code>abc=</code> (exactly match &quot;abc&quot;);<button data-filter-column="1">John&quot;</button> or <button data-filter-column="1">John=</button> (exactly match &quot;John&quot;)</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>&quot;</code>) to exactly <em>not</em> match a filter (<span class="version">v2.17.1</span>).</td><td><code>!fe</code> (hide rows with &quot;female&quot; in that column, but shows rows with &quot;male&quot;);<button data-filter-column="1">!a</button> (find text that doesn't contain an &quot;a&quot;);<button data-filter-column="1">!"Bruce"</button> (find content that does not exactly match "Bruce")</td></tr>
<tr><td class="center"><code>&nbsp;&&&nbsp;</code> or <code>&nbsp;AND&nbsp;</code></td><td>Logical &quot;and&quot;. 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 &quot;box&quot; and &quot;bat&quot;);<button data-filter-column="1">Br && c</button> (Find text that contains both &quot;br&quot; and &quot;c&quot;)</td></tr> <tr><td class="center">6</td><td class="center"><code>&quot;</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&quot;</code> or <code>abc=</code> (exactly match &quot;abc&quot;);<button data-filter-column="1">John&quot;</button> or <button data-filter-column="1">John=</button> (exactly match &quot;John&quot;)</td></tr>
<tr><td class="center"><code>&nbsp;-&nbsp;</code> or <code>&nbsp;to&nbsp;</code></td><td>Find a range of values. Make sure there is a space before and after the dash (or the word &quot;to&quot;) <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">7</td><td class="center"><code>&nbsp;-&nbsp;</code> or <code>&nbsp;to&nbsp;</code></td><td>Find a range of values. Make sure there is a space before and after the dash (or the word &quot;to&quot;) <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 &quot;Jan&quot; and &quot;Jun&quot;, but not &quot;Joan&quot;);<button data-filter-column="2">a?s</button> (finds &quot;Dumass&quot; and &quot;Evans&quot;, but not &quot;McMasters&quot;)</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 &quot;Jan&quot; and &quot;Jun&quot;, but not &quot;Joan&quot;);<button data-filter-column="2">a?s</button> (finds &quot;Dumass&quot; and &quot;Evans&quot;, but not &quot;McMasters&quot;)</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 &quot;Black&quot; and &quot;Book&quot;);<button data-filter-column="2">a*s</button> (matches &quot;Dumass&quot;, &quot;Evans&quot; and &quot;McMasters&quot;)</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 &quot;Black&quot; and &quot;Book&quot;);<button data-filter-column="2">a*s</button> (matches &quot;Dumass&quot;, &quot;Evans&quot; and &quot;McMasters&quot;)</td></tr>
<tr><td class="center"><code>|</code> or <code>&nbsp;OR&nbsp;</code></td><td>Logical &quot;or&quot; (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 &quot;box&quot; or &quot;bat&quot;);<button data-filter-column="1">Alex|Peter</button> (Find text that contains either &quot;Alex&quot; or &quot;Peter&quot;)</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 &quot;Bruce Lee&quot; and &quot;Brenda Dexter&quot;), or <button data-filter-column="1">~piano</button> (matches &quot;Philip Aaron Wong&quot;)</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 &quot;Bruce Lee&quot; and &quot;Brenda Dexter&quot;), or <button data-filter-column="1">~piano</button> (matches &quot;Philip Aaron Wong&quot;)</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 &quot;abc&quot;, &quot;abcd&quot;, &quot;abcde&quot;, etc);<button data-filter-column="1">Aaron</button> (finds &quot;Aaron&quot; and &quot;Philip Aaron Wong&quot;)</td></tr>
</tbody> </tbody>
</table> </table>
<span class="bright">(1)</span> You cannot combine these operators with each other (except for the wildcards).<br> <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>&gt;</strong> operators (<code>&lt; &lt;= &gt;= &gt;</code>) <strong>&gt;</strong> not match (<code>!</code>) <strong>&gt;</strong> exact (<code>"</code>) <strong>&gt;</strong> and (<code>&nbsp;AND&nbsp;</code>) <strong>&gt;</strong> range (<code>&nbsp;-&nbsp;</code>) <strong>&gt;</strong> wild/or (<code>?</code>, <code>*</code> and <code>&nbsp;OR&nbsp;</code>) <strong>&gt;</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">(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). <span class="bright">(4)</span> In tablesorter <span class="version">v2.10</span>, comparisons can be made in date columns (if properly parsed).
</li> </li>
@ -768,7 +776,14 @@ $.extend($.tablesorter.language, {
<h1>CSS</h1> <h1>CSS</h1>
<div> <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 */ /* filter row */
.tablesorter-filter-row td { .tablesorter-filter-row td {
background: #eee; background: #eee;

View File

@ -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="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">&dagger;</span> Filter widget (<span class="version updated">v2.22.1</span>): <li><span class="results">&dagger;</span> Filter widget (<span class="version updated">v2.22.1</span>):
<ul> <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-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-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> <li><a href="example-widget-filter-custom.html">custom</a> (v2.3.6; <span class="version updated">v2.22.0</span>)</li>

View File

@ -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 ) */ /* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) { (function(factory) {
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
@ -2654,6 +2654,66 @@ ts.filter = {
// data.index = column index; table = table element ( DOM ) // data.index = column index; table = table element ( DOM )
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class ) // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
types: { 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 // Look for regex
regex: function( c, data ) { regex: function( c, data ) {
if ( ts.filter.regex.regex.test( data.filter ) ) { if ( ts.filter.regex.regex.test( data.filter ) ) {
@ -2741,23 +2801,6 @@ ts.filter = {
} }
return null; 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! // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
range : function( c, data ) { range : function( c, data ) {
if ( ts.filter.regex.toTest.test( data.iFilter ) ) { if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
@ -2794,24 +2837,20 @@ ts.filter = {
}, },
// Look for wild card: ? = single, * = multiple, or | = logical OR // Look for wild card: ? = single, * = multiple, or | = logical OR
wild : function( c, data ) { wild : function( c, data ) {
if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) { if ( /[\?\*\|]/.test( data.iFilter ) ) {
var index = data.index, var index = data.index,
parsed = data.parsed[ index ], parsed = data.parsed[ index ],
txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ), query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
// look for an exact match with the 'or' unless the 'filter-match' class is found // look for an exact match with the 'or' unless the 'filter-match' class is found
if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) { if ( !/\?\*/.test( query ) && data.nestedFilters ) {
// show all results while using filter match. Fixes #727 query = data.isMatch ? query : '^(' + query + ')$';
if ( query[ query.length - 1 ] === '|' ) {
query += '*';
}
query = data.anyMatch && $.isArray( data.rowArray ) ?
'(' + query + ')' :
'^(' + query + ')$';
} }
// parsing the filter may not work properly when using wildcards =/ // parsing the filter may not work properly when using wildcards =/
return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) ) return new RegExp(
.test( data.iExact ); query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
c.widgetOptions.filter_ignoreCase ? 'i' : ''
)
.test( data.exact );
} }
return null; return null;
}, },
@ -2865,7 +2904,7 @@ ts.filter = {
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ), toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ), andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ), 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' ), iQuery : new RegExp( val, 'i' ),
igQuery : new RegExp( val, 'ig' ) igQuery : new RegExp( val, 'ig' )
}); });
@ -3085,7 +3124,6 @@ ts.filter = {
} }
} }
}, },
setDefaults: function( table, c, wo ) { setDefaults: function( table, c, wo ) {
var isArray, saved, indx, col, $filters, var isArray, saved, indx, col, $filters,
// get current ( default ) filters // get current ( default ) filters
@ -3430,8 +3468,22 @@ ts.filter = {
} }
return columns; 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 ) { processRow: function( c, data, vars ) {
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch, var columnIndex, hasSelect, result, val, filterMatched,
fxn, ffxn, txt, fxn, ffxn, txt,
regex = ts.filter.regex, regex = ts.filter.regex,
wo = c.widgetOptions, wo = c.widgetOptions,
@ -3442,6 +3494,7 @@ ts.filter = {
// look for multiple columns '1-3,4-6,8' // look for multiple columns '1-3,4-6,8'
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch ); columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
data.anyMatch = true; data.anyMatch = true;
data.isMatch = true;
data.rowArray = data.$cells.map( function( i ) { data.rowArray = data.$cells.map( function( i ) {
if ( $.inArray( i, columnIndex ) > -1 ) { if ( $.inArray( i, columnIndex ) > -1 ) {
if ( data.parsed[ i ] ) { if ( data.parsed[ i ] ) {
@ -3461,16 +3514,10 @@ ts.filter = {
data.exact = data.rowArray.join( ' ' ); data.exact = data.rowArray.join( ' ' );
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact; data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' ); data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
filterMatched = null;
matches = null; vars.excludeMatch = vars.noAnyMatch;
for ( ffxn in ts.filter.types ) { filterMatched = ts.filter.processTypes( c, data, vars );
if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
matches = ts.filter.types[ffxn]( c, data );
if ( matches !== null ) {
filterMatched = matches;
}
}
}
if ( filterMatched !== null ) { if ( filterMatched !== null ) {
showRow = filterMatched; showRow = filterMatched;
} else { } else {
@ -3497,7 +3544,7 @@ ts.filter = {
data.index = columnIndex; data.index = columnIndex;
// filter types to exclude, per column // filter types to exclude, per column
excludeMatch = vars.excludeFilter[ columnIndex ]; vars.excludeMatch = vars.excludeFilter[ columnIndex ];
// ignore if filter is empty or disabled // ignore if filter is empty or disabled
if ( data.filter ) { if ( data.filter ) {
@ -3511,6 +3558,9 @@ ts.filter = {
} }
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ? data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
data.exact.toLowerCase() : data.exact; data.exact.toLowerCase() : data.exact;
data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
result = showRow; // if showRow is true, show that row 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' // 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.filter = case sensitive
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter; data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
fxn = vars.functions[ columnIndex ]; fxn = vars.functions[ columnIndex ];
$cell = c.$headerIndexed[ columnIndex ]; hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
hasSelect = $cell.hasClass( 'filter-select' );
filterMatched = null; filterMatched = null;
if ( fxn || ( hasSelect && val ) ) { if ( fxn || ( hasSelect && val ) ) {
if ( fxn === true || hasSelect ) { if ( fxn === true || hasSelect ) {
// default selector uses exact match unless 'filter-match' class is found // 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.iExact.search( data.iFilter ) >= 0 :
data.filter === data.exact; data.filter === data.exact;
} else if ( typeof fxn === 'function' ) { } else if ( typeof fxn === 'function' ) {
@ -3558,15 +3607,7 @@ ts.filter = {
if ( filterMatched === null ) { if ( filterMatched === null ) {
// cycle through the different filters // cycle through the different filters
// filters return a boolean or null if nothing matches // filters return a boolean or null if nothing matches
matches = null; filterMatched = ts.filter.processTypes( c, data, vars );
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;
}
}
}
if ( filterMatched !== null ) { if ( filterMatched !== null ) {
result = filterMatched; result = filterMatched;
// Look for match, and add child row data for matching // Look for match, and add child row data for matching

View File

@ -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 ) */ /* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) { (function(factory) {
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
@ -476,6 +476,66 @@ ts.filter = {
// data.index = column index; table = table element ( DOM ) // data.index = column index; table = table element ( DOM )
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class ) // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
types: { 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 // Look for regex
regex: function( c, data ) { regex: function( c, data ) {
if ( ts.filter.regex.regex.test( data.filter ) ) { if ( ts.filter.regex.regex.test( data.filter ) ) {
@ -563,23 +623,6 @@ ts.filter = {
} }
return null; 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! // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
range : function( c, data ) { range : function( c, data ) {
if ( ts.filter.regex.toTest.test( data.iFilter ) ) { if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
@ -616,24 +659,20 @@ ts.filter = {
}, },
// Look for wild card: ? = single, * = multiple, or | = logical OR // Look for wild card: ? = single, * = multiple, or | = logical OR
wild : function( c, data ) { wild : function( c, data ) {
if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) { if ( /[\?\*\|]/.test( data.iFilter ) ) {
var index = data.index, var index = data.index,
parsed = data.parsed[ index ], parsed = data.parsed[ index ],
txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ), query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
// look for an exact match with the 'or' unless the 'filter-match' class is found // look for an exact match with the 'or' unless the 'filter-match' class is found
if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) { if ( !/\?\*/.test( query ) && data.nestedFilters ) {
// show all results while using filter match. Fixes #727 query = data.isMatch ? query : '^(' + query + ')$';
if ( query[ query.length - 1 ] === '|' ) {
query += '*';
}
query = data.anyMatch && $.isArray( data.rowArray ) ?
'(' + query + ')' :
'^(' + query + ')$';
} }
// parsing the filter may not work properly when using wildcards =/ // parsing the filter may not work properly when using wildcards =/
return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) ) return new RegExp(
.test( data.iExact ); query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
c.widgetOptions.filter_ignoreCase ? 'i' : ''
)
.test( data.exact );
} }
return null; return null;
}, },
@ -687,7 +726,7 @@ ts.filter = {
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ), toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ), andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ), 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' ), iQuery : new RegExp( val, 'i' ),
igQuery : new RegExp( val, 'ig' ) igQuery : new RegExp( val, 'ig' )
}); });
@ -907,7 +946,6 @@ ts.filter = {
} }
} }
}, },
setDefaults: function( table, c, wo ) { setDefaults: function( table, c, wo ) {
var isArray, saved, indx, col, $filters, var isArray, saved, indx, col, $filters,
// get current ( default ) filters // get current ( default ) filters
@ -1252,8 +1290,22 @@ ts.filter = {
} }
return columns; 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 ) { processRow: function( c, data, vars ) {
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch, var columnIndex, hasSelect, result, val, filterMatched,
fxn, ffxn, txt, fxn, ffxn, txt,
regex = ts.filter.regex, regex = ts.filter.regex,
wo = c.widgetOptions, wo = c.widgetOptions,
@ -1264,6 +1316,7 @@ ts.filter = {
// look for multiple columns '1-3,4-6,8' // look for multiple columns '1-3,4-6,8'
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch ); columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
data.anyMatch = true; data.anyMatch = true;
data.isMatch = true;
data.rowArray = data.$cells.map( function( i ) { data.rowArray = data.$cells.map( function( i ) {
if ( $.inArray( i, columnIndex ) > -1 ) { if ( $.inArray( i, columnIndex ) > -1 ) {
if ( data.parsed[ i ] ) { if ( data.parsed[ i ] ) {
@ -1283,16 +1336,10 @@ ts.filter = {
data.exact = data.rowArray.join( ' ' ); data.exact = data.rowArray.join( ' ' );
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact; data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' ); data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
filterMatched = null;
matches = null; vars.excludeMatch = vars.noAnyMatch;
for ( ffxn in ts.filter.types ) { filterMatched = ts.filter.processTypes( c, data, vars );
if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
matches = ts.filter.types[ffxn]( c, data );
if ( matches !== null ) {
filterMatched = matches;
}
}
}
if ( filterMatched !== null ) { if ( filterMatched !== null ) {
showRow = filterMatched; showRow = filterMatched;
} else { } else {
@ -1319,7 +1366,7 @@ ts.filter = {
data.index = columnIndex; data.index = columnIndex;
// filter types to exclude, per column // filter types to exclude, per column
excludeMatch = vars.excludeFilter[ columnIndex ]; vars.excludeMatch = vars.excludeFilter[ columnIndex ];
// ignore if filter is empty or disabled // ignore if filter is empty or disabled
if ( data.filter ) { if ( data.filter ) {
@ -1333,6 +1380,9 @@ ts.filter = {
} }
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ? data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
data.exact.toLowerCase() : data.exact; data.exact.toLowerCase() : data.exact;
data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
result = showRow; // if showRow is true, show that row 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' // 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.filter = case sensitive
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter; data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
fxn = vars.functions[ columnIndex ]; fxn = vars.functions[ columnIndex ];
$cell = c.$headerIndexed[ columnIndex ]; hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
hasSelect = $cell.hasClass( 'filter-select' );
filterMatched = null; filterMatched = null;
if ( fxn || ( hasSelect && val ) ) { if ( fxn || ( hasSelect && val ) ) {
if ( fxn === true || hasSelect ) { if ( fxn === true || hasSelect ) {
// default selector uses exact match unless 'filter-match' class is found // 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.iExact.search( data.iFilter ) >= 0 :
data.filter === data.exact; data.filter === data.exact;
} else if ( typeof fxn === 'function' ) { } else if ( typeof fxn === 'function' ) {
@ -1380,15 +1429,7 @@ ts.filter = {
if ( filterMatched === null ) { if ( filterMatched === null ) {
// cycle through the different filters // cycle through the different filters
// filters return a boolean or null if nothing matches // filters return a boolean or null if nothing matches
matches = null; filterMatched = ts.filter.processTypes( c, data, vars );
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;
}
}
}
if ( filterMatched !== null ) { if ( filterMatched !== null ) {
result = filterMatched; result = filterMatched;
// Look for match, and add child row data for matching // Look for match, and add child row data for matching

View File

@ -103,6 +103,66 @@ ts.filter = {
// data.index = column index; table = table element ( DOM ) // data.index = column index; table = table element ( DOM )
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class ) // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
types: { 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 // Look for regex
regex: function( c, data ) { regex: function( c, data ) {
if ( ts.filter.regex.regex.test( data.filter ) ) { if ( ts.filter.regex.regex.test( data.filter ) ) {
@ -190,23 +250,6 @@ ts.filter = {
} }
return null; 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! // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
range : function( c, data ) { range : function( c, data ) {
if ( ts.filter.regex.toTest.test( data.iFilter ) ) { if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
@ -243,24 +286,20 @@ ts.filter = {
}, },
// Look for wild card: ? = single, * = multiple, or | = logical OR // Look for wild card: ? = single, * = multiple, or | = logical OR
wild : function( c, data ) { wild : function( c, data ) {
if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) { if ( /[\?\*\|]/.test( data.iFilter ) ) {
var index = data.index, var index = data.index,
parsed = data.parsed[ index ], parsed = data.parsed[ index ],
txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ), query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
// look for an exact match with the 'or' unless the 'filter-match' class is found // look for an exact match with the 'or' unless the 'filter-match' class is found
if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) { if ( !/\?\*/.test( query ) && data.nestedFilters ) {
// show all results while using filter match. Fixes #727 query = data.isMatch ? query : '^(' + query + ')$';
if ( query[ query.length - 1 ] === '|' ) {
query += '*';
}
query = data.anyMatch && $.isArray( data.rowArray ) ?
'(' + query + ')' :
'^(' + query + ')$';
} }
// parsing the filter may not work properly when using wildcards =/ // parsing the filter may not work properly when using wildcards =/
return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) ) return new RegExp(
.test( data.iExact ); query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
c.widgetOptions.filter_ignoreCase ? 'i' : ''
)
.test( data.exact );
} }
return null; return null;
}, },
@ -314,7 +353,7 @@ ts.filter = {
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ), toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ), andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ), 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' ), iQuery : new RegExp( val, 'i' ),
igQuery : new RegExp( val, 'ig' ) igQuery : new RegExp( val, 'ig' )
}); });
@ -534,7 +573,6 @@ ts.filter = {
} }
} }
}, },
setDefaults: function( table, c, wo ) { setDefaults: function( table, c, wo ) {
var isArray, saved, indx, col, $filters, var isArray, saved, indx, col, $filters,
// get current ( default ) filters // get current ( default ) filters
@ -879,8 +917,22 @@ ts.filter = {
} }
return columns; 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 ) { processRow: function( c, data, vars ) {
var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch, var columnIndex, hasSelect, result, val, filterMatched,
fxn, ffxn, txt, fxn, ffxn, txt,
regex = ts.filter.regex, regex = ts.filter.regex,
wo = c.widgetOptions, wo = c.widgetOptions,
@ -891,6 +943,7 @@ ts.filter = {
// look for multiple columns '1-3,4-6,8' // look for multiple columns '1-3,4-6,8'
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch ); columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
data.anyMatch = true; data.anyMatch = true;
data.isMatch = true;
data.rowArray = data.$cells.map( function( i ) { data.rowArray = data.$cells.map( function( i ) {
if ( $.inArray( i, columnIndex ) > -1 ) { if ( $.inArray( i, columnIndex ) > -1 ) {
if ( data.parsed[ i ] ) { if ( data.parsed[ i ] ) {
@ -910,16 +963,10 @@ ts.filter = {
data.exact = data.rowArray.join( ' ' ); data.exact = data.rowArray.join( ' ' );
data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact; data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' ); data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
filterMatched = null;
matches = null; vars.excludeMatch = vars.noAnyMatch;
for ( ffxn in ts.filter.types ) { filterMatched = ts.filter.processTypes( c, data, vars );
if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
matches = ts.filter.types[ffxn]( c, data );
if ( matches !== null ) {
filterMatched = matches;
}
}
}
if ( filterMatched !== null ) { if ( filterMatched !== null ) {
showRow = filterMatched; showRow = filterMatched;
} else { } else {
@ -946,7 +993,7 @@ ts.filter = {
data.index = columnIndex; data.index = columnIndex;
// filter types to exclude, per column // filter types to exclude, per column
excludeMatch = vars.excludeFilter[ columnIndex ]; vars.excludeMatch = vars.excludeFilter[ columnIndex ];
// ignore if filter is empty or disabled // ignore if filter is empty or disabled
if ( data.filter ) { if ( data.filter ) {
@ -960,6 +1007,9 @@ ts.filter = {
} }
data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ? data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
data.exact.toLowerCase() : data.exact; data.exact.toLowerCase() : data.exact;
data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
result = showRow; // if showRow is true, show that row 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' // 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.filter = case sensitive
data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter; data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
fxn = vars.functions[ columnIndex ]; fxn = vars.functions[ columnIndex ];
$cell = c.$headerIndexed[ columnIndex ]; hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
hasSelect = $cell.hasClass( 'filter-select' );
filterMatched = null; filterMatched = null;
if ( fxn || ( hasSelect && val ) ) { if ( fxn || ( hasSelect && val ) ) {
if ( fxn === true || hasSelect ) { if ( fxn === true || hasSelect ) {
// default selector uses exact match unless 'filter-match' class is found // 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.iExact.search( data.iFilter ) >= 0 :
data.filter === data.exact; data.filter === data.exact;
} else if ( typeof fxn === 'function' ) { } else if ( typeof fxn === 'function' ) {
@ -1007,15 +1056,7 @@ ts.filter = {
if ( filterMatched === null ) { if ( filterMatched === null ) {
// cycle through the different filters // cycle through the different filters
// filters return a boolean or null if nothing matches // filters return a boolean or null if nothing matches
matches = null; filterMatched = ts.filter.processTypes( c, data, vars );
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;
}
}
}
if ( filterMatched !== null ) { if ( filterMatched !== null ) {
result = filterMatched; result = filterMatched;
// Look for match, and add child row data for matching // Look for match, and add child row data for matching

View File

@ -148,7 +148,7 @@ $(function(){
wo = this.wo, wo = this.wo,
$table = this.$table, $table = this.$table,
table = this.table; table = this.table;
expect(27); expect(31);
return QUnit.SequentialRunner( return QUnit.SequentialRunner(
function(actions, assertions) { function(actions, assertions) {
@ -205,6 +205,18 @@ $(function(){
).nextTask( ).nextTask(
function(){ ts.setFilters( table, ['', 'br && cl'], true ); }, function(){ ts.setFilters( table, ['', 'br && cl'], true ); },
function(){ assert.cacheCompare( table, 1, ['Brandon Clark'], 'search and match; ensure search filtered gets cleared', 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( ).nextTask(
function(){ ts.setFilters( table, ['', 'alex|br*'], true ); }, function(){ ts.setFilters( table, ['', 'alex|br*'], true ); },
function(){ assert.cacheCompare( table, 1, ['Brandon Clark', 'Bruce', 'Alex', 'Bruce Lee', 'Brenda Dexter'], 'search OR match', true ); } function(){ assert.cacheCompare( table, 1, ['Brandon Clark', 'Bruce', 'Alex', 'Bruce Lee', 'Brenda Dexter'], 'search OR match', true ); }