version bump

This commit is contained in:
Mottie 2015-08-23 13:22:56 -05:00
parent aa315b1e88
commit 68ae07cb79
15 changed files with 761 additions and 580 deletions

View File

@ -82,6 +82,21 @@ If you would like to contribute, please...
View the [complete change log here](//github.com/Mottie/tablesorter/wiki/Changes).
#### <a name="v2.23.2">Version 2.23.2</a> (8/23/2015)
* Readme
* Corrections for last update
* Docs
* Add parsed values function no longer wraps empty content.
* Core
* Cache regular expressions.
* ColumnSelector
* Add `columnSelector_updated` option (triggered event name).
* Filter
* Allow dynamically changing the "any match" filter. Fixes [issue #998](https://github.com/Mottie/tablesorter/issues/998).
* Cache regular expressions.
* Add reference to widget code to make the file more compressible.
#### <a name="v2.23.1">Version 2.23.1</a> (8/19/2015)
* Core
@ -154,9 +169,3 @@ View the [complete change log here](//github.com/Mottie/tablesorter/wiki/Changes
* Miscellaneous cleanup of testing code.
* Add empty `ignore` entry to bower.json. Fixes [issue #991](https://github.com/Mottie/tablesorter/issues/991).
* Fix license in package.json to match the new spdx license expression syntax.
#### <a name="v2.22.5">Version 2.22.5</a> (7/28/2015)
* Overall:
* Set JSHint "undef" & "unused" options. Fixed issues.
* The math widget was throwing a javascript error after missing a changed variable name & JSHint wasn't catching it, until now.

View File

@ -1,4 +1,4 @@
/*! tablesorter (FORK) - updated 08-21-2015 (v2.23.1)*/
/*! tablesorter (FORK) - updated 08-23-2015 (v2.23.2)*/
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) {
if (typeof define === 'function' && define.amd) {
@ -10,7 +10,7 @@
}
}(function($) {
/*! TableSorter (FORK) v2.23.1 *//*
/*! TableSorter (FORK) v2.23.2 *//*
* Client-side table sorting with ease!
* @requires jQuery v1.2.6+
*
@ -38,7 +38,7 @@
var ts = this;
ts.version = '2.23.1';
ts.version = '2.23.2';
ts.parsers = [];
ts.widgets = [];
@ -163,6 +163,15 @@
nextNone : 'activate to remove the sort'
};
ts.regex = {
templateContent : /\{content\}/g,
templateIcon : /\{icon\}/g,
templateName : /\{name\}/i,
spaces : /\s+/g,
nonWord : /\W/g,
formElements : /(input|select|button|textarea)/i
};
// These methods can be applied on table.config instance
ts.instanceMethods = {};
@ -455,7 +464,9 @@
// if headerTemplate is empty, don't reformat the header cell
if ( c.headerTemplate !== '' && !$t.find('.' + ts.css.headerIn).length ) {
// set up header template
t = c.headerTemplate.replace(/\{content\}/g, $t.html()).replace(/\{icon\}/g, $t.find('.' + ts.css.icon).length ? '' : i);
t = c.headerTemplate
.replace(ts.regex.templateContent, $t.html())
.replace(ts.regex.templateIcon, $t.find('.' + ts.css.icon).length ? '' : i);
if (c.onRenderTemplate) {
h = c.onRenderTemplate.apply( $t, [ index, t ] );
if (h && typeof h === 'string') { t = h; } // only change t if something is returned
@ -868,7 +879,7 @@
.join( c.namespace + ' ' );
// apply easy methods that trigger bound events
$table
.unbind( events.replace( /\s+/g, ' ' ) )
.unbind( events.replace( ts.regex.spaces, ' ' ) )
.bind( 'sortReset' + c.namespace, function( e, callback ) {
e.stopPropagation();
// using this.config to ensure functions are getting a non-cached version of the config
@ -1015,7 +1026,7 @@
c.namespace = '.tablesorter' + Math.random().toString(16).slice(2);
} else {
// make sure namespace starts with a period & doesn't have weird characters
c.namespace = '.' + c.namespace.replace(/\W/g, '');
c.namespace = '.' + c.namespace.replace(ts.regex.nonWord, '');
}
c.$table.children().children('tr').attr('role', 'row');
@ -1243,7 +1254,7 @@
}
}
t = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' )
.replace(/\s+/g, ' ')
.replace(ts.regex.spaces, ' ')
.split(' ')
.join(c.namespace + ' ');
// apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)
@ -1277,7 +1288,7 @@
}
downTarget = null;
// prevent sort being triggered on form elements
if ( /(input|select|button|textarea)/i.test(e.target.nodeName) ||
if ( ts.regex.formElements.test(e.target.nodeName) ||
// nosort class name, or elements within a nosort container
$target.hasClass(c.cssNoSort) || $target.parents('.' + c.cssNoSort).length > 0 ||
// elements within a button
@ -1563,13 +1574,13 @@
.join(c.namespace + ' ');
$t
.removeData('tablesorter')
.unbind( events.replace(/\s+/g, ' ') );
.unbind( events.replace(ts.regex.spaces, ' ') );
c.$headers.add($f)
.removeClass( [ ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone ].join(' ') )
.removeAttr('data-column')
.removeAttr('aria-label')
.attr('aria-disabled', 'true');
$r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(/\s+/g, ' ') );
$r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(ts.regex.spaces, ' ') );
ts.restoreHeaders(table);
$t.toggleClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false);
// clear flag in case the plugin is initialized again
@ -1585,11 +1596,9 @@
// *** sort functions ***
// regex used in natural sort
ts.regex = {
chunk : /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters
chunks: /(^\\0|\\0$)/, // replace chunks @ ends
hex: /^0x[0-9a-f]+$/i // hex
};
ts.regex.chunk = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi; // chunk/tokenize numbers & letters
ts.regex.chunks = /(^\\0|\\0$)/; // replace chunks @ ends
ts.regex.hex = /^0x[0-9a-f]+$/i; // hex
// Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)
// this function will only accept strings, or you'll see 'TypeError: undefined is not a function'
@ -1816,7 +1825,7 @@
if (c.debug) { time = new Date(); }
// look for widgets to apply from in table class
// stop using \b otherwise this matches 'ui-widget-content' & adds 'content' widget
wd = new RegExp( '\\s' + c.widgetClass.replace( /\{name\}/i, '([\\w-]+)' ) + '\\s', 'g' );
wd = new RegExp( '\\s' + c.widgetClass.replace( ts.regex.templateName, '([\\w-]+)' ) + '\\s', 'g' );
if ( tableClass.match( wd ) ) {
// extract out the widget id from the table class (widget id's can include dashes)
w = tableClass.match( wd );
@ -2042,6 +2051,10 @@
return $.trim(val);
};
ts.regex.comma = /,/g;
ts.regex.digitNonUS = /[\s|\.]/g;
ts.regex.digitNegativeTest = /^\s*\([.\d]+\)/;
ts.regex.digitNegativeReplace = /^\s*\(([.\d]+)\)/;
ts.formatFloat = function(s, table) {
if (typeof s !== 'string' || s === '') { return s; }
// allow using formatFloat without a table; defaults to US number format
@ -2050,24 +2063,28 @@
typeof table !== 'undefined' ? table : true;
if (t) {
// US Format - 1,234,567.89 -> 1234567.89
s = s.replace(/,/g, '');
s = s.replace(ts.regex.comma, '');
} else {
// German Format = 1.234.567,89 -> 1234567.89
// French Format = 1 234 567,89 -> 1234567.89
s = s.replace(/[\s|\.]/g, '').replace(/,/g, '.');
s = s.replace(ts.regex.digitNonUS, '').replace(ts.regex.comma, '.');
}
if (/^\s*\([.\d]+\)/.test(s)) {
if (ts.regex.digitNegativeTest.test(s)) {
// make (#) into a negative number -> (10) = -10
s = s.replace(/^\s*\(([.\d]+)\)/, '-$1');
s = s.replace(ts.regex.digitNegativeReplace, '-$1');
}
i = parseFloat(s);
// return the text instead of zero
return isNaN(i) ? $.trim(s) : i;
};
ts.regex.digitTest = /^[\-+(]?\d+[)]?$/;
ts.regex.digitReplace = /[,.'"\s]/g;
ts.isDigit = function(s) {
// replace all unwanted chars and match
return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : s !== '';
return isNaN(s) ?
ts.regex.digitTest.test( s.toString().replace( ts.regex.digitReplace, '' ) ) :
s !== '';
};
}()
@ -2126,65 +2143,76 @@
type: 'text'
});
ts.regex.nondigit = /[^\w,. \-()]/g;
ts.addParser({
id: 'digit',
is: function(s) {
return ts.isDigit(s);
},
format: function(s, table) {
var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
var n = ts.formatFloat((s || '').replace(ts.regex.nondigit, ''), table);
return s && typeof n === 'number' ? n :
s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
},
type: 'numeric'
});
ts.regex.currencyReplace = /[+\-,. ]/g;
ts.regex.currencyTest = /^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/;
ts.addParser({
id: 'currency',
is: function(s) {
s = (s || '').replace(/[+\-,. ]/g, '');
s = (s || '').replace(ts.regex.currencyReplace, '');
// test for £$€¤¥¢
return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test(s);
return ts.regex.currencyTest.test(s);
},
format: function(s, table) {
var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
var n = ts.formatFloat((s || '').replace(ts.regex.nondigit, ''), table);
return s && typeof n === 'number' ? n :
s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
},
type: 'numeric'
});
// too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme
// now, this regex can be updated before initialization
ts.regex.urlProtocolTest = /^(https?|ftp|file):\/\//;
ts.regex.urlProtocolReplace = /(https?|ftp|file):\/\//;
ts.addParser({
id: 'url',
is: function(s) {
return (/^(https?|ftp|file):\/\//).test(s);
return ts.regex.urlProtocolTest.test(s);
},
format: function(s) {
return s ? $.trim(s.replace(/(https?|ftp|file):\/\//, '')) : s;
return s ? $.trim(s.replace(ts.regex.urlProtocolReplace, '')) : s;
},
parsed : true, // filter widget flag
type: 'text'
});
ts.regex.dash = /-/g;
ts.regex.isoDate = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/;
ts.addParser({
id: 'isoDate',
is: function(s) {
return (/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/).test(s);
return ts.regex.isoDate.test(s);
},
format: function(s, table) {
var date = s ? new Date( s.replace(/-/g, '/') ) : s;
var date = s ? new Date( s.replace(ts.regex.dash, '/') ) : s;
return date instanceof Date && isFinite(date) ? date.getTime() : s;
},
type: 'numeric'
});
ts.regex.percent = /%/g;
ts.regex.percentTest = /(\d\s*?%|%\s*?\d)/;
ts.addParser({
id: 'percent',
is: function(s) {
return (/(\d\s*?%|%\s*?\d)/).test(s) && s.length < 15;
return ts.regex.percentTest.test(s) && s.length < 15;
},
format: function(s, table) {
return s ? ts.formatFloat(s.replace(/%/g, ''), table) : s;
return s ? ts.formatFloat(s.replace(ts.regex.percent, ''), table) : s;
},
type: 'numeric'
});
@ -2202,27 +2230,35 @@
type: 'text'
});
ts.regex.dateReplace = /(\S)([AP]M)$/i; // used by usLongDate & time parser
ts.regex.usLongDateTest1 = /^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i;
ts.regex.usLongDateTest2 = /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i;
ts.addParser({
id: 'usLongDate',
is: function(s) {
// two digit years are not allowed cross-browser
// Jan 01, 2013 12:34:56 PM or 01 Jan 2013
return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) ||
(/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s);
return ts.regex.usLongDateTest1.test(s) || ts.regex.usLongDateTest2.test(s);
},
format: function(s, table) {
var date = s ? new Date( s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s;
var date = s ? new Date( s.replace(ts.regex.dateReplace, '$1 $2') ) : s;
return date instanceof Date && isFinite(date) ? date.getTime() : s;
},
type: 'numeric'
});
// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
ts.regex.shortDateTest = /(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/;
// escaped "-" because JSHint in Firefox was showing it as an error
ts.regex.shortDateReplace = /[\-.,]/g;
// XXY covers MDY & DMY formats
ts.regex.shortDateXXY = /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/;
ts.regex.shortDateYMD = /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/;
ts.addParser({
id: 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
is: function(s) {
s = (s || '').replace(/\s+/g, ' ').replace(/[\-.,]/g, '/');
// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test(s);
s = (s || '').replace(ts.regex.spaces, ' ').replace(ts.regex.shortDateReplace, '/');
return ts.regex.shortDateTest.test(s);
},
format: function(s, table, cell, cellIndex) {
if (s) {
@ -2232,14 +2268,13 @@
format = ci.length && ci[0].dateFormat ||
ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') ||
c.dateFormat;
// escaped "-" because JSHint in Firefox was showing it as an error
d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/');
d = s.replace(ts.regex.spaces, ' ').replace(ts.regex.shortDateReplace, '/');
if (format === 'mmddyyyy') {
d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$1/$2');
d = d.replace(ts.regex.shortDateXXY, '$3/$1/$2');
} else if (format === 'ddmmyyyy') {
d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$2/$1');
d = d.replace(ts.regex.shortDateXXY, '$3/$2/$1');
} else if (format === 'yyyymmdd') {
d = d.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, '$1/$2/$3');
d = d.replace(ts.regex.shortDateYMD, '$1/$2/$3');
}
date = new Date(d);
return date instanceof Date && isFinite(date) ? date.getTime() : s;
@ -2249,13 +2284,14 @@
type: 'numeric'
});
ts.regex.timeTest = /^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i;
ts.addParser({
id: 'time',
is: function(s) {
return (/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i).test(s);
return ts.regex.timeTest.test(s);
},
format: function(s, table) {
var date = s ? new Date( '2000/01/01 ' + s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s;
var date = s ? new Date( '2000/01/01 ' + s.replace(ts.regex.dateReplace, '$1 $2') ) : s;
return date instanceof Date && isFinite(date) ? date.getTime() : s;
},
type: 'numeric'
@ -2672,14 +2708,15 @@
})(jQuery);
/*! Widget: filter - updated 8/17/2015 (v2.23.0) *//*
/*! Widget: filter - updated 8/23/2015 (v2.23.2) *//*
* Requires tablesorter v2.8+ and jQuery 1.7+
* by Rob Garrison
*/
;( function ( $ ) {
'use strict';
var ts = $.tablesorter || {},
tscss = ts.css;
var tsf,
ts = $.tablesorter || {},
tscss = ts.css;
$.extend( tscss, {
filterRow : 'tablesorter-filter-row',
@ -2723,7 +2760,7 @@
},
format: function( table, c, wo ) {
if ( !c.$table.hasClass( 'hasFilters' ) ) {
ts.filter.init( table, c, wo );
tsf.init( table, c, wo );
}
},
remove: function( table, c, wo, refreshing ) {
@ -2735,7 +2772,7 @@
$table
.removeClass( 'hasFilters' )
// add .tsfilter namespace to all BUT search
.unbind( events.replace( /\s+/g, ' ' ) )
.unbind( events.replace( ts.regex.spaces, ' ' ) )
// remove the filter row even if refreshing, because the column might have been moved
.find( '.' + tscss.filterRow ).remove();
if ( refreshing ) { return; }
@ -2750,7 +2787,7 @@
}
});
ts.filter = {
tsf = ts.filter = {
// regex used in filter 'check' functions - not for general use and not documented
regex: {
@ -2759,9 +2796,13 @@
filtered : /filtered/, // filtered (hidden) row class name; updated in the script
type : /undefined|number/, // check type
exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==')
nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser)
operators : /[<>=]/g, // replace operators
query : '(q|query)' // replace filter queries
query : '(q|query)', // replace filter queries
wild01 : /\?/g, // wild card match 0 or 1
wild0More : /\*/g, // wild care match 0 or more
quote : /\"/g,
isNeg1 : /(>=?\s*-\d)/,
isNeg2 : /(<=?\s*\d)/
},
// function( c, data ) { }
// c = table.config
@ -2778,27 +2819,27 @@
// 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 ) ) {
if ( tsf.regex.orTest.test( data.iFilter ) || tsf.regex.orSplit.test( data.filter ) ) {
var indx, filterMatched, 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 ),
filter = data.filter.split( tsf.regex.orSplit ),
iFilter = data.iFilter.split( tsf.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 ) || '' ) + ')';
data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
query = '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
try {
// use try/catch, because query may not be a valid regex if "|" is contained within a partial regex search,
// e.g "/(Alex|Aar" -> Uncaught SyntaxError: Invalid regular expression: /(/(Alex)/: Unterminated group
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 );
filterMatched = regex.test( data2.exact ) || tsf.processTypes( c, data2, vars );
if ( filterMatched ) {
return filterMatched;
}
@ -2813,27 +2854,27 @@
},
// Look for an AND or && operator ( logical and )
and : function( c, data, vars ) {
if ( ts.filter.regex.andTest.test( data.filter ) ) {
if ( tsf.regex.andTest.test( data.filter ) ) {
var indx, filterMatched, result, 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 ),
filter = data.filter.split( tsf.regex.andSplit ),
iFilter = data.iFilter.split( tsf.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 ) || '' ) + ')' )
data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
query = ( '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
// replace wild cards since /(a*)/i will match anything
.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
.replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' );
try {
// use try/catch just in case RegExp is invalid
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 ) );
result = ( regex.test( data2.exact ) || tsf.processTypes( c, data2, vars ) );
if ( indx === 0 ) {
filterMatched = result;
} else {
@ -2850,10 +2891,10 @@
},
// Look for regex
regex: function( c, data ) {
if ( ts.filter.regex.regex.test( data.filter ) ) {
if ( tsf.regex.regex.test( data.filter ) ) {
var matches,
// cache regex per column for optimal speed
regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
regex = data.filter_regexCache[ data.index ] || tsf.regex.regex.exec( data.filter ),
isRegex = regex instanceof RegExp;
try {
if ( !isRegex ) {
@ -2872,18 +2913,18 @@
// Look for operators >, >=, < or <=
operators: function( c, data ) {
// ignore empty strings... because '' < 10 is true
if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) {
if ( tsf.regex.operTest.test( data.iFilter ) && data.iExact !== '' ) {
var cachedValue, result, txt,
table = c.table,
index = data.index,
parsed = data.parsed[index],
query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ),
query = ts.formatFloat( data.iFilter.replace( tsf.regex.operators, '' ), table ),
parser = c.parsers[index],
savedSearch = query;
// parse filter value in case we're comparing numbers ( dates )
if ( parsed || parser.type === 'numeric' ) {
txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) );
result = ts.filter.parseFilter( c, txt, index, true );
txt = $.trim( '' + data.iFilter.replace( tsf.regex.operators, '' ) );
result = tsf.parseFilter( c, txt, index, true );
query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
}
// iExact may be numeric - see issue #149;
@ -2892,13 +2933,13 @@
typeof data.cache !== 'undefined' ) {
cachedValue = data.cache;
} else {
txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
txt = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
cachedValue = ts.formatFloat( txt, table );
}
if ( />/.test( data.iFilter ) ) {
result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
} else if ( /</.test( data.iFilter ) ) {
result = /<=/.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
if ( tsf.regex.gtTest.test( data.iFilter ) ) {
result = tsf.regex.gteTest.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
} else if ( tsf.regex.ltTest.test( data.iFilter ) ) {
result = tsf.regex.lteTest.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
}
// keep showing all rows if nothing follows the operator
if ( !result && savedSearch === '' ) {
@ -2910,13 +2951,13 @@
},
// Look for a not match
notMatch: function( c, data ) {
if ( /^\!/.test( data.iFilter ) ) {
if ( tsf.regex.notTest.test( data.iFilter ) ) {
var indx,
txt = data.iFilter.replace( '!', '' ),
filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( ts.filter.regex.exact.test( filter ) ) {
filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( tsf.regex.exact.test( filter ) ) {
// look for exact not matches - see #628
filter = filter.replace( ts.filter.regex.exact, '' );
filter = filter.replace( tsf.regex.exact, '' );
return filter === '' ? true : $.trim( filter ) !== data.iExact;
} else {
indx = data.iExact.search( $.trim( filter ) );
@ -2928,27 +2969,27 @@
// Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
exact: function( c, data ) {
/*jshint eqeqeq:false */
if ( ts.filter.regex.exact.test( data.iFilter ) ) {
var txt = data.iFilter.replace( ts.filter.regex.exact, '' ),
filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( tsf.regex.exact.test( data.iFilter ) ) {
var txt = data.iFilter.replace( tsf.regex.exact, '' ),
filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
}
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 ) ) {
if ( tsf.regex.toTest.test( data.iFilter ) ) {
var result, tmp, range1, range2,
table = c.table,
index = data.index,
parsed = data.parsed[index],
// make sure the dash is for a range and not indicating a negative number
query = data.iFilter.split( ts.filter.regex.toSplit );
query = data.iFilter.split( tsf.regex.toSplit );
tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || '';
range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || '';
range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
tmp = query[0].replace( ts.regex.nondigit, '' ) || '';
range1 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
tmp = query[1].replace( ts.regex.nondigit, '' ) || '';
range2 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
// parse filter value in case we're comparing numbers ( dates )
if ( parsed || c.parsers[index].type === 'numeric' ) {
result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
@ -2959,7 +3000,7 @@
if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
result = data.cache;
} else {
tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
result = ts.formatFloat( tmp, table );
}
if ( range1 > range2 ) {
@ -2971,18 +3012,18 @@
},
// Look for wild card: ? = single, * = multiple, or | = logical OR
wild : function( c, data ) {
if ( /[\?\*\|]/.test( data.iFilter ) ) {
if ( tsf.regex.wildOrTest.test( data.iFilter ) ) {
var index = data.index,
parsed = data.parsed[ index ],
query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
query = '' + ( tsf.parseFilter( c, data.iFilter, index, parsed ) || '' );
// look for an exact match with the 'or' unless the 'filter-match' class is found
if ( !/\?\*/.test( query ) && data.nestedFilters ) {
if ( !tsf.regex.wildTest.test( query ) && data.nestedFilters ) {
query = data.isMatch ? query : '^(' + query + ')$';
}
// parsing the filter may not work properly when using wildcards =/
try {
return new RegExp(
query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
query.replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' ),
c.widgetOptions.filter_ignoreCase ? 'i' : ''
)
.test( data.exact );
@ -2994,12 +3035,12 @@
},
// fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
fuzzy: function( c, data ) {
if ( /^~/.test( data.iFilter ) ) {
if ( tsf.regex.fuzzyTest.test( data.iFilter ) ) {
var indx,
patternIndx = 0,
len = data.iExact.length,
txt = data.iFilter.slice( 1 ),
pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
pattern = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
for ( indx = 0; indx < len; indx++ ) {
if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
patternIndx += 1;
@ -3022,7 +3063,7 @@
}, ts.language );
var options, string, txt, $header, column, filters, val, fxn, noSelect,
regex = ts.filter.regex;
regex = tsf.regex;
c.$table.addClass( 'hasFilters' );
// define timers so using clearTimeout won't cause an undefined error
@ -3033,7 +3074,7 @@
wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
val = '\\{' + ts.filter.regex.query + '\\}';
val = '\\{' + tsf.regex.query + '\\}';
$.extend( regex, {
child : new RegExp( c.cssChildRow ),
filtered : new RegExp( wo.filter_filteredRow ),
@ -3042,9 +3083,20 @@
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' ),
orTest : /\|/,
orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
iQuery : new RegExp( val, 'i' ),
igQuery : new RegExp( val, 'ig' )
igQuery : new RegExp( val, 'ig' ),
operTest : /^[<>]=?/,
gtTest : />/,
gteTest : />=/,
ltTest : /</,
lteTest : /<=/,
notTest : /^\!/,
wildOrTest : /[\?\*\|]/,
wildTest : /\?\*/,
fuzzyTest : /^~/,
exactTest : /[=\"\|!]/
});
// don't build filter row if columnFilters is false or all columns are set to 'filter-false'
@ -3052,7 +3104,7 @@
val = c.$headers.filter( '.filter-false, .parser-false' ).length;
if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
// build filter row
ts.filter.buildRow( table, c, wo );
tsf.buildRow( table, c, wo );
}
txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
@ -3065,13 +3117,13 @@
c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
if ( !/(search|filter)/.test( event.type ) ) {
event.stopPropagation();
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
}
if ( event.type === 'filterReset' ) {
c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
ts.filter.searching( table, [] );
tsf.searching( table, [] );
} else if ( event.type === 'filterEnd' ) {
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
} else {
// send false argument to force a new search; otherwise if the filter hasn't changed,
// it will return
@ -3085,7 +3137,7 @@
// pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
// input ensures all inputs are updated when a search is triggered on the table
// $( 'table' ).trigger( 'search', [...] );
ts.filter.searching( table, filter, true );
tsf.searching( table, filter, true );
}
return false;
});
@ -3118,7 +3170,7 @@
noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
options = '';
if ( fxn === true && noSelect ) {
ts.filter.buildSelect( table, column );
tsf.buildSelect( table, column );
} else if ( typeof fxn === 'object' && noSelect ) {
// add custom drop down list
for ( string in fxn ) {
@ -3151,7 +3203,7 @@
fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column );
if ( fxn ) {
// updating so the extra options are appended
ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
tsf.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
}
}
}
@ -3159,22 +3211,22 @@
}
// not really updating, but if the column has both the 'filter-select' class &
// filter_functions set to true, it would append the same options twice.
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
tsf.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
if ( wo.filter_external ) {
ts.filter.bindSearch( table, wo.filter_external );
tsf.bindSearch( table, wo.filter_external );
}
if ( wo.filter_hideFilters ) {
ts.filter.hideFilters( table, c );
tsf.hideFilters( table, c );
}
// show processing icon
if ( c.showProcessing ) {
txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
c.$table
.unbind( txt.replace( /\s+/g, ' ' ) )
.unbind( txt.replace( ts.regex.spaces, ' ' ) )
.bind( txt, function( event, columns ) {
// only add processing to certain columns to all columns
$header = ( columns ) ?
@ -3194,11 +3246,11 @@
// add default values
txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
c.$table
.unbind( txt.replace( /\s+/g, ' ' ) )
.unbind( txt.replace( ts.regex.spaces, ' ' ) )
.bind( txt, function() {
// redefine 'wo' as it does not update properly inside this callback
var wo = this.config.widgetOptions;
filters = ts.filter.setDefaults( table, c, wo ) || [];
filters = tsf.setDefaults( table, c, wo ) || [];
if ( filters.length ) {
// prevent delayInit from triggering a cache build if filters are empty
if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
@ -3209,7 +3261,7 @@
// trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
setTimeout( function() {
if ( !wo.filter_initialized ) {
ts.filter.filterInitComplete( c );
tsf.filterInitComplete( c );
}
}, 100 );
});
@ -3217,7 +3269,7 @@
if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
c.$table.trigger( 'filterFomatterUpdate' );
setTimeout( function() {
ts.filter.filterInitComplete( c );
tsf.filterInitComplete( c );
}, 100 );
}
},
@ -3238,7 +3290,7 @@
completed = function() {
wo.filter_initialized = true;
c.$table.trigger( 'filterInit', c );
ts.filter.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
tsf.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
};
if ( $.isEmptyObject( wo.filter_formatter ) ) {
completed();
@ -3390,7 +3442,7 @@
// use data attribute instead of jQuery data since the head is cloned without including
// the data/binding
.attr( 'data-lastSearchTime', new Date().getTime() )
.unbind( tmp.replace( /\s+/g, ' ' ) )
.unbind( tmp.replace( ts.regex.spaces, ' ' ) )
// include change for select - fixes #473
.bind( 'keyup' + namespace, function( event ) {
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
@ -3410,7 +3462,7 @@
return;
}
// change event = no delay; last true flag tells getFilters to skip newest timed input
ts.filter.searching( table, true, true );
tsf.searching( table, true, true );
})
.bind( 'search change keypress '.split( ' ' ).join( namespace + ' ' ), function( event ) {
// don't get cached data, in case data-column changes dynamically
@ -3421,7 +3473,7 @@
event.preventDefault();
// init search with no delay
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
ts.filter.searching( table, false, true );
tsf.searching( table, false, true );
}
});
},
@ -3431,11 +3483,11 @@
if ( typeof filter === 'undefined' || filter === true ) {
// delay filtering
wo.searchTimer = setTimeout( function() {
ts.filter.checkFilters( table, filter, skipFirst );
tsf.checkFilters( table, filter, skipFirst );
}, wo.filter_liveSearch ? wo.filter_searchDelay : 10 );
} else {
// skip delay
ts.filter.checkFilters( table, filter, skipFirst );
tsf.checkFilters( table, filter, skipFirst );
}
},
checkFilters: function( table, filter, skipFirst ) {
@ -3449,7 +3501,7 @@
// update cache if delayInit set & pager has initialized ( after user initiates a search )
if ( c.delayInit && c.pager && c.pager.initialized ) {
c.$table.trigger( 'updateCache', [ function() {
ts.filter.checkFilters( table, false, skipFirst );
tsf.checkFilters( table, false, skipFirst );
} ] );
}
return;
@ -3480,11 +3532,11 @@
if ( c.showProcessing ) {
// give it time for the processing icon to kick in
setTimeout( function() {
ts.filter.findRows( table, filters, combinedFilters );
tsf.findRows( table, filters, combinedFilters );
return false;
}, 30 );
} else {
ts.filter.findRows( table, filters, combinedFilters );
tsf.findRows( table, filters, combinedFilters );
return false;
}
},
@ -3527,8 +3579,8 @@
},
defaultFilter: function( filter, mask ) {
if ( filter === '' ) { return filter; }
var regex = ts.filter.regex.iQuery,
maskLen = mask.match( ts.filter.regex.igQuery ).length,
var regex = tsf.regex.iQuery,
maskLen = mask.match( tsf.regex.igQuery ).length,
query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
len = query.length - 1,
indx = 0,
@ -3564,7 +3616,7 @@
// & don't target 'all' column inputs if they don't exist
targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
columns = [],
val = $.trim( ts.filter.getLatestSearch( $input ).attr( 'data-column' ) || '' );
val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
if ( !/[,-]/.test(val) && val.length === 1 ) {
return parseInt( val, 10 );
}
@ -3614,9 +3666,9 @@
var ffxn,
filterMatched = null,
matches = null;
for ( ffxn in ts.filter.types ) {
for ( ffxn in tsf.types ) {
if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
matches = ts.filter.types[ffxn]( c, data, vars );
matches = tsf.types[ffxn]( c, data, vars );
if ( matches !== null ) {
filterMatched = matches;
}
@ -3627,7 +3679,7 @@
processRow: function( c, data, vars ) {
var hasSelect, result, val, filterMatched,
fxn, ffxn, txt,
regex = ts.filter.regex,
regex = tsf.regex,
wo = c.widgetOptions,
showRow = true,
@ -3636,7 +3688,7 @@
// for the entire row - see #998
columnIndex = wo.filter_$anyMatch && wo.filter_$anyMatch.length ?
// look for multiple columns '1-3,4-6,8'
ts.filter.multipleColumns( c, wo.filter_$anyMatch ) :
tsf.multipleColumns( c, wo.filter_$anyMatch ) :
[];
data.$cells = data.$row.children();
@ -3665,7 +3717,7 @@
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
vars.excludeMatch = vars.noAnyMatch;
filterMatched = ts.filter.processTypes( c, data, vars );
filterMatched = tsf.processTypes( c, data, vars );
if ( filterMatched !== null ) {
showRow = filterMatched;
@ -3726,7 +3778,7 @@
val = true;
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
data.filter = ts.filter.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
data.filter = tsf.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
// val is used to indicate that a filter select is using a default filter;
// so we override the exact & partial matches
val = false;
@ -3757,13 +3809,13 @@
if ( filterMatched === null ) {
// cycle through the different filters
// filters return a boolean or null if nothing matches
filterMatched = ts.filter.processTypes( c, data, vars );
filterMatched = tsf.processTypes( c, data, vars );
if ( filterMatched !== null ) {
result = filterMatched;
// Look for match, and add child row data for matching
} else {
txt = ( data.iExact + data.childRowText )
.indexOf( ts.filter.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
.indexOf( tsf.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
}
} else {
@ -3783,7 +3835,7 @@
isChild, childRow, lastSearch, showRow, time, val, indx,
notFiltered, searchFiltered, query, injected, res, id, txt,
storedFilters = $.extend( [], filters ),
regex = ts.filter.regex,
regex = tsf.regex,
c = table.config,
wo = c.widgetOptions,
// data object passed to filters; anyMatch is a flag for the filters
@ -3860,7 +3912,7 @@
data.anyMatchFlag = true;
data.anyMatchFilter = '' + (
filters[ c.columns ] ||
wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() ||
wo.filter_$anyMatch && tsf.getLatestSearch( wo.filter_$anyMatch ).val() ||
''
);
if ( wo.filter_columnAnyMatch ) {
@ -3902,10 +3954,10 @@
// if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
!regex.alreadyFiltered.test( val ) &&
// if we are not doing exact matches, using '|' ( logical or ) or not '!'
!/[=\"\|!]/.test( val ) &&
!regex.exactTest.test( val ) &&
// don't search only filtered if the value is negative
// ( '> -10' => '> -100' will ignore hidden rows )
!( /(>=?\s*-\d)/.test( val ) || /(<=?\s*\d)/.test( val ) ) &&
!( regex.isNeg1.test( val ) || regex.isNeg2.test( val ) ) &&
// if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
!( val !== '' && c.$filters && c.$filters.eq( indx ).find( 'select' ).length &&
!c.$headerIndexed[indx].hasClass( 'filter-match' ) );
@ -3924,7 +3976,7 @@
data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
}
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) {
data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
data.anyMatchFilter = tsf.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
// clear search filtered flag because default filters are not saved to the last search
searchFiltered = false;
}
@ -3967,7 +4019,7 @@
'';
}
showRow = ts.filter.processRow( c, data, vars );
showRow = tsf.processRow( c, data, vars );
childRow = rowData.$row.filter( ':gt( 0 )' );
if ( wo.filter_childRows && childRow.length ) {
@ -3978,7 +4030,7 @@
data.cacheArray = rowData.child[ indx ];
data.rawArray = data.cacheArray;
// use OR comparison on child rows
showRow = showRow || ts.filter.processRow( c, data, vars );
showRow = showRow || tsf.processRow( c, data, vars );
}
}
childRow.toggleClass( wo.filter_filteredRow, !showRow );
@ -4040,7 +4092,7 @@
}
if ( arry === false ) {
// fall back to original method
arry = ts.filter.getOptions( table, column, onlyAvail );
arry = tsf.getOptions( table, column, onlyAvail );
}
// get unique elements and sort the list
@ -4152,13 +4204,13 @@
// nothing included in arry ( external source ), so get the options from
// filter_selectSource or column data
if ( typeof arry === 'undefined' || arry === '' ) {
arry = ts.filter.getOptionSource( table, column, onlyAvail );
arry = tsf.getOptionSource( table, column, onlyAvail );
}
if ( $.isArray( arry ) ) {
// build option list
for ( indx = 0; indx < arry.length; indx++ ) {
txt = arry[indx] = ( '' + arry[indx] ).replace( /\"/g, '&quot;' );
txt = arry[indx] = ( '' + arry[indx] ).replace( tsf.regex.quote, '&quot;' );
val = txt;
// allow including a symbol in the selectSource array
// 'a-z|A through Z' so that 'a-z' becomes the option value
@ -4214,7 +4266,7 @@
// look for the filter-select class; build/update it if found
if ( ( $header.hasClass( 'filter-select' ) ||
ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
ts.filter.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
tsf.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
}
}
}
@ -4250,7 +4302,7 @@
$column = $filters.filter( cols );
if ( $column.length ) {
// move the latest search to the first slot in the array
$column = ts.filter.getLatestSearch( $column );
$column = tsf.getLatestSearch( $column );
if ( $.isArray( setFilters ) ) {
// skip first ( latest input ) to maintain cursor position while typing
if ( skipFirst && $column.length > 1 ) {
@ -4300,7 +4352,7 @@
// ensure new set filters are applied, even if the search is the same
c.lastCombinedFilter = null;
c.lastSearch = [];
ts.filter.searching( c.table, filter, skipFirst );
tsf.searching( c.table, filter, skipFirst );
c.$table.trigger( 'filterFomatterUpdate' );
}
return !!valid;

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@
}
}(function($) {
/*! TableSorter (FORK) v2.23.1 *//*
/*! TableSorter (FORK) v2.23.2 *//*
* Client-side table sorting with ease!
* @requires jQuery v1.2.6+
*
@ -36,7 +36,7 @@
var ts = this;
ts.version = '2.23.1';
ts.version = '2.23.2';
ts.parsers = [];
ts.widgets = [];
@ -161,6 +161,15 @@
nextNone : 'activate to remove the sort'
};
ts.regex = {
templateContent : /\{content\}/g,
templateIcon : /\{icon\}/g,
templateName : /\{name\}/i,
spaces : /\s+/g,
nonWord : /\W/g,
formElements : /(input|select|button|textarea)/i
};
// These methods can be applied on table.config instance
ts.instanceMethods = {};
@ -453,7 +462,9 @@
// if headerTemplate is empty, don't reformat the header cell
if ( c.headerTemplate !== '' && !$t.find('.' + ts.css.headerIn).length ) {
// set up header template
t = c.headerTemplate.replace(/\{content\}/g, $t.html()).replace(/\{icon\}/g, $t.find('.' + ts.css.icon).length ? '' : i);
t = c.headerTemplate
.replace(ts.regex.templateContent, $t.html())
.replace(ts.regex.templateIcon, $t.find('.' + ts.css.icon).length ? '' : i);
if (c.onRenderTemplate) {
h = c.onRenderTemplate.apply( $t, [ index, t ] );
if (h && typeof h === 'string') { t = h; } // only change t if something is returned
@ -866,7 +877,7 @@
.join( c.namespace + ' ' );
// apply easy methods that trigger bound events
$table
.unbind( events.replace( /\s+/g, ' ' ) )
.unbind( events.replace( ts.regex.spaces, ' ' ) )
.bind( 'sortReset' + c.namespace, function( e, callback ) {
e.stopPropagation();
// using this.config to ensure functions are getting a non-cached version of the config
@ -1013,7 +1024,7 @@
c.namespace = '.tablesorter' + Math.random().toString(16).slice(2);
} else {
// make sure namespace starts with a period & doesn't have weird characters
c.namespace = '.' + c.namespace.replace(/\W/g, '');
c.namespace = '.' + c.namespace.replace(ts.regex.nonWord, '');
}
c.$table.children().children('tr').attr('role', 'row');
@ -1241,7 +1252,7 @@
}
}
t = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' )
.replace(/\s+/g, ' ')
.replace(ts.regex.spaces, ' ')
.split(' ')
.join(c.namespace + ' ');
// apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)
@ -1275,7 +1286,7 @@
}
downTarget = null;
// prevent sort being triggered on form elements
if ( /(input|select|button|textarea)/i.test(e.target.nodeName) ||
if ( ts.regex.formElements.test(e.target.nodeName) ||
// nosort class name, or elements within a nosort container
$target.hasClass(c.cssNoSort) || $target.parents('.' + c.cssNoSort).length > 0 ||
// elements within a button
@ -1561,13 +1572,13 @@
.join(c.namespace + ' ');
$t
.removeData('tablesorter')
.unbind( events.replace(/\s+/g, ' ') );
.unbind( events.replace(ts.regex.spaces, ' ') );
c.$headers.add($f)
.removeClass( [ ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone ].join(' ') )
.removeAttr('data-column')
.removeAttr('aria-label')
.attr('aria-disabled', 'true');
$r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(/\s+/g, ' ') );
$r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(ts.regex.spaces, ' ') );
ts.restoreHeaders(table);
$t.toggleClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false);
// clear flag in case the plugin is initialized again
@ -1583,11 +1594,9 @@
// *** sort functions ***
// regex used in natural sort
ts.regex = {
chunk : /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters
chunks: /(^\\0|\\0$)/, // replace chunks @ ends
hex: /^0x[0-9a-f]+$/i // hex
};
ts.regex.chunk = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi; // chunk/tokenize numbers & letters
ts.regex.chunks = /(^\\0|\\0$)/; // replace chunks @ ends
ts.regex.hex = /^0x[0-9a-f]+$/i; // hex
// Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)
// this function will only accept strings, or you'll see 'TypeError: undefined is not a function'
@ -1814,7 +1823,7 @@
if (c.debug) { time = new Date(); }
// look for widgets to apply from in table class
// stop using \b otherwise this matches 'ui-widget-content' & adds 'content' widget
wd = new RegExp( '\\s' + c.widgetClass.replace( /\{name\}/i, '([\\w-]+)' ) + '\\s', 'g' );
wd = new RegExp( '\\s' + c.widgetClass.replace( ts.regex.templateName, '([\\w-]+)' ) + '\\s', 'g' );
if ( tableClass.match( wd ) ) {
// extract out the widget id from the table class (widget id's can include dashes)
w = tableClass.match( wd );
@ -2040,6 +2049,10 @@
return $.trim(val);
};
ts.regex.comma = /,/g;
ts.regex.digitNonUS = /[\s|\.]/g;
ts.regex.digitNegativeTest = /^\s*\([.\d]+\)/;
ts.regex.digitNegativeReplace = /^\s*\(([.\d]+)\)/;
ts.formatFloat = function(s, table) {
if (typeof s !== 'string' || s === '') { return s; }
// allow using formatFloat without a table; defaults to US number format
@ -2048,24 +2061,28 @@
typeof table !== 'undefined' ? table : true;
if (t) {
// US Format - 1,234,567.89 -> 1234567.89
s = s.replace(/,/g, '');
s = s.replace(ts.regex.comma, '');
} else {
// German Format = 1.234.567,89 -> 1234567.89
// French Format = 1 234 567,89 -> 1234567.89
s = s.replace(/[\s|\.]/g, '').replace(/,/g, '.');
s = s.replace(ts.regex.digitNonUS, '').replace(ts.regex.comma, '.');
}
if (/^\s*\([.\d]+\)/.test(s)) {
if (ts.regex.digitNegativeTest.test(s)) {
// make (#) into a negative number -> (10) = -10
s = s.replace(/^\s*\(([.\d]+)\)/, '-$1');
s = s.replace(ts.regex.digitNegativeReplace, '-$1');
}
i = parseFloat(s);
// return the text instead of zero
return isNaN(i) ? $.trim(s) : i;
};
ts.regex.digitTest = /^[\-+(]?\d+[)]?$/;
ts.regex.digitReplace = /[,.'"\s]/g;
ts.isDigit = function(s) {
// replace all unwanted chars and match
return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : s !== '';
return isNaN(s) ?
ts.regex.digitTest.test( s.toString().replace( ts.regex.digitReplace, '' ) ) :
s !== '';
};
}()
@ -2124,65 +2141,76 @@
type: 'text'
});
ts.regex.nondigit = /[^\w,. \-()]/g;
ts.addParser({
id: 'digit',
is: function(s) {
return ts.isDigit(s);
},
format: function(s, table) {
var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
var n = ts.formatFloat((s || '').replace(ts.regex.nondigit, ''), table);
return s && typeof n === 'number' ? n :
s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
},
type: 'numeric'
});
ts.regex.currencyReplace = /[+\-,. ]/g;
ts.regex.currencyTest = /^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/;
ts.addParser({
id: 'currency',
is: function(s) {
s = (s || '').replace(/[+\-,. ]/g, '');
s = (s || '').replace(ts.regex.currencyReplace, '');
// test for £$€¤¥¢
return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test(s);
return ts.regex.currencyTest.test(s);
},
format: function(s, table) {
var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
var n = ts.formatFloat((s || '').replace(ts.regex.nondigit, ''), table);
return s && typeof n === 'number' ? n :
s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
},
type: 'numeric'
});
// too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme
// now, this regex can be updated before initialization
ts.regex.urlProtocolTest = /^(https?|ftp|file):\/\//;
ts.regex.urlProtocolReplace = /(https?|ftp|file):\/\//;
ts.addParser({
id: 'url',
is: function(s) {
return (/^(https?|ftp|file):\/\//).test(s);
return ts.regex.urlProtocolTest.test(s);
},
format: function(s) {
return s ? $.trim(s.replace(/(https?|ftp|file):\/\//, '')) : s;
return s ? $.trim(s.replace(ts.regex.urlProtocolReplace, '')) : s;
},
parsed : true, // filter widget flag
type: 'text'
});
ts.regex.dash = /-/g;
ts.regex.isoDate = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/;
ts.addParser({
id: 'isoDate',
is: function(s) {
return (/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/).test(s);
return ts.regex.isoDate.test(s);
},
format: function(s, table) {
var date = s ? new Date( s.replace(/-/g, '/') ) : s;
var date = s ? new Date( s.replace(ts.regex.dash, '/') ) : s;
return date instanceof Date && isFinite(date) ? date.getTime() : s;
},
type: 'numeric'
});
ts.regex.percent = /%/g;
ts.regex.percentTest = /(\d\s*?%|%\s*?\d)/;
ts.addParser({
id: 'percent',
is: function(s) {
return (/(\d\s*?%|%\s*?\d)/).test(s) && s.length < 15;
return ts.regex.percentTest.test(s) && s.length < 15;
},
format: function(s, table) {
return s ? ts.formatFloat(s.replace(/%/g, ''), table) : s;
return s ? ts.formatFloat(s.replace(ts.regex.percent, ''), table) : s;
},
type: 'numeric'
});
@ -2200,27 +2228,35 @@
type: 'text'
});
ts.regex.dateReplace = /(\S)([AP]M)$/i; // used by usLongDate & time parser
ts.regex.usLongDateTest1 = /^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i;
ts.regex.usLongDateTest2 = /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i;
ts.addParser({
id: 'usLongDate',
is: function(s) {
// two digit years are not allowed cross-browser
// Jan 01, 2013 12:34:56 PM or 01 Jan 2013
return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) ||
(/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s);
return ts.regex.usLongDateTest1.test(s) || ts.regex.usLongDateTest2.test(s);
},
format: function(s, table) {
var date = s ? new Date( s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s;
var date = s ? new Date( s.replace(ts.regex.dateReplace, '$1 $2') ) : s;
return date instanceof Date && isFinite(date) ? date.getTime() : s;
},
type: 'numeric'
});
// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
ts.regex.shortDateTest = /(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/;
// escaped "-" because JSHint in Firefox was showing it as an error
ts.regex.shortDateReplace = /[\-.,]/g;
// XXY covers MDY & DMY formats
ts.regex.shortDateXXY = /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/;
ts.regex.shortDateYMD = /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/;
ts.addParser({
id: 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
is: function(s) {
s = (s || '').replace(/\s+/g, ' ').replace(/[\-.,]/g, '/');
// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test(s);
s = (s || '').replace(ts.regex.spaces, ' ').replace(ts.regex.shortDateReplace, '/');
return ts.regex.shortDateTest.test(s);
},
format: function(s, table, cell, cellIndex) {
if (s) {
@ -2230,14 +2266,13 @@
format = ci.length && ci[0].dateFormat ||
ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') ||
c.dateFormat;
// escaped "-" because JSHint in Firefox was showing it as an error
d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/');
d = s.replace(ts.regex.spaces, ' ').replace(ts.regex.shortDateReplace, '/');
if (format === 'mmddyyyy') {
d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$1/$2');
d = d.replace(ts.regex.shortDateXXY, '$3/$1/$2');
} else if (format === 'ddmmyyyy') {
d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$2/$1');
d = d.replace(ts.regex.shortDateXXY, '$3/$2/$1');
} else if (format === 'yyyymmdd') {
d = d.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, '$1/$2/$3');
d = d.replace(ts.regex.shortDateYMD, '$1/$2/$3');
}
date = new Date(d);
return date instanceof Date && isFinite(date) ? date.getTime() : s;
@ -2247,13 +2282,14 @@
type: 'numeric'
});
ts.regex.timeTest = /^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i;
ts.addParser({
id: 'time',
is: function(s) {
return (/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i).test(s);
return ts.regex.timeTest.test(s);
},
format: function(s, table) {
var date = s ? new Date( '2000/01/01 ' + s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s;
var date = s ? new Date( '2000/01/01 ' + s.replace(ts.regex.dateReplace, '$1 $2') ) : s;
return date instanceof Date && isFinite(date) ? date.getTime() : s;
},
type: 'numeric'

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
/*! tablesorter (FORK) - updated 08-21-2015 (v2.23.1)*/
/*! tablesorter (FORK) - updated 08-23-2015 (v2.23.2)*/
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) {
if (typeof define === 'function' && define.amd) {
@ -366,14 +366,15 @@
})(jQuery);
/*! Widget: filter - updated 8/17/2015 (v2.23.0) *//*
/*! Widget: filter - updated 8/23/2015 (v2.23.2) *//*
* Requires tablesorter v2.8+ and jQuery 1.7+
* by Rob Garrison
*/
;( function ( $ ) {
'use strict';
var ts = $.tablesorter || {},
tscss = ts.css;
var tsf,
ts = $.tablesorter || {},
tscss = ts.css;
$.extend( tscss, {
filterRow : 'tablesorter-filter-row',
@ -417,7 +418,7 @@
},
format: function( table, c, wo ) {
if ( !c.$table.hasClass( 'hasFilters' ) ) {
ts.filter.init( table, c, wo );
tsf.init( table, c, wo );
}
},
remove: function( table, c, wo, refreshing ) {
@ -429,7 +430,7 @@
$table
.removeClass( 'hasFilters' )
// add .tsfilter namespace to all BUT search
.unbind( events.replace( /\s+/g, ' ' ) )
.unbind( events.replace( ts.regex.spaces, ' ' ) )
// remove the filter row even if refreshing, because the column might have been moved
.find( '.' + tscss.filterRow ).remove();
if ( refreshing ) { return; }
@ -444,7 +445,7 @@
}
});
ts.filter = {
tsf = ts.filter = {
// regex used in filter 'check' functions - not for general use and not documented
regex: {
@ -453,9 +454,13 @@
filtered : /filtered/, // filtered (hidden) row class name; updated in the script
type : /undefined|number/, // check type
exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==')
nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser)
operators : /[<>=]/g, // replace operators
query : '(q|query)' // replace filter queries
query : '(q|query)', // replace filter queries
wild01 : /\?/g, // wild card match 0 or 1
wild0More : /\*/g, // wild care match 0 or more
quote : /\"/g,
isNeg1 : /(>=?\s*-\d)/,
isNeg2 : /(<=?\s*\d)/
},
// function( c, data ) { }
// c = table.config
@ -472,27 +477,27 @@
// 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 ) ) {
if ( tsf.regex.orTest.test( data.iFilter ) || tsf.regex.orSplit.test( data.filter ) ) {
var indx, filterMatched, 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 ),
filter = data.filter.split( tsf.regex.orSplit ),
iFilter = data.iFilter.split( tsf.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 ) || '' ) + ')';
data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
query = '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
try {
// use try/catch, because query may not be a valid regex if "|" is contained within a partial regex search,
// e.g "/(Alex|Aar" -> Uncaught SyntaxError: Invalid regular expression: /(/(Alex)/: Unterminated group
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 );
filterMatched = regex.test( data2.exact ) || tsf.processTypes( c, data2, vars );
if ( filterMatched ) {
return filterMatched;
}
@ -507,27 +512,27 @@
},
// Look for an AND or && operator ( logical and )
and : function( c, data, vars ) {
if ( ts.filter.regex.andTest.test( data.filter ) ) {
if ( tsf.regex.andTest.test( data.filter ) ) {
var indx, filterMatched, result, 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 ),
filter = data.filter.split( tsf.regex.andSplit ),
iFilter = data.iFilter.split( tsf.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 ) || '' ) + ')' )
data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
query = ( '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
// replace wild cards since /(a*)/i will match anything
.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
.replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' );
try {
// use try/catch just in case RegExp is invalid
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 ) );
result = ( regex.test( data2.exact ) || tsf.processTypes( c, data2, vars ) );
if ( indx === 0 ) {
filterMatched = result;
} else {
@ -544,10 +549,10 @@
},
// Look for regex
regex: function( c, data ) {
if ( ts.filter.regex.regex.test( data.filter ) ) {
if ( tsf.regex.regex.test( data.filter ) ) {
var matches,
// cache regex per column for optimal speed
regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
regex = data.filter_regexCache[ data.index ] || tsf.regex.regex.exec( data.filter ),
isRegex = regex instanceof RegExp;
try {
if ( !isRegex ) {
@ -566,18 +571,18 @@
// Look for operators >, >=, < or <=
operators: function( c, data ) {
// ignore empty strings... because '' < 10 is true
if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) {
if ( tsf.regex.operTest.test( data.iFilter ) && data.iExact !== '' ) {
var cachedValue, result, txt,
table = c.table,
index = data.index,
parsed = data.parsed[index],
query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ),
query = ts.formatFloat( data.iFilter.replace( tsf.regex.operators, '' ), table ),
parser = c.parsers[index],
savedSearch = query;
// parse filter value in case we're comparing numbers ( dates )
if ( parsed || parser.type === 'numeric' ) {
txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) );
result = ts.filter.parseFilter( c, txt, index, true );
txt = $.trim( '' + data.iFilter.replace( tsf.regex.operators, '' ) );
result = tsf.parseFilter( c, txt, index, true );
query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
}
// iExact may be numeric - see issue #149;
@ -586,13 +591,13 @@
typeof data.cache !== 'undefined' ) {
cachedValue = data.cache;
} else {
txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
txt = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
cachedValue = ts.formatFloat( txt, table );
}
if ( />/.test( data.iFilter ) ) {
result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
} else if ( /</.test( data.iFilter ) ) {
result = /<=/.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
if ( tsf.regex.gtTest.test( data.iFilter ) ) {
result = tsf.regex.gteTest.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
} else if ( tsf.regex.ltTest.test( data.iFilter ) ) {
result = tsf.regex.lteTest.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
}
// keep showing all rows if nothing follows the operator
if ( !result && savedSearch === '' ) {
@ -604,13 +609,13 @@
},
// Look for a not match
notMatch: function( c, data ) {
if ( /^\!/.test( data.iFilter ) ) {
if ( tsf.regex.notTest.test( data.iFilter ) ) {
var indx,
txt = data.iFilter.replace( '!', '' ),
filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( ts.filter.regex.exact.test( filter ) ) {
filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( tsf.regex.exact.test( filter ) ) {
// look for exact not matches - see #628
filter = filter.replace( ts.filter.regex.exact, '' );
filter = filter.replace( tsf.regex.exact, '' );
return filter === '' ? true : $.trim( filter ) !== data.iExact;
} else {
indx = data.iExact.search( $.trim( filter ) );
@ -622,27 +627,27 @@
// Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
exact: function( c, data ) {
/*jshint eqeqeq:false */
if ( ts.filter.regex.exact.test( data.iFilter ) ) {
var txt = data.iFilter.replace( ts.filter.regex.exact, '' ),
filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( tsf.regex.exact.test( data.iFilter ) ) {
var txt = data.iFilter.replace( tsf.regex.exact, '' ),
filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
}
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 ) ) {
if ( tsf.regex.toTest.test( data.iFilter ) ) {
var result, tmp, range1, range2,
table = c.table,
index = data.index,
parsed = data.parsed[index],
// make sure the dash is for a range and not indicating a negative number
query = data.iFilter.split( ts.filter.regex.toSplit );
query = data.iFilter.split( tsf.regex.toSplit );
tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || '';
range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || '';
range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
tmp = query[0].replace( ts.regex.nondigit, '' ) || '';
range1 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
tmp = query[1].replace( ts.regex.nondigit, '' ) || '';
range2 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
// parse filter value in case we're comparing numbers ( dates )
if ( parsed || c.parsers[index].type === 'numeric' ) {
result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
@ -653,7 +658,7 @@
if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
result = data.cache;
} else {
tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
result = ts.formatFloat( tmp, table );
}
if ( range1 > range2 ) {
@ -665,18 +670,18 @@
},
// Look for wild card: ? = single, * = multiple, or | = logical OR
wild : function( c, data ) {
if ( /[\?\*\|]/.test( data.iFilter ) ) {
if ( tsf.regex.wildOrTest.test( data.iFilter ) ) {
var index = data.index,
parsed = data.parsed[ index ],
query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
query = '' + ( tsf.parseFilter( c, data.iFilter, index, parsed ) || '' );
// look for an exact match with the 'or' unless the 'filter-match' class is found
if ( !/\?\*/.test( query ) && data.nestedFilters ) {
if ( !tsf.regex.wildTest.test( query ) && data.nestedFilters ) {
query = data.isMatch ? query : '^(' + query + ')$';
}
// parsing the filter may not work properly when using wildcards =/
try {
return new RegExp(
query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
query.replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' ),
c.widgetOptions.filter_ignoreCase ? 'i' : ''
)
.test( data.exact );
@ -688,12 +693,12 @@
},
// fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
fuzzy: function( c, data ) {
if ( /^~/.test( data.iFilter ) ) {
if ( tsf.regex.fuzzyTest.test( data.iFilter ) ) {
var indx,
patternIndx = 0,
len = data.iExact.length,
txt = data.iFilter.slice( 1 ),
pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
pattern = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
for ( indx = 0; indx < len; indx++ ) {
if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
patternIndx += 1;
@ -716,7 +721,7 @@
}, ts.language );
var options, string, txt, $header, column, filters, val, fxn, noSelect,
regex = ts.filter.regex;
regex = tsf.regex;
c.$table.addClass( 'hasFilters' );
// define timers so using clearTimeout won't cause an undefined error
@ -727,7 +732,7 @@
wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
val = '\\{' + ts.filter.regex.query + '\\}';
val = '\\{' + tsf.regex.query + '\\}';
$.extend( regex, {
child : new RegExp( c.cssChildRow ),
filtered : new RegExp( wo.filter_filteredRow ),
@ -736,9 +741,20 @@
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' ),
orTest : /\|/,
orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
iQuery : new RegExp( val, 'i' ),
igQuery : new RegExp( val, 'ig' )
igQuery : new RegExp( val, 'ig' ),
operTest : /^[<>]=?/,
gtTest : />/,
gteTest : />=/,
ltTest : /</,
lteTest : /<=/,
notTest : /^\!/,
wildOrTest : /[\?\*\|]/,
wildTest : /\?\*/,
fuzzyTest : /^~/,
exactTest : /[=\"\|!]/
});
// don't build filter row if columnFilters is false or all columns are set to 'filter-false'
@ -746,7 +762,7 @@
val = c.$headers.filter( '.filter-false, .parser-false' ).length;
if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
// build filter row
ts.filter.buildRow( table, c, wo );
tsf.buildRow( table, c, wo );
}
txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
@ -759,13 +775,13 @@
c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
if ( !/(search|filter)/.test( event.type ) ) {
event.stopPropagation();
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
}
if ( event.type === 'filterReset' ) {
c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
ts.filter.searching( table, [] );
tsf.searching( table, [] );
} else if ( event.type === 'filterEnd' ) {
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
} else {
// send false argument to force a new search; otherwise if the filter hasn't changed,
// it will return
@ -779,7 +795,7 @@
// pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
// input ensures all inputs are updated when a search is triggered on the table
// $( 'table' ).trigger( 'search', [...] );
ts.filter.searching( table, filter, true );
tsf.searching( table, filter, true );
}
return false;
});
@ -812,7 +828,7 @@
noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
options = '';
if ( fxn === true && noSelect ) {
ts.filter.buildSelect( table, column );
tsf.buildSelect( table, column );
} else if ( typeof fxn === 'object' && noSelect ) {
// add custom drop down list
for ( string in fxn ) {
@ -845,7 +861,7 @@
fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column );
if ( fxn ) {
// updating so the extra options are appended
ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
tsf.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
}
}
}
@ -853,22 +869,22 @@
}
// not really updating, but if the column has both the 'filter-select' class &
// filter_functions set to true, it would append the same options twice.
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
tsf.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
if ( wo.filter_external ) {
ts.filter.bindSearch( table, wo.filter_external );
tsf.bindSearch( table, wo.filter_external );
}
if ( wo.filter_hideFilters ) {
ts.filter.hideFilters( table, c );
tsf.hideFilters( table, c );
}
// show processing icon
if ( c.showProcessing ) {
txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
c.$table
.unbind( txt.replace( /\s+/g, ' ' ) )
.unbind( txt.replace( ts.regex.spaces, ' ' ) )
.bind( txt, function( event, columns ) {
// only add processing to certain columns to all columns
$header = ( columns ) ?
@ -888,11 +904,11 @@
// add default values
txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
c.$table
.unbind( txt.replace( /\s+/g, ' ' ) )
.unbind( txt.replace( ts.regex.spaces, ' ' ) )
.bind( txt, function() {
// redefine 'wo' as it does not update properly inside this callback
var wo = this.config.widgetOptions;
filters = ts.filter.setDefaults( table, c, wo ) || [];
filters = tsf.setDefaults( table, c, wo ) || [];
if ( filters.length ) {
// prevent delayInit from triggering a cache build if filters are empty
if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
@ -903,7 +919,7 @@
// trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
setTimeout( function() {
if ( !wo.filter_initialized ) {
ts.filter.filterInitComplete( c );
tsf.filterInitComplete( c );
}
}, 100 );
});
@ -911,7 +927,7 @@
if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
c.$table.trigger( 'filterFomatterUpdate' );
setTimeout( function() {
ts.filter.filterInitComplete( c );
tsf.filterInitComplete( c );
}, 100 );
}
},
@ -932,7 +948,7 @@
completed = function() {
wo.filter_initialized = true;
c.$table.trigger( 'filterInit', c );
ts.filter.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
tsf.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
};
if ( $.isEmptyObject( wo.filter_formatter ) ) {
completed();
@ -1084,7 +1100,7 @@
// use data attribute instead of jQuery data since the head is cloned without including
// the data/binding
.attr( 'data-lastSearchTime', new Date().getTime() )
.unbind( tmp.replace( /\s+/g, ' ' ) )
.unbind( tmp.replace( ts.regex.spaces, ' ' ) )
// include change for select - fixes #473
.bind( 'keyup' + namespace, function( event ) {
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
@ -1104,7 +1120,7 @@
return;
}
// change event = no delay; last true flag tells getFilters to skip newest timed input
ts.filter.searching( table, true, true );
tsf.searching( table, true, true );
})
.bind( 'search change keypress '.split( ' ' ).join( namespace + ' ' ), function( event ) {
// don't get cached data, in case data-column changes dynamically
@ -1115,7 +1131,7 @@
event.preventDefault();
// init search with no delay
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
ts.filter.searching( table, false, true );
tsf.searching( table, false, true );
}
});
},
@ -1125,11 +1141,11 @@
if ( typeof filter === 'undefined' || filter === true ) {
// delay filtering
wo.searchTimer = setTimeout( function() {
ts.filter.checkFilters( table, filter, skipFirst );
tsf.checkFilters( table, filter, skipFirst );
}, wo.filter_liveSearch ? wo.filter_searchDelay : 10 );
} else {
// skip delay
ts.filter.checkFilters( table, filter, skipFirst );
tsf.checkFilters( table, filter, skipFirst );
}
},
checkFilters: function( table, filter, skipFirst ) {
@ -1143,7 +1159,7 @@
// update cache if delayInit set & pager has initialized ( after user initiates a search )
if ( c.delayInit && c.pager && c.pager.initialized ) {
c.$table.trigger( 'updateCache', [ function() {
ts.filter.checkFilters( table, false, skipFirst );
tsf.checkFilters( table, false, skipFirst );
} ] );
}
return;
@ -1174,11 +1190,11 @@
if ( c.showProcessing ) {
// give it time for the processing icon to kick in
setTimeout( function() {
ts.filter.findRows( table, filters, combinedFilters );
tsf.findRows( table, filters, combinedFilters );
return false;
}, 30 );
} else {
ts.filter.findRows( table, filters, combinedFilters );
tsf.findRows( table, filters, combinedFilters );
return false;
}
},
@ -1221,8 +1237,8 @@
},
defaultFilter: function( filter, mask ) {
if ( filter === '' ) { return filter; }
var regex = ts.filter.regex.iQuery,
maskLen = mask.match( ts.filter.regex.igQuery ).length,
var regex = tsf.regex.iQuery,
maskLen = mask.match( tsf.regex.igQuery ).length,
query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
len = query.length - 1,
indx = 0,
@ -1258,7 +1274,7 @@
// & don't target 'all' column inputs if they don't exist
targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
columns = [],
val = $.trim( ts.filter.getLatestSearch( $input ).attr( 'data-column' ) || '' );
val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
if ( !/[,-]/.test(val) && val.length === 1 ) {
return parseInt( val, 10 );
}
@ -1308,9 +1324,9 @@
var ffxn,
filterMatched = null,
matches = null;
for ( ffxn in ts.filter.types ) {
for ( ffxn in tsf.types ) {
if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
matches = ts.filter.types[ffxn]( c, data, vars );
matches = tsf.types[ffxn]( c, data, vars );
if ( matches !== null ) {
filterMatched = matches;
}
@ -1321,7 +1337,7 @@
processRow: function( c, data, vars ) {
var hasSelect, result, val, filterMatched,
fxn, ffxn, txt,
regex = ts.filter.regex,
regex = tsf.regex,
wo = c.widgetOptions,
showRow = true,
@ -1330,7 +1346,7 @@
// for the entire row - see #998
columnIndex = wo.filter_$anyMatch && wo.filter_$anyMatch.length ?
// look for multiple columns '1-3,4-6,8'
ts.filter.multipleColumns( c, wo.filter_$anyMatch ) :
tsf.multipleColumns( c, wo.filter_$anyMatch ) :
[];
data.$cells = data.$row.children();
@ -1359,7 +1375,7 @@
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
vars.excludeMatch = vars.noAnyMatch;
filterMatched = ts.filter.processTypes( c, data, vars );
filterMatched = tsf.processTypes( c, data, vars );
if ( filterMatched !== null ) {
showRow = filterMatched;
@ -1420,7 +1436,7 @@
val = true;
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
data.filter = ts.filter.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
data.filter = tsf.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
// val is used to indicate that a filter select is using a default filter;
// so we override the exact & partial matches
val = false;
@ -1451,13 +1467,13 @@
if ( filterMatched === null ) {
// cycle through the different filters
// filters return a boolean or null if nothing matches
filterMatched = ts.filter.processTypes( c, data, vars );
filterMatched = tsf.processTypes( c, data, vars );
if ( filterMatched !== null ) {
result = filterMatched;
// Look for match, and add child row data for matching
} else {
txt = ( data.iExact + data.childRowText )
.indexOf( ts.filter.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
.indexOf( tsf.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
}
} else {
@ -1477,7 +1493,7 @@
isChild, childRow, lastSearch, showRow, time, val, indx,
notFiltered, searchFiltered, query, injected, res, id, txt,
storedFilters = $.extend( [], filters ),
regex = ts.filter.regex,
regex = tsf.regex,
c = table.config,
wo = c.widgetOptions,
// data object passed to filters; anyMatch is a flag for the filters
@ -1554,7 +1570,7 @@
data.anyMatchFlag = true;
data.anyMatchFilter = '' + (
filters[ c.columns ] ||
wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() ||
wo.filter_$anyMatch && tsf.getLatestSearch( wo.filter_$anyMatch ).val() ||
''
);
if ( wo.filter_columnAnyMatch ) {
@ -1596,10 +1612,10 @@
// if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
!regex.alreadyFiltered.test( val ) &&
// if we are not doing exact matches, using '|' ( logical or ) or not '!'
!/[=\"\|!]/.test( val ) &&
!regex.exactTest.test( val ) &&
// don't search only filtered if the value is negative
// ( '> -10' => '> -100' will ignore hidden rows )
!( /(>=?\s*-\d)/.test( val ) || /(<=?\s*\d)/.test( val ) ) &&
!( regex.isNeg1.test( val ) || regex.isNeg2.test( val ) ) &&
// if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
!( val !== '' && c.$filters && c.$filters.eq( indx ).find( 'select' ).length &&
!c.$headerIndexed[indx].hasClass( 'filter-match' ) );
@ -1618,7 +1634,7 @@
data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
}
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) {
data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
data.anyMatchFilter = tsf.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
// clear search filtered flag because default filters are not saved to the last search
searchFiltered = false;
}
@ -1661,7 +1677,7 @@
'';
}
showRow = ts.filter.processRow( c, data, vars );
showRow = tsf.processRow( c, data, vars );
childRow = rowData.$row.filter( ':gt( 0 )' );
if ( wo.filter_childRows && childRow.length ) {
@ -1672,7 +1688,7 @@
data.cacheArray = rowData.child[ indx ];
data.rawArray = data.cacheArray;
// use OR comparison on child rows
showRow = showRow || ts.filter.processRow( c, data, vars );
showRow = showRow || tsf.processRow( c, data, vars );
}
}
childRow.toggleClass( wo.filter_filteredRow, !showRow );
@ -1734,7 +1750,7 @@
}
if ( arry === false ) {
// fall back to original method
arry = ts.filter.getOptions( table, column, onlyAvail );
arry = tsf.getOptions( table, column, onlyAvail );
}
// get unique elements and sort the list
@ -1846,13 +1862,13 @@
// nothing included in arry ( external source ), so get the options from
// filter_selectSource or column data
if ( typeof arry === 'undefined' || arry === '' ) {
arry = ts.filter.getOptionSource( table, column, onlyAvail );
arry = tsf.getOptionSource( table, column, onlyAvail );
}
if ( $.isArray( arry ) ) {
// build option list
for ( indx = 0; indx < arry.length; indx++ ) {
txt = arry[indx] = ( '' + arry[indx] ).replace( /\"/g, '&quot;' );
txt = arry[indx] = ( '' + arry[indx] ).replace( tsf.regex.quote, '&quot;' );
val = txt;
// allow including a symbol in the selectSource array
// 'a-z|A through Z' so that 'a-z' becomes the option value
@ -1908,7 +1924,7 @@
// look for the filter-select class; build/update it if found
if ( ( $header.hasClass( 'filter-select' ) ||
ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
ts.filter.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
tsf.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
}
}
}
@ -1944,7 +1960,7 @@
$column = $filters.filter( cols );
if ( $column.length ) {
// move the latest search to the first slot in the array
$column = ts.filter.getLatestSearch( $column );
$column = tsf.getLatestSearch( $column );
if ( $.isArray( setFilters ) ) {
// skip first ( latest input ) to maintain cursor position while typing
if ( skipFirst && $column.length > 1 ) {
@ -1994,7 +2010,7 @@
// ensure new set filters are applied, even if the search is the same
c.lastCombinedFilter = null;
c.lastSearch = [];
ts.filter.searching( c.table, filter, skipFirst );
tsf.searching( c.table, filter, skipFirst );
c.$table.trigger( 'filterFomatterUpdate' );
}
return !!valid;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
*/
/*! tablesorter (FORK) - updated 08-21-2015 (v2.23.1)*/
/*! tablesorter (FORK) - updated 08-23-2015 (v2.23.2)*/
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) {
if (typeof define === 'function' && define.amd) {
@ -16,7 +16,7 @@
}
}(function($) {
/*! TableSorter (FORK) v2.23.1 *//*
/*! TableSorter (FORK) v2.23.2 *//*
* Client-side table sorting with ease!
* @requires jQuery v1.2.6+
*
@ -44,7 +44,7 @@
var ts = this;
ts.version = '2.23.1';
ts.version = '2.23.2';
ts.parsers = [];
ts.widgets = [];
@ -169,6 +169,15 @@
nextNone : 'activate to remove the sort'
};
ts.regex = {
templateContent : /\{content\}/g,
templateIcon : /\{icon\}/g,
templateName : /\{name\}/i,
spaces : /\s+/g,
nonWord : /\W/g,
formElements : /(input|select|button|textarea)/i
};
// These methods can be applied on table.config instance
ts.instanceMethods = {};
@ -461,7 +470,9 @@
// if headerTemplate is empty, don't reformat the header cell
if ( c.headerTemplate !== '' && !$t.find('.' + ts.css.headerIn).length ) {
// set up header template
t = c.headerTemplate.replace(/\{content\}/g, $t.html()).replace(/\{icon\}/g, $t.find('.' + ts.css.icon).length ? '' : i);
t = c.headerTemplate
.replace(ts.regex.templateContent, $t.html())
.replace(ts.regex.templateIcon, $t.find('.' + ts.css.icon).length ? '' : i);
if (c.onRenderTemplate) {
h = c.onRenderTemplate.apply( $t, [ index, t ] );
if (h && typeof h === 'string') { t = h; } // only change t if something is returned
@ -874,7 +885,7 @@
.join( c.namespace + ' ' );
// apply easy methods that trigger bound events
$table
.unbind( events.replace( /\s+/g, ' ' ) )
.unbind( events.replace( ts.regex.spaces, ' ' ) )
.bind( 'sortReset' + c.namespace, function( e, callback ) {
e.stopPropagation();
// using this.config to ensure functions are getting a non-cached version of the config
@ -1021,7 +1032,7 @@
c.namespace = '.tablesorter' + Math.random().toString(16).slice(2);
} else {
// make sure namespace starts with a period & doesn't have weird characters
c.namespace = '.' + c.namespace.replace(/\W/g, '');
c.namespace = '.' + c.namespace.replace(ts.regex.nonWord, '');
}
c.$table.children().children('tr').attr('role', 'row');
@ -1249,7 +1260,7 @@
}
}
t = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' )
.replace(/\s+/g, ' ')
.replace(ts.regex.spaces, ' ')
.split(' ')
.join(c.namespace + ' ');
// apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)
@ -1283,7 +1294,7 @@
}
downTarget = null;
// prevent sort being triggered on form elements
if ( /(input|select|button|textarea)/i.test(e.target.nodeName) ||
if ( ts.regex.formElements.test(e.target.nodeName) ||
// nosort class name, or elements within a nosort container
$target.hasClass(c.cssNoSort) || $target.parents('.' + c.cssNoSort).length > 0 ||
// elements within a button
@ -1569,13 +1580,13 @@
.join(c.namespace + ' ');
$t
.removeData('tablesorter')
.unbind( events.replace(/\s+/g, ' ') );
.unbind( events.replace(ts.regex.spaces, ' ') );
c.$headers.add($f)
.removeClass( [ ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone ].join(' ') )
.removeAttr('data-column')
.removeAttr('aria-label')
.attr('aria-disabled', 'true');
$r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(/\s+/g, ' ') );
$r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(ts.regex.spaces, ' ') );
ts.restoreHeaders(table);
$t.toggleClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false);
// clear flag in case the plugin is initialized again
@ -1591,11 +1602,9 @@
// *** sort functions ***
// regex used in natural sort
ts.regex = {
chunk : /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, // chunk/tokenize numbers & letters
chunks: /(^\\0|\\0$)/, // replace chunks @ ends
hex: /^0x[0-9a-f]+$/i // hex
};
ts.regex.chunk = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi; // chunk/tokenize numbers & letters
ts.regex.chunks = /(^\\0|\\0$)/; // replace chunks @ ends
ts.regex.hex = /^0x[0-9a-f]+$/i; // hex
// Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)
// this function will only accept strings, or you'll see 'TypeError: undefined is not a function'
@ -1822,7 +1831,7 @@
if (c.debug) { time = new Date(); }
// look for widgets to apply from in table class
// stop using \b otherwise this matches 'ui-widget-content' & adds 'content' widget
wd = new RegExp( '\\s' + c.widgetClass.replace( /\{name\}/i, '([\\w-]+)' ) + '\\s', 'g' );
wd = new RegExp( '\\s' + c.widgetClass.replace( ts.regex.templateName, '([\\w-]+)' ) + '\\s', 'g' );
if ( tableClass.match( wd ) ) {
// extract out the widget id from the table class (widget id's can include dashes)
w = tableClass.match( wd );
@ -2048,6 +2057,10 @@
return $.trim(val);
};
ts.regex.comma = /,/g;
ts.regex.digitNonUS = /[\s|\.]/g;
ts.regex.digitNegativeTest = /^\s*\([.\d]+\)/;
ts.regex.digitNegativeReplace = /^\s*\(([.\d]+)\)/;
ts.formatFloat = function(s, table) {
if (typeof s !== 'string' || s === '') { return s; }
// allow using formatFloat without a table; defaults to US number format
@ -2056,24 +2069,28 @@
typeof table !== 'undefined' ? table : true;
if (t) {
// US Format - 1,234,567.89 -> 1234567.89
s = s.replace(/,/g, '');
s = s.replace(ts.regex.comma, '');
} else {
// German Format = 1.234.567,89 -> 1234567.89
// French Format = 1 234 567,89 -> 1234567.89
s = s.replace(/[\s|\.]/g, '').replace(/,/g, '.');
s = s.replace(ts.regex.digitNonUS, '').replace(ts.regex.comma, '.');
}
if (/^\s*\([.\d]+\)/.test(s)) {
if (ts.regex.digitNegativeTest.test(s)) {
// make (#) into a negative number -> (10) = -10
s = s.replace(/^\s*\(([.\d]+)\)/, '-$1');
s = s.replace(ts.regex.digitNegativeReplace, '-$1');
}
i = parseFloat(s);
// return the text instead of zero
return isNaN(i) ? $.trim(s) : i;
};
ts.regex.digitTest = /^[\-+(]?\d+[)]?$/;
ts.regex.digitReplace = /[,.'"\s]/g;
ts.isDigit = function(s) {
// replace all unwanted chars and match
return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : s !== '';
return isNaN(s) ?
ts.regex.digitTest.test( s.toString().replace( ts.regex.digitReplace, '' ) ) :
s !== '';
};
}()
@ -2132,65 +2149,76 @@
type: 'text'
});
ts.regex.nondigit = /[^\w,. \-()]/g;
ts.addParser({
id: 'digit',
is: function(s) {
return ts.isDigit(s);
},
format: function(s, table) {
var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
var n = ts.formatFloat((s || '').replace(ts.regex.nondigit, ''), table);
return s && typeof n === 'number' ? n :
s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
},
type: 'numeric'
});
ts.regex.currencyReplace = /[+\-,. ]/g;
ts.regex.currencyTest = /^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/;
ts.addParser({
id: 'currency',
is: function(s) {
s = (s || '').replace(/[+\-,. ]/g, '');
s = (s || '').replace(ts.regex.currencyReplace, '');
// test for £$€¤¥¢
return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test(s);
return ts.regex.currencyTest.test(s);
},
format: function(s, table) {
var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
var n = ts.formatFloat((s || '').replace(ts.regex.nondigit, ''), table);
return s && typeof n === 'number' ? n :
s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
},
type: 'numeric'
});
// too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme
// now, this regex can be updated before initialization
ts.regex.urlProtocolTest = /^(https?|ftp|file):\/\//;
ts.regex.urlProtocolReplace = /(https?|ftp|file):\/\//;
ts.addParser({
id: 'url',
is: function(s) {
return (/^(https?|ftp|file):\/\//).test(s);
return ts.regex.urlProtocolTest.test(s);
},
format: function(s) {
return s ? $.trim(s.replace(/(https?|ftp|file):\/\//, '')) : s;
return s ? $.trim(s.replace(ts.regex.urlProtocolReplace, '')) : s;
},
parsed : true, // filter widget flag
type: 'text'
});
ts.regex.dash = /-/g;
ts.regex.isoDate = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/;
ts.addParser({
id: 'isoDate',
is: function(s) {
return (/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/).test(s);
return ts.regex.isoDate.test(s);
},
format: function(s, table) {
var date = s ? new Date( s.replace(/-/g, '/') ) : s;
var date = s ? new Date( s.replace(ts.regex.dash, '/') ) : s;
return date instanceof Date && isFinite(date) ? date.getTime() : s;
},
type: 'numeric'
});
ts.regex.percent = /%/g;
ts.regex.percentTest = /(\d\s*?%|%\s*?\d)/;
ts.addParser({
id: 'percent',
is: function(s) {
return (/(\d\s*?%|%\s*?\d)/).test(s) && s.length < 15;
return ts.regex.percentTest.test(s) && s.length < 15;
},
format: function(s, table) {
return s ? ts.formatFloat(s.replace(/%/g, ''), table) : s;
return s ? ts.formatFloat(s.replace(ts.regex.percent, ''), table) : s;
},
type: 'numeric'
});
@ -2208,27 +2236,35 @@
type: 'text'
});
ts.regex.dateReplace = /(\S)([AP]M)$/i; // used by usLongDate & time parser
ts.regex.usLongDateTest1 = /^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i;
ts.regex.usLongDateTest2 = /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i;
ts.addParser({
id: 'usLongDate',
is: function(s) {
// two digit years are not allowed cross-browser
// Jan 01, 2013 12:34:56 PM or 01 Jan 2013
return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) ||
(/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s);
return ts.regex.usLongDateTest1.test(s) || ts.regex.usLongDateTest2.test(s);
},
format: function(s, table) {
var date = s ? new Date( s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s;
var date = s ? new Date( s.replace(ts.regex.dateReplace, '$1 $2') ) : s;
return date instanceof Date && isFinite(date) ? date.getTime() : s;
},
type: 'numeric'
});
// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
ts.regex.shortDateTest = /(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/;
// escaped "-" because JSHint in Firefox was showing it as an error
ts.regex.shortDateReplace = /[\-.,]/g;
// XXY covers MDY & DMY formats
ts.regex.shortDateXXY = /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/;
ts.regex.shortDateYMD = /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/;
ts.addParser({
id: 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
is: function(s) {
s = (s || '').replace(/\s+/g, ' ').replace(/[\-.,]/g, '/');
// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test(s);
s = (s || '').replace(ts.regex.spaces, ' ').replace(ts.regex.shortDateReplace, '/');
return ts.regex.shortDateTest.test(s);
},
format: function(s, table, cell, cellIndex) {
if (s) {
@ -2238,14 +2274,13 @@
format = ci.length && ci[0].dateFormat ||
ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') ||
c.dateFormat;
// escaped "-" because JSHint in Firefox was showing it as an error
d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/');
d = s.replace(ts.regex.spaces, ' ').replace(ts.regex.shortDateReplace, '/');
if (format === 'mmddyyyy') {
d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$1/$2');
d = d.replace(ts.regex.shortDateXXY, '$3/$1/$2');
} else if (format === 'ddmmyyyy') {
d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$2/$1');
d = d.replace(ts.regex.shortDateXXY, '$3/$2/$1');
} else if (format === 'yyyymmdd') {
d = d.replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, '$1/$2/$3');
d = d.replace(ts.regex.shortDateYMD, '$1/$2/$3');
}
date = new Date(d);
return date instanceof Date && isFinite(date) ? date.getTime() : s;
@ -2255,13 +2290,14 @@
type: 'numeric'
});
ts.regex.timeTest = /^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i;
ts.addParser({
id: 'time',
is: function(s) {
return (/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i).test(s);
return ts.regex.timeTest.test(s);
},
format: function(s, table) {
var date = s ? new Date( '2000/01/01 ' + s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s;
var date = s ? new Date( '2000/01/01 ' + s.replace(ts.regex.dateReplace, '$1 $2') ) : s;
return date instanceof Date && isFinite(date) ? date.getTime() : s;
},
type: 'numeric'
@ -2678,14 +2714,15 @@
})(jQuery);
/*! Widget: filter - updated 8/17/2015 (v2.23.0) *//*
/*! Widget: filter - updated 8/23/2015 (v2.23.2) *//*
* Requires tablesorter v2.8+ and jQuery 1.7+
* by Rob Garrison
*/
;( function ( $ ) {
'use strict';
var ts = $.tablesorter || {},
tscss = ts.css;
var tsf,
ts = $.tablesorter || {},
tscss = ts.css;
$.extend( tscss, {
filterRow : 'tablesorter-filter-row',
@ -2729,7 +2766,7 @@
},
format: function( table, c, wo ) {
if ( !c.$table.hasClass( 'hasFilters' ) ) {
ts.filter.init( table, c, wo );
tsf.init( table, c, wo );
}
},
remove: function( table, c, wo, refreshing ) {
@ -2741,7 +2778,7 @@
$table
.removeClass( 'hasFilters' )
// add .tsfilter namespace to all BUT search
.unbind( events.replace( /\s+/g, ' ' ) )
.unbind( events.replace( ts.regex.spaces, ' ' ) )
// remove the filter row even if refreshing, because the column might have been moved
.find( '.' + tscss.filterRow ).remove();
if ( refreshing ) { return; }
@ -2756,7 +2793,7 @@
}
});
ts.filter = {
tsf = ts.filter = {
// regex used in filter 'check' functions - not for general use and not documented
regex: {
@ -2765,9 +2802,13 @@
filtered : /filtered/, // filtered (hidden) row class name; updated in the script
type : /undefined|number/, // check type
exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==')
nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser)
operators : /[<>=]/g, // replace operators
query : '(q|query)' // replace filter queries
query : '(q|query)', // replace filter queries
wild01 : /\?/g, // wild card match 0 or 1
wild0More : /\*/g, // wild care match 0 or more
quote : /\"/g,
isNeg1 : /(>=?\s*-\d)/,
isNeg2 : /(<=?\s*\d)/
},
// function( c, data ) { }
// c = table.config
@ -2784,27 +2825,27 @@
// 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 ) ) {
if ( tsf.regex.orTest.test( data.iFilter ) || tsf.regex.orSplit.test( data.filter ) ) {
var indx, filterMatched, 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 ),
filter = data.filter.split( tsf.regex.orSplit ),
iFilter = data.iFilter.split( tsf.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 ) || '' ) + ')';
data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
query = '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
try {
// use try/catch, because query may not be a valid regex if "|" is contained within a partial regex search,
// e.g "/(Alex|Aar" -> Uncaught SyntaxError: Invalid regular expression: /(/(Alex)/: Unterminated group
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 );
filterMatched = regex.test( data2.exact ) || tsf.processTypes( c, data2, vars );
if ( filterMatched ) {
return filterMatched;
}
@ -2819,27 +2860,27 @@
},
// Look for an AND or && operator ( logical and )
and : function( c, data, vars ) {
if ( ts.filter.regex.andTest.test( data.filter ) ) {
if ( tsf.regex.andTest.test( data.filter ) ) {
var indx, filterMatched, result, 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 ),
filter = data.filter.split( tsf.regex.andSplit ),
iFilter = data.iFilter.split( tsf.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 ) || '' ) + ')' )
data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
query = ( '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
// replace wild cards since /(a*)/i will match anything
.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
.replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' );
try {
// use try/catch just in case RegExp is invalid
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 ) );
result = ( regex.test( data2.exact ) || tsf.processTypes( c, data2, vars ) );
if ( indx === 0 ) {
filterMatched = result;
} else {
@ -2856,10 +2897,10 @@
},
// Look for regex
regex: function( c, data ) {
if ( ts.filter.regex.regex.test( data.filter ) ) {
if ( tsf.regex.regex.test( data.filter ) ) {
var matches,
// cache regex per column for optimal speed
regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
regex = data.filter_regexCache[ data.index ] || tsf.regex.regex.exec( data.filter ),
isRegex = regex instanceof RegExp;
try {
if ( !isRegex ) {
@ -2878,18 +2919,18 @@
// Look for operators >, >=, < or <=
operators: function( c, data ) {
// ignore empty strings... because '' < 10 is true
if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) {
if ( tsf.regex.operTest.test( data.iFilter ) && data.iExact !== '' ) {
var cachedValue, result, txt,
table = c.table,
index = data.index,
parsed = data.parsed[index],
query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ),
query = ts.formatFloat( data.iFilter.replace( tsf.regex.operators, '' ), table ),
parser = c.parsers[index],
savedSearch = query;
// parse filter value in case we're comparing numbers ( dates )
if ( parsed || parser.type === 'numeric' ) {
txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) );
result = ts.filter.parseFilter( c, txt, index, true );
txt = $.trim( '' + data.iFilter.replace( tsf.regex.operators, '' ) );
result = tsf.parseFilter( c, txt, index, true );
query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
}
// iExact may be numeric - see issue #149;
@ -2898,13 +2939,13 @@
typeof data.cache !== 'undefined' ) {
cachedValue = data.cache;
} else {
txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
txt = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
cachedValue = ts.formatFloat( txt, table );
}
if ( />/.test( data.iFilter ) ) {
result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
} else if ( /</.test( data.iFilter ) ) {
result = /<=/.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
if ( tsf.regex.gtTest.test( data.iFilter ) ) {
result = tsf.regex.gteTest.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
} else if ( tsf.regex.ltTest.test( data.iFilter ) ) {
result = tsf.regex.lteTest.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
}
// keep showing all rows if nothing follows the operator
if ( !result && savedSearch === '' ) {
@ -2916,13 +2957,13 @@
},
// Look for a not match
notMatch: function( c, data ) {
if ( /^\!/.test( data.iFilter ) ) {
if ( tsf.regex.notTest.test( data.iFilter ) ) {
var indx,
txt = data.iFilter.replace( '!', '' ),
filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( ts.filter.regex.exact.test( filter ) ) {
filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( tsf.regex.exact.test( filter ) ) {
// look for exact not matches - see #628
filter = filter.replace( ts.filter.regex.exact, '' );
filter = filter.replace( tsf.regex.exact, '' );
return filter === '' ? true : $.trim( filter ) !== data.iExact;
} else {
indx = data.iExact.search( $.trim( filter ) );
@ -2934,27 +2975,27 @@
// Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
exact: function( c, data ) {
/*jshint eqeqeq:false */
if ( ts.filter.regex.exact.test( data.iFilter ) ) {
var txt = data.iFilter.replace( ts.filter.regex.exact, '' ),
filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( tsf.regex.exact.test( data.iFilter ) ) {
var txt = data.iFilter.replace( tsf.regex.exact, '' ),
filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
}
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 ) ) {
if ( tsf.regex.toTest.test( data.iFilter ) ) {
var result, tmp, range1, range2,
table = c.table,
index = data.index,
parsed = data.parsed[index],
// make sure the dash is for a range and not indicating a negative number
query = data.iFilter.split( ts.filter.regex.toSplit );
query = data.iFilter.split( tsf.regex.toSplit );
tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || '';
range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || '';
range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
tmp = query[0].replace( ts.regex.nondigit, '' ) || '';
range1 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
tmp = query[1].replace( ts.regex.nondigit, '' ) || '';
range2 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
// parse filter value in case we're comparing numbers ( dates )
if ( parsed || c.parsers[index].type === 'numeric' ) {
result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
@ -2965,7 +3006,7 @@
if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
result = data.cache;
} else {
tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
result = ts.formatFloat( tmp, table );
}
if ( range1 > range2 ) {
@ -2977,18 +3018,18 @@
},
// Look for wild card: ? = single, * = multiple, or | = logical OR
wild : function( c, data ) {
if ( /[\?\*\|]/.test( data.iFilter ) ) {
if ( tsf.regex.wildOrTest.test( data.iFilter ) ) {
var index = data.index,
parsed = data.parsed[ index ],
query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
query = '' + ( tsf.parseFilter( c, data.iFilter, index, parsed ) || '' );
// look for an exact match with the 'or' unless the 'filter-match' class is found
if ( !/\?\*/.test( query ) && data.nestedFilters ) {
if ( !tsf.regex.wildTest.test( query ) && data.nestedFilters ) {
query = data.isMatch ? query : '^(' + query + ')$';
}
// parsing the filter may not work properly when using wildcards =/
try {
return new RegExp(
query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
query.replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' ),
c.widgetOptions.filter_ignoreCase ? 'i' : ''
)
.test( data.exact );
@ -3000,12 +3041,12 @@
},
// fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
fuzzy: function( c, data ) {
if ( /^~/.test( data.iFilter ) ) {
if ( tsf.regex.fuzzyTest.test( data.iFilter ) ) {
var indx,
patternIndx = 0,
len = data.iExact.length,
txt = data.iFilter.slice( 1 ),
pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
pattern = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
for ( indx = 0; indx < len; indx++ ) {
if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
patternIndx += 1;
@ -3028,7 +3069,7 @@
}, ts.language );
var options, string, txt, $header, column, filters, val, fxn, noSelect,
regex = ts.filter.regex;
regex = tsf.regex;
c.$table.addClass( 'hasFilters' );
// define timers so using clearTimeout won't cause an undefined error
@ -3039,7 +3080,7 @@
wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
val = '\\{' + ts.filter.regex.query + '\\}';
val = '\\{' + tsf.regex.query + '\\}';
$.extend( regex, {
child : new RegExp( c.cssChildRow ),
filtered : new RegExp( wo.filter_filteredRow ),
@ -3048,9 +3089,20 @@
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' ),
orTest : /\|/,
orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
iQuery : new RegExp( val, 'i' ),
igQuery : new RegExp( val, 'ig' )
igQuery : new RegExp( val, 'ig' ),
operTest : /^[<>]=?/,
gtTest : />/,
gteTest : />=/,
ltTest : /</,
lteTest : /<=/,
notTest : /^\!/,
wildOrTest : /[\?\*\|]/,
wildTest : /\?\*/,
fuzzyTest : /^~/,
exactTest : /[=\"\|!]/
});
// don't build filter row if columnFilters is false or all columns are set to 'filter-false'
@ -3058,7 +3110,7 @@
val = c.$headers.filter( '.filter-false, .parser-false' ).length;
if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
// build filter row
ts.filter.buildRow( table, c, wo );
tsf.buildRow( table, c, wo );
}
txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
@ -3071,13 +3123,13 @@
c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
if ( !/(search|filter)/.test( event.type ) ) {
event.stopPropagation();
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
}
if ( event.type === 'filterReset' ) {
c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
ts.filter.searching( table, [] );
tsf.searching( table, [] );
} else if ( event.type === 'filterEnd' ) {
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
} else {
// send false argument to force a new search; otherwise if the filter hasn't changed,
// it will return
@ -3091,7 +3143,7 @@
// pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
// input ensures all inputs are updated when a search is triggered on the table
// $( 'table' ).trigger( 'search', [...] );
ts.filter.searching( table, filter, true );
tsf.searching( table, filter, true );
}
return false;
});
@ -3124,7 +3176,7 @@
noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
options = '';
if ( fxn === true && noSelect ) {
ts.filter.buildSelect( table, column );
tsf.buildSelect( table, column );
} else if ( typeof fxn === 'object' && noSelect ) {
// add custom drop down list
for ( string in fxn ) {
@ -3157,7 +3209,7 @@
fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column );
if ( fxn ) {
// updating so the extra options are appended
ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
tsf.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
}
}
}
@ -3165,22 +3217,22 @@
}
// not really updating, but if the column has both the 'filter-select' class &
// filter_functions set to true, it would append the same options twice.
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
tsf.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
if ( wo.filter_external ) {
ts.filter.bindSearch( table, wo.filter_external );
tsf.bindSearch( table, wo.filter_external );
}
if ( wo.filter_hideFilters ) {
ts.filter.hideFilters( table, c );
tsf.hideFilters( table, c );
}
// show processing icon
if ( c.showProcessing ) {
txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
c.$table
.unbind( txt.replace( /\s+/g, ' ' ) )
.unbind( txt.replace( ts.regex.spaces, ' ' ) )
.bind( txt, function( event, columns ) {
// only add processing to certain columns to all columns
$header = ( columns ) ?
@ -3200,11 +3252,11 @@
// add default values
txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
c.$table
.unbind( txt.replace( /\s+/g, ' ' ) )
.unbind( txt.replace( ts.regex.spaces, ' ' ) )
.bind( txt, function() {
// redefine 'wo' as it does not update properly inside this callback
var wo = this.config.widgetOptions;
filters = ts.filter.setDefaults( table, c, wo ) || [];
filters = tsf.setDefaults( table, c, wo ) || [];
if ( filters.length ) {
// prevent delayInit from triggering a cache build if filters are empty
if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
@ -3215,7 +3267,7 @@
// trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
setTimeout( function() {
if ( !wo.filter_initialized ) {
ts.filter.filterInitComplete( c );
tsf.filterInitComplete( c );
}
}, 100 );
});
@ -3223,7 +3275,7 @@
if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
c.$table.trigger( 'filterFomatterUpdate' );
setTimeout( function() {
ts.filter.filterInitComplete( c );
tsf.filterInitComplete( c );
}, 100 );
}
},
@ -3244,7 +3296,7 @@
completed = function() {
wo.filter_initialized = true;
c.$table.trigger( 'filterInit', c );
ts.filter.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
tsf.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
};
if ( $.isEmptyObject( wo.filter_formatter ) ) {
completed();
@ -3396,7 +3448,7 @@
// use data attribute instead of jQuery data since the head is cloned without including
// the data/binding
.attr( 'data-lastSearchTime', new Date().getTime() )
.unbind( tmp.replace( /\s+/g, ' ' ) )
.unbind( tmp.replace( ts.regex.spaces, ' ' ) )
// include change for select - fixes #473
.bind( 'keyup' + namespace, function( event ) {
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
@ -3416,7 +3468,7 @@
return;
}
// change event = no delay; last true flag tells getFilters to skip newest timed input
ts.filter.searching( table, true, true );
tsf.searching( table, true, true );
})
.bind( 'search change keypress '.split( ' ' ).join( namespace + ' ' ), function( event ) {
// don't get cached data, in case data-column changes dynamically
@ -3427,7 +3479,7 @@
event.preventDefault();
// init search with no delay
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
ts.filter.searching( table, false, true );
tsf.searching( table, false, true );
}
});
},
@ -3437,11 +3489,11 @@
if ( typeof filter === 'undefined' || filter === true ) {
// delay filtering
wo.searchTimer = setTimeout( function() {
ts.filter.checkFilters( table, filter, skipFirst );
tsf.checkFilters( table, filter, skipFirst );
}, wo.filter_liveSearch ? wo.filter_searchDelay : 10 );
} else {
// skip delay
ts.filter.checkFilters( table, filter, skipFirst );
tsf.checkFilters( table, filter, skipFirst );
}
},
checkFilters: function( table, filter, skipFirst ) {
@ -3455,7 +3507,7 @@
// update cache if delayInit set & pager has initialized ( after user initiates a search )
if ( c.delayInit && c.pager && c.pager.initialized ) {
c.$table.trigger( 'updateCache', [ function() {
ts.filter.checkFilters( table, false, skipFirst );
tsf.checkFilters( table, false, skipFirst );
} ] );
}
return;
@ -3486,11 +3538,11 @@
if ( c.showProcessing ) {
// give it time for the processing icon to kick in
setTimeout( function() {
ts.filter.findRows( table, filters, combinedFilters );
tsf.findRows( table, filters, combinedFilters );
return false;
}, 30 );
} else {
ts.filter.findRows( table, filters, combinedFilters );
tsf.findRows( table, filters, combinedFilters );
return false;
}
},
@ -3533,8 +3585,8 @@
},
defaultFilter: function( filter, mask ) {
if ( filter === '' ) { return filter; }
var regex = ts.filter.regex.iQuery,
maskLen = mask.match( ts.filter.regex.igQuery ).length,
var regex = tsf.regex.iQuery,
maskLen = mask.match( tsf.regex.igQuery ).length,
query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
len = query.length - 1,
indx = 0,
@ -3570,7 +3622,7 @@
// & don't target 'all' column inputs if they don't exist
targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
columns = [],
val = $.trim( ts.filter.getLatestSearch( $input ).attr( 'data-column' ) || '' );
val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
if ( !/[,-]/.test(val) && val.length === 1 ) {
return parseInt( val, 10 );
}
@ -3620,9 +3672,9 @@
var ffxn,
filterMatched = null,
matches = null;
for ( ffxn in ts.filter.types ) {
for ( ffxn in tsf.types ) {
if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
matches = ts.filter.types[ffxn]( c, data, vars );
matches = tsf.types[ffxn]( c, data, vars );
if ( matches !== null ) {
filterMatched = matches;
}
@ -3633,7 +3685,7 @@
processRow: function( c, data, vars ) {
var hasSelect, result, val, filterMatched,
fxn, ffxn, txt,
regex = ts.filter.regex,
regex = tsf.regex,
wo = c.widgetOptions,
showRow = true,
@ -3642,7 +3694,7 @@
// for the entire row - see #998
columnIndex = wo.filter_$anyMatch && wo.filter_$anyMatch.length ?
// look for multiple columns '1-3,4-6,8'
ts.filter.multipleColumns( c, wo.filter_$anyMatch ) :
tsf.multipleColumns( c, wo.filter_$anyMatch ) :
[];
data.$cells = data.$row.children();
@ -3671,7 +3723,7 @@
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
vars.excludeMatch = vars.noAnyMatch;
filterMatched = ts.filter.processTypes( c, data, vars );
filterMatched = tsf.processTypes( c, data, vars );
if ( filterMatched !== null ) {
showRow = filterMatched;
@ -3732,7 +3784,7 @@
val = true;
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
data.filter = ts.filter.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
data.filter = tsf.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
// val is used to indicate that a filter select is using a default filter;
// so we override the exact & partial matches
val = false;
@ -3763,13 +3815,13 @@
if ( filterMatched === null ) {
// cycle through the different filters
// filters return a boolean or null if nothing matches
filterMatched = ts.filter.processTypes( c, data, vars );
filterMatched = tsf.processTypes( c, data, vars );
if ( filterMatched !== null ) {
result = filterMatched;
// Look for match, and add child row data for matching
} else {
txt = ( data.iExact + data.childRowText )
.indexOf( ts.filter.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
.indexOf( tsf.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
}
} else {
@ -3789,7 +3841,7 @@
isChild, childRow, lastSearch, showRow, time, val, indx,
notFiltered, searchFiltered, query, injected, res, id, txt,
storedFilters = $.extend( [], filters ),
regex = ts.filter.regex,
regex = tsf.regex,
c = table.config,
wo = c.widgetOptions,
// data object passed to filters; anyMatch is a flag for the filters
@ -3866,7 +3918,7 @@
data.anyMatchFlag = true;
data.anyMatchFilter = '' + (
filters[ c.columns ] ||
wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() ||
wo.filter_$anyMatch && tsf.getLatestSearch( wo.filter_$anyMatch ).val() ||
''
);
if ( wo.filter_columnAnyMatch ) {
@ -3908,10 +3960,10 @@
// if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
!regex.alreadyFiltered.test( val ) &&
// if we are not doing exact matches, using '|' ( logical or ) or not '!'
!/[=\"\|!]/.test( val ) &&
!regex.exactTest.test( val ) &&
// don't search only filtered if the value is negative
// ( '> -10' => '> -100' will ignore hidden rows )
!( /(>=?\s*-\d)/.test( val ) || /(<=?\s*\d)/.test( val ) ) &&
!( regex.isNeg1.test( val ) || regex.isNeg2.test( val ) ) &&
// if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
!( val !== '' && c.$filters && c.$filters.eq( indx ).find( 'select' ).length &&
!c.$headerIndexed[indx].hasClass( 'filter-match' ) );
@ -3930,7 +3982,7 @@
data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
}
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) {
data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
data.anyMatchFilter = tsf.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
// clear search filtered flag because default filters are not saved to the last search
searchFiltered = false;
}
@ -3973,7 +4025,7 @@
'';
}
showRow = ts.filter.processRow( c, data, vars );
showRow = tsf.processRow( c, data, vars );
childRow = rowData.$row.filter( ':gt( 0 )' );
if ( wo.filter_childRows && childRow.length ) {
@ -3984,7 +4036,7 @@
data.cacheArray = rowData.child[ indx ];
data.rawArray = data.cacheArray;
// use OR comparison on child rows
showRow = showRow || ts.filter.processRow( c, data, vars );
showRow = showRow || tsf.processRow( c, data, vars );
}
}
childRow.toggleClass( wo.filter_filteredRow, !showRow );
@ -4046,7 +4098,7 @@
}
if ( arry === false ) {
// fall back to original method
arry = ts.filter.getOptions( table, column, onlyAvail );
arry = tsf.getOptions( table, column, onlyAvail );
}
// get unique elements and sort the list
@ -4158,13 +4210,13 @@
// nothing included in arry ( external source ), so get the options from
// filter_selectSource or column data
if ( typeof arry === 'undefined' || arry === '' ) {
arry = ts.filter.getOptionSource( table, column, onlyAvail );
arry = tsf.getOptionSource( table, column, onlyAvail );
}
if ( $.isArray( arry ) ) {
// build option list
for ( indx = 0; indx < arry.length; indx++ ) {
txt = arry[indx] = ( '' + arry[indx] ).replace( /\"/g, '&quot;' );
txt = arry[indx] = ( '' + arry[indx] ).replace( tsf.regex.quote, '&quot;' );
val = txt;
// allow including a symbol in the selectSource array
// 'a-z|A through Z' so that 'a-z' becomes the option value
@ -4220,7 +4272,7 @@
// look for the filter-select class; build/update it if found
if ( ( $header.hasClass( 'filter-select' ) ||
ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
ts.filter.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
tsf.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
}
}
}
@ -4256,7 +4308,7 @@
$column = $filters.filter( cols );
if ( $column.length ) {
// move the latest search to the first slot in the array
$column = ts.filter.getLatestSearch( $column );
$column = tsf.getLatestSearch( $column );
if ( $.isArray( setFilters ) ) {
// skip first ( latest input ) to maintain cursor position while typing
if ( skipFirst && $column.length > 1 ) {
@ -4306,7 +4358,7 @@
// ensure new set filters are applied, even if the search is the same
c.lastCombinedFilter = null;
c.lastSearch = [];
ts.filter.searching( c.table, filter, skipFirst );
tsf.searching( c.table, filter, skipFirst );
c.$table.trigger( 'filterFomatterUpdate' );
}
return !!valid;

View File

@ -1,4 +1,4 @@
/*! TableSorter (FORK) v2.23.1 *//*
/*! TableSorter (FORK) v2.23.2 *//*
* Client-side table sorting with ease!
* @requires jQuery v1.2.6+
*
@ -26,7 +26,7 @@
var ts = this;
ts.version = '2.23.1';
ts.version = '2.23.2';
ts.parsers = [];
ts.widgets = [];

View File

@ -4,7 +4,7 @@
*/
/*! tablesorter (FORK) - updated 08-21-2015 (v2.23.1)*/
/*! tablesorter (FORK) - updated 08-23-2015 (v2.23.2)*/
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
(function(factory) {
if (typeof define === 'function' && define.amd) {
@ -372,14 +372,15 @@
})(jQuery);
/*! Widget: filter - updated 8/17/2015 (v2.23.0) *//*
/*! Widget: filter - updated 8/23/2015 (v2.23.2) *//*
* Requires tablesorter v2.8+ and jQuery 1.7+
* by Rob Garrison
*/
;( function ( $ ) {
'use strict';
var ts = $.tablesorter || {},
tscss = ts.css;
var tsf,
ts = $.tablesorter || {},
tscss = ts.css;
$.extend( tscss, {
filterRow : 'tablesorter-filter-row',
@ -423,7 +424,7 @@
},
format: function( table, c, wo ) {
if ( !c.$table.hasClass( 'hasFilters' ) ) {
ts.filter.init( table, c, wo );
tsf.init( table, c, wo );
}
},
remove: function( table, c, wo, refreshing ) {
@ -435,7 +436,7 @@
$table
.removeClass( 'hasFilters' )
// add .tsfilter namespace to all BUT search
.unbind( events.replace( /\s+/g, ' ' ) )
.unbind( events.replace( ts.regex.spaces, ' ' ) )
// remove the filter row even if refreshing, because the column might have been moved
.find( '.' + tscss.filterRow ).remove();
if ( refreshing ) { return; }
@ -450,7 +451,7 @@
}
});
ts.filter = {
tsf = ts.filter = {
// regex used in filter 'check' functions - not for general use and not documented
regex: {
@ -459,9 +460,13 @@
filtered : /filtered/, // filtered (hidden) row class name; updated in the script
type : /undefined|number/, // check type
exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==')
nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser)
operators : /[<>=]/g, // replace operators
query : '(q|query)' // replace filter queries
query : '(q|query)', // replace filter queries
wild01 : /\?/g, // wild card match 0 or 1
wild0More : /\*/g, // wild care match 0 or more
quote : /\"/g,
isNeg1 : /(>=?\s*-\d)/,
isNeg2 : /(<=?\s*\d)/
},
// function( c, data ) { }
// c = table.config
@ -478,27 +483,27 @@
// 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 ) ) {
if ( tsf.regex.orTest.test( data.iFilter ) || tsf.regex.orSplit.test( data.filter ) ) {
var indx, filterMatched, 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 ),
filter = data.filter.split( tsf.regex.orSplit ),
iFilter = data.iFilter.split( tsf.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 ) || '' ) + ')';
data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
query = '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
try {
// use try/catch, because query may not be a valid regex if "|" is contained within a partial regex search,
// e.g "/(Alex|Aar" -> Uncaught SyntaxError: Invalid regular expression: /(/(Alex)/: Unterminated group
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 );
filterMatched = regex.test( data2.exact ) || tsf.processTypes( c, data2, vars );
if ( filterMatched ) {
return filterMatched;
}
@ -513,27 +518,27 @@
},
// Look for an AND or && operator ( logical and )
and : function( c, data, vars ) {
if ( ts.filter.regex.andTest.test( data.filter ) ) {
if ( tsf.regex.andTest.test( data.filter ) ) {
var indx, filterMatched, result, 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 ),
filter = data.filter.split( tsf.regex.andSplit ),
iFilter = data.iFilter.split( tsf.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 ) || '' ) + ')' )
data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
query = ( '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
// replace wild cards since /(a*)/i will match anything
.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
.replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' );
try {
// use try/catch just in case RegExp is invalid
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 ) );
result = ( regex.test( data2.exact ) || tsf.processTypes( c, data2, vars ) );
if ( indx === 0 ) {
filterMatched = result;
} else {
@ -550,10 +555,10 @@
},
// Look for regex
regex: function( c, data ) {
if ( ts.filter.regex.regex.test( data.filter ) ) {
if ( tsf.regex.regex.test( data.filter ) ) {
var matches,
// cache regex per column for optimal speed
regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
regex = data.filter_regexCache[ data.index ] || tsf.regex.regex.exec( data.filter ),
isRegex = regex instanceof RegExp;
try {
if ( !isRegex ) {
@ -572,18 +577,18 @@
// Look for operators >, >=, < or <=
operators: function( c, data ) {
// ignore empty strings... because '' < 10 is true
if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) {
if ( tsf.regex.operTest.test( data.iFilter ) && data.iExact !== '' ) {
var cachedValue, result, txt,
table = c.table,
index = data.index,
parsed = data.parsed[index],
query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ),
query = ts.formatFloat( data.iFilter.replace( tsf.regex.operators, '' ), table ),
parser = c.parsers[index],
savedSearch = query;
// parse filter value in case we're comparing numbers ( dates )
if ( parsed || parser.type === 'numeric' ) {
txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) );
result = ts.filter.parseFilter( c, txt, index, true );
txt = $.trim( '' + data.iFilter.replace( tsf.regex.operators, '' ) );
result = tsf.parseFilter( c, txt, index, true );
query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
}
// iExact may be numeric - see issue #149;
@ -592,13 +597,13 @@
typeof data.cache !== 'undefined' ) {
cachedValue = data.cache;
} else {
txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
txt = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
cachedValue = ts.formatFloat( txt, table );
}
if ( />/.test( data.iFilter ) ) {
result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
} else if ( /</.test( data.iFilter ) ) {
result = /<=/.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
if ( tsf.regex.gtTest.test( data.iFilter ) ) {
result = tsf.regex.gteTest.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
} else if ( tsf.regex.ltTest.test( data.iFilter ) ) {
result = tsf.regex.lteTest.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
}
// keep showing all rows if nothing follows the operator
if ( !result && savedSearch === '' ) {
@ -610,13 +615,13 @@
},
// Look for a not match
notMatch: function( c, data ) {
if ( /^\!/.test( data.iFilter ) ) {
if ( tsf.regex.notTest.test( data.iFilter ) ) {
var indx,
txt = data.iFilter.replace( '!', '' ),
filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( ts.filter.regex.exact.test( filter ) ) {
filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( tsf.regex.exact.test( filter ) ) {
// look for exact not matches - see #628
filter = filter.replace( ts.filter.regex.exact, '' );
filter = filter.replace( tsf.regex.exact, '' );
return filter === '' ? true : $.trim( filter ) !== data.iExact;
} else {
indx = data.iExact.search( $.trim( filter ) );
@ -628,27 +633,27 @@
// Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
exact: function( c, data ) {
/*jshint eqeqeq:false */
if ( ts.filter.regex.exact.test( data.iFilter ) ) {
var txt = data.iFilter.replace( ts.filter.regex.exact, '' ),
filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
if ( tsf.regex.exact.test( data.iFilter ) ) {
var txt = data.iFilter.replace( tsf.regex.exact, '' ),
filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
}
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 ) ) {
if ( tsf.regex.toTest.test( data.iFilter ) ) {
var result, tmp, range1, range2,
table = c.table,
index = data.index,
parsed = data.parsed[index],
// make sure the dash is for a range and not indicating a negative number
query = data.iFilter.split( ts.filter.regex.toSplit );
query = data.iFilter.split( tsf.regex.toSplit );
tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || '';
range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || '';
range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
tmp = query[0].replace( ts.regex.nondigit, '' ) || '';
range1 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
tmp = query[1].replace( ts.regex.nondigit, '' ) || '';
range2 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
// parse filter value in case we're comparing numbers ( dates )
if ( parsed || c.parsers[index].type === 'numeric' ) {
result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
@ -659,7 +664,7 @@
if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
result = data.cache;
} else {
tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
result = ts.formatFloat( tmp, table );
}
if ( range1 > range2 ) {
@ -671,18 +676,18 @@
},
// Look for wild card: ? = single, * = multiple, or | = logical OR
wild : function( c, data ) {
if ( /[\?\*\|]/.test( data.iFilter ) ) {
if ( tsf.regex.wildOrTest.test( data.iFilter ) ) {
var index = data.index,
parsed = data.parsed[ index ],
query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
query = '' + ( tsf.parseFilter( c, data.iFilter, index, parsed ) || '' );
// look for an exact match with the 'or' unless the 'filter-match' class is found
if ( !/\?\*/.test( query ) && data.nestedFilters ) {
if ( !tsf.regex.wildTest.test( query ) && data.nestedFilters ) {
query = data.isMatch ? query : '^(' + query + ')$';
}
// parsing the filter may not work properly when using wildcards =/
try {
return new RegExp(
query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
query.replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' ),
c.widgetOptions.filter_ignoreCase ? 'i' : ''
)
.test( data.exact );
@ -694,12 +699,12 @@
},
// fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
fuzzy: function( c, data ) {
if ( /^~/.test( data.iFilter ) ) {
if ( tsf.regex.fuzzyTest.test( data.iFilter ) ) {
var indx,
patternIndx = 0,
len = data.iExact.length,
txt = data.iFilter.slice( 1 ),
pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
pattern = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
for ( indx = 0; indx < len; indx++ ) {
if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
patternIndx += 1;
@ -722,7 +727,7 @@
}, ts.language );
var options, string, txt, $header, column, filters, val, fxn, noSelect,
regex = ts.filter.regex;
regex = tsf.regex;
c.$table.addClass( 'hasFilters' );
// define timers so using clearTimeout won't cause an undefined error
@ -733,7 +738,7 @@
wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
val = '\\{' + ts.filter.regex.query + '\\}';
val = '\\{' + tsf.regex.query + '\\}';
$.extend( regex, {
child : new RegExp( c.cssChildRow ),
filtered : new RegExp( wo.filter_filteredRow ),
@ -742,9 +747,20 @@
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' ),
orTest : /\|/,
orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
iQuery : new RegExp( val, 'i' ),
igQuery : new RegExp( val, 'ig' )
igQuery : new RegExp( val, 'ig' ),
operTest : /^[<>]=?/,
gtTest : />/,
gteTest : />=/,
ltTest : /</,
lteTest : /<=/,
notTest : /^\!/,
wildOrTest : /[\?\*\|]/,
wildTest : /\?\*/,
fuzzyTest : /^~/,
exactTest : /[=\"\|!]/
});
// don't build filter row if columnFilters is false or all columns are set to 'filter-false'
@ -752,7 +768,7 @@
val = c.$headers.filter( '.filter-false, .parser-false' ).length;
if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
// build filter row
ts.filter.buildRow( table, c, wo );
tsf.buildRow( table, c, wo );
}
txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
@ -765,13 +781,13 @@
c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
if ( !/(search|filter)/.test( event.type ) ) {
event.stopPropagation();
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
}
if ( event.type === 'filterReset' ) {
c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
ts.filter.searching( table, [] );
tsf.searching( table, [] );
} else if ( event.type === 'filterEnd' ) {
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
} else {
// send false argument to force a new search; otherwise if the filter hasn't changed,
// it will return
@ -785,7 +801,7 @@
// pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
// input ensures all inputs are updated when a search is triggered on the table
// $( 'table' ).trigger( 'search', [...] );
ts.filter.searching( table, filter, true );
tsf.searching( table, filter, true );
}
return false;
});
@ -818,7 +834,7 @@
noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
options = '';
if ( fxn === true && noSelect ) {
ts.filter.buildSelect( table, column );
tsf.buildSelect( table, column );
} else if ( typeof fxn === 'object' && noSelect ) {
// add custom drop down list
for ( string in fxn ) {
@ -851,7 +867,7 @@
fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column );
if ( fxn ) {
// updating so the extra options are appended
ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
tsf.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
}
}
}
@ -859,22 +875,22 @@
}
// not really updating, but if the column has both the 'filter-select' class &
// filter_functions set to true, it would append the same options twice.
ts.filter.buildDefault( table, true );
tsf.buildDefault( table, true );
ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
tsf.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
if ( wo.filter_external ) {
ts.filter.bindSearch( table, wo.filter_external );
tsf.bindSearch( table, wo.filter_external );
}
if ( wo.filter_hideFilters ) {
ts.filter.hideFilters( table, c );
tsf.hideFilters( table, c );
}
// show processing icon
if ( c.showProcessing ) {
txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
c.$table
.unbind( txt.replace( /\s+/g, ' ' ) )
.unbind( txt.replace( ts.regex.spaces, ' ' ) )
.bind( txt, function( event, columns ) {
// only add processing to certain columns to all columns
$header = ( columns ) ?
@ -894,11 +910,11 @@
// add default values
txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
c.$table
.unbind( txt.replace( /\s+/g, ' ' ) )
.unbind( txt.replace( ts.regex.spaces, ' ' ) )
.bind( txt, function() {
// redefine 'wo' as it does not update properly inside this callback
var wo = this.config.widgetOptions;
filters = ts.filter.setDefaults( table, c, wo ) || [];
filters = tsf.setDefaults( table, c, wo ) || [];
if ( filters.length ) {
// prevent delayInit from triggering a cache build if filters are empty
if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
@ -909,7 +925,7 @@
// trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
setTimeout( function() {
if ( !wo.filter_initialized ) {
ts.filter.filterInitComplete( c );
tsf.filterInitComplete( c );
}
}, 100 );
});
@ -917,7 +933,7 @@
if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
c.$table.trigger( 'filterFomatterUpdate' );
setTimeout( function() {
ts.filter.filterInitComplete( c );
tsf.filterInitComplete( c );
}, 100 );
}
},
@ -938,7 +954,7 @@
completed = function() {
wo.filter_initialized = true;
c.$table.trigger( 'filterInit', c );
ts.filter.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
tsf.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
};
if ( $.isEmptyObject( wo.filter_formatter ) ) {
completed();
@ -1090,7 +1106,7 @@
// use data attribute instead of jQuery data since the head is cloned without including
// the data/binding
.attr( 'data-lastSearchTime', new Date().getTime() )
.unbind( tmp.replace( /\s+/g, ' ' ) )
.unbind( tmp.replace( ts.regex.spaces, ' ' ) )
// include change for select - fixes #473
.bind( 'keyup' + namespace, function( event ) {
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
@ -1110,7 +1126,7 @@
return;
}
// change event = no delay; last true flag tells getFilters to skip newest timed input
ts.filter.searching( table, true, true );
tsf.searching( table, true, true );
})
.bind( 'search change keypress '.split( ' ' ).join( namespace + ' ' ), function( event ) {
// don't get cached data, in case data-column changes dynamically
@ -1121,7 +1137,7 @@
event.preventDefault();
// init search with no delay
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
ts.filter.searching( table, false, true );
tsf.searching( table, false, true );
}
});
},
@ -1131,11 +1147,11 @@
if ( typeof filter === 'undefined' || filter === true ) {
// delay filtering
wo.searchTimer = setTimeout( function() {
ts.filter.checkFilters( table, filter, skipFirst );
tsf.checkFilters( table, filter, skipFirst );
}, wo.filter_liveSearch ? wo.filter_searchDelay : 10 );
} else {
// skip delay
ts.filter.checkFilters( table, filter, skipFirst );
tsf.checkFilters( table, filter, skipFirst );
}
},
checkFilters: function( table, filter, skipFirst ) {
@ -1149,7 +1165,7 @@
// update cache if delayInit set & pager has initialized ( after user initiates a search )
if ( c.delayInit && c.pager && c.pager.initialized ) {
c.$table.trigger( 'updateCache', [ function() {
ts.filter.checkFilters( table, false, skipFirst );
tsf.checkFilters( table, false, skipFirst );
} ] );
}
return;
@ -1180,11 +1196,11 @@
if ( c.showProcessing ) {
// give it time for the processing icon to kick in
setTimeout( function() {
ts.filter.findRows( table, filters, combinedFilters );
tsf.findRows( table, filters, combinedFilters );
return false;
}, 30 );
} else {
ts.filter.findRows( table, filters, combinedFilters );
tsf.findRows( table, filters, combinedFilters );
return false;
}
},
@ -1227,8 +1243,8 @@
},
defaultFilter: function( filter, mask ) {
if ( filter === '' ) { return filter; }
var regex = ts.filter.regex.iQuery,
maskLen = mask.match( ts.filter.regex.igQuery ).length,
var regex = tsf.regex.iQuery,
maskLen = mask.match( tsf.regex.igQuery ).length,
query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
len = query.length - 1,
indx = 0,
@ -1264,7 +1280,7 @@
// & don't target 'all' column inputs if they don't exist
targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
columns = [],
val = $.trim( ts.filter.getLatestSearch( $input ).attr( 'data-column' ) || '' );
val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
if ( !/[,-]/.test(val) && val.length === 1 ) {
return parseInt( val, 10 );
}
@ -1314,9 +1330,9 @@
var ffxn,
filterMatched = null,
matches = null;
for ( ffxn in ts.filter.types ) {
for ( ffxn in tsf.types ) {
if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
matches = ts.filter.types[ffxn]( c, data, vars );
matches = tsf.types[ffxn]( c, data, vars );
if ( matches !== null ) {
filterMatched = matches;
}
@ -1327,7 +1343,7 @@
processRow: function( c, data, vars ) {
var hasSelect, result, val, filterMatched,
fxn, ffxn, txt,
regex = ts.filter.regex,
regex = tsf.regex,
wo = c.widgetOptions,
showRow = true,
@ -1336,7 +1352,7 @@
// for the entire row - see #998
columnIndex = wo.filter_$anyMatch && wo.filter_$anyMatch.length ?
// look for multiple columns '1-3,4-6,8'
ts.filter.multipleColumns( c, wo.filter_$anyMatch ) :
tsf.multipleColumns( c, wo.filter_$anyMatch ) :
[];
data.$cells = data.$row.children();
@ -1365,7 +1381,7 @@
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
vars.excludeMatch = vars.noAnyMatch;
filterMatched = ts.filter.processTypes( c, data, vars );
filterMatched = tsf.processTypes( c, data, vars );
if ( filterMatched !== null ) {
showRow = filterMatched;
@ -1426,7 +1442,7 @@
val = true;
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
data.filter = ts.filter.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
data.filter = tsf.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
// val is used to indicate that a filter select is using a default filter;
// so we override the exact & partial matches
val = false;
@ -1457,13 +1473,13 @@
if ( filterMatched === null ) {
// cycle through the different filters
// filters return a boolean or null if nothing matches
filterMatched = ts.filter.processTypes( c, data, vars );
filterMatched = tsf.processTypes( c, data, vars );
if ( filterMatched !== null ) {
result = filterMatched;
// Look for match, and add child row data for matching
} else {
txt = ( data.iExact + data.childRowText )
.indexOf( ts.filter.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
.indexOf( tsf.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
}
} else {
@ -1483,7 +1499,7 @@
isChild, childRow, lastSearch, showRow, time, val, indx,
notFiltered, searchFiltered, query, injected, res, id, txt,
storedFilters = $.extend( [], filters ),
regex = ts.filter.regex,
regex = tsf.regex,
c = table.config,
wo = c.widgetOptions,
// data object passed to filters; anyMatch is a flag for the filters
@ -1560,7 +1576,7 @@
data.anyMatchFlag = true;
data.anyMatchFilter = '' + (
filters[ c.columns ] ||
wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() ||
wo.filter_$anyMatch && tsf.getLatestSearch( wo.filter_$anyMatch ).val() ||
''
);
if ( wo.filter_columnAnyMatch ) {
@ -1602,10 +1618,10 @@
// if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
!regex.alreadyFiltered.test( val ) &&
// if we are not doing exact matches, using '|' ( logical or ) or not '!'
!/[=\"\|!]/.test( val ) &&
!regex.exactTest.test( val ) &&
// don't search only filtered if the value is negative
// ( '> -10' => '> -100' will ignore hidden rows )
!( /(>=?\s*-\d)/.test( val ) || /(<=?\s*\d)/.test( val ) ) &&
!( regex.isNeg1.test( val ) || regex.isNeg2.test( val ) ) &&
// if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
!( val !== '' && c.$filters && c.$filters.eq( indx ).find( 'select' ).length &&
!c.$headerIndexed[indx].hasClass( 'filter-match' ) );
@ -1624,7 +1640,7 @@
data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
}
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) {
data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
data.anyMatchFilter = tsf.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
// clear search filtered flag because default filters are not saved to the last search
searchFiltered = false;
}
@ -1667,7 +1683,7 @@
'';
}
showRow = ts.filter.processRow( c, data, vars );
showRow = tsf.processRow( c, data, vars );
childRow = rowData.$row.filter( ':gt( 0 )' );
if ( wo.filter_childRows && childRow.length ) {
@ -1678,7 +1694,7 @@
data.cacheArray = rowData.child[ indx ];
data.rawArray = data.cacheArray;
// use OR comparison on child rows
showRow = showRow || ts.filter.processRow( c, data, vars );
showRow = showRow || tsf.processRow( c, data, vars );
}
}
childRow.toggleClass( wo.filter_filteredRow, !showRow );
@ -1740,7 +1756,7 @@
}
if ( arry === false ) {
// fall back to original method
arry = ts.filter.getOptions( table, column, onlyAvail );
arry = tsf.getOptions( table, column, onlyAvail );
}
// get unique elements and sort the list
@ -1852,13 +1868,13 @@
// nothing included in arry ( external source ), so get the options from
// filter_selectSource or column data
if ( typeof arry === 'undefined' || arry === '' ) {
arry = ts.filter.getOptionSource( table, column, onlyAvail );
arry = tsf.getOptionSource( table, column, onlyAvail );
}
if ( $.isArray( arry ) ) {
// build option list
for ( indx = 0; indx < arry.length; indx++ ) {
txt = arry[indx] = ( '' + arry[indx] ).replace( /\"/g, '&quot;' );
txt = arry[indx] = ( '' + arry[indx] ).replace( tsf.regex.quote, '&quot;' );
val = txt;
// allow including a symbol in the selectSource array
// 'a-z|A through Z' so that 'a-z' becomes the option value
@ -1914,7 +1930,7 @@
// look for the filter-select class; build/update it if found
if ( ( $header.hasClass( 'filter-select' ) ||
ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
ts.filter.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
tsf.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
}
}
}
@ -1950,7 +1966,7 @@
$column = $filters.filter( cols );
if ( $column.length ) {
// move the latest search to the first slot in the array
$column = ts.filter.getLatestSearch( $column );
$column = tsf.getLatestSearch( $column );
if ( $.isArray( setFilters ) ) {
// skip first ( latest input ) to maintain cursor position while typing
if ( skipFirst && $column.length > 1 ) {
@ -2000,7 +2016,7 @@
// ensure new set filters are applied, even if the search is the same
c.lastCombinedFilter = null;
c.lastSearch = [];
ts.filter.searching( c.table, filter, skipFirst );
tsf.searching( c.table, filter, skipFirst );
c.$table.trigger( 'filterFomatterUpdate' );
}
return !!valid;

View File

@ -1,4 +1,4 @@
/* Widget: columnSelector (responsive table widget) - updated 8/17/2015 (v2.23.0) *//*
/* Widget: columnSelector (responsive table widget) - updated 8/23/2015 (v2.23.2) *//*
* Requires tablesorter v2.8+ and jQuery 1.7+
* by Justin Hallett & Rob Garrison
*/

View File

@ -1,4 +1,4 @@
/*! Widget: filter - updated 8/17/2015 (v2.23.0) *//*
/*! Widget: filter - updated 8/23/2015 (v2.23.2) *//*
* Requires tablesorter v2.8+ and jQuery 1.7+
* by Rob Garrison
*/

View File

@ -1,7 +1,7 @@
{
"name": "tablesorter",
"title": "tablesorter",
"version": "2.23.1",
"version": "2.23.2",
"description": "tablesorter (FORK) is a jQuery plugin for turning a standard HTML table with THEAD and TBODY tags into a sortable table without page refreshes. tablesorter can successfully parse and sort many types of data including linked data in a cell.",
"author": {
"name": "Christian Bach",

View File

@ -1,7 +1,7 @@
{
"name": "tablesorter",
"title": "tablesorter",
"version": "2.23.1",
"version": "2.23.2",
"description": "tablesorter is a jQuery plugin for turning a standard HTML table with THEAD and TBODY tags into a sortable table without page refreshes. tablesorter can successfully parse and sort many types of data including linked data in a cell.\n\nThis forked version adds lots of new enhancements including: alphanumeric sorting, pager callback functons, multiple widgets providing column styling, ui theme application, sticky headers, column filters and resizer, as well as extended documentation with a lot more demos.",
"author": {
"name": "Christian Bach",