jquery-tablesorter 1.17.1 → 1.17.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.
Files changed (21) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/jquery-tablesorter/version.rb +1 -1
  4. data/vendor/assets/javascripts/jquery-tablesorter/addons/pager/jquery.tablesorter.pager.js +6 -2
  5. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.combined.js +353 -228
  6. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +41 -37
  7. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets.js +313 -192
  8. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-input-select.js +2 -1
  9. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-metric.js +63 -48
  10. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-alignChar.js +1 -1
  11. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-columnSelector.js +17 -12
  12. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-editable.js +10 -5
  13. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-filter.js +114 -71
  14. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-output.js +95 -66
  15. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-pager.js +3 -2
  16. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-repeatheaders.js +1 -1
  17. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-resizable.js +120 -59
  18. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-scroller.js +510 -242
  19. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-sortTbodies.js +228 -0
  20. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-stickyHeaders.js +76 -59
  21. metadata +3 -2
@@ -1,4 +1,4 @@
1
- /*! TableSorter (FORK) v2.22.1 *//*
1
+ /*! TableSorter (FORK) v2.22.3 *//*
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.22.1';
29
+ ts.version = '2.22.3';
30
30
 
31
31
  ts.parsers = [];
32
32
  ts.widgets = [];
@@ -191,10 +191,10 @@
191
191
  if (typeof(t) === 'string') {
192
192
  // check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow!
193
193
  // http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/
194
- return $.trim(
195
- ( t === 'basic' ? $node.attr(c.textAttribute) || node.textContent : node.textContent ) ||
196
- $node.text()
197
- );
194
+ if ( t === 'basic' && typeof ( te = $node.attr(c.textAttribute) ) !== 'undefined' ) {
195
+ return $.trim( te );
196
+ }
197
+ return $.trim( node.textContent || $node.text() );
198
198
  } else {
199
199
  if (typeof(t) === 'function') {
200
200
  return $.trim( t($node[0], c.table, cellIndex) );
@@ -206,9 +206,8 @@
206
206
  return $.trim( $node[0].textContent || $node.text() );
207
207
  };
208
208
 
209
- function detectParserForColumn(table, rows, rowIndex, cellIndex) {
209
+ function detectParserForColumn(c, rows, rowIndex, cellIndex) {
210
210
  var cur, $node,
211
- c = table.config,
212
211
  i = ts.parsers.length,
213
212
  node = false,
214
213
  nodeValue = '',
@@ -219,7 +218,7 @@
219
218
  node = rows[rowIndex].cells[cellIndex];
220
219
  nodeValue = ts.getElementText(c, node, cellIndex);
221
220
  $node = $(node);
222
- if (table.config.debug) {
221
+ if (c.debug) {
223
222
  log('Checking if value was empty on row ' + rowIndex + ', column: ' + cellIndex + ': "' + nodeValue + '"');
224
223
  }
225
224
  } else {
@@ -229,7 +228,7 @@
229
228
  while (--i >= 0) {
230
229
  cur = ts.parsers[i];
231
230
  // ignore the default text parser because it will always be true
232
- if (cur && cur.id !== 'text' && cur.is && cur.is(nodeValue, table, node, $node)) {
231
+ if (cur && cur.id !== 'text' && cur.is && cur.is(nodeValue, c.table, node, $node)) {
233
232
  return cur;
234
233
  }
235
234
  }
@@ -238,7 +237,7 @@
238
237
  }
239
238
 
240
239
  // centralized function to extract/parse cell contents
241
- function getParsedText( c, cell, colIndex, txt ) {
240
+ ts.getParsedText = function( c, cell, colIndex, txt ) {
242
241
  if ( typeof txt === 'undefined' ) {
243
242
  txt = ts.getElementText( c, cell, colIndex );
244
243
  }
@@ -261,16 +260,17 @@
261
260
  }
262
261
  }
263
262
  return val;
264
- }
263
+ };
265
264
 
266
- function buildParserCache(table) {
267
- var c = table.config,
268
- // update table bodies in case we start with an empty table
269
- tb = c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'),
270
- rows, list, l, i, h, ch, np, p, e, time,
265
+ function buildParserCache( c, $tbodies ) {
266
+ var rows, list, l, i, h, ch, np, p, e, time, tb, len,
267
+ table = c.table,
271
268
  j = 0,
272
- parsersDebug = '',
273
- len = tb.length;
269
+ parsersDebug = '';
270
+ // update table bodies in case we start with an empty table
271
+ c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')');
272
+ tb = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies;
273
+ len = tb.length;
274
274
  if ( len === 0) {
275
275
  return c.debug ? log('Warning: *Empty table!* Not building a parser cache') : '';
276
276
  } else if (c.debug) {
@@ -305,7 +305,7 @@
305
305
  e = false;
306
306
  }
307
307
  if (!p) {
308
- p = detectParserForColumn(table, rows, -1, i);
308
+ p = detectParserForColumn(c, rows, -1, i);
309
309
  }
310
310
  if (c.debug) {
311
311
  parsersDebug += 'column:' + i + '; extractor:' + e.id + '; parser:' + p.id + '; string:' + c.strings[i] + '; empty: ' + c.empties[i] + '\n';
@@ -325,12 +325,14 @@
325
325
  }
326
326
 
327
327
  /* utils */
328
- function buildCache(table) {
329
- var cc, t, v, i, j, k, $row, cols, cacheTime,
328
+ function buildCache(table, $tbodies) {
329
+ var cc, t, v, i, j, k, $tb, $row, cols, cacheTime,
330
330
  totalRows, rowData, prevRowData, colMax,
331
331
  c = table.config,
332
- $tb = c.$tbodies,
333
332
  parsers = c.parsers;
333
+ // update tbody variable
334
+ c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')');
335
+ $tb = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies,
334
336
  c.cache = {};
335
337
  c.totalRows = 0;
336
338
  // if no parsers found, return - it's an empty table.
@@ -378,7 +380,7 @@
378
380
  prevRowData.child[ t ] = [];
379
381
  // child row content does not account for colspans/rowspans; so indexing may be off
380
382
  for ( j = 0; j < c.columns; j++ ) {
381
- prevRowData.child[ t ][ j ] = getParsedText( c, v[ j ], j );
383
+ prevRowData.child[ t ][ j ] = ts.getParsedText( c, v[ j ], j );
382
384
  }
383
385
  // go to the next for loop
384
386
  continue;
@@ -394,7 +396,7 @@
394
396
  }
395
397
  t = ts.getElementText( c, $row[ 0 ].cells[j], j );
396
398
  rowData.raw.push( t ); // save original row text
397
- v = getParsedText( c, $row[ 0 ].cells[ j ], j, t );
399
+ v = ts.getParsedText( c, $row[ 0 ].cells[ j ], j, t );
398
400
  cols.push( v );
399
401
  if ( ( parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) {
400
402
  // determine column max value (ignore sign)
@@ -547,7 +549,7 @@
547
549
  // remove rows/elements before update
548
550
  c.$table.find(c.selectorRemove).remove();
549
551
  // rebuild parsers
550
- buildParserCache(table);
552
+ buildParserCache(c);
551
553
  // rebuild the cache map
552
554
  buildCache(table);
553
555
  checkResort(c, resort, callback);
@@ -837,7 +839,7 @@
837
839
  num = (c.strings[col]) ? c.string[c.strings[col]] || 0 : 0;
838
840
  }
839
841
  // fall back to built-in numeric sort
840
- // var sort = $.tablesorter['sort' + s](table, a[c], b[c], c, colMax[c], dir);
842
+ // var sort = $.tablesorter['sort' + s]( a[c], b[c], dir, colMax[c], table);
841
843
  sort = c.numberSorter ? c.numberSorter(a[col], b[col], dir, colMax[col], table) :
842
844
  ts[ 'sortNumeric' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], num, colMax[col], col, table);
843
845
  } else {
@@ -950,7 +952,7 @@
950
952
  row = $tb.eq( tbdy ).find( 'tr' ).index( $row );
951
953
  cache = tbcache.normalized[ row ];
952
954
  icell = $cell.index();
953
- t = getParsedText( c, cell, icell );
955
+ t = ts.getParsedText( c, cell, icell );
954
956
  cache[ icell ] = t;
955
957
  cache[ c.columns ].$row = $row;
956
958
  if ( (c.parsers[icell].type || '').toLowerCase() === 'numeric' ) {
@@ -985,7 +987,7 @@
985
987
  tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') );
986
988
  // fixes adding rows to an empty table - see issue #179
987
989
  if (!(c.parsers && c.parsers.length)) {
988
- buildParserCache(table);
990
+ buildParserCache(c);
989
991
  }
990
992
  // add each row
991
993
  for (i = 0; i < rows; i++) {
@@ -998,7 +1000,7 @@
998
1000
  };
999
1001
  // add each cell
1000
1002
  for (j = 0; j < l; j++) {
1001
- cells[j] = getParsedText( c, $row[i].cells[j], j );
1003
+ cells[j] = ts.getParsedText( c, $row[i].cells[j], j );
1002
1004
  if ((c.parsers[j].type || '').toLowerCase() === 'numeric') {
1003
1005
  // update column max value (ignore sign)
1004
1006
  c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0);
@@ -1043,13 +1045,14 @@
1043
1045
  callback(table);
1044
1046
  }
1045
1047
  })
1046
- .bind('updateCache' + c.namespace, function(e, callback){
1048
+ // $tbodies variable is used by the tbody sorting widget
1049
+ .bind('updateCache' + c.namespace, function(e, callback, $tbodies){
1047
1050
  // rebuild parsers
1048
1051
  if (!(c.parsers && c.parsers.length)) {
1049
- buildParserCache(table);
1052
+ buildParserCache(c, $tbodies);
1050
1053
  }
1051
1054
  // rebuild the cache map
1052
- buildCache(table);
1055
+ buildCache(table, $tbodies);
1053
1056
  if ($.isFunction(callback)) {
1054
1057
  callback(table);
1055
1058
  }
@@ -1169,7 +1172,7 @@
1169
1172
  // add widget options before parsing (e.g. grouping widget has parser settings)
1170
1173
  ts.applyWidgetOptions(table, c);
1171
1174
  // try to auto detect column type, and store in tables config
1172
- buildParserCache(table);
1175
+ buildParserCache(c);
1173
1176
  // start total row count at zero
1174
1177
  c.totalRows = 0;
1175
1178
  // build the cache for the tbody cells
@@ -1395,10 +1398,11 @@
1395
1398
  }
1396
1399
  // ignore mouseup if mousedown wasn't on the same target
1397
1400
  if ( type.match(' ' + c.pointerUp + ' ') && downTarget !== e.target && external !== true ) { return; }
1398
- // set timer on mousedown
1401
+ // set target on mousedown
1399
1402
  if ( type.match(' ' + c.pointerDown + ' ') ) {
1400
1403
  downTarget = e.target;
1401
- // needed or jQuery v1.3.2 or older throws an "Uncaught TypeError: handler.apply is not a function" error
1404
+ // preventDefault needed or jQuery v1.3.2 and older throws an
1405
+ // "Uncaught TypeError: handler.apply is not a function" error
1402
1406
  temp = $target.jquery.split( '.' );
1403
1407
  if ( temp[0] === '1' && temp[1] < 4 ) { e.preventDefault(); }
1404
1408
  return;
@@ -2137,7 +2141,7 @@
2137
2141
  format: function(table, c, wo) {
2138
2142
  var $tv, $tr, row, even, time, k, i, len,
2139
2143
  child = new RegExp(c.cssChildRow, 'i'),
2140
- b = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody' ) );
2144
+ b = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody:not(.' + c.cssInfoBlock + ')' ) );
2141
2145
  if (c.debug) {
2142
2146
  time = new Date();
2143
2147
  }
@@ -4,7 +4,7 @@
4
4
  ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀▀▀▀██
5
5
  █████▀ ▀████▀ ██ ██ ▀████▀ ██ ██ ██ ██ ▀████▀ █████▀ ██ ██ █████▀
6
6
  */
7
- /*! tablesorter (FORK) - updated 05-18-2015 (v2.22.1)*/
7
+ /*! tablesorter (FORK) - updated 06-30-2015 (v2.22.2)*/
8
8
  /* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
9
9
  (function(factory) {
10
10
  if (typeof define === 'function' && define.amd) {
@@ -476,6 +476,66 @@ ts.filter = {
476
476
  // data.index = column index; table = table element ( DOM )
477
477
  // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
478
478
  types: {
479
+ or : function( c, data, vars ) {
480
+ if ( /\|/.test( data.iFilter ) || ts.filter.regex.orSplit.test( data.filter ) ) {
481
+ var indx, filterMatched, txt, query, regex,
482
+ // duplicate data but split filter
483
+ data2 = $.extend( {}, data ),
484
+ index = data.index,
485
+ parsed = data.parsed[ index ],
486
+ filter = data.filter.split( ts.filter.regex.orSplit ),
487
+ iFilter = data.iFilter.split( ts.filter.regex.orSplit ),
488
+ len = filter.length;
489
+ for ( indx = 0; indx < len; indx++ ) {
490
+ data2.nestedFilters = true;
491
+ data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
492
+ data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
493
+ query = '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
494
+ regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
495
+ // filterMatched = data2.filter === '' && indx > 0 ? true
496
+ // look for an exact match with the 'or' unless the 'filter-match' class is found
497
+ filterMatched = regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars );
498
+ if ( filterMatched ) {
499
+ return filterMatched;
500
+ }
501
+ }
502
+ // may be null from processing types
503
+ return filterMatched || false;
504
+ }
505
+ return null;
506
+ },
507
+ // Look for an AND or && operator ( logical and )
508
+ and : function( c, data, vars ) {
509
+ if ( ts.filter.regex.andTest.test( data.filter ) ) {
510
+ var indx, filterMatched, result, txt, query, regex,
511
+ // duplicate data but split filter
512
+ data2 = $.extend( {}, data ),
513
+ index = data.index,
514
+ parsed = data.parsed[ index ],
515
+ filter = data.filter.split( ts.filter.regex.andSplit ),
516
+ iFilter = data.iFilter.split( ts.filter.regex.andSplit ),
517
+ len = filter.length;
518
+ for ( indx = 0; indx < len; indx++ ) {
519
+ data2.nestedFilters = true;
520
+ data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
521
+ data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
522
+ query = ( '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
523
+ // replace wild cards since /(a*)/i will match anything
524
+ .replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
525
+ regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
526
+ // look for an exact match with the 'and' unless the 'filter-match' class is found
527
+ result = ( regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars ) );
528
+ if ( indx === 0 ) {
529
+ filterMatched = result;
530
+ } else {
531
+ filterMatched = filterMatched && result;
532
+ }
533
+ }
534
+ // may be null from processing types
535
+ return filterMatched || false;
536
+ }
537
+ return null;
538
+ },
479
539
  // Look for regex
480
540
  regex: function( c, data ) {
481
541
  if ( ts.filter.regex.regex.test( data.filter ) ) {
@@ -563,23 +623,6 @@ ts.filter = {
563
623
  }
564
624
  return null;
565
625
  },
566
- // Look for an AND or && operator ( logical and )
567
- and : function( c, data ) {
568
- if ( ts.filter.regex.andTest.test( data.filter ) ) {
569
- var index = data.index,
570
- parsed = data.parsed[index],
571
- query = data.iFilter.split( ts.filter.regex.andSplit ),
572
- result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0,
573
- indx = query.length - 1;
574
- while ( result && indx ) {
575
- result = result &&
576
- data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0;
577
- indx--;
578
- }
579
- return result;
580
- }
581
- return null;
582
- },
583
626
  // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
584
627
  range : function( c, data ) {
585
628
  if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
@@ -616,24 +659,20 @@ ts.filter = {
616
659
  },
617
660
  // Look for wild card: ? = single, * = multiple, or | = logical OR
618
661
  wild : function( c, data ) {
619
- if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) {
662
+ if ( /[\?\*\|]/.test( data.iFilter ) ) {
620
663
  var index = data.index,
621
664
  parsed = data.parsed[ index ],
622
- txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ),
623
- query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
665
+ query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
624
666
  // look for an exact match with the 'or' unless the 'filter-match' class is found
625
- if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) {
626
- // show all results while using filter match. Fixes #727
627
- if ( query[ query.length - 1 ] === '|' ) {
628
- query += '*';
629
- }
630
- query = data.anyMatch && $.isArray( data.rowArray ) ?
631
- '(' + query + ')' :
632
- '^(' + query + ')$';
667
+ if ( !/\?\*/.test( query ) && data.nestedFilters ) {
668
+ query = data.isMatch ? query : '^(' + query + ')$';
633
669
  }
634
670
  // parsing the filter may not work properly when using wildcards =/
635
- return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) )
636
- .test( data.iExact );
671
+ return new RegExp(
672
+ query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
673
+ c.widgetOptions.filter_ignoreCase ? 'i' : ''
674
+ )
675
+ .test( data.exact );
637
676
  }
638
677
  return null;
639
678
  },
@@ -687,7 +726,7 @@ ts.filter = {
687
726
  toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
688
727
  andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
689
728
  andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
690
- orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ),
729
+ orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
691
730
  iQuery : new RegExp( val, 'i' ),
692
731
  igQuery : new RegExp( val, 'ig' )
693
732
  });
@@ -907,7 +946,6 @@ ts.filter = {
907
946
  }
908
947
  }
909
948
  },
910
-
911
949
  setDefaults: function( table, c, wo ) {
912
950
  var isArray, saved, indx, col, $filters,
913
951
  // get current ( default ) filters
@@ -1134,14 +1172,13 @@ ts.filter = {
1134
1172
  }
1135
1173
  },
1136
1174
  hideFilters: function( table, c ) {
1137
- var $filterRow, $filterRow2, timer;
1138
- $( table )
1175
+ var timer;
1176
+ c.$table
1139
1177
  .find( '.' + tscss.filterRow )
1140
- .addClass( tscss.filterRowHide )
1141
1178
  .bind( 'mouseenter mouseleave', function( e ) {
1142
1179
  // save event object - http://bugs.jquery.com/ticket/12140
1143
- var event = e;
1144
- $filterRow = $( this );
1180
+ var event = e,
1181
+ $filterRow = $( this );
1145
1182
  clearTimeout( timer );
1146
1183
  timer = setTimeout( function() {
1147
1184
  if ( /enter|over/.test( event.type ) ) {
@@ -1159,13 +1196,14 @@ ts.filter = {
1159
1196
  }, 200 );
1160
1197
  })
1161
1198
  .find( 'input, select' ).bind( 'focus blur', function( e ) {
1162
- $filterRow2 = $( this ).closest( 'tr' );
1199
+ var event = e,
1200
+ $row = $( this ).closest( 'tr' );
1163
1201
  clearTimeout( timer );
1164
- var event = e;
1165
1202
  timer = setTimeout( function() {
1203
+ clearTimeout( timer );
1166
1204
  // don't hide row if any filter has a value
1167
1205
  if ( ts.getFilters( c.$table ).join( '' ) === '' ) {
1168
- $filterRow2.toggleClass( tscss.filterRowHide, event.type === 'focus' );
1206
+ $row.toggleClass( tscss.filterRowHide, event.type !== 'focus' );
1169
1207
  }
1170
1208
  }, 200 );
1171
1209
  });
@@ -1199,7 +1237,7 @@ ts.filter = {
1199
1237
  return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' );
1200
1238
  });
1201
1239
  }
1202
- return $();
1240
+ return $input || $();
1203
1241
  },
1204
1242
  multipleColumns: function( c, $input ) {
1205
1243
  // look for multiple columns '1-3,4-6,8' in data-column
@@ -1252,8 +1290,22 @@ ts.filter = {
1252
1290
  }
1253
1291
  return columns;
1254
1292
  },
1293
+ processTypes: function( c, data, vars ) {
1294
+ var ffxn,
1295
+ filterMatched = null,
1296
+ matches = null;
1297
+ for ( ffxn in ts.filter.types ) {
1298
+ if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
1299
+ matches = ts.filter.types[ffxn]( c, data, vars );
1300
+ if ( matches !== null ) {
1301
+ filterMatched = matches;
1302
+ }
1303
+ }
1304
+ }
1305
+ return filterMatched;
1306
+ },
1255
1307
  processRow: function( c, data, vars ) {
1256
- var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch,
1308
+ var columnIndex, hasSelect, result, val, filterMatched,
1257
1309
  fxn, ffxn, txt,
1258
1310
  regex = ts.filter.regex,
1259
1311
  wo = c.widgetOptions,
@@ -1264,6 +1316,7 @@ ts.filter = {
1264
1316
  // look for multiple columns '1-3,4-6,8'
1265
1317
  columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
1266
1318
  data.anyMatch = true;
1319
+ data.isMatch = true;
1267
1320
  data.rowArray = data.$cells.map( function( i ) {
1268
1321
  if ( $.inArray( i, columnIndex ) > -1 ) {
1269
1322
  if ( data.parsed[ i ] ) {
@@ -1283,16 +1336,10 @@ ts.filter = {
1283
1336
  data.exact = data.rowArray.join( ' ' );
1284
1337
  data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
1285
1338
  data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
1286
- filterMatched = null;
1287
- matches = null;
1288
- for ( ffxn in ts.filter.types ) {
1289
- if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
1290
- matches = ts.filter.types[ffxn]( c, data );
1291
- if ( matches !== null ) {
1292
- filterMatched = matches;
1293
- }
1294
- }
1295
- }
1339
+
1340
+ vars.excludeMatch = vars.noAnyMatch;
1341
+ filterMatched = ts.filter.processTypes( c, data, vars );
1342
+
1296
1343
  if ( filterMatched !== null ) {
1297
1344
  showRow = filterMatched;
1298
1345
  } else {
@@ -1319,7 +1366,7 @@ ts.filter = {
1319
1366
  data.index = columnIndex;
1320
1367
 
1321
1368
  // filter types to exclude, per column
1322
- excludeMatch = vars.excludeFilter[ columnIndex ];
1369
+ vars.excludeMatch = vars.excludeFilter[ columnIndex ];
1323
1370
 
1324
1371
  // ignore if filter is empty or disabled
1325
1372
  if ( data.filter ) {
@@ -1333,6 +1380,9 @@ ts.filter = {
1333
1380
  }
1334
1381
  data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
1335
1382
  data.exact.toLowerCase() : data.exact;
1383
+
1384
+ data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
1385
+
1336
1386
  result = showRow; // if showRow is true, show that row
1337
1387
 
1338
1388
  // in case select filter option has a different value vs text 'a - z|A through Z'
@@ -1357,13 +1407,12 @@ ts.filter = {
1357
1407
  // data.filter = case sensitive
1358
1408
  data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
1359
1409
  fxn = vars.functions[ columnIndex ];
1360
- $cell = c.$headerIndexed[ columnIndex ];
1361
- hasSelect = $cell.hasClass( 'filter-select' );
1410
+ hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
1362
1411
  filterMatched = null;
1363
1412
  if ( fxn || ( hasSelect && val ) ) {
1364
1413
  if ( fxn === true || hasSelect ) {
1365
1414
  // default selector uses exact match unless 'filter-match' class is found
1366
- filterMatched = $cell.hasClass( 'filter-match' ) ?
1415
+ filterMatched = data.isMatch ?
1367
1416
  data.iExact.search( data.iFilter ) >= 0 :
1368
1417
  data.filter === data.exact;
1369
1418
  } else if ( typeof fxn === 'function' ) {
@@ -1380,15 +1429,7 @@ ts.filter = {
1380
1429
  if ( filterMatched === null ) {
1381
1430
  // cycle through the different filters
1382
1431
  // filters return a boolean or null if nothing matches
1383
- matches = null;
1384
- for ( ffxn in ts.filter.types ) {
1385
- if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) {
1386
- matches = ts.filter.types[ ffxn ]( c, data );
1387
- if ( matches !== null ) {
1388
- filterMatched = matches;
1389
- }
1390
- }
1391
- }
1432
+ filterMatched = ts.filter.processTypes( c, data, vars );
1392
1433
  if ( filterMatched !== null ) {
1393
1434
  result = filterMatched;
1394
1435
  // Look for match, and add child row data for matching
@@ -1422,7 +1463,7 @@ ts.filter = {
1422
1463
  anyMatch: false,
1423
1464
  filters: filters,
1424
1465
  // regex filter type cache
1425
- filter_regexCache : [],
1466
+ filter_regexCache : []
1426
1467
  },
1427
1468
  vars = {
1428
1469
  // anyMatch really screws up with these types of filters
@@ -1643,7 +1684,7 @@ ts.filter = {
1643
1684
  },
1644
1685
  getOptionSource: function( table, column, onlyAvail ) {
1645
1686
  table = $( table )[0];
1646
- var cts, indx, len,
1687
+ var cts, txt, indx, len,
1647
1688
  c = table.config,
1648
1689
  wo = c.widgetOptions,
1649
1690
  parsed = [],
@@ -1688,11 +1729,13 @@ ts.filter = {
1688
1729
  len = arry.length;
1689
1730
  // parse select option values
1690
1731
  for ( indx = 0; indx < len; indx++ ) {
1732
+ txt = arry[ indx ];
1691
1733
  // parse array data using set column parser; this DOES NOT pass the original
1692
1734
  // table cell to the parser format function
1693
1735
  parsed.push({
1694
- t : arry[ indx ],
1695
- p : c.parsers && c.parsers[ column ].format( arry[ indx ], table, [], column )
1736
+ t : txt,
1737
+ // check parser length - fixes #934
1738
+ p : c.parsers && c.parsers.length && c.parsers[ column ].format( txt, table, [], column ) || txt
1696
1739
  });
1697
1740
  }
1698
1741
 
@@ -1882,8 +1925,8 @@ ts.getFilters = function( table, getRaw, setFilters, skipFirst ) {
1882
1925
  $column = ts.filter.getLatestSearch( $column );
1883
1926
  if ( $.isArray( setFilters ) ) {
1884
1927
  // skip first ( latest input ) to maintain cursor position while typing
1885
- if ( skipFirst ) {
1886
- $column.slice( 1 );
1928
+ if ( skipFirst && $column.length > 1 ) {
1929
+ $column = $column.slice( 1 );
1887
1930
  }
1888
1931
  if ( i === c.columns ) {
1889
1932
  // prevent data-column='all' from filling data-column='0,1' ( etc )
@@ -1955,32 +1998,34 @@ $.extend(ts.css, {
1955
1998
  // Add a resize event to table headers
1956
1999
  ts.addHeaderResizeEvent = function(table, disable, settings) {
1957
2000
  table = $(table)[0]; // make sure we're using a dom element
1958
- var headers,
1959
- defaults = {
2001
+ if ( !table.config ) { return; }
2002
+ var defaults = {
1960
2003
  timer : 250
1961
2004
  },
1962
2005
  options = $.extend({}, defaults, settings),
1963
2006
  c = table.config,
1964
2007
  wo = c.widgetOptions,
1965
- checkSizes = function(triggerEvent) {
2008
+ checkSizes = function( triggerEvent ) {
2009
+ var index, headers, $header, sizes, width, height,
2010
+ len = c.$headers.length;
1966
2011
  wo.resize_flag = true;
1967
2012
  headers = [];
1968
- c.$headers.each(function() {
1969
- var $header = $(this),
1970
- sizes = $header.data('savedSizes') || [0,0], // fixes #394
1971
- width = this.offsetWidth,
1972
- height = this.offsetHeight;
1973
- if (width !== sizes[0] || height !== sizes[1]) {
1974
- $header.data('savedSizes', [ width, height ]);
1975
- headers.push(this);
2013
+ for ( index = 0; index < len; index++ ) {
2014
+ $header = c.$headers.eq( index );
2015
+ sizes = $header.data( 'savedSizes' ) || [ 0,0 ]; // fixes #394
2016
+ width = $header[0].offsetWidth;
2017
+ height = $header[0].offsetHeight;
2018
+ if ( width !== sizes[0] || height !== sizes[1] ) {
2019
+ $header.data( 'savedSizes', [ width, height ] );
2020
+ headers.push( $header[0] );
1976
2021
  }
1977
- });
1978
- if (headers.length && triggerEvent !== false) {
1979
- c.$table.trigger('resize', [ headers ]);
2022
+ }
2023
+ if ( headers.length && triggerEvent !== false ) {
2024
+ c.$table.trigger( 'resize', [ headers ] );
1980
2025
  }
1981
2026
  wo.resize_flag = false;
1982
2027
  };
1983
- checkSizes(false);
2028
+ checkSizes( false );
1984
2029
  clearInterval(wo.resize_timer);
1985
2030
  if (disable) {
1986
2031
  wo.resize_flag = false;
@@ -2016,7 +2061,8 @@ ts.addWidget({
2016
2061
  if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) {
2017
2062
  return;
2018
2063
  }
2019
- var $table = c.$table,
2064
+ var index, len, $t,
2065
+ $table = c.$table,
2020
2066
  // add position: relative to attach element, hopefully it won't cause trouble.
2021
2067
  $attach = $(wo.stickyHeaders_attachTo),
2022
2068
  namespace = c.namespace + 'stickyheaders ',
@@ -2051,17 +2097,19 @@ ts.addWidget({
2051
2097
  laststate = '',
2052
2098
  spacing = 0,
2053
2099
  setWidth = function($orig, $clone){
2054
- $orig.filter(':visible').each(function(i) {
2055
- var width, border,
2056
- $cell = $clone.filter(':visible').eq(i),
2057
- $this = $(this);
2100
+ var index, width, border, $cell, $this,
2101
+ $cells = $orig.filter(':visible'),
2102
+ len = $cells.length;
2103
+ for ( index = 0; index < len; index++ ) {
2104
+ $cell = $clone.filter(':visible').eq(index);
2105
+ $this = $cells.eq(index);
2058
2106
  // code from https://github.com/jmosbech/StickyTableHeaders
2059
2107
  if ($this.css('box-sizing') === 'border-box') {
2060
2108
  width = $this.outerWidth();
2061
2109
  } else {
2062
2110
  if ($cell.css('border-collapse') === 'collapse') {
2063
2111
  if (window.getComputedStyle) {
2064
- width = parseFloat( window.getComputedStyle(this, null).width );
2112
+ width = parseFloat( window.getComputedStyle($this[0], null).width );
2065
2113
  } else {
2066
2114
  // ie8 only
2067
2115
  border = parseFloat( $this.css('border-width') );
@@ -2072,10 +2120,11 @@ ts.addWidget({
2072
2120
  }
2073
2121
  }
2074
2122
  $cell.css({
2123
+ 'width': width,
2075
2124
  'min-width': width,
2076
2125
  'max-width': width
2077
2126
  });
2078
- });
2127
+ }
2079
2128
  },
2080
2129
  resizeHeader = function() {
2081
2130
  stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0;
@@ -2087,6 +2136,39 @@ ts.addWidget({
2087
2136
  });
2088
2137
  setWidth( $table, $stickyTable );
2089
2138
  setWidth( $header, $stickyCells );
2139
+ },
2140
+ scrollSticky = function( resizing ) {
2141
+ if (!$table.is(':visible')) { return; } // fixes #278
2142
+ // Detect nested tables - fixes #724
2143
+ nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
2144
+ var offset = $table.offset(),
2145
+ yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3
2146
+ xWindow = $.isWindow( $xScroll[0] ),
2147
+ // scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
2148
+ scrollTop = ( $attach.length ? ( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
2149
+ tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)),
2150
+ isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
2151
+ cssSettings = { visibility : isVisible };
2152
+
2153
+ if ($attach.length) {
2154
+ cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop();
2155
+ }
2156
+ if (xWindow) {
2157
+ // adjust when scrolling horizontally - fixes issue #143
2158
+ cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing;
2159
+ }
2160
+ if ($nestedSticky.length) {
2161
+ cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop;
2162
+ }
2163
+ $stickyWrap
2164
+ .removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide )
2165
+ .addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide )
2166
+ .css(cssSettings);
2167
+ if (isVisible !== laststate || resizing) {
2168
+ // make sure the column widths match
2169
+ resizeHeader();
2170
+ laststate = isVisible;
2171
+ }
2090
2172
  };
2091
2173
  // only add a position relative if a position isn't already defined
2092
2174
  if ($attach.length && !$attach.css('position')) {
@@ -2118,48 +2200,26 @@ ts.addWidget({
2118
2200
 
2119
2201
  // onRenderHeader is defined, we need to do something about it (fixes #641)
2120
2202
  if (c.onRenderHeader) {
2121
- $stickyThead.children('tr').children().each(function(index){
2203
+ $t = $stickyThead.children('tr').children();
2204
+ len = $t.length;
2205
+ for ( index = 0; index < len; index++ ) {
2122
2206
  // send second parameter
2123
- c.onRenderHeader.apply( $(this), [ index, c, $stickyTable ] );
2124
- });
2207
+ c.onRenderHeader.apply( $t.eq( index ), [ index, c, $stickyTable ] );
2208
+ }
2125
2209
  }
2126
2210
 
2127
2211
  // make it sticky!
2128
2212
  $xScroll.add($yScroll)
2129
- .unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') )
2130
- .bind('scroll resize '.split(' ').join( namespace ), function(event) {
2131
- if (!$table.is(':visible')) { return; } // fixes #278
2132
- // Detect nested tables - fixes #724
2133
- nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
2134
- var offset = $table.offset(),
2135
- yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3
2136
- xWindow = $.isWindow( $xScroll[0] ),
2137
- // scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
2138
- scrollTop = ( $attach.length ? ( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
2139
- tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)),
2140
- isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
2141
- cssSettings = { visibility : isVisible };
2142
-
2143
- if ($attach.length) {
2144
- cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop();
2145
- }
2146
- if (xWindow) {
2147
- // adjust when scrolling horizontally - fixes issue #143
2148
- cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing;
2149
- }
2150
- if ($nestedSticky.length) {
2151
- cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop;
2152
- }
2153
- $stickyWrap
2154
- .removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide )
2155
- .addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide )
2156
- .css(cssSettings);
2157
- if (isVisible !== laststate || event.type === 'resize') {
2158
- // make sure the column widths match
2159
- resizeHeader();
2160
- laststate = isVisible;
2161
- }
2162
- });
2213
+ .unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') )
2214
+ .bind('scroll resize '.split(' ').join( namespace ), function( event ) {
2215
+ scrollSticky( event.type === 'resize' );
2216
+ });
2217
+ c.$table
2218
+ .unbind('stickyHeadersUpdate' + namespace)
2219
+ .bind('stickyHeadersUpdate' + namespace, function(){
2220
+ scrollSticky( true );
2221
+ });
2222
+
2163
2223
  if (wo.stickyHeaders_addResizeEvent) {
2164
2224
  ts.addHeaderResizeEvent(table);
2165
2225
  }
@@ -2195,7 +2255,7 @@ ts.addWidget({
2195
2255
  var namespace = c.namespace + 'stickyheaders ';
2196
2256
  c.$table
2197
2257
  .removeClass('hasStickyHeaders')
2198
- .unbind( ('pagerComplete filterEnd '.split(' ').join(namespace)).replace(/\s+/g, ' ') )
2258
+ .unbind( ('pagerComplete filterEnd stickyHeadersUpdate '.split(' ').join(namespace)).replace(/\s+/g, ' ') )
2199
2259
  .next('.' + ts.css.stickyWrap).remove();
2200
2260
  if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table
2201
2261
  $(window)
@@ -2209,7 +2269,8 @@ ts.addWidget({
2209
2269
 
2210
2270
  })(jQuery, window);
2211
2271
 
2212
- /*! Widget: resizable - updated 5/17/2015 (v2.22.0) */
2272
+ /*! Widget: resizable - updated 6/26/2015 (v2.22.2) */
2273
+ /*jshint browser:true, jquery:true, unused:false */
2213
2274
  ;(function ($, window) {
2214
2275
  'use strict';
2215
2276
  var ts = $.tablesorter || {};
@@ -2228,8 +2289,8 @@ $(function(){
2228
2289
  '-khtml-user-select: none; -webkit-user-select: none; user-select: none; }' +
2229
2290
  '.' + ts.css.resizableContainer + ' { position: relative; height: 1px; }' +
2230
2291
  // make handle z-index > than stickyHeader z-index, so the handle stays above sticky header
2231
- '.' + ts.css.resizableHandle + ' { position: absolute; display: inline-block; width: 8px; top: 1px;' +
2232
- 'cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }' +
2292
+ '.' + ts.css.resizableHandle + ' { position: absolute; display: inline-block; width: 8px;' +
2293
+ 'top: 1px; cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }' +
2233
2294
  '</style>';
2234
2295
  $(s).appendTo('body');
2235
2296
  });
@@ -2238,34 +2299,69 @@ ts.resizable = {
2238
2299
  init : function( c, wo ) {
2239
2300
  if ( c.$table.hasClass( 'hasResizable' ) ) { return; }
2240
2301
  c.$table.addClass( 'hasResizable' );
2241
- ts.resizableReset( c.table, true ); // set default widths
2302
+
2303
+ var noResize, $header, column, storedSizes, tmp,
2304
+ $table = c.$table,
2305
+ $parent = $table.parent(),
2306
+ marginTop = parseInt( $table.css( 'margin-top' ), 10 ),
2242
2307
 
2243
2308
  // internal variables
2244
- wo.resizable_ = {
2245
- $wrap : c.$table.parent(),
2309
+ vars = wo.resizable_ = {
2310
+ useStorage : ts.storage && wo.resizable !== false,
2311
+ $wrap : $parent,
2246
2312
  mouseXPosition : 0,
2247
2313
  $target : null,
2248
2314
  $next : null,
2249
- overflow : c.$table.parent().css('overflow') === 'auto',
2250
- fullWidth : Math.abs(c.$table.parent().width() - c.$table.width()) < 20,
2315
+ overflow : $parent.css('overflow') === 'auto' ||
2316
+ $parent.css('overflow') === 'scroll' ||
2317
+ $parent.css('overflow-x') === 'auto' ||
2318
+ $parent.css('overflow-x') === 'scroll',
2251
2319
  storedSizes : []
2252
2320
  };
2253
2321
 
2254
- var noResize, $header, column, storedSizes,
2255
- marginTop = parseInt( c.$table.css( 'margin-top' ), 10 );
2256
-
2257
- wo.resizable_.storedSizes = storedSizes = ( ( ts.storage && wo.resizable !== false ) ?
2322
+ // set default widths
2323
+ ts.resizableReset( c.table, true );
2324
+
2325
+ // now get measurements!
2326
+ vars.tableWidth = $table.width();
2327
+ // attempt to autodetect
2328
+ vars.fullWidth = Math.abs( $parent.width() - vars.tableWidth ) < 20;
2329
+
2330
+ /*
2331
+ // Hacky method to determine if table width is set to "auto"
2332
+ // http://stackoverflow.com/a/20892048/145346
2333
+ if ( !vars.fullWidth ) {
2334
+ tmp = $table.width();
2335
+ $header = $table.wrap('<span>').parent(); // temp variable
2336
+ storedSizes = parseInt( $table.css( 'margin-left' ), 10 ) || 0;
2337
+ $table.css( 'margin-left', storedSizes + 50 );
2338
+ vars.tableWidth = $header.width() > tmp ? 'auto' : tmp;
2339
+ $table.css( 'margin-left', storedSizes ? storedSizes : '' );
2340
+ $header = null;
2341
+ $table.unwrap('<span>');
2342
+ }
2343
+ */
2344
+
2345
+ if ( vars.useStorage && vars.overflow ) {
2346
+ // save table width
2347
+ ts.storage( c.table, 'tablesorter-table-original-css-width', vars.tableWidth );
2348
+ tmp = ts.storage( c.table, 'tablesorter-table-resized-width' ) || 'auto';
2349
+ ts.resizable.setWidth( $table, tmp, true );
2350
+ }
2351
+ wo.resizable_.storedSizes = storedSizes = ( vars.useStorage ?
2258
2352
  ts.storage( c.table, ts.css.resizableStorage ) :
2259
2353
  [] ) || [];
2260
2354
  ts.resizable.setWidths( c, wo, storedSizes );
2355
+ ts.resizable.updateStoredSizes( c, wo );
2261
2356
 
2262
2357
  wo.$resizable_container = $( '<div class="' + ts.css.resizableContainer + '">' )
2263
2358
  .css({ top : marginTop })
2264
- .insertBefore( c.$table );
2359
+ .insertBefore( $table );
2265
2360
  // add container
2266
2361
  for ( column = 0; column < c.columns; column++ ) {
2267
2362
  $header = c.$headerIndexed[ column ];
2268
- noResize = ts.getData( $header, ts.getColumnData( c.table, c.headers, column ), 'resizable' ) === 'false';
2363
+ tmp = ts.getColumnData( c.table, c.headers, column );
2364
+ noResize = ts.getData( $header, tmp, 'resizable' ) === 'false';
2269
2365
  if ( !noResize ) {
2270
2366
  $( '<div class="' + ts.css.resizableHandle + '">' )
2271
2367
  .appendTo( wo.$resizable_container )
@@ -2277,37 +2373,52 @@ ts.resizable = {
2277
2373
  .bind( 'selectstart', false );
2278
2374
  }
2279
2375
  }
2280
- c.$table.one('tablesorter-initialized', function() {
2376
+ $table.one('tablesorter-initialized', function() {
2281
2377
  ts.resizable.setHandlePosition( c, wo );
2282
2378
  ts.resizable.bindings( this.config, this.config.widgetOptions );
2283
2379
  });
2284
2380
  },
2285
2381
 
2286
- setWidth : function( $el, width ) {
2382
+ updateStoredSizes : function( c, wo ) {
2383
+ var column, $header,
2384
+ len = c.columns,
2385
+ vars = wo.resizable_;
2386
+ vars.storedSizes = [];
2387
+ for ( column = 0; column < len; column++ ) {
2388
+ $header = c.$headerIndexed[ column ];
2389
+ vars.storedSizes[ column ] = $header.is(':visible') ? $header.width() : 0;
2390
+ }
2391
+ },
2392
+
2393
+ setWidth : function( $el, width, overflow ) {
2394
+ // overflow tables need min & max width set as well
2287
2395
  $el.css({
2288
2396
  'width' : width,
2289
- 'min-width' : '',
2290
- 'max-width' : ''
2397
+ 'min-width' : overflow ? width : '',
2398
+ 'max-width' : overflow ? width : ''
2291
2399
  });
2292
2400
  },
2293
2401
 
2294
2402
  setWidths : function( c, wo, storedSizes ) {
2295
- var column,
2403
+ var column, $temp,
2404
+ vars = wo.resizable_,
2296
2405
  $extra = $( c.namespace + '_extra_headers' ),
2297
2406
  $col = c.$table.children( 'colgroup' ).children( 'col' );
2298
- storedSizes = storedSizes || wo.resizable_.storedSizes || [];
2407
+ storedSizes = storedSizes || vars.storedSizes || [];
2299
2408
  // process only if table ID or url match
2300
2409
  if ( storedSizes.length ) {
2301
2410
  for ( column = 0; column < c.columns; column++ ) {
2302
2411
  // set saved resizable widths
2303
- c.$headerIndexed[ column ].width( storedSizes[ column ] );
2412
+ ts.resizable.setWidth( c.$headerIndexed[ column ], storedSizes[ column ], vars.overflow );
2304
2413
  if ( $extra.length ) {
2305
2414
  // stickyHeaders needs to modify min & max width as well
2306
- ts.resizable.setWidth( $extra.eq( column ).add( $col.eq( column ) ), storedSizes[ column ] );
2415
+ $temp = $extra.eq( column ).add( $col.eq( column ) );
2416
+ ts.resizable.setWidth( $temp, storedSizes[ column ], vars.overflow );
2307
2417
  }
2308
2418
  }
2309
- if ( $( c.namespace + '_extra_table' ).length && !ts.hasWidget( c.table, 'scroller' ) ) {
2310
- ts.resizable.setWidth( $( c.namespace + '_extra_table' ), c.$table.outerWidth() );
2419
+ $temp = $( c.namespace + '_extra_table' );
2420
+ if ( $temp.length && !ts.hasWidget( c.table, 'scroller' ) ) {
2421
+ ts.resizable.setWidth( $temp, c.$table.outerWidth(), vars.overflow );
2311
2422
  }
2312
2423
  }
2313
2424
  },
@@ -2367,7 +2478,7 @@ ts.resizable = {
2367
2478
  var namespace = c.namespace + 'tsresize';
2368
2479
  wo.$resizable_container.children().bind( 'mousedown', function( event ) {
2369
2480
  // save header cell and mouse position
2370
- var column, $this,
2481
+ var column,
2371
2482
  vars = wo.resizable_,
2372
2483
  $extras = $( c.namespace + '_extra_headers' ),
2373
2484
  $header = $( event.target ).data( 'header' );
@@ -2386,11 +2497,7 @@ ts.resizable = {
2386
2497
  vars.next = column;
2387
2498
 
2388
2499
  vars.mouseXPosition = event.pageX;
2389
- vars.storedSizes = [];
2390
- for ( column = 0; column < c.columns; column++ ) {
2391
- $this = c.$headerIndexed[ column ];
2392
- vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0;
2393
- }
2500
+ ts.resizable.updateStoredSizes( c, wo );
2394
2501
  ts.resizable.toggleTextSelection( c, true );
2395
2502
  });
2396
2503
 
@@ -2441,47 +2548,51 @@ ts.resizable = {
2441
2548
  mouseMove : function( c, wo, event ) {
2442
2549
  if ( wo.resizable_.mouseXPosition === 0 || !wo.resizable_.$target ) { return; }
2443
2550
  // resize columns
2444
- var vars = wo.resizable_,
2551
+ var column,
2552
+ total = 0,
2553
+ vars = wo.resizable_,
2445
2554
  $next = vars.$next,
2555
+ tar = vars.storedSizes[ vars.target ],
2446
2556
  leftEdge = event.pageX - vars.mouseXPosition;
2447
- if ( vars.fullWidth ) {
2448
- vars.storedSizes[ vars.target ] += leftEdge;
2449
- vars.storedSizes[ vars.next ] -= leftEdge;
2450
- ts.resizable.setWidths( c, wo );
2451
-
2452
- } else if ( vars.overflow ) {
2453
- c.$table.add( $( c.namespace + '_extra_table' ) ).width(function(i, w){
2454
- return w + leftEdge;
2455
- });
2557
+ if ( vars.overflow ) {
2558
+ if ( tar + leftEdge > 0 ) {
2559
+ vars.storedSizes[ vars.target ] += leftEdge;
2560
+ ts.resizable.setWidth( vars.$target, vars.storedSizes[ vars.target ], true );
2561
+ // update the entire table width
2562
+ for ( column = 0; column < c.columns; column++ ) {
2563
+ total += vars.storedSizes[ column ];
2564
+ }
2565
+ ts.resizable.setWidth( c.$table.add( $( c.namespace + '_extra_table' ) ), total );
2566
+ }
2456
2567
  if ( !$next.length ) {
2457
2568
  // if expanding right-most column, scroll the wrapper
2458
2569
  vars.$wrap[0].scrollLeft = c.$table.width();
2459
2570
  }
2571
+ } else if ( vars.fullWidth ) {
2572
+ vars.storedSizes[ vars.target ] += leftEdge;
2573
+ vars.storedSizes[ vars.next ] -= leftEdge;
2574
+ ts.resizable.setWidths( c, wo );
2460
2575
  } else {
2461
2576
  vars.storedSizes[ vars.target ] += leftEdge;
2462
2577
  ts.resizable.setWidths( c, wo );
2463
2578
  }
2464
2579
  vars.mouseXPosition = event.pageX;
2580
+ // dynamically update sticky header widths
2581
+ c.$table.trigger('stickyHeadersUpdate');
2465
2582
  },
2466
2583
 
2467
2584
  stopResize : function( c, wo ) {
2468
- var $this, column,
2469
- vars = wo.resizable_;
2470
- vars.storedSizes = [];
2471
- if ( ts.storage ) {
2472
- vars.storedSizes = [];
2473
- for ( column = 0; column < c.columns; column++ ) {
2474
- $this = c.$headerIndexed[ column ];
2475
- vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0;
2476
- }
2477
- if ( wo.resizable !== false ) {
2478
- // save all column widths
2479
- ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
2480
- }
2585
+ var vars = wo.resizable_;
2586
+ ts.resizable.updateStoredSizes( c, wo );
2587
+ if ( vars.useStorage ) {
2588
+ // save all column widths
2589
+ ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
2590
+ ts.storage( c.table, 'tablesorter-table-resized-width', c.$table.width() );
2481
2591
  }
2482
2592
  vars.mouseXPosition = 0;
2483
2593
  vars.$target = vars.$next = null;
2484
- $(window).trigger('resize'); // will update stickyHeaders, just in case
2594
+ // will update stickyHeaders, just in case, see #912
2595
+ c.$table.trigger('stickyHeadersUpdate');
2485
2596
  }
2486
2597
  };
2487
2598
 
@@ -2492,11 +2603,12 @@ ts.addWidget({
2492
2603
  id: "resizable",
2493
2604
  priority: 40,
2494
2605
  options: {
2495
- resizable : true,
2606
+ resizable : true, // save column widths to storage
2496
2607
  resizable_addLastColumn : false,
2497
2608
  resizable_widths : [],
2498
2609
  resizable_throttle : false, // set to true (5ms) or any number 0-10 range
2499
- resizable_targetLast : false
2610
+ resizable_targetLast : false,
2611
+ resizable_fullWidth : null
2500
2612
  },
2501
2613
  init: function(table, thisWidget, c, wo) {
2502
2614
  ts.resizable.init( c, wo );
@@ -2520,19 +2632,28 @@ ts.resizableReset = function( table, refreshing ) {
2520
2632
  $( table ).each(function(){
2521
2633
  var index, $t,
2522
2634
  c = this.config,
2523
- wo = c && c.widgetOptions;
2635
+ wo = c && c.widgetOptions,
2636
+ vars = wo.resizable_;
2524
2637
  if ( table && c && c.$headerIndexed.length ) {
2638
+ // restore the initial table width
2639
+ if ( vars.overflow && vars.tableWidth ) {
2640
+ ts.resizable.setWidth( c.$table, vars.tableWidth, true );
2641
+ if ( vars.useStorage ) {
2642
+ ts.storage( table, 'tablesorter-table-resized-width', 'auto' );
2643
+ }
2644
+ }
2525
2645
  for ( index = 0; index < c.columns; index++ ) {
2526
2646
  $t = c.$headerIndexed[ index ];
2527
2647
  if ( wo.resizable_widths && wo.resizable_widths[ index ] ) {
2528
- $t.css( 'width', wo.resizable_widths[ index ] );
2648
+ ts.resizable.setWidth( $t, wo.resizable_widths[ index ], vars.overflow );
2529
2649
  } else if ( !$t.hasClass( 'resizable-false' ) ) {
2530
2650
  // don't clear the width of any column that is not resizable
2531
- $t.css( 'width', '' );
2651
+ ts.resizable.setWidth( $t, '', vars.overflow );
2532
2652
  }
2533
2653
  }
2654
+
2534
2655
  // reset stickyHeader widths
2535
- $( window ).trigger( 'resize' );
2656
+ c.$table.trigger( 'stickyHeadersUpdate' );
2536
2657
  if ( ts.storage && !refreshing ) {
2537
2658
  ts.storage( this, ts.css.resizableStorage, {} );
2538
2659
  }