jquery-tablesorter 1.17.4 → 1.18.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- /*! TableSorter (FORK) v2.22.5 *//*
1
+ /*! TableSorter (FORK) v2.23.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.22.5';
29
+ ts.version = '2.23.0';
30
30
 
31
31
  ts.parsers = [];
32
32
  ts.widgets = [];
@@ -155,13 +155,13 @@
155
155
  ts.instanceMethods = {};
156
156
 
157
157
  // $.isEmptyObject from jQuery v1.4
158
- function isEmptyObject(obj) {
158
+ ts.isEmptyObject = function( obj ) {
159
159
  /*jshint forin: false */
160
- for (var name in obj) {
160
+ for ( var name in obj ) {
161
161
  return false;
162
162
  }
163
163
  return true;
164
- }
164
+ };
165
165
 
166
166
  ts.getElementText = function(c, node, cellIndex) {
167
167
  if (!node) { return ''; }
@@ -304,7 +304,7 @@
304
304
  j += (list.parsers.length) ? len : 1;
305
305
  }
306
306
  if ( c.debug ) {
307
- if ( !isEmptyObject( debug ) ) {
307
+ if ( !ts.isEmptyObject( debug ) ) {
308
308
  console[ console.table ? 'table' : 'log' ]( debug );
309
309
  } else {
310
310
  console.warn( ' No parsers detected!' );
@@ -317,7 +317,7 @@
317
317
  }
318
318
 
319
319
  /* utils */
320
- function buildCache(table, $tbodies) {
320
+ function buildCache(table, callback, $tbodies) {
321
321
  var cc, t, v, i, j, k, $tb, $row, cols, cacheTime,
322
322
  totalRows, rowData, prevRowData, colMax,
323
323
  c = table.config,
@@ -410,54 +410,8 @@
410
410
  if ( c.debug ) {
411
411
  console.log( 'Building cache for ' + totalRows + ' rows' + ts.benchmark( cacheTime ) );
412
412
  }
413
- }
414
-
415
- // init flag (true) used by pager plugin to prevent widget application
416
- function appendToTable(table, init) {
417
- var c = table.config,
418
- wo = c.widgetOptions,
419
- $tbodies = c.$tbodies,
420
- rows = [],
421
- cc = c.cache,
422
- n, totalRows, $bk, $tb,
423
- i, k, appendTime;
424
- // empty table - fixes #206/#346
425
- if (isEmptyObject(cc)) {
426
- // run pager appender in case the table was just emptied
427
- return c.appender ? c.appender(table, rows) :
428
- table.isUpdating ? c.$table.trigger('updateComplete', table) : ''; // Fixes #532
429
- }
430
- if (c.debug) {
431
- appendTime = new Date();
432
- }
433
- for (k = 0; k < $tbodies.length; k++) {
434
- $bk = $tbodies.eq(k);
435
- if ($bk.length) {
436
- // get tbody
437
- $tb = ts.processTbody(table, $bk, true);
438
- n = cc[k].normalized;
439
- totalRows = n.length;
440
- for (i = 0; i < totalRows; i++) {
441
- rows.push(n[i][c.columns].$row);
442
- // removeRows used by the pager plugin; don't render if using ajax - fixes #411
443
- if (!c.appender || (c.pager && (!c.pager.removeRows || !wo.pager_removeRows) && !c.pager.ajax)) {
444
- $tb.append(n[i][c.columns].$row);
445
- }
446
- }
447
- // restore tbody
448
- ts.processTbody(table, $tb, false);
449
- }
450
- }
451
- if (c.appender) {
452
- c.appender(table, rows);
453
- }
454
- if (c.debug) {
455
- console.log( 'Rebuilt table' + ts.benchmark(appendTime) );
456
- }
457
- // apply table widgets; but not before ajax completes
458
- if (!init && !c.appender) { ts.applyWidget(table); }
459
- if (table.isUpdating) {
460
- c.$table.trigger('updateComplete', table);
413
+ if ( $.isFunction( callback ) ) {
414
+ callback( table );
461
415
  }
462
416
  }
463
417
 
@@ -466,9 +420,8 @@
466
420
  return (/^d/i.test(v) || v === 1);
467
421
  }
468
422
 
469
- function buildHeaders(table) {
470
- var ch, $t, h, i, t, lock, time, indx,
471
- c = table.config;
423
+ function buildHeaders( c ) {
424
+ var ch, $t, h, i, t, lock, time, indx;
472
425
  c.headerList = [];
473
426
  c.headerContent = [];
474
427
  if (c.debug) {
@@ -479,12 +432,12 @@
479
432
  // add icon if cssIcon option exists
480
433
  i = c.cssIcon ? '<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' : '';
481
434
  // redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683
482
- c.$headers = $( $.map( $(table).find(c.selectorHeaders), function(elem, index) {
435
+ c.$headers = $( $.map( c.$table.find(c.selectorHeaders), function(elem, index) {
483
436
  $t = $(elem);
484
437
  // ignore cell (don't add it to c.$headers) if row has ignoreRow class
485
438
  if ($t.parent().hasClass(c.cssIgnoreRow)) { return; }
486
439
  // make sure to get header cell & not column indexed cell
487
- ch = ts.getColumnData( table, c.headers, index, true );
440
+ ch = ts.getColumnData( c.table, c.headers, index, true );
488
441
  // save original header content
489
442
  c.headerContent[index] = $t.html();
490
443
  // if headerTemplate is empty, don't reformat the header cell
@@ -526,12 +479,12 @@
526
479
  // .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6
527
480
  c.$headerIndexed[indx] = $t.not('.sorter-false').length ? $t.not('.sorter-false').filter(':last') : $t.filter(':last');
528
481
  }
529
- $(table).find(c.selectorHeaders).attr({
482
+ c.$table.find(c.selectorHeaders).attr({
530
483
  scope: 'col',
531
484
  role : 'columnheader'
532
485
  });
533
486
  // enable/disable sorting
534
- updateHeader(table);
487
+ updateHeader(c.table);
535
488
  if (c.debug) {
536
489
  console.log( 'Built headers:' + ts.benchmark( time ) );
537
490
  console.log( c.$headers );
@@ -788,7 +741,7 @@
788
741
  // set css for headers
789
742
  setHeadersCss(table);
790
743
  multisort(table);
791
- appendToTable(table);
744
+ ts.appendCache( c );
792
745
  $table.trigger('sortEnd', table);
793
746
  }, 1);
794
747
  }
@@ -803,7 +756,7 @@
803
756
  sortList = c.sortList,
804
757
  l = sortList.length,
805
758
  bl = c.$tbodies.length;
806
- if (c.serverSideSorting || isEmptyObject(c.cache)) { // empty table - fixes #206/#346
759
+ if (c.serverSideSorting || ts.isEmptyObject(c.cache)) { // empty table - fixes #206/#346
807
760
  return;
808
761
  }
809
762
  if (c.debug) { sortTime = new Date(); }
@@ -894,188 +847,84 @@
894
847
  }
895
848
  }
896
849
 
897
- function bindMethods(table){
850
+ function bindMethods( table ){
898
851
  var c = table.config,
899
852
  $table = c.$table,
900
- events = ('sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache ' +
901
- 'updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ').split(' ')
902
- .join(c.namespace + ' ');
853
+ events = ( 'sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete ' +
854
+ 'sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup ' +
855
+ 'mouseleave ' ).split( ' ' )
856
+ .join( c.namespace + ' ' );
903
857
  // apply easy methods that trigger bound events
904
858
  $table
905
- .unbind( events.replace(/\s+/g, ' ') )
906
- .bind('sortReset' + c.namespace, function(e, callback){
859
+ .unbind( events.replace( /\s+/g, ' ' ) )
860
+ .bind( 'sortReset' + c.namespace, function( e, callback ) {
907
861
  e.stopPropagation();
908
- c.sortList = [];
909
- setHeadersCss(table);
910
- multisort(table);
911
- appendToTable(table);
912
- if ($.isFunction(callback)) {
913
- callback(table);
914
- }
862
+ // using this.config to ensure functions are getting a non-cached version of the config
863
+ ts.sortReset( this.config, callback );
915
864
  })
916
- .bind('updateAll' + c.namespace, function(e, resort, callback){
865
+ .bind( 'updateAll' + c.namespace, function( e, resort, callback ) {
917
866
  e.stopPropagation();
918
- table.isUpdating = true;
919
- ts.refreshWidgets(table, true, true);
920
- buildHeaders(table);
921
- ts.bindEvents(table, c.$headers, true);
922
- bindMethods(table);
923
- commonUpdate(table, resort, callback);
867
+ ts.updateAll( this.config, resort, callback );
924
868
  })
925
- .bind('update' + c.namespace + ' updateRows' + c.namespace, function(e, resort, callback) {
869
+ .bind( 'update' + c.namespace + ' updateRows' + c.namespace, function( e, resort, callback ) {
926
870
  e.stopPropagation();
927
- table.isUpdating = true;
928
- // update sorting (if enabled/disabled)
929
- updateHeader(table);
930
- commonUpdate(table, resort, callback);
871
+ ts.update( this.config, resort, callback );
931
872
  })
932
- .bind('updateCell' + c.namespace, function(e, cell, resort, callback) {
873
+ .bind( 'updateHeaders' + c.namespace, function( e, callback ) {
933
874
  e.stopPropagation();
934
- table.isUpdating = true;
935
- $table.find(c.selectorRemove).remove();
936
- // get position from the dom
937
- var t, row, icell, cache,
938
- $tb = c.$tbodies,
939
- $cell = $(cell),
940
- // update cache - format: function(s, table, cell, cellIndex)
941
- // no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr');
942
- tbdy = $tb.index( $.fn.closest ? $cell.closest('tbody') : $cell.parents('tbody').filter(':first') ),
943
- tbcache = c.cache[ tbdy ],
944
- $row = $.fn.closest ? $cell.closest('tr') : $cell.parents('tr').filter(':first');
945
- cell = $cell[0]; // in case cell is a jQuery object
946
- // tbody may not exist if update is initialized while tbody is removed for processing
947
- if ($tb.length && tbdy >= 0) {
948
- row = $tb.eq( tbdy ).find( 'tr' ).index( $row );
949
- cache = tbcache.normalized[ row ];
950
- icell = $cell.index();
951
- t = ts.getParsedText( c, cell, icell );
952
- cache[ icell ] = t;
953
- cache[ c.columns ].$row = $row;
954
- if ( (c.parsers[icell].type || '').toLowerCase() === 'numeric' ) {
955
- // update column max value (ignore sign)
956
- tbcache.colMax[icell] = Math.max(Math.abs(t) || 0, tbcache.colMax[icell] || 0);
957
- }
958
- t = resort !== 'undefined' ? resort : c.resort;
959
- if (t !== false) {
960
- // widgets will be reapplied
961
- checkResort(c, t, callback);
962
- } else {
963
- // don't reapply widgets is resort is false, just in case it causes
964
- // problems with element focus
965
- if ($.isFunction(callback)) {
966
- callback(table);
967
- }
968
- c.$table.trigger('updateComplete', c.table);
969
- }
970
- }
875
+ ts.updateHeaders( this.config, callback );
971
876
  })
972
- .bind('addRows' + c.namespace, function(e, $row, resort, callback) {
877
+ .bind( 'updateCell' + c.namespace, function(e, cell, resort, callback ) {
973
878
  e.stopPropagation();
974
- table.isUpdating = true;
975
- if (isEmptyObject(c.cache)) {
976
- // empty table, do an update instead - fixes #450
977
- updateHeader(table);
978
- commonUpdate(table, resort, callback);
979
- } else {
980
- $row = $($row).attr('role', 'row'); // make sure we're using a jQuery object
981
- var i, j, l, rowData, cells,
982
- rows = $row.filter('tr').length,
983
- tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') );
984
- // fixes adding rows to an empty table - see issue #179
985
- if (!(c.parsers && c.parsers.length)) {
986
- buildParserCache(c);
987
- }
988
- // add each row
989
- for (i = 0; i < rows; i++) {
990
- l = $row[i].cells.length;
991
- cells = [];
992
- rowData = {
993
- child: [],
994
- $row : $row.eq(i),
995
- order: c.cache[tbdy].normalized.length
996
- };
997
- // add each cell
998
- for (j = 0; j < l; j++) {
999
- cells[j] = ts.getParsedText( c, $row[i].cells[j], j );
1000
- if ((c.parsers[j].type || '').toLowerCase() === 'numeric') {
1001
- // update column max value (ignore sign)
1002
- c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0);
1003
- }
1004
- }
1005
- // add the row data to the end
1006
- cells.push(rowData);
1007
- // update cache
1008
- c.cache[tbdy].normalized.push(cells);
1009
- }
1010
- // resort using current settings
1011
- checkResort(c, resort, callback);
1012
- }
879
+ ts.updateCell( this.config, cell, resort, callback );
1013
880
  })
1014
- .bind('updateComplete' + c.namespace, function(){
881
+ .bind( 'addRows' + c.namespace, function(e, $row, resort, callback) {
882
+ e.stopPropagation();
883
+ ts.addRows( this.config, $row, resort, callback );
884
+ })
885
+ .bind( 'updateComplete' + c.namespace, function() {
1015
886
  table.isUpdating = false;
1016
887
  })
1017
- .bind('sorton' + c.namespace, function(e, list, callback, init) {
1018
- var c = table.config;
888
+ .bind( 'sorton' + c.namespace, function( e, list, callback, init ) {
1019
889
  e.stopPropagation();
1020
- $table.trigger('sortStart', this);
1021
- // update header count index
1022
- updateHeaderSortCount(table, list);
1023
- // set css for headers
1024
- setHeadersCss(table);
1025
- // fixes #346
1026
- if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); }
1027
- $table.trigger('sortBegin', this);
1028
- // sort the table and append it to the dom
1029
- multisort(table);
1030
- appendToTable(table, init);
1031
- $table.trigger('sortEnd', this);
1032
- ts.applyWidget(table);
1033
- if ($.isFunction(callback)) {
1034
- callback(table);
1035
- }
890
+ ts.sortOn( this.config, list, callback, init );
1036
891
  })
1037
- .bind('appendCache' + c.namespace, function(e, callback, init) {
892
+ .bind( 'appendCache' + c.namespace, function( e, callback, init ) {
1038
893
  e.stopPropagation();
1039
- appendToTable(table, init);
1040
- if ($.isFunction(callback)) {
1041
- callback(table);
894
+ ts.appendCache( this.config, init );
895
+ if ( $.isFunction( callback ) ) {
896
+ callback( table );
1042
897
  }
1043
898
  })
1044
899
  // $tbodies variable is used by the tbody sorting widget
1045
- .bind('updateCache' + c.namespace, function(e, callback, $tbodies){
1046
- // rebuild parsers
1047
- if (!(c.parsers && c.parsers.length)) {
1048
- buildParserCache(c, $tbodies);
1049
- }
1050
- // rebuild the cache map
1051
- buildCache(table, $tbodies);
1052
- if ($.isFunction(callback)) {
1053
- callback(table);
1054
- }
900
+ .bind( 'updateCache' + c.namespace, function( e, callback, $tbodies ){
901
+ e.stopPropagation();
902
+ ts.updateCache( this.config, callback, $tbodies );
1055
903
  })
1056
- .bind('applyWidgetId' + c.namespace, function(e, id) {
904
+ .bind( 'applyWidgetId' + c.namespace, function( e, id ) {
1057
905
  e.stopPropagation();
1058
- ts.getWidgetById(id).format(table, c, c.widgetOptions);
906
+ ts.getWidgetById( id ).format( table, this.config, this.config.widgetOptions );
1059
907
  })
1060
- .bind('applyWidgets' + c.namespace, function(e, init) {
908
+ .bind( 'applyWidgets' + c.namespace, function( e, init ) {
1061
909
  e.stopPropagation();
1062
910
  // apply widgets
1063
- ts.applyWidget(table, init);
911
+ ts.applyWidget( table, init );
1064
912
  })
1065
- .bind('refreshWidgets' + c.namespace, function(e, all, dontapply){
913
+ .bind( 'refreshWidgets' + c.namespace, function( e, all, dontapply ) {
1066
914
  e.stopPropagation();
1067
- ts.refreshWidgets(table, all, dontapply);
915
+ ts.refreshWidgets( table, all, dontapply );
1068
916
  })
1069
- .bind('destroy' + c.namespace, function(e, c, cb){
917
+ .bind( 'destroy' + c.namespace, function( e, removeClasses, callback ) {
1070
918
  e.stopPropagation();
1071
- ts.destroy(table, c, cb);
919
+ ts.destroy( table, removeClasses, callback );
1072
920
  })
1073
- .bind('resetToLoadState' + c.namespace, function(){
921
+ .bind( 'resetToLoadState' + c.namespace, function( e ) {
922
+ e.stopPropagation();
1074
923
  // remove all widgets
1075
- ts.removeWidget(table, true, false);
924
+ ts.removeWidget( table, true, false );
1076
925
  // restore original settings; this clears out current settings, but does not clear
1077
926
  // values saved to storage.
1078
- c = $.extend(true, ts.defaults, c.originalSettings);
927
+ c = $.extend( true, ts.defaults, c.originalSettings );
1079
928
  table.hasInitialized = false;
1080
929
  // setup the entire table again
1081
930
  ts.setup( table, c );
@@ -1171,7 +1020,7 @@
1171
1020
  // change textExtraction via data-attribute
1172
1021
  c.textExtraction = c.$table.attr('data-text-extraction') || c.textExtraction || 'basic';
1173
1022
  // build headers
1174
- buildHeaders(table);
1023
+ buildHeaders( c );
1175
1024
  // fixate columns if the users supplies the fixedWidth option
1176
1025
  // do this after theme has been applied
1177
1026
  ts.fixColumnWidth(table);
@@ -1391,7 +1240,7 @@
1391
1240
  .find(c.selectorSort).add( $headers.filter(c.selectorSort) )
1392
1241
  .unbind(t)
1393
1242
  .bind(t, function(e, external) {
1394
- var cell, temp,
1243
+ var $cell, cell, temp,
1395
1244
  $target = $(e.target),
1396
1245
  // wrap event type in spaces, so the match doesn't trigger on inner words
1397
1246
  type = ' ' + e.type + ' ';
@@ -1423,12 +1272,13 @@
1423
1272
  $target.parents('button').length > 0 ) {
1424
1273
  return !c.cancelSelection;
1425
1274
  }
1426
- if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); }
1275
+ if (c.delayInit && ts.isEmptyObject(c.cache)) { buildCache(table); }
1427
1276
  // jQuery v1.2.6 doesn't have closest()
1428
- cell = $.fn.closest ? $(this).closest('th, td')[0] : /TH|TD/.test(this.nodeName) ? this : $(this).parents('th, td')[0];
1277
+ $cell = $.fn.closest ? $(this).closest('th, td') : /TH|TD/.test(this.nodeName) ? $(this) : $(this).parents('th, td');
1429
1278
  // reference original table headers and find the same cell
1430
- cell = c.$headers[ $headers.index( cell ) ];
1431
- if (!cell.sortDisabled) {
1279
+ // don't use $headers or IE8 throws an error - see #987
1280
+ cell = c.$headers[ $cell.prevAll().length ];
1281
+ if (cell && !cell.sortDisabled) {
1432
1282
  initSort(table, cell, e);
1433
1283
  }
1434
1284
  });
@@ -1444,6 +1294,219 @@
1444
1294
  }
1445
1295
  };
1446
1296
 
1297
+ ts.sortReset = function( c, callback ) {
1298
+ var table = c.table;
1299
+ c.sortList = [];
1300
+ setHeadersCss( table );
1301
+ multisort( table );
1302
+ ts.appendCache( c );
1303
+ if ( $.isFunction( callback ) ) {
1304
+ callback( table );
1305
+ }
1306
+ };
1307
+
1308
+ ts.updateAll = function( c, resort, callback ) {
1309
+ var table = c.table;
1310
+ table.isUpdating = true;
1311
+ ts.refreshWidgets( table, true, true );
1312
+ buildHeaders( c );
1313
+ ts.bindEvents( table, c.$headers, true );
1314
+ bindMethods( table);
1315
+ commonUpdate( table, resort, callback );
1316
+ };
1317
+
1318
+ ts.update = function( c, resort, callback ) {
1319
+ var table = c.table;
1320
+ table.isUpdating = true;
1321
+ // update sorting (if enabled/disabled)
1322
+ updateHeader( table );
1323
+ commonUpdate( table, resort, callback );
1324
+ };
1325
+
1326
+ // simple header update - see #989
1327
+ ts.updateHeaders = function( c, callback ) {
1328
+ c.table.isUpdating = true;
1329
+ buildHeaders( c );
1330
+ ts.bindEvents( c.table, c.$headers, true );
1331
+ resortComplete( c, callback );
1332
+ };
1333
+
1334
+ ts.updateCell = function( c, cell, resort, callback ) {
1335
+ c.table.isUpdating = true;
1336
+ c.$table.find( c.selectorRemove ).remove();
1337
+ // get position from the dom
1338
+ var t, row, icell, cache,
1339
+ table = c.table,
1340
+ $tb = c.$tbodies,
1341
+ $cell = $(cell),
1342
+ // update cache - format: function(s, table, cell, cellIndex)
1343
+ // no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr');
1344
+ tbdy = $tb.index( $.fn.closest ? $cell.closest( 'tbody' ) : $cell.parents( 'tbody' ).filter( ':first' ) ),
1345
+ tbcache = c.cache[ tbdy ],
1346
+ $row = $.fn.closest ? $cell.closest( 'tr' ) : $cell.parents( 'tr' ).filter( ':first' );
1347
+ cell = $cell[ 0 ]; // in case cell is a jQuery object
1348
+ // tbody may not exist if update is initialized while tbody is removed for processing
1349
+ if ( $tb.length && tbdy >= 0 ) {
1350
+ row = $tb.eq( tbdy ).find( 'tr' ).index( $row );
1351
+ cache = tbcache.normalized[ row ];
1352
+ icell = $cell.index();
1353
+ t = ts.getParsedText( c, cell, icell );
1354
+ cache[ icell ] = t;
1355
+ cache[ c.columns ].$row = $row;
1356
+ if ( ( c.parsers[ icell ].type || '' ).toLowerCase() === 'numeric' ) {
1357
+ // update column max value (ignore sign)
1358
+ tbcache.colMax[ icell ] = Math.max( Math.abs( t ) || 0, tbcache.colMax[ icell ] || 0 );
1359
+ }
1360
+ t = resort !== 'undefined' ? resort : c.resort;
1361
+ if ( t !== false ) {
1362
+ // widgets will be reapplied
1363
+ checkResort( c, t, callback );
1364
+ } else {
1365
+ // don't reapply widgets is resort is false, just in case it causes
1366
+ // problems with element focus
1367
+ resortComplete( c, callback );
1368
+ }
1369
+ }
1370
+ };
1371
+
1372
+ ts.addRows = function( c, $row, resort, callback ) {
1373
+ var i, j, l, rowData, cells, rows, tbdy,
1374
+ // allow passing a row string if only one non-info tbody exists in the table
1375
+ valid = typeof $row === 'string' && c.$tbodies.length === 1 && /<tr/.test( $row || '' ),
1376
+ table = c.table;
1377
+ if ( valid ) {
1378
+ $row = $( $row );
1379
+ c.$tbodies.append( $row );
1380
+ } else if ( !$row ||
1381
+ // row is a jQuery object?
1382
+ !( $row instanceof jQuery ) ||
1383
+ // row contained in the table?
1384
+ ( $.fn.closest ? $row.closest( 'table' )[ 0 ] : $row.parents( 'table' )[ 0 ] ) !== c.table ) {
1385
+ if ( c.debug ) {
1386
+ console.error( 'addRows method requires (1) a jQuery selector reference to rows that have already ' +
1387
+ 'been added to the table, or (2) row HTML string to be added to a table with only one tbody' );
1388
+ }
1389
+ return false;
1390
+ }
1391
+ table.isUpdating = true;
1392
+ if ( ts.isEmptyObject( c.cache ) ) {
1393
+ // empty table, do an update instead - fixes #450
1394
+ updateHeader( table );
1395
+ commonUpdate( table, resort, callback );
1396
+ } else {
1397
+ rows = $row.filter( 'tr' ).attr( 'role', 'row' ).length;
1398
+ tbdy = c.$tbodies.index( $row.parents( 'tbody' ).filter( ':first' ) );
1399
+ // fixes adding rows to an empty table - see issue #179
1400
+ if ( !( c.parsers && c.parsers.length ) ) {
1401
+ buildParserCache( c );
1402
+ }
1403
+ // add each row
1404
+ for ( i = 0; i < rows; i++ ) {
1405
+ l = $row[ i ].cells.length;
1406
+ cells = [];
1407
+ rowData = {
1408
+ child: [],
1409
+ $row : $row.eq( i ),
1410
+ order: c.cache[ tbdy ].normalized.length
1411
+ };
1412
+ // add each cell
1413
+ for ( j = 0; j < l; j++ ) {
1414
+ cells[ j ] = ts.getParsedText( c, $row[ i ].cells[ j ], j );
1415
+ if ( ( c.parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) {
1416
+ // update column max value (ignore sign)
1417
+ c.cache[ tbdy ].colMax[ j ] = Math.max( Math.abs( cells[ j ] ) || 0, c.cache[ tbdy ].colMax[ j ] || 0 );
1418
+ }
1419
+ }
1420
+ // add the row data to the end
1421
+ cells.push( rowData );
1422
+ // update cache
1423
+ c.cache[ tbdy ].normalized.push( cells );
1424
+ }
1425
+ // resort using current settings
1426
+ checkResort( c, resort, callback );
1427
+ }
1428
+ };
1429
+
1430
+ ts.updateCache = function( c, callback, $tbodies ) {
1431
+ // rebuild parsers
1432
+ if ( !( c.parsers && c.parsers.length ) ) {
1433
+ buildParserCache( c, $tbodies );
1434
+ }
1435
+ // rebuild the cache map
1436
+ buildCache( c.table, callback, $tbodies );
1437
+ };
1438
+
1439
+ // init flag (true) used by pager plugin to prevent widget application
1440
+ // renamed from appendToTable
1441
+ ts.appendCache = function( c, init ) {
1442
+ var n, totalRows, $bk, $tb, i, k, appendTime,
1443
+ table = c.table,
1444
+ wo = c.widgetOptions,
1445
+ $tbodies = c.$tbodies,
1446
+ rows = [],
1447
+ cc = c.cache;
1448
+ // empty table - fixes #206/#346
1449
+ if ( ts.isEmptyObject( cc ) ) {
1450
+ // run pager appender in case the table was just emptied
1451
+ return c.appender ? c.appender( table, rows ) :
1452
+ table.isUpdating ? c.$table.trigger( 'updateComplete', table ) : ''; // Fixes #532
1453
+ }
1454
+ if ( c.debug ) {
1455
+ appendTime = new Date();
1456
+ }
1457
+ for ( k = 0; k < $tbodies.length; k++ ) {
1458
+ $bk = $tbodies.eq( k );
1459
+ if ( $bk.length ) {
1460
+ // get tbody
1461
+ $tb = ts.processTbody( table, $bk, true );
1462
+ n = cc[ k ].normalized;
1463
+ totalRows = n.length;
1464
+ for ( i = 0; i < totalRows; i++ ) {
1465
+ rows.push( n[ i ][ c.columns ].$row );
1466
+ // removeRows used by the pager plugin; don't render if using ajax - fixes #411
1467
+ if ( !c.appender || ( c.pager && ( !c.pager.removeRows || !wo.pager_removeRows ) && !c.pager.ajax ) ) {
1468
+ $tb.append( n[ i ][ c.columns ].$row );
1469
+ }
1470
+ }
1471
+ // restore tbody
1472
+ ts.processTbody( table, $tb, false );
1473
+ }
1474
+ }
1475
+ if ( c.appender ) {
1476
+ c.appender( table, rows );
1477
+ }
1478
+ if ( c.debug ) {
1479
+ console.log( 'Rebuilt table' + ts.benchmark( appendTime ) );
1480
+ }
1481
+ // apply table widgets; but not before ajax completes
1482
+ if ( !init && !c.appender ) { ts.applyWidget( table ); }
1483
+ if ( table.isUpdating ) {
1484
+ c.$table.trigger( 'updateComplete', table );
1485
+ }
1486
+ };
1487
+
1488
+ ts.sortOn = function( c, list, callback, init ) {
1489
+ var table = c.table;
1490
+ c.$table.trigger( 'sortStart', table );
1491
+ // update header count index
1492
+ updateHeaderSortCount( table, list );
1493
+ // set css for headers
1494
+ setHeadersCss( table );
1495
+ // fixes #346
1496
+ if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
1497
+ buildCache( table );
1498
+ }
1499
+ c.$table.trigger( 'sortBegin', table );
1500
+ // sort the table and append it to the dom
1501
+ multisort( table );
1502
+ ts.appendCache( c, init );
1503
+ c.$table.trigger( 'sortEnd', table );
1504
+ ts.applyWidget( table );
1505
+ if ( $.isFunction( callback ) ) {
1506
+ callback( table );
1507
+ }
1508
+ };
1509
+
1447
1510
  // restore headers
1448
1511
  ts.restoreHeaders = function(table){
1449
1512
  var index, $cell,
@@ -1482,8 +1545,9 @@
1482
1545
  // remove widget added rows, just in case
1483
1546
  $h.find('tr').not($r).remove();
1484
1547
  // disable tablesorter
1485
- events = 'sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache ' +
1486
- 'applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState '.split(' ')
1548
+ events = 'sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton ' +
1549
+ 'appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress ' +
1550
+ 'sortBegin sortEnd resetToLoadState '.split(' ')
1487
1551
  .join(c.namespace + ' ');
1488
1552
  $t
1489
1553
  .removeData('tablesorter')
@@ -1905,7 +1969,7 @@
1905
1969
  allColumns = column === 'all',
1906
1970
  data = { raw : [], parsed: [], $cell: [] },
1907
1971
  c = table.config;
1908
- if ( isEmptyObject( c ) ) {
1972
+ if ( ts.isEmptyObject( c ) ) {
1909
1973
  if ( c.debug ) {
1910
1974
  console.warn( 'No cache found - aborting getColumnText function!' );
1911
1975
  }
@@ -2057,7 +2121,8 @@
2057
2121
  },
2058
2122
  format: function(s, table) {
2059
2123
  var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
2060
- return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
2124
+ return s && typeof n === 'number' ? n :
2125
+ s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
2061
2126
  },
2062
2127
  type: 'numeric'
2063
2128
  });
@@ -2065,11 +2130,14 @@
2065
2130
  ts.addParser({
2066
2131
  id: 'currency',
2067
2132
  is: function(s) {
2068
- return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test((s || '').replace(/[+\-,. ]/g, '')); // £$€¤¥¢
2133
+ s = (s || '').replace(/[+\-,. ]/g, '');
2134
+ // test for £$€¤¥¢
2135
+ return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test(s);
2069
2136
  },
2070
2137
  format: function(s, table) {
2071
2138
  var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
2072
- return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
2139
+ return s && typeof n === 'number' ? n :
2140
+ s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
2073
2141
  },
2074
2142
  type: 'numeric'
2075
2143
  });
@@ -2127,7 +2195,8 @@
2127
2195
  is: function(s) {
2128
2196
  // two digit years are not allowed cross-browser
2129
2197
  // Jan 01, 2013 12:34:56 PM or 01 Jan 2013
2130
- return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) || (/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s);
2198
+ return (/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i).test(s) ||
2199
+ (/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s);
2131
2200
  },
2132
2201
  format: function(s, table) {
2133
2202
  var date = s ? new Date( s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s;
@@ -2139,16 +2208,20 @@
2139
2208
  ts.addParser({
2140
2209
  id: 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
2141
2210
  is: function(s) {
2211
+ s = (s || '').replace(/\s+/g, ' ').replace(/[\-.,]/g, '/');
2142
2212
  // testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
2143
- return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test((s || '').replace(/\s+/g, ' ').replace(/[\-.,]/g, '/'));
2213
+ return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test(s);
2144
2214
  },
2145
2215
  format: function(s, table, cell, cellIndex) {
2146
2216
  if (s) {
2147
2217
  var date, d,
2148
2218
  c = table.config,
2149
2219
  ci = c.$headerIndexed[ cellIndex ],
2150
- format = ci.length && ci[0].dateFormat || ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') || c.dateFormat;
2151
- d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/'); // escaped - because JSHint in Firefox was showing it as an error
2220
+ format = ci.length && ci[0].dateFormat ||
2221
+ ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') ||
2222
+ c.dateFormat;
2223
+ // escaped "-" because JSHint in Firefox was showing it as an error
2224
+ d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/');
2152
2225
  if (format === 'mmddyyyy') {
2153
2226
  d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$1/$2');
2154
2227
  } else if (format === 'ddmmyyyy') {