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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eb7ba6c4dbd8076b0e52b6f0abccb9ee298dc366
4
- data.tar.gz: 887a64f685ec1c39e48c7aa7819f7892b793fab4
3
+ metadata.gz: 853a88593e71f448072c8a7917b8f1365d45e98b
4
+ data.tar.gz: c021dba2083ef3ee1efe3b0039ec1de19232f5df
5
5
  SHA512:
6
- metadata.gz: d0ba74694869a7ff4b46a7c3f271ce77d376b2ffc53a0b553878c5fa58a473b9c942eae7f406a3a2526ec963ba18435bf14829e1c18d4e3de913eeec74495599
7
- data.tar.gz: 458ac71eacbf0b9ac0a8bd625acaa533a19d2fd80c1ee72cf90427419d7903b3074b757df37c01ff6978b4cab77108853f16db74bc35abc8a26286a3107f53b4
6
+ metadata.gz: e2863d563ad0304efcdf39676e4b54411da4f1da60929229f09991fa5e0cefb85f3b1e1fe49bc4c10ce02558e059d3946e26cbb001205a0f0209c799aafb1afe
7
+ data.tar.gz: 9f3b893120f50751ac24432d432ea54d74fb0501c084fd931c672fc32b07911739005f63089270d7b3746acc72f9a0f5f9934130597b17cf50c0bd3759ca37f4
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Simple integration of jquery-tablesorter into the asset pipeline.
6
6
 
7
- Current tablesorter version: 2.22.1 (5/17/2015), [documentation]
7
+ Current tablesorter version: 2.22.3 (6/30/2015), [documentation]
8
8
 
9
9
  Any issue associated with the js/css files, please report to [Mottie's fork].
10
10
 
@@ -1,3 +1,3 @@
1
1
  module JqueryTablesorter
2
- VERSION = '1.17.1'
2
+ VERSION = '1.17.2'
3
3
  end
@@ -408,7 +408,7 @@
408
408
  c.totalRows = p.totalRows = result.total;
409
409
  c.filteredRows = p.filteredRows = typeof result.filteredRows !== 'undefined' ? result.filteredRows : result.total;
410
410
  th = result.headers;
411
- d = result.rows;
411
+ d = result.rows || [];
412
412
  } else {
413
413
  // allow [ total, rows, headers ] or [ rows, total, headers ]
414
414
  t = isNaN(result[0]) && !isNaN(result[1]);
@@ -417,7 +417,8 @@
417
417
  p.totalRows = isNaN(rr_count) ? p.totalRows || 0 : rr_count;
418
418
  // can't set filtered rows when returning an array
419
419
  c.totalRows = c.filteredRows = p.filteredRows = p.totalRows;
420
- d = p.totalRows === 0 ? [""] : result[t ? 0 : 1] || []; // row data
420
+ // set row data to empty array if nothing found - see http://stackoverflow.com/q/30875583/145346
421
+ d = p.totalRows === 0 ? [] : result[t ? 0 : 1] || []; // row data
421
422
  th = result[2]; // headers
422
423
  }
423
424
  l = d && d.length;
@@ -1046,6 +1047,9 @@
1046
1047
  updatePageDisplay(table, p, false);
1047
1048
  }
1048
1049
  }
1050
+
1051
+ // make the hasWidget function think that the pager widget is being used
1052
+ c.widgetInit.pager = true;
1049
1053
  });
1050
1054
  };
1051
1055
 
@@ -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) {
@@ -16,7 +16,7 @@
16
16
  }
17
17
  }(function($) {
18
18
 
19
- /*! TableSorter (FORK) v2.22.1 *//*
19
+ /*! TableSorter (FORK) v2.22.3 *//*
20
20
  * Client-side table sorting with ease!
21
21
  * @requires jQuery v1.2.6+
22
22
  *
@@ -44,7 +44,7 @@
44
44
 
45
45
  var ts = this;
46
46
 
47
- ts.version = '2.22.1';
47
+ ts.version = '2.22.3';
48
48
 
49
49
  ts.parsers = [];
50
50
  ts.widgets = [];
@@ -209,10 +209,10 @@
209
209
  if (typeof(t) === 'string') {
210
210
  // check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow!
211
211
  // http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/
212
- return $.trim(
213
- ( t === 'basic' ? $node.attr(c.textAttribute) || node.textContent : node.textContent ) ||
214
- $node.text()
215
- );
212
+ if ( t === 'basic' && typeof ( te = $node.attr(c.textAttribute) ) !== 'undefined' ) {
213
+ return $.trim( te );
214
+ }
215
+ return $.trim( node.textContent || $node.text() );
216
216
  } else {
217
217
  if (typeof(t) === 'function') {
218
218
  return $.trim( t($node[0], c.table, cellIndex) );
@@ -224,9 +224,8 @@
224
224
  return $.trim( $node[0].textContent || $node.text() );
225
225
  };
226
226
 
227
- function detectParserForColumn(table, rows, rowIndex, cellIndex) {
227
+ function detectParserForColumn(c, rows, rowIndex, cellIndex) {
228
228
  var cur, $node,
229
- c = table.config,
230
229
  i = ts.parsers.length,
231
230
  node = false,
232
231
  nodeValue = '',
@@ -237,7 +236,7 @@
237
236
  node = rows[rowIndex].cells[cellIndex];
238
237
  nodeValue = ts.getElementText(c, node, cellIndex);
239
238
  $node = $(node);
240
- if (table.config.debug) {
239
+ if (c.debug) {
241
240
  log('Checking if value was empty on row ' + rowIndex + ', column: ' + cellIndex + ': "' + nodeValue + '"');
242
241
  }
243
242
  } else {
@@ -247,7 +246,7 @@
247
246
  while (--i >= 0) {
248
247
  cur = ts.parsers[i];
249
248
  // ignore the default text parser because it will always be true
250
- if (cur && cur.id !== 'text' && cur.is && cur.is(nodeValue, table, node, $node)) {
249
+ if (cur && cur.id !== 'text' && cur.is && cur.is(nodeValue, c.table, node, $node)) {
251
250
  return cur;
252
251
  }
253
252
  }
@@ -256,7 +255,7 @@
256
255
  }
257
256
 
258
257
  // centralized function to extract/parse cell contents
259
- function getParsedText( c, cell, colIndex, txt ) {
258
+ ts.getParsedText = function( c, cell, colIndex, txt ) {
260
259
  if ( typeof txt === 'undefined' ) {
261
260
  txt = ts.getElementText( c, cell, colIndex );
262
261
  }
@@ -279,16 +278,17 @@
279
278
  }
280
279
  }
281
280
  return val;
282
- }
281
+ };
283
282
 
284
- function buildParserCache(table) {
285
- var c = table.config,
286
- // update table bodies in case we start with an empty table
287
- tb = c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'),
288
- rows, list, l, i, h, ch, np, p, e, time,
283
+ function buildParserCache( c, $tbodies ) {
284
+ var rows, list, l, i, h, ch, np, p, e, time, tb, len,
285
+ table = c.table,
289
286
  j = 0,
290
- parsersDebug = '',
291
- len = tb.length;
287
+ parsersDebug = '';
288
+ // update table bodies in case we start with an empty table
289
+ c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')');
290
+ tb = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies;
291
+ len = tb.length;
292
292
  if ( len === 0) {
293
293
  return c.debug ? log('Warning: *Empty table!* Not building a parser cache') : '';
294
294
  } else if (c.debug) {
@@ -323,7 +323,7 @@
323
323
  e = false;
324
324
  }
325
325
  if (!p) {
326
- p = detectParserForColumn(table, rows, -1, i);
326
+ p = detectParserForColumn(c, rows, -1, i);
327
327
  }
328
328
  if (c.debug) {
329
329
  parsersDebug += 'column:' + i + '; extractor:' + e.id + '; parser:' + p.id + '; string:' + c.strings[i] + '; empty: ' + c.empties[i] + '\n';
@@ -343,12 +343,14 @@
343
343
  }
344
344
 
345
345
  /* utils */
346
- function buildCache(table) {
347
- var cc, t, v, i, j, k, $row, cols, cacheTime,
346
+ function buildCache(table, $tbodies) {
347
+ var cc, t, v, i, j, k, $tb, $row, cols, cacheTime,
348
348
  totalRows, rowData, prevRowData, colMax,
349
349
  c = table.config,
350
- $tb = c.$tbodies,
351
350
  parsers = c.parsers;
351
+ // update tbody variable
352
+ c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')');
353
+ $tb = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies,
352
354
  c.cache = {};
353
355
  c.totalRows = 0;
354
356
  // if no parsers found, return - it's an empty table.
@@ -396,7 +398,7 @@
396
398
  prevRowData.child[ t ] = [];
397
399
  // child row content does not account for colspans/rowspans; so indexing may be off
398
400
  for ( j = 0; j < c.columns; j++ ) {
399
- prevRowData.child[ t ][ j ] = getParsedText( c, v[ j ], j );
401
+ prevRowData.child[ t ][ j ] = ts.getParsedText( c, v[ j ], j );
400
402
  }
401
403
  // go to the next for loop
402
404
  continue;
@@ -412,7 +414,7 @@
412
414
  }
413
415
  t = ts.getElementText( c, $row[ 0 ].cells[j], j );
414
416
  rowData.raw.push( t ); // save original row text
415
- v = getParsedText( c, $row[ 0 ].cells[ j ], j, t );
417
+ v = ts.getParsedText( c, $row[ 0 ].cells[ j ], j, t );
416
418
  cols.push( v );
417
419
  if ( ( parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) {
418
420
  // determine column max value (ignore sign)
@@ -565,7 +567,7 @@
565
567
  // remove rows/elements before update
566
568
  c.$table.find(c.selectorRemove).remove();
567
569
  // rebuild parsers
568
- buildParserCache(table);
570
+ buildParserCache(c);
569
571
  // rebuild the cache map
570
572
  buildCache(table);
571
573
  checkResort(c, resort, callback);
@@ -855,7 +857,7 @@
855
857
  num = (c.strings[col]) ? c.string[c.strings[col]] || 0 : 0;
856
858
  }
857
859
  // fall back to built-in numeric sort
858
- // var sort = $.tablesorter['sort' + s](table, a[c], b[c], c, colMax[c], dir);
860
+ // var sort = $.tablesorter['sort' + s]( a[c], b[c], dir, colMax[c], table);
859
861
  sort = c.numberSorter ? c.numberSorter(a[col], b[col], dir, colMax[col], table) :
860
862
  ts[ 'sortNumeric' + (dir ? 'Asc' : 'Desc') ](a[col], b[col], num, colMax[col], col, table);
861
863
  } else {
@@ -968,7 +970,7 @@
968
970
  row = $tb.eq( tbdy ).find( 'tr' ).index( $row );
969
971
  cache = tbcache.normalized[ row ];
970
972
  icell = $cell.index();
971
- t = getParsedText( c, cell, icell );
973
+ t = ts.getParsedText( c, cell, icell );
972
974
  cache[ icell ] = t;
973
975
  cache[ c.columns ].$row = $row;
974
976
  if ( (c.parsers[icell].type || '').toLowerCase() === 'numeric' ) {
@@ -1003,7 +1005,7 @@
1003
1005
  tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') );
1004
1006
  // fixes adding rows to an empty table - see issue #179
1005
1007
  if (!(c.parsers && c.parsers.length)) {
1006
- buildParserCache(table);
1008
+ buildParserCache(c);
1007
1009
  }
1008
1010
  // add each row
1009
1011
  for (i = 0; i < rows; i++) {
@@ -1016,7 +1018,7 @@
1016
1018
  };
1017
1019
  // add each cell
1018
1020
  for (j = 0; j < l; j++) {
1019
- cells[j] = getParsedText( c, $row[i].cells[j], j );
1021
+ cells[j] = ts.getParsedText( c, $row[i].cells[j], j );
1020
1022
  if ((c.parsers[j].type || '').toLowerCase() === 'numeric') {
1021
1023
  // update column max value (ignore sign)
1022
1024
  c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0);
@@ -1061,13 +1063,14 @@
1061
1063
  callback(table);
1062
1064
  }
1063
1065
  })
1064
- .bind('updateCache' + c.namespace, function(e, callback){
1066
+ // $tbodies variable is used by the tbody sorting widget
1067
+ .bind('updateCache' + c.namespace, function(e, callback, $tbodies){
1065
1068
  // rebuild parsers
1066
1069
  if (!(c.parsers && c.parsers.length)) {
1067
- buildParserCache(table);
1070
+ buildParserCache(c, $tbodies);
1068
1071
  }
1069
1072
  // rebuild the cache map
1070
- buildCache(table);
1073
+ buildCache(table, $tbodies);
1071
1074
  if ($.isFunction(callback)) {
1072
1075
  callback(table);
1073
1076
  }
@@ -1187,7 +1190,7 @@
1187
1190
  // add widget options before parsing (e.g. grouping widget has parser settings)
1188
1191
  ts.applyWidgetOptions(table, c);
1189
1192
  // try to auto detect column type, and store in tables config
1190
- buildParserCache(table);
1193
+ buildParserCache(c);
1191
1194
  // start total row count at zero
1192
1195
  c.totalRows = 0;
1193
1196
  // build the cache for the tbody cells
@@ -1413,10 +1416,11 @@
1413
1416
  }
1414
1417
  // ignore mouseup if mousedown wasn't on the same target
1415
1418
  if ( type.match(' ' + c.pointerUp + ' ') && downTarget !== e.target && external !== true ) { return; }
1416
- // set timer on mousedown
1419
+ // set target on mousedown
1417
1420
  if ( type.match(' ' + c.pointerDown + ' ') ) {
1418
1421
  downTarget = e.target;
1419
- // needed or jQuery v1.3.2 or older throws an "Uncaught TypeError: handler.apply is not a function" error
1422
+ // preventDefault needed or jQuery v1.3.2 and older throws an
1423
+ // "Uncaught TypeError: handler.apply is not a function" error
1420
1424
  temp = $target.jquery.split( '.' );
1421
1425
  if ( temp[0] === '1' && temp[1] < 4 ) { e.preventDefault(); }
1422
1426
  return;
@@ -2155,7 +2159,7 @@
2155
2159
  format: function(table, c, wo) {
2156
2160
  var $tv, $tr, row, even, time, k, i, len,
2157
2161
  child = new RegExp(c.cssChildRow, 'i'),
2158
- b = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody' ) );
2162
+ b = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody:not(.' + c.cssInfoBlock + ')' ) );
2159
2163
  if (c.debug) {
2160
2164
  time = new Date();
2161
2165
  }
@@ -2650,6 +2654,66 @@ ts.filter = {
2650
2654
  // data.index = column index; table = table element ( DOM )
2651
2655
  // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
2652
2656
  types: {
2657
+ or : function( c, data, vars ) {
2658
+ if ( /\|/.test( data.iFilter ) || ts.filter.regex.orSplit.test( data.filter ) ) {
2659
+ var indx, filterMatched, txt, query, regex,
2660
+ // duplicate data but split filter
2661
+ data2 = $.extend( {}, data ),
2662
+ index = data.index,
2663
+ parsed = data.parsed[ index ],
2664
+ filter = data.filter.split( ts.filter.regex.orSplit ),
2665
+ iFilter = data.iFilter.split( ts.filter.regex.orSplit ),
2666
+ len = filter.length;
2667
+ for ( indx = 0; indx < len; indx++ ) {
2668
+ data2.nestedFilters = true;
2669
+ data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
2670
+ data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
2671
+ query = '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')';
2672
+ regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
2673
+ // filterMatched = data2.filter === '' && indx > 0 ? true
2674
+ // look for an exact match with the 'or' unless the 'filter-match' class is found
2675
+ filterMatched = regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars );
2676
+ if ( filterMatched ) {
2677
+ return filterMatched;
2678
+ }
2679
+ }
2680
+ // may be null from processing types
2681
+ return filterMatched || false;
2682
+ }
2683
+ return null;
2684
+ },
2685
+ // Look for an AND or && operator ( logical and )
2686
+ and : function( c, data, vars ) {
2687
+ if ( ts.filter.regex.andTest.test( data.filter ) ) {
2688
+ var indx, filterMatched, result, txt, query, regex,
2689
+ // duplicate data but split filter
2690
+ data2 = $.extend( {}, data ),
2691
+ index = data.index,
2692
+ parsed = data.parsed[ index ],
2693
+ filter = data.filter.split( ts.filter.regex.andSplit ),
2694
+ iFilter = data.iFilter.split( ts.filter.regex.andSplit ),
2695
+ len = filter.length;
2696
+ for ( indx = 0; indx < len; indx++ ) {
2697
+ data2.nestedFilters = true;
2698
+ data2.filter = '' + ( ts.filter.parseFilter( c, filter[ indx ], index, parsed ) || '' );
2699
+ data2.iFilter = '' + ( ts.filter.parseFilter( c, iFilter[ indx ], index, parsed ) || '' );
2700
+ query = ( '(' + ( ts.filter.parseFilter( c, data2.filter, index, parsed ) || '' ) + ')' )
2701
+ // replace wild cards since /(a*)/i will match anything
2702
+ .replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' );
2703
+ regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
2704
+ // look for an exact match with the 'and' unless the 'filter-match' class is found
2705
+ result = ( regex.test( data2.exact ) || ts.filter.processTypes( c, data2, vars ) );
2706
+ if ( indx === 0 ) {
2707
+ filterMatched = result;
2708
+ } else {
2709
+ filterMatched = filterMatched && result;
2710
+ }
2711
+ }
2712
+ // may be null from processing types
2713
+ return filterMatched || false;
2714
+ }
2715
+ return null;
2716
+ },
2653
2717
  // Look for regex
2654
2718
  regex: function( c, data ) {
2655
2719
  if ( ts.filter.regex.regex.test( data.filter ) ) {
@@ -2737,23 +2801,6 @@ ts.filter = {
2737
2801
  }
2738
2802
  return null;
2739
2803
  },
2740
- // Look for an AND or && operator ( logical and )
2741
- and : function( c, data ) {
2742
- if ( ts.filter.regex.andTest.test( data.filter ) ) {
2743
- var index = data.index,
2744
- parsed = data.parsed[index],
2745
- query = data.iFilter.split( ts.filter.regex.andSplit ),
2746
- result = data.iExact.search( $.trim( ts.filter.parseFilter( c, query[0], index, parsed ) ) ) >= 0,
2747
- indx = query.length - 1;
2748
- while ( result && indx ) {
2749
- result = result &&
2750
- data.iExact.search( $.trim( ts.filter.parseFilter( c, query[indx], index, parsed ) ) ) >= 0;
2751
- indx--;
2752
- }
2753
- return result;
2754
- }
2755
- return null;
2756
- },
2757
2804
  // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
2758
2805
  range : function( c, data ) {
2759
2806
  if ( ts.filter.regex.toTest.test( data.iFilter ) ) {
@@ -2790,24 +2837,20 @@ ts.filter = {
2790
2837
  },
2791
2838
  // Look for wild card: ? = single, * = multiple, or | = logical OR
2792
2839
  wild : function( c, data ) {
2793
- if ( /[\?\*\|]/.test( data.iFilter ) || ts.filter.regex.orReplace.test( data.filter ) ) {
2840
+ if ( /[\?\*\|]/.test( data.iFilter ) ) {
2794
2841
  var index = data.index,
2795
2842
  parsed = data.parsed[ index ],
2796
- txt = data.iFilter.replace( ts.filter.regex.orReplace, '|' ),
2797
- query = '' + ( ts.filter.parseFilter( c, txt, index, parsed ) || '' );
2843
+ query = '' + ( ts.filter.parseFilter( c, data.iFilter, index, parsed ) || '' );
2798
2844
  // look for an exact match with the 'or' unless the 'filter-match' class is found
2799
- if ( !c.$headerIndexed[ index ].hasClass( 'filter-match' ) && /\|/.test( query ) ) {
2800
- // show all results while using filter match. Fixes #727
2801
- if ( query[ query.length - 1 ] === '|' ) {
2802
- query += '*';
2803
- }
2804
- query = data.anyMatch && $.isArray( data.rowArray ) ?
2805
- '(' + query + ')' :
2806
- '^(' + query + ')$';
2845
+ if ( !/\?\*/.test( query ) && data.nestedFilters ) {
2846
+ query = data.isMatch ? query : '^(' + query + ')$';
2807
2847
  }
2808
2848
  // parsing the filter may not work properly when using wildcards =/
2809
- return new RegExp( query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ) )
2810
- .test( data.iExact );
2849
+ return new RegExp(
2850
+ query.replace( /\?/g, '\\S{1}' ).replace( /\*/g, '\\S*' ),
2851
+ c.widgetOptions.filter_ignoreCase ? 'i' : ''
2852
+ )
2853
+ .test( data.exact );
2811
2854
  }
2812
2855
  return null;
2813
2856
  },
@@ -2861,7 +2904,7 @@ ts.filter = {
2861
2904
  toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)' ,'gi' ),
2862
2905
  andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
2863
2906
  andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
2864
- orReplace : new RegExp( '\\s+(' + ts.language.or + ')\\s+', 'gi' ),
2907
+ orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
2865
2908
  iQuery : new RegExp( val, 'i' ),
2866
2909
  igQuery : new RegExp( val, 'ig' )
2867
2910
  });
@@ -3081,7 +3124,6 @@ ts.filter = {
3081
3124
  }
3082
3125
  }
3083
3126
  },
3084
-
3085
3127
  setDefaults: function( table, c, wo ) {
3086
3128
  var isArray, saved, indx, col, $filters,
3087
3129
  // get current ( default ) filters
@@ -3308,14 +3350,13 @@ ts.filter = {
3308
3350
  }
3309
3351
  },
3310
3352
  hideFilters: function( table, c ) {
3311
- var $filterRow, $filterRow2, timer;
3312
- $( table )
3353
+ var timer;
3354
+ c.$table
3313
3355
  .find( '.' + tscss.filterRow )
3314
- .addClass( tscss.filterRowHide )
3315
3356
  .bind( 'mouseenter mouseleave', function( e ) {
3316
3357
  // save event object - http://bugs.jquery.com/ticket/12140
3317
- var event = e;
3318
- $filterRow = $( this );
3358
+ var event = e,
3359
+ $filterRow = $( this );
3319
3360
  clearTimeout( timer );
3320
3361
  timer = setTimeout( function() {
3321
3362
  if ( /enter|over/.test( event.type ) ) {
@@ -3333,13 +3374,14 @@ ts.filter = {
3333
3374
  }, 200 );
3334
3375
  })
3335
3376
  .find( 'input, select' ).bind( 'focus blur', function( e ) {
3336
- $filterRow2 = $( this ).closest( 'tr' );
3377
+ var event = e,
3378
+ $row = $( this ).closest( 'tr' );
3337
3379
  clearTimeout( timer );
3338
- var event = e;
3339
3380
  timer = setTimeout( function() {
3381
+ clearTimeout( timer );
3340
3382
  // don't hide row if any filter has a value
3341
3383
  if ( ts.getFilters( c.$table ).join( '' ) === '' ) {
3342
- $filterRow2.toggleClass( tscss.filterRowHide, event.type === 'focus' );
3384
+ $row.toggleClass( tscss.filterRowHide, event.type !== 'focus' );
3343
3385
  }
3344
3386
  }, 200 );
3345
3387
  });
@@ -3373,7 +3415,7 @@ ts.filter = {
3373
3415
  return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' );
3374
3416
  });
3375
3417
  }
3376
- return $();
3418
+ return $input || $();
3377
3419
  },
3378
3420
  multipleColumns: function( c, $input ) {
3379
3421
  // look for multiple columns '1-3,4-6,8' in data-column
@@ -3426,8 +3468,22 @@ ts.filter = {
3426
3468
  }
3427
3469
  return columns;
3428
3470
  },
3471
+ processTypes: function( c, data, vars ) {
3472
+ var ffxn,
3473
+ filterMatched = null,
3474
+ matches = null;
3475
+ for ( ffxn in ts.filter.types ) {
3476
+ if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
3477
+ matches = ts.filter.types[ffxn]( c, data, vars );
3478
+ if ( matches !== null ) {
3479
+ filterMatched = matches;
3480
+ }
3481
+ }
3482
+ }
3483
+ return filterMatched;
3484
+ },
3429
3485
  processRow: function( c, data, vars ) {
3430
- var $cell, columnIndex, hasSelect, matches, result, val, filterMatched, excludeMatch,
3486
+ var columnIndex, hasSelect, result, val, filterMatched,
3431
3487
  fxn, ffxn, txt,
3432
3488
  regex = ts.filter.regex,
3433
3489
  wo = c.widgetOptions,
@@ -3438,6 +3494,7 @@ ts.filter = {
3438
3494
  // look for multiple columns '1-3,4-6,8'
3439
3495
  columnIndex = ts.filter.multipleColumns( c, wo.filter_$anyMatch );
3440
3496
  data.anyMatch = true;
3497
+ data.isMatch = true;
3441
3498
  data.rowArray = data.$cells.map( function( i ) {
3442
3499
  if ( $.inArray( i, columnIndex ) > -1 ) {
3443
3500
  if ( data.parsed[ i ] ) {
@@ -3457,16 +3514,10 @@ ts.filter = {
3457
3514
  data.exact = data.rowArray.join( ' ' );
3458
3515
  data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
3459
3516
  data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
3460
- filterMatched = null;
3461
- matches = null;
3462
- for ( ffxn in ts.filter.types ) {
3463
- if ( $.inArray( ffxn, vars.noAnyMatch ) < 0 && matches === null ) {
3464
- matches = ts.filter.types[ffxn]( c, data );
3465
- if ( matches !== null ) {
3466
- filterMatched = matches;
3467
- }
3468
- }
3469
- }
3517
+
3518
+ vars.excludeMatch = vars.noAnyMatch;
3519
+ filterMatched = ts.filter.processTypes( c, data, vars );
3520
+
3470
3521
  if ( filterMatched !== null ) {
3471
3522
  showRow = filterMatched;
3472
3523
  } else {
@@ -3493,7 +3544,7 @@ ts.filter = {
3493
3544
  data.index = columnIndex;
3494
3545
 
3495
3546
  // filter types to exclude, per column
3496
- excludeMatch = vars.excludeFilter[ columnIndex ];
3547
+ vars.excludeMatch = vars.excludeFilter[ columnIndex ];
3497
3548
 
3498
3549
  // ignore if filter is empty or disabled
3499
3550
  if ( data.filter ) {
@@ -3507,6 +3558,9 @@ ts.filter = {
3507
3558
  }
3508
3559
  data.iExact = !regex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
3509
3560
  data.exact.toLowerCase() : data.exact;
3561
+
3562
+ data.isMatch = c.$headerIndexed[ data.index ].hasClass( 'filter-match' );
3563
+
3510
3564
  result = showRow; // if showRow is true, show that row
3511
3565
 
3512
3566
  // in case select filter option has a different value vs text 'a - z|A through Z'
@@ -3531,13 +3585,12 @@ ts.filter = {
3531
3585
  // data.filter = case sensitive
3532
3586
  data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
3533
3587
  fxn = vars.functions[ columnIndex ];
3534
- $cell = c.$headerIndexed[ columnIndex ];
3535
- hasSelect = $cell.hasClass( 'filter-select' );
3588
+ hasSelect = c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
3536
3589
  filterMatched = null;
3537
3590
  if ( fxn || ( hasSelect && val ) ) {
3538
3591
  if ( fxn === true || hasSelect ) {
3539
3592
  // default selector uses exact match unless 'filter-match' class is found
3540
- filterMatched = $cell.hasClass( 'filter-match' ) ?
3593
+ filterMatched = data.isMatch ?
3541
3594
  data.iExact.search( data.iFilter ) >= 0 :
3542
3595
  data.filter === data.exact;
3543
3596
  } else if ( typeof fxn === 'function' ) {
@@ -3554,15 +3607,7 @@ ts.filter = {
3554
3607
  if ( filterMatched === null ) {
3555
3608
  // cycle through the different filters
3556
3609
  // filters return a boolean or null if nothing matches
3557
- matches = null;
3558
- for ( ffxn in ts.filter.types ) {
3559
- if ( $.inArray( ffxn, excludeMatch ) < 0 && matches === null ) {
3560
- matches = ts.filter.types[ ffxn ]( c, data );
3561
- if ( matches !== null ) {
3562
- filterMatched = matches;
3563
- }
3564
- }
3565
- }
3610
+ filterMatched = ts.filter.processTypes( c, data, vars );
3566
3611
  if ( filterMatched !== null ) {
3567
3612
  result = filterMatched;
3568
3613
  // Look for match, and add child row data for matching
@@ -3596,7 +3641,7 @@ ts.filter = {
3596
3641
  anyMatch: false,
3597
3642
  filters: filters,
3598
3643
  // regex filter type cache
3599
- filter_regexCache : [],
3644
+ filter_regexCache : []
3600
3645
  },
3601
3646
  vars = {
3602
3647
  // anyMatch really screws up with these types of filters
@@ -3817,7 +3862,7 @@ ts.filter = {
3817
3862
  },
3818
3863
  getOptionSource: function( table, column, onlyAvail ) {
3819
3864
  table = $( table )[0];
3820
- var cts, indx, len,
3865
+ var cts, txt, indx, len,
3821
3866
  c = table.config,
3822
3867
  wo = c.widgetOptions,
3823
3868
  parsed = [],
@@ -3862,11 +3907,13 @@ ts.filter = {
3862
3907
  len = arry.length;
3863
3908
  // parse select option values
3864
3909
  for ( indx = 0; indx < len; indx++ ) {
3910
+ txt = arry[ indx ];
3865
3911
  // parse array data using set column parser; this DOES NOT pass the original
3866
3912
  // table cell to the parser format function
3867
3913
  parsed.push({
3868
- t : arry[ indx ],
3869
- p : c.parsers && c.parsers[ column ].format( arry[ indx ], table, [], column )
3914
+ t : txt,
3915
+ // check parser length - fixes #934
3916
+ p : c.parsers && c.parsers.length && c.parsers[ column ].format( txt, table, [], column ) || txt
3870
3917
  });
3871
3918
  }
3872
3919
 
@@ -4056,8 +4103,8 @@ ts.getFilters = function( table, getRaw, setFilters, skipFirst ) {
4056
4103
  $column = ts.filter.getLatestSearch( $column );
4057
4104
  if ( $.isArray( setFilters ) ) {
4058
4105
  // skip first ( latest input ) to maintain cursor position while typing
4059
- if ( skipFirst ) {
4060
- $column.slice( 1 );
4106
+ if ( skipFirst && $column.length > 1 ) {
4107
+ $column = $column.slice( 1 );
4061
4108
  }
4062
4109
  if ( i === c.columns ) {
4063
4110
  // prevent data-column='all' from filling data-column='0,1' ( etc )
@@ -4129,32 +4176,34 @@ $.extend(ts.css, {
4129
4176
  // Add a resize event to table headers
4130
4177
  ts.addHeaderResizeEvent = function(table, disable, settings) {
4131
4178
  table = $(table)[0]; // make sure we're using a dom element
4132
- var headers,
4133
- defaults = {
4179
+ if ( !table.config ) { return; }
4180
+ var defaults = {
4134
4181
  timer : 250
4135
4182
  },
4136
4183
  options = $.extend({}, defaults, settings),
4137
4184
  c = table.config,
4138
4185
  wo = c.widgetOptions,
4139
- checkSizes = function(triggerEvent) {
4186
+ checkSizes = function( triggerEvent ) {
4187
+ var index, headers, $header, sizes, width, height,
4188
+ len = c.$headers.length;
4140
4189
  wo.resize_flag = true;
4141
4190
  headers = [];
4142
- c.$headers.each(function() {
4143
- var $header = $(this),
4144
- sizes = $header.data('savedSizes') || [0,0], // fixes #394
4145
- width = this.offsetWidth,
4146
- height = this.offsetHeight;
4147
- if (width !== sizes[0] || height !== sizes[1]) {
4148
- $header.data('savedSizes', [ width, height ]);
4149
- headers.push(this);
4191
+ for ( index = 0; index < len; index++ ) {
4192
+ $header = c.$headers.eq( index );
4193
+ sizes = $header.data( 'savedSizes' ) || [ 0,0 ]; // fixes #394
4194
+ width = $header[0].offsetWidth;
4195
+ height = $header[0].offsetHeight;
4196
+ if ( width !== sizes[0] || height !== sizes[1] ) {
4197
+ $header.data( 'savedSizes', [ width, height ] );
4198
+ headers.push( $header[0] );
4150
4199
  }
4151
- });
4152
- if (headers.length && triggerEvent !== false) {
4153
- c.$table.trigger('resize', [ headers ]);
4200
+ }
4201
+ if ( headers.length && triggerEvent !== false ) {
4202
+ c.$table.trigger( 'resize', [ headers ] );
4154
4203
  }
4155
4204
  wo.resize_flag = false;
4156
4205
  };
4157
- checkSizes(false);
4206
+ checkSizes( false );
4158
4207
  clearInterval(wo.resize_timer);
4159
4208
  if (disable) {
4160
4209
  wo.resize_flag = false;
@@ -4190,7 +4239,8 @@ ts.addWidget({
4190
4239
  if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) {
4191
4240
  return;
4192
4241
  }
4193
- var $table = c.$table,
4242
+ var index, len, $t,
4243
+ $table = c.$table,
4194
4244
  // add position: relative to attach element, hopefully it won't cause trouble.
4195
4245
  $attach = $(wo.stickyHeaders_attachTo),
4196
4246
  namespace = c.namespace + 'stickyheaders ',
@@ -4225,17 +4275,19 @@ ts.addWidget({
4225
4275
  laststate = '',
4226
4276
  spacing = 0,
4227
4277
  setWidth = function($orig, $clone){
4228
- $orig.filter(':visible').each(function(i) {
4229
- var width, border,
4230
- $cell = $clone.filter(':visible').eq(i),
4231
- $this = $(this);
4278
+ var index, width, border, $cell, $this,
4279
+ $cells = $orig.filter(':visible'),
4280
+ len = $cells.length;
4281
+ for ( index = 0; index < len; index++ ) {
4282
+ $cell = $clone.filter(':visible').eq(index);
4283
+ $this = $cells.eq(index);
4232
4284
  // code from https://github.com/jmosbech/StickyTableHeaders
4233
4285
  if ($this.css('box-sizing') === 'border-box') {
4234
4286
  width = $this.outerWidth();
4235
4287
  } else {
4236
4288
  if ($cell.css('border-collapse') === 'collapse') {
4237
4289
  if (window.getComputedStyle) {
4238
- width = parseFloat( window.getComputedStyle(this, null).width );
4290
+ width = parseFloat( window.getComputedStyle($this[0], null).width );
4239
4291
  } else {
4240
4292
  // ie8 only
4241
4293
  border = parseFloat( $this.css('border-width') );
@@ -4246,10 +4298,11 @@ ts.addWidget({
4246
4298
  }
4247
4299
  }
4248
4300
  $cell.css({
4301
+ 'width': width,
4249
4302
  'min-width': width,
4250
4303
  'max-width': width
4251
4304
  });
4252
- });
4305
+ }
4253
4306
  },
4254
4307
  resizeHeader = function() {
4255
4308
  stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0;
@@ -4261,6 +4314,39 @@ ts.addWidget({
4261
4314
  });
4262
4315
  setWidth( $table, $stickyTable );
4263
4316
  setWidth( $header, $stickyCells );
4317
+ },
4318
+ scrollSticky = function( resizing ) {
4319
+ if (!$table.is(':visible')) { return; } // fixes #278
4320
+ // Detect nested tables - fixes #724
4321
+ nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
4322
+ var offset = $table.offset(),
4323
+ yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3
4324
+ xWindow = $.isWindow( $xScroll[0] ),
4325
+ // scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
4326
+ scrollTop = ( $attach.length ? ( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
4327
+ tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)),
4328
+ isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
4329
+ cssSettings = { visibility : isVisible };
4330
+
4331
+ if ($attach.length) {
4332
+ cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop();
4333
+ }
4334
+ if (xWindow) {
4335
+ // adjust when scrolling horizontally - fixes issue #143
4336
+ cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing;
4337
+ }
4338
+ if ($nestedSticky.length) {
4339
+ cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop;
4340
+ }
4341
+ $stickyWrap
4342
+ .removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide )
4343
+ .addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide )
4344
+ .css(cssSettings);
4345
+ if (isVisible !== laststate || resizing) {
4346
+ // make sure the column widths match
4347
+ resizeHeader();
4348
+ laststate = isVisible;
4349
+ }
4264
4350
  };
4265
4351
  // only add a position relative if a position isn't already defined
4266
4352
  if ($attach.length && !$attach.css('position')) {
@@ -4292,48 +4378,26 @@ ts.addWidget({
4292
4378
 
4293
4379
  // onRenderHeader is defined, we need to do something about it (fixes #641)
4294
4380
  if (c.onRenderHeader) {
4295
- $stickyThead.children('tr').children().each(function(index){
4381
+ $t = $stickyThead.children('tr').children();
4382
+ len = $t.length;
4383
+ for ( index = 0; index < len; index++ ) {
4296
4384
  // send second parameter
4297
- c.onRenderHeader.apply( $(this), [ index, c, $stickyTable ] );
4298
- });
4385
+ c.onRenderHeader.apply( $t.eq( index ), [ index, c, $stickyTable ] );
4386
+ }
4299
4387
  }
4300
4388
 
4301
4389
  // make it sticky!
4302
4390
  $xScroll.add($yScroll)
4303
- .unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') )
4304
- .bind('scroll resize '.split(' ').join( namespace ), function(event) {
4305
- if (!$table.is(':visible')) { return; } // fixes #278
4306
- // Detect nested tables - fixes #724
4307
- nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
4308
- var offset = $table.offset(),
4309
- yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3
4310
- xWindow = $.isWindow( $xScroll[0] ),
4311
- // scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
4312
- scrollTop = ( $attach.length ? ( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
4313
- tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)),
4314
- isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
4315
- cssSettings = { visibility : isVisible };
4316
-
4317
- if ($attach.length) {
4318
- cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop();
4319
- }
4320
- if (xWindow) {
4321
- // adjust when scrolling horizontally - fixes issue #143
4322
- cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing;
4323
- }
4324
- if ($nestedSticky.length) {
4325
- cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop;
4326
- }
4327
- $stickyWrap
4328
- .removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide )
4329
- .addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide )
4330
- .css(cssSettings);
4331
- if (isVisible !== laststate || event.type === 'resize') {
4332
- // make sure the column widths match
4333
- resizeHeader();
4334
- laststate = isVisible;
4335
- }
4336
- });
4391
+ .unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') )
4392
+ .bind('scroll resize '.split(' ').join( namespace ), function( event ) {
4393
+ scrollSticky( event.type === 'resize' );
4394
+ });
4395
+ c.$table
4396
+ .unbind('stickyHeadersUpdate' + namespace)
4397
+ .bind('stickyHeadersUpdate' + namespace, function(){
4398
+ scrollSticky( true );
4399
+ });
4400
+
4337
4401
  if (wo.stickyHeaders_addResizeEvent) {
4338
4402
  ts.addHeaderResizeEvent(table);
4339
4403
  }
@@ -4369,7 +4433,7 @@ ts.addWidget({
4369
4433
  var namespace = c.namespace + 'stickyheaders ';
4370
4434
  c.$table
4371
4435
  .removeClass('hasStickyHeaders')
4372
- .unbind( ('pagerComplete filterEnd '.split(' ').join(namespace)).replace(/\s+/g, ' ') )
4436
+ .unbind( ('pagerComplete filterEnd stickyHeadersUpdate '.split(' ').join(namespace)).replace(/\s+/g, ' ') )
4373
4437
  .next('.' + ts.css.stickyWrap).remove();
4374
4438
  if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table
4375
4439
  $(window)
@@ -4383,7 +4447,8 @@ ts.addWidget({
4383
4447
 
4384
4448
  })(jQuery, window);
4385
4449
 
4386
- /*! Widget: resizable - updated 5/17/2015 (v2.22.0) */
4450
+ /*! Widget: resizable - updated 6/26/2015 (v2.22.2) */
4451
+ /*jshint browser:true, jquery:true, unused:false */
4387
4452
  ;(function ($, window) {
4388
4453
  'use strict';
4389
4454
  var ts = $.tablesorter || {};
@@ -4402,8 +4467,8 @@ $(function(){
4402
4467
  '-khtml-user-select: none; -webkit-user-select: none; user-select: none; }' +
4403
4468
  '.' + ts.css.resizableContainer + ' { position: relative; height: 1px; }' +
4404
4469
  // make handle z-index > than stickyHeader z-index, so the handle stays above sticky header
4405
- '.' + ts.css.resizableHandle + ' { position: absolute; display: inline-block; width: 8px; top: 1px;' +
4406
- 'cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }' +
4470
+ '.' + ts.css.resizableHandle + ' { position: absolute; display: inline-block; width: 8px;' +
4471
+ 'top: 1px; cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }' +
4407
4472
  '</style>';
4408
4473
  $(s).appendTo('body');
4409
4474
  });
@@ -4412,34 +4477,69 @@ ts.resizable = {
4412
4477
  init : function( c, wo ) {
4413
4478
  if ( c.$table.hasClass( 'hasResizable' ) ) { return; }
4414
4479
  c.$table.addClass( 'hasResizable' );
4415
- ts.resizableReset( c.table, true ); // set default widths
4480
+
4481
+ var noResize, $header, column, storedSizes, tmp,
4482
+ $table = c.$table,
4483
+ $parent = $table.parent(),
4484
+ marginTop = parseInt( $table.css( 'margin-top' ), 10 ),
4416
4485
 
4417
4486
  // internal variables
4418
- wo.resizable_ = {
4419
- $wrap : c.$table.parent(),
4487
+ vars = wo.resizable_ = {
4488
+ useStorage : ts.storage && wo.resizable !== false,
4489
+ $wrap : $parent,
4420
4490
  mouseXPosition : 0,
4421
4491
  $target : null,
4422
4492
  $next : null,
4423
- overflow : c.$table.parent().css('overflow') === 'auto',
4424
- fullWidth : Math.abs(c.$table.parent().width() - c.$table.width()) < 20,
4493
+ overflow : $parent.css('overflow') === 'auto' ||
4494
+ $parent.css('overflow') === 'scroll' ||
4495
+ $parent.css('overflow-x') === 'auto' ||
4496
+ $parent.css('overflow-x') === 'scroll',
4425
4497
  storedSizes : []
4426
4498
  };
4427
4499
 
4428
- var noResize, $header, column, storedSizes,
4429
- marginTop = parseInt( c.$table.css( 'margin-top' ), 10 );
4500
+ // set default widths
4501
+ ts.resizableReset( c.table, true );
4502
+
4503
+ // now get measurements!
4504
+ vars.tableWidth = $table.width();
4505
+ // attempt to autodetect
4506
+ vars.fullWidth = Math.abs( $parent.width() - vars.tableWidth ) < 20;
4507
+
4508
+ /*
4509
+ // Hacky method to determine if table width is set to "auto"
4510
+ // http://stackoverflow.com/a/20892048/145346
4511
+ if ( !vars.fullWidth ) {
4512
+ tmp = $table.width();
4513
+ $header = $table.wrap('<span>').parent(); // temp variable
4514
+ storedSizes = parseInt( $table.css( 'margin-left' ), 10 ) || 0;
4515
+ $table.css( 'margin-left', storedSizes + 50 );
4516
+ vars.tableWidth = $header.width() > tmp ? 'auto' : tmp;
4517
+ $table.css( 'margin-left', storedSizes ? storedSizes : '' );
4518
+ $header = null;
4519
+ $table.unwrap('<span>');
4520
+ }
4521
+ */
4430
4522
 
4431
- wo.resizable_.storedSizes = storedSizes = ( ( ts.storage && wo.resizable !== false ) ?
4523
+ if ( vars.useStorage && vars.overflow ) {
4524
+ // save table width
4525
+ ts.storage( c.table, 'tablesorter-table-original-css-width', vars.tableWidth );
4526
+ tmp = ts.storage( c.table, 'tablesorter-table-resized-width' ) || 'auto';
4527
+ ts.resizable.setWidth( $table, tmp, true );
4528
+ }
4529
+ wo.resizable_.storedSizes = storedSizes = ( vars.useStorage ?
4432
4530
  ts.storage( c.table, ts.css.resizableStorage ) :
4433
4531
  [] ) || [];
4434
4532
  ts.resizable.setWidths( c, wo, storedSizes );
4533
+ ts.resizable.updateStoredSizes( c, wo );
4435
4534
 
4436
4535
  wo.$resizable_container = $( '<div class="' + ts.css.resizableContainer + '">' )
4437
4536
  .css({ top : marginTop })
4438
- .insertBefore( c.$table );
4537
+ .insertBefore( $table );
4439
4538
  // add container
4440
4539
  for ( column = 0; column < c.columns; column++ ) {
4441
4540
  $header = c.$headerIndexed[ column ];
4442
- noResize = ts.getData( $header, ts.getColumnData( c.table, c.headers, column ), 'resizable' ) === 'false';
4541
+ tmp = ts.getColumnData( c.table, c.headers, column );
4542
+ noResize = ts.getData( $header, tmp, 'resizable' ) === 'false';
4443
4543
  if ( !noResize ) {
4444
4544
  $( '<div class="' + ts.css.resizableHandle + '">' )
4445
4545
  .appendTo( wo.$resizable_container )
@@ -4451,37 +4551,52 @@ ts.resizable = {
4451
4551
  .bind( 'selectstart', false );
4452
4552
  }
4453
4553
  }
4454
- c.$table.one('tablesorter-initialized', function() {
4554
+ $table.one('tablesorter-initialized', function() {
4455
4555
  ts.resizable.setHandlePosition( c, wo );
4456
4556
  ts.resizable.bindings( this.config, this.config.widgetOptions );
4457
4557
  });
4458
4558
  },
4459
4559
 
4460
- setWidth : function( $el, width ) {
4560
+ updateStoredSizes : function( c, wo ) {
4561
+ var column, $header,
4562
+ len = c.columns,
4563
+ vars = wo.resizable_;
4564
+ vars.storedSizes = [];
4565
+ for ( column = 0; column < len; column++ ) {
4566
+ $header = c.$headerIndexed[ column ];
4567
+ vars.storedSizes[ column ] = $header.is(':visible') ? $header.width() : 0;
4568
+ }
4569
+ },
4570
+
4571
+ setWidth : function( $el, width, overflow ) {
4572
+ // overflow tables need min & max width set as well
4461
4573
  $el.css({
4462
4574
  'width' : width,
4463
- 'min-width' : '',
4464
- 'max-width' : ''
4575
+ 'min-width' : overflow ? width : '',
4576
+ 'max-width' : overflow ? width : ''
4465
4577
  });
4466
4578
  },
4467
4579
 
4468
4580
  setWidths : function( c, wo, storedSizes ) {
4469
- var column,
4581
+ var column, $temp,
4582
+ vars = wo.resizable_,
4470
4583
  $extra = $( c.namespace + '_extra_headers' ),
4471
4584
  $col = c.$table.children( 'colgroup' ).children( 'col' );
4472
- storedSizes = storedSizes || wo.resizable_.storedSizes || [];
4585
+ storedSizes = storedSizes || vars.storedSizes || [];
4473
4586
  // process only if table ID or url match
4474
4587
  if ( storedSizes.length ) {
4475
4588
  for ( column = 0; column < c.columns; column++ ) {
4476
4589
  // set saved resizable widths
4477
- c.$headerIndexed[ column ].width( storedSizes[ column ] );
4590
+ ts.resizable.setWidth( c.$headerIndexed[ column ], storedSizes[ column ], vars.overflow );
4478
4591
  if ( $extra.length ) {
4479
4592
  // stickyHeaders needs to modify min & max width as well
4480
- ts.resizable.setWidth( $extra.eq( column ).add( $col.eq( column ) ), storedSizes[ column ] );
4593
+ $temp = $extra.eq( column ).add( $col.eq( column ) );
4594
+ ts.resizable.setWidth( $temp, storedSizes[ column ], vars.overflow );
4481
4595
  }
4482
4596
  }
4483
- if ( $( c.namespace + '_extra_table' ).length && !ts.hasWidget( c.table, 'scroller' ) ) {
4484
- ts.resizable.setWidth( $( c.namespace + '_extra_table' ), c.$table.outerWidth() );
4597
+ $temp = $( c.namespace + '_extra_table' );
4598
+ if ( $temp.length && !ts.hasWidget( c.table, 'scroller' ) ) {
4599
+ ts.resizable.setWidth( $temp, c.$table.outerWidth(), vars.overflow );
4485
4600
  }
4486
4601
  }
4487
4602
  },
@@ -4541,7 +4656,7 @@ ts.resizable = {
4541
4656
  var namespace = c.namespace + 'tsresize';
4542
4657
  wo.$resizable_container.children().bind( 'mousedown', function( event ) {
4543
4658
  // save header cell and mouse position
4544
- var column, $this,
4659
+ var column,
4545
4660
  vars = wo.resizable_,
4546
4661
  $extras = $( c.namespace + '_extra_headers' ),
4547
4662
  $header = $( event.target ).data( 'header' );
@@ -4560,11 +4675,7 @@ ts.resizable = {
4560
4675
  vars.next = column;
4561
4676
 
4562
4677
  vars.mouseXPosition = event.pageX;
4563
- vars.storedSizes = [];
4564
- for ( column = 0; column < c.columns; column++ ) {
4565
- $this = c.$headerIndexed[ column ];
4566
- vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0;
4567
- }
4678
+ ts.resizable.updateStoredSizes( c, wo );
4568
4679
  ts.resizable.toggleTextSelection( c, true );
4569
4680
  });
4570
4681
 
@@ -4615,47 +4726,51 @@ ts.resizable = {
4615
4726
  mouseMove : function( c, wo, event ) {
4616
4727
  if ( wo.resizable_.mouseXPosition === 0 || !wo.resizable_.$target ) { return; }
4617
4728
  // resize columns
4618
- var vars = wo.resizable_,
4729
+ var column,
4730
+ total = 0,
4731
+ vars = wo.resizable_,
4619
4732
  $next = vars.$next,
4733
+ tar = vars.storedSizes[ vars.target ],
4620
4734
  leftEdge = event.pageX - vars.mouseXPosition;
4621
- if ( vars.fullWidth ) {
4622
- vars.storedSizes[ vars.target ] += leftEdge;
4623
- vars.storedSizes[ vars.next ] -= leftEdge;
4624
- ts.resizable.setWidths( c, wo );
4625
-
4626
- } else if ( vars.overflow ) {
4627
- c.$table.add( $( c.namespace + '_extra_table' ) ).width(function(i, w){
4628
- return w + leftEdge;
4629
- });
4735
+ if ( vars.overflow ) {
4736
+ if ( tar + leftEdge > 0 ) {
4737
+ vars.storedSizes[ vars.target ] += leftEdge;
4738
+ ts.resizable.setWidth( vars.$target, vars.storedSizes[ vars.target ], true );
4739
+ // update the entire table width
4740
+ for ( column = 0; column < c.columns; column++ ) {
4741
+ total += vars.storedSizes[ column ];
4742
+ }
4743
+ ts.resizable.setWidth( c.$table.add( $( c.namespace + '_extra_table' ) ), total );
4744
+ }
4630
4745
  if ( !$next.length ) {
4631
4746
  // if expanding right-most column, scroll the wrapper
4632
4747
  vars.$wrap[0].scrollLeft = c.$table.width();
4633
4748
  }
4749
+ } else if ( vars.fullWidth ) {
4750
+ vars.storedSizes[ vars.target ] += leftEdge;
4751
+ vars.storedSizes[ vars.next ] -= leftEdge;
4752
+ ts.resizable.setWidths( c, wo );
4634
4753
  } else {
4635
4754
  vars.storedSizes[ vars.target ] += leftEdge;
4636
4755
  ts.resizable.setWidths( c, wo );
4637
4756
  }
4638
4757
  vars.mouseXPosition = event.pageX;
4758
+ // dynamically update sticky header widths
4759
+ c.$table.trigger('stickyHeadersUpdate');
4639
4760
  },
4640
4761
 
4641
4762
  stopResize : function( c, wo ) {
4642
- var $this, column,
4643
- vars = wo.resizable_;
4644
- vars.storedSizes = [];
4645
- if ( ts.storage ) {
4646
- vars.storedSizes = [];
4647
- for ( column = 0; column < c.columns; column++ ) {
4648
- $this = c.$headerIndexed[ column ];
4649
- vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0;
4650
- }
4651
- if ( wo.resizable !== false ) {
4652
- // save all column widths
4653
- ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
4654
- }
4763
+ var vars = wo.resizable_;
4764
+ ts.resizable.updateStoredSizes( c, wo );
4765
+ if ( vars.useStorage ) {
4766
+ // save all column widths
4767
+ ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
4768
+ ts.storage( c.table, 'tablesorter-table-resized-width', c.$table.width() );
4655
4769
  }
4656
4770
  vars.mouseXPosition = 0;
4657
4771
  vars.$target = vars.$next = null;
4658
- $(window).trigger('resize'); // will update stickyHeaders, just in case
4772
+ // will update stickyHeaders, just in case, see #912
4773
+ c.$table.trigger('stickyHeadersUpdate');
4659
4774
  }
4660
4775
  };
4661
4776
 
@@ -4666,11 +4781,12 @@ ts.addWidget({
4666
4781
  id: "resizable",
4667
4782
  priority: 40,
4668
4783
  options: {
4669
- resizable : true,
4784
+ resizable : true, // save column widths to storage
4670
4785
  resizable_addLastColumn : false,
4671
4786
  resizable_widths : [],
4672
4787
  resizable_throttle : false, // set to true (5ms) or any number 0-10 range
4673
- resizable_targetLast : false
4788
+ resizable_targetLast : false,
4789
+ resizable_fullWidth : null
4674
4790
  },
4675
4791
  init: function(table, thisWidget, c, wo) {
4676
4792
  ts.resizable.init( c, wo );
@@ -4694,19 +4810,28 @@ ts.resizableReset = function( table, refreshing ) {
4694
4810
  $( table ).each(function(){
4695
4811
  var index, $t,
4696
4812
  c = this.config,
4697
- wo = c && c.widgetOptions;
4813
+ wo = c && c.widgetOptions,
4814
+ vars = wo.resizable_;
4698
4815
  if ( table && c && c.$headerIndexed.length ) {
4816
+ // restore the initial table width
4817
+ if ( vars.overflow && vars.tableWidth ) {
4818
+ ts.resizable.setWidth( c.$table, vars.tableWidth, true );
4819
+ if ( vars.useStorage ) {
4820
+ ts.storage( table, 'tablesorter-table-resized-width', 'auto' );
4821
+ }
4822
+ }
4699
4823
  for ( index = 0; index < c.columns; index++ ) {
4700
4824
  $t = c.$headerIndexed[ index ];
4701
4825
  if ( wo.resizable_widths && wo.resizable_widths[ index ] ) {
4702
- $t.css( 'width', wo.resizable_widths[ index ] );
4826
+ ts.resizable.setWidth( $t, wo.resizable_widths[ index ], vars.overflow );
4703
4827
  } else if ( !$t.hasClass( 'resizable-false' ) ) {
4704
4828
  // don't clear the width of any column that is not resizable
4705
- $t.css( 'width', '' );
4829
+ ts.resizable.setWidth( $t, '', vars.overflow );
4706
4830
  }
4707
4831
  }
4832
+
4708
4833
  // reset stickyHeader widths
4709
- $( window ).trigger( 'resize' );
4834
+ c.$table.trigger( 'stickyHeadersUpdate' );
4710
4835
  if ( ts.storage && !refreshing ) {
4711
4836
  ts.storage( this, ts.css.resizableStorage, {} );
4712
4837
  }