jquery-tablesorter 1.16.5 → 1.17.0

Sign up to get free protection for your applications and to get access to all the features.
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){