jquery-tablesorter 1.17.1 → 1.17.2

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.
Files changed (21) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/jquery-tablesorter/version.rb +1 -1
  4. data/vendor/assets/javascripts/jquery-tablesorter/addons/pager/jquery.tablesorter.pager.js +6 -2
  5. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.combined.js +353 -228
  6. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +41 -37
  7. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets.js +313 -192
  8. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-input-select.js +2 -1
  9. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-metric.js +63 -48
  10. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-alignChar.js +1 -1
  11. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-columnSelector.js +17 -12
  12. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-editable.js +10 -5
  13. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-filter.js +114 -71
  14. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-output.js +95 -66
  15. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-pager.js +3 -2
  16. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-repeatheaders.js +1 -1
  17. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-resizable.js +120 -59
  18. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-scroller.js +510 -242
  19. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-sortTbodies.js +228 -0
  20. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-stickyHeaders.js +76 -59
  21. metadata +3 -2
@@ -31,7 +31,8 @@ output = ts.output = {
31
31
  init : function(c) {
32
32
  c.$table
33
33
  .off(output.event)
34
- .on(output.event, function(){
34
+ .on(output.event, function( e ) {
35
+ e.stopPropagation();
35
36
  // explicitly use table.config.widgetOptions because we want
36
37
  // the most up-to-date values; not the "wo" from initialization
37
38
  output.process(c, c.widgetOptions);
@@ -39,81 +40,101 @@ output = ts.output = {
39
40
  },
40
41
 
41
42
  processRow: function(c, $rows, isHeader, isJSON) {
42
- var $this, row, col, rowlen, collen, txt,
43
+ var $cell, $cells, cellsLen, rowIndex, row, col, indx, rowspanLen, colspanLen, txt,
43
44
  wo = c.widgetOptions,
44
45
  tmpRow = [],
45
46
  dupe = wo.output_duplicateSpans,
46
47
  addSpanIndex = isHeader && isJSON && wo.output_headerRows && $.isFunction(wo.output_callbackJSON),
47
- cellIndex = 0;
48
- $rows.each(function(rowIndex) {
48
+ cellIndex = 0,
49
+ rowsLength = $rows.length;
50
+
51
+ for ( rowIndex = 0; rowIndex < rowsLength; rowIndex++ ) {
49
52
  if (!tmpRow[rowIndex]) { tmpRow[rowIndex] = []; }
50
53
  cellIndex = 0;
51
- $(this).children().each(function(){
52
- $this = $(this);
54
+ $cells = $rows.eq( rowIndex ).children();
55
+ cellsLen = $cells.length;
56
+ for ( indx = 0; indx < cellsLen; indx++ ) {
57
+ $cell = $cells.eq( indx );
53
58
  // process rowspans
54
- if ($this.filter('[rowspan]').length) {
55
- rowlen = parseInt( $this.attr('rowspan'), 10) - 1;
56
- txt = output.formatData( wo, $this.attr(wo.output_dataAttrib) || $this.html(), isHeader );
57
- for (row = 1; row <= rowlen; row++) {
59
+ if ($cell.filter('[rowspan]').length) {
60
+ rowspanLen = parseInt( $cell.attr('rowspan'), 10) - 1;
61
+ txt = output.formatData( wo, $cell, isHeader );
62
+ for (row = 1; row <= rowspanLen; row++) {
58
63
  if (!tmpRow[rowIndex + row]) { tmpRow[rowIndex + row] = []; }
59
64
  tmpRow[rowIndex + row][cellIndex] = isHeader ? txt : dupe ? txt : '';
60
65
  }
61
66
  }
62
67
  // process colspans
63
- if ($this.filter('[colspan]').length) {
64
- collen = parseInt( $this.attr('colspan'), 10) - 1;
65
- txt = output.formatData( wo, $this.attr(wo.output_dataAttrib) || $this.html(), isHeader );
66
- for (col = 1; col <= collen; col++) {
68
+ if ($cell.filter('[colspan]').length) {
69
+ colspanLen = parseInt( $cell.attr('colspan'), 10) - 1;
70
+ // allow data-attribute to be an empty string
71
+ txt = output.formatData( wo, $cell, isHeader );
72
+ for (col = 1; col <= colspanLen; col++) {
67
73
  // if we're processing the header & making JSON, the header names need to be unique
68
- if ($this.filter('[rowspan]').length) {
69
- rowlen = parseInt( $this.attr('rowspan'), 10);
70
- for (row = 0; row < rowlen; row++) {
74
+ if ($cell.filter('[rowspan]').length) {
75
+ rowspanLen = parseInt( $cell.attr('rowspan'), 10);
76
+ for (row = 0; row < rowspanLen; row++) {
71
77
  if (!tmpRow[rowIndex + row]) { tmpRow[rowIndex + row] = []; }
72
78
  tmpRow[rowIndex + row][cellIndex + col] = addSpanIndex ?
73
- wo.output_callbackJSON($this, txt, cellIndex + col) || txt + '(' + (cellIndex + col) + ')' : isHeader ? txt : dupe ? txt : '';
79
+ wo.output_callbackJSON($cell, txt, cellIndex + col) ||
80
+ txt + '(' + (cellIndex + col) + ')' : isHeader ? txt : dupe ? txt : '';
74
81
  }
75
82
  } else {
76
83
  tmpRow[rowIndex][cellIndex + col] = addSpanIndex ?
77
- wo.output_callbackJSON($this, txt, cellIndex + col) || txt + '(' + (cellIndex + col) + ')' : isHeader ? txt : dupe ? txt : '';
84
+ wo.output_callbackJSON($cell, txt, cellIndex + col) ||
85
+ txt + '(' + (cellIndex + col) + ')' : isHeader ? txt : dupe ? txt : '';
78
86
  }
79
87
  }
80
88
  }
81
89
 
82
- // don't include hidden columns, unless option is set
83
- if ( !wo.output_hiddenColumns && $this.css('display') !== 'none' ) {
84
- // skip column if already defined
85
- while (typeof tmpRow[rowIndex][cellIndex] !== 'undefined') { cellIndex++; }
86
- tmpRow[rowIndex][cellIndex] = tmpRow[rowIndex][cellIndex] ||
87
- output.formatData( wo, $this.attr(wo.output_dataAttrib) || $this.html(), isHeader );
88
- cellIndex++;
89
- }
90
- });
91
- });
92
- return tmpRow;
90
+ // skip column if already defined
91
+ while (typeof tmpRow[rowIndex][cellIndex] !== 'undefined') { cellIndex++; }
92
+
93
+ tmpRow[rowIndex][cellIndex] = tmpRow[rowIndex][cellIndex] ||
94
+ output.formatData( wo, $cell, isHeader );
95
+ cellIndex++;
96
+ }
97
+ }
98
+ return ts.output.removeColumns( c, wo, tmpRow );
93
99
  },
94
100
 
95
- ignoreColumns : function(wo, data) {
96
- // ignore columns -> remove data from built array (because we've already processed any rowspan/colspan)
97
- $.each( data, function(indx, val){
98
- data[indx] = $.grep(val, function(v, cellIndx){
99
- return $.inArray(cellIndx, wo.output_ignoreColumns) < 0;
100
- });
101
- });
101
+ // remove hidden/ignored columns
102
+ removeColumns : function( c, wo, arry ) {
103
+ var rowIndex, row, colIndex,
104
+ data = [],
105
+ len = arry.length;
106
+ for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
107
+ row = arry[ rowIndex ];
108
+ data[ rowIndex ] = [];
109
+ for ( colIndex = 0; colIndex < c.columns; colIndex++ ) {
110
+ if ( !wo.output_hiddenColumnArray[ colIndex ] ) {
111
+ data[ rowIndex ].push( row[ colIndex ] );
112
+ }
113
+ }
114
+ }
102
115
  return data;
103
116
  },
104
117
 
105
118
  process : function(c, wo) {
106
- var mydata, $this, $rows, headers, csvData, len,
119
+ var mydata, $this, $rows, headers, csvData, len, rowsLen, tmp,
107
120
  hasStringify = window.JSON && JSON.hasOwnProperty('stringify'),
108
121
  indx = 0,
109
122
  tmpData = (wo.output_separator || ',').toLowerCase(),
110
123
  outputJSON = tmpData === 'json',
111
124
  outputArray = tmpData === 'array',
112
125
  separator = outputJSON || outputArray ? ',' : wo.output_separator,
126
+ saveRows = wo.output_saveRows,
113
127
  $el = c.$table;
114
128
  // regex to look for the set separator or HTML
115
129
  wo.output_regex = new RegExp('(' + (/\\/.test(separator) ? '\\' : '' ) + separator + ')' );
116
130
 
131
+ // make a list of hidden columns
132
+ wo.output_hiddenColumnArray = [];
133
+ for ( indx = 0; indx < c.columns; indx++ ) {
134
+ wo.output_hiddenColumnArray[ indx ] = $.inArray( indx, wo.output_ignoreColumns ) > -1 ||
135
+ c.$headerIndexed[ indx ].css( 'display' ) === 'none';
136
+ }
137
+
117
138
  // get header cells
118
139
  $this = $el.find('thead tr:visible').not('.' + (ts.css.filterRow || 'tablesorter-filter-row') );
119
140
  headers = output.processRow(c, $this, true, outputJSON);
@@ -121,36 +142,40 @@ output = ts.output = {
121
142
  // all tbody rows
122
143
  $rows = $el.children('tbody').children('tr');
123
144
 
145
+ // get (f)iltered, (v)isible, all rows (look for the first letter only), or jQuery filter selector
146
+ $rows = /^f/.test(saveRows) ? $rows.not('.' + (wo.filter_filteredRow || 'filtered') ) :
147
+ /^v/.test(saveRows) ? $rows.filter(':visible') :
148
+ // look for '.' (class selector), '#' (id selector),
149
+ // ':' (basic filters, e.g. ':not()') or '[' (attribute selector start)
150
+ /^[.#:\[]/.test(saveRows) ? $rows.filter(saveRows) :
151
+ // default to all rows
152
+ $rows;
153
+
154
+ // process to array of arrays
155
+ csvData = output.processRow(c, $rows);
156
+
124
157
  if (wo.output_includeFooter) {
125
158
  // clone, to force the tfoot rows to the end of this selection of rows
126
159
  // otherwise they appear after the thead (the order in the HTML)
127
- $rows = $rows.add( $el.children('tfoot').children('tr').clone() );
160
+ csvData = csvData.concat( output.processRow( c, $el.children('tfoot').children('tr:visible') ) );
128
161
  }
129
162
 
130
- // get (f)iltered, (v)isible or all rows (look for the first letter only)
131
- $rows = /f/.test(wo.output_saveRows) ? $rows.not('.' + (wo.filter_filteredRow || 'filtered') ) :
132
- /v/.test(wo.output_saveRows) ? $rows.filter(':visible') : $rows;
133
-
134
- // process to array of arrays
135
- csvData = output.processRow(c, $rows);
136
163
  len = headers.length;
137
164
 
138
- if (wo.output_ignoreColumns.length) {
139
- headers = output.ignoreColumns(wo, headers);
140
- csvData = output.ignoreColumns(wo, csvData);
141
- }
142
-
143
165
  if (outputJSON) {
144
166
  tmpData = [];
145
- $.each( csvData, function(indx, val){
167
+ rowsLen = csvData.length;
168
+ for ( indx = 0; indx < rowsLen; indx++ ) {
146
169
  // multiple header rows & output_headerRows = true, pick the last row...
147
- tmpData.push( output.row2Hash( headers[ (len > 1 && wo.output_headerRows) ? indx % len : len - 1], val ) );
148
- });
170
+ tmp = headers[ ( len > 1 && wo.output_headerRows ) ? indx % len : len - 1 ];
171
+ tmpData.push( output.row2Hash( tmp, csvData[ indx ] ) );
172
+ }
149
173
 
150
174
  // requires JSON stringify; if it doesn't exist, the output will show [object Object],... in the output window
151
175
  mydata = hasStringify ? JSON.stringify(tmpData) : tmpData;
152
176
  } else {
153
- tmpData = output.row2CSV(wo, wo.output_headerRows ? headers : [ headers[ (len > 1 && wo.output_headerRows) ? indx % len : len - 1] ], outputArray)
177
+ tmp = [ headers[ ( len > 1 && wo.output_headerRows ) ? indx % len : len - 1 ] ];
178
+ tmpData = output.row2CSV(wo, wo.output_headerRows ? headers : tmp, outputArray)
154
179
  .concat( output.row2CSV(wo, csvData, outputArray) );
155
180
 
156
181
  // stringify the array; if stringify doesn't exist the array will be flattened
@@ -174,30 +199,33 @@ output = ts.output = {
174
199
  rowLen = tmpRow.length;
175
200
  for (rowIndex = 0; rowIndex < rowLen; rowIndex++) {
176
201
  // remove any blank rows
177
- tmp = tmpRow[rowIndex].join('').replace(/\"/g,'');
178
- if (tmpRow[rowIndex].length > 0 && tmp !== '') {
202
+ tmp = ( tmpRow[rowIndex] || [] ).join('').replace(/\"/g,'');
203
+ if ( ( tmpRow[rowIndex] || [] ).length > 0 && tmp !== '' ) {
179
204
  csvData[csvData.length] = outputArray ? tmpRow[rowIndex] : tmpRow[rowIndex].join(wo.output_separator);
180
205
  }
181
206
  }
182
207
  return csvData;
183
208
  },
184
209
 
185
- row2Hash : function(keys, values) {
186
- var json = {};
187
- $.each(values, function(indx, val) {
210
+ row2Hash : function( keys, values ) {
211
+ var indx,
212
+ json = {},
213
+ len = values.length;
214
+ for ( indx = 0; indx < len; indx++ ) {
188
215
  if ( indx < keys.length ) {
189
- json[ keys[indx] ] = val;
216
+ json[ keys[ indx ] ] = values[ indx ];
190
217
  }
191
- });
218
+ }
192
219
  return json;
193
220
  },
194
221
 
195
- formatData : function(wo, input, isHeader) {
196
- var txt,
222
+ formatData : function(wo, $el, isHeader) {
223
+ var attr = $el.attr(wo.output_dataAttrib),
224
+ txt = typeof attr !== 'undefined' ? attr : $el.html(),
197
225
  quotes = (wo.output_separator || ',').toLowerCase(),
198
226
  separator = quotes === 'json' || quotes === 'array',
199
227
  // replace " with “ if undefined
200
- result = input.replace(/\"/g, wo.output_replaceQuote || '\u201c');
228
+ result = txt.replace(/\"/g, wo.output_replaceQuote || '\u201c');
201
229
  // replace line breaks with \\n & tabs with \\t
202
230
  if (!wo.output_trimSpaces) {
203
231
  result = result.replace(output.regexBR, output.replaceCR).replace(/\t/g, output.replaceTab);
@@ -269,7 +297,8 @@ output = ts.output = {
269
297
  // Dispatching click event; using $(link).trigger() won't work
270
298
  if (document.createEvent) {
271
299
  e = document.createEvent('MouseEvents');
272
- // event.initMouseEvent(type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);
300
+ // event.initMouseEvent(type, canBubble, cancelable, view, detail, screenX, screenY, clientX, clientY,
301
+ // ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);
273
302
  e.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
274
303
  link.dispatchEvent(e);
275
304
  }
@@ -300,7 +329,7 @@ ts.addWidget({
300
329
  output_dataAttrib : 'data-name', // header attrib containing modified header name
301
330
  output_headerRows : false, // if true, include multiple header rows (JSON only)
302
331
  output_delivery : 'popup', // popup, download
303
- output_saveRows : 'filtered', // all, visible or filtered
332
+ output_saveRows : 'filtered', // (a)ll, (v)isible, (f)iltered or jQuery filter selector
304
333
  output_duplicateSpans: true, // duplicate output data in tbody colspan/rowspan
305
334
  output_replaceQuote : '\u201c;', // left double quote
306
335
  output_includeHTML : false,
@@ -661,7 +661,7 @@ tsp = ts.pager = {
661
661
  c.totalRows = p.totalRows = result.total;
662
662
  c.filteredRows = p.filteredRows = typeof result.filteredRows !== 'undefined' ? result.filteredRows : result.total;
663
663
  th = result.headers;
664
- d = result.rows;
664
+ d = result.rows || [];
665
665
  } else {
666
666
  // allow [ total, rows, headers ] or [ rows, total, headers ]
667
667
  t = isNaN(result[0]) && !isNaN(result[1]);
@@ -670,7 +670,8 @@ tsp = ts.pager = {
670
670
  p.totalRows = isNaN(rr_count) ? p.totalRows || 0 : rr_count;
671
671
  // can't set filtered rows when returning an array
672
672
  c.totalRows = c.filteredRows = p.filteredRows = p.totalRows;
673
- d = p.totalRows === 0 ? [""] : result[t ? 0 : 1] || []; // row data
673
+ // set row data to empty array if nothing found - see http://stackoverflow.com/q/30875583/145346
674
+ d = p.totalRows === 0 ? [] : result[t ? 0 : 1] || []; // row data
674
675
  th = result[2]; // headers
675
676
  }
676
677
  l = d && d.length;
@@ -17,7 +17,7 @@
17
17
  var h = '', i, $tr, l, skip;
18
18
  // cache and collect all TH headers
19
19
  if (!wo.repeatHeaders) {
20
- h = '<tr class="repeated-header remove-me">';
20
+ h = '<tr class="repeated-header ' + c.selectorRemove.slice(1) + '">';
21
21
  for (i = 0; i < c.columns; i++) {
22
22
  // only get the headerContent text
23
23
  h += '<th>' + $.trim( c.$headers.eq(i).text() ) + '</th>';
@@ -1,4 +1,5 @@
1
- /*! Widget: resizable - updated 5/17/2015 (v2.22.0) */
1
+ /*! Widget: resizable - updated 6/26/2015 (v2.22.2) */
2
+ /*jshint browser:true, jquery:true, unused:false */
2
3
  ;(function ($, window) {
3
4
  'use strict';
4
5
  var ts = $.tablesorter || {};
@@ -17,8 +18,8 @@ $(function(){
17
18
  '-khtml-user-select: none; -webkit-user-select: none; user-select: none; }' +
18
19
  '.' + ts.css.resizableContainer + ' { position: relative; height: 1px; }' +
19
20
  // make handle z-index > than stickyHeader z-index, so the handle stays above sticky header
20
- '.' + ts.css.resizableHandle + ' { position: absolute; display: inline-block; width: 8px; top: 1px;' +
21
- 'cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }' +
21
+ '.' + ts.css.resizableHandle + ' { position: absolute; display: inline-block; width: 8px;' +
22
+ 'top: 1px; cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }' +
22
23
  '</style>';
23
24
  $(s).appendTo('body');
24
25
  });
@@ -27,34 +28,69 @@ ts.resizable = {
27
28
  init : function( c, wo ) {
28
29
  if ( c.$table.hasClass( 'hasResizable' ) ) { return; }
29
30
  c.$table.addClass( 'hasResizable' );
30
- ts.resizableReset( c.table, true ); // set default widths
31
+
32
+ var noResize, $header, column, storedSizes, tmp,
33
+ $table = c.$table,
34
+ $parent = $table.parent(),
35
+ marginTop = parseInt( $table.css( 'margin-top' ), 10 ),
31
36
 
32
37
  // internal variables
33
- wo.resizable_ = {
34
- $wrap : c.$table.parent(),
38
+ vars = wo.resizable_ = {
39
+ useStorage : ts.storage && wo.resizable !== false,
40
+ $wrap : $parent,
35
41
  mouseXPosition : 0,
36
42
  $target : null,
37
43
  $next : null,
38
- overflow : c.$table.parent().css('overflow') === 'auto',
39
- fullWidth : Math.abs(c.$table.parent().width() - c.$table.width()) < 20,
44
+ overflow : $parent.css('overflow') === 'auto' ||
45
+ $parent.css('overflow') === 'scroll' ||
46
+ $parent.css('overflow-x') === 'auto' ||
47
+ $parent.css('overflow-x') === 'scroll',
40
48
  storedSizes : []
41
49
  };
42
50
 
43
- var noResize, $header, column, storedSizes,
44
- marginTop = parseInt( c.$table.css( 'margin-top' ), 10 );
51
+ // set default widths
52
+ ts.resizableReset( c.table, true );
53
+
54
+ // now get measurements!
55
+ vars.tableWidth = $table.width();
56
+ // attempt to autodetect
57
+ vars.fullWidth = Math.abs( $parent.width() - vars.tableWidth ) < 20;
45
58
 
46
- wo.resizable_.storedSizes = storedSizes = ( ( ts.storage && wo.resizable !== false ) ?
59
+ /*
60
+ // Hacky method to determine if table width is set to "auto"
61
+ // http://stackoverflow.com/a/20892048/145346
62
+ if ( !vars.fullWidth ) {
63
+ tmp = $table.width();
64
+ $header = $table.wrap('<span>').parent(); // temp variable
65
+ storedSizes = parseInt( $table.css( 'margin-left' ), 10 ) || 0;
66
+ $table.css( 'margin-left', storedSizes + 50 );
67
+ vars.tableWidth = $header.width() > tmp ? 'auto' : tmp;
68
+ $table.css( 'margin-left', storedSizes ? storedSizes : '' );
69
+ $header = null;
70
+ $table.unwrap('<span>');
71
+ }
72
+ */
73
+
74
+ if ( vars.useStorage && vars.overflow ) {
75
+ // save table width
76
+ ts.storage( c.table, 'tablesorter-table-original-css-width', vars.tableWidth );
77
+ tmp = ts.storage( c.table, 'tablesorter-table-resized-width' ) || 'auto';
78
+ ts.resizable.setWidth( $table, tmp, true );
79
+ }
80
+ wo.resizable_.storedSizes = storedSizes = ( vars.useStorage ?
47
81
  ts.storage( c.table, ts.css.resizableStorage ) :
48
82
  [] ) || [];
49
83
  ts.resizable.setWidths( c, wo, storedSizes );
84
+ ts.resizable.updateStoredSizes( c, wo );
50
85
 
51
86
  wo.$resizable_container = $( '<div class="' + ts.css.resizableContainer + '">' )
52
87
  .css({ top : marginTop })
53
- .insertBefore( c.$table );
88
+ .insertBefore( $table );
54
89
  // add container
55
90
  for ( column = 0; column < c.columns; column++ ) {
56
91
  $header = c.$headerIndexed[ column ];
57
- noResize = ts.getData( $header, ts.getColumnData( c.table, c.headers, column ), 'resizable' ) === 'false';
92
+ tmp = ts.getColumnData( c.table, c.headers, column );
93
+ noResize = ts.getData( $header, tmp, 'resizable' ) === 'false';
58
94
  if ( !noResize ) {
59
95
  $( '<div class="' + ts.css.resizableHandle + '">' )
60
96
  .appendTo( wo.$resizable_container )
@@ -66,37 +102,52 @@ ts.resizable = {
66
102
  .bind( 'selectstart', false );
67
103
  }
68
104
  }
69
- c.$table.one('tablesorter-initialized', function() {
105
+ $table.one('tablesorter-initialized', function() {
70
106
  ts.resizable.setHandlePosition( c, wo );
71
107
  ts.resizable.bindings( this.config, this.config.widgetOptions );
72
108
  });
73
109
  },
74
110
 
75
- setWidth : function( $el, width ) {
111
+ updateStoredSizes : function( c, wo ) {
112
+ var column, $header,
113
+ len = c.columns,
114
+ vars = wo.resizable_;
115
+ vars.storedSizes = [];
116
+ for ( column = 0; column < len; column++ ) {
117
+ $header = c.$headerIndexed[ column ];
118
+ vars.storedSizes[ column ] = $header.is(':visible') ? $header.width() : 0;
119
+ }
120
+ },
121
+
122
+ setWidth : function( $el, width, overflow ) {
123
+ // overflow tables need min & max width set as well
76
124
  $el.css({
77
125
  'width' : width,
78
- 'min-width' : '',
79
- 'max-width' : ''
126
+ 'min-width' : overflow ? width : '',
127
+ 'max-width' : overflow ? width : ''
80
128
  });
81
129
  },
82
130
 
83
131
  setWidths : function( c, wo, storedSizes ) {
84
- var column,
132
+ var column, $temp,
133
+ vars = wo.resizable_,
85
134
  $extra = $( c.namespace + '_extra_headers' ),
86
135
  $col = c.$table.children( 'colgroup' ).children( 'col' );
87
- storedSizes = storedSizes || wo.resizable_.storedSizes || [];
136
+ storedSizes = storedSizes || vars.storedSizes || [];
88
137
  // process only if table ID or url match
89
138
  if ( storedSizes.length ) {
90
139
  for ( column = 0; column < c.columns; column++ ) {
91
140
  // set saved resizable widths
92
- c.$headerIndexed[ column ].width( storedSizes[ column ] );
141
+ ts.resizable.setWidth( c.$headerIndexed[ column ], storedSizes[ column ], vars.overflow );
93
142
  if ( $extra.length ) {
94
143
  // stickyHeaders needs to modify min & max width as well
95
- ts.resizable.setWidth( $extra.eq( column ).add( $col.eq( column ) ), storedSizes[ column ] );
144
+ $temp = $extra.eq( column ).add( $col.eq( column ) );
145
+ ts.resizable.setWidth( $temp, storedSizes[ column ], vars.overflow );
96
146
  }
97
147
  }
98
- if ( $( c.namespace + '_extra_table' ).length && !ts.hasWidget( c.table, 'scroller' ) ) {
99
- ts.resizable.setWidth( $( c.namespace + '_extra_table' ), c.$table.outerWidth() );
148
+ $temp = $( c.namespace + '_extra_table' );
149
+ if ( $temp.length && !ts.hasWidget( c.table, 'scroller' ) ) {
150
+ ts.resizable.setWidth( $temp, c.$table.outerWidth(), vars.overflow );
100
151
  }
101
152
  }
102
153
  },
@@ -156,7 +207,7 @@ ts.resizable = {
156
207
  var namespace = c.namespace + 'tsresize';
157
208
  wo.$resizable_container.children().bind( 'mousedown', function( event ) {
158
209
  // save header cell and mouse position
159
- var column, $this,
210
+ var column,
160
211
  vars = wo.resizable_,
161
212
  $extras = $( c.namespace + '_extra_headers' ),
162
213
  $header = $( event.target ).data( 'header' );
@@ -175,11 +226,7 @@ ts.resizable = {
175
226
  vars.next = column;
176
227
 
177
228
  vars.mouseXPosition = event.pageX;
178
- vars.storedSizes = [];
179
- for ( column = 0; column < c.columns; column++ ) {
180
- $this = c.$headerIndexed[ column ];
181
- vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0;
182
- }
229
+ ts.resizable.updateStoredSizes( c, wo );
183
230
  ts.resizable.toggleTextSelection( c, true );
184
231
  });
185
232
 
@@ -230,47 +277,51 @@ ts.resizable = {
230
277
  mouseMove : function( c, wo, event ) {
231
278
  if ( wo.resizable_.mouseXPosition === 0 || !wo.resizable_.$target ) { return; }
232
279
  // resize columns
233
- var vars = wo.resizable_,
280
+ var column,
281
+ total = 0,
282
+ vars = wo.resizable_,
234
283
  $next = vars.$next,
284
+ tar = vars.storedSizes[ vars.target ],
235
285
  leftEdge = event.pageX - vars.mouseXPosition;
236
- if ( vars.fullWidth ) {
237
- vars.storedSizes[ vars.target ] += leftEdge;
238
- vars.storedSizes[ vars.next ] -= leftEdge;
239
- ts.resizable.setWidths( c, wo );
240
-
241
- } else if ( vars.overflow ) {
242
- c.$table.add( $( c.namespace + '_extra_table' ) ).width(function(i, w){
243
- return w + leftEdge;
244
- });
286
+ if ( vars.overflow ) {
287
+ if ( tar + leftEdge > 0 ) {
288
+ vars.storedSizes[ vars.target ] += leftEdge;
289
+ ts.resizable.setWidth( vars.$target, vars.storedSizes[ vars.target ], true );
290
+ // update the entire table width
291
+ for ( column = 0; column < c.columns; column++ ) {
292
+ total += vars.storedSizes[ column ];
293
+ }
294
+ ts.resizable.setWidth( c.$table.add( $( c.namespace + '_extra_table' ) ), total );
295
+ }
245
296
  if ( !$next.length ) {
246
297
  // if expanding right-most column, scroll the wrapper
247
298
  vars.$wrap[0].scrollLeft = c.$table.width();
248
299
  }
300
+ } else if ( vars.fullWidth ) {
301
+ vars.storedSizes[ vars.target ] += leftEdge;
302
+ vars.storedSizes[ vars.next ] -= leftEdge;
303
+ ts.resizable.setWidths( c, wo );
249
304
  } else {
250
305
  vars.storedSizes[ vars.target ] += leftEdge;
251
306
  ts.resizable.setWidths( c, wo );
252
307
  }
253
308
  vars.mouseXPosition = event.pageX;
309
+ // dynamically update sticky header widths
310
+ c.$table.trigger('stickyHeadersUpdate');
254
311
  },
255
312
 
256
313
  stopResize : function( c, wo ) {
257
- var $this, column,
258
- vars = wo.resizable_;
259
- vars.storedSizes = [];
260
- if ( ts.storage ) {
261
- vars.storedSizes = [];
262
- for ( column = 0; column < c.columns; column++ ) {
263
- $this = c.$headerIndexed[ column ];
264
- vars.storedSizes[ column ] = $this.is(':visible') ? $this.width() : 0;
265
- }
266
- if ( wo.resizable !== false ) {
267
- // save all column widths
268
- ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
269
- }
314
+ var vars = wo.resizable_;
315
+ ts.resizable.updateStoredSizes( c, wo );
316
+ if ( vars.useStorage ) {
317
+ // save all column widths
318
+ ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
319
+ ts.storage( c.table, 'tablesorter-table-resized-width', c.$table.width() );
270
320
  }
271
321
  vars.mouseXPosition = 0;
272
322
  vars.$target = vars.$next = null;
273
- $(window).trigger('resize'); // will update stickyHeaders, just in case
323
+ // will update stickyHeaders, just in case, see #912
324
+ c.$table.trigger('stickyHeadersUpdate');
274
325
  }
275
326
  };
276
327
 
@@ -281,11 +332,12 @@ ts.addWidget({
281
332
  id: "resizable",
282
333
  priority: 40,
283
334
  options: {
284
- resizable : true,
335
+ resizable : true, // save column widths to storage
285
336
  resizable_addLastColumn : false,
286
337
  resizable_widths : [],
287
338
  resizable_throttle : false, // set to true (5ms) or any number 0-10 range
288
- resizable_targetLast : false
339
+ resizable_targetLast : false,
340
+ resizable_fullWidth : null
289
341
  },
290
342
  init: function(table, thisWidget, c, wo) {
291
343
  ts.resizable.init( c, wo );
@@ -309,19 +361,28 @@ ts.resizableReset = function( table, refreshing ) {
309
361
  $( table ).each(function(){
310
362
  var index, $t,
311
363
  c = this.config,
312
- wo = c && c.widgetOptions;
364
+ wo = c && c.widgetOptions,
365
+ vars = wo.resizable_;
313
366
  if ( table && c && c.$headerIndexed.length ) {
367
+ // restore the initial table width
368
+ if ( vars.overflow && vars.tableWidth ) {
369
+ ts.resizable.setWidth( c.$table, vars.tableWidth, true );
370
+ if ( vars.useStorage ) {
371
+ ts.storage( table, 'tablesorter-table-resized-width', 'auto' );
372
+ }
373
+ }
314
374
  for ( index = 0; index < c.columns; index++ ) {
315
375
  $t = c.$headerIndexed[ index ];
316
376
  if ( wo.resizable_widths && wo.resizable_widths[ index ] ) {
317
- $t.css( 'width', wo.resizable_widths[ index ] );
377
+ ts.resizable.setWidth( $t, wo.resizable_widths[ index ], vars.overflow );
318
378
  } else if ( !$t.hasClass( 'resizable-false' ) ) {
319
379
  // don't clear the width of any column that is not resizable
320
- $t.css( 'width', '' );
380
+ ts.resizable.setWidth( $t, '', vars.overflow );
321
381
  }
322
382
  }
383
+
323
384
  // reset stickyHeader widths
324
- $( window ).trigger( 'resize' );
385
+ c.$table.trigger( 'stickyHeadersUpdate' );
325
386
  if ( ts.storage && !refreshing ) {
326
387
  ts.storage( this, ts.css.resizableStorage, {} );
327
388
  }