jquery-tablesorter 1.18.1 → 1.18.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -4
- data/lib/jquery-tablesorter/version.rb +1 -1
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.combined.js +218 -155
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +79 -43
- data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets.js +139 -112
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-columnSelector.js +6 -4
- data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-filter.js +138 -111
- metadata +2 -2
@@ -1,4 +1,4 @@
|
|
1
|
-
/*! TableSorter (FORK) v2.23.
|
1
|
+
/*! TableSorter (FORK) v2.23.2 *//*
|
2
2
|
* Client-side table sorting with ease!
|
3
3
|
* @requires jQuery v1.2.6+
|
4
4
|
*
|
@@ -26,7 +26,7 @@
|
|
26
26
|
|
27
27
|
var ts = this;
|
28
28
|
|
29
|
-
ts.version = '2.23.
|
29
|
+
ts.version = '2.23.2';
|
30
30
|
|
31
31
|
ts.parsers = [];
|
32
32
|
ts.widgets = [];
|
@@ -151,6 +151,15 @@
|
|
151
151
|
nextNone : 'activate to remove the sort'
|
152
152
|
};
|
153
153
|
|
154
|
+
ts.regex = {
|
155
|
+
templateContent : /\{content\}/g,
|
156
|
+
templateIcon : /\{icon\}/g,
|
157
|
+
templateName : /\{name\}/i,
|
158
|
+
spaces : /\s+/g,
|
159
|
+
nonWord : /\W/g,
|
160
|
+
formElements : /(input|select|button|textarea)/i
|
161
|
+
};
|
162
|
+
|
154
163
|
// These methods can be applied on table.config instance
|
155
164
|
ts.instanceMethods = {};
|
156
165
|
|
@@ -443,7 +452,9 @@
|
|
443
452
|
// if headerTemplate is empty, don't reformat the header cell
|
444
453
|
if ( c.headerTemplate !== '' && !$t.find('.' + ts.css.headerIn).length ) {
|
445
454
|
// set up header template
|
446
|
-
t = c.headerTemplate
|
455
|
+
t = c.headerTemplate
|
456
|
+
.replace(ts.regex.templateContent, $t.html())
|
457
|
+
.replace(ts.regex.templateIcon, $t.find('.' + ts.css.icon).length ? '' : i);
|
447
458
|
if (c.onRenderTemplate) {
|
448
459
|
h = c.onRenderTemplate.apply( $t, [ index, t ] );
|
449
460
|
if (h && typeof h === 'string') { t = h; } // only change t if something is returned
|
@@ -856,7 +867,7 @@
|
|
856
867
|
.join( c.namespace + ' ' );
|
857
868
|
// apply easy methods that trigger bound events
|
858
869
|
$table
|
859
|
-
.unbind( events.replace(
|
870
|
+
.unbind( events.replace( ts.regex.spaces, ' ' ) )
|
860
871
|
.bind( 'sortReset' + c.namespace, function( e, callback ) {
|
861
872
|
e.stopPropagation();
|
862
873
|
// using this.config to ensure functions are getting a non-cached version of the config
|
@@ -1003,7 +1014,7 @@
|
|
1003
1014
|
c.namespace = '.tablesorter' + Math.random().toString(16).slice(2);
|
1004
1015
|
} else {
|
1005
1016
|
// make sure namespace starts with a period & doesn't have weird characters
|
1006
|
-
c.namespace = '.' + c.namespace.replace(
|
1017
|
+
c.namespace = '.' + c.namespace.replace(ts.regex.nonWord, '');
|
1007
1018
|
}
|
1008
1019
|
|
1009
1020
|
c.$table.children().children('tr').attr('role', 'row');
|
@@ -1231,7 +1242,7 @@
|
|
1231
1242
|
}
|
1232
1243
|
}
|
1233
1244
|
t = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' )
|
1234
|
-
.replace(
|
1245
|
+
.replace(ts.regex.spaces, ' ')
|
1235
1246
|
.split(' ')
|
1236
1247
|
.join(c.namespace + ' ');
|
1237
1248
|
// apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)
|
@@ -1265,7 +1276,7 @@
|
|
1265
1276
|
}
|
1266
1277
|
downTarget = null;
|
1267
1278
|
// prevent sort being triggered on form elements
|
1268
|
-
if (
|
1279
|
+
if ( ts.regex.formElements.test(e.target.nodeName) ||
|
1269
1280
|
// nosort class name, or elements within a nosort container
|
1270
1281
|
$target.hasClass(c.cssNoSort) || $target.parents('.' + c.cssNoSort).length > 0 ||
|
1271
1282
|
// elements within a button
|
@@ -1551,13 +1562,13 @@
|
|
1551
1562
|
.join(c.namespace + ' ');
|
1552
1563
|
$t
|
1553
1564
|
.removeData('tablesorter')
|
1554
|
-
.unbind( events.replace(
|
1565
|
+
.unbind( events.replace(ts.regex.spaces, ' ') );
|
1555
1566
|
c.$headers.add($f)
|
1556
1567
|
.removeClass( [ ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone ].join(' ') )
|
1557
1568
|
.removeAttr('data-column')
|
1558
1569
|
.removeAttr('aria-label')
|
1559
1570
|
.attr('aria-disabled', 'true');
|
1560
|
-
$r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(
|
1571
|
+
$r.find(c.selectorSort).unbind( ('mousedown mouseup keypress '.split(' ').join(c.namespace + ' ')).replace(ts.regex.spaces, ' ') );
|
1561
1572
|
ts.restoreHeaders(table);
|
1562
1573
|
$t.toggleClass(ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false);
|
1563
1574
|
// clear flag in case the plugin is initialized again
|
@@ -1573,11 +1584,9 @@
|
|
1573
1584
|
|
1574
1585
|
// *** sort functions ***
|
1575
1586
|
// regex used in natural sort
|
1576
|
-
ts.regex =
|
1577
|
-
|
1578
|
-
|
1579
|
-
hex: /^0x[0-9a-f]+$/i // hex
|
1580
|
-
};
|
1587
|
+
ts.regex.chunk = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi; // chunk/tokenize numbers & letters
|
1588
|
+
ts.regex.chunks = /(^\\0|\\0$)/; // replace chunks @ ends
|
1589
|
+
ts.regex.hex = /^0x[0-9a-f]+$/i; // hex
|
1581
1590
|
|
1582
1591
|
// Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)
|
1583
1592
|
// this function will only accept strings, or you'll see 'TypeError: undefined is not a function'
|
@@ -1804,7 +1813,7 @@
|
|
1804
1813
|
if (c.debug) { time = new Date(); }
|
1805
1814
|
// look for widgets to apply from in table class
|
1806
1815
|
// stop using \b otherwise this matches 'ui-widget-content' & adds 'content' widget
|
1807
|
-
wd = new RegExp( '\\s' + c.widgetClass.replace(
|
1816
|
+
wd = new RegExp( '\\s' + c.widgetClass.replace( ts.regex.templateName, '([\\w-]+)' ) + '\\s', 'g' );
|
1808
1817
|
if ( tableClass.match( wd ) ) {
|
1809
1818
|
// extract out the widget id from the table class (widget id's can include dashes)
|
1810
1819
|
w = tableClass.match( wd );
|
@@ -2030,6 +2039,10 @@
|
|
2030
2039
|
return $.trim(val);
|
2031
2040
|
};
|
2032
2041
|
|
2042
|
+
ts.regex.comma = /,/g;
|
2043
|
+
ts.regex.digitNonUS = /[\s|\.]/g;
|
2044
|
+
ts.regex.digitNegativeTest = /^\s*\([.\d]+\)/;
|
2045
|
+
ts.regex.digitNegativeReplace = /^\s*\(([.\d]+)\)/;
|
2033
2046
|
ts.formatFloat = function(s, table) {
|
2034
2047
|
if (typeof s !== 'string' || s === '') { return s; }
|
2035
2048
|
// allow using formatFloat without a table; defaults to US number format
|
@@ -2038,24 +2051,28 @@
|
|
2038
2051
|
typeof table !== 'undefined' ? table : true;
|
2039
2052
|
if (t) {
|
2040
2053
|
// US Format - 1,234,567.89 -> 1234567.89
|
2041
|
-
s = s.replace(
|
2054
|
+
s = s.replace(ts.regex.comma, '');
|
2042
2055
|
} else {
|
2043
2056
|
// German Format = 1.234.567,89 -> 1234567.89
|
2044
2057
|
// French Format = 1 234 567,89 -> 1234567.89
|
2045
|
-
s = s.replace(
|
2058
|
+
s = s.replace(ts.regex.digitNonUS, '').replace(ts.regex.comma, '.');
|
2046
2059
|
}
|
2047
|
-
if (
|
2060
|
+
if (ts.regex.digitNegativeTest.test(s)) {
|
2048
2061
|
// make (#) into a negative number -> (10) = -10
|
2049
|
-
s = s.replace(
|
2062
|
+
s = s.replace(ts.regex.digitNegativeReplace, '-$1');
|
2050
2063
|
}
|
2051
2064
|
i = parseFloat(s);
|
2052
2065
|
// return the text instead of zero
|
2053
2066
|
return isNaN(i) ? $.trim(s) : i;
|
2054
2067
|
};
|
2055
2068
|
|
2069
|
+
ts.regex.digitTest = /^[\-+(]?\d+[)]?$/;
|
2070
|
+
ts.regex.digitReplace = /[,.'"\s]/g;
|
2056
2071
|
ts.isDigit = function(s) {
|
2057
2072
|
// replace all unwanted chars and match
|
2058
|
-
return isNaN(s) ?
|
2073
|
+
return isNaN(s) ?
|
2074
|
+
ts.regex.digitTest.test( s.toString().replace( ts.regex.digitReplace, '' ) ) :
|
2075
|
+
s !== '';
|
2059
2076
|
};
|
2060
2077
|
|
2061
2078
|
}()
|
@@ -2114,65 +2131,76 @@
|
|
2114
2131
|
type: 'text'
|
2115
2132
|
});
|
2116
2133
|
|
2134
|
+
ts.regex.nondigit = /[^\w,. \-()]/g;
|
2117
2135
|
ts.addParser({
|
2118
2136
|
id: 'digit',
|
2119
2137
|
is: function(s) {
|
2120
2138
|
return ts.isDigit(s);
|
2121
2139
|
},
|
2122
2140
|
format: function(s, table) {
|
2123
|
-
var n = ts.formatFloat((s || '').replace(
|
2141
|
+
var n = ts.formatFloat((s || '').replace(ts.regex.nondigit, ''), table);
|
2124
2142
|
return s && typeof n === 'number' ? n :
|
2125
2143
|
s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
|
2126
2144
|
},
|
2127
2145
|
type: 'numeric'
|
2128
2146
|
});
|
2129
2147
|
|
2148
|
+
ts.regex.currencyReplace = /[+\-,. ]/g;
|
2149
|
+
ts.regex.currencyTest = /^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/;
|
2130
2150
|
ts.addParser({
|
2131
2151
|
id: 'currency',
|
2132
2152
|
is: function(s) {
|
2133
|
-
s = (s || '').replace(
|
2153
|
+
s = (s || '').replace(ts.regex.currencyReplace, '');
|
2134
2154
|
// test for £$€¤¥¢
|
2135
|
-
return
|
2155
|
+
return ts.regex.currencyTest.test(s);
|
2136
2156
|
},
|
2137
2157
|
format: function(s, table) {
|
2138
|
-
var n = ts.formatFloat((s || '').replace(
|
2158
|
+
var n = ts.formatFloat((s || '').replace(ts.regex.nondigit, ''), table);
|
2139
2159
|
return s && typeof n === 'number' ? n :
|
2140
2160
|
s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
|
2141
2161
|
},
|
2142
2162
|
type: 'numeric'
|
2143
2163
|
});
|
2144
2164
|
|
2165
|
+
// too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme
|
2166
|
+
// now, this regex can be updated before initialization
|
2167
|
+
ts.regex.urlProtocolTest = /^(https?|ftp|file):\/\//;
|
2168
|
+
ts.regex.urlProtocolReplace = /(https?|ftp|file):\/\//;
|
2145
2169
|
ts.addParser({
|
2146
2170
|
id: 'url',
|
2147
2171
|
is: function(s) {
|
2148
|
-
return
|
2172
|
+
return ts.regex.urlProtocolTest.test(s);
|
2149
2173
|
},
|
2150
2174
|
format: function(s) {
|
2151
|
-
return s ? $.trim(s.replace(
|
2175
|
+
return s ? $.trim(s.replace(ts.regex.urlProtocolReplace, '')) : s;
|
2152
2176
|
},
|
2153
2177
|
parsed : true, // filter widget flag
|
2154
2178
|
type: 'text'
|
2155
2179
|
});
|
2156
2180
|
|
2181
|
+
ts.regex.dash = /-/g;
|
2182
|
+
ts.regex.isoDate = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/;
|
2157
2183
|
ts.addParser({
|
2158
2184
|
id: 'isoDate',
|
2159
2185
|
is: function(s) {
|
2160
|
-
return
|
2186
|
+
return ts.regex.isoDate.test(s);
|
2161
2187
|
},
|
2162
2188
|
format: function(s, table) {
|
2163
|
-
var date = s ? new Date( s.replace(
|
2189
|
+
var date = s ? new Date( s.replace(ts.regex.dash, '/') ) : s;
|
2164
2190
|
return date instanceof Date && isFinite(date) ? date.getTime() : s;
|
2165
2191
|
},
|
2166
2192
|
type: 'numeric'
|
2167
2193
|
});
|
2168
2194
|
|
2195
|
+
ts.regex.percent = /%/g;
|
2196
|
+
ts.regex.percentTest = /(\d\s*?%|%\s*?\d)/;
|
2169
2197
|
ts.addParser({
|
2170
2198
|
id: 'percent',
|
2171
2199
|
is: function(s) {
|
2172
|
-
return
|
2200
|
+
return ts.regex.percentTest.test(s) && s.length < 15;
|
2173
2201
|
},
|
2174
2202
|
format: function(s, table) {
|
2175
|
-
return s ? ts.formatFloat(s.replace(
|
2203
|
+
return s ? ts.formatFloat(s.replace(ts.regex.percent, ''), table) : s;
|
2176
2204
|
},
|
2177
2205
|
type: 'numeric'
|
2178
2206
|
});
|
@@ -2190,27 +2218,35 @@
|
|
2190
2218
|
type: 'text'
|
2191
2219
|
});
|
2192
2220
|
|
2221
|
+
ts.regex.dateReplace = /(\S)([AP]M)$/i; // used by usLongDate & time parser
|
2222
|
+
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;
|
2223
|
+
ts.regex.usLongDateTest2 = /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i;
|
2193
2224
|
ts.addParser({
|
2194
2225
|
id: 'usLongDate',
|
2195
2226
|
is: function(s) {
|
2196
2227
|
// two digit years are not allowed cross-browser
|
2197
2228
|
// Jan 01, 2013 12:34:56 PM or 01 Jan 2013
|
2198
|
-
return (
|
2199
|
-
(/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s);
|
2229
|
+
return ts.regex.usLongDateTest1.test(s) || ts.regex.usLongDateTest2.test(s);
|
2200
2230
|
},
|
2201
2231
|
format: function(s, table) {
|
2202
|
-
var date = s ? new Date( s.replace(
|
2232
|
+
var date = s ? new Date( s.replace(ts.regex.dateReplace, '$1 $2') ) : s;
|
2203
2233
|
return date instanceof Date && isFinite(date) ? date.getTime() : s;
|
2204
2234
|
},
|
2205
2235
|
type: 'numeric'
|
2206
2236
|
});
|
2207
2237
|
|
2238
|
+
// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
|
2239
|
+
ts.regex.shortDateTest = /(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/;
|
2240
|
+
// escaped "-" because JSHint in Firefox was showing it as an error
|
2241
|
+
ts.regex.shortDateReplace = /[\-.,]/g;
|
2242
|
+
// XXY covers MDY & DMY formats
|
2243
|
+
ts.regex.shortDateXXY = /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/;
|
2244
|
+
ts.regex.shortDateYMD = /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/;
|
2208
2245
|
ts.addParser({
|
2209
2246
|
id: 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
|
2210
2247
|
is: function(s) {
|
2211
|
-
s = (s || '').replace(
|
2212
|
-
|
2213
|
-
return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test(s);
|
2248
|
+
s = (s || '').replace(ts.regex.spaces, ' ').replace(ts.regex.shortDateReplace, '/');
|
2249
|
+
return ts.regex.shortDateTest.test(s);
|
2214
2250
|
},
|
2215
2251
|
format: function(s, table, cell, cellIndex) {
|
2216
2252
|
if (s) {
|
@@ -2220,14 +2256,13 @@
|
|
2220
2256
|
format = ci.length && ci[0].dateFormat ||
|
2221
2257
|
ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') ||
|
2222
2258
|
c.dateFormat;
|
2223
|
-
|
2224
|
-
d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/');
|
2259
|
+
d = s.replace(ts.regex.spaces, ' ').replace(ts.regex.shortDateReplace, '/');
|
2225
2260
|
if (format === 'mmddyyyy') {
|
2226
|
-
d = d.replace(
|
2261
|
+
d = d.replace(ts.regex.shortDateXXY, '$3/$1/$2');
|
2227
2262
|
} else if (format === 'ddmmyyyy') {
|
2228
|
-
d = d.replace(
|
2263
|
+
d = d.replace(ts.regex.shortDateXXY, '$3/$2/$1');
|
2229
2264
|
} else if (format === 'yyyymmdd') {
|
2230
|
-
d = d.replace(
|
2265
|
+
d = d.replace(ts.regex.shortDateYMD, '$1/$2/$3');
|
2231
2266
|
}
|
2232
2267
|
date = new Date(d);
|
2233
2268
|
return date instanceof Date && isFinite(date) ? date.getTime() : s;
|
@@ -2237,13 +2272,14 @@
|
|
2237
2272
|
type: 'numeric'
|
2238
2273
|
});
|
2239
2274
|
|
2275
|
+
ts.regex.timeTest = /^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i;
|
2240
2276
|
ts.addParser({
|
2241
2277
|
id: 'time',
|
2242
2278
|
is: function(s) {
|
2243
|
-
return
|
2279
|
+
return ts.regex.timeTest.test(s);
|
2244
2280
|
},
|
2245
2281
|
format: function(s, table) {
|
2246
|
-
var date = s ? new Date( '2000/01/01 ' + s.replace(
|
2282
|
+
var date = s ? new Date( '2000/01/01 ' + s.replace(ts.regex.dateReplace, '$1 $2') ) : s;
|
2247
2283
|
return date instanceof Date && isFinite(date) ? date.getTime() : s;
|
2248
2284
|
},
|
2249
2285
|
type: 'numeric'
|
@@ -4,7 +4,7 @@
|
|
4
4
|
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀▀▀▀██
|
5
5
|
█████▀ ▀████▀ ██ ██ ▀████▀ ██ ██ ██ ██ ▀████▀ █████▀ ██ ██ █████▀
|
6
6
|
*/
|
7
|
-
/*! tablesorter (FORK) - updated 08-
|
7
|
+
/*! tablesorter (FORK) - updated 08-23-2015 (v2.23.2)*/
|
8
8
|
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
|
9
9
|
(function(factory) {
|
10
10
|
if (typeof define === 'function' && define.amd) {
|
@@ -372,14 +372,15 @@
|
|
372
372
|
|
373
373
|
})(jQuery);
|
374
374
|
|
375
|
-
/*! Widget: filter - updated 8/
|
375
|
+
/*! Widget: filter - updated 8/23/2015 (v2.23.2) *//*
|
376
376
|
* Requires tablesorter v2.8+ and jQuery 1.7+
|
377
377
|
* by Rob Garrison
|
378
378
|
*/
|
379
379
|
;( function ( $ ) {
|
380
380
|
'use strict';
|
381
|
-
var
|
382
|
-
|
381
|
+
var tsf,
|
382
|
+
ts = $.tablesorter || {},
|
383
|
+
tscss = ts.css;
|
383
384
|
|
384
385
|
$.extend( tscss, {
|
385
386
|
filterRow : 'tablesorter-filter-row',
|
@@ -423,7 +424,7 @@
|
|
423
424
|
},
|
424
425
|
format: function( table, c, wo ) {
|
425
426
|
if ( !c.$table.hasClass( 'hasFilters' ) ) {
|
426
|
-
|
427
|
+
tsf.init( table, c, wo );
|
427
428
|
}
|
428
429
|
},
|
429
430
|
remove: function( table, c, wo, refreshing ) {
|
@@ -435,7 +436,7 @@
|
|
435
436
|
$table
|
436
437
|
.removeClass( 'hasFilters' )
|
437
438
|
// add .tsfilter namespace to all BUT search
|
438
|
-
.unbind( events.replace(
|
439
|
+
.unbind( events.replace( ts.regex.spaces, ' ' ) )
|
439
440
|
// remove the filter row even if refreshing, because the column might have been moved
|
440
441
|
.find( '.' + tscss.filterRow ).remove();
|
441
442
|
if ( refreshing ) { return; }
|
@@ -450,7 +451,7 @@
|
|
450
451
|
}
|
451
452
|
});
|
452
453
|
|
453
|
-
ts.filter = {
|
454
|
+
tsf = ts.filter = {
|
454
455
|
|
455
456
|
// regex used in filter 'check' functions - not for general use and not documented
|
456
457
|
regex: {
|
@@ -459,9 +460,13 @@
|
|
459
460
|
filtered : /filtered/, // filtered (hidden) row class name; updated in the script
|
460
461
|
type : /undefined|number/, // check type
|
461
462
|
exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==')
|
462
|
-
nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser)
|
463
463
|
operators : /[<>=]/g, // replace operators
|
464
|
-
query : '(q|query)' // replace filter queries
|
464
|
+
query : '(q|query)', // replace filter queries
|
465
|
+
wild01 : /\?/g, // wild card match 0 or 1
|
466
|
+
wild0More : /\*/g, // wild care match 0 or more
|
467
|
+
quote : /\"/g,
|
468
|
+
isNeg1 : /(>=?\s*-\d)/,
|
469
|
+
isNeg2 : /(<=?\s*\d)/
|
465
470
|
},
|
466
471
|
// function( c, data ) { }
|
467
472
|
// c = table.config
|
@@ -478,27 +483,27 @@
|
|
478
483
|
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
|
479
484
|
types: {
|
480
485
|
or : function( c, data, vars ) {
|
481
|
-
if (
|
486
|
+
if ( tsf.regex.orTest.test( data.iFilter ) || tsf.regex.orSplit.test( data.filter ) ) {
|
482
487
|
var indx, filterMatched, query, regex,
|
483
488
|
// duplicate data but split filter
|
484
489
|
data2 = $.extend( {}, data ),
|
485
490
|
index = data.index,
|
486
491
|
parsed = data.parsed[ index ],
|
487
|
-
filter = data.filter.split(
|
488
|
-
iFilter = data.iFilter.split(
|
492
|
+
filter = data.filter.split( tsf.regex.orSplit ),
|
493
|
+
iFilter = data.iFilter.split( tsf.regex.orSplit ),
|
489
494
|
len = filter.length;
|
490
495
|
for ( indx = 0; indx < len; indx++ ) {
|
491
496
|
data2.nestedFilters = true;
|
492
|
-
data2.filter = '' + (
|
493
|
-
data2.iFilter = '' + (
|
494
|
-
query = '(' + (
|
497
|
+
data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
498
|
+
data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
499
|
+
query = '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
|
495
500
|
try {
|
496
501
|
// use try/catch, because query may not be a valid regex if "|" is contained within a partial regex search,
|
497
502
|
// e.g "/(Alex|Aar" -> Uncaught SyntaxError: Invalid regular expression: /(/(Alex)/: Unterminated group
|
498
503
|
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
499
504
|
// filterMatched = data2.filter === '' && indx > 0 ? true
|
500
505
|
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
501
|
-
filterMatched = regex.test( data2.exact ) ||
|
506
|
+
filterMatched = regex.test( data2.exact ) || tsf.processTypes( c, data2, vars );
|
502
507
|
if ( filterMatched ) {
|
503
508
|
return filterMatched;
|
504
509
|
}
|
@@ -513,27 +518,27 @@
|
|
513
518
|
},
|
514
519
|
// Look for an AND or && operator ( logical and )
|
515
520
|
and : function( c, data, vars ) {
|
516
|
-
if (
|
521
|
+
if ( tsf.regex.andTest.test( data.filter ) ) {
|
517
522
|
var indx, filterMatched, result, query, regex,
|
518
523
|
// duplicate data but split filter
|
519
524
|
data2 = $.extend( {}, data ),
|
520
525
|
index = data.index,
|
521
526
|
parsed = data.parsed[ index ],
|
522
|
-
filter = data.filter.split(
|
523
|
-
iFilter = data.iFilter.split(
|
527
|
+
filter = data.filter.split( tsf.regex.andSplit ),
|
528
|
+
iFilter = data.iFilter.split( tsf.regex.andSplit ),
|
524
529
|
len = filter.length;
|
525
530
|
for ( indx = 0; indx < len; indx++ ) {
|
526
531
|
data2.nestedFilters = true;
|
527
|
-
data2.filter = '' + (
|
528
|
-
data2.iFilter = '' + (
|
529
|
-
query = ( '(' + (
|
532
|
+
data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
|
533
|
+
data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
|
534
|
+
query = ( '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
|
530
535
|
// replace wild cards since /(a*)/i will match anything
|
531
|
-
.replace(
|
536
|
+
.replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' );
|
532
537
|
try {
|
533
538
|
// use try/catch just in case RegExp is invalid
|
534
539
|
regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
|
535
540
|
// look for an exact match with the 'and' unless the 'filter-match' class is found
|
536
|
-
result = ( regex.test( data2.exact ) ||
|
541
|
+
result = ( regex.test( data2.exact ) || tsf.processTypes( c, data2, vars ) );
|
537
542
|
if ( indx === 0 ) {
|
538
543
|
filterMatched = result;
|
539
544
|
} else {
|
@@ -550,10 +555,10 @@
|
|
550
555
|
},
|
551
556
|
// Look for regex
|
552
557
|
regex: function( c, data ) {
|
553
|
-
if (
|
558
|
+
if ( tsf.regex.regex.test( data.filter ) ) {
|
554
559
|
var matches,
|
555
560
|
// cache regex per column for optimal speed
|
556
|
-
regex = data.filter_regexCache[ data.index ] ||
|
561
|
+
regex = data.filter_regexCache[ data.index ] || tsf.regex.regex.exec( data.filter ),
|
557
562
|
isRegex = regex instanceof RegExp;
|
558
563
|
try {
|
559
564
|
if ( !isRegex ) {
|
@@ -572,18 +577,18 @@
|
|
572
577
|
// Look for operators >, >=, < or <=
|
573
578
|
operators: function( c, data ) {
|
574
579
|
// ignore empty strings... because '' < 10 is true
|
575
|
-
if (
|
580
|
+
if ( tsf.regex.operTest.test( data.iFilter ) && data.iExact !== '' ) {
|
576
581
|
var cachedValue, result, txt,
|
577
582
|
table = c.table,
|
578
583
|
index = data.index,
|
579
584
|
parsed = data.parsed[index],
|
580
|
-
query = ts.formatFloat( data.iFilter.replace(
|
585
|
+
query = ts.formatFloat( data.iFilter.replace( tsf.regex.operators, '' ), table ),
|
581
586
|
parser = c.parsers[index],
|
582
587
|
savedSearch = query;
|
583
588
|
// parse filter value in case we're comparing numbers ( dates )
|
584
589
|
if ( parsed || parser.type === 'numeric' ) {
|
585
|
-
txt = $.trim( '' + data.iFilter.replace(
|
586
|
-
result =
|
590
|
+
txt = $.trim( '' + data.iFilter.replace( tsf.regex.operators, '' ) );
|
591
|
+
result = tsf.parseFilter( c, txt, index, true );
|
587
592
|
query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
|
588
593
|
}
|
589
594
|
// iExact may be numeric - see issue #149;
|
@@ -592,13 +597,13 @@
|
|
592
597
|
typeof data.cache !== 'undefined' ) {
|
593
598
|
cachedValue = data.cache;
|
594
599
|
} else {
|
595
|
-
txt = isNaN( data.iExact ) ? data.iExact.replace( ts.
|
600
|
+
txt = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
|
596
601
|
cachedValue = ts.formatFloat( txt, table );
|
597
602
|
}
|
598
|
-
if (
|
599
|
-
result =
|
600
|
-
} else if (
|
601
|
-
result =
|
603
|
+
if ( tsf.regex.gtTest.test( data.iFilter ) ) {
|
604
|
+
result = tsf.regex.gteTest.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
|
605
|
+
} else if ( tsf.regex.ltTest.test( data.iFilter ) ) {
|
606
|
+
result = tsf.regex.lteTest.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
|
602
607
|
}
|
603
608
|
// keep showing all rows if nothing follows the operator
|
604
609
|
if ( !result && savedSearch === '' ) {
|
@@ -610,13 +615,13 @@
|
|
610
615
|
},
|
611
616
|
// Look for a not match
|
612
617
|
notMatch: function( c, data ) {
|
613
|
-
if (
|
618
|
+
if ( tsf.regex.notTest.test( data.iFilter ) ) {
|
614
619
|
var indx,
|
615
620
|
txt = data.iFilter.replace( '!', '' ),
|
616
|
-
filter =
|
617
|
-
if (
|
621
|
+
filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
|
622
|
+
if ( tsf.regex.exact.test( filter ) ) {
|
618
623
|
// look for exact not matches - see #628
|
619
|
-
filter = filter.replace(
|
624
|
+
filter = filter.replace( tsf.regex.exact, '' );
|
620
625
|
return filter === '' ? true : $.trim( filter ) !== data.iExact;
|
621
626
|
} else {
|
622
627
|
indx = data.iExact.search( $.trim( filter ) );
|
@@ -628,27 +633,27 @@
|
|
628
633
|
// Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
|
629
634
|
exact: function( c, data ) {
|
630
635
|
/*jshint eqeqeq:false */
|
631
|
-
if (
|
632
|
-
var txt = data.iFilter.replace(
|
633
|
-
filter =
|
636
|
+
if ( tsf.regex.exact.test( data.iFilter ) ) {
|
637
|
+
var txt = data.iFilter.replace( tsf.regex.exact, '' ),
|
638
|
+
filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
|
634
639
|
return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
|
635
640
|
}
|
636
641
|
return null;
|
637
642
|
},
|
638
643
|
// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
|
639
644
|
range : function( c, data ) {
|
640
|
-
if (
|
645
|
+
if ( tsf.regex.toTest.test( data.iFilter ) ) {
|
641
646
|
var result, tmp, range1, range2,
|
642
647
|
table = c.table,
|
643
648
|
index = data.index,
|
644
649
|
parsed = data.parsed[index],
|
645
650
|
// make sure the dash is for a range and not indicating a negative number
|
646
|
-
query = data.iFilter.split(
|
651
|
+
query = data.iFilter.split( tsf.regex.toSplit );
|
647
652
|
|
648
|
-
tmp = query[0].replace( ts.
|
649
|
-
range1 = ts.formatFloat(
|
650
|
-
tmp = query[1].replace( ts.
|
651
|
-
range2 = ts.formatFloat(
|
653
|
+
tmp = query[0].replace( ts.regex.nondigit, '' ) || '';
|
654
|
+
range1 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
|
655
|
+
tmp = query[1].replace( ts.regex.nondigit, '' ) || '';
|
656
|
+
range2 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
|
652
657
|
// parse filter value in case we're comparing numbers ( dates )
|
653
658
|
if ( parsed || c.parsers[index].type === 'numeric' ) {
|
654
659
|
result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
|
@@ -659,7 +664,7 @@
|
|
659
664
|
if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
|
660
665
|
result = data.cache;
|
661
666
|
} else {
|
662
|
-
tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.
|
667
|
+
tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
|
663
668
|
result = ts.formatFloat( tmp, table );
|
664
669
|
}
|
665
670
|
if ( range1 > range2 ) {
|
@@ -671,18 +676,18 @@
|
|
671
676
|
},
|
672
677
|
// Look for wild card: ? = single, * = multiple, or | = logical OR
|
673
678
|
wild : function( c, data ) {
|
674
|
-
if (
|
679
|
+
if ( tsf.regex.wildOrTest.test( data.iFilter ) ) {
|
675
680
|
var index = data.index,
|
676
681
|
parsed = data.parsed[ index ],
|
677
|
-
query = '' + (
|
682
|
+
query = '' + ( tsf.parseFilter( c, data.iFilter, index, parsed ) || '' );
|
678
683
|
// look for an exact match with the 'or' unless the 'filter-match' class is found
|
679
|
-
if (
|
684
|
+
if ( !tsf.regex.wildTest.test( query ) && data.nestedFilters ) {
|
680
685
|
query = data.isMatch ? query : '^(' + query + ')$';
|
681
686
|
}
|
682
687
|
// parsing the filter may not work properly when using wildcards =/
|
683
688
|
try {
|
684
689
|
return new RegExp(
|
685
|
-
query.replace(
|
690
|
+
query.replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' ),
|
686
691
|
c.widgetOptions.filter_ignoreCase ? 'i' : ''
|
687
692
|
)
|
688
693
|
.test( data.exact );
|
@@ -694,12 +699,12 @@
|
|
694
699
|
},
|
695
700
|
// fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
|
696
701
|
fuzzy: function( c, data ) {
|
697
|
-
if (
|
702
|
+
if ( tsf.regex.fuzzyTest.test( data.iFilter ) ) {
|
698
703
|
var indx,
|
699
704
|
patternIndx = 0,
|
700
705
|
len = data.iExact.length,
|
701
706
|
txt = data.iFilter.slice( 1 ),
|
702
|
-
pattern =
|
707
|
+
pattern = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
|
703
708
|
for ( indx = 0; indx < len; indx++ ) {
|
704
709
|
if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
|
705
710
|
patternIndx += 1;
|
@@ -722,7 +727,7 @@
|
|
722
727
|
}, ts.language );
|
723
728
|
|
724
729
|
var options, string, txt, $header, column, filters, val, fxn, noSelect,
|
725
|
-
regex =
|
730
|
+
regex = tsf.regex;
|
726
731
|
c.$table.addClass( 'hasFilters' );
|
727
732
|
|
728
733
|
// define timers so using clearTimeout won't cause an undefined error
|
@@ -733,7 +738,7 @@
|
|
733
738
|
wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
|
734
739
|
wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
|
735
740
|
|
736
|
-
val = '\\{' +
|
741
|
+
val = '\\{' + tsf.regex.query + '\\}';
|
737
742
|
$.extend( regex, {
|
738
743
|
child : new RegExp( c.cssChildRow ),
|
739
744
|
filtered : new RegExp( wo.filter_filteredRow ),
|
@@ -742,9 +747,20 @@
|
|
742
747
|
toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)', 'gi' ),
|
743
748
|
andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
|
744
749
|
andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
|
750
|
+
orTest : /\|/,
|
745
751
|
orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
|
746
752
|
iQuery : new RegExp( val, 'i' ),
|
747
|
-
igQuery : new RegExp( val, 'ig' )
|
753
|
+
igQuery : new RegExp( val, 'ig' ),
|
754
|
+
operTest : /^[<>]=?/,
|
755
|
+
gtTest : />/,
|
756
|
+
gteTest : />=/,
|
757
|
+
ltTest : /</,
|
758
|
+
lteTest : /<=/,
|
759
|
+
notTest : /^\!/,
|
760
|
+
wildOrTest : /[\?\*\|]/,
|
761
|
+
wildTest : /\?\*/,
|
762
|
+
fuzzyTest : /^~/,
|
763
|
+
exactTest : /[=\"\|!]/
|
748
764
|
});
|
749
765
|
|
750
766
|
// don't build filter row if columnFilters is false or all columns are set to 'filter-false'
|
@@ -752,7 +768,7 @@
|
|
752
768
|
val = c.$headers.filter( '.filter-false, .parser-false' ).length;
|
753
769
|
if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
|
754
770
|
// build filter row
|
755
|
-
|
771
|
+
tsf.buildRow( table, c, wo );
|
756
772
|
}
|
757
773
|
|
758
774
|
txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
|
@@ -765,13 +781,13 @@
|
|
765
781
|
c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
|
766
782
|
if ( !/(search|filter)/.test( event.type ) ) {
|
767
783
|
event.stopPropagation();
|
768
|
-
|
784
|
+
tsf.buildDefault( table, true );
|
769
785
|
}
|
770
786
|
if ( event.type === 'filterReset' ) {
|
771
787
|
c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
|
772
|
-
|
788
|
+
tsf.searching( table, [] );
|
773
789
|
} else if ( event.type === 'filterEnd' ) {
|
774
|
-
|
790
|
+
tsf.buildDefault( table, true );
|
775
791
|
} else {
|
776
792
|
// send false argument to force a new search; otherwise if the filter hasn't changed,
|
777
793
|
// it will return
|
@@ -785,7 +801,7 @@
|
|
785
801
|
// pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
|
786
802
|
// input ensures all inputs are updated when a search is triggered on the table
|
787
803
|
// $( 'table' ).trigger( 'search', [...] );
|
788
|
-
|
804
|
+
tsf.searching( table, filter, true );
|
789
805
|
}
|
790
806
|
return false;
|
791
807
|
});
|
@@ -818,7 +834,7 @@
|
|
818
834
|
noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
|
819
835
|
options = '';
|
820
836
|
if ( fxn === true && noSelect ) {
|
821
|
-
|
837
|
+
tsf.buildSelect( table, column );
|
822
838
|
} else if ( typeof fxn === 'object' && noSelect ) {
|
823
839
|
// add custom drop down list
|
824
840
|
for ( string in fxn ) {
|
@@ -851,7 +867,7 @@
|
|
851
867
|
fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column );
|
852
868
|
if ( fxn ) {
|
853
869
|
// updating so the extra options are appended
|
854
|
-
|
870
|
+
tsf.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
|
855
871
|
}
|
856
872
|
}
|
857
873
|
}
|
@@ -859,22 +875,22 @@
|
|
859
875
|
}
|
860
876
|
// not really updating, but if the column has both the 'filter-select' class &
|
861
877
|
// filter_functions set to true, it would append the same options twice.
|
862
|
-
|
878
|
+
tsf.buildDefault( table, true );
|
863
879
|
|
864
|
-
|
880
|
+
tsf.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
|
865
881
|
if ( wo.filter_external ) {
|
866
|
-
|
882
|
+
tsf.bindSearch( table, wo.filter_external );
|
867
883
|
}
|
868
884
|
|
869
885
|
if ( wo.filter_hideFilters ) {
|
870
|
-
|
886
|
+
tsf.hideFilters( table, c );
|
871
887
|
}
|
872
888
|
|
873
889
|
// show processing icon
|
874
890
|
if ( c.showProcessing ) {
|
875
891
|
txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
|
876
892
|
c.$table
|
877
|
-
.unbind( txt.replace(
|
893
|
+
.unbind( txt.replace( ts.regex.spaces, ' ' ) )
|
878
894
|
.bind( txt, function( event, columns ) {
|
879
895
|
// only add processing to certain columns to all columns
|
880
896
|
$header = ( columns ) ?
|
@@ -894,11 +910,11 @@
|
|
894
910
|
// add default values
|
895
911
|
txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
|
896
912
|
c.$table
|
897
|
-
.unbind( txt.replace(
|
913
|
+
.unbind( txt.replace( ts.regex.spaces, ' ' ) )
|
898
914
|
.bind( txt, function() {
|
899
915
|
// redefine 'wo' as it does not update properly inside this callback
|
900
916
|
var wo = this.config.widgetOptions;
|
901
|
-
filters =
|
917
|
+
filters = tsf.setDefaults( table, c, wo ) || [];
|
902
918
|
if ( filters.length ) {
|
903
919
|
// prevent delayInit from triggering a cache build if filters are empty
|
904
920
|
if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
|
@@ -909,7 +925,7 @@
|
|
909
925
|
// trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
|
910
926
|
setTimeout( function() {
|
911
927
|
if ( !wo.filter_initialized ) {
|
912
|
-
|
928
|
+
tsf.filterInitComplete( c );
|
913
929
|
}
|
914
930
|
}, 100 );
|
915
931
|
});
|
@@ -917,7 +933,7 @@
|
|
917
933
|
if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
|
918
934
|
c.$table.trigger( 'filterFomatterUpdate' );
|
919
935
|
setTimeout( function() {
|
920
|
-
|
936
|
+
tsf.filterInitComplete( c );
|
921
937
|
}, 100 );
|
922
938
|
}
|
923
939
|
},
|
@@ -938,7 +954,7 @@
|
|
938
954
|
completed = function() {
|
939
955
|
wo.filter_initialized = true;
|
940
956
|
c.$table.trigger( 'filterInit', c );
|
941
|
-
|
957
|
+
tsf.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
|
942
958
|
};
|
943
959
|
if ( $.isEmptyObject( wo.filter_formatter ) ) {
|
944
960
|
completed();
|
@@ -1090,7 +1106,7 @@
|
|
1090
1106
|
// use data attribute instead of jQuery data since the head is cloned without including
|
1091
1107
|
// the data/binding
|
1092
1108
|
.attr( 'data-lastSearchTime', new Date().getTime() )
|
1093
|
-
.unbind( tmp.replace(
|
1109
|
+
.unbind( tmp.replace( ts.regex.spaces, ' ' ) )
|
1094
1110
|
// include change for select - fixes #473
|
1095
1111
|
.bind( 'keyup' + namespace, function( event ) {
|
1096
1112
|
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
|
@@ -1110,17 +1126,18 @@
|
|
1110
1126
|
return;
|
1111
1127
|
}
|
1112
1128
|
// change event = no delay; last true flag tells getFilters to skip newest timed input
|
1113
|
-
|
1129
|
+
tsf.searching( table, true, true );
|
1114
1130
|
})
|
1115
1131
|
.bind( 'search change keypress '.split( ' ' ).join( namespace + ' ' ), function( event ) {
|
1116
|
-
|
1132
|
+
// don't get cached data, in case data-column changes dynamically
|
1133
|
+
var column = parseInt( $( this ).attr( 'data-column' ), 10 );
|
1117
1134
|
// don't allow 'change' event to process if the input value is the same - fixes #685
|
1118
1135
|
if ( event.which === 13 || event.type === 'search' ||
|
1119
1136
|
event.type === 'change' && this.value !== c.lastSearch[column] ) {
|
1120
1137
|
event.preventDefault();
|
1121
1138
|
// init search with no delay
|
1122
1139
|
$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
|
1123
|
-
|
1140
|
+
tsf.searching( table, false, true );
|
1124
1141
|
}
|
1125
1142
|
});
|
1126
1143
|
},
|
@@ -1130,11 +1147,11 @@
|
|
1130
1147
|
if ( typeof filter === 'undefined' || filter === true ) {
|
1131
1148
|
// delay filtering
|
1132
1149
|
wo.searchTimer = setTimeout( function() {
|
1133
|
-
|
1150
|
+
tsf.checkFilters( table, filter, skipFirst );
|
1134
1151
|
}, wo.filter_liveSearch ? wo.filter_searchDelay : 10 );
|
1135
1152
|
} else {
|
1136
1153
|
// skip delay
|
1137
|
-
|
1154
|
+
tsf.checkFilters( table, filter, skipFirst );
|
1138
1155
|
}
|
1139
1156
|
},
|
1140
1157
|
checkFilters: function( table, filter, skipFirst ) {
|
@@ -1148,7 +1165,7 @@
|
|
1148
1165
|
// update cache if delayInit set & pager has initialized ( after user initiates a search )
|
1149
1166
|
if ( c.delayInit && c.pager && c.pager.initialized ) {
|
1150
1167
|
c.$table.trigger( 'updateCache', [ function() {
|
1151
|
-
|
1168
|
+
tsf.checkFilters( table, false, skipFirst );
|
1152
1169
|
} ] );
|
1153
1170
|
}
|
1154
1171
|
return;
|
@@ -1179,11 +1196,11 @@
|
|
1179
1196
|
if ( c.showProcessing ) {
|
1180
1197
|
// give it time for the processing icon to kick in
|
1181
1198
|
setTimeout( function() {
|
1182
|
-
|
1199
|
+
tsf.findRows( table, filters, combinedFilters );
|
1183
1200
|
return false;
|
1184
1201
|
}, 30 );
|
1185
1202
|
} else {
|
1186
|
-
|
1203
|
+
tsf.findRows( table, filters, combinedFilters );
|
1187
1204
|
return false;
|
1188
1205
|
}
|
1189
1206
|
},
|
@@ -1226,8 +1243,8 @@
|
|
1226
1243
|
},
|
1227
1244
|
defaultFilter: function( filter, mask ) {
|
1228
1245
|
if ( filter === '' ) { return filter; }
|
1229
|
-
var regex =
|
1230
|
-
maskLen = mask.match(
|
1246
|
+
var regex = tsf.regex.iQuery,
|
1247
|
+
maskLen = mask.match( tsf.regex.igQuery ).length,
|
1231
1248
|
query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
|
1232
1249
|
len = query.length - 1,
|
1233
1250
|
indx = 0,
|
@@ -1263,7 +1280,10 @@
|
|
1263
1280
|
// & don't target 'all' column inputs if they don't exist
|
1264
1281
|
targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
|
1265
1282
|
columns = [],
|
1266
|
-
val = $.trim(
|
1283
|
+
val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
|
1284
|
+
if ( !/[,-]/.test(val) && val.length === 1 ) {
|
1285
|
+
return parseInt( val, 10 );
|
1286
|
+
}
|
1267
1287
|
// process column range
|
1268
1288
|
if ( targets && /-/.test( val ) ) {
|
1269
1289
|
ranges = val.match( /(\d+)\s*-\s*(\d+)/g );
|
@@ -1310,9 +1330,9 @@
|
|
1310
1330
|
var ffxn,
|
1311
1331
|
filterMatched = null,
|
1312
1332
|
matches = null;
|
1313
|
-
for ( ffxn in
|
1333
|
+
for ( ffxn in tsf.types ) {
|
1314
1334
|
if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
|
1315
|
-
matches =
|
1335
|
+
matches = tsf.types[ffxn]( c, data, vars );
|
1316
1336
|
if ( matches !== null ) {
|
1317
1337
|
filterMatched = matches;
|
1318
1338
|
}
|
@@ -1321,16 +1341,23 @@
|
|
1321
1341
|
return filterMatched;
|
1322
1342
|
},
|
1323
1343
|
processRow: function( c, data, vars ) {
|
1324
|
-
var
|
1344
|
+
var hasSelect, result, val, filterMatched,
|
1325
1345
|
fxn, ffxn, txt,
|
1326
|
-
regex =
|
1346
|
+
regex = tsf.regex,
|
1327
1347
|
wo = c.widgetOptions,
|
1328
|
-
showRow = true
|
1348
|
+
showRow = true,
|
1349
|
+
|
1350
|
+
// if wo.filter_$anyMatch data-column attribute is changed dynamically
|
1351
|
+
// we don't want to do an "anyMatch" search on one column using data
|
1352
|
+
// for the entire row - see #998
|
1353
|
+
columnIndex = wo.filter_$anyMatch && wo.filter_$anyMatch.length ?
|
1354
|
+
// look for multiple columns '1-3,4-6,8'
|
1355
|
+
tsf.multipleColumns( c, wo.filter_$anyMatch ) :
|
1356
|
+
[];
|
1357
|
+
|
1329
1358
|
data.$cells = data.$row.children();
|
1330
1359
|
|
1331
|
-
if ( data.anyMatchFlag ) {
|
1332
|
-
// look for multiple columns '1-3,4-6,8'
|
1333
|
-
columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
|
1360
|
+
if ( data.anyMatchFlag && columnIndex.length > 1 ) {
|
1334
1361
|
data.anyMatch = true;
|
1335
1362
|
data.isMatch = true;
|
1336
1363
|
data.rowArray = data.$cells.map( function( i ) {
|
@@ -1354,7 +1381,7 @@
|
|
1354
1381
|
data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
|
1355
1382
|
|
1356
1383
|
vars.excludeMatch = vars.noAnyMatch;
|
1357
|
-
filterMatched =
|
1384
|
+
filterMatched = tsf.processTypes( c, data, vars );
|
1358
1385
|
|
1359
1386
|
if ( filterMatched !== null ) {
|
1360
1387
|
showRow = filterMatched;
|
@@ -1415,7 +1442,7 @@
|
|
1415
1442
|
|
1416
1443
|
val = true;
|
1417
1444
|
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
|
1418
|
-
data.filter =
|
1445
|
+
data.filter = tsf.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
|
1419
1446
|
// val is used to indicate that a filter select is using a default filter;
|
1420
1447
|
// so we override the exact & partial matches
|
1421
1448
|
val = false;
|
@@ -1446,13 +1473,13 @@
|
|
1446
1473
|
if ( filterMatched === null ) {
|
1447
1474
|
// cycle through the different filters
|
1448
1475
|
// filters return a boolean or null if nothing matches
|
1449
|
-
filterMatched =
|
1476
|
+
filterMatched = tsf.processTypes( c, data, vars );
|
1450
1477
|
if ( filterMatched !== null ) {
|
1451
1478
|
result = filterMatched;
|
1452
1479
|
// Look for match, and add child row data for matching
|
1453
1480
|
} else {
|
1454
1481
|
txt = ( data.iExact + data.childRowText )
|
1455
|
-
.indexOf(
|
1482
|
+
.indexOf( tsf.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
|
1456
1483
|
result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
|
1457
1484
|
}
|
1458
1485
|
} else {
|
@@ -1472,7 +1499,7 @@
|
|
1472
1499
|
isChild, childRow, lastSearch, showRow, time, val, indx,
|
1473
1500
|
notFiltered, searchFiltered, query, injected, res, id, txt,
|
1474
1501
|
storedFilters = $.extend( [], filters ),
|
1475
|
-
regex =
|
1502
|
+
regex = tsf.regex,
|
1476
1503
|
c = table.config,
|
1477
1504
|
wo = c.widgetOptions,
|
1478
1505
|
// data object passed to filters; anyMatch is a flag for the filters
|
@@ -1549,7 +1576,7 @@
|
|
1549
1576
|
data.anyMatchFlag = true;
|
1550
1577
|
data.anyMatchFilter = '' + (
|
1551
1578
|
filters[ c.columns ] ||
|
1552
|
-
wo.filter_$anyMatch &&
|
1579
|
+
wo.filter_$anyMatch && tsf.getLatestSearch( wo.filter_$anyMatch ).val() ||
|
1553
1580
|
''
|
1554
1581
|
);
|
1555
1582
|
if ( wo.filter_columnAnyMatch ) {
|
@@ -1591,10 +1618,10 @@
|
|
1591
1618
|
// if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
|
1592
1619
|
!regex.alreadyFiltered.test( val ) &&
|
1593
1620
|
// if we are not doing exact matches, using '|' ( logical or ) or not '!'
|
1594
|
-
|
1621
|
+
!regex.exactTest.test( val ) &&
|
1595
1622
|
// don't search only filtered if the value is negative
|
1596
1623
|
// ( '> -10' => '> -100' will ignore hidden rows )
|
1597
|
-
!(
|
1624
|
+
!( regex.isNeg1.test( val ) || regex.isNeg2.test( val ) ) &&
|
1598
1625
|
// if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
|
1599
1626
|
!( val !== '' && c.$filters && c.$filters.eq( indx ).find( 'select' ).length &&
|
1600
1627
|
!c.$headerIndexed[indx].hasClass( 'filter-match' ) );
|
@@ -1613,7 +1640,7 @@
|
|
1613
1640
|
data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
|
1614
1641
|
}
|
1615
1642
|
if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) {
|
1616
|
-
data.anyMatchFilter =
|
1643
|
+
data.anyMatchFilter = tsf.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
|
1617
1644
|
// clear search filtered flag because default filters are not saved to the last search
|
1618
1645
|
searchFiltered = false;
|
1619
1646
|
}
|
@@ -1656,7 +1683,7 @@
|
|
1656
1683
|
'';
|
1657
1684
|
}
|
1658
1685
|
|
1659
|
-
showRow =
|
1686
|
+
showRow = tsf.processRow( c, data, vars );
|
1660
1687
|
childRow = rowData.$row.filter( ':gt( 0 )' );
|
1661
1688
|
|
1662
1689
|
if ( wo.filter_childRows && childRow.length ) {
|
@@ -1667,7 +1694,7 @@
|
|
1667
1694
|
data.cacheArray = rowData.child[ indx ];
|
1668
1695
|
data.rawArray = data.cacheArray;
|
1669
1696
|
// use OR comparison on child rows
|
1670
|
-
showRow = showRow ||
|
1697
|
+
showRow = showRow || tsf.processRow( c, data, vars );
|
1671
1698
|
}
|
1672
1699
|
}
|
1673
1700
|
childRow.toggleClass( wo.filter_filteredRow, !showRow );
|
@@ -1729,7 +1756,7 @@
|
|
1729
1756
|
}
|
1730
1757
|
if ( arry === false ) {
|
1731
1758
|
// fall back to original method
|
1732
|
-
arry =
|
1759
|
+
arry = tsf.getOptions( table, column, onlyAvail );
|
1733
1760
|
}
|
1734
1761
|
|
1735
1762
|
// get unique elements and sort the list
|
@@ -1841,13 +1868,13 @@
|
|
1841
1868
|
// nothing included in arry ( external source ), so get the options from
|
1842
1869
|
// filter_selectSource or column data
|
1843
1870
|
if ( typeof arry === 'undefined' || arry === '' ) {
|
1844
|
-
arry =
|
1871
|
+
arry = tsf.getOptionSource( table, column, onlyAvail );
|
1845
1872
|
}
|
1846
1873
|
|
1847
1874
|
if ( $.isArray( arry ) ) {
|
1848
1875
|
// build option list
|
1849
1876
|
for ( indx = 0; indx < arry.length; indx++ ) {
|
1850
|
-
txt = arry[indx] = ( '' + arry[indx] ).replace(
|
1877
|
+
txt = arry[indx] = ( '' + arry[indx] ).replace( tsf.regex.quote, '"' );
|
1851
1878
|
val = txt;
|
1852
1879
|
// allow including a symbol in the selectSource array
|
1853
1880
|
// 'a-z|A through Z' so that 'a-z' becomes the option value
|
@@ -1903,7 +1930,7 @@
|
|
1903
1930
|
// look for the filter-select class; build/update it if found
|
1904
1931
|
if ( ( $header.hasClass( 'filter-select' ) ||
|
1905
1932
|
ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
|
1906
|
-
|
1933
|
+
tsf.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
|
1907
1934
|
}
|
1908
1935
|
}
|
1909
1936
|
}
|
@@ -1939,7 +1966,7 @@
|
|
1939
1966
|
$column = $filters.filter( cols );
|
1940
1967
|
if ( $column.length ) {
|
1941
1968
|
// move the latest search to the first slot in the array
|
1942
|
-
$column =
|
1969
|
+
$column = tsf.getLatestSearch( $column );
|
1943
1970
|
if ( $.isArray( setFilters ) ) {
|
1944
1971
|
// skip first ( latest input ) to maintain cursor position while typing
|
1945
1972
|
if ( skipFirst && $column.length > 1 ) {
|
@@ -1989,7 +2016,7 @@
|
|
1989
2016
|
// ensure new set filters are applied, even if the search is the same
|
1990
2017
|
c.lastCombinedFilter = null;
|
1991
2018
|
c.lastSearch = [];
|
1992
|
-
|
2019
|
+
tsf.searching( c.table, filter, skipFirst );
|
1993
2020
|
c.$table.trigger( 'filterFomatterUpdate' );
|
1994
2021
|
}
|
1995
2022
|
return !!valid;
|