jquery-tablesorter 1.16.2 → 1.16.3

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 (30) 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 +8 -6
  5. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.js +30 -20
  6. data/vendor/assets/javascripts/jquery-tablesorter/jquery.tablesorter.widgets.js +343 -193
  7. data/vendor/assets/javascripts/jquery-tablesorter/parsers/parser-input-select.js +4 -4
  8. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-build-table.js +3 -2
  9. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-filter-formatter-select2.js +2 -2
  10. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-filter.js +26 -23
  11. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-output.js +2 -3
  12. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-pager.js +11 -5
  13. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-resizable.js +277 -139
  14. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-scroller.js +543 -220
  15. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-stickyHeaders.js +3 -10
  16. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-storage.js +28 -15
  17. data/vendor/assets/javascripts/jquery-tablesorter/widgets/widget-uitheme.js +7 -4
  18. data/vendor/assets/stylesheets/jquery-tablesorter/theme.black-ice.css +5 -4
  19. data/vendor/assets/stylesheets/jquery-tablesorter/theme.blue.css +8 -5
  20. data/vendor/assets/stylesheets/jquery-tablesorter/theme.bootstrap.css +5 -4
  21. data/vendor/assets/stylesheets/jquery-tablesorter/theme.bootstrap_2.css +6 -5
  22. data/vendor/assets/stylesheets/jquery-tablesorter/theme.dark.css +6 -5
  23. data/vendor/assets/stylesheets/jquery-tablesorter/theme.default.css +6 -5
  24. data/vendor/assets/stylesheets/jquery-tablesorter/theme.dropbox.css +5 -5
  25. data/vendor/assets/stylesheets/jquery-tablesorter/theme.green.css +13 -8
  26. data/vendor/assets/stylesheets/jquery-tablesorter/theme.grey.css +8 -5
  27. data/vendor/assets/stylesheets/jquery-tablesorter/theme.ice.css +16 -9
  28. data/vendor/assets/stylesheets/jquery-tablesorter/theme.jui.css +4 -3
  29. data/vendor/assets/stylesheets/jquery-tablesorter/theme.metro-dark.css +5 -4
  30. metadata +3 -3
@@ -1,5 +1,5 @@
1
- /*! input & select parsers for jQuery 1.7+ & tablesorter 2.7.11+
2
- * Updated 3/5/2015 (v2.21.0)
1
+ /*! parser: input & select - updated 3/26/2015 (v2.21.3) *//*
2
+ * for jQuery 1.7+ & tablesorter 2.7.11+
3
3
  * Demo: http://mottie.github.com/tablesorter/docs/example-widget-grouping.html
4
4
  */
5
5
  /*jshint browser: true, jquery:true, unused:false */
@@ -111,7 +111,7 @@
111
111
  // bind to .tablesorter (default class name)
112
112
  $(this).children('tbody')
113
113
  .on('mouseleave', function(e){
114
- restoreValue(e.target.tagName === 'TBODY');
114
+ restoreValue(e.target.nodeName === 'TBODY');
115
115
  })
116
116
  .on('focus', 'select, input, textarea', function(){
117
117
  $(this).data('ts-original-value', this.value);
@@ -129,7 +129,7 @@
129
129
  }
130
130
  // Update cell cache using... select: change, input: enter or textarea: alt + enter
131
131
  if ( ( e.type === 'change' ) ||
132
- ( e.type === 'keyup' && e.which === 13 && ( e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' && e.altKey ) ) ) {
132
+ ( e.type === 'keyup' && e.which === 13 && ( e.target.nodeName === 'INPUT' || e.target.nodeName === 'TEXTAREA' && e.altKey ) ) ) {
133
133
  var undef,
134
134
  $tar = $(e.target),
135
135
  $cell = $tar.closest('td'),
@@ -1,4 +1,5 @@
1
- /*! Build Table widget for tableSorter v2.16.0; updated 2/7/2015 (v2.19.0)
1
+ /*! Widget: Build Table - updated 3/26/2015 (v2.21.3) *//*
2
+ * for tableSorter v2.16.0+
2
3
  * by Rob Garrison
3
4
  */
4
5
  /*jshint browser:true, jquery:true, unused:false */
@@ -12,7 +13,7 @@ var ts = $.tablesorter = $.tablesorter || {},
12
13
  // data.rows contains an array of rows which contains an array of cells
13
14
  bt = ts.buildTable = function(tar, c){
14
15
  // add table if one doesn't exist
15
- var $tbl = tar.tagName === 'TABLE' ? $(tar) : $('<table>').appendTo(tar),
16
+ var $tbl = tar.nodeName === 'TABLE' ? $(tar) : $('<table>').appendTo(tar),
16
17
  table = $tbl[0],
17
18
  wo = c.widgetOptions = $.extend( true, {}, bt.defaults, c.widgetOptions ),
18
19
  p = wo.build_processing,
@@ -1,4 +1,4 @@
1
- /*! Filter widget select2 formatter function - updated 2/7/2015 (v2.19.0)
1
+ /*! Widget: Filter formatter function select2 - updated 3/26/2015 (v2.21.3) *//*
2
2
  * requires: jQuery 1.7.2+, tableSorter (FORK) 2.16+, filter widget 2.16+ and select2 v3.4.6+ plugin
3
3
  */
4
4
  /*jshint browser:true, jquery:true, unused:false */
@@ -52,7 +52,7 @@ ts.filterFormatter.select2 = function($cell, indx, select2Def) {
52
52
  v = v.join('\u0000');
53
53
  }
54
54
  // escape special regex characters (http://stackoverflow.com/a/9310752/145346)
55
- v = v.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
55
+ v = v.replace(/[-[\]{}()*+?.,/\\^$|#\s]/g, '\\$&');
56
56
  // convert string back into an array
57
57
  if (arry) {
58
58
  v = v.split('\u0000');
@@ -1,14 +1,17 @@
1
- /*! Widget: filter - updated 3/5/2015 (v2.21.0) *//*
1
+ /*! Widget: filter - updated 3/26/2015 (v2.21.3) *//*
2
2
  * Requires tablesorter v2.8+ and jQuery 1.7+
3
3
  * by Rob Garrison
4
4
  */
5
5
  ;(function ($) {
6
6
  'use strict';
7
- var ts = $.tablesorter = $.tablesorter || {};
7
+ var ts = $.tablesorter = $.tablesorter || {},
8
+ tscss = ts.css;
8
9
 
9
- $.extend(ts.css, {
10
- filterRow : 'tablesorter-filter-row',
11
- filter : 'tablesorter-filter'
10
+ $.extend(tscss, {
11
+ filterRow : 'tablesorter-filter-row',
12
+ filter : 'tablesorter-filter',
13
+ filterDisabled : 'disabled',
14
+ filterRowHide : 'hideme'
12
15
  });
13
16
 
14
17
  ts.addWidget({
@@ -58,7 +61,7 @@ ts.addWidget({
58
61
  // add .tsfilter namespace to all BUT search
59
62
  .unbind( events.replace(/\s+/g, ' ') )
60
63
  // remove the filter row even if refreshing, because the column might have been moved
61
- .find('.' + ts.css.filterRow).remove();
64
+ .find('.' + tscss.filterRow).remove();
62
65
  if (refreshing) { return; }
63
66
  for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
64
67
  $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody
@@ -286,13 +289,13 @@ ts.filter = {
286
289
  c.$table.bind( txt, function(event, filter) {
287
290
  val = (wo.filter_hideEmpty && $.isEmptyObject(c.cache) && !(c.delayInit && event.type === 'appendCache'));
288
291
  // hide filter row using the "filtered" class name
289
- c.$table.find('.' + ts.css.filterRow).toggleClass(wo.filter_filteredRow, val ); // fixes #450
292
+ c.$table.find('.' + tscss.filterRow).toggleClass(wo.filter_filteredRow, val ); // fixes #450
290
293
  if ( !/(search|filter)/.test(event.type) ) {
291
294
  event.stopPropagation();
292
295
  ts.filter.buildDefault(table, true);
293
296
  }
294
297
  if (event.type === 'filterReset') {
295
- c.$table.find('.' + ts.css.filter).add(wo.filter_$externalFilters).val('');
298
+ c.$table.find('.' + tscss.filter).add(wo.filter_$externalFilters).val('');
296
299
  ts.filter.searching(table, []);
297
300
  } else if (event.type === 'filterEnd') {
298
301
  ts.filter.buildDefault(table, true);
@@ -355,7 +358,7 @@ ts.filter = {
355
358
  options += '<option ' + (txt === val ? '' : 'data-function-name="' + string + '" ') + 'value="' + val + '">' + txt + '</option>';
356
359
  }
357
360
  }
358
- c.$table.find('thead').find('select.' + ts.css.filter + '[data-column="' + column + '"]').append(options);
361
+ c.$table.find('thead').find('select.' + tscss.filter + '[data-column="' + column + '"]').append(options);
359
362
  }
360
363
  }
361
364
  }
@@ -364,7 +367,7 @@ ts.filter = {
364
367
  // it would append the same options twice.
365
368
  ts.filter.buildDefault(table, true);
366
369
 
367
- ts.filter.bindSearch( table, c.$table.find('.' + ts.css.filter), true );
370
+ ts.filter.bindSearch( table, c.$table.find('.' + tscss.filter), true );
368
371
  if (wo.filter_external) {
369
372
  ts.filter.bindSearch( table, wo.filter_external );
370
373
  }
@@ -379,7 +382,7 @@ ts.filter = {
379
382
  .unbind( ('filterStart filterEnd '.split(' ').join(c.namespace + 'filter ')).replace(/\s+/g, ' ') )
380
383
  .bind( 'filterStart filterEnd '.split(' ').join(c.namespace + 'filter '), function(event, columns) {
381
384
  // only add processing to certain columns to all columns
382
- $header = (columns) ? c.$table.find('.' + ts.css.header).filter('[data-column]').filter(function() {
385
+ $header = (columns) ? c.$table.find('.' + tscss.header).filter('[data-column]').filter(function() {
383
386
  return columns[$(this).data('column')] !== '';
384
387
  }) : '';
385
388
  ts.isProcessing(table, event.type === 'filterStart', columns ? $header : '');
@@ -493,7 +496,7 @@ ts.filter = {
493
496
  // c.columns defined in computeThIndexes()
494
497
  columns = c.columns,
495
498
  arry = $.isArray(wo.filter_cellFilter),
496
- buildFilter = '<tr role="row" class="' + ts.css.filterRow + '">';
499
+ buildFilter = '<tr role="row" class="' + tscss.filterRow + ' ' + c.cssIgnoreRow + '">';
497
500
  for (column = 0; column < columns; column++) {
498
501
  if (arry) {
499
502
  buildFilter += '<td' + ( wo.filter_cellFilter[column] ? ' class="' + wo.filter_cellFilter[column] + '"' : '' ) + '></td>';
@@ -542,9 +545,9 @@ ts.filter = {
542
545
  name = ( $.isArray(wo.filter_cssFilter) ?
543
546
  (typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '') :
544
547
  wo.filter_cssFilter ) || '';
545
- buildFilter.addClass( ts.css.filter + ' ' + name ).attr('data-column', column);
548
+ buildFilter.addClass( tscss.filter + ' ' + name ).attr('data-column', column);
546
549
  if (disabled) {
547
- buildFilter.attr('placeholder', '').addClass('disabled')[0].disabled = true; // disabled!
550
+ buildFilter.attr('placeholder', '').addClass(tscss.filterDisabled)[0].disabled = true; // disabled!
548
551
  }
549
552
  }
550
553
  }
@@ -638,7 +641,7 @@ ts.filter = {
638
641
  }
639
642
  if (wo.filter_hideFilters) {
640
643
  // show/hide filter row as needed
641
- c.$table.find('.' + ts.css.filterRow).trigger( combinedFilters === '' ? 'mouseleave' : 'mouseenter' );
644
+ c.$table.find('.' + tscss.filterRow).trigger( combinedFilters === '' ? 'mouseleave' : 'mouseenter' );
642
645
  }
643
646
  // return if the last search is the same; but filter === false when updating the search
644
647
  // see example-widget-filter.html filter toggle buttons
@@ -664,8 +667,8 @@ ts.filter = {
664
667
  hideFilters: function(table, c) {
665
668
  var $filterRow, $filterRow2, timer;
666
669
  $(table)
667
- .find('.' + ts.css.filterRow)
668
- .addClass('hideme')
670
+ .find('.' + tscss.filterRow)
671
+ .addClass(tscss.filterRowHide)
669
672
  .bind('mouseenter mouseleave', function(e) {
670
673
  // save event object - http://bugs.jquery.com/ticket/12140
671
674
  var event = e;
@@ -673,14 +676,14 @@ ts.filter = {
673
676
  clearTimeout(timer);
674
677
  timer = setTimeout(function() {
675
678
  if ( /enter|over/.test(event.type) ) {
676
- $filterRow.removeClass('hideme');
679
+ $filterRow.removeClass(tscss.filterRowHide);
677
680
  } else {
678
681
  // don't hide if input has focus
679
682
  // $(':focus') needs jQuery 1.6+
680
683
  if ( $(document.activeElement).closest('tr')[0] !== $filterRow[0] ) {
681
684
  // don't hide row if any filter has a value
682
685
  if (c.lastCombinedFilter === '') {
683
- $filterRow.addClass('hideme');
686
+ $filterRow.addClass(tscss.filterRowHide);
684
687
  }
685
688
  }
686
689
  }
@@ -693,7 +696,7 @@ ts.filter = {
693
696
  timer = setTimeout(function() {
694
697
  // don't hide row if any filter has a value
695
698
  if (ts.getFilters(c.$table).join('') === '') {
696
- $filterRow2[ event.type === 'focus' ? 'removeClass' : 'addClass']('hideme');
699
+ $filterRow2[ event.type === 'focus' ? 'removeClass' : 'addClass'](tscss.filterRowHide);
697
700
  }
698
701
  }, 200);
699
702
  });
@@ -1181,7 +1184,7 @@ ts.filter = {
1181
1184
  // t.data('placeholder') won't work in jQuery older than 1.4.3
1182
1185
  options = '<option value="">' + ( node.data('placeholder') || node.attr('data-placeholder') || wo.filter_placeholder.select || '' ) + '</option>',
1183
1186
  // Get curent filter value
1184
- currentValue = c.$table.find('thead').find('select.' + ts.css.filter + '[data-column="' + column + '"]').val();
1187
+ currentValue = c.$table.find('thead').find('select.' + tscss.filter + '[data-column="' + column + '"]').val();
1185
1188
  // nothing included in arry (external source), so get the options from filter_selectSource or column data
1186
1189
  if (typeof arry === 'undefined' || arry === '') {
1187
1190
  arry = ts.filter.getOptionSource(table, column, onlyAvail);
@@ -1208,7 +1211,7 @@ ts.filter = {
1208
1211
  }
1209
1212
 
1210
1213
  // update all selects in the same column (clone thead in sticky headers & any external selects) - fixes 473
1211
- $filters = ( c.$filters ? c.$filters : c.$table.children('thead') ).find('.' + ts.css.filter);
1214
+ $filters = ( c.$filters ? c.$filters : c.$table.children('thead') ).find('.' + tscss.filter);
1212
1215
  if (wo.filter_$externalFilters) {
1213
1216
  $filters = $filters && $filters.length ? $filters.add(wo.filter_$externalFilters) : wo.filter_$externalFilters;
1214
1217
  }
@@ -1252,7 +1255,7 @@ ts.getFilters = function(table, getRaw, setFilters, skipFirst) {
1252
1255
  }
1253
1256
  if (c) {
1254
1257
  if (c.$filters) {
1255
- $filters = c.$filters.find('.' + ts.css.filter);
1258
+ $filters = c.$filters.find('.' + tscss.filter);
1256
1259
  }
1257
1260
  if (wo.filter_$externalFilters) {
1258
1261
  $filters = $filters && $filters.length ? $filters.add(wo.filter_$externalFilters) : wo.filter_$externalFilters;
@@ -1,4 +1,4 @@
1
- /* Output widget for TableSorter 3/5/2015 (v2.21.0)
1
+ /*! Widget: Output - updated 3/26/2015 (v2.21.3) *//*
2
2
  * Requires tablesorter v2.8+ and jQuery 1.7+
3
3
  * Modified from:
4
4
  * HTML Table to CSV: http://www.kunalbabre.com/projects/table2CSV.php (License unknown?)
@@ -160,7 +160,7 @@ output = ts.output = {
160
160
  // callback; if true returned, continue processing
161
161
  if ($.isFunction(wo.output_callback) && !wo.output_callback(c, mydata)) { return; }
162
162
 
163
- if ( /p/.test( (wo.output_delivery || '').toLowerCase() ) ) {
163
+ if ( /p/i.test( wo.output_delivery || '' ) ) {
164
164
  output.popup(mydata, wo.output_popupStyle, outputJSON || outputArray);
165
165
  } else {
166
166
  output.download(wo, mydata);
@@ -314,7 +314,6 @@ ts.addWidget({
314
314
  output_callbackJSON : function($cell, txt, cellIndex) { return txt + '(' + (cellIndex) + ')'; },
315
315
  // the need to modify this for Excel no longer exists
316
316
  output_encoding : 'data:application/octet-stream;charset=utf8,'
317
-
318
317
  },
319
318
  init: function(table, thisWidget, c) {
320
319
  output.init(c);
@@ -1,4 +1,7 @@
1
- /* Pager widget for TableSorter 3/5/2015 (v2.21.0) - requires jQuery 1.7+ */
1
+ /*! Widget: Pager - updated 3/26/2015 (v2.21.3) */
2
+ /* Requires tablesorter v2.8+ and jQuery 1.7+
3
+ * by Rob Garrison
4
+ */
2
5
  /*jshint browser:true, jquery:true, unused:false */
3
6
  ;(function($){
4
7
  "use strict";
@@ -143,7 +146,7 @@ tsp = ts.pager = {
143
146
  setSize: wo.pager_size,
144
147
  setPage: wo.pager_startPage,
145
148
  events: 'filterInit filterStart filterEnd sortEnd disable enable destroy updateComplete ' +
146
- 'pageSize pageSet pageAndSize pagerUpdate '
149
+ 'pageSize pageSet pageAndSize pagerUpdate refreshComplete '
147
150
  }, c.pager);
148
151
 
149
152
  // pager initializes multiple times before table has completed initialization
@@ -296,9 +299,12 @@ tsp = ts.pager = {
296
299
  })
297
300
  .on('pageSet.pager pagerUpdate.pager', function(e,v){
298
301
  e.stopPropagation();
299
- p.page = (parseInt(v, 10) || 1) - 1;
300
302
  // force pager refresh
301
- if (e.type === 'pagerUpdate') { p.last.page = true; }
303
+ if (e.type === 'pagerUpdate') {
304
+ v = typeof v === 'undefined' ? p.page + 1 : v;
305
+ p.last.page = true;
306
+ }
307
+ p.page = (parseInt(v, 10) || 1) - 1;
302
308
  tsp.moveToPage(table, p, true);
303
309
  tsp.updatePageDisplay(table, c, false);
304
310
  })
@@ -454,7 +460,7 @@ tsp = ts.pager = {
454
460
  p.$goto.html(t).val( p.page + 1 );
455
461
  }
456
462
  if ($out.length) {
457
- $out[ ($out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
463
+ $out[ ($out[0].nodeName === 'INPUT') ? 'val' : 'html' ](s);
458
464
  // rebind startRow/page inputs
459
465
  $out.find('.ts-startRow, .ts-page').off('change.pager').on('change.pager', function(){
460
466
  var v = $(this).val(),
@@ -1,176 +1,314 @@
1
- /*! Widget: resizable */
1
+ /*! Widget: resizable - updated 3/26/2015 (v2.21.3) */
2
2
  ;(function ($, window) {
3
3
  'use strict';
4
4
  var ts = $.tablesorter = $.tablesorter || {};
5
5
 
6
6
  $.extend(ts.css, {
7
- resizer : 'tablesorter-resizer' // resizable
7
+ resizableContainer : 'tablesorter-resizable-container',
8
+ resizableHandle : 'tablesorter-resizable-handle',
9
+ resizableNoSelect : 'tablesorter-disableSelection',
10
+ resizableStorage : 'tablesorter-resizable'
8
11
  });
9
12
 
10
- // this widget saves the column widths if
11
- // $.tablesorter.storage function is included
12
- // **************************
13
- ts.addWidget({
14
- id: "resizable",
15
- priority: 40,
16
- options: {
17
- resizable : true,
18
- resizable_addLastColumn : false,
19
- resizable_widths : [],
20
- resizable_throttle : false // set to true (5ms) or any number 0-10 range
13
+ // Add extra scroller css
14
+ $(function(){
15
+ var s = '<style>' +
16
+ 'body.' + ts.css.resizableNoSelect + ' { -ms-user-select: none; -moz-user-select: -moz-none;' +
17
+ '-khtml-user-select: none; -webkit-user-select: none; user-select: none; }' +
18
+ '.' + ts.css.resizableContainer + ' { position: relative; height: 1px; }' +
19
+ // 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; }' +
22
+ '</style>';
23
+ $(s).appendTo('body');
24
+ });
25
+
26
+ ts.resizable = {
27
+ init : function( c, wo ) {
28
+ if ( c.$table.hasClass( 'hasResizable' ) ) { return; }
29
+ c.$table.addClass( 'hasResizable' );
30
+ ts.resizableReset( c.table, true ); // set default widths
31
+
32
+ // internal variables
33
+ wo.resizable_ = {
34
+ $wrap : c.$table.parent(),
35
+ mouseXPosition : 0,
36
+ $target : null,
37
+ $next : null,
38
+ overflow : c.$table.parent().css('overflow') === 'auto',
39
+ fullWidth : Math.abs(c.$table.parent().width() - c.$table.width()) < 20,
40
+ storedSizes : []
41
+ };
42
+
43
+ var noResize, $header, column, storedSizes,
44
+ marginTop = parseInt( c.$table.css( 'margin-top' ), 10 );
45
+
46
+ wo.resizable_.storedSizes = storedSizes = ( ( ts.storage && wo.resizable !== false ) ?
47
+ ts.storage( c.table, ts.css.resizableStorage ) :
48
+ [] ) || [];
49
+ ts.resizable.setWidths( c, wo, storedSizes );
50
+
51
+ wo.$resizable_container = $( '<div class="' + ts.css.resizableContainer + '">' )
52
+ .css({ top : marginTop })
53
+ .insertBefore( c.$table );
54
+ // add container
55
+ for ( column = 0; column < c.columns; column++ ) {
56
+ $header = c.$headerIndexed[ column ];
57
+ noResize = ts.getData( $header, ts.getColumnData( c.table, c.headers, column ), 'resizable' ) === 'false';
58
+ if ( !noResize ) {
59
+ $( '<div class="' + ts.css.resizableHandle + '">' )
60
+ .appendTo( wo.$resizable_container )
61
+ .attr({
62
+ 'data-column' : column,
63
+ 'unselectable' : 'on'
64
+ })
65
+ .data( 'header', $header )
66
+ .bind( 'selectstart', false );
67
+ }
68
+ }
69
+ c.$table.one('tablesorter-initialized', function() {
70
+ ts.resizable.setHandlePosition( c, wo );
71
+ ts.resizable.bindings( this.config, this.config.widgetOptions );
72
+ });
21
73
  },
22
- format: function(table, c, wo) {
23
- if (c.$table.hasClass('hasResizable')) { return; }
24
- c.$table.addClass('hasResizable');
25
- ts.resizableReset(table, true); // set default widths
26
- var $rows, $columns, $column, column, timer,
27
- storedSizes = {},
28
- $table = c.$table,
29
- $wrap = $table.parent(),
30
- overflow = $table.parent().css('overflow') === 'auto',
31
- mouseXPosition = 0,
32
- $target = null,
33
- $next = null,
34
- fullWidth = Math.abs($table.parent().width() - $table.width()) < 20,
35
- mouseMove = function(event){
36
- if (mouseXPosition === 0 || !$target) { return; }
37
- // resize columns
38
- var leftEdge = event.pageX - mouseXPosition,
39
- targetWidth = $target.width();
40
- $target.width( targetWidth + leftEdge );
41
- if ($target.width() !== targetWidth && fullWidth) {
42
- $next.width( $next.width() - leftEdge );
43
- } else if (overflow) {
44
- $table.width(function(i, w){
45
- return w + leftEdge;
46
- });
47
- if (!$next.length) {
48
- // if expanding right-most column, scroll the wrapper
49
- $wrap[0].scrollLeft = $table.width();
50
- }
51
- }
52
- mouseXPosition = event.pageX;
53
- },
54
- stopResize = function() {
55
- if (ts.storage && $target && $next) {
56
- storedSizes = {};
57
- storedSizes[$target.index()] = $target.width();
58
- storedSizes[$next.index()] = $next.width();
59
- $target.width( storedSizes[$target.index()] );
60
- $next.width( storedSizes[$next.index()] );
61
- if (wo.resizable !== false) {
62
- // save all column widths
63
- ts.storage(table, 'tablesorter-resizable', c.$headers.map(function(){ return $(this).width(); }).get() );
64
- }
65
- }
66
- mouseXPosition = 0;
67
- $target = $next = null;
68
- $(window).trigger('resize'); // will update stickyHeaders, just in case
69
- };
70
- storedSizes = (ts.storage && wo.resizable !== false) ? ts.storage(table, 'tablesorter-resizable') : {};
74
+
75
+ setWidth : function( $el, width ) {
76
+ $el.css({
77
+ 'width' : width,
78
+ 'min-width' : '',
79
+ 'max-width' : ''
80
+ });
81
+ },
82
+
83
+ setWidths : function( c, wo, storedSizes ) {
84
+ var column,
85
+ $extra = $( c.namespace + '_extra_headers' ),
86
+ $col = c.$table.children( 'colgroup' ).children( 'col' );
87
+ storedSizes = storedSizes || wo.resizable_.storedSizes || [];
71
88
  // process only if table ID or url match
72
- if (storedSizes) {
73
- for (column in storedSizes) {
74
- if (!isNaN(column) && column < c.$headers.length) {
75
- c.$headers.eq(column).width(storedSizes[column]); // set saved resizable widths
89
+ if ( storedSizes.length ) {
90
+ for ( column = 0; column < c.columns; column++ ) {
91
+ // set saved resizable widths
92
+ c.$headers.eq( column ).width( storedSizes[ column ] );
93
+ if ( $extra.length ) {
94
+ // stickyHeaders needs to modify min & max width as well
95
+ ts.resizable.setWidth( $extra.eq( column ).add( $col.eq( column ) ), storedSizes[ column ] );
76
96
  }
77
97
  }
98
+ if ( $( c.namespace + '_extra_table' ).length && !ts.hasWidget( c.table, 'scroller' ) ) {
99
+ ts.resizable.setWidth( $( c.namespace + '_extra_table' ), c.$table.outerWidth() );
100
+ }
78
101
  }
79
- $rows = $table.children('thead:first').children('tr');
80
- // add resizable-false class name to headers (across rows as needed)
81
- $rows.children().each(function() {
82
- var canResize,
83
- $column = $(this);
84
- column = $column.attr('data-column');
85
- canResize = ts.getData( $column, ts.getColumnData( table, c.headers, column ), 'resizable') === "false";
86
- $rows.children().filter('[data-column="' + column + '"]')[canResize ? 'addClass' : 'removeClass']('resizable-false');
87
- });
88
- // add wrapper inside each cell to allow for positioning of the resizable target block
89
- $rows.each(function() {
90
- $column = $(this).children().not('.resizable-false');
91
- if (!$(this).find('.' + ts.css.wrapper).length) {
92
- // Firefox needs this inner div to position the resizer correctly
93
- $column.wrapInner('<div class="' + ts.css.wrapper + '" style="position:relative;height:100%;width:100%"></div>');
102
+ },
103
+
104
+ setHandlePosition : function( c, wo ) {
105
+ var tableWidth = c.$table.outerWidth(),
106
+ hasScroller = ts.hasWidget( c.table, 'scroller' ),
107
+ tableHeight = c.$table.height(),
108
+ $handles = wo.$resizable_container.children(),
109
+ handleCenter = Math.floor( $handles.width() / 2 - parseFloat( c.$headers.css( 'border-right-width' ) ) * 2 );
110
+
111
+ if ( hasScroller ) {
112
+ tableHeight = 0;
113
+ c.$table.closest( '.' + ts.css.scrollerWrap ).children().each(function(){
114
+ var $this = $(this);
115
+ // center table has a max-height set
116
+ tableHeight += $this.filter('[style*="height"]').length ? $this.height() : $this.children('table').height();
117
+ });
118
+ }
119
+ $handles.each( function() {
120
+ var $this = $(this),
121
+ column = parseInt( $this.attr( 'data-column' ), 10 ),
122
+ columns = c.columns - 1,
123
+ $header = $this.data( 'header' );
124
+ if ( column < columns || column === columns && wo.resizable_addLastColumn ) {
125
+ $this.css({
126
+ height : tableHeight,
127
+ left : $header.position().left + $header.width() - handleCenter
128
+ });
94
129
  }
95
- // don't include the last column of the row
96
- if (!wo.resizable_addLastColumn) { $column = $column.slice(0,-1); }
97
- $columns = $columns ? $columns.add($column) : $column;
98
130
  });
99
- $columns
100
- .each(function() {
101
- var $column = $(this),
102
- padding = parseInt($column.css('padding-right'), 10) + 10; // 10 is 1/2 of the 20px wide resizer
103
- $column
104
- .find('.' + ts.css.wrapper)
105
- .append('<div class="' + ts.css.resizer + '" style="cursor:w-resize;position:absolute;z-index:1;right:-' +
106
- padding + 'px;top:0;height:100%;width:20px;"></div>');
107
- })
108
- .find('.' + ts.css.resizer)
109
- .bind('mousedown', function(event) {
131
+ },
132
+
133
+ // prevent text selection while dragging resize bar
134
+ toggleTextSelection : function( c, toggle ) {
135
+ var namespace = c.namespace + 'tsresize';
136
+ c.widgetOptions.resizable_.disabled = toggle;
137
+ $( 'body' ).toggleClass( ts.css.resizableNoSelect, toggle );
138
+ if ( toggle ) {
139
+ $( 'body' )
140
+ .attr( 'unselectable', 'on' )
141
+ .bind( 'selectstart' + namespace, false );
142
+ } else {
143
+ $( 'body' )
144
+ .removeAttr( 'unselectable' )
145
+ .unbind( 'selectstart' + namespace );
146
+ }
147
+ },
148
+
149
+ bindings : function( c, wo ) {
150
+ var namespace = c.namespace + 'tsresize';
151
+ wo.$resizable_container.children().bind( 'mousedown', function( event ) {
110
152
  // save header cell and mouse position
111
- $target = $(event.target).closest('th');
112
- var $header = c.$headers.filter('[data-column="' + $target.attr('data-column') + '"]');
113
- if ($header.length > 1) { $target = $target.add($header); }
153
+ var column,
154
+ vars = wo.resizable_,
155
+ $extras = $( c.namespace + '_extra_headers' ),
156
+ $header = $( event.target ).data( 'header' );
157
+
158
+ column = parseInt( $header.attr( 'data-column' ), 10 );
159
+ vars.$target = $header = $header.add( $extras.filter('[data-column="' + column + '"]') );
160
+ vars.target = column;
161
+
114
162
  // if table is not as wide as it's parent, then resize the table
115
- $next = event.shiftKey ? $target.parent().find('th').not('.resizable-false').filter(':last') : $target.nextAll(':not(.resizable-false)').eq(0);
116
- mouseXPosition = event.pageX;
163
+ vars.$next = event.shiftKey || wo.resizable_targetLast ?
164
+ $header.parent().children().not( '.resizable-false' ).filter( ':last' ) :
165
+ $header.nextAll( ':not(.resizable-false)' ).eq( 0 );
166
+
167
+ column = parseInt( vars.$next.attr( 'data-column' ), 10 );
168
+ vars.$next = vars.$next.add( $extras.filter('[data-column="' + column + '"]') );
169
+ vars.next = column;
170
+
171
+ vars.mouseXPosition = event.pageX;
172
+ vars.storedSizes = c.$headers.map(function(){ return $(this).width(); }).get();
173
+ ts.resizable.toggleTextSelection( c, true );
117
174
  });
118
- $(document)
119
- .bind('mousemove.tsresize', function(event) {
120
- // ignore mousemove if no mousedown
121
- if (mouseXPosition === 0 || !$target) { return; }
122
- if (wo.resizable_throttle) {
123
- clearTimeout(timer);
124
- timer = setTimeout(function(){
125
- mouseMove(event);
126
- }, isNaN(wo.resizable_throttle) ? 5 : wo.resizable_throttle );
127
- } else {
128
- mouseMove(event);
129
- }
130
- })
131
- .bind('mouseup.tsresize', function() {
132
- stopResize();
175
+
176
+ $( document )
177
+ .bind( 'mousemove' + namespace, function( event ) {
178
+ var vars = wo.resizable_;
179
+ // ignore mousemove if no mousedown
180
+ if ( !vars.disabled || vars.mouseXPosition === 0 || !vars.$target ) { return; }
181
+ if ( wo.resizable_throttle ) {
182
+ clearTimeout( vars.timer );
183
+ vars.timer = setTimeout( function() {
184
+ ts.resizable.mouseMove( c, wo, event );
185
+ }, isNaN( wo.resizable_throttle ) ? 5 : wo.resizable_throttle );
186
+ } else {
187
+ ts.resizable.mouseMove( c, wo, event );
188
+ }
189
+ })
190
+ .bind( 'mouseup' + namespace, function() {
191
+ if (!wo.resizable_.disabled) { return; }
192
+ ts.resizable.toggleTextSelection( c, false );
193
+ ts.resizable.stopResize( c, wo );
194
+ ts.resizable.setHandlePosition( c, wo );
195
+ });
196
+
197
+ // resizeEnd event triggered by scroller widget
198
+ $( window ).bind( 'resize' + namespace + ' resizeEnd' + namespace, function() {
199
+ ts.resizable.setHandlePosition( c, wo );
133
200
  });
134
201
 
135
202
  // right click to reset columns to default widths
136
- $table.find('thead:first').bind('contextmenu.tsresize', function() {
137
- ts.resizableReset(table);
203
+ c.$table.find( 'thead:first' ).add( $( c.namespace + '_extra_table' ).find( 'thead:first' ) )
204
+ .bind( 'contextmenu' + namespace, function() {
138
205
  // $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset
139
- var allowClick = $.isEmptyObject ? $.isEmptyObject(storedSizes) : true;
140
- storedSizes = {};
206
+ var allowClick = wo.resizable_.storedSizes.length === 0;
207
+ ts.resizableReset( c.table );
208
+ ts.resizable.setHandlePosition( c, wo );
209
+ wo.resizable_.storedSizes = [];
141
210
  return allowClick;
142
211
  });
212
+
143
213
  },
144
- remove: function(table, c) {
145
- c.$table
146
- .removeClass('hasResizable')
147
- .children('thead')
148
- .unbind('mouseup.tsresize mouseleave.tsresize contextmenu.tsresize')
149
- .children('tr').children()
150
- .unbind('mousemove.tsresize mouseup.tsresize')
151
- // don't remove "tablesorter-wrapper" as uitheme uses it too
152
- .find('.' + ts.css.resizer).remove();
153
- ts.resizableReset(table);
214
+
215
+ mouseMove : function( c, wo, event ) {
216
+ if ( wo.resizable_.mouseXPosition === 0 || !wo.resizable_.$target ) { return; }
217
+ // resize columns
218
+ var vars = wo.resizable_,
219
+ $target = vars.$target,
220
+ $next = vars.$next,
221
+ leftEdge = event.pageX - vars.mouseXPosition,
222
+ targetWidth = $target.width();
223
+ if ( vars.fullWidth ) {
224
+ vars.storedSizes[ vars.target ] += leftEdge;
225
+ vars.storedSizes[ vars.next ] -= leftEdge;
226
+ ts.resizable.setWidths( c, wo );
227
+
228
+ } else if ( vars.overflow ) {
229
+ c.$table.add( $( c.namespace + '_extra_table' ) ).width(function(i, w){
230
+ return w + leftEdge;
231
+ });
232
+ if ( !$next.length ) {
233
+ // if expanding right-most column, scroll the wrapper
234
+ vars.$wrap[0].scrollLeft = c.$table.width();
235
+ }
236
+ } else {
237
+ vars.storedSizes[ vars.target ] += leftEdge;
238
+ ts.resizable.setWidths( c, wo );
239
+ }
240
+ vars.mouseXPosition = event.pageX;
241
+ },
242
+
243
+ stopResize : function( c, wo ) {
244
+ var vars = wo.resizable_;
245
+ vars.storedSizes = [];
246
+ if ( ts.storage ) {
247
+ vars.storedSizes = c.$headers.map(function(){ return $(this).width(); }).get();
248
+ if ( wo.resizable !== false ) {
249
+ // save all column widths
250
+ ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
251
+ }
252
+ }
253
+ vars.mouseXPosition = 0;
254
+ vars.$target = vars.$next = null;
255
+ $(window).trigger('resize'); // will update stickyHeaders, just in case
256
+ }
257
+ };
258
+
259
+ // this widget saves the column widths if
260
+ // $.tablesorter.storage function is included
261
+ // **************************
262
+ ts.addWidget({
263
+ id: "resizable",
264
+ priority: 40,
265
+ options: {
266
+ resizable : true,
267
+ resizable_addLastColumn : false,
268
+ resizable_widths : [],
269
+ resizable_throttle : false, // set to true (5ms) or any number 0-10 range
270
+ resizable_targetLast : false
271
+ },
272
+ init: function(table, thisWidget, c, wo) {
273
+ ts.resizable.init( c, wo );
274
+ },
275
+ remove: function( table, c, wo ) {
276
+ if (wo.$resizable_container) {
277
+ var namespace = c.namespace + 'tsresize';
278
+ c.$table.add( $( c.namespace + '_extra_table' ) )
279
+ .removeClass('hasResizable')
280
+ .children( 'thead' ).unbind( 'contextmenu' + namespace );
281
+
282
+ wo.$resizable_container.remove();
283
+ ts.resizable.toggleTextSelection( c, false );
284
+ ts.resizableReset( table );
285
+ $( document ).unbind( 'mousemove' + namespace + ' mouseup' + namespace );
286
+ }
154
287
  }
155
288
  });
156
- ts.resizableReset = function(table, nosave) {
157
- $(table).each(function(){
289
+
290
+ ts.resizableReset = function( table, nosave ) {
291
+ $( table ).each(function(){
158
292
  var $t,
159
293
  c = this.config,
160
294
  wo = c && c.widgetOptions;
161
- if (table && c) {
162
- c.$headers.each(function(i){
295
+ if ( table && c ) {
296
+ c.$headers.each( function( i ) {
163
297
  $t = $(this);
164
- if (wo.resizable_widths && wo.resizable_widths[i]) {
165
- $t.css('width', wo.resizable_widths[i]);
166
- } else if (!$t.hasClass('resizable-false')) {
298
+ if ( wo.resizable_widths && wo.resizable_widths[ i ] ) {
299
+ $t.css( 'width', wo.resizable_widths[ i ] );
300
+ } else if ( !$t.hasClass( 'resizable-false' ) ) {
167
301
  // don't clear the width of any column that is not resizable
168
- $t.css('width','');
302
+ $t.css( 'width', '' );
169
303
  }
170
304
  });
171
- if (ts.storage && !nosave) { ts.storage(this, 'tablesorter-resizable', {}); }
305
+ // reset stickyHeader widths
306
+ $( window ).trigger( 'resize' );
307
+ if ( ts.storage && !nosave ) {
308
+ ts.storage( this, ts.css.resizableStorage, {} );
309
+ }
172
310
  }
173
311
  });
174
312
  };
175
313
 
176
- })(jQuery, window);
314
+ })( jQuery, window );