jquery-tablesorter 1.18.1 → 1.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /* Widget: columnSelector (responsive table widget) - updated 8/17/2015 (v2.23.0) *//*
1
+ /* Widget: columnSelector (responsive table widget) - updated 8/23/2015 (v2.23.2) *//*
2
2
  * Requires tablesorter v2.8+ and jQuery 1.7+
3
3
  * by Justin Hallett & Rob Garrison
4
4
  */
@@ -224,7 +224,7 @@
224
224
  }
225
225
  // trigger columnUpdate if auto is true (it gets skipped in updateCols()
226
226
  if (colSel.auto) {
227
- c.$table.trigger('columnUpdate');
227
+ c.$table.trigger(wo.columnSelector_updated);
228
228
  }
229
229
  },
230
230
 
@@ -299,7 +299,7 @@
299
299
  if (wo.columnSelector_saveColumns && ts.storage) {
300
300
  ts.storage( c.$table[0], 'tablesorter-columnSelector', colSel.states );
301
301
  }
302
- c.$table.trigger('columnUpdate');
302
+ c.$table.trigger(wo.columnSelector_updated);
303
303
  },
304
304
 
305
305
  attachTo : function(table, elm) {
@@ -370,7 +370,9 @@
370
370
  columnSelector_priority : 'data-priority',
371
371
  // class name added to checked checkboxes - this fixes an issue with Chrome not updating FontAwesome
372
372
  // applied icons; use this class name (input.checked) instead of input:checked
373
- columnSelector_cssChecked : 'checked'
373
+ columnSelector_cssChecked : 'checked',
374
+ // event triggered when columnSelector completes
375
+ columnSelector_updated : 'columnUpdate'
374
376
 
375
377
  },
376
378
  init: function(table, thisWidget, c, wo) {
@@ -1,11 +1,12 @@
1
- /*! Widget: filter - updated 8/17/2015 (v2.23.0) *//*
1
+ /*! Widget: filter - updated 8/23/2015 (v2.23.2) *//*
2
2
  * Requires tablesorter v2.8+ and jQuery 1.7+
3
3
  * by Rob Garrison
4
4
  */
5
5
  ;( function ( $ ) {
6
6
  'use strict';
7
- var ts = $.tablesorter || {},
8
- tscss = ts.css;
7
+ var tsf,
8
+ ts = $.tablesorter || {},
9
+ tscss = ts.css;
9
10
 
10
11
  $.extend( tscss, {
11
12
  filterRow : 'tablesorter-filter-row',
@@ -49,7 +50,7 @@
49
50
  },
50
51
  format: function( table, c, wo ) {
51
52
  if ( !c.$table.hasClass( 'hasFilters' ) ) {
52
- ts.filter.init( table, c, wo );
53
+ tsf.init( table, c, wo );
53
54
  }
54
55
  },
55
56
  remove: function( table, c, wo, refreshing ) {
@@ -61,7 +62,7 @@
61
62
  $table
62
63
  .removeClass( 'hasFilters' )
63
64
  // add .tsfilter namespace to all BUT search
64
- .unbind( events.replace( /\s+/g, ' ' ) )
65
+ .unbind( events.replace( ts.regex.spaces, ' ' ) )
65
66
  // remove the filter row even if refreshing, because the column might have been moved
66
67
  .find( '.' + tscss.filterRow ).remove();
67
68
  if ( refreshing ) { return; }
@@ -76,7 +77,7 @@
76
77
  }
77
78
  });
78
79
 
79
- ts.filter = {
80
+ tsf = ts.filter = {
80
81
 
81
82
  // regex used in filter 'check' functions - not for general use and not documented
82
83
  regex: {
@@ -85,9 +86,13 @@
85
86
  filtered : /filtered/, // filtered (hidden) row class name; updated in the script
86
87
  type : /undefined|number/, // check type
87
88
  exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==')
88
- nondigit : /[^\w,. \-()]/g, // replace non-digits (from digit & currency parser)
89
89
  operators : /[<>=]/g, // replace operators
90
- query : '(q|query)' // replace filter queries
90
+ query : '(q|query)', // replace filter queries
91
+ wild01 : /\?/g, // wild card match 0 or 1
92
+ wild0More : /\*/g, // wild care match 0 or more
93
+ quote : /\"/g,
94
+ isNeg1 : /(>=?\s*-\d)/,
95
+ isNeg2 : /(<=?\s*\d)/
91
96
  },
92
97
  // function( c, data ) { }
93
98
  // c = table.config
@@ -104,27 +109,27 @@
104
109
  // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
105
110
  types: {
106
111
  or : function( c, data, vars ) {
107
- if ( /\|/.test( data.iFilter ) || ts.filter.regex.orSplit.test( data.filter ) ) {
112
+ if ( tsf.regex.orTest.test( data.iFilter ) || tsf.regex.orSplit.test( data.filter ) ) {
108
113
  var indx, filterMatched, query, regex,
109
114
  // duplicate data but split filter
110
115
  data2 = $.extend( {}, data ),
111
116
  index = data.index,
112
117
  parsed = data.parsed[ index ],
113
- filter = data.filter.split( ts.filter.regex.orSplit ),
114
- iFilter = data.iFilter.split( ts.filter.regex.orSplit ),
118
+ filter = data.filter.split( tsf.regex.orSplit ),
119
+ iFilter = data.iFilter.split( tsf.regex.orSplit ),
115
120
  len = filter.length;
116
121
  for ( indx = 0; indx < len; indx++ ) {
117
122
  data2.nestedFilters = true;
118
- data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
119
- data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
120
- query = '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
123
+ data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
124
+ data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
125
+ query = '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
121
126
  try {
122
127
  // use try/catch, because query may not be a valid regex if "|" is contained within a partial regex search,
123
128
  // e.g "/(Alex|Aar" -> Uncaught SyntaxError: Invalid regular expression: /(/(Alex)/: Unterminated group
124
129
  regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
125
130
  // filterMatched = data2.filter === '' && indx > 0 ? true
126
131
  // look for an exact match with the 'or' unless the 'filter-match' class is found
127
- filterMatched = regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars );
132
+ filterMatched = regex.test( data2.exact ) || tsf.processTypes( c, data2, vars );
128
133
  if ( filterMatched ) {
129
134
  return filterMatched;
130
135
  }
@@ -139,27 +144,27 @@
139
144
  },
140
145
  // Look for an AND or && operator ( logical and )
141
146
  and : function( c, data, vars ) {
142
- if ( ts.filter.regex.andTest.test( data.filter ) ) {
147
+ if ( tsf.regex.andTest.test( data.filter ) ) {
143
148
  var indx, filterMatched, result, query, regex,
144
149
  // duplicate data but split filter
145
150
  data2 = $.extend( {}, data ),
146
151
  index = data.index,
147
152
  parsed = data.parsed[ index ],
148
- filter = data.filter.split( ts.filter.regex.andSplit ),
149
- iFilter = data.iFilter.split( ts.filter.regex.andSplit ),
153
+ filter = data.filter.split( tsf.regex.andSplit ),
154
+ iFilter = data.iFilter.split( tsf.regex.andSplit ),
150
155
  len = filter.length;
151
156
  for ( indx = 0; indx < len; indx++ ) {
152
157
  data2.nestedFilters = true;
153
- data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
154
- data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
155
- query = ( '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
158
+ data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], index, parsed ) || '' );
159
+ data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
160
+ query = ( '(' + ( tsf.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
156
161
  // replace wild cards since /(a*)/i will match anything
157
- .replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
162
+ .replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' );
158
163
  try {
159
164
  // use try/catch just in case RegExp is invalid
160
165
  regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
161
166
  // look for an exact match with the 'and' unless the 'filter-match' class is found
162
- result = ( regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars ) );
167
+ result = ( regex.test( data2.exact ) || tsf.processTypes( c, data2, vars ) );
163
168
  if ( indx === 0 ) {
164
169
  filterMatched = result;
165
170
  } else {
@@ -176,10 +181,10 @@
176
181
  },
177
182
  // Look for regex
178
183
  regex: function( c, data ) {
179
- if ( ts.filter.regex.regex.test( data.filter ) ) {
184
+ if ( tsf.regex.regex.test( data.filter ) ) {
180
185
  var matches,
181
186
  // cache regex per column for optimal speed
182
- regex = data.filter_regexCache[ data.index ] || ts.filter.regex.regex.exec( data.filter ),
187
+ regex = data.filter_regexCache[ data.index ] || tsf.regex.regex.exec( data.filter ),
183
188
  isRegex = regex instanceof RegExp;
184
189
  try {
185
190
  if ( !isRegex ) {
@@ -198,18 +203,18 @@
198
203
  // Look for operators >, >=, < or <=
199
204
  operators: function( c, data ) {
200
205
  // ignore empty strings... because '' < 10 is true
201
- if ( /^[<>]=?/.test( data.iFilter ) && data.iExact !== '' ) {
206
+ if ( tsf.regex.operTest.test( data.iFilter ) && data.iExact !== '' ) {
202
207
  var cachedValue, result, txt,
203
208
  table = c.table,
204
209
  index = data.index,
205
210
  parsed = data.parsed[index],
206
- query = ts.formatFloat( data.iFilter.replace( ts.filter.regex.operators, '' ), table ),
211
+ query = ts.formatFloat( data.iFilter.replace( tsf.regex.operators, '' ), table ),
207
212
  parser = c.parsers[index],
208
213
  savedSearch = query;
209
214
  // parse filter value in case we're comparing numbers ( dates )
210
215
  if ( parsed || parser.type === 'numeric' ) {
211
- txt = $.trim( '' + data.iFilter.replace( ts.filter.regex.operators, '' ) );
212
- result = ts.filter.parseFilter( c, txt, index, true );
216
+ txt = $.trim( '' + data.iFilter.replace( tsf.regex.operators, '' ) );
217
+ result = tsf.parseFilter( c, txt, index, true );
213
218
  query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
214
219
  }
215
220
  // iExact may be numeric - see issue #149;
@@ -218,13 +223,13 @@
218
223
  typeof data.cache !== 'undefined' ) {
219
224
  cachedValue = data.cache;
220
225
  } else {
221
- txt = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
226
+ txt = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
222
227
  cachedValue = ts.formatFloat( txt, table );
223
228
  }
224
- if ( />/.test( data.iFilter ) ) {
225
- result = />=/.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
226
- } else if ( /</.test( data.iFilter ) ) {
227
- result = /<=/.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
229
+ if ( tsf.regex.gtTest.test( data.iFilter ) ) {
230
+ result = tsf.regex.gteTest.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
231
+ } else if ( tsf.regex.ltTest.test( data.iFilter ) ) {
232
+ result = tsf.regex.lteTest.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
228
233
  }
229
234
  // keep showing all rows if nothing follows the operator
230
235
  if ( !result && savedSearch === '' ) {
@@ -236,13 +241,13 @@
236
241
  },
237
242
  // Look for a not match
238
243
  notMatch: function( c, data ) {
239
- if ( /^\!/.test( data.iFilter ) ) {
244
+ if ( tsf.regex.notTest.test( data.iFilter ) ) {
240
245
  var indx,
241
246
  txt = data.iFilter.replace( '!', '' ),
242
- filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
243
- if ( ts.filter.regex.exact.test( filter ) ) {
247
+ filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
248
+ if ( tsf.regex.exact.test( filter ) ) {
244
249
  // look for exact not matches - see #628
245
- filter = filter.replace( ts.filter.regex.exact, '' );
250
+ filter = filter.replace( tsf.regex.exact, '' );
246
251
  return filter === '' ? true : $.trim( filter ) !== data.iExact;
247
252
  } else {
248
253
  indx = data.iExact.search( $.trim( filter ) );
@@ -254,27 +259,27 @@
254
259
  // Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
255
260
  exact: function( c, data ) {
256
261
  /*jshint eqeqeq:false */
257
- if ( ts.filter.regex.exact.test( data.iFilter ) ) {
258
- var txt = data.iFilter.replace( ts.filter.regex.exact, '' ),
259
- filter = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
262
+ if ( tsf.regex.exact.test( data.iFilter ) ) {
263
+ var txt = data.iFilter.replace( tsf.regex.exact, '' ),
264
+ filter = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
260
265
  return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
261
266
  }
262
267
  return null;
263
268
  },
264
269
  // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
265
270
  range : function( c, data ) {
266
- if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
271
+ if ( tsf.regex.toTest.test( data.iFilter ) ) {
267
272
  var result, tmp, range1, range2,
268
273
  table = c.table,
269
274
  index = data.index,
270
275
  parsed = data.parsed[index],
271
276
  // make sure the dash is for a range and not indicating a negative number
272
- query = data.iFilter.split( ts.filter.regex.toSplit );
277
+ query = data.iFilter.split( tsf.regex.toSplit );
273
278
 
274
- tmp = query[0].replace( ts.filter.regex.nondigit, '' ) || '';
275
- range1 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
276
- tmp = query[1].replace( ts.filter.regex.nondigit, '' ) || '';
277
- range2 = ts.formatFloat( ts.filter.parseFilter( c, tmp, index, parsed ), table );
279
+ tmp = query[0].replace( ts.regex.nondigit, '' ) || '';
280
+ range1 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
281
+ tmp = query[1].replace( ts.regex.nondigit, '' ) || '';
282
+ range2 = ts.formatFloat( tsf.parseFilter( c, tmp, index, parsed ), table );
278
283
  // parse filter value in case we're comparing numbers ( dates )
279
284
  if ( parsed || c.parsers[index].type === 'numeric' ) {
280
285
  result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
@@ -285,7 +290,7 @@
285
290
  if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
286
291
  result = data.cache;
287
292
  } else {
288
- tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.filter.regex.nondigit, '' ) : data.iExact;
293
+ tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
289
294
  result = ts.formatFloat( tmp, table );
290
295
  }
291
296
  if ( range1 > range2 ) {
@@ -297,18 +302,18 @@
297
302
  },
298
303
  // Look for wild card: ? = single, * = multiple, or | = logical OR
299
304
  wild : function( c, data ) {
300
- if ( /[\?\*\|]/.test( data.iFilter ) ) {
305
+ if ( tsf.regex.wildOrTest.test( data.iFilter ) ) {
301
306
  var index = data.index,
302
307
  parsed = data.parsed[ index ],
303
- query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
308
+ query = '' + ( tsf.parseFilter( c, data.iFilter, index, parsed ) || '' );
304
309
  // look for an exact match with the 'or' unless the 'filter-match' class is found
305
- if ( !/\?\*/.test( query ) && data.nestedFilters ) {
310
+ if ( !tsf.regex.wildTest.test( query ) && data.nestedFilters ) {
306
311
  query = data.isMatch ? query : '^(' + query + ')$';
307
312
  }
308
313
  // parsing the filter may not work properly when using wildcards =/
309
314
  try {
310
315
  return new RegExp(
311
- query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
316
+ query.replace( tsf.regex.wild01, '\\S{1}' ).replace( tsf.regex.wild0More, '\\S*' ),
312
317
  c.widgetOptions.filter_ignoreCase ? 'i' : ''
313
318
  )
314
319
  .test( data.exact );
@@ -320,12 +325,12 @@
320
325
  },
321
326
  // fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
322
327
  fuzzy: function( c, data ) {
323
- if ( /^~/.test( data.iFilter ) ) {
328
+ if ( tsf.regex.fuzzyTest.test( data.iFilter ) ) {
324
329
  var indx,
325
330
  patternIndx = 0,
326
331
  len = data.iExact.length,
327
332
  txt = data.iFilter.slice( 1 ),
328
- pattern = ts.filter.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
333
+ pattern = tsf.parseFilter( c, txt, data.index, data.parsed[data.index] ) || '';
329
334
  for ( indx = 0; indx < len; indx++ ) {
330
335
  if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
331
336
  patternIndx += 1;
@@ -348,7 +353,7 @@
348
353
  }, ts.language );
349
354
 
350
355
  var options, string, txt, $header, column, filters, val, fxn, noSelect,
351
- regex = ts.filter.regex;
356
+ regex = tsf.regex;
352
357
  c.$table.addClass( 'hasFilters' );
353
358
 
354
359
  // define timers so using clearTimeout won't cause an undefined error
@@ -359,7 +364,7 @@
359
364
  wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
360
365
  wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
361
366
 
362
- val = '\\{' + ts.filter.regex.query + '\\}';
367
+ val = '\\{' + tsf.regex.query + '\\}';
363
368
  $.extend( regex, {
364
369
  child : new RegExp( c.cssChildRow ),
365
370
  filtered : new RegExp( wo.filter_filteredRow ),
@@ -368,9 +373,20 @@
368
373
  toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)', 'gi' ),
369
374
  andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
370
375
  andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
376
+ orTest : /\|/,
371
377
  orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
372
378
  iQuery : new RegExp( val, 'i' ),
373
- igQuery : new RegExp( val, 'ig' )
379
+ igQuery : new RegExp( val, 'ig' ),
380
+ operTest : /^[<>]=?/,
381
+ gtTest : />/,
382
+ gteTest : />=/,
383
+ ltTest : /</,
384
+ lteTest : /<=/,
385
+ notTest : /^\!/,
386
+ wildOrTest : /[\?\*\|]/,
387
+ wildTest : /\?\*/,
388
+ fuzzyTest : /^~/,
389
+ exactTest : /[=\"\|!]/
374
390
  });
375
391
 
376
392
  // don't build filter row if columnFilters is false or all columns are set to 'filter-false'
@@ -378,7 +394,7 @@
378
394
  val = c.$headers.filter( '.filter-false, .parser-false' ).length;
379
395
  if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
380
396
  // build filter row
381
- ts.filter.buildRow( table, c, wo );
397
+ tsf.buildRow( table, c, wo );
382
398
  }
383
399
 
384
400
  txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
@@ -391,13 +407,13 @@
391
407
  c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
392
408
  if ( !/(search|filter)/.test( event.type ) ) {
393
409
  event.stopPropagation();
394
- ts.filter.buildDefault( table, true );
410
+ tsf.buildDefault( table, true );
395
411
  }
396
412
  if ( event.type === 'filterReset' ) {
397
413
  c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
398
- ts.filter.searching( table, [] );
414
+ tsf.searching( table, [] );
399
415
  } else if ( event.type === 'filterEnd' ) {
400
- ts.filter.buildDefault( table, true );
416
+ tsf.buildDefault( table, true );
401
417
  } else {
402
418
  // send false argument to force a new search; otherwise if the filter hasn't changed,
403
419
  // it will return
@@ -411,7 +427,7 @@
411
427
  // pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
412
428
  // input ensures all inputs are updated when a search is triggered on the table
413
429
  // $( 'table' ).trigger( 'search', [...] );
414
- ts.filter.searching( table, filter, true );
430
+ tsf.searching( table, filter, true );
415
431
  }
416
432
  return false;
417
433
  });
@@ -444,7 +460,7 @@
444
460
  noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
445
461
  options = '';
446
462
  if ( fxn === true && noSelect ) {
447
- ts.filter.buildSelect( table, column );
463
+ tsf.buildSelect( table, column );
448
464
  } else if ( typeof fxn === 'object' && noSelect ) {
449
465
  // add custom drop down list
450
466
  for ( string in fxn ) {
@@ -477,7 +493,7 @@
477
493
  fxn = $.isFunction( txt ) ? true : ts.getColumnData( table, txt, column );
478
494
  if ( fxn ) {
479
495
  // updating so the extra options are appended
480
- ts.filter.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
496
+ tsf.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
481
497
  }
482
498
  }
483
499
  }
@@ -485,22 +501,22 @@
485
501
  }
486
502
  // not really updating, but if the column has both the 'filter-select' class &
487
503
  // filter_functions set to true, it would append the same options twice.
488
- ts.filter.buildDefault( table, true );
504
+ tsf.buildDefault( table, true );
489
505
 
490
- ts.filter.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
506
+ tsf.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
491
507
  if ( wo.filter_external ) {
492
- ts.filter.bindSearch( table, wo.filter_external );
508
+ tsf.bindSearch( table, wo.filter_external );
493
509
  }
494
510
 
495
511
  if ( wo.filter_hideFilters ) {
496
- ts.filter.hideFilters( table, c );
512
+ tsf.hideFilters( table, c );
497
513
  }
498
514
 
499
515
  // show processing icon
500
516
  if ( c.showProcessing ) {
501
517
  txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
502
518
  c.$table
503
- .unbind( txt.replace( /\s+/g, ' ' ) )
519
+ .unbind( txt.replace( ts.regex.spaces, ' ' ) )
504
520
  .bind( txt, function( event, columns ) {
505
521
  // only add processing to certain columns to all columns
506
522
  $header = ( columns ) ?
@@ -520,11 +536,11 @@
520
536
  // add default values
521
537
  txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
522
538
  c.$table
523
- .unbind( txt.replace( /\s+/g, ' ' ) )
539
+ .unbind( txt.replace( ts.regex.spaces, ' ' ) )
524
540
  .bind( txt, function() {
525
541
  // redefine 'wo' as it does not update properly inside this callback
526
542
  var wo = this.config.widgetOptions;
527
- filters = ts.filter.setDefaults( table, c, wo ) || [];
543
+ filters = tsf.setDefaults( table, c, wo ) || [];
528
544
  if ( filters.length ) {
529
545
  // prevent delayInit from triggering a cache build if filters are empty
530
546
  if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
@@ -535,7 +551,7 @@
535
551
  // trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
536
552
  setTimeout( function() {
537
553
  if ( !wo.filter_initialized ) {
538
- ts.filter.filterInitComplete( c );
554
+ tsf.filterInitComplete( c );
539
555
  }
540
556
  }, 100 );
541
557
  });
@@ -543,7 +559,7 @@
543
559
  if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
544
560
  c.$table.trigger( 'filterFomatterUpdate' );
545
561
  setTimeout( function() {
546
- ts.filter.filterInitComplete( c );
562
+ tsf.filterInitComplete( c );
547
563
  }, 100 );
548
564
  }
549
565
  },
@@ -564,7 +580,7 @@
564
580
  completed = function() {
565
581
  wo.filter_initialized = true;
566
582
  c.$table.trigger( 'filterInit', c );
567
- ts.filter.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
583
+ tsf.findRows( c.table, c.$table.data( 'lastSearch' ) || [] );
568
584
  };
569
585
  if ( $.isEmptyObject( wo.filter_formatter ) ) {
570
586
  completed();
@@ -716,7 +732,7 @@
716
732
  // use data attribute instead of jQuery data since the head is cloned without including
717
733
  // the data/binding
718
734
  .attr( 'data-lastSearchTime', new Date().getTime() )
719
- .unbind( tmp.replace( /\s+/g, ' ' ) )
735
+ .unbind( tmp.replace( ts.regex.spaces, ' ' ) )
720
736
  // include change for select - fixes #473
721
737
  .bind( 'keyup' + namespace, function( event ) {
722
738
  $( this ).attr( 'data-lastSearchTime', new Date().getTime() );
@@ -736,17 +752,18 @@
736
752
  return;
737
753
  }
738
754
  // change event = no delay; last true flag tells getFilters to skip newest timed input
739
- ts.filter.searching( table, true, true );
755
+ tsf.searching( table, true, true );
740
756
  })
741
757
  .bind( 'search change keypress '.split( ' ' ).join( namespace + ' ' ), function( event ) {
742
- var column = $( this ).data( 'column' );
758
+ // don't get cached data, in case data-column changes dynamically
759
+ var column = parseInt( $( this ).attr( 'data-column' ), 10 );
743
760
  // don't allow 'change' event to process if the input value is the same - fixes #685
744
761
  if ( event.which === 13 || event.type === 'search' ||
745
762
  event.type === 'change' && this.value !== c.lastSearch[column] ) {
746
763
  event.preventDefault();
747
764
  // init search with no delay
748
765
  $( this ).attr( 'data-lastSearchTime', new Date().getTime() );
749
- ts.filter.searching( table, false, true );
766
+ tsf.searching( table, false, true );
750
767
  }
751
768
  });
752
769
  },
@@ -756,11 +773,11 @@
756
773
  if ( typeof filter === 'undefined' || filter === true ) {
757
774
  // delay filtering
758
775
  wo.searchTimer = setTimeout( function() {
759
- ts.filter.checkFilters( table, filter, skipFirst );
776
+ tsf.checkFilters( table, filter, skipFirst );
760
777
  }, wo.filter_liveSearch ? wo.filter_searchDelay : 10 );
761
778
  } else {
762
779
  // skip delay
763
- ts.filter.checkFilters( table, filter, skipFirst );
780
+ tsf.checkFilters( table, filter, skipFirst );
764
781
  }
765
782
  },
766
783
  checkFilters: function( table, filter, skipFirst ) {
@@ -774,7 +791,7 @@
774
791
  // update cache if delayInit set & pager has initialized ( after user initiates a search )
775
792
  if ( c.delayInit && c.pager && c.pager.initialized ) {
776
793
  c.$table.trigger( 'updateCache', [ function() {
777
- ts.filter.checkFilters( table, false, skipFirst );
794
+ tsf.checkFilters( table, false, skipFirst );
778
795
  } ] );
779
796
  }
780
797
  return;
@@ -805,11 +822,11 @@
805
822
  if ( c.showProcessing ) {
806
823
  // give it time for the processing icon to kick in
807
824
  setTimeout( function() {
808
- ts.filter.findRows( table, filters, combinedFilters );
825
+ tsf.findRows( table, filters, combinedFilters );
809
826
  return false;
810
827
  }, 30 );
811
828
  } else {
812
- ts.filter.findRows( table, filters, combinedFilters );
829
+ tsf.findRows( table, filters, combinedFilters );
813
830
  return false;
814
831
  }
815
832
  },
@@ -852,8 +869,8 @@
852
869
  },
853
870
  defaultFilter: function( filter, mask ) {
854
871
  if ( filter === '' ) { return filter; }
855
- var regex = ts.filter.regex.iQuery,
856
- maskLen = mask.match( ts.filter.regex.igQuery ).length,
872
+ var regex = tsf.regex.iQuery,
873
+ maskLen = mask.match( tsf.regex.igQuery ).length,
857
874
  query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
858
875
  len = query.length - 1,
859
876
  indx = 0,
@@ -889,7 +906,10 @@
889
906
  // & don't target 'all' column inputs if they don't exist
890
907
  targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
891
908
  columns = [],
892
- val = $.trim( ts.filter.getLatestSearch( $input ).attr( 'data-column' ) || '' );
909
+ val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
910
+ if ( !/[,-]/.test(val) && val.length === 1 ) {
911
+ return parseInt( val, 10 );
912
+ }
893
913
  // process column range
894
914
  if ( targets && /-/.test( val ) ) {
895
915
  ranges = val.match( /(\d+)\s*-\s*(\d+)/g );
@@ -936,9 +956,9 @@
936
956
  var ffxn,
937
957
  filterMatched = null,
938
958
  matches = null;
939
- for ( ffxn in ts.filter.types ) {
959
+ for ( ffxn in tsf.types ) {
940
960
  if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
941
- matches = ts.filter.types[ffxn]( c, data, vars );
961
+ matches = tsf.types[ffxn]( c, data, vars );
942
962
  if ( matches !== null ) {
943
963
  filterMatched = matches;
944
964
  }
@@ -947,16 +967,23 @@
947
967
  return filterMatched;
948
968
  },
949
969
  processRow: function( c, data, vars ) {
950
- var columnIndex, hasSelect, result, val, filterMatched,
970
+ var hasSelect, result, val, filterMatched,
951
971
  fxn, ffxn, txt,
952
- regex = ts.filter.regex,
972
+ regex = tsf.regex,
953
973
  wo = c.widgetOptions,
954
- showRow = true;
974
+ showRow = true,
975
+
976
+ // if wo.filter_$anyMatch data-column attribute is changed dynamically
977
+ // we don't want to do an "anyMatch" search on one column using data
978
+ // for the entire row - see #998
979
+ columnIndex = wo.filter_$anyMatch && wo.filter_$anyMatch.length ?
980
+ // look for multiple columns '1-3,4-6,8'
981
+ tsf.multipleColumns( c, wo.filter_$anyMatch ) :
982
+ [];
983
+
955
984
  data.$cells = data.$row.children();
956
985
 
957
- if ( data.anyMatchFlag ) {
958
- // look for multiple columns '1-3,4-6,8'
959
- columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
986
+ if ( data.anyMatchFlag && columnIndex.length > 1 ) {
960
987
  data.anyMatch = true;
961
988
  data.isMatch = true;
962
989
  data.rowArray = data.$cells.map( function( i ) {
@@ -980,7 +1007,7 @@
980
1007
  data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
981
1008
 
982
1009
  vars.excludeMatch = vars.noAnyMatch;
983
- filterMatched = ts.filter.processTypes( c, data, vars );
1010
+ filterMatched = tsf.processTypes( c, data, vars );
984
1011
 
985
1012
  if ( filterMatched !== null ) {
986
1013
  showRow = filterMatched;
@@ -1041,7 +1068,7 @@
1041
1068
 
1042
1069
  val = true;
1043
1070
  if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
1044
- data.filter = ts.filter.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
1071
+ data.filter = tsf.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
1045
1072
  // val is used to indicate that a filter select is using a default filter;
1046
1073
  // so we override the exact & partial matches
1047
1074
  val = false;
@@ -1072,13 +1099,13 @@
1072
1099
  if ( filterMatched === null ) {
1073
1100
  // cycle through the different filters
1074
1101
  // filters return a boolean or null if nothing matches
1075
- filterMatched = ts.filter.processTypes( c, data, vars );
1102
+ filterMatched = tsf.processTypes( c, data, vars );
1076
1103
  if ( filterMatched !== null ) {
1077
1104
  result = filterMatched;
1078
1105
  // Look for match, and add child row data for matching
1079
1106
  } else {
1080
1107
  txt = ( data.iExact + data.childRowText )
1081
- .indexOf( ts.filter.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
1108
+ .indexOf( tsf.parseFilter( c, data.iFilter, columnIndex, data.parsed[ columnIndex ] ) );
1082
1109
  result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
1083
1110
  }
1084
1111
  } else {
@@ -1098,7 +1125,7 @@
1098
1125
  isChild, childRow, lastSearch, showRow, time, val, indx,
1099
1126
  notFiltered, searchFiltered, query, injected, res, id, txt,
1100
1127
  storedFilters = $.extend( [], filters ),
1101
- regex = ts.filter.regex,
1128
+ regex = tsf.regex,
1102
1129
  c = table.config,
1103
1130
  wo = c.widgetOptions,
1104
1131
  // data object passed to filters; anyMatch is a flag for the filters
@@ -1175,7 +1202,7 @@
1175
1202
  data.anyMatchFlag = true;
1176
1203
  data.anyMatchFilter = '' + (
1177
1204
  filters[ c.columns ] ||
1178
- wo.filter_$anyMatch && ts.filter.getLatestSearch( wo.filter_$anyMatch ).val() ||
1205
+ wo.filter_$anyMatch && tsf.getLatestSearch( wo.filter_$anyMatch ).val() ||
1179
1206
  ''
1180
1207
  );
1181
1208
  if ( wo.filter_columnAnyMatch ) {
@@ -1217,10 +1244,10 @@
1217
1244
  // if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
1218
1245
  !regex.alreadyFiltered.test( val ) &&
1219
1246
  // if we are not doing exact matches, using '|' ( logical or ) or not '!'
1220
- !/[=\"\|!]/.test( val ) &&
1247
+ !regex.exactTest.test( val ) &&
1221
1248
  // don't search only filtered if the value is negative
1222
1249
  // ( '> -10' => '> -100' will ignore hidden rows )
1223
- !( /(>=?\s*-\d)/.test( val ) || /(<=?\s*\d)/.test( val ) ) &&
1250
+ !( regex.isNeg1.test( val ) || regex.isNeg2.test( val ) ) &&
1224
1251
  // if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
1225
1252
  !( val !== '' && c.$filters && c.$filters.eq( indx ).find( 'select' ).length &&
1226
1253
  !c.$headerIndexed[indx].hasClass( 'filter-match' ) );
@@ -1239,7 +1266,7 @@
1239
1266
  data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
1240
1267
  }
1241
1268
  if ( wo.filter_defaultFilter && regex.iQuery.test( vars.defaultAnyFilter ) ) {
1242
- data.anyMatchFilter = ts.filter.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
1269
+ data.anyMatchFilter = tsf.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
1243
1270
  // clear search filtered flag because default filters are not saved to the last search
1244
1271
  searchFiltered = false;
1245
1272
  }
@@ -1282,7 +1309,7 @@
1282
1309
  '';
1283
1310
  }
1284
1311
 
1285
- showRow = ts.filter.processRow( c, data, vars );
1312
+ showRow = tsf.processRow( c, data, vars );
1286
1313
  childRow = rowData.$row.filter( ':gt( 0 )' );
1287
1314
 
1288
1315
  if ( wo.filter_childRows && childRow.length ) {
@@ -1293,7 +1320,7 @@
1293
1320
  data.cacheArray = rowData.child[ indx ];
1294
1321
  data.rawArray = data.cacheArray;
1295
1322
  // use OR comparison on child rows
1296
- showRow = showRow || ts.filter.processRow( c, data, vars );
1323
+ showRow = showRow || tsf.processRow( c, data, vars );
1297
1324
  }
1298
1325
  }
1299
1326
  childRow.toggleClass( wo.filter_filteredRow, !showRow );
@@ -1355,7 +1382,7 @@
1355
1382
  }
1356
1383
  if ( arry === false ) {
1357
1384
  // fall back to original method
1358
- arry = ts.filter.getOptions( table, column, onlyAvail );
1385
+ arry = tsf.getOptions( table, column, onlyAvail );
1359
1386
  }
1360
1387
 
1361
1388
  // get unique elements and sort the list
@@ -1467,13 +1494,13 @@
1467
1494
  // nothing included in arry ( external source ), so get the options from
1468
1495
  // filter_selectSource or column data
1469
1496
  if ( typeof arry === 'undefined' || arry === '' ) {
1470
- arry = ts.filter.getOptionSource( table, column, onlyAvail );
1497
+ arry = tsf.getOptionSource( table, column, onlyAvail );
1471
1498
  }
1472
1499
 
1473
1500
  if ( $.isArray( arry ) ) {
1474
1501
  // build option list
1475
1502
  for ( indx = 0; indx < arry.length; indx++ ) {
1476
- txt = arry[indx] = ( '' + arry[indx] ).replace( /\"/g, '&quot;' );
1503
+ txt = arry[indx] = ( '' + arry[indx] ).replace( tsf.regex.quote, '&quot;' );
1477
1504
  val = txt;
1478
1505
  // allow including a symbol in the selectSource array
1479
1506
  // 'a-z|A through Z' so that 'a-z' becomes the option value
@@ -1529,7 +1556,7 @@
1529
1556
  // look for the filter-select class; build/update it if found
1530
1557
  if ( ( $header.hasClass( 'filter-select' ) ||
1531
1558
  ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
1532
- ts.filter.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
1559
+ tsf.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
1533
1560
  }
1534
1561
  }
1535
1562
  }
@@ -1565,7 +1592,7 @@
1565
1592
  $column = $filters.filter( cols );
1566
1593
  if ( $column.length ) {
1567
1594
  // move the latest search to the first slot in the array
1568
- $column = ts.filter.getLatestSearch( $column );
1595
+ $column = tsf.getLatestSearch( $column );
1569
1596
  if ( $.isArray( setFilters ) ) {
1570
1597
  // skip first ( latest input ) to maintain cursor position while typing
1571
1598
  if ( skipFirst && $column.length > 1 ) {
@@ -1615,7 +1642,7 @@
1615
1642
  // ensure new set filters are applied, even if the search is the same
1616
1643
  c.lastCombinedFilter = null;
1617
1644
  c.lastSearch = [];
1618
- ts.filter.searching( c.table, filter, skipFirst );
1645
+ tsf.searching( c.table, filter, skipFirst );
1619
1646
  c.$table.trigger( 'filterFomatterUpdate' );
1620
1647
  }
1621
1648
  return !!valid;