jquery-tablesorter 1.16.5 → 1.17.0

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 (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/jquery-tablesorter/version.rb +1 -1
  4. data/vendor/assets/javascripts/jquery-tablesorter/addons/pager/jquery.tablesorter.pager.js +38 -27
  5. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.combined.js +1104 -839
  6. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +167 -123
  7. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets.js +938 -717
  8. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-date.js +5 -5
  9. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-globalize.js +46 -0
  10. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-input-select.js +96 -72
  11. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-named-numbers.js +6 -5
  12. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-network.js +26 -17
  13. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-columns.js +1 -1
  14. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-editable.js +95 -42
  15. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-filter.js +921 -700
  16. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-grouping.js +5 -3
  17. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-math.js +22 -20
  18. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-output.js +7 -5
  19. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-pager.js +40 -29
  20. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-resizable.js +6 -6
  21. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-saveSort.js +1 -1
  22. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-scroller.js +53 -31
  23. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-stickyHeaders.js +1 -1
  24. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-storage.js +1 -1
  25. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-uitheme.js +1 -1
  26. data/vendor/assets/stylesheets/jquery-tablesorter/theme.black-ice.css +2 -1
  27. data/vendor/assets/stylesheets/jquery-tablesorter/theme.blue.css +2 -1
  28. data/vendor/assets/stylesheets/jquery-tablesorter/theme.bootstrap.css +2 -1
  29. data/vendor/assets/stylesheets/jquery-tablesorter/theme.bootstrap_2.css +8 -6
  30. data/vendor/assets/stylesheets/jquery-tablesorter/theme.dark.css +2 -1
  31. data/vendor/assets/stylesheets/jquery-tablesorter/theme.default.css +1 -1
  32. metadata +3 -2
@@ -1,4 +1,4 @@
1
- /*! TableSorter (FORK) v2.21.5 *//*
1
+ /*! TableSorter (FORK) v2.22.0 *//*
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.21.5';
29
+ ts.version = '2.22.0';
30
30
 
31
31
  ts.parsers = [];
32
32
  ts.widgets = [];
@@ -101,6 +101,11 @@
101
101
  cssNoSort : 'tablesorter-noSort', // class name added to element inside header; clicking on it won't cause a sort
102
102
  cssIgnoreRow : 'tablesorter-ignoreRow', // header row to ignore; cells within this row will not be added to c.$headers
103
103
 
104
+ // *** events
105
+ pointerClick : 'click',
106
+ pointerDown : 'mousedown',
107
+ pointerUp : 'mouseup',
108
+
104
109
  // *** selectors
105
110
  selectorHeaders : '> thead th, > thead td',
106
111
  selectorSort : 'th, td', // jQuery selector of content within selectorHeaders that is clickable to trigger a sort
@@ -185,7 +190,11 @@
185
190
  $node = node.jquery ? node : $(node);
186
191
  if (typeof(t) === 'string') {
187
192
  // check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow!
188
- return $.trim( ( t === 'basic' ? $node.attr(c.textAttribute) || node.textContent : node.textContent ) || $node.text() || '' );
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
+ );
189
198
  } else {
190
199
  if (typeof(t) === 'function') {
191
200
  return $.trim( t($node[0], c.table, cellIndex) );
@@ -194,7 +203,7 @@
194
203
  }
195
204
  }
196
205
  // fallback
197
- return $.trim( $node[0].textContent || $node.text() || '' );
206
+ return $.trim( $node[0].textContent || $node.text() );
198
207
  };
199
208
 
200
209
  function detectParserForColumn(table, rows, rowIndex, cellIndex) {
@@ -228,6 +237,32 @@
228
237
  return ts.getParserById('text');
229
238
  }
230
239
 
240
+ // centralized function to extract/parse cell contents
241
+ function getParsedText( c, cell, colIndex, txt ) {
242
+ if ( typeof txt === 'undefined' ) {
243
+ txt = ts.getElementText( c, cell, colIndex );
244
+ }
245
+ // if no parser, make sure to return the txt
246
+ var val = '' + txt,
247
+ parser = c.parsers[ colIndex ],
248
+ extractor = c.extractors[ colIndex ];
249
+ if ( parser ) {
250
+ // do extract before parsing, if there is one
251
+ if ( extractor && typeof extractor.format === 'function' ) {
252
+ txt = extractor.format( txt, c.table, cell, colIndex );
253
+ }
254
+ // allow parsing if the string is empty, previously parsing would change it to zero,
255
+ // in case the parser needs to extract data from the table cell attributes
256
+ val = parser.id === 'no-parser' ? '' :
257
+ // make sure txt is a string (extractor may have converted it)
258
+ parser.format( '' + txt, c.table, cell, colIndex );
259
+ if ( c.ignoreCase && typeof val === 'string' ) {
260
+ val = val.toLowerCase();
261
+ }
262
+ }
263
+ return val;
264
+ }
265
+
231
266
  function buildParserCache(table) {
232
267
  var c = table.config,
233
268
  // update table bodies in case we start with an empty table
@@ -291,11 +326,10 @@
291
326
 
292
327
  /* utils */
293
328
  function buildCache(table) {
294
- var cc, t, tx, v, i, j, k, $row, cols, cacheTime,
295
- totalRows, rowData, colMax,
329
+ var cc, t, v, i, j, k, $row, cols, cacheTime,
330
+ totalRows, rowData, prevRowData, colMax,
296
331
  c = table.config,
297
332
  $tb = c.$tbodies,
298
- extractors = c.extractors,
299
333
  parsers = c.parsers;
300
334
  c.cache = {};
301
335
  c.totalRows = 0;
@@ -326,62 +360,61 @@
326
360
  raw: [] // original row text
327
361
  };
328
362
  /** Add the table data to main data array */
329
- $row = $($tb[k].rows[i]);
363
+ $row = $( $tb[ k ].rows[ i ] );
330
364
  cols = [];
331
365
  // if this is a child row, add it to the last row's children and continue to the next row
332
366
  // ignore child row class, if it is the first row
333
- if ($row.hasClass(c.cssChildRow) && i !== 0) {
367
+ if ( $row.hasClass( c.cssChildRow ) && i !== 0 ) {
334
368
  t = cc.normalized.length - 1;
335
- cc.normalized[t][c.columns].$row = cc.normalized[t][c.columns].$row.add($row);
369
+ prevRowData = cc.normalized[ t ][ c.columns ];
370
+ prevRowData.$row = prevRowData.$row.add( $row );
336
371
  // add 'hasChild' class name to parent row
337
- if (!$row.prev().hasClass(c.cssChildRow)) {
338
- $row.prev().addClass(ts.css.cssHasChild);
372
+ if ( !$row.prev().hasClass( c.cssChildRow ) ) {
373
+ $row.prev().addClass( ts.css.cssHasChild );
339
374
  }
340
375
  // save child row content (un-parsed!)
341
- rowData.child[t] = $.trim( $row[0].textContent || $row.text() || '' );
376
+ v = $row.children( 'th, td' );
377
+ t = prevRowData.child.length;
378
+ prevRowData.child[ t ] = [];
379
+ // child row content does not account for colspans/rowspans; so indexing may be off
380
+ for ( j = 0; j < c.columns; j++ ) {
381
+ prevRowData.child[ t ][ j ] = getParsedText( c, v[ j ], j );
382
+ }
342
383
  // go to the next for loop
343
384
  continue;
344
385
  }
345
386
  rowData.$row = $row;
346
387
  rowData.order = i; // add original row position to rowCache
347
- for (j = 0; j < c.columns; ++j) {
348
- if (typeof parsers[j] === 'undefined') {
349
- if (c.debug) {
350
- log('No parser found for cell:', $row[0].cells[j], 'does it have a header?');
388
+ for ( j = 0; j < c.columns; ++j ) {
389
+ if (typeof parsers[ j ] === 'undefined') {
390
+ if ( c.debug ) {
391
+ log( 'No parser found for cell:', $row[ 0 ].cells[ j ], 'does it have a header?' );
351
392
  }
352
393
  continue;
353
394
  }
354
- t = ts.getElementText(c, $row[0].cells[j], j);
355
- rowData.raw.push(t); // save original row text
356
- // do extract before parsing if there is one
357
- if (typeof extractors[j].id === 'undefined') {
358
- tx = t;
359
- } else {
360
- tx = extractors[j].format(t, table, $row[0].cells[j], j);
361
- }
362
- // allow parsing if the string is empty, previously parsing would change it to zero,
363
- // in case the parser needs to extract data from the table cell attributes
364
- v = parsers[j].id === 'no-parser' ? '' : parsers[j].format(tx, table, $row[0].cells[j], j);
365
- cols.push( c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v );
366
- if ((parsers[j].type || '').toLowerCase() === 'numeric') {
395
+ t = ts.getElementText( c, $row[ 0 ].cells[j], j );
396
+ rowData.raw.push( t ); // save original row text
397
+ v = getParsedText( c, $row[ 0 ].cells[ j ], j, t );
398
+ cols.push( v );
399
+ if ( ( parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) {
367
400
  // determine column max value (ignore sign)
368
- colMax[j] = Math.max(Math.abs(v) || 0, colMax[j] || 0);
401
+ colMax[ j ] = Math.max( Math.abs( v ) || 0, colMax[ j ] || 0 );
369
402
  }
370
403
  }
371
404
  // ensure rowData is always in the same location (after the last column)
372
- cols[c.columns] = rowData;
373
- cc.normalized.push(cols);
405
+ cols[ c.columns ] = rowData;
406
+ cc.normalized.push( cols );
374
407
  }
375
408
  cc.colMax = colMax;
376
409
  // total up rows, not including child rows
377
410
  c.totalRows += cc.normalized.length;
378
411
 
379
412
  }
380
- if (c.showProcessing) {
381
- ts.isProcessing(table); // remove processing icon
413
+ if ( c.showProcessing ) {
414
+ ts.isProcessing( table ); // remove processing icon
382
415
  }
383
- if (c.debug) {
384
- benchmark('Building cache for ' + totalRows + ' rows', cacheTime);
416
+ if ( c.debug ) {
417
+ benchmark( 'Building cache for ' + totalRows + ' rows', cacheTime );
385
418
  }
386
419
  }
387
420
 
@@ -521,14 +554,15 @@
521
554
  }
522
555
 
523
556
  function updateHeader(table) {
524
- var s, $th, col,
525
- c = table.config;
526
- c.$headers.each(function(index, th){
527
- $th = $(th);
557
+ var index, s, $th, col,
558
+ c = table.config,
559
+ len = c.$headers.length;
560
+ for ( index = 0; index < len; index++ ) {
561
+ $th = c.$headers.eq( index );
528
562
  col = ts.getColumnData( table, c.headers, index, true );
529
563
  // add 'sorter-false' class if 'parser-false' is set
530
- s = ts.getData( th, col, 'sorter' ) === 'false' || ts.getData( th, col, 'parser' ) === 'false';
531
- th.sortDisabled = s;
564
+ s = ts.getData( $th, col, 'sorter' ) === 'false' || ts.getData( $th, col, 'parser' ) === 'false';
565
+ $th[0].sortDisabled = s;
532
566
  $th[ s ? 'addClass' : 'removeClass' ]('sorter-false').attr('aria-disabled', '' + s);
533
567
  // aria-controls - requires table ID
534
568
  if (table.id) {
@@ -538,11 +572,11 @@
538
572
  $th.attr('aria-controls', table.id);
539
573
  }
540
574
  }
541
- });
575
+ }
542
576
  }
543
577
 
544
578
  function setHeadersCss(table) {
545
- var f, i, j,
579
+ var f, h, i, j, $headers, $h, nextSort, txt,
546
580
  c = table.config,
547
581
  list = c.sortList,
548
582
  len = list.length,
@@ -586,14 +620,19 @@
586
620
  }
587
621
  }
588
622
  // add verbose aria labels
589
- c.$headers.not('.sorter-false').each(function(){
590
- var $this = $(this),
591
- nextSort = this.order[(this.count + 1) % (c.sortReset ? 3 : 2)],
592
- txt = $.trim( $this.text() ) + ': ' +
593
- ts.language[ $this.hasClass(ts.css.sortAsc) ? 'sortAsc' : $this.hasClass(ts.css.sortDesc) ? 'sortDesc' : 'sortNone' ] +
623
+ len = c.$headers.length;
624
+ $headers = c.$headers.not('.sorter-false');
625
+ for ( i = 0; i < len; i++ ) {
626
+ $h = $headers.eq( i );
627
+ if ( $h.length ) {
628
+ h = $headers[ i ];
629
+ nextSort = h.order[ ( h.count + 1 ) % ( c.sortReset ? 3 : 2 ) ],
630
+ txt = $.trim( $h.text() ) + ': ' +
631
+ ts.language[ $h.hasClass( ts.css.sortAsc ) ? 'sortAsc' : $h.hasClass( ts.css.sortDesc ) ? 'sortDesc' : 'sortNone' ] +
594
632
  ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ];
595
- $this.attr('aria-label', txt );
596
- });
633
+ $h.attr( 'aria-label', txt );
634
+ }
635
+ }
597
636
  }
598
637
 
599
638
  function updateHeaderSortCount( table, list ) {
@@ -606,9 +645,10 @@
606
645
  val = sortList[indx];
607
646
  // ensure all sortList values are numeric - fixes #127
608
647
  col = parseInt(val[0], 10);
609
- // make sure header exists
610
- header = c.$headerIndexed[col][0];
611
- if (header) { // prevents error if sorton array is wrong
648
+ // prevents error if sorton array is wrong
649
+ if ( col < c.columns && c.$headerIndexed[col] ) {
650
+ // make sure header exists
651
+ header = c.$headerIndexed[col][0];
612
652
  // o.count = o.count + 1;
613
653
  dir = ('' + val[1]).match(/^(1|d|s|o|n)/);
614
654
  dir = dir ? dir[0] : '';
@@ -652,10 +692,11 @@
652
692
  // let any updates complete before initializing a sort
653
693
  return setTimeout(function(){ initSort(table, cell, event); }, 50);
654
694
  }
655
- var arry, indx, col, order, s,
695
+ var arry, indx, i, col, order, s, $header,
656
696
  c = table.config,
657
697
  key = !event[c.sortMultiSortKey],
658
- $table = c.$table;
698
+ $table = c.$table,
699
+ len = c.$headers.length;
659
700
  // Only call sortStart if sorting is enabled
660
701
  $table.trigger('sortStart', table);
661
702
  // get current column sort order
@@ -663,12 +704,13 @@
663
704
  // reset all sorts on non-current column - issue #30
664
705
  if (c.sortRestart) {
665
706
  indx = cell;
666
- c.$headers.each(function() {
707
+ for ( i = 0; i < len; i++ ) {
708
+ $header = c.$headers.eq( i );
667
709
  // only reset counts on columns that weren't just clicked on and if not included in a multisort
668
- if (this !== indx && (key || !$(this).is('.' + ts.css.sortDesc + ',.' + ts.css.sortAsc))) {
669
- this.count = -1;
710
+ if ( $header[0] !== indx && ( key || !$header.is('.' + ts.css.sortDesc + ',.' + ts.css.sortAsc) ) ) {
711
+ $header[0].count = -1;
670
712
  }
671
- });
713
+ }
672
714
  }
673
715
  // get current column index
674
716
  indx = parseInt( $(cell).attr('data-column'), 10 );
@@ -894,35 +936,31 @@
894
936
  table.isUpdating = true;
895
937
  $table.find(c.selectorRemove).remove();
896
938
  // get position from the dom
897
- var v, t, row, icell,
939
+ var t, row, icell, cache,
898
940
  $tb = c.$tbodies,
899
941
  $cell = $(cell),
900
942
  // update cache - format: function(s, table, cell, cellIndex)
901
943
  // no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr');
902
944
  tbdy = $tb.index( $.fn.closest ? $cell.closest('tbody') : $cell.parents('tbody').filter(':first') ),
945
+ tbcache = c.cache[ tbdy ],
903
946
  $row = $.fn.closest ? $cell.closest('tr') : $cell.parents('tr').filter(':first');
904
947
  cell = $cell[0]; // in case cell is a jQuery object
905
948
  // tbody may not exist if update is initialized while tbody is removed for processing
906
949
  if ($tb.length && tbdy >= 0) {
907
- row = $tb.eq(tbdy).find('tr').index( $row );
950
+ row = $tb.eq( tbdy ).find( 'tr' ).index( $row );
951
+ cache = tbcache.normalized[ row ];
908
952
  icell = $cell.index();
909
- c.cache[tbdy].normalized[row][c.columns].$row = $row;
910
- if (typeof c.extractors[icell].id === 'undefined') {
911
- t = ts.getElementText(c, cell, icell);
912
- } else {
913
- t = c.extractors[icell].format( ts.getElementText(c, cell, icell), table, cell, icell );
914
- }
915
- v = c.parsers[icell].id === 'no-parser' ? '' :
916
- c.parsers[icell].format( t, table, cell, icell );
917
- c.cache[tbdy].normalized[row][icell] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
918
- if ((c.parsers[icell].type || '').toLowerCase() === 'numeric') {
953
+ t = getParsedText( c, cell, icell );
954
+ cache[ icell ] = t;
955
+ cache[ c.columns ].$row = $row;
956
+ if ( (c.parsers[icell].type || '').toLowerCase() === 'numeric' ) {
919
957
  // update column max value (ignore sign)
920
- c.cache[tbdy].colMax[icell] = Math.max(Math.abs(v) || 0, c.cache[tbdy].colMax[icell] || 0);
958
+ tbcache.colMax[icell] = Math.max(Math.abs(t) || 0, tbcache.colMax[icell] || 0);
921
959
  }
922
- v = resort !== 'undefined' ? resort : c.resort;
923
- if (v !== false) {
960
+ t = resort !== 'undefined' ? resort : c.resort;
961
+ if (t !== false) {
924
962
  // widgets will be reapplied
925
- checkResort(c, v, callback);
963
+ checkResort(c, t, callback);
926
964
  } else {
927
965
  // don't reapply widgets is resort is false, just in case it causes
928
966
  // problems with element focus
@@ -942,7 +980,7 @@
942
980
  commonUpdate(table, resort, callback);
943
981
  } else {
944
982
  $row = $($row).attr('role', 'row'); // make sure we're using a jQuery object
945
- var i, j, l, t, v, rowData, cells,
983
+ var i, j, l, rowData, cells,
946
984
  rows = $row.filter('tr').length,
947
985
  tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') );
948
986
  // fixes adding rows to an empty table - see issue #179
@@ -960,14 +998,7 @@
960
998
  };
961
999
  // add each cell
962
1000
  for (j = 0; j < l; j++) {
963
- if (typeof c.extractors[j].id === 'undefined') {
964
- t = ts.getElementText(c, $row[i].cells[j], j);
965
- } else {
966
- t = c.extractors[j].format( ts.getElementText(c, $row[i].cells[j], j), table, $row[i].cells[j], j );
967
- }
968
- v = c.parsers[j].id === 'no-parser' ? '' :
969
- c.parsers[j].format( t, table, $row[i].cells[j], j );
970
- cells[j] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
1001
+ cells[j] = getParsedText( c, $row[i].cells[j], j );
971
1002
  if ((c.parsers[j].type || '').toLowerCase() === 'numeric') {
972
1003
  // update column max value (ignore sign)
973
1004
  c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0);
@@ -1195,7 +1226,7 @@
1195
1226
  // automatically add a colgroup with col elements set to a percentage width
1196
1227
  ts.fixColumnWidth = function(table) {
1197
1228
  table = $(table)[0];
1198
- var overallWidth, percent,
1229
+ var overallWidth, percent, $tbodies, len, index,
1199
1230
  c = table.config,
1200
1231
  colgroup = c.$table.children('colgroup');
1201
1232
  // remove plugin-added colgroup, in case we need to refresh the widths
@@ -1206,10 +1237,12 @@
1206
1237
  colgroup = $('<colgroup class="' + ts.css.colgroup + '">');
1207
1238
  overallWidth = c.$table.width();
1208
1239
  // only add col for visible columns - fixes #371
1209
- c.$tbodies.find('tr:first').children(':visible').each(function() {
1210
- percent = parseInt( ( $(this).width() / overallWidth ) * 1000, 10 ) / 10 + '%';
1240
+ $tbodies = c.$tbodies.find('tr:first').children(':visible'); //.each(function()
1241
+ len = $tbodies.length;
1242
+ for ( index = 0; index < len; index++ ) {
1243
+ percent = parseInt( ( $tbodies.eq( index ).width() / overallWidth ) * 1000, 10 ) / 10 + '%';
1211
1244
  colgroup.append( $('<col>').css('width', percent) );
1212
- });
1245
+ }
1213
1246
  c.$table.prepend(colgroup);
1214
1247
  }
1215
1248
  };
@@ -1244,9 +1277,10 @@
1244
1277
  // http://www.javascripttoolbox.com/lib/table/examples.php
1245
1278
  // http://www.javascripttoolbox.com/temp/table_cellindex.html
1246
1279
  ts.computeColumnIndex = function(trs) {
1247
- var matrix = [],
1248
- lookup = {},
1249
- i, j, k, l, $cell, cell, cells, rowIndex, cellId, rowSpan, colSpan, firstAvailCol, matrixrow;
1280
+ var i, j, k, l, $cell, cell, cells, rowIndex, cellId, rowSpan, colSpan, firstAvailCol,
1281
+ matrix = [],
1282
+ matrixrow = [],
1283
+ lookup = {};
1250
1284
  for (i = 0; i < trs.length; i++) {
1251
1285
  cells = trs[i].cells;
1252
1286
  for (j = 0; j < cells.length; j++) {
@@ -1326,7 +1360,7 @@
1326
1360
  $(table)[0].config.$tbodies.children().detach();
1327
1361
  };
1328
1362
 
1329
- ts.bindEvents = function(table, $headers, core){
1363
+ ts.bindEvents = function(table, $headers, core) {
1330
1364
  table = $(table)[0];
1331
1365
  var t, downTarget = null,
1332
1366
  c = table.config;
@@ -1337,28 +1371,35 @@
1337
1371
  $(t).addClass( c.namespace.slice(1) + '_extra_table' );
1338
1372
  }
1339
1373
  }
1374
+ t = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' )
1375
+ .replace(/\s+/g, ' ')
1376
+ .split(' ')
1377
+ .join(c.namespace + ' ');
1340
1378
  // apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)
1341
1379
  $headers
1342
1380
  // http://stackoverflow.com/questions/5312849/jquery-find-self;
1343
1381
  .find(c.selectorSort).add( $headers.filter(c.selectorSort) )
1344
- .unbind( ('mousedown mouseup click sort keyup '.split(' ').join(c.namespace + ' ')).replace(/\s+/g, ' ') )
1345
- .bind( 'mousedown mouseup click sort keyup '.split(' ').join(c.namespace + ' '), function(e, external) {
1382
+ .unbind(t)
1383
+ .bind(t, function(e, external) {
1346
1384
  var cell,
1347
1385
  $target = $(e.target),
1348
- type = e.type;
1386
+ // wrap event type in spaces, so the match doesn't trigger on inner words
1387
+ type = ' ' + e.type + ' ';
1349
1388
  // only recognize left clicks
1350
- if ( ( ( e.which || e.button ) !== 1 && !/sort|keyup|click/.test(type) ) ||
1389
+ if ( ( ( e.which || e.button ) !== 1 && !type.match( ' ' + c.pointerClick + ' | sort | keyup ' ) ) ||
1351
1390
  // allow pressing enter
1352
- ( type === 'keyup' && e.which !== 13 ) ||
1391
+ ( type === ' keyup ' && e.which !== 13 ) ||
1353
1392
  // allow triggering a click event (e.which is undefined) & ignore physical clicks
1354
- ( type === 'click' && typeof e.which !== 'undefined' ) ) {
1393
+ ( type.match(' ' + c.pointerClick + ' ') && typeof e.which !== 'undefined' ) ) {
1355
1394
  return;
1356
1395
  }
1357
1396
  // ignore mouseup if mousedown wasn't on the same target
1358
- if ( type === 'mouseup' && downTarget !== e.target && external !== true ) { return; }
1397
+ if ( type.match(' ' + c.pointerUp + ' ') && downTarget !== e.target && external !== true ) { return; }
1359
1398
  // set timer on mousedown
1360
- if ( type === 'mousedown' ) {
1399
+ if ( type.match(' ' + c.pointerDown + ' ') ) {
1361
1400
  downTarget = e.target;
1401
+ // needed or jQuery v1.2.6 throws an error
1402
+ e.preventDefault();
1362
1403
  return;
1363
1404
  }
1364
1405
  downTarget = null;
@@ -1393,17 +1434,20 @@
1393
1434
 
1394
1435
  // restore headers
1395
1436
  ts.restoreHeaders = function(table){
1396
- var $cell,
1397
- c = $(table)[0].config;
1437
+ var index, $cell,
1438
+ c = $(table)[0].config,
1439
+ $headers = c.$table.find( c.selectorHeaders ),
1440
+ len = $headers.length;
1398
1441
  // don't use c.$headers here in case header cells were swapped
1399
- c.$table.find(c.selectorHeaders).each(function(i){
1400
- $cell = $(this);
1442
+ for ( index = 0; index < len; index++ ) {
1443
+ // c.$table.find(c.selectorHeaders).each(function(i){
1444
+ $cell = $headers.eq( index );
1401
1445
  // only restore header cells if it is wrapped
1402
1446
  // because this is also used by the updateAll method
1403
- if ($cell.find('.' + ts.css.headerIn).length){
1404
- $cell.html( c.headerContent[i] );
1447
+ if ( $cell.find( '.' + ts.css.headerIn ).length ) {
1448
+ $cell.html( c.headerContent[ index ] );
1405
1449
  }
1406
- });
1450
+ }
1407
1451
  };
1408
1452
 
1409
1453
  ts.destroy = function(table, removeClasses, callback){
@@ -1563,8 +1607,8 @@
1563
1607
  'E' : '\u00c9\u00c8\u00ca\u00cb\u011a\u0118', // ÉÈÊËĚĘ
1564
1608
  'i' : '\u00ed\u00ec\u0130\u00ee\u00ef\u0131', // íìİîïı
1565
1609
  'I' : '\u00cd\u00cc\u0130\u00ce\u00cf', // ÍÌİÎÏ
1566
- 'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6', // óòôõö
1567
- 'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6', // ÓÒÔÕÖ
1610
+ 'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6\u014d', // óòôõöō
1611
+ 'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6\u014c', // ÓÒÔÕÖŌ
1568
1612
  'ss': '\u00df', // ß (s sharp)
1569
1613
  'SS': '\u1e9e', // ẞ (Capital sharp s)
1570
1614
  'u' : '\u00fa\u00f9\u00fb\u00fc\u016f', // úùûüů
@@ -1904,7 +1948,7 @@
1904
1948
 
1905
1949
  ts.isDigit = function(s) {
1906
1950
  // replace all unwanted chars and match
1907
- return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : true;
1951
+ return isNaN(s) ? (/^[\-+(]?\d+[)]?$/).test(s.toString().replace(/[,.'"\s]/g, '')) : s !== '';
1908
1952
  };
1909
1953
 
1910
1954
  }()
@@ -2090,7 +2134,7 @@
2090
2134
  id: 'zebra',
2091
2135
  priority: 90,
2092
2136
  format: function(table, c, wo) {
2093
- var $tb, $tv, $tr, row, even, time, k,
2137
+ var $tv, $tr, row, even, time, k, i, len,
2094
2138
  child = new RegExp(c.cssChildRow, 'i'),
2095
2139
  b = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody' ) );
2096
2140
  if (c.debug) {
@@ -2099,17 +2143,17 @@
2099
2143
  for (k = 0; k < b.length; k++ ) {
2100
2144
  // loop through the visible rows
2101
2145
  row = 0;
2102
- $tb = b.eq(k);
2103
- $tv = $tb.children('tr:visible').not(c.selectorRemove);
2104
- // revered back to using jQuery each - strangely it's the fastest method
2105
- /*jshint loopfunc:true */
2106
- $tv.each(function(){
2107
- $tr = $(this);
2146
+ $tv = b.eq( k ).children( 'tr:visible' ).not( c.selectorRemove );
2147
+ len = $tv.length;
2148
+ for ( i = 0; i < len; i++ ) {
2149
+ $tr = $tv.eq( i );
2108
2150
  // style child rows the same way the parent row was styled
2109
- if (!child.test(this.className)) { row++; }
2110
- even = (row % 2 === 0);
2111
- $tr.removeClass(wo.zebra[even ? 1 : 0]).addClass(wo.zebra[even ? 0 : 1]);
2112
- });
2151
+ if ( !child.test( $tr[0].className ) ) { row++; }
2152
+ even = ( row % 2 === 0 );
2153
+ $tr
2154
+ .removeClass( wo.zebra[ even ? 1 : 0 ] )
2155
+ .addClass( wo.zebra[ even ? 0 : 1 ] );
2156
+ }
2113
2157
  }
2114
2158
  },
2115
2159
  remove: function(table, c, wo, refreshing){