jquery-tablesorter 1.12.5 → 1.12.6

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: d3a2967474752c48b4b2bcd5743672332758b852
4
- data.tar.gz: e78a3ef07c01f2d563ee9df828b69ff6dec9d114
3
+ metadata.gz: dad82916aeb678dc8bf4d725a13478229aac98c6
4
+ data.tar.gz: be61736afbcfacfcfad39a3beedbe9d23c424b10
5
5
  SHA512:
6
- metadata.gz: 7290bf0447e717080dd596016945d29db62e82d586c32ad329d0177eb2691ca979729bb162d31f7e707f24a181df2385febb1e26e5d5a7cc89f3c16e14683e09
7
- data.tar.gz: 12387d4cfe2fa24a7ff2906002012a43afb7970fc91e432fa1caae5522e3206b3a41fb73e9acf612d526333039699ab683cc56eeb6bf01c3a5cffbc753989b9b
6
+ metadata.gz: b60c0de8ee6f20f55e5c1e393ca69a3f53d8fc50eef292152fcd57d18ef465ea64bb45b9dd00903483fb5aaf12f3cf833fab0cd0ec17d72f1bba02436417a83b
7
+ data.tar.gz: 13c349069d081c29bffffdac92708e18b6cfff3a8bdc9ccfe78e6a19072940a89a854527fae4a687ca53811637a1fbf8bdcb2f0d2b023e88107536607837acc4
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.17.5 (7/17/2014), [documentation]
7
+ Current tablesorter version: 2.17.6 (8/1/2014), [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.12.5'
2
+ VERSION = '1.12.6'
3
3
  end
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * tablesorter pager plugin
3
- * updated 7/17/2014 (v2.17.5)
3
+ * updated 8/1/2014 (v2.17.6)
4
4
  */
5
5
  /*jshint browser:true, jquery:true, unused:false */
6
6
  ;(function($) {
@@ -129,7 +129,7 @@
129
129
  },
130
130
 
131
131
  updatePageDisplay = function(table, p, completed) {
132
- var i, pg, s, out, regex,
132
+ var i, pg, s, $out, regex,
133
133
  c = table.config,
134
134
  f = c.$table.hasClass('hasFilters'),
135
135
  t = [],
@@ -159,7 +159,7 @@
159
159
  p.startRow = (t) ? 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1);
160
160
  p.page = (t) ? 0 : p.page;
161
161
  p.endRow = Math.min( p.filteredRows, p.totalRows, p.size * ( p.page + 1 ) );
162
- out = p.$container.find(p.cssPageDisplay);
162
+ $out = p.$container.find(p.cssPageDisplay);
163
163
  // form the output string (can now get a new output string from the server)
164
164
  s = ( p.ajaxData && p.ajaxData.output ? p.ajaxData.output || p.output : p.output )
165
165
  // {page} = one-based index; {page+#} = zero based index +/- value
@@ -168,15 +168,21 @@
168
168
  })
169
169
  // {totalPages}, {extra}, {extra:0} (array) or {extra : key} (object)
170
170
  .replace(/\{\w+(\s*:\s*\w+)?\}/gi, function(m){
171
- var str = m.replace(/[{}\s]/g,''),
171
+ var len, indx,
172
+ str = m.replace(/[{}\s]/g,''),
172
173
  extra = str.split(':'),
173
174
  data = p.ajaxData,
174
175
  // return zero for default page/row numbers
175
176
  deflt = /(rows?|pages?)$/i.test(str) ? 0 : '';
177
+ if (/(startRow|page)/.test(extra[0]) && extra[1] === 'input') {
178
+ len = ('' + (extra[0] === 'page' ? p.totalPages : p.totalRows)).length;
179
+ indx = extra[0] === 'page' ? p.page + 1 : p.startRow;
180
+ return '<input type="text" class="ts-' + extra[0] + '" style="max-width:' + len + 'em" value="' + indx + '"/>';
181
+ }
176
182
  return extra.length > 1 && data && data[extra[0]] ? data[extra[0]][extra[1]] : p[str] || (data ? data[str] : deflt) || deflt;
177
183
  });
178
- if (out.length) {
179
- out[ (out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
184
+ if ($out.length) {
185
+ $out[ ($out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
180
186
  if ( p.$goto.length ) {
181
187
  t = '';
182
188
  pg = Math.min( p.totalPages, p.filteredPages );
@@ -185,6 +191,12 @@
185
191
  }
186
192
  p.$goto.html(t).val( p.page + 1 );
187
193
  }
194
+ // rebind startRow/page inputs
195
+ $out.find('.ts-startRow, .ts-page').unbind('change').bind('change', function(){
196
+ var v = $(this).val(),
197
+ pg = $(this).hasClass('ts-startRow') ? Math.floor( v/p.size ) + 1 : v;
198
+ c.$table.trigger('pageSet.pager', [ pg ]);
199
+ });
188
200
  }
189
201
  }
190
202
  pagerArrows(p);
@@ -546,7 +558,7 @@
546
558
  }
547
559
  }
548
560
  // disable size selector
549
- p.$size.add(p.$goto).each(function(){
561
+ p.$size.add(p.$goto).add(p.$container.find('.ts-startRow, .ts-page')).each(function(){
550
562
  $(this).attr('aria-disabled', 'true').addClass(p.cssDisabled)[0].disabled = true;
551
563
  });
552
564
  },
@@ -665,7 +677,10 @@
665
677
  enablePager = function(table, p, triggered){
666
678
  var info,
667
679
  c = table.config;
668
- p.$size.add(p.$goto).removeClass(p.cssDisabled).removeAttr('disabled').attr('aria-disabled', 'false');
680
+ p.$size.add(p.$goto).add(p.$container.find('.ts-startRow, .ts-page'))
681
+ .removeClass(p.cssDisabled)
682
+ .removeAttr('disabled')
683
+ .attr('aria-disabled', 'false');
669
684
  p.isDisabled = false;
670
685
  p.page = $.data(table, 'pagerLastPage') || p.page || 0;
671
686
  p.size = $.data(table, 'pagerLastSize') || parseInt(p.$size.find('option[selected]').val(), 10) || p.size || 10;
@@ -827,6 +842,8 @@
827
842
  // page size selector
828
843
  p.$size = pager.find(p.cssPageSize);
829
844
  if ( p.$size.length ) {
845
+ // setting an option as selected appears to cause issues with initial page size
846
+ p.$size.find('option').removeAttr('selected');
830
847
  p.$size.unbind('change.pager').bind('change.pager', function() {
831
848
  p.$size.val( $(this).val() ); // in case there are more than one pagers
832
849
  if ( !$(this).hasClass(p.cssDisabled) ) {
@@ -1,5 +1,5 @@
1
1
  /**!
2
- * TableSorter 2.17.5 - Client-side table sorting with ease!
2
+ * TableSorter 2.17.6 - Client-side table sorting with ease!
3
3
  * @requires jQuery v1.2.6+
4
4
  *
5
5
  * Copyright (c) 2007 Christian Bach
@@ -24,7 +24,7 @@
24
24
 
25
25
  var ts = this;
26
26
 
27
- ts.version = "2.17.5";
27
+ ts.version = "2.17.6";
28
28
 
29
29
  ts.parsers = [];
30
30
  ts.widgets = [];
@@ -219,7 +219,7 @@
219
219
  var c = table.config,
220
220
  // update table bodies in case we start with an empty table
221
221
  tb = c.$tbodies = c.$table.children('tbody:not(.' + c.cssInfoBlock + ')'),
222
- rows, list, l, i, h, ch, np, p, time,
222
+ rows, list, l, i, h, ch, np, p, e, time,
223
223
  j = 0,
224
224
  parsersDebug = "",
225
225
  len = tb.length;
@@ -229,7 +229,10 @@
229
229
  time = new Date();
230
230
  log('Detecting parsers for each column');
231
231
  }
232
- list = [];
232
+ list = {
233
+ extractors: [],
234
+ parsers: []
235
+ };
233
236
  while (j < len) {
234
237
  rows = tb[j].rows;
235
238
  if (rows[j]) {
@@ -238,7 +241,8 @@
238
241
  h = c.$headers.filter('[data-column="' + i + '"]:last');
239
242
  // get column indexed table cell
240
243
  ch = ts.getColumnData( table, c.headers, i );
241
- // get column parser
244
+ // get column parser/extractor
245
+ e = ts.getParserById( ts.getData(h, ch, 'extractor') );
242
246
  p = ts.getParserById( ts.getData(h, ch, 'sorter') );
243
247
  np = ts.getData(h, ch, 'parser') === 'false';
244
248
  // empty cells behaviour - keeping emptyToBottom for backwards compatibility
@@ -248,31 +252,38 @@
248
252
  if (np) {
249
253
  p = ts.getParserById('no-parser');
250
254
  }
255
+ if (!e) {
256
+ // For now, maybe detect someday
257
+ e = false;
258
+ }
251
259
  if (!p) {
252
260
  p = detectParserForColumn(table, rows, -1, i);
253
261
  }
254
262
  if (c.debug) {
255
- parsersDebug += "column:" + i + "; parser:" + p.id + "; string:" + c.strings[i] + '; empty: ' + c.empties[i] + "\n";
263
+ parsersDebug += "column:" + i + "; extractor:" + e.id + "; parser:" + p.id + "; string:" + c.strings[i] + '; empty: ' + c.empties[i] + "\n";
256
264
  }
257
- list[i] = p;
265
+ list.parsers[i] = p;
266
+ list.extractors[i] = e;
258
267
  }
259
268
  }
260
- j += (list.length) ? len : 1;
269
+ j += (list.parsers.length) ? len : 1;
261
270
  }
262
271
  if (c.debug) {
263
272
  log(parsersDebug ? parsersDebug : "No parsers detected");
264
273
  benchmark("Completed detecting parsers", time);
265
274
  }
266
- c.parsers = list;
275
+ c.parsers = list.parsers;
276
+ c.extractors = list.extractors;
267
277
  }
268
278
 
269
279
  /* utils */
270
280
  function buildCache(table) {
271
- var cc, t, v, i, j, k, $row, rows, cols, cacheTime,
281
+ var cc, t, tx, v, i, j, k, $row, rows, cols, cacheTime,
272
282
  totalRows, rowData, colMax,
273
283
  c = table.config,
274
284
  $tb = c.$table.children('tbody'),
275
- parsers = c.parsers;
285
+ extractors = c.extractors,
286
+ parsers = c.parsers;
276
287
  c.cache = {};
277
288
  c.totalRows = 0;
278
289
  // if no parsers found, return - it's an empty table.
@@ -330,10 +341,16 @@
330
341
  continue;
331
342
  }
332
343
  t = getElementText(table, $row[0].cells[j], j);
344
+ // do extract before parsing if there is one
345
+ if (typeof extractors[j].id === 'undefined') {
346
+ tx = t;
347
+ } else {
348
+ tx = extractors[j].format(t, table, $row[0].cells[j], j);
349
+ }
333
350
  // allow parsing if the string is empty, previously parsing would change it to zero,
334
351
  // in case the parser needs to extract data from the table cell attributes
335
- v = parsers[j].id === 'no-parser' ? '' : parsers[j].format(t, table, $row[0].cells[j], j);
336
- cols.push(v);
352
+ v = parsers[j].id === 'no-parser' ? '' : parsers[j].format(tx, table, $row[0].cells[j], j);
353
+ cols.push( c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v );
337
354
  if ((parsers[j].type || '').toLowerCase() === "numeric") {
338
355
  // determine column max value (ignore sign)
339
356
  colMax[j] = Math.max(Math.abs(v) || 0, colMax[j] || 0);
@@ -379,6 +396,7 @@
379
396
  if ($bk.length && !$bk.hasClass(c.cssInfoBlock)) {
380
397
  // get tbody
381
398
  $tb = ts.processTbody(table, $bk, true);
399
+ $tb.children().detach(); // remove rows
382
400
  n = cc[k].normalized;
383
401
  totalRows = n.length;
384
402
  for (i = 0; i < totalRows; i++) {
@@ -423,7 +441,8 @@
423
441
  c.columns = ts.computeColumnIndex( c.$table.children('thead, tfoot').children('tr') );
424
442
  // add icon if cssIcon option exists
425
443
  i = c.cssIcon ? '<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' : '';
426
- c.$headers.each(function(index) {
444
+ // redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683
445
+ c.$headers = $(table).find(c.selectorHeaders).each(function(index) {
427
446
  $t = $(this);
428
447
  // make sure to get header cell & not column indexed cell
429
448
  ch = ts.getColumnData( table, c.headers, index, true );
@@ -477,11 +496,13 @@
477
496
  }
478
497
 
479
498
  function updateHeader(table) {
480
- var s, $th,
499
+ var s, $th, col,
481
500
  c = table.config;
482
501
  c.$headers.each(function(index, th){
483
502
  $th = $(th);
484
- s = ts.getData( th, ts.getColumnData( table, c.headers, index, true ), 'sorter' ) === 'false';
503
+ col = ts.getColumnData( table, c.headers, index, true );
504
+ // add "sorter-false" class if "parser-false" is set
505
+ s = ts.getData( th, col, 'sorter' ) === 'false' || ts.getData( th, col, 'parser' ) === 'false';
485
506
  th.sortDisabled = s;
486
507
  $th[ s ? 'addClass' : 'removeClass' ]('sorter-false').attr('aria-disabled', '' + s);
487
508
  // aria-controls - requires table ID
@@ -544,7 +565,7 @@
544
565
  var colgroup = $('<colgroup>'),
545
566
  overallWidth = $(table).width();
546
567
  // only add col for visible columns - fixes #371
547
- $(table.tBodies[0]).find("tr:first").children("td:visible").each(function() {
568
+ $(table.tBodies[0]).find("tr:first").children(":visible").each(function() {
548
569
  colgroup.append($('<col>').css('width', parseInt(($(this).width()/overallWidth)*1000, 10)/10 + '%'));
549
570
  });
550
571
  $(table).prepend(colgroup);
@@ -601,6 +622,10 @@
601
622
  }
602
623
 
603
624
  function initSort(table, cell, event){
625
+ if (table.isUpdating) {
626
+ // let any updates complete before initializing a sort
627
+ return setTimeout(function(){ initSort(table, cell, event); }, 50);
628
+ }
604
629
  var arry, indx, col, order, s,
605
630
  c = table.config,
606
631
  key = !event[c.sortMultiSortKey],
@@ -833,7 +858,7 @@
833
858
  table.isUpdating = true;
834
859
  $table.find(c.selectorRemove).remove();
835
860
  // get position from the dom
836
- var v, row, icell,
861
+ var v, t, row, icell,
837
862
  $tb = $table.find('tbody'),
838
863
  $cell = $(cell),
839
864
  // update cache - format: function(s, table, cell, cellIndex)
@@ -846,8 +871,14 @@
846
871
  row = $tb.eq(tbdy).find('tr').index( $row );
847
872
  icell = $cell.index();
848
873
  c.cache[tbdy].normalized[row][c.columns].$row = $row;
849
- v = c.cache[tbdy].normalized[row][icell] = c.parsers[icell].id === 'no-parser' ? '' :
850
- c.parsers[icell].format( getElementText(table, cell, icell), table, cell, icell );
874
+ if (typeof c.extractors[icell].id === 'undefined') {
875
+ t = getElementText(table, cell, icell);
876
+ } else {
877
+ t = c.extractors[icell].format( getElementText(table, cell, icell), table, cell, icell );
878
+ }
879
+ v = c.parsers[icell].id === 'no-parser' ? '' :
880
+ c.parsers[icell].format( t, table, cell, icell );
881
+ c.cache[tbdy].normalized[row][icell] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
851
882
  if ((c.parsers[icell].type || '').toLowerCase() === "numeric") {
852
883
  // update column max value (ignore sign)
853
884
  c.cache[tbdy].colMax[icell] = Math.max(Math.abs(v) || 0, c.cache[tbdy].colMax[icell] || 0);
@@ -863,8 +894,8 @@
863
894
  updateHeader(table);
864
895
  commonUpdate(table, resort, callback);
865
896
  } else {
866
- $row = $($row); // make sure we're using a jQuery object
867
- var i, j, l, rowData, cells,
897
+ $row = $($row).attr('role', 'row'); // make sure we're using a jQuery object
898
+ var i, j, l, t, v, rowData, cells,
868
899
  rows = $row.filter('tr').length,
869
900
  tbdy = $table.find('tbody').index( $row.parents('tbody').filter(':first') );
870
901
  // fixes adding rows to an empty table - see issue #179
@@ -882,8 +913,14 @@
882
913
  };
883
914
  // add each cell
884
915
  for (j = 0; j < l; j++) {
885
- cells[j] = c.parsers[j].id === 'no-parser' ? '' :
886
- c.parsers[j].format( getElementText(table, $row[i].cells[j], j), table, $row[i].cells[j], j );
916
+ if (typeof c.extractors[j].id === 'undefined') {
917
+ t = getElementText(table, $row[i].cells[j], j);
918
+ } else {
919
+ t = c.extractors[j].format( getElementText(table, $row[i].cells[j], j), table, $row[i].cells[j], j );
920
+ }
921
+ v = c.parsers[j].id === 'no-parser' ? '' :
922
+ c.parsers[j].format( t, table, $row[i].cells[j], j );
923
+ cells[j] = c.ignoreCase && typeof v === 'string' ? v.toLowerCase() : v;
887
924
  if ((c.parsers[j].type || '').toLowerCase() === "numeric") {
888
925
  // update column max value (ignore sign)
889
926
  c.cache[tbdy].colMax[j] = Math.max(Math.abs(cells[j]) || 0, c.cache[tbdy].colMax[j] || 0);
@@ -1019,8 +1056,8 @@
1019
1056
  c.table = table;
1020
1057
  c.$table = $table
1021
1058
  .addClass(ts.css.table + ' ' + c.tableClass + k)
1022
- .attr({ role : 'grid'});
1023
- c.$headers = $(table).find(c.selectorHeaders);
1059
+ .attr('role', 'grid');
1060
+ c.$headers = $table.find(c.selectorHeaders);
1024
1061
 
1025
1062
  // give the table a unique id, which will be used in namespace binding
1026
1063
  if (!c.namespace) {
@@ -1030,6 +1067,7 @@
1030
1067
  c.namespace = '.' + c.namespace.replace(/\W/g,'');
1031
1068
  }
1032
1069
 
1070
+ c.$table.children().children('tr').attr('role', 'row');
1033
1071
  c.$tbodies = $table.children('tbody:not(.' + c.cssInfoBlock + ')').attr({
1034
1072
  'aria-live' : 'polite',
1035
1073
  'aria-relevant' : 'all'
@@ -1,4 +1,4 @@
1
- /*! tableSorter 2.16+ widgets - updated 7/17/2014 (v2.17.5)
1
+ /*! tableSorter 2.16+ widgets - updated 8/1/2014 (v2.17.6)
2
2
  *
3
3
  * Column Styles
4
4
  * Column Filters
@@ -131,6 +131,7 @@ ts.storage = function(table, key, value, options) {
131
131
  // Add a resize event to table headers
132
132
  // **************************
133
133
  ts.addHeaderResizeEvent = function(table, disable, settings) {
134
+ table = $(table)[0]; // make sure we're usig a dom element
134
135
  var headers,
135
136
  defaults = {
136
137
  timer : 250
@@ -371,7 +372,8 @@ ts.addWidget({
371
372
  filter_startsWith : false, // if true, filter start from the beginning of the cell contents
372
373
  filter_useParsedData : false, // filter all data using parsed content
373
374
  filter_serversideFiltering : false, // if true, server-side filtering should be performed because client-side filtering will be disabled, but the ui and events will still be used.
374
- filter_defaultAttrib : 'data-value' // data attribute in the header cell that contains the default filter value
375
+ filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value
376
+ filter_selectSourceSeparator : '|' // filter_selectSource array text left of the separator is added to the option value, right into the option text
375
377
  },
376
378
  format: function(table, c, wo) {
377
379
  if (!c.$table.hasClass('hasFilters')) {
@@ -565,7 +567,7 @@ ts.filter = {
565
567
  and : 'and'
566
568
  }, ts.language);
567
569
 
568
- var options, string, $header, column, filters, time, fxn,
570
+ var options, string, txt, $header, column, filters, val, time, fxn, noSelect,
569
571
  regex = ts.filter.regex;
570
572
  if (c.debug) {
571
573
  time = new Date();
@@ -590,7 +592,7 @@ ts.filter = {
590
592
  });
591
593
 
592
594
  // don't build filter row if columnFilters is false or all columns are set to "filter-false" - issue #156
593
- if (wo.filter_columnFilters !== false && c.$headers.filter('.filter-false').length !== c.$headers.length) {
595
+ if (wo.filter_columnFilters !== false && c.$headers.filter('.filter-false, .parser-false').length !== c.$headers.length) {
594
596
  // build filter row
595
597
  ts.filter.buildRow(table, c, wo);
596
598
  }
@@ -642,17 +644,27 @@ ts.filter = {
642
644
  for (column = 0; column < c.columns; column++) {
643
645
  fxn = ts.getColumnData( table, wo.filter_functions, column );
644
646
  if (fxn) {
645
- $header = c.$headers.filter('[data-column="' + column + '"]:last');
647
+ // remove "filter-select" from header otherwise the options added here are replaced with all options
648
+ $header = c.$headers.filter('[data-column="' + column + '"]:last').removeClass('filter-select');
649
+ // don't build select if "filter-false" or "parser-false" set
650
+ noSelect = !($header.hasClass('filter-false') || $header.hasClass('parser-false'));
646
651
  options = '';
647
- if (fxn === true && !$header.hasClass('filter-false')) {
652
+ if ( fxn === true && noSelect ) {
648
653
  ts.filter.buildSelect(table, column);
649
- } else if (typeof fxn === 'object' && !$header.hasClass('filter-false')) {
654
+ } else if ( typeof fxn === 'object' && noSelect ) {
650
655
  // add custom drop down list
651
656
  for (string in fxn) {
652
657
  if (typeof string === 'string') {
653
658
  options += options === '' ?
654
659
  '<option value="">' + ($header.data('placeholder') || $header.attr('data-placeholder') || wo.filter_placeholder.select || '') + '</option>' : '';
655
- options += '<option value="' + string + '">' + string + '</option>';
660
+ val = string;
661
+ txt = string;
662
+ if (string.indexOf(wo.filter_selectSourceSeparator) >= 0) {
663
+ val = string.split(wo.filter_selectSourceSeparator);
664
+ txt = val[1];
665
+ val = val[0];
666
+ }
667
+ options += '<option ' + (txt === val ? '' : 'data-function-name="' + string + '" ') + 'value="' + val + '">' + txt + '</option>';
656
668
  }
657
669
  }
658
670
  c.$table.find('thead').find('select.' + ts.css.filter + '[data-column="' + column + '"]').append(options);
@@ -691,7 +703,7 @@ ts.filter = {
691
703
  ts.benchmark("Applying Filter widget", time);
692
704
  }
693
705
  // add default values
694
- c.$table.bind('tablesorter-initialized pagerInitialized', function(e) {
706
+ c.$table.bind('tablesorter-initialized pagerInitialized', function() {
695
707
  // redefine "wo" as it does not update properly inside this callback
696
708
  var wo = this.config.widgetOptions;
697
709
  filters = ts.filter.setDefaults(table, c, wo) || [];
@@ -775,10 +787,10 @@ ts.filter = {
775
787
  filter;
776
788
  },
777
789
  buildRow: function(table, c, wo) {
778
- var column, $header, buildSelect, disabled, name, ffxn,
790
+ var col, column, $header, buildSelect, disabled, name, ffxn,
779
791
  // c.columns defined in computeThIndexes()
780
792
  columns = c.columns,
781
- buildFilter = '<tr class="' + ts.css.filterRow + '">';
793
+ buildFilter = '<tr role="row" class="' + ts.css.filterRow + '">';
782
794
  for (column = 0; column < columns; column++) {
783
795
  buildFilter += '<td></td>';
784
796
  }
@@ -792,7 +804,8 @@ ts.filter = {
792
804
  buildSelect = (wo.filter_functions && ffxn && typeof ffxn !== "function" ) ||
793
805
  $header.hasClass('filter-select');
794
806
  // get data from jQuery data, metadata, headers option or header class name
795
- disabled = ts.getData($header[0], ts.getColumnData( table, c.headers, column ), 'filter') === 'false';
807
+ col = ts.getColumnData( table, c.headers, column );
808
+ disabled = ts.getData($header[0], col, 'filter') === 'false' || ts.getData($header[0], col, 'parser') === 'false';
796
809
 
797
810
  if (buildSelect) {
798
811
  buildFilter = $('<select>').appendTo( c.$filters.eq(column) );
@@ -983,7 +996,7 @@ ts.filter = {
983
996
  var cached, len, $rows, rowIndex, tbodyIndex, $tbody, $cells, columnIndex,
984
997
  childRow, childRowText, exact, iExact, iFilter, lastSearch, matches, result,
985
998
  notFiltered, searchFiltered, filterMatched, showRow, time, val, indx,
986
- anyMatch, iAnyMatch, rowArray, rowText, iRowText, rowCache, fxn,
999
+ anyMatch, iAnyMatch, rowArray, rowText, iRowText, rowCache, fxn, ffxn,
987
1000
  regex = ts.filter.regex,
988
1001
  c = table.config,
989
1002
  wo = c.widgetOptions,
@@ -1098,7 +1111,16 @@ ts.filter = {
1098
1111
  if (filterMatched !== null) {
1099
1112
  showRow = filterMatched;
1100
1113
  } else {
1101
- showRow = (iRowText + childRowText).indexOf(iAnyMatch) >= 0;
1114
+ if (wo.filter_startsWith) {
1115
+ showRow = false;
1116
+ columnIndex = columns;
1117
+ while (!showRow && columnIndex > 0) {
1118
+ columnIndex--;
1119
+ showRow = showRow || rowArray[columnIndex].indexOf(iAnyMatch) === 0;
1120
+ }
1121
+ } else {
1122
+ showRow = (iRowText + childRowText).indexOf(iAnyMatch) >= 0;
1123
+ }
1102
1124
  }
1103
1125
  }
1104
1126
 
@@ -1117,6 +1139,9 @@ ts.filter = {
1117
1139
  iExact = !regex.type.test(typeof exact) && wo.filter_ignoreCase ? exact.toLocaleLowerCase() : exact;
1118
1140
  result = showRow; // if showRow is true, show that row
1119
1141
 
1142
+ // in case select filter option has a different value vs text "a - z|A through Z"
1143
+ ffxn = c.$filters.eq(columnIndex).find('select option:selected').attr('data-function-name') || '';
1144
+
1120
1145
  // replace accents - see #357
1121
1146
  filters[columnIndex] = c.sortLocaleCompare ? ts.replaceAccents(filters[columnIndex]) : filters[columnIndex];
1122
1147
  // val = case insensitive, filters[columnIndex] = case sensitive
@@ -1130,9 +1155,9 @@ ts.filter = {
1130
1155
  } else if (typeof fxn === 'function') {
1131
1156
  // filter callback( exact cell content, parser normalized content, filter input value, column index, jQuery row object )
1132
1157
  result = fxn(exact, cached, filters[columnIndex], columnIndex, $rows.eq(rowIndex));
1133
- } else if (typeof fxn[filters[columnIndex]] === 'function') {
1158
+ } else if (typeof fxn[ffxn || filters[columnIndex]] === 'function') {
1134
1159
  // selector option function
1135
- result = fxn[filters[columnIndex]](exact, cached, filters[columnIndex], columnIndex, $rows.eq(rowIndex));
1160
+ result = fxn[ffxn || filters[columnIndex]](exact, cached, filters[columnIndex], columnIndex, $rows.eq(rowIndex));
1136
1161
  }
1137
1162
  } else {
1138
1163
  filterMatched = null;
@@ -1189,12 +1214,22 @@ ts.filter = {
1189
1214
  parsed = [],
1190
1215
  arry = false,
1191
1216
  source = wo.filter_selectSource,
1217
+ last = c.$table.data('lastSearch') || [],
1192
1218
  fxn = $.isFunction(source) ? true : ts.getColumnData( table, source, column );
1193
1219
 
1220
+ if (onlyAvail && last[column] !== '') {
1221
+ onlyAvail = false;
1222
+ }
1223
+
1194
1224
  // filter select source option
1195
1225
  if (fxn === true) {
1196
1226
  // OVERALL source
1197
1227
  arry = source(table, column, onlyAvail);
1228
+ } else if ( fxn instanceof $ || ($.type(fxn) === 'string' && fxn.indexOf('</option>') >= 0) ) {
1229
+ // selectSource is a jQuery object or string of options
1230
+ return fxn;
1231
+ } else if ($.isArray(fxn)) {
1232
+ arry = fxn;
1198
1233
  } else if ($.type(source) === 'object' && fxn) {
1199
1234
  // custom select source function for a SPECIFIC COLUMN
1200
1235
  arry = fxn(table, column, onlyAvail);
@@ -1278,46 +1313,73 @@ ts.filter = {
1278
1313
  }
1279
1314
  return arry;
1280
1315
  },
1281
- buildSelect: function(table, column, updating, onlyAvail) {
1282
- if (!table.config.cache || $.isEmptyObject(table.config.cache)) { return; }
1316
+ buildSelect: function(table, column, arry, updating, onlyAvail) {
1317
+ table = $(table)[0];
1283
1318
  column = parseInt(column, 10);
1284
- var indx, txt, $filters,
1319
+ if (!table.config.cache || $.isEmptyObject(table.config.cache)) { return; }
1320
+ var indx, val, txt, t, $filters, $filter,
1285
1321
  c = table.config,
1286
1322
  wo = c.widgetOptions,
1287
1323
  node = c.$headers.filter('[data-column="' + column + '"]:last'),
1288
1324
  // t.data('placeholder') won't work in jQuery older than 1.4.3
1289
1325
  options = '<option value="">' + ( node.data('placeholder') || node.attr('data-placeholder') || wo.filter_placeholder.select || '' ) + '</option>',
1290
- arry = ts.filter.getOptionSource(table, column, onlyAvail),
1291
1326
  // Get curent filter value
1292
1327
  currentValue = c.$table.find('thead').find('select.' + ts.css.filter + '[data-column="' + column + '"]').val();
1328
+ // nothing included in arry (external source), so get the options from filter_selectSource or column data
1329
+ if (typeof arry === 'undefined' || arry === '') {
1330
+ arry = ts.filter.getOptionSource(table, column, onlyAvail);
1331
+ }
1293
1332
 
1294
- // build option list
1295
- for (indx = 0; indx < arry.length; indx++) {
1296
- txt = arry[indx].replace(/\"/g, "&quot;");
1297
- // replace quotes - fixes #242 & ignore empty strings - see http://stackoverflow.com/q/14990971/145346
1298
- options += arry[indx] !== '' ? '<option value="' + txt + '"' + (currentValue === txt ? ' selected="selected"' : '') +
1299
- '>' + arry[indx] + '</option>' : '';
1333
+ if ($.isArray(arry)) {
1334
+ // build option list
1335
+ for (indx = 0; indx < arry.length; indx++) {
1336
+ txt = arry[indx] = ('' + arry[indx]).replace(/\"/g, "&quot;");
1337
+ val = txt;
1338
+ // allow including a symbol in the selectSource array
1339
+ // "a-z|A through Z" so that "a-z" becomes the option value
1340
+ // and "A through Z" becomes the option text
1341
+ if (txt.indexOf(wo.filter_selectSourceSeparator) >= 0) {
1342
+ t = txt.split(wo.filter_selectSourceSeparator);
1343
+ val = t[0];
1344
+ txt = t[1];
1345
+ }
1346
+ // replace quotes - fixes #242 & ignore empty strings - see http://stackoverflow.com/q/14990971/145346
1347
+ options += arry[indx] !== '' ? '<option ' + (val === txt ? '' : 'data-function-name="' + arry[indx] + '" ') + 'value="' + val + '">' + txt + '</option>' : '';
1348
+ }
1349
+ // clear arry so it doesn't get appended twice
1350
+ arry = [];
1300
1351
  }
1352
+
1301
1353
  // update all selects in the same column (clone thead in sticky headers & any external selects) - fixes 473
1302
1354
  $filters = ( c.$filters ? c.$filters : c.$table.children('thead') ).find('.' + ts.css.filter);
1303
1355
  if (wo.filter_$externalFilters) {
1304
1356
  $filters = $filters && $filters.length ? $filters.add(wo.filter_$externalFilters) : wo.filter_$externalFilters;
1305
1357
  }
1306
- $filters.filter('select[data-column="' + column + '"]')[ updating ? 'html' : 'append' ](options);
1307
- if (!wo.filter_functions) { wo.filter_functions = {}; }
1308
- wo.filter_functions[column] = true;
1358
+ $filter = $filters.filter('select[data-column="' + column + '"]');
1359
+
1360
+ // make sure there is a select there!
1361
+ if ($filter.length) {
1362
+ $filter[ updating ? 'html' : 'append' ](options);
1363
+ if (!$.isArray(arry)) {
1364
+ // append options if arry is provided externally as a string or jQuery object
1365
+ // options (default value) was already added
1366
+ $filter.append(arry).val(currentValue);
1367
+ }
1368
+ $filter.val(currentValue);
1369
+ }
1309
1370
  },
1310
1371
  buildDefault: function(table, updating) {
1311
- var columnIndex, $header,
1372
+ var columnIndex, $header, noSelect,
1312
1373
  c = table.config,
1313
1374
  wo = c.widgetOptions,
1314
1375
  columns = c.columns;
1315
1376
  // build default select dropdown
1316
1377
  for (columnIndex = 0; columnIndex < columns; columnIndex++) {
1317
1378
  $header = c.$headers.filter('[data-column="' + columnIndex + '"]:last');
1379
+ noSelect = !($header.hasClass('filter-false') || $header.hasClass('parser-false'));
1318
1380
  // look for the filter-select class; build/update it if found
1319
- if (($header.hasClass('filter-select') || ts.getColumnData( table, wo.filter_functions, columnIndex ) === true) && !$header.hasClass('filter-false')) {
1320
- ts.filter.buildSelect(table, columnIndex, updating, $header.hasClass(wo.filter_onlyAvail));
1381
+ if (($header.hasClass('filter-select') || ts.getColumnData( table, wo.filter_functions, columnIndex ) === true) && noSelect) {
1382
+ ts.filter.buildSelect(table, columnIndex, '', updating, $header.hasClass(wo.filter_onlyAvail));
1321
1383
  }
1322
1384
  }
1323
1385
  }
@@ -71,7 +71,6 @@
71
71
  var date = s.replace(/\s+/g," ").replace(/[\-.,]/g, "/").match(/(\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i);
72
72
  if (date) {
73
73
  date = date[0].replace(/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/, "$2/$3/$1");
74
- console.log(date);
75
74
  return $.tablesorter.formatFloat((new Date(date).getTime() || ''), table) || s;
76
75
  }
77
76
  return s;
@@ -1,5 +1,5 @@
1
1
  /*! input & select parsers for jQuery 1.7+ & tablesorter 2.7.11+
2
- * Updated 7/17/2014 (v2.17.5)
2
+ * Updated 8/1/2014 (v2.17.6)
3
3
  * Demo: http://mottie.github.com/tablesorter/docs/example-widget-grouping.html
4
4
  */
5
5
  /*jshint browser: true, jquery:true, unused:false */
@@ -78,6 +78,20 @@
78
78
  type: "text"
79
79
  });
80
80
 
81
+ // Custom parser for parsing textarea values
82
+ // updated dynamically using the "change" function below
83
+ $.tablesorter.addParser({
84
+ id: "textarea",
85
+ is: function(){
86
+ return false;
87
+ },
88
+ format: function(s, table, cell) {
89
+ return $(cell).find('textarea').val() || s;
90
+ },
91
+ parsed : true, // filter widget flag
92
+ type: "text"
93
+ });
94
+
81
95
  // update select and all input types in the tablesorter cache when the change event fires.
82
96
  // This method only works with jQuery 1.7+
83
97
  // you can change it to use delegate (v1.4.3+) or live (v1.3+) as desired
@@ -86,10 +100,36 @@
86
100
  $('table').on('tablesorter-initialized', function(){
87
101
  // this flag prevents the updateCell event from being spammed
88
102
  // it happens when you modify input text and hit enter
89
- var alreadyUpdating = false;
103
+ var focused = false,
104
+ restoreValue = function(){
105
+ // focused = false; // uncomment this line to prevent auto-accepting changes
106
+ // make sure we restore original values
107
+ $(':focus').blur();
108
+ return;
109
+ };
90
110
  // bind to .tablesorter (default class name)
91
- $(this).children('tbody').on('change', 'select, input', function(e){
92
- if (!alreadyUpdating) {
111
+ $(this).children('tbody')
112
+ .on('mouseleave', function(){
113
+ restoreValue();
114
+ })
115
+ .on('focus', 'select, input, textarea', function(){
116
+ focused = true;
117
+ $(this).data('ts-original-value', this.value);
118
+ })
119
+ .on('blur', 'input, textarea', function(){
120
+ // restore input value;
121
+ // "change" is triggered before "blur" so this doesn't replace the new update with the original
122
+ this.value = $(this).data('ts-original-value');
123
+ })
124
+ .on('change keyup', 'select, input, textarea', function(e){
125
+ if ( e.which === 27 ) {
126
+ // escape: restore original value
127
+ this.value = $(this).data('ts-original-value');
128
+ return;
129
+ }
130
+ // Update cell cache using... select: change, input: enter or textarea: alt + enter
131
+ if ( ( e.type === 'change' && focused ) ||
132
+ ( e.type === 'keyup' && e.which === 13 && ( e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' && e.altKey ) ) ) {
93
133
  var $tar = $(e.target),
94
134
  $cell = $tar.closest('td'),
95
135
  $table = $cell.closest('table'),
@@ -98,14 +138,17 @@
98
138
  $hdr = c && c.$headers && c.$headers.eq(indx);
99
139
  // abort if not a tablesorter table, or
100
140
  // don't use updateCell if column is set to "sorter-false" and "filter-false", or column is set to "parser-false"
101
- if ( !c || ( $hdr && $hdr.length && ( $hdr.hasClass('parser-false') || ($hdr.hasClass('sorter-false') && $hdr.hasClass('filter-false')) ) ) ){
102
- return false;
141
+ if ( !c || ( $hdr && $hdr.length && ( $hdr.hasClass('parser-false') || ( $hdr.hasClass('sorter-false') && $hdr.hasClass('filter-false') ) ) ) ) {
142
+ return restoreValue();
143
+ }
144
+ // ignore change event if nothing changed
145
+ if ($tar.val() !== $tar.data('ts-original-value')) {
146
+ $tar.data('ts-original-value', $tar.val());
147
+ $table.trigger('updateCell', [ $tar.closest('td'), resort, function(){
148
+ updateServer(e, $table, $tar);
149
+ setTimeout(function(){ focused = false; }, 10);
150
+ } ]);
103
151
  }
104
- alreadyUpdating = true;
105
- $table.trigger('updateCell', [ $tar.closest('td'), resort, function(){
106
- updateServer(e, $table, $tar);
107
- setTimeout(function(){ alreadyUpdating = false; }, 10);
108
- } ]);
109
152
  }
110
153
  });
111
154
  });
@@ -1,4 +1,4 @@
1
- /*! tablesorter Editable Content widget - updated 1/24/2014 (core v2.15.0)
1
+ /*! tablesorter Editable Content widget - updated 8/1/2014 (core v2.17.6)
2
2
  * Requires tablesorter v2.8+ and jQuery 1.7+
3
3
  * by Rob Garrison
4
4
  */
@@ -12,76 +12,100 @@
12
12
  options : {
13
13
  editable_columns : [],
14
14
  editable_enterToAccept : true,
15
+ editable_autoAccept : true,
15
16
  editable_autoResort : false,
17
+ editable_validate : null, // function(text, originalText){ return text; }
16
18
  editable_noEdit : 'no-edit',
17
19
  editable_editComplete : 'editComplete'
18
20
  },
19
21
  init: function(table, thisWidget, c, wo){
20
- if (!wo.editable_columns.length) { return; }
21
- var indx, tmp, $t, cols = [];
22
- if (wo.editable_columns.indexOf('-') >= 0) {
22
+ if ( !wo.editable_columns.length ) { return; }
23
+ var indx, tmp, $t,
24
+ cols = [];
25
+ if ( $.type(wo.editable_columns) === "string" && wo.editable_columns.indexOf('-') >= 0 ) {
23
26
  // editable_columns can contain a range string (i.e. "2-4" )
24
27
  tmp = wo.editable_columns.split('-');
25
28
  indx = parseInt(tmp[0],10) || 0;
26
29
  tmp = parseInt(tmp[1],10) || (c.columns - 1);
27
- if (tmp > c.columns) { tmp = c.columns - 1; }
28
- for (; indx <= tmp; indx++) {
30
+ if ( tmp > c.columns ) { tmp = c.columns - 1; }
31
+ for ( ; indx <= tmp; indx++ ) {
29
32
  cols.push('td:nth-child(' + (indx + 1) + ')');
30
33
  }
31
- } else if ($.isArray(wo.editable_columns)) {
34
+ } else if ( $.isArray(wo.editable_columns) ) {
32
35
  $.each(wo.editable_columns, function(i, col){
33
- cols.push('td:nth-child(' + (col + 1) + ')');
36
+ if ( col < c.columns ) {
37
+ cols.push('td:nth-child(' + (col + 1) + ')');
38
+ }
34
39
  });
35
40
  }
36
41
  // IE does not allow making TR/TH/TD cells directly editable (issue #404)
37
42
  // so add a div or span inside ( it's faster than using wrapInner() )
38
- c.$tbodies.find( cols.join(',') ).not('.' + wo.editable_noEdit).each(function(){
43
+ c.$tbodies.find( cols.join(',') ).not( '.' + wo.editable_noEdit ).each(function(){
39
44
  // test for children, if they exist, then make the children editable
40
45
  $t = $(this);
41
- ( $t.children().length ? $t.children() : $t ).prop('contenteditable', true);
46
+ ( $t.children().length ? $t.children() : $t ).prop( 'contenteditable', true );
42
47
  });
43
48
  c.$tbodies
44
49
  .on('mouseleave.tseditable', function(){
45
- if (c.$table.data('contentFocused')) {
50
+ if ( c.$table.data('contentFocused') ) {
51
+ // change to "true" instead of element to allow focusout to process
52
+ c.$table.data( 'contentFocused', true );
46
53
  $(':focus').trigger('blur');
47
54
  }
48
55
  })
49
- .on('focus.tseditable', '[contenteditable]', function(){
50
- c.$table.data('contentFocused', true);
51
- var $this = $(this), v = $this.html();
56
+ .on('focus.tseditable', '[contenteditable]', function(e){
57
+ c.$table.data( 'contentFocused', e.target );
58
+ var $this = $(this),
59
+ v = $this.html();
52
60
  if (wo.editable_enterToAccept) {
53
61
  // prevent enter from adding into the content
54
62
  $this.on('keydown.tseditable', function(e){
55
- if (e.which === 13) {
63
+ if ( e.which === 13 ) {
56
64
  e.preventDefault();
57
65
  }
58
66
  });
59
67
  }
60
68
  $this.data({ before : v, original: v });
61
69
  })
62
- .on('blur focusout keyup '.split(' ').join('.tseditable '), '[contenteditable]', function(e){
63
- if (!c.$table.data('contentFocused')) { return; }
64
- var $this = $(e.target), t;
65
- if (e.which === 27) {
70
+ .on('blur focusout keydown '.split(' ').join('.tseditable '), '[contenteditable]', function(e){
71
+ if ( !c.$table.data('contentFocused') ) { return; }
72
+ var t,
73
+ valid = false,
74
+ $this = $(e.target);
75
+ if ( e.which === 27 ) {
66
76
  // user cancelled
67
77
  $this.html( $this.data('original') ).trigger('blur.tseditable');
68
- c.$table.data('contentFocused', false);
78
+ c.$table.data( 'contentFocused', false );
69
79
  return false;
70
80
  }
71
- t = e.type !== 'keyup' || (wo.editable_enterToAccept && e.which === 13);
81
+ t = e.which === 13 && ( wo.editable_enterToAccept || e.altKey ) || wo.editable_autoAccept && e.type !== 'keydown';
72
82
  // change if new or user hits enter (if option set)
73
- if ($this.data('before') !== $this.html() || t) {
74
- $this.data('before', $this.html()).trigger('change');
75
- if (t) {
76
- c.$table
77
- .data('contentFocused', false)
78
- .trigger('updateCell', [ $this.closest('td'), wo.editable_autoResort, function(table){
79
- $this.trigger( wo.editable_editComplete );
83
+ if ( t && $this.data('before') !== $this.html() ) {
84
+ valid = $.isFunction(wo.editable_validate) ? wo.editable_validate( $this.html(), $this.data('original') ) : $this.html();
85
+ if ( t && valid !== false ) {
86
+ $this
87
+ .html( valid )
88
+ .data('before', valid)
89
+ .trigger('change');
90
+ c.$table.trigger('updateCell', [ $this.closest('td'), wo.editable_autoResort, function(table){
91
+ $this.trigger( wo.editable_editComplete, [c] );
92
+ $this.data( 'original', $this.html() );
93
+ if ( wo.editable_autoResort && c.sortList.length ) {
80
94
  c.$table.trigger('applyWidgets');
81
- } ]);
82
- $this.trigger('blur.tseditable');
95
+ }
96
+ // restore focus last cell after updating
97
+ setTimeout(function(){
98
+ var t = c.$table.data('contentFocused');
99
+ if ( t instanceof HTMLElement ) { t.focus(); }
100
+ }, 50);
101
+ } ]);
102
+ return false;
83
103
  }
84
104
  }
105
+ if ( !valid && e.type !== 'keydown' ) {
106
+ // restore original content on blur
107
+ $this.html( $this.data('original') );
108
+ }
85
109
  });
86
110
  }
87
111
  });
@@ -1,4 +1,4 @@
1
- /* Pager widget for TableSorter 7/17/2014 (v2.17.5) */
1
+ /* Pager widget for TableSorter 8/1/2014 (v2.17.6) */
2
2
  /*jshint browser:true, jquery:true, unused:false */
3
3
  ;(function($){
4
4
  "use strict";
@@ -306,6 +306,8 @@ tsp = ts.pager = {
306
306
  }
307
307
 
308
308
  if ( p.$size.length ) {
309
+ // setting an option as selected appears to cause issues with initial page size
310
+ p.$size.find('option').removeAttr('selected');
309
311
  p.$size
310
312
  .unbind('change.pager')
311
313
  .bind('change.pager', function() {
@@ -336,7 +338,7 @@ tsp = ts.pager = {
336
338
  },
337
339
 
338
340
  updatePageDisplay: function(table, c, completed) {
339
- var i, pg, s, out, regex,
341
+ var i, pg, s, $out, regex,
340
342
  wo = c.widgetOptions,
341
343
  p = c.pager,
342
344
  f = c.$table.hasClass('hasFilters'),
@@ -368,7 +370,7 @@ tsp = ts.pager = {
368
370
  p.startRow = (t) ? 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1);
369
371
  p.page = (t) ? 0 : p.page;
370
372
  p.endRow = Math.min( p.filteredRows, p.totalRows, p.size * ( p.page + 1 ) );
371
- out = p.$container.find(wo.pager_selectors.pageDisplay);
373
+ $out = p.$container.find(wo.pager_selectors.pageDisplay);
372
374
  // form the output string (can now get a new output string from the server)
373
375
  s = ( p.ajaxData && p.ajaxData.output ? p.ajaxData.output || wo.pager_output : wo.pager_output )
374
376
  // {page} = one-based index; {page+#} = zero based index +/- value
@@ -377,15 +379,21 @@ tsp = ts.pager = {
377
379
  })
378
380
  // {totalPages}, {extra}, {extra:0} (array) or {extra : key} (object)
379
381
  .replace(/\{\w+(\s*:\s*\w+)?\}/gi, function(m){
380
- var str = m.replace(/[{}\s]/g,''),
382
+ var len, indx,
383
+ str = m.replace(/[{}\s]/g,''),
381
384
  extra = str.split(':'),
382
385
  data = p.ajaxData,
383
386
  // return zero for default page/row numbers
384
387
  deflt = /(rows?|pages?)$/i.test(str) ? 0 : '';
388
+ if (/(startRow|page)/.test(extra[0]) && extra[1] === 'input') {
389
+ len = ('' + (extra[0] === 'page' ? p.totalPages : p.totalRows)).length;
390
+ indx = extra[0] === 'page' ? p.page + 1 : p.startRow;
391
+ return '<input type="text" class="ts-' + extra[0] + '" style="max-width:' + len + 'em" value="' + indx + '"/>';
392
+ }
385
393
  return extra.length > 1 && data && data[extra[0]] ? data[extra[0]][extra[1]] : p[str] || (data ? data[str] : deflt) || deflt;
386
394
  });
387
- if (out.length) {
388
- out[ (out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
395
+ if ($out.length) {
396
+ $out[ ($out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
389
397
  if ( p.$goto.length ) {
390
398
  t = '';
391
399
  pg = Math.min( p.totalPages, p.filteredPages );
@@ -394,6 +402,12 @@ tsp = ts.pager = {
394
402
  }
395
403
  p.$goto.html(t).val( p.page + 1 );
396
404
  }
405
+ // rebind startRow/page inputs
406
+ $out.find('.ts-startRow, .ts-page').unbind('change').bind('change', function(){
407
+ var v = $(this).val(),
408
+ pg = $(this).hasClass('ts-startRow') ? Math.floor( v/p.size ) + 1 : v;
409
+ c.$table.trigger('pageSet.pager', [ pg ]);
410
+ });
397
411
  }
398
412
  }
399
413
  tsp.pagerArrows(c);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jquery-tablesorter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.5
4
+ version: 1.12.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jun Lin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-07-19 00:00:00.000000000 Z
12
+ date: 2014-08-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties