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.
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;