jquery-tablesorter 1.17.4 → 1.18.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6ff3892ce162fb8eec75bb7764185d2c6efba957
4
- data.tar.gz: 3ffe106aa3ccd5983d7c427e58a110d9870ec275
3
+ metadata.gz: a402dc3202ed41650d8eb5729cd40f73da187b60
4
+ data.tar.gz: b7ec31bebc3bea3bd8f0392b3445bae5584dd7b6
5
5
  SHA512:
6
- metadata.gz: dfede884f564297700b11fcf802d4f7d364b47e6ae0c45698bbe34c44b698ae97b77d3d27018238da7bbfc07449d48afd1b36840000c7fb297352f0a0970b4df
7
- data.tar.gz: 2e41d3642f6cd8eab091c236019f02871d3fbfcf8917bfac1c498fe467b7474fc5e3f44d6c9ccbb1e2fbdf5f0089b854602d41f690ebccfd75a816db914f9109
6
+ metadata.gz: 13eed15d8f851d226506481307bb636a16cc2345b50431daf07adece73086d1d19958b8367d295094bbf49d2f48570f5497a70fe1dc833cde5edb17c07856633
7
+ data.tar.gz: 10c804e1daa809c4439547a9fe0e601373873f0a9eaf758663721dbde19dde5b4e7eb2817c6019bde8f8c78fe5d17daec01115fa66628365d487da67f81f5831
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.5 (7/28/2015), [documentation]
7
+ Current tablesorter version: 2.23.0 (8/17/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.4'
2
+ VERSION = '1.18.0'
3
3
  end
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * tablesorter (FORK) pager plugin
3
- * updated 7/28/2015 (v2.22.4)
3
+ * updated 8/17/2015 (v2.23.0)
4
4
  */
5
5
  /*jshint browser:true, jquery:true, unused:false */
6
6
  ;(function($) {
@@ -25,6 +25,11 @@
25
25
  // modify the url after all processing has been applied
26
26
  customAjaxUrl: function(table, url) { return url; },
27
27
 
28
+ // ajax error callback from $.tablesorter.showError function
29
+ // ajaxError: function( config, xhr, exception ){ return exception; };
30
+ // returning false will abort the error message
31
+ ajaxError: null,
32
+
28
33
  // modify the $.ajax object to allow complete control over your ajax requests
29
34
  ajaxObject: {
30
35
  dataType: 'json'
@@ -114,7 +119,7 @@
114
119
 
115
120
  };
116
121
 
117
- var pagerEvents = 'filterInit filterStart filterEnd sortEnd disable enable destroy updateComplete ' +
122
+ var pagerEvents = 'filterInit filterStart filterEnd sortEnd disablePager enablePager destroyPager updateComplete ' +
118
123
  'pageSize pageSet pageAndSize pagerUpdate refreshComplete ',
119
124
 
120
125
  $this = this,
@@ -139,7 +144,7 @@
139
144
  c = table.config,
140
145
  hasFilters = c.$table.hasClass('hasFilters');
141
146
  if (hasFilters && !p.ajaxUrl) {
142
- if ($.isEmptyObject(c.cache)) {
147
+ if (ts.isEmptyObject(c.cache)) {
143
148
  // delayInit: true so nothing is in the cache
144
149
  p.filteredRows = p.totalRows = c.$tbodies.eq(0).children('tr').not( p.countChildRows ? '' : '.' + c.cssChildRow ).length;
145
150
  } else {
@@ -386,20 +391,13 @@
386
391
  hl = $table.find('thead th').length;
387
392
 
388
393
  // Clean up any previous error.
389
- ts.showError(table);
394
+ ts.showError( table );
390
395
 
391
396
  if ( exception ) {
392
397
  if (c.debug) {
393
398
  console.error('Pager: >> Ajax Error', xhr, exception);
394
399
  }
395
- ts.showError(table,
396
- xhr.status === 0 ? 'Not connected, verify Network' :
397
- xhr.status === 404 ? 'Requested page not found [404]' :
398
- xhr.status === 500 ? 'Internal Server Error [500]' :
399
- exception === 'parsererror' ? 'Requested JSON parse failed' :
400
- exception === 'timeout' ? 'Time out error' :
401
- exception === 'abort' ? 'Ajax Request aborted' :
402
- 'Uncaught error: ' + xhr.statusText + ' [' + xhr.status + ']' );
400
+ ts.showError( table, xhr, exception );
403
401
  c.$tbodies.eq(0).children('tr').detach();
404
402
  p.totalRows = 0;
405
403
  } else {
@@ -708,7 +706,7 @@
708
706
  var pg, c = table.config,
709
707
  $t = $(table),
710
708
  l = p.last;
711
- if ( pageMoved !== false && p.initialized && $.isEmptyObject(c.cache)) {
709
+ if ( pageMoved !== false && p.initialized && ts.isEmptyObject(c.cache)) {
712
710
  return updateCache(table);
713
711
  }
714
712
  // abort page move if the table has filters and has not been initialized
@@ -801,16 +799,23 @@
801
799
  },
802
800
 
803
801
  destroyPager = function(table, p) {
802
+ var c = table.config,
803
+ namespace = c.namespace + 'pager',
804
+ ctrls = [ p.cssFirst, p.cssPrev, p.cssNext, p.cssLast, p.cssGoto, p.cssPageSize ].join( ',' );
804
805
  showAllRows(table, p);
805
- p.$container.hide(); // hide pager
806
- var c = table.config;
806
+ p.$container
807
+ // hide pager controls
808
+ .hide()
809
+ // unbind
810
+ .find( ctrls )
811
+ .unbind( namespace );
807
812
  c.appender = null; // remove pager appender function
808
- p.initialized = false;
809
- delete c.rowsCopy;
810
- $(table).unbind( pagerEvents.split(' ').join(c.namespace + 'pager ').replace(/\s+/g, ' ') );
813
+ c.$table.unbind( namespace );
811
814
  if (ts.storage) {
812
815
  ts.storage(table, p.storageKey, '');
813
816
  }
817
+ delete c.pager;
818
+ delete c.rowsCopy;
814
819
  },
815
820
 
816
821
  enablePager = function(table, p, triggered) {
@@ -888,6 +893,7 @@
888
893
  p.regexRows = new RegExp('(' + (wo.filter_filteredRow || 'filtered') + '|' + c.selectorRemove.slice(1) + '|' + c.cssChildRow + ')');
889
894
 
890
895
  $t
896
+ // .unbind( namespace ) adding in jQuery 1.4.3 ( I think )
891
897
  .unbind( pagerEvents.split(' ').join(namespace + ' ').replace(/\s+/g, ' ') )
892
898
  .bind('filterInit filterStart '.split(' ').join(namespace + ' '), function(e, filters) {
893
899
  p.currentFilters = $.isArray(filters) ? filters : c.$table.data('lastSearch');
@@ -909,15 +915,15 @@
909
915
  c.$table.trigger('applyWidgets');
910
916
  }
911
917
  })
912
- .bind('disable' + namespace, function(e){
918
+ .bind('disablePager' + namespace, function(e){
913
919
  e.stopPropagation();
914
920
  showAllRows(table, p);
915
921
  })
916
- .bind('enable' + namespace, function(e){
922
+ .bind('enablePager' + namespace, function(e){
917
923
  e.stopPropagation();
918
924
  enablePager(table, p, true);
919
925
  })
920
- .bind('destroy' + namespace, function(e){
926
+ .bind('destroyPager' + namespace, function(e){
921
927
  e.stopPropagation();
922
928
  destroyPager(table, p);
923
929
  })
@@ -1061,31 +1067,73 @@
1061
1067
  }() });
1062
1068
 
1063
1069
  // see #486
1064
- ts.showError = function(table, message) {
1065
- var index, $row, c, errorRow,
1070
+ ts.showError = function( table, xhr, exception ) {
1071
+ var $row,
1066
1072
  $table = $( table ),
1067
- len = $table.length;
1068
- for ( index = 0; index < len; index++ ) {
1069
- c = $table[ index ].config;
1070
- if ( c ) {
1071
- errorRow = c.pager && c.pager.cssErrorRow || c.widgetOptions.pager_css && c.widgetOptions.pager_css.errorRow || 'tablesorter-errorRow';
1072
- if ( typeof message === 'undefined' ) {
1073
- c.$table.find('thead').find(c.selectorRemove).remove();
1073
+ c = $table[0].config,
1074
+ wo = c && c.widgetOptions,
1075
+ errorRow = c.pager && c.pager.cssErrorRow || wo.pager_css && wo.pager_css.errorRow || 'tablesorter-errorRow',
1076
+ typ = typeof xhr,
1077
+ valid = true,
1078
+ message = '',
1079
+ removeRow = function(){
1080
+ c.$table.find( 'thead' ).find( '.' + errorRow ).remove();
1081
+ };
1082
+
1083
+ if ( !$table.length ) {
1084
+ console.error('tablesorter showError: no table parameter passed');
1085
+ return;
1086
+ }
1087
+
1088
+ if ( typ !== 'string' ) {
1089
+ // ajaxError callback for plugin or widget - see #992
1090
+ if ( typeof c.pager.ajaxError === 'function' ) {
1091
+ valid = c.pager.ajaxError( c, xhr, exception );
1092
+ if ( valid === false ) {
1093
+ return removeRow();
1074
1094
  } else {
1075
- $row = ( /tr\>/.test(message) ? $(message) : $('<tr><td colspan="' + c.columns + '">' + message + '</td></tr>') )
1076
- .click(function(){
1077
- $(this).remove();
1078
- })
1079
- // add error row to thead instead of tbody, or clicking on the header will result in a parser error
1080
- .appendTo( c.$table.find('thead:first') )
1081
- .addClass( errorRow + ' ' + c.selectorRemove.slice(1) )
1082
- .attr({
1083
- role : 'alert',
1084
- 'aria-live' : 'assertive'
1085
- });
1095
+ message = valid;
1086
1096
  }
1097
+ } else if ( typeof wo.pager_ajaxError === 'function' ) {
1098
+ valid = wo.pager_ajaxError( c, xhr, exception );
1099
+ if ( valid === false ) {
1100
+ return removeRow();
1101
+ } else {
1102
+ message = valid;
1103
+ }
1104
+ } else {
1105
+ message =
1106
+ xhr.status === 0 ? 'Not connected, verify Network' :
1107
+ xhr.status === 404 ? 'Requested page not found [404]' :
1108
+ xhr.status === 500 ? 'Internal Server Error [500]' :
1109
+ exception === 'parsererror' ? 'Requested JSON parse failed' :
1110
+ exception === 'timeout' ? 'Time out error' :
1111
+ exception === 'abort' ? 'Ajax Request aborted' :
1112
+ 'Uncaught error: ' + xhr.statusText + ' [' + xhr.status + ']';
1087
1113
  }
1114
+ } else if ( typ !== 'undefined' ) {
1115
+ // keep backward compatibility (external usage just passes a message string)
1116
+ message = xhr;
1117
+ }
1118
+
1119
+ if ( message === '' ) {
1120
+ // remove all error rows
1121
+ return removeRow();
1088
1122
  }
1123
+
1124
+ // allow message to include HTML (must include entire row!)
1125
+ $row = ( /tr\>/.test(message) ? $(message) : $('<tr><td colspan="' + c.columns + '">' + message + '</td></tr>') )
1126
+ .click( function() {
1127
+ $( this ).remove();
1128
+ })
1129
+ // add error row to thead instead of tbody, or clicking on the header will result in a parser error
1130
+ .appendTo( c.$table.find( 'thead:first' ) )
1131
+ .addClass( errorRow + ' ' + c.selectorRemove.slice(1) )
1132
+ .attr({
1133
+ role : 'alert',
1134
+ 'aria-live' : 'assertive'
1135
+ });
1136
+
1089
1137
  };
1090
1138
 
1091
1139
  // extend plugin scope
@@ -4,7 +4,7 @@
4
4
  ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀▀▀▀██
5
5
  █████▀ ▀████▀ ██ ██ ▀████▀ ██ ██ ██ ██ ▀████▀ █████▀ ██ ██ █████▀
6
6
  */
7
- /*! tablesorter (FORK) - updated 07-28-2015 (v2.22.5)*/
7
+ /*! tablesorter (FORK) - updated 08-17-2015 (v2.23.0)*/
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.5 *//*
19
+ /*! TableSorter (FORK) v2.23.0 *//*
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.5';
47
+ ts.version = '2.23.0';
48
48
 
49
49
  ts.parsers = [];
50
50
  ts.widgets = [];
@@ -173,13 +173,13 @@
173
173
  ts.instanceMethods = {};
174
174
 
175
175
  // $.isEmptyObject from jQuery v1.4
176
- function isEmptyObject(obj) {
176
+ ts.isEmptyObject = function( obj ) {
177
177
  /*jshint forin: false */
178
- for (var name in obj) {
178
+ for ( var name in obj ) {
179
179
  return false;
180
180
  }
181
181
  return true;
182
- }
182
+ };
183
183
 
184
184
  ts.getElementText = function(c, node, cellIndex) {
185
185
  if (!node) { return ''; }
@@ -322,7 +322,7 @@
322
322
  j += (list.parsers.length) ? len : 1;
323
323
  }
324
324
  if ( c.debug ) {
325
- if ( !isEmptyObject( debug ) ) {
325
+ if ( !ts.isEmptyObject( debug ) ) {
326
326
  console[ console.table ? 'table' : 'log' ]( debug );
327
327
  } else {
328
328
  console.warn( ' No parsers detected!' );
@@ -335,7 +335,7 @@
335
335
  }
336
336
 
337
337
  /* utils */
338
- function buildCache(table, $tbodies) {
338
+ function buildCache(table, callback, $tbodies) {
339
339
  var cc, t, v, i, j, k, $tb, $row, cols, cacheTime,
340
340
  totalRows, rowData, prevRowData, colMax,
341
341
  c = table.config,
@@ -428,54 +428,8 @@
428
428
  if ( c.debug ) {
429
429
  console.log( 'Building cache for ' + totalRows + ' rows' + ts.benchmark( cacheTime ) );
430
430
  }
431
- }
432
-
433
- // init flag (true) used by pager plugin to prevent widget application
434
- function appendToTable(table, init) {
435
- var c = table.config,
436
- wo = c.widgetOptions,
437
- $tbodies = c.$tbodies,
438
- rows = [],
439
- cc = c.cache,
440
- n, totalRows, $bk, $tb,
441
- i, k, appendTime;
442
- // empty table - fixes #206/#346
443
- if (isEmptyObject(cc)) {
444
- // run pager appender in case the table was just emptied
445
- return c.appender ? c.appender(table, rows) :
446
- table.isUpdating ? c.$table.trigger('updateComplete', table) : ''; // Fixes #532
447
- }
448
- if (c.debug) {
449
- appendTime = new Date();
450
- }
451
- for (k = 0; k < $tbodies.length; k++) {
452
- $bk = $tbodies.eq(k);
453
- if ($bk.length) {
454
- // get tbody
455
- $tb = ts.processTbody(table, $bk, true);
456
- n = cc[k].normalized;
457
- totalRows = n.length;
458
- for (i = 0; i < totalRows; i++) {
459
- rows.push(n[i][c.columns].$row);
460
- // removeRows used by the pager plugin; don't render if using ajax - fixes #411
461
- if (!c.appender || (c.pager && (!c.pager.removeRows || !wo.pager_removeRows) && !c.pager.ajax)) {
462
- $tb.append(n[i][c.columns].$row);
463
- }
464
- }
465
- // restore tbody
466
- ts.processTbody(table, $tb, false);
467
- }
468
- }
469
- if (c.appender) {
470
- c.appender(table, rows);
471
- }
472
- if (c.debug) {
473
- console.log( 'Rebuilt table' + ts.benchmark(appendTime) );
474
- }
475
- // apply table widgets; but not before ajax completes
476
- if (!init && !c.appender) { ts.applyWidget(table); }
477
- if (table.isUpdating) {
478
- c.$table.trigger('updateComplete', table);
431
+ if ( $.isFunction( callback ) ) {
432
+ callback( table );
479
433
  }
480
434
  }
481
435
 
@@ -484,9 +438,8 @@
484
438
  return (/^d/i.test(v) || v === 1);
485
439
  }
486
440
 
487
- function buildHeaders(table) {
488
- var ch, $t, h, i, t, lock, time, indx,
489
- c = table.config;
441
+ function buildHeaders( c ) {
442
+ var ch, $t, h, i, t, lock, time, indx;
490
443
  c.headerList = [];
491
444
  c.headerContent = [];
492
445
  if (c.debug) {
@@ -497,12 +450,12 @@
497
450
  // add icon if cssIcon option exists
498
451
  i = c.cssIcon ? '<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' : '';
499
452
  // redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683
500
- c.$headers = $( $.map( $(table).find(c.selectorHeaders), function(elem, index) {
453
+ c.$headers = $( $.map( c.$table.find(c.selectorHeaders), function(elem, index) {
501
454
  $t = $(elem);
502
455
  // ignore cell (don't add it to c.$headers) if row has ignoreRow class
503
456
  if ($t.parent().hasClass(c.cssIgnoreRow)) { return; }
504
457
  // make sure to get header cell & not column indexed cell
505
- ch = ts.getColumnData( table, c.headers, index, true );
458
+ ch = ts.getColumnData( c.table, c.headers, index, true );
506
459
  // save original header content
507
460
  c.headerContent[index] = $t.html();
508
461
  // if headerTemplate is empty, don't reformat the header cell
@@ -544,12 +497,12 @@
544
497
  // .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6
545
498
  c.$headerIndexed[indx] = $t.not('.sorter-false').length ? $t.not('.sorter-false').filter(':last') : $t.filter(':last');
546
499
  }
547
- $(table).find(c.selectorHeaders).attr({
500
+ c.$table.find(c.selectorHeaders).attr({
548
501
  scope: 'col',
549
502
  role : 'columnheader'
550
503
  });
551
504
  // enable/disable sorting
552
- updateHeader(table);
505
+ updateHeader(c.table);
553
506
  if (c.debug) {
554
507
  console.log( 'Built headers:' + ts.benchmark( time ) );
555
508
  console.log( c.$headers );
@@ -806,7 +759,7 @@
806
759
  // set css for headers
807
760
  setHeadersCss(table);
808
761
  multisort(table);
809
- appendToTable(table);
762
+ ts.appendCache( c );
810
763
  $table.trigger('sortEnd', table);
811
764
  }, 1);
812
765
  }
@@ -821,7 +774,7 @@
821
774
  sortList = c.sortList,
822
775
  l = sortList.length,
823
776
  bl = c.$tbodies.length;
824
- if (c.serverSideSorting || isEmptyObject(c.cache)) { // empty table - fixes #206/#346
777
+ if (c.serverSideSorting || ts.isEmptyObject(c.cache)) { // empty table - fixes #206/#346
825
778
  return;
826
779
  }
827
780
  if (c.debug) { sortTime = new Date(); }
@@ -912,188 +865,84 @@
912
865
  }
913
866
  }
914
867
 
915
- function bindMethods(table){
868
+ function bindMethods( table ){
916
869
  var c = table.config,
917
870
  $table = c.$table,
918
- events = ('sortReset update updateRows updateCell updateAll addRows updateComplete sorton appendCache ' +
919
- 'updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ').split(' ')
920
- .join(c.namespace + ' ');
871
+ events = ( 'sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete ' +
872
+ 'sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup ' +
873
+ 'mouseleave ' ).split( ' ' )
874
+ .join( c.namespace + ' ' );
921
875
  // apply easy methods that trigger bound events
922
876
  $table
923
- .unbind( events.replace(/\s+/g, ' ') )
924
- .bind('sortReset' + c.namespace, function(e, callback){
877
+ .unbind( events.replace( /\s+/g, ' ' ) )
878
+ .bind( 'sortReset' + c.namespace, function( e, callback ) {
925
879
  e.stopPropagation();
926
- c.sortList = [];
927
- setHeadersCss(table);
928
- multisort(table);
929
- appendToTable(table);
930
- if ($.isFunction(callback)) {
931
- callback(table);
932
- }
880
+ // using this.config to ensure functions are getting a non-cached version of the config
881
+ ts.sortReset( this.config, callback );
933
882
  })
934
- .bind('updateAll' + c.namespace, function(e, resort, callback){
883
+ .bind( 'updateAll' + c.namespace, function( e, resort, callback ) {
935
884
  e.stopPropagation();
936
- table.isUpdating = true;
937
- ts.refreshWidgets(table, true, true);
938
- buildHeaders(table);
939
- ts.bindEvents(table, c.$headers, true);
940
- bindMethods(table);
941
- commonUpdate(table, resort, callback);
885
+ ts.updateAll( this.config, resort, callback );
942
886
  })
943
- .bind('update' + c.namespace + ' updateRows' + c.namespace, function(e, resort, callback) {
887
+ .bind( 'update' + c.namespace + ' updateRows' + c.namespace, function( e, resort, callback ) {
944
888
  e.stopPropagation();
945
- table.isUpdating = true;
946
- // update sorting (if enabled/disabled)
947
- updateHeader(table);
948
- commonUpdate(table, resort, callback);
889
+ ts.update( this.config, resort, callback );
949
890
  })
950
- .bind('updateCell' + c.namespace, function(e, cell, resort, callback) {
891
+ .bind( 'updateHeaders' + c.namespace, function( e, callback ) {
951
892
  e.stopPropagation();
952
- table.isUpdating = true;
953
- $table.find(c.selectorRemove).remove();
954
- // get position from the dom
955
- var t, row, icell, cache,
956
- $tb = c.$tbodies,
957
- $cell = $(cell),
958
- // update cache - format: function(s, table, cell, cellIndex)
959
- // no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr');
960
- tbdy = $tb.index( $.fn.closest ? $cell.closest('tbody') : $cell.parents('tbody').filter(':first') ),
961
- tbcache = c.cache[ tbdy ],
962
- $row = $.fn.closest ? $cell.closest('tr') : $cell.parents('tr').filter(':first');
963
- cell = $cell[0]; // in case cell is a jQuery object
964
- // tbody may not exist if update is initialized while tbody is removed for processing
965
- if ($tb.length && tbdy >= 0) {
966
- row = $tb.eq( tbdy ).find( 'tr' ).index( $row );
967
- cache = tbcache.normalized[ row ];
968
- icell = $cell.index();
969
- t = ts.getParsedText( c, cell, icell );
970
- cache[ icell ] = t;
971
- cache[ c.columns ].$row = $row;
972
- if ( (c.parsers[icell].type || '').toLowerCase() === 'numeric' ) {
973
- // update column max value (ignore sign)
974
- tbcache.colMax[icell] = Math.max(Math.abs(t) || 0, tbcache.colMax[icell] || 0);
975
- }
976
- t = resort !== 'undefined' ? resort : c.resort;
977
- if (t !== false) {
978
- // widgets will be reapplied
979
- checkResort(c, t, callback);
980
- } else {
981
- // don't reapply widgets is resort is false, just in case it causes
982
- // problems with element focus
983
- if ($.isFunction(callback)) {
984
- callback(table);
985
- }
986
- c.$table.trigger('updateComplete', c.table);
987
- }
988
- }
893
+ ts.updateHeaders( this.config, callback );
989
894
  })
990
- .bind('addRows' + c.namespace, function(e, $row, resort, callback) {
895
+ .bind( 'updateCell' + c.namespace, function(e, cell, resort, callback ) {
991
896
  e.stopPropagation();
992
- table.isUpdating = true;
993
- if (isEmptyObject(c.cache)) {
994
- // empty table, do an update instead - fixes #450
995
- updateHeader(table);
996
- commonUpdate(table, resort, callback);
997
- } else {
998
- $row = $($row).attr('role', 'row'); // make sure we're using a jQuery object
999
- var i, j, l, rowData, cells,
1000
- rows = $row.filter('tr').length,
1001
- tbdy = c.$tbodies.index( $row.parents('tbody').filter(':first') );
1002
- // fixes adding rows to an empty table - see issue #179
1003
- if (!(c.parsers && c.parsers.length)) {
1004
- buildParserCache(c);
1005
- }
1006
- // add each row
1007
- for (i = 0; i < rows; i++) {
1008
- l = $row[i].cells.length;
1009
- cells = [];
1010
- rowData = {
1011
- child: [],
1012
- $row : $row.eq(i),
1013
- order: c.cache[tbdy].normalized.length
1014
- };
1015
- // add each cell
1016
- for (j = 0; j < l; j++) {
1017
- cells[j] = ts.getParsedText( c, $row[i].cells[j], j );
1018
- if ((c.parsers[j].type || '').toLowerCase() === 'numeric') {
1019
- // update column max value (ignore sign)
1020
- c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0);
1021
- }
1022
- }
1023
- // add the row data to the end
1024
- cells.push(rowData);
1025
- // update cache
1026
- c.cache[tbdy].normalized.push(cells);
1027
- }
1028
- // resort using current settings
1029
- checkResort(c, resort, callback);
1030
- }
897
+ ts.updateCell( this.config, cell, resort, callback );
1031
898
  })
1032
- .bind('updateComplete' + c.namespace, function(){
899
+ .bind( 'addRows' + c.namespace, function(e, $row, resort, callback) {
900
+ e.stopPropagation();
901
+ ts.addRows( this.config, $row, resort, callback );
902
+ })
903
+ .bind( 'updateComplete' + c.namespace, function() {
1033
904
  table.isUpdating = false;
1034
905
  })
1035
- .bind('sorton' + c.namespace, function(e, list, callback, init) {
1036
- var c = table.config;
906
+ .bind( 'sorton' + c.namespace, function( e, list, callback, init ) {
1037
907
  e.stopPropagation();
1038
- $table.trigger('sortStart', this);
1039
- // update header count index
1040
- updateHeaderSortCount(table, list);
1041
- // set css for headers
1042
- setHeadersCss(table);
1043
- // fixes #346
1044
- if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); }
1045
- $table.trigger('sortBegin', this);
1046
- // sort the table and append it to the dom
1047
- multisort(table);
1048
- appendToTable(table, init);
1049
- $table.trigger('sortEnd', this);
1050
- ts.applyWidget(table);
1051
- if ($.isFunction(callback)) {
1052
- callback(table);
1053
- }
908
+ ts.sortOn( this.config, list, callback, init );
1054
909
  })
1055
- .bind('appendCache' + c.namespace, function(e, callback, init) {
910
+ .bind( 'appendCache' + c.namespace, function( e, callback, init ) {
1056
911
  e.stopPropagation();
1057
- appendToTable(table, init);
1058
- if ($.isFunction(callback)) {
1059
- callback(table);
912
+ ts.appendCache( this.config, init );
913
+ if ( $.isFunction( callback ) ) {
914
+ callback( table );
1060
915
  }
1061
916
  })
1062
917
  // $tbodies variable is used by the tbody sorting widget
1063
- .bind('updateCache' + c.namespace, function(e, callback, $tbodies){
1064
- // rebuild parsers
1065
- if (!(c.parsers && c.parsers.length)) {
1066
- buildParserCache(c, $tbodies);
1067
- }
1068
- // rebuild the cache map
1069
- buildCache(table, $tbodies);
1070
- if ($.isFunction(callback)) {
1071
- callback(table);
1072
- }
918
+ .bind( 'updateCache' + c.namespace, function( e, callback, $tbodies ){
919
+ e.stopPropagation();
920
+ ts.updateCache( this.config, callback, $tbodies );
1073
921
  })
1074
- .bind('applyWidgetId' + c.namespace, function(e, id) {
922
+ .bind( 'applyWidgetId' + c.namespace, function( e, id ) {
1075
923
  e.stopPropagation();
1076
- ts.getWidgetById(id).format(table, c, c.widgetOptions);
924
+ ts.getWidgetById( id ).format( table, this.config, this.config.widgetOptions );
1077
925
  })
1078
- .bind('applyWidgets' + c.namespace, function(e, init) {
926
+ .bind( 'applyWidgets' + c.namespace, function( e, init ) {
1079
927
  e.stopPropagation();
1080
928
  // apply widgets
1081
- ts.applyWidget(table, init);
929
+ ts.applyWidget( table, init );
1082
930
  })
1083
- .bind('refreshWidgets' + c.namespace, function(e, all, dontapply){
931
+ .bind( 'refreshWidgets' + c.namespace, function( e, all, dontapply ) {
1084
932
  e.stopPropagation();
1085
- ts.refreshWidgets(table, all, dontapply);
933
+ ts.refreshWidgets( table, all, dontapply );
1086
934
  })
1087
- .bind('destroy' + c.namespace, function(e, c, cb){
935
+ .bind( 'destroy' + c.namespace, function( e, removeClasses, callback ) {
1088
936
  e.stopPropagation();
1089
- ts.destroy(table, c, cb);
937
+ ts.destroy( table, removeClasses, callback );
1090
938
  })
1091
- .bind('resetToLoadState' + c.namespace, function(){
939
+ .bind( 'resetToLoadState' + c.namespace, function( e ) {
940
+ e.stopPropagation();
1092
941
  // remove all widgets
1093
- ts.removeWidget(table, true, false);
942
+ ts.removeWidget( table, true, false );
1094
943
  // restore original settings; this clears out current settings, but does not clear
1095
944
  // values saved to storage.
1096
- c = $.extend(true, ts.defaults, c.originalSettings);
945
+ c = $.extend( true, ts.defaults, c.originalSettings );
1097
946
  table.hasInitialized = false;
1098
947
  // setup the entire table again
1099
948
  ts.setup( table, c );
@@ -1189,7 +1038,7 @@
1189
1038
  // change textExtraction via data-attribute
1190
1039
  c.textExtraction = c.$table.attr('data-text-extraction') || c.textExtraction || 'basic';
1191
1040
  // build headers
1192
- buildHeaders(table);
1041
+ buildHeaders( c );
1193
1042
  // fixate columns if the users supplies the fixedWidth option
1194
1043
  // do this after theme has been applied
1195
1044
  ts.fixColumnWidth(table);
@@ -1409,7 +1258,7 @@
1409
1258
  .find(c.selectorSort).add( $headers.filter(c.selectorSort) )
1410
1259
  .unbind(t)
1411
1260
  .bind(t, function(e, external) {
1412
- var cell, temp,
1261
+ var $cell, cell, temp,
1413
1262
  $target = $(e.target),
1414
1263
  // wrap event type in spaces, so the match doesn't trigger on inner words
1415
1264
  type = ' ' + e.type + ' ';
@@ -1441,12 +1290,13 @@
1441
1290
  $target.parents('button').length > 0 ) {
1442
1291
  return !c.cancelSelection;
1443
1292
  }
1444
- if (c.delayInit && isEmptyObject(c.cache)) { buildCache(table); }
1293
+ if (c.delayInit && ts.isEmptyObject(c.cache)) { buildCache(table); }
1445
1294
  // jQuery v1.2.6 doesn't have closest()
1446
- cell = $.fn.closest ? $(this).closest('th, td')[0] : /TH|TD/.test(this.nodeName) ? this : $(this).parents('th, td')[0];
1295
+ $cell = $.fn.closest ? $(this).closest('th, td') : /TH|TD/.test(this.nodeName) ? $(this) : $(this).parents('th, td');
1447
1296
  // reference original table headers and find the same cell
1448
- cell = c.$headers[ $headers.index( cell ) ];
1449
- if (!cell.sortDisabled) {
1297
+ // don't use $headers or IE8 throws an error - see #987
1298
+ cell = c.$headers[ $cell.prevAll().length ];
1299
+ if (cell && !cell.sortDisabled) {
1450
1300
  initSort(table, cell, e);
1451
1301
  }
1452
1302
  });
@@ -1462,6 +1312,219 @@
1462
1312
  }
1463
1313
  };
1464
1314
 
1315
+ ts.sortReset = function( c, callback ) {
1316
+ var table = c.table;
1317
+ c.sortList = [];
1318
+ setHeadersCss( table );
1319
+ multisort( table );
1320
+ ts.appendCache( c );
1321
+ if ( $.isFunction( callback ) ) {
1322
+ callback( table );
1323
+ }
1324
+ };
1325
+
1326
+ ts.updateAll = function( c, resort, callback ) {
1327
+ var table = c.table;
1328
+ table.isUpdating = true;
1329
+ ts.refreshWidgets( table, true, true );
1330
+ buildHeaders( c );
1331
+ ts.bindEvents( table, c.$headers, true );
1332
+ bindMethods( table);
1333
+ commonUpdate( table, resort, callback );
1334
+ };
1335
+
1336
+ ts.update = function( c, resort, callback ) {
1337
+ var table = c.table;
1338
+ table.isUpdating = true;
1339
+ // update sorting (if enabled/disabled)
1340
+ updateHeader( table );
1341
+ commonUpdate( table, resort, callback );
1342
+ };
1343
+
1344
+ // simple header update - see #989
1345
+ ts.updateHeaders = function( c, callback ) {
1346
+ c.table.isUpdating = true;
1347
+ buildHeaders( c );
1348
+ ts.bindEvents( c.table, c.$headers, true );
1349
+ resortComplete( c, callback );
1350
+ };
1351
+
1352
+ ts.updateCell = function( c, cell, resort, callback ) {
1353
+ c.table.isUpdating = true;
1354
+ c.$table.find( c.selectorRemove ).remove();
1355
+ // get position from the dom
1356
+ var t, row, icell, cache,
1357
+ table = c.table,
1358
+ $tb = c.$tbodies,
1359
+ $cell = $(cell),
1360
+ // update cache - format: function(s, table, cell, cellIndex)
1361
+ // no closest in jQuery v1.2.6 - tbdy = $tb.index( $(cell).closest('tbody') ),$row = $(cell).closest('tr');
1362
+ tbdy = $tb.index( $.fn.closest ? $cell.closest( 'tbody' ) : $cell.parents( 'tbody' ).filter( ':first' ) ),
1363
+ tbcache = c.cache[ tbdy ],
1364
+ $row = $.fn.closest ? $cell.closest( 'tr' ) : $cell.parents( 'tr' ).filter( ':first' );
1365
+ cell = $cell[ 0 ]; // in case cell is a jQuery object
1366
+ // tbody may not exist if update is initialized while tbody is removed for processing
1367
+ if ( $tb.length && tbdy >= 0 ) {
1368
+ row = $tb.eq( tbdy ).find( 'tr' ).index( $row );
1369
+ cache = tbcache.normalized[ row ];
1370
+ icell = $cell.index();
1371
+ t = ts.getParsedText( c, cell, icell );
1372
+ cache[ icell ] = t;
1373
+ cache[ c.columns ].$row = $row;
1374
+ if ( ( c.parsers[ icell ].type || '' ).toLowerCase() === 'numeric' ) {
1375
+ // update column max value (ignore sign)
1376
+ tbcache.colMax[ icell ] = Math.max( Math.abs( t ) || 0, tbcache.colMax[ icell ] || 0 );
1377
+ }
1378
+ t = resort !== 'undefined' ? resort : c.resort;
1379
+ if ( t !== false ) {
1380
+ // widgets will be reapplied
1381
+ checkResort( c, t, callback );
1382
+ } else {
1383
+ // don't reapply widgets is resort is false, just in case it causes
1384
+ // problems with element focus
1385
+ resortComplete( c, callback );
1386
+ }
1387
+ }
1388
+ };
1389
+
1390
+ ts.addRows = function( c, $row, resort, callback ) {
1391
+ var i, j, l, rowData, cells, rows, tbdy,
1392
+ // allow passing a row string if only one non-info tbody exists in the table
1393
+ valid = typeof $row === 'string' && c.$tbodies.length === 1 && /<tr/.test( $row || '' ),
1394
+ table = c.table;
1395
+ if ( valid ) {
1396
+ $row = $( $row );
1397
+ c.$tbodies.append( $row );
1398
+ } else if ( !$row ||
1399
+ // row is a jQuery object?
1400
+ !( $row instanceof jQuery ) ||
1401
+ // row contained in the table?
1402
+ ( $.fn.closest ? $row.closest( 'table' )[ 0 ] : $row.parents( 'table' )[ 0 ] ) !== c.table ) {
1403
+ if ( c.debug ) {
1404
+ console.error( 'addRows method requires (1) a jQuery selector reference to rows that have already ' +
1405
+ 'been added to the table, or (2) row HTML string to be added to a table with only one tbody' );
1406
+ }
1407
+ return false;
1408
+ }
1409
+ table.isUpdating = true;
1410
+ if ( ts.isEmptyObject( c.cache ) ) {
1411
+ // empty table, do an update instead - fixes #450
1412
+ updateHeader( table );
1413
+ commonUpdate( table, resort, callback );
1414
+ } else {
1415
+ rows = $row.filter( 'tr' ).attr( 'role', 'row' ).length;
1416
+ tbdy = c.$tbodies.index( $row.parents( 'tbody' ).filter( ':first' ) );
1417
+ // fixes adding rows to an empty table - see issue #179
1418
+ if ( !( c.parsers && c.parsers.length ) ) {
1419
+ buildParserCache( c );
1420
+ }
1421
+ // add each row
1422
+ for ( i = 0; i < rows; i++ ) {
1423
+ l = $row[ i ].cells.length;
1424
+ cells = [];
1425
+ rowData = {
1426
+ child: [],
1427
+ $row : $row.eq( i ),
1428
+ order: c.cache[ tbdy ].normalized.length
1429
+ };
1430
+ // add each cell
1431
+ for ( j = 0; j < l; j++ ) {
1432
+ cells[ j ] = ts.getParsedText( c, $row[ i ].cells[ j ], j );
1433
+ if ( ( c.parsers[ j ].type || '' ).toLowerCase() === 'numeric' ) {
1434
+ // update column max value (ignore sign)
1435
+ c.cache[ tbdy ].colMax[ j ] = Math.max( Math.abs( cells[ j ] ) || 0, c.cache[ tbdy ].colMax[ j ] || 0 );
1436
+ }
1437
+ }
1438
+ // add the row data to the end
1439
+ cells.push( rowData );
1440
+ // update cache
1441
+ c.cache[ tbdy ].normalized.push( cells );
1442
+ }
1443
+ // resort using current settings
1444
+ checkResort( c, resort, callback );
1445
+ }
1446
+ };
1447
+
1448
+ ts.updateCache = function( c, callback, $tbodies ) {
1449
+ // rebuild parsers
1450
+ if ( !( c.parsers && c.parsers.length ) ) {
1451
+ buildParserCache( c, $tbodies );
1452
+ }
1453
+ // rebuild the cache map
1454
+ buildCache( c.table, callback, $tbodies );
1455
+ };
1456
+
1457
+ // init flag (true) used by pager plugin to prevent widget application
1458
+ // renamed from appendToTable
1459
+ ts.appendCache = function( c, init ) {
1460
+ var n, totalRows, $bk, $tb, i, k, appendTime,
1461
+ table = c.table,
1462
+ wo = c.widgetOptions,
1463
+ $tbodies = c.$tbodies,
1464
+ rows = [],
1465
+ cc = c.cache;
1466
+ // empty table - fixes #206/#346
1467
+ if ( ts.isEmptyObject( cc ) ) {
1468
+ // run pager appender in case the table was just emptied
1469
+ return c.appender ? c.appender( table, rows ) :
1470
+ table.isUpdating ? c.$table.trigger( 'updateComplete', table ) : ''; // Fixes #532
1471
+ }
1472
+ if ( c.debug ) {
1473
+ appendTime = new Date();
1474
+ }
1475
+ for ( k = 0; k < $tbodies.length; k++ ) {
1476
+ $bk = $tbodies.eq( k );
1477
+ if ( $bk.length ) {
1478
+ // get tbody
1479
+ $tb = ts.processTbody( table, $bk, true );
1480
+ n = cc[ k ].normalized;
1481
+ totalRows = n.length;
1482
+ for ( i = 0; i < totalRows; i++ ) {
1483
+ rows.push( n[ i ][ c.columns ].$row );
1484
+ // removeRows used by the pager plugin; don't render if using ajax - fixes #411
1485
+ if ( !c.appender || ( c.pager && ( !c.pager.removeRows || !wo.pager_removeRows ) && !c.pager.ajax ) ) {
1486
+ $tb.append( n[ i ][ c.columns ].$row );
1487
+ }
1488
+ }
1489
+ // restore tbody
1490
+ ts.processTbody( table, $tb, false );
1491
+ }
1492
+ }
1493
+ if ( c.appender ) {
1494
+ c.appender( table, rows );
1495
+ }
1496
+ if ( c.debug ) {
1497
+ console.log( 'Rebuilt table' + ts.benchmark( appendTime ) );
1498
+ }
1499
+ // apply table widgets; but not before ajax completes
1500
+ if ( !init && !c.appender ) { ts.applyWidget( table ); }
1501
+ if ( table.isUpdating ) {
1502
+ c.$table.trigger( 'updateComplete', table );
1503
+ }
1504
+ };
1505
+
1506
+ ts.sortOn = function( c, list, callback, init ) {
1507
+ var table = c.table;
1508
+ c.$table.trigger( 'sortStart', table );
1509
+ // update header count index
1510
+ updateHeaderSortCount( table, list );
1511
+ // set css for headers
1512
+ setHeadersCss( table );
1513
+ // fixes #346
1514
+ if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
1515
+ buildCache( table );
1516
+ }
1517
+ c.$table.trigger( 'sortBegin', table );
1518
+ // sort the table and append it to the dom
1519
+ multisort( table );
1520
+ ts.appendCache( c, init );
1521
+ c.$table.trigger( 'sortEnd', table );
1522
+ ts.applyWidget( table );
1523
+ if ( $.isFunction( callback ) ) {
1524
+ callback( table );
1525
+ }
1526
+ };
1527
+
1465
1528
  // restore headers
1466
1529
  ts.restoreHeaders = function(table){
1467
1530
  var index, $cell,
@@ -1500,8 +1563,9 @@
1500
1563
  // remove widget added rows, just in case
1501
1564
  $h.find('tr').not($r).remove();
1502
1565
  // disable tablesorter
1503
- events = 'sortReset update updateAll updateRows updateCell addRows updateComplete sorton appendCache updateCache ' +
1504
- 'applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress sortBegin sortEnd resetToLoadState '.split(' ')
1566
+ events = 'sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton ' +
1567
+ 'appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress ' +
1568
+ 'sortBegin sortEnd resetToLoadState '.split(' ')
1505
1569
  .join(c.namespace + ' ');
1506
1570
  $t
1507
1571
  .removeData('tablesorter')
@@ -1923,7 +1987,7 @@
1923
1987
  allColumns = column === 'all',
1924
1988
  data = { raw : [], parsed: [], $cell: [] },
1925
1989
  c = table.config;
1926
- if ( isEmptyObject( c ) ) {
1990
+ if ( ts.isEmptyObject( c ) ) {
1927
1991
  if ( c.debug ) {
1928
1992
  console.warn( 'No cache found - aborting getColumnText function!' );
1929
1993
  }
@@ -2075,7 +2139,8 @@
2075
2139
  },
2076
2140
  format: function(s, table) {
2077
2141
  var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
2078
- return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
2142
+ return s && typeof n === 'number' ? n :
2143
+ s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
2079
2144
  },
2080
2145
  type: 'numeric'
2081
2146
  });
@@ -2083,11 +2148,14 @@
2083
2148
  ts.addParser({
2084
2149
  id: 'currency',
2085
2150
  is: function(s) {
2086
- return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test((s || '').replace(/[+\-,. ]/g, '')); // £$€¤¥¢
2151
+ s = (s || '').replace(/[+\-,. ]/g, '');
2152
+ // test for £$€¤¥¢
2153
+ return (/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/).test(s);
2087
2154
  },
2088
2155
  format: function(s, table) {
2089
2156
  var n = ts.formatFloat((s || '').replace(/[^\w,. \-()]/g, ''), table);
2090
- return s && typeof n === 'number' ? n : s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
2157
+ return s && typeof n === 'number' ? n :
2158
+ s ? $.trim( s && table.config.ignoreCase ? s.toLocaleLowerCase() : s ) : s;
2091
2159
  },
2092
2160
  type: 'numeric'
2093
2161
  });
@@ -2145,7 +2213,8 @@
2145
2213
  is: function(s) {
2146
2214
  // two digit years are not allowed cross-browser
2147
2215
  // Jan 01, 2013 12:34:56 PM or 01 Jan 2013
2148
- 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);
2216
+ 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) ||
2217
+ (/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i).test(s);
2149
2218
  },
2150
2219
  format: function(s, table) {
2151
2220
  var date = s ? new Date( s.replace(/(\S)([AP]M)$/i, '$1 $2') ) : s;
@@ -2157,16 +2226,20 @@
2157
2226
  ts.addParser({
2158
2227
  id: 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
2159
2228
  is: function(s) {
2229
+ s = (s || '').replace(/\s+/g, ' ').replace(/[\-.,]/g, '/');
2160
2230
  // testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
2161
- 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, '/'));
2231
+ return (/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/).test(s);
2162
2232
  },
2163
2233
  format: function(s, table, cell, cellIndex) {
2164
2234
  if (s) {
2165
2235
  var date, d,
2166
2236
  c = table.config,
2167
2237
  ci = c.$headerIndexed[ cellIndex ],
2168
- format = ci.length && ci[0].dateFormat || ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') || c.dateFormat;
2169
- d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/'); // escaped - because JSHint in Firefox was showing it as an error
2238
+ format = ci.length && ci[0].dateFormat ||
2239
+ ts.getData( ci, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat') ||
2240
+ c.dateFormat;
2241
+ // escaped "-" because JSHint in Firefox was showing it as an error
2242
+ d = s.replace(/\s+/g, ' ').replace(/[\-.,]/g, '/');
2170
2243
  if (format === 'mmddyyyy') {
2171
2244
  d = d.replace(/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/, '$3/$1/$2');
2172
2245
  } else if (format === 'ddmmyyyy') {
@@ -2605,7 +2678,7 @@
2605
2678
 
2606
2679
  })(jQuery);
2607
2680
 
2608
- /*! Widget: filter - updated 7/28/2015 (v2.22.4) *//*
2681
+ /*! Widget: filter - updated 8/17/2015 (v2.23.0) *//*
2609
2682
  * Requires tablesorter v2.8+ and jQuery 1.7+
2610
2683
  * by Rob Garrison
2611
2684
  */
@@ -3594,7 +3667,8 @@
3594
3667
  } else {
3595
3668
  if ( wo.filter_startsWith ) {
3596
3669
  showRow = false;
3597
- columnIndex = c.columns;
3670
+ // data.rowArray may not contain all columns
3671
+ columnIndex = Math.min( c.columns, data.rowArray.length );
3598
3672
  while ( !showRow && columnIndex > 0 ) {
3599
3673
  columnIndex--;
3600
3674
  showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0;