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
@@ -11,23 +11,22 @@
11
11
 
12
12
  Resizable scroller widget for the jQuery tablesorter plugin
13
13
 
14
- Version 2.0 - modified by Rob Garrison 4/12/2013; updated 3/5/2015 (v2.21.0)
14
+ Version 2.0 - modified by Rob Garrison 4/12/2013;
15
+ updated 3/5/2015 (v2.22.2) with lots of help from TheSin-
15
16
  Requires jQuery v1.7+
16
17
  Requires the tablesorter plugin, v2.8+, available at http://mottie.github.com/tablesorter/docs/
17
18
 
18
19
  Usage:
19
-
20
20
  $(function() {
21
-
22
21
  $('table.tablesorter').tablesorter({
23
22
  widgets: ['zebra', 'scroller'],
24
23
  widgetOptions : {
25
24
  scroller_height : 300, // height of scroll window
26
- scroller_barWidth : 18, // scroll bar width
27
25
  scroller_jumpToHeader : true, // header snap to browser top when scrolling the tbody
26
+ scroller_upAfterSort : true, // scroll tbody to top after sorting
27
+ scroller_fixedColumns : 0 // set number of fixed columns
28
28
  }
29
29
  });
30
-
31
30
  });
32
31
 
33
32
  Website: www.tconnell.com
@@ -47,8 +46,15 @@ $.extend( ts.css, {
47
46
  scrollerFixed : 'tablesorter-scroller-fixed',
48
47
  scrollerFixedPanel : 'tablesorter-scroller-fixed-panel',
49
48
  scrollerHasFix : 'tablesorter-scroller-has-fixed-columns',
50
- scrollerReset : 'tablesorter-scroller-reset',
51
- scrollerRtl : 'tablesorter-scroller-rtl'
49
+ scrollerHideColumn : 'tablesorter-scroller-hidden-column',
50
+ scrollerHideElement : 'tablesorter-scroller-hidden',
51
+ scrollerSpacerRow : 'tablesorter-scroller-spacer',
52
+ scrollerBarSpacer : 'tablesorter-scroller-bar-spacer',
53
+ scrollerAddedHeight : 'tablesorter-scroller-added-height',
54
+ scrollerHack : 'tablesorter-scroller-scrollbar-hack',
55
+ // class name on table cannot start with 'tablesorter-' or the
56
+ // suffix "scroller-rtl" will match as a theme name
57
+ scrollerRtl : 'ts-scroller-rtl'
52
58
  });
53
59
 
54
60
  ts.addWidget({
@@ -56,18 +62,21 @@ ts.addWidget({
56
62
  priority : 60, // run after the filter widget
57
63
  options : {
58
64
  scroller_height : 300,
65
+ // pop table header into view while scrolling up the page
59
66
  scroller_jumpToHeader : true,
67
+ // scroll tbody to top after sorting
60
68
  scroller_upAfterSort : true,
61
- // set number of columns to fix
69
+ // set number of fixed columns
62
70
  scroller_fixedColumns : 0,
63
71
  // add hover highlighting to the fixed column (disable if it causes slowing)
64
72
  scroller_rowHighlight : 'hover',
65
73
  // add a fixed column overlay for styling
66
74
  scroller_addFixedOverlay : false,
67
- // bar width is now calculated; set a value to override
75
+ // In tablesorter v2.19.0 the scroll bar width is auto-detected
76
+ // add a value here to override the auto-detected setting
68
77
  scroller_barWidth : null
69
78
  },
70
- format: function( table, c, wo ) {
79
+ format : function( table, c, wo ) {
71
80
  if ( !c.isScrolling ) {
72
81
  // initialize here instead of in widget init to give the
73
82
  // filter widget time to finish building the filter row
@@ -81,59 +90,52 @@ ts.addWidget({
81
90
 
82
91
  /* Add window resizeEnd event */
83
92
  ts.window_resize = function() {
84
- if ( this.resize_timer ) {
85
- clearTimeout( this.resize_timer );
93
+ if ( ts.timer_resize ) {
94
+ clearTimeout( ts.timer_resize );
86
95
  }
87
- this.resize_timer = setTimeout( function() {
88
- $( this ).trigger( 'resizeEnd' );
96
+ ts.timer_resize = setTimeout( function() {
97
+ $( window ).trigger( 'resizeEnd' );
89
98
  }, 250 );
90
99
  };
91
100
 
92
101
  // Add extra scroller css
93
102
  $( function() {
94
103
  var style = '<style>' +
95
- /* measure scroll bar width */
96
- '.' + tscss.scrollerWrap + 'Measure { width: 100px; height: 100px; overflow: scroll; position: absolute; top: -9999px; }' +
97
- /* reset width to get accurate measurements after window resize */
98
- '.' + tscss.scrollerReset + ' { width: auto !important; min-width: auto !important; max-width: auto !important; }' +
99
104
  /* overall wrapper & table section wrappers */
100
105
  '.' + tscss.scrollerWrap + ' { position: relative; overflow: hidden; }' +
101
106
  /* add border-box sizing to all scroller widget tables; see #135 */
102
107
  '.' + tscss.scrollerWrap + ' * { box-sizing: border-box; }' +
103
- '.' + tscss.scrollerHeader + ', .' + tscss.scrollerFooter + ' { overflow: hidden; }' +
108
+ '.' + tscss.scrollerHeader + ', .' + tscss.scrollerFooter + ' { position: relative; overflow: hidden; }' +
104
109
  '.' + tscss.scrollerHeader + ' table.' + tscss.table + ' { margin-bottom: 0; }' +
105
- '.' + tscss.scrollerFooter + ' table.' + tscss.table + ' thead { visibility: hidden, height: 0; overflow: hidden; }' +
106
- /* always leave the scroll bar visible for tbody, or table overflows into the scrollbar when height < max height (filtering) */
107
- '.' + tscss.scrollerTable + ' { overflow-y: scroll; }' +
108
- '.' + tscss.scrollerTable + ' table.' + tscss.table + ' { border-top: 0; margin-top: 0; margin-bottom: 0; overflow-y: scroll; }' +
109
- /* hide filter row in clones */
110
- '.' + tscss.scrollerTable + ' .' + ( tscss.filterRow || 'tablesorter-filter-row' ) + ',.' + tscss.scrollerFooter + ' .' +
111
- ( tscss.filterRow || 'tablesorter-filter-row' ) + ',.' + tscss.scrollerTable + ' tfoot { display: none; }' +
112
- /* visibly hide header rows in clones, so we can still set a width on it and still effect the rest of the column */
113
- '.' + tscss.scrollerTable + ' table.' + tscss.table + ' thead tr.' + tscss.headerRow + ' *, .' + tscss.scrollerFooter +
114
- ' table.' + tscss.table + ' thead * { line-height: 0; height: 0; border: none; background-image: none; padding-top: 0;' +
115
- ' padding-bottom: 0; margin-top: 0; margin-bottom: 0; overflow: hidden; }' +
110
+ /* always leave the scroll bar visible for tbody, or table overflows into the scrollbar
111
+ when height < max height (filtering) */
112
+ '.' + tscss.scrollerTable + ' { position: relative; overflow: auto; }' +
113
+ '.' + tscss.scrollerTable + ' table.' + tscss.table +
114
+ ' { border-top: 0; margin-top: 0; margin-bottom: 0; overflow: hidden; }' +
115
+ /* hide footer in original table */
116
+ '.' + tscss.scrollerTable + ' tfoot, .' + tscss.scrollerHideElement + ', .' + tscss.scrollerHideColumn +
117
+ ' { display: none; }' +
116
118
 
117
119
  /*** fixed column ***/
118
120
  /* disable pointer-events on fixed column wrapper or the user can't interact with the horizontal scrollbar */
119
- '.' + tscss.scrollerFixed + ', .' + tscss.scrollerFixed + ' .' + tscss.scrollerFixedPanel + ' { pointer-events: none; }' +
121
+ '.' + tscss.scrollerFixed + ', .' + tscss.scrollerFixed + ' .' + tscss.scrollerFixedPanel +
122
+ ' { pointer-events: none; }' +
120
123
  /* enable pointer-events for fixed column children; see #135 & #878 */
121
124
  '.' + tscss.scrollerFixed + ' > div { pointer-events: all; }' +
122
125
  '.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixed + ' { position: absolute; top: 0; z-index: 1; left: 0 } ' +
123
126
  '.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixed + '.' + tscss.scrollerRtl + ' { left: auto; right: 0 } ' +
124
127
  /* add horizontal scroll bar; set to "auto", see #135 */
125
- '.' + tscss.scrollerWrap + '.' + tscss.scrollerHasFix + ' > .' + tscss.scrollerTable + ' { overflow-x: auto; }' +
126
- /* need to position the tbody & tfoot absolutely to hide the scrollbar & move the footer below the horizontal scrollbar */
128
+ '.' + tscss.scrollerWrap + '.' + tscss.scrollerHasFix + ' > .' + tscss.scrollerTable + ' { overflow: auto; }' +
129
+ /* need to position the tbody & tfoot absolutely to hide the scrollbar & move the footer
130
+ below the horizontal scrollbar */
127
131
  '.' + tscss.scrollerFixed + ' .' + tscss.scrollerFooter + ' { position: absolute; bottom: 0; }' +
128
- /* hide fixed tbody scrollbar - see http://goo.gl/VsLe6n */
129
- '.' + tscss.scrollerFixed + ' .' + tscss.scrollerTable + ' { position: relative; left: 0; overflow-x: hidden; overflow-y: scroll; -ms-overflow-style: none; }' +
132
+ /* hide fixed tbody scrollbar - see http://goo.gl/VsLe6n - set overflow to auto here for mousewheel scroll */
133
+ '.' + tscss.scrollerFixed + ' .' + tscss.scrollerTable +
134
+ ' { position: relative; left: 0; overflow: auto; -ms-overflow-style: none; }' +
130
135
  '.' + tscss.scrollerFixed + ' .' + tscss.scrollerTable + '::-webkit-scrollbar { display: none; }' +
131
- /* remove right border of fixed header tables to hide the boundary */
132
- '.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixed + ' table { border-right-color: transparent; padding-right: 0; }' +
133
- '.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixed + '.' + tscss.scrollerRtl + ' table { border-left-color: transparent; padding-left: 0; }' +
134
-
135
136
  /*** fixed column panel ***/
136
- '.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixedPanel + ' { position: absolute; top: 0; bottom: 0; z-index: 2; left: 0; right: 0; } ' +
137
+ '.' + tscss.scrollerWrap + ' .' + tscss.scrollerFixedPanel +
138
+ ' { position: absolute; top: 0; bottom: 0; z-index: 2; left: 0; right: 0; } ' +
137
139
  '</style>';
138
140
  $( style ).appendTo( 'body' );
139
141
  });
@@ -144,9 +146,18 @@ ts.scroller = {
144
146
  isFirefox : navigator.userAgent.toLowerCase().indexOf( 'firefox' ) > -1,
145
147
  // old IE needs a wrap to hide the fixed column scrollbar; http://stackoverflow.com/a/24408672/145346
146
148
  isOldIE : document.all && !window.atob,
147
-
148
- hasScrollBar : function( $target ) {
149
- return $target.get(0).scrollHeight > $target.height();
149
+ isIE : ( document.all && !window.atob ) || navigator.appVersion.indexOf( 'Trident/' ) > 0,
150
+ // http://stackoverflow.com/questions/7944460/detect-safari-browser - needed to position scrolling body
151
+ // when the table is set up in RTL direction
152
+ isSafari : navigator.userAgent.toLowerCase().indexOf( 'safari' ) > -1 &&
153
+ navigator.userAgent.toLowerCase().indexOf( 'chrome' ) === -1,
154
+
155
+ hasScrollBar : function( $target, checkWidth ) {
156
+ if ( checkWidth ) {
157
+ return $target.get(0).scrollWidth > $target.width();
158
+ } else {
159
+ return $target.get(0).scrollHeight > $target.height();
160
+ }
150
161
  },
151
162
 
152
163
  setWidth : function( $el, width ) {
@@ -159,39 +170,56 @@ ts.scroller = {
159
170
 
160
171
  // modified from http://davidwalsh.name/detect-scrollbar-width
161
172
  getBarWidth : function() {
162
- var $scrollDiv = $( '<div class="' + tscss.scrollerWrap + 'Measure">' ).appendTo( 'body' ),
163
- div = $scrollDiv[ 0 ],
164
- barWidth = div.offsetWidth - div.clientWidth;
165
- $scrollDiv.remove();
173
+ var $div = $( '<div>' ).css({
174
+ 'position' : 'absolute',
175
+ 'top' : '-9999px',
176
+ 'left' : 0,
177
+ 'width' : '100px',
178
+ 'height' : '100px',
179
+ 'overflow' : 'scroll',
180
+ 'visibility' : 'hidden'
181
+ }).appendTo( 'body' ),
182
+ div = $div[0],
183
+ barWidth = div.offsetWidth - div.clientWidth;
184
+ $div.remove();
166
185
  return barWidth;
167
186
  },
168
187
 
169
188
  setup : function( c, wo ) {
170
- var maxHt, tbHt, $hdr, $t, $hCells, $fCells, $tableWrap,
189
+ var maxHt, tbHt, $hdr, $t, $hCells, $fCells, $tableWrap, events, tmp,
171
190
  $win = $( window ),
191
+ tsScroller = ts.scroller,
172
192
  namespace = c.namespace + 'tsscroller',
173
193
  $foot = $(),
174
194
  // c.namespace contains a unique tablesorter ID, per table
175
195
  id = c.namespace.slice( 1 ) + 'tsscroller',
176
196
  $table = c.$table;
177
197
 
178
- // force developer to set fixedWidth to maintain column widths
198
+ // force config.widthFixed option - this helps maintain proper alignment across cloned tables
179
199
  c.widthFixed = true;
200
+
201
+ wo.scroller_calcWidths = [];
202
+ wo.scroller_saved = [ 0, 0 ];
203
+ wo.scroller_isBusy = true;
204
+
205
+ // set scrollbar width & allow setting width to zero
206
+ wo.scroller_barSetWidth = wo.scroller_barWidth !== null ?
207
+ wo.scroller_barWidth :
208
+ ( tsScroller.getBarWidth() || 15 );
209
+
180
210
  maxHt = wo.scroller_height || 300;
181
- tbHt = $table.children( 'tbody' ).height();
182
- if ( tbHt !== 0 && maxHt > tbHt ) { maxHt = tbHt + 10; } // Table is less than h px
183
211
 
184
- wo.scroller_$header = $hdr = $( '<table class="' + $table.attr( 'class' ) + '" cellpadding=0 cellspacing=0>' +
185
- $table.children( 'thead' )[0].outerHTML +
186
- '</table>' )
187
- .addClass( c.namespace.slice(1) + '_extra_table' );
212
+ $hdr = $( '<table class="' + $table.attr( 'class' ) + '" cellpadding=0 cellspacing=0>' +
213
+ $table.children( 'thead' )[ 0 ].outerHTML + '</table>' );
214
+ wo.scroller_$header = $hdr.addClass( c.namespace.slice( 1 ) + '_extra_table' );
188
215
 
189
216
  $t = $table.children( 'tfoot' );
190
217
  if ( $t.length ) {
191
- $foot = $( '<table class="' + $table.attr('class') + '" cellpadding=0 cellspacing=0 style="margin-top:0"></table>' )
192
- .addClass( c.namespace.slice(1) + '_extra_table' )
193
- .append( $t.clone( true ) ) // maintain any bindings on the tfoot cells
194
- .append( $table.children( 'thead' )[ 0 ].outerHTML )
218
+ $foot = $( '<table class="' + $table.attr( 'class' ) +
219
+ '" cellpadding=0 cellspacing=0 style="margin-top:0"></table>' )
220
+ .addClass( c.namespace.slice( 1 ) + '_extra_table' )
221
+ // maintain any bindings on the tfoot cells
222
+ .append( $t.clone( true ) )
195
223
  .wrap( '<div class="' + tscss.scrollerFooter + '"/>' );
196
224
  $fCells = $foot.children( 'tfoot' ).eq( 0 ).children( 'tr' ).children();
197
225
  }
@@ -201,7 +229,8 @@ ts.scroller = {
201
229
  .wrap( '<div id="' + id + '" class="' + tscss.scrollerWrap + '" />' )
202
230
  .before( $hdr )
203
231
  // shrink filter row but don't completely hide it because the inputs/selectors may distort the columns
204
- .find( '.' + tscss.filterRow ).addClass( tscss.filterRowHide );
232
+ .find( '.' + tscss.filterRow )
233
+ .addClass( tscss.filterRowHide );
205
234
 
206
235
  wo.scroller_$container = $table.parent();
207
236
 
@@ -223,19 +252,12 @@ ts.scroller = {
223
252
 
224
253
  // look for filter widget
225
254
  if ( $table.hasClass( 'hasFilters' ) ) {
226
- ts.filter.bindSearch( $table, $hdr.find('.' + tscss.filter) );
227
- }
228
-
229
- // remove any previous fixed columns ( in case we're updating )
230
- wo.scroller_$container.find( '.' + tscss.scrollerFixed ).remove();
231
-
232
- if ( wo.scroller_fixedColumns > 0 ) {
233
- ts.scroller.setupFixed( c, wo );
255
+ ts.filter.bindSearch( $table, $hdr.find( '.' + tscss.filter ) );
234
256
  }
235
257
 
236
- ts.scroller.resize( c, wo );
237
-
238
- $table.find( 'thead' ).css( 'visibility', 'hidden' );
258
+ $table
259
+ .find( 'thead' )
260
+ .addClass( tscss.scrollerHideElement );
239
261
 
240
262
  tbHt = $tableWrap.parent().height();
241
263
 
@@ -249,33 +271,60 @@ ts.scroller = {
249
271
  $win.scrollTop( $hdr.offset().top );
250
272
  }
251
273
  }
252
- $hdr.parent().add( $foot.parent() ).scrollLeft( $( this ).scrollLeft() );
274
+ $hdr
275
+ .parent()
276
+ .add( $foot.parent() )
277
+ .scrollLeft( $( this ).scrollLeft() );
253
278
  });
254
279
 
255
- // Sorting, so scroll to top
280
+ // resize/update events
281
+ events = ( ( ts.hasWidget( c.table, 'filter' ) ? 'filterEnd' : 'tablesorter-initialized' ) +
282
+ ' updateComplete pagerComplete columnUpdate ' ).split( ' ' ).join( namespace + ' ' );
283
+
256
284
  $table
257
- .off( 'sortEnd setFixedColumnSize updateComplete '.split( ' ' ).join( namespace + ' ' ) )
258
- .on( 'sortEnd' + namespace, function() {
259
- if ( wo.scroller_upAfterSort ) {
260
- $table.parent().animate({ scrollTop: 0 }, 'fast' );
285
+ .off( namespace )
286
+ .on( 'sortEnd filterEnd'.split( ' ' ).join( namespace + ' ' ), function( event ) {
287
+ // Sorting, so scroll to top
288
+ if ( event.type === 'sortEnd' && wo.scroller_upAfterSort ) {
289
+ $tableWrap.animate({
290
+ scrollTop : 0
291
+ }, 'fast' );
292
+ } else if ( wo.scroller_fixedColumns ) {
293
+ setTimeout( function() {
294
+ // restore previous scroll position
295
+ $tableWrap
296
+ .scrollTop( wo.scroller_saved[1] )
297
+ .scrollLeft( wo.scroller_saved[0] );
298
+ tsScroller.updateFixed( c, wo, false );
299
+ }, 0 );
261
300
  }
262
301
  })
263
302
  .on( 'setFixedColumnSize' + namespace, function( event, size ) {
303
+ var $wrap = wo.scroller_$container;
264
304
  if ( typeof size !== 'undefined' && !isNaN( size ) ) {
265
305
  wo.scroller_fixedColumns = parseInt( size, 10 );
266
306
  }
267
307
  // remove fixed columns
268
- wo.scroller_$container.find( '.' + tscss.scrollerFixed ).remove();
308
+ tsScroller.removeFixed( c, wo );
269
309
  size = wo.scroller_fixedColumns;
270
310
  if ( size > 0 && size < c.columns - 1 ) {
271
- ts.scroller.setupFixed( c, wo );
272
- } else {
273
- wo.scroller_$container.removeClass( tscss.scrollerHasFix );
311
+ tsScroller.updateFixed( c, wo );
312
+ } else if ( $wrap.hasClass( tscss.scrollerHasFix ) ) {
313
+ $wrap.removeClass( tscss.scrollerHasFix );
314
+ // resize needed to make tables full width
315
+ tsScroller.resize( c, wo );
274
316
  }
275
317
  })
276
- .on( 'updateComplete' + namespace, function() {
318
+ .on( events, function( event ) {
319
+ // Stop from running twice with pager
320
+ if ( ts.hasWidget( 'pager' ) && event.type === 'updateComplete' ) {
321
+ return;
322
+ }
323
+ if ( wo.scroller_fixedColumns > 0 ) {
324
+ tsScroller.updateFixed( c, wo, false );
325
+ }
277
326
  // adjust column sizes after an update
278
- ts.scroller.resize( c, wo );
327
+ tsScroller.resize( c, wo );
279
328
  });
280
329
 
281
330
  // Setup window.resizeEnd event
@@ -286,110 +335,128 @@ ts.scroller = {
286
335
  // IE calls resize when you modify content, so we have to unbind the resize event
287
336
  // so we don't end up with an infinite loop. we can rebind after we're done.
288
337
  $win.off( 'resize' + namespace, ts.window_resize );
289
- ts.scroller.resize( c, wo );
338
+ tsScroller.resize( c, wo );
290
339
  $win.on( 'resize' + namespace, ts.window_resize );
340
+ $tableWrap.trigger( 'scroll' + namespace );
291
341
  });
292
342
 
293
343
  // initialization flag
294
344
  c.isScrolling = true;
295
345
 
346
+ tsScroller.updateFixed( c, wo );
347
+
296
348
  },
297
349
 
298
350
  resize : function( c, wo ) {
299
- var index, borderWidth, setWidth, $hCells, $bCells, $fCells, $headers, $this,
351
+ if ( wo.scroller_isBusy ) { return; }
352
+ var index, borderWidth, setWidth, $hCells, $bCells, $fCells, $headers, $this, temp,
353
+ tsScroller = ts.scroller,
354
+ $container = wo.scroller_$container,
300
355
  $table = c.$table,
301
356
  $tableWrap = $table.parent(),
302
357
  $hdr = wo.scroller_$header,
303
358
  $foot = wo.scroller_$footer,
304
359
  id = c.namespace.slice( 1 ) + 'tsscroller',
305
360
  // Hide other scrollers so we can resize
306
- $div = $( 'div.' + tscss.scrollerWrap + '[id != "' + id + '"]' ).hide();
361
+ $div = $( 'div.' + tscss.scrollerWrap + '[id!="' + id + '"]' )
362
+ .addClass( tscss.scrollerHideElement ),
363
+ row = '<tr class="' + tscss.scrollerSpacerRow + ' ' + c.selectorRemove.slice(1) + '">';
307
364
 
308
- $table.children( 'thead' ).show();
309
- // only remove colgroup if it was added by the plugin
310
- // the $.tablesorter.fixColumnWidth() function already does this (v2.19.0)
311
- // but we need to get "accurate" resized measurements here - see issue #680
312
- $table.add( $hdr ).add( $foot ).children( 'colgroup' ).remove();
365
+ wo.scroller_calcWidths = [];
313
366
 
314
- // Reset sizes so parent can resize.
367
+ // Remove fixed so we get proper widths and heights
368
+ tsScroller.removeFixed( c, wo );
369
+ $container.find( '.' + tscss.scrollerSpacerRow ).remove();
370
+ // remove ts added colgroups
371
+ $container.find( '.' + ts.css.colgroup ).remove();
372
+
373
+ // show original table elements to get proper alignment
315
374
  $table
316
- .addClass( tscss.scrollerReset )
317
- .children( 'thead' )
318
- .find( '.' + tscss.headerIn ).addClass( tscss.scrollerReset ).end()
319
- .find( '.' + tscss.filterRow ).show();
320
- $tableWrap.addClass( tscss.scrollerReset );
375
+ .find( '.' + tscss.scrollerHideElement )
376
+ .removeClass( tscss.scrollerHideElement );
321
377
 
322
378
  // include left & right border widths
323
379
  borderWidth = parseInt( $table.css( 'border-left-width' ), 10 );
324
380
 
325
- // Shrink a bit to accommodate scrollbar
326
- wo.scroller_barSetWidth = ( wo.scroller_barWidth || ts.scroller.getBarWidth() || 18 ) + borderWidth;
381
+ $headers = c.$headerIndexed;
327
382
 
328
- $tableWrap.width( $tableWrap.parent().innerWidth() - ( ts.scroller.hasScrollBar( $tableWrap.parent() ) ? wo.scroller_barSetWidth : 0 ) );
329
- setWidth = $tableWrap.innerWidth() - ( ts.scroller.hasScrollBar( $tableWrap ) ? wo.scroller_barSetWidth : 0 ) + borderWidth;
330
- $hdr.parent().add( $foot.parent() ).width( setWidth );
331
-
332
- $hCells = $hdr.children( 'thead' ).children().children( 'th, td' ).filter( ':visible' );
333
- $bCells = $table.children('tbody').eq( 0 ).children().eq( 0 ).children( 'th, td' ).filter( ':visible' );
334
- $fCells = $foot.children( 'tfoot' ).children().children( 'th, td' ).filter( ':visible' );
335
-
336
- ts.scroller.setWidth( $hCells.add( $bCells ).add( $fCells ), '' );
337
- $headers = $table.children( 'thead' ).children().eq( 0 ).children( 'th, td' );
338
- for ( index = 0; index < $headers.length; index++ ) {
339
- $this = $headers.eq( index );
383
+ for ( index = 0; index < c.columns; index++ ) {
384
+ $this = $headers[ index ];
340
385
  // code from https://github.com/jmosbech/StickyTableHeaders
341
386
  if ( $this.css( 'box-sizing' ) === 'border-box' ) {
342
387
  setWidth = $this.outerWidth();
343
388
  } else {
344
389
  if ( $hCells.eq( index ).css( 'border-collapse' ) === 'collapse' ) {
345
390
  if ( $this.length && window.getComputedStyle ) {
346
- setWidth = parseFloat( window.getComputedStyle( $this[0], null ).width );
391
+ setWidth = parseFloat( window.getComputedStyle( $this[ 0 ], null ).width );
347
392
  } else {
348
393
  // ie8 only
349
- borderWidth = parseFloat( $this.css( 'border-width' ) ) || 0;
350
- setWidth = $this.outerWidth() - parseFloat( $this.css( 'padding-left' ) ) - parseFloat( $this.css( 'padding-right' ) ) - borderWidth;
394
+ setWidth = $this.outerWidth() - parseFloat( $this.css( 'padding-left' ) ) -
395
+ parseFloat( $this.css( 'padding-right' ) ) -
396
+ ( parseFloat( $this.css( 'border-width' ) ) || 0 );
351
397
  }
352
398
  } else {
353
399
  setWidth = $this.width();
354
400
  }
355
401
  }
356
- ts.scroller.setWidth( $hCells.eq( index ).add( $bCells.eq( index ) ).add( $fCells.eq( index ) ), setWidth );
357
- }
402
+ row += '<td data-column="' + index + '" style="padding:0;margin:0;border:0;height:0;max-height:0;' +
403
+ 'min-height:0;width:' + setWidth + 'px;min-width:' + setWidth + 'px;max-width:' + setWidth + 'px"></td>';
358
404
 
359
- wo.scroller_$container
360
- .find( '.' + tscss.scrollerReset )
361
- .removeClass( tscss.scrollerReset );
405
+ // save current widths
406
+ wo.scroller_calcWidths[ index ] = setWidth;
407
+ }
408
+ row += '</tr>';
409
+ c.$tbodies.eq(0).prepend( row ); // tbody
410
+ $hdr.children( 'thead' ).append( row );
411
+ $foot.children( 'tfoot' ).append( row );
362
412
 
363
- // refresh colgroup & copy to cloned header
413
+ // include colgroup or alignment is off
364
414
  ts.fixColumnWidth( c.table );
415
+ row = c.$table.children( 'colgroup' )[0].outerHTML;
416
+ $hdr.prepend( row );
417
+ $foot.prepend( row );
365
418
 
366
- // add colgroup to all clones
367
- $hCells = $table.children( 'colgroup' );
368
- if ( $hCells.length ) {
369
- $bCells = $hCells[0].outerHTML;
370
- $hdr.prepend( $bCells );
371
- if ( $foot.length ) {
372
- $foot.prepend( $bCells );
373
- }
374
- }
419
+ temp = $tableWrap.parent().innerWidth() -
420
+ ( tsScroller.hasScrollBar( $tableWrap ) ? wo.scroller_barSetWidth : 0 );
421
+ $tableWrap.width( temp );
422
+
423
+ temp = ( tsScroller.hasScrollBar( $tableWrap ) ? wo.scroller_barSetWidth : 0 ) + borderWidth;
424
+ setWidth = $tableWrap.innerWidth() - temp;
425
+
426
+ $hdr
427
+ .parent()
428
+ .add( $foot.parent() )
429
+ .width( setWidth );
430
+
431
+ $tableWrap
432
+ .width( setWidth + temp );
433
+
434
+ // hide original table thead
435
+ $table.children( 'thead' ).addClass( tscss.scrollerHideElement );
375
436
 
376
437
  // update fixed column sizes
377
- if ( wo.scroller_fixedColumns > 0 ) {
378
- ts.scroller.updateFixed( c, wo, true );
379
- }
438
+ tsScroller.updateFixed( c, wo );
380
439
 
381
- // hide filter row because filterEnd event fires
382
- $table.children( 'thead' ).find( '.' + tscss.filterRow ).hide();
440
+ $div.removeClass( tscss.scrollerHideElement );
441
+
442
+ // restore scrollTop - fixes #926
443
+ $tableWrap.scrollTop( wo.scroller_saved[1] );
444
+ wo.scroller_$container
445
+ .find( '.' + tscss.scrollerFixed )
446
+ .find( '.' + tscss.scrollerTable )
447
+ .scrollTop( wo.scroller_saved[1] );
383
448
 
384
- $div.show();
449
+ // update resizable widget handles
450
+ setTimeout( function() {
451
+ c.$table.trigger( 'resizableUpdate' );
452
+ }, 100 );
385
453
 
386
454
  },
387
455
 
388
- // Add fixed (frozen) columns
456
+ // Add fixed (frozen) columns (Do not call directly, use updateFixed)
389
457
  setupFixed : function( c, wo ) {
390
- var index, index2, $el, len, temp, $fixedColumn, $fixedTbody, $fixedContainer,
458
+ var index, index2, $el, len, temp, $fixedColumn, $fixedTbody,
391
459
  $table = c.$table,
392
- namespace = c.namespace + 'tsscrollerFixed',
393
460
  $wrapper = wo.scroller_$container,
394
461
  fixedColumns = wo.scroller_fixedColumns;
395
462
 
@@ -399,14 +466,18 @@ ts.scroller = {
399
466
  .addClass( tscss.scrollerFixed )
400
467
  .removeClass( tscss.scrollerWrap )
401
468
  .attr( 'id', '' );
469
+
402
470
  if ( wo.scroller_addFixedOverlay ) {
403
471
  $fixedColumn.append( '<div class="' + tscss.scrollerFixedPanel + '">' );
404
472
  }
473
+
405
474
  $fixedTbody = $fixedColumn.find( '.' + tscss.scrollerTable );
406
- $fixedTbody.find( 'table' )
407
- .addClass( c.namespace.slice(1) + '_extra_table' )
408
- .attr( 'id', '' );
409
- $fixedContainer = $fixedTbody.find( 'tbody' );
475
+ $fixedTbody
476
+ .children( 'table' )
477
+ .addClass( c.namespace.slice( 1 ) + '_extra_table' )
478
+ .attr( 'id', '' )
479
+ .children( 'thead, tfoot' )
480
+ .remove();
410
481
 
411
482
  wo.scroller_$fixedColumns = $fixedColumn;
412
483
 
@@ -420,13 +491,22 @@ ts.scroller = {
420
491
  for ( index = 0; index < len; index++ ) {
421
492
  $el.eq( index ).children( ':gt(' + ( fixedColumns - 1 ) + ')' ).remove();
422
493
  }
423
- $fixedColumn.hide().prependTo( $wrapper );
494
+ $fixedColumn
495
+ .addClass( tscss.scrollerHideElement )
496
+ .prependTo( $wrapper );
424
497
 
425
498
  // look for filter widget
426
499
  if ( c.$table.hasClass( 'hasFilters' ) ) {
500
+ // make sure fixed column filters aren't disabled
501
+ $el = $fixedColumn
502
+ .find( '.' + tscss.filter )
503
+ .not( '.' + tscss.filterDisabled )
504
+ .prop( 'disabled', false );
427
505
  ts.filter.bindSearch( $table, $fixedColumn.find( '.' + tscss.filter ) );
428
506
  // disable/enable filters behind fixed column
429
- $el = $wrapper.children( '.' + tscss.scrollerHeader ).find( '.' + tscss.filter );
507
+ $el = $wrapper
508
+ .children( '.' + tscss.scrollerHeader )
509
+ .find( '.' + tscss.filter );
430
510
  len = $el.length;
431
511
  for ( index = 0; index < len; index++ ) {
432
512
  // previously disabled filter; don't mess with it! filterDisabled class added by filter widget
@@ -441,10 +521,14 @@ ts.scroller = {
441
521
  c.$table
442
522
  .add( '.' + tscss.scrollerFooter + ' table' )
443
523
  .children( 'thead' )
444
- .children( 'tr.' + tscss.headerRow ).children().attr( 'tabindex', -1 );
524
+ .children( 'tr.' + tscss.headerRow )
525
+ .children()
526
+ .attr( 'tabindex', -1 );
527
+
445
528
  $el = wo.scroller_$header
446
529
  .add( $fixedColumn.find( '.' + tscss.scrollerTable + ' table' ) )
447
- .children( 'thead' ).children( 'tr.' + tscss.headerRow );
530
+ .children( 'thead' )
531
+ .children( 'tr.' + tscss.headerRow );
448
532
  len = $el.length;
449
533
  for ( index = 0; index < len; index++ ) {
450
534
  temp = $el.eq( index ).children();
@@ -454,179 +538,363 @@ ts.scroller = {
454
538
  }
455
539
 
456
540
  ts.bindEvents( c.table, $fixedColumn.find( '.' + tscss.header ) );
541
+ ts.scroller.bindFixedColumnEvents( c, wo );
542
+
543
+ /*** Scrollbar hack! Since we can't hide the scrollbar with css ***/
544
+ if ( ts.scroller.isFirefox || ts.scroller.isOldIE ) {
545
+ $fixedTbody.wrap( '<div class="' + tscss.scrollerHack + '" style="overflow:hidden;">' );
546
+ }
547
+
548
+ },
457
549
 
550
+ bindFixedColumnEvents : function( c, wo ) {
458
551
  // update thead & tbody in fixed column
459
- temp = ( 'tablesorter-initialized sortEnd filterEnd ' ).split( ' ' ).join( namespace + ' ' );
552
+ var tsScroller = ts.scroller,
553
+ namespace = c.namespace + 'tsscrollerFixed',
554
+ events = 'scroll' + namespace,
555
+ $fixedTbody = wo.scroller_$fixedColumns.find( '.' + tscss.scrollerTable ),
556
+ fixedScroll = true,
557
+ tableScroll = true;
558
+
460
559
  c.$table
461
- .off( temp )
462
- .on( temp, function( event, size ) {
463
- ts.scroller.updateFixed( c, wo, false );
464
- })
465
560
  .parent()
466
561
  // *** SCROLL *** scroll fixed column along with main
467
- .off( 'scroll' + namespace )
468
- .on( 'scroll' + namespace, function() {
469
- $fixedTbody.scrollTop( $( this ).scrollTop() );
562
+ .off( events )
563
+ .on( events, function() {
564
+ if ( wo.scroller_isBusy ) { return; }
565
+ // using flags to prevent firing the scroll event excessively leading to slow scrolling in Firefox
566
+ if ( !wo.scroller_isBusy && ( fixedScroll || !( tsScroller.isFirefox || tsScroller.isIE ) ) ) {
567
+ tableScroll = false;
568
+ var $this = $( this );
569
+ $fixedTbody[0].scrollTop = wo.scroller_saved[1] = $this.scrollTop();
570
+ wo.scroller_saved[0] = $this.scrollLeft();
571
+ setTimeout( function() {
572
+ tableScroll = true;
573
+ }, 20 );
574
+ }
470
575
  });
471
576
  // scroll main along with fixed column
472
577
  $fixedTbody
473
- .off( 'scroll' + namespace )
474
- .on( 'scroll' + namespace, function() {
475
- c.$table.parent().scrollTop( $fixedTbody.scrollTop() );
578
+ .off( events )
579
+ .on( events, function() {
580
+ // using flags to prevent firing the scroll event excessively leading to slow scrolling in Firefox
581
+ if ( !wo.scroller_isBusy && ( tableScroll || !( tsScroller.isFirefox || tsScroller.isIE ) ) ) {
582
+ fixedScroll = false;
583
+ var $this = $( this );
584
+ c.$table.parent()[0].scrollTop = wo.scroller_saved[1] = $this.scrollTop();
585
+ setTimeout( function() {
586
+ fixedScroll = true;
587
+ }, 20 );
588
+ }
476
589
  })
477
590
  .scroll();
478
591
 
479
592
  // *** ROW HIGHLIGHT ***
480
593
  if ( wo.scroller_rowHighlight !== '' ) {
481
- temp = 'mouseover mouseleave '.split( ' ' ).join( namespace + ' ' );
594
+ events = 'mouseover mouseleave '.split( ' ' ).join( namespace + ' ' );
595
+ // can't use c.$tbodies because it doesn't include info-only tbodies
482
596
  c.$table
483
- .off( temp, 'tr' )
484
- .on( temp, 'tr', function( event ) {
485
- var indx = $( this ).index();
486
- $fixedContainer.children().eq( indx )
597
+ .off( events, 'tbody > tr' )
598
+ .on( events, 'tbody > tr', function( event ) {
599
+ var indx = c.$table.children( 'tbody' ).children( 'tr' ).index( this );
600
+ $fixedTbody
601
+ .children( 'table' )
602
+ .children( 'tbody' )
603
+ .children( 'tr' )
604
+ .eq( indx )
487
605
  .add( this )
488
606
  .toggleClass( wo.scroller_rowHighlight, event.type === 'mouseover' );
489
607
  });
490
- $fixedTbody.find( 'table' )
491
- .off( temp, 'tr' )
492
- .on( temp, 'tr', function( event ) {
493
- var indx = $( this ).index();
494
- c.$tbodies.children().eq( indx )
608
+ $fixedTbody
609
+ .find( 'table' )
610
+ .off( events, 'tbody > tr' )
611
+ .on( events, 'tbody > tr', function( event ) {
612
+ var $fixed = $fixedTbody.children( 'table' ).children( 'tbody' ).children( 'tr' ),
613
+ indx = $fixed.index( this );
614
+ c.$table
615
+ .children( 'tbody' )
616
+ .children( 'tr' )
617
+ .eq( indx )
495
618
  .add( this )
496
619
  .toggleClass( wo.scroller_rowHighlight, event.type === 'mouseover' );
497
620
  });
498
621
  }
622
+ },
499
623
 
500
- /*** Scrollbar hack! Since we can't hide the scrollbar with css ***/
501
- if ( ts.scroller.isFirefox || ts.scroller.isOldIE ) {
502
- $fixedTbody.wrap( '<div class="scroller-scrollbar-hack" style="overflow:hidden;">' );
503
- }
504
-
505
- ts.scroller.updateFixed( c, wo, true );
624
+ adjustWidth : function( c, wo, totalWidth, adj, dir ) {
625
+ var $wrapper = wo.scroller_$container;
506
626
 
627
+ // RTL support (fixes column on right)
628
+ $wrapper
629
+ .children( '.' + tscss.scrollerTable )
630
+ .css( dir ? 'right' : 'left', totalWidth );
631
+ $wrapper
632
+ .children( '.' + tscss.scrollerHeader + ', .' + tscss.scrollerFooter )
633
+ // Safari needs a scrollbar width of extra adjusment to align the fixed & scrolling columns
634
+ .css( dir ? 'right' : 'left', totalWidth + ( dir && ts.scroller.isSafari ? adj : 0 ) );
507
635
  },
508
636
 
509
637
  updateFixed : function( c, wo ) {
510
- if ( !c.isScrolling ) { return; }
638
+ var temp, adj,
639
+ $wrapper = wo.scroller_$container,
640
+ $hdr = wo.scroller_$header,
641
+ $foot = wo.scroller_$footer,
642
+ $table = c.$table,
643
+ $tableWrap = $table.parent(),
644
+ scrollBarWidth = wo.scroller_barSetWidth,
645
+ dir = $table.hasClass( tscss.scrollerRtl );
646
+
647
+ if ( wo.scroller_fixedColumns === 0 ) {
648
+ wo.scroller_isBusy = false;
649
+ ts.scroller.removeFixed( c, wo );
650
+ temp = $wrapper.width();
651
+ $tableWrap.width( temp );
652
+ adj = ts.scroller.hasScrollBar( $tableWrap ) ? scrollBarWidth : 0;
653
+ $hdr
654
+ .parent()
655
+ .add( $foot.parent() )
656
+ .width( temp - adj );
657
+ return;
658
+ }
659
+
660
+ if ( !c.isScrolling ) {
661
+ return;
662
+ }
663
+
664
+ wo.scroller_isBusy = true;
511
665
 
512
- // no idea why this happens, but sometimes the main table wrapper gets the scrollbar width
513
- // subtracted from it on load and on theme change - it can be very sporatic; this fixes it.
514
- c.$table.parent().width( wo.scroller_$container.width() );
666
+ // Make sure the wo.scroller_$fixedColumns container exists, if not build it
667
+ if ( !$wrapper.find( '.' + tscss.scrollerFixed ).length ) {
668
+ ts.scroller.setupFixed( c, wo );
669
+ }
515
670
 
516
671
  // scroller_fixedColumns
517
- var index, tbodyIndex, rowIndex, $tbody, $adjCol, $fb, totalRows, widths,
518
- $table = c.$table,
519
- $wrapper = wo.scroller_$container,
672
+ var index, tbodyIndex, rowIndex, $tbody, $adjCol, $fb, $fixHead, $fixBody, $fixFoot,
673
+ totalRows, row,
520
674
 
521
675
  // source cells for measurement
522
- $mainTbodies = wo.scroller_$container.children( '.' + tscss.scrollerTable ).children( 'table' ).children( 'tbody' ),
523
- $rows = wo.scroller_$header.children( 'thead' ).children( '.' + tscss.headerRow ), // variable gets redefined
676
+ $mainTbodies = wo.scroller_$container
677
+ .children( '.' + tscss.scrollerTable )
678
+ .children( 'table' )
679
+ .children( 'tbody' ),
680
+ // variable gets redefined
681
+ $rows = wo.scroller_$header
682
+ .children( 'thead' )
683
+ .children( '.' + tscss.headerRow ),
524
684
 
525
685
  // hide fixed column during resize, or we get a FOUC
526
- $fixedColumn = wo.scroller_$fixedColumns.hide(),
686
+ $fixedColumn = wo.scroller_$fixedColumns
687
+ .addClass( tscss.scrollerHideElement ),
527
688
 
528
689
  // target cells
529
- $fixedTbodiesTable = $fixedColumn.find( '.' + tscss.scrollerTable ).children( 'table' ),
530
- $fixedTbodies = $fixedTbodiesTable.children( 'tbody' ),
531
- $fixedHeader = $fixedColumn.find( '.' + tscss.scrollerHeader ).children( 'table' ).children( 'thead' ),
690
+ $fixedTbodiesTable = $fixedColumn
691
+ .find( '.' + tscss.scrollerTable )
692
+ .children( 'table' ),
693
+ $fixedTbodies = $fixedTbodiesTable
694
+ .children( 'tbody' ),
532
695
  // variables
533
696
  tsScroller = ts.scroller,
534
- scrollBarWidth = wo.scroller_barSetWidth,
535
697
  fixedColumns = wo.scroller_fixedColumns,
536
698
  // get dimensions
537
699
  $temp = $table.find( 'tbody td' ),
538
700
  borderRightWidth = parseInt( $temp.css( 'border-right-width' ), 10 ) || 1,
539
- borderBottomWidth = parseInt( $temp.css( 'border-bottom-width' ), 10 ) || 1,
540
- borderSpacing = parseInt( $temp.css( 'border-spacing' ).split( /\s/ )[ 0 ], 10 ) / 2 || 0,
541
- totalWidth = parseInt( $table.css( 'padding-left' ), 10 ) + parseInt( $table.css( 'padding-right' ), 10 ) - borderRightWidth;
542
-
543
- // fixed header cell height
544
- $temp = $fixedHeader.children( '.' + tscss.headerRow );
545
- for ( index = 0; index < $temp.length; index++ ) {
546
- $temp.eq( index ).height( $rows.eq( index ).outerHeight() );
547
- }
701
+ borderSpacing = parseInt( ( $temp.css( 'border-spacing' ) || '' ).split( /\s/ )[ 0 ], 10 ) / 2 || 0,
702
+ totalWidth = parseInt( $table.css( 'padding-left' ), 10 ) +
703
+ parseInt( $table.css( 'padding-right' ), 10 ) -
704
+ borderRightWidth,
705
+ widths = wo.scroller_calcWidths;
548
706
 
549
- // body cell dimensions seem to be more accurate *shrug*
550
- $rows = ( c.filteredRows > 0 ? c.$tbodies : $table.children( 'thead' ) ).children( 'tr:visible' );
551
- // recalculate widths
552
- widths = $rows.children( ':lt(' + fixedColumns + ')' ).map( function() {
553
- totalWidth += $( this ).outerWidth() + borderSpacing;
554
- return $( this ).outerWidth();
555
- }).get();
556
-
557
- // set fixed column width
558
- tsScroller.setWidth( $fixedColumn.add( $fixedColumn.children() ), totalWidth + borderRightWidth * 2 - borderSpacing );
559
- tsScroller.setWidth( $fixedColumn.find( 'table' ), totalWidth + borderRightWidth );
560
-
561
- // set fixed column height ( changes with filtering )
562
- $fixedColumn.height( $wrapper.height() );
707
+ ts.scroller.removeFixed( c, wo, false );
563
708
 
564
- if ( wo.scroller_$footer.length ) {
565
- // adjust footer row heights (text could wrap on resize)
566
- $temp = $wrapper.children( '.' + tscss.scrollerFooter ).find( 'tfoot tr' );
567
- $rows = $fixedColumn.find( '.' + tscss.scrollerFooter + ' tfoot tr' );
568
- for ( index = 0; index < $rows.length; index++ ) {
569
- $rows.eq( index ).height( $temp.eq( index ).height() );
570
- }
709
+ // calculate fixed column width
710
+ for ( index = 0; index < fixedColumns; index++ ) {
711
+ totalWidth += widths[ index ] + borderSpacing;
571
712
  }
572
- // leave a gap under the tbody for the horizontal scrollbar
573
- $fixedColumn.find( '.' + tscss.scrollerTable )
574
- .height( $table.parent().height() - scrollBarWidth + borderBottomWidth );
575
713
 
576
- // update fixed column tbody content, set row height & set cell widths for first row
714
+ // set fixed column width
715
+ totalWidth = totalWidth + borderRightWidth * 2 - borderSpacing;
716
+ tsScroller.setWidth( $fixedColumn.add( $fixedColumn.children() ), totalWidth );
717
+ tsScroller.setWidth( $fixedColumn.children().children( 'table' ), totalWidth );
718
+
719
+ // update fixed column tbody content, set cell widths on hidden row
577
720
  for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
578
721
  $tbody = $mainTbodies.eq( tbodyIndex );
579
722
  if ( $tbody.length ) {
580
723
  // get tbody
581
724
  $rows = $tbody.children();
582
725
  totalRows = $rows.length;
583
- $fb = ts.processTbody( $fixedTbodiesTable, $fixedTbodies.eq( tbodyIndex ), true);
726
+ $fb = ts.processTbody( $fixedTbodiesTable, $fixedTbodies.eq( tbodyIndex ), true );
584
727
  $fb.empty();
585
728
  // update tbody cells after sort/filtering
586
729
  for ( rowIndex = 0; rowIndex < totalRows; rowIndex++ ) {
587
730
  $adjCol = $( $rows[ rowIndex ].outerHTML );
588
- $adjCol.children( 'td, th' ).slice( fixedColumns ).remove();
589
- // set row height
590
- $adjCol.children().eq( 0 ).height( $rows.eq( rowIndex ).outerHeight() - ( tsScroller.isFirefox ? borderBottomWidth * 2 : 0 ) );
591
- // still need to adjust tbody cell widths ( the previous row may now be filtered )
592
- if ( rowIndex === 0 ) {
593
- tsScroller.setWidth( $adjCol.children().eq( 0 ), widths[ 0 ] );
594
- }
731
+ $adjCol
732
+ .children( 'td, th' )
733
+ .slice( fixedColumns )
734
+ .remove();
595
735
  $fb.append( $adjCol );
596
736
  }
597
737
 
598
- // adjust fixed header cell widths
599
- $temp = $fixedColumn.find( 'thead' ).children( 'tr.' + tscss.headerRow );
600
- for ( index = 0; index < fixedColumns; index++ ) {
601
- tsScroller.setWidth( $temp.children( ':eq(' + index + ')' ), widths[ index ] );
602
- }
603
-
604
738
  // restore tbody
605
739
  ts.processTbody( $fixedTbodiesTable, $fb, false );
606
740
  }
607
741
  }
608
742
 
743
+ adj = ts.scroller.hasScrollBar( $tableWrap ) ? scrollBarWidth : 0;
744
+
609
745
  /*** scrollbar HACK! Since we can't hide the scrollbar with css ***/
610
746
  if ( tsScroller.isFirefox || tsScroller.isOldIE ) {
611
- $fixedTbodiesTable.parent().css({
612
- 'width' : totalWidth + scrollBarWidth + borderRightWidth
613
- });
747
+ $fixedTbodiesTable
748
+ .css( 'width', totalWidth )
749
+ .parent()
750
+ .css( 'width', totalWidth + adj );
614
751
  }
615
752
 
616
- $fixedColumn.show();
753
+ $fixedColumn.removeClass( tscss.scrollerHideElement );
754
+ for ( index = 0; index < fixedColumns; index++ ) {
755
+ $wrapper
756
+ .children( 'div' )
757
+ .children( 'table' )
758
+ .find( 'th:nth-child(' + ( index + 1 ) + '), td:nth-child(' + ( index + 1 ) + ')' )
759
+ .addClass( tscss.scrollerHideColumn );
760
+ }
761
+
762
+ totalWidth = totalWidth - borderRightWidth;
763
+ temp = $tableWrap.parent().innerWidth() - totalWidth;
764
+ $tableWrap.width( temp );
765
+ // RTL support (fixes column on right)
766
+ $wrapper
767
+ .children( '.' + tscss.scrollerTable )
768
+ .css( dir ? 'right' : 'left', totalWidth );
769
+ $wrapper
770
+ .children( '.' + tscss.scrollerHeader + ', .' + tscss.scrollerFooter )
771
+ // Safari needs a scrollbar width of extra adjusment to align the fixed & scrolling columns
772
+ .css( dir ? 'right' : 'left', totalWidth + ( dir && ts.scroller.isSafari ? adj : 0 ) );
773
+
774
+ $hdr
775
+ .parent()
776
+ .add( $foot.parent() )
777
+ .width( temp - adj );
778
+
779
+ // fix gap under the tbody for the horizontal scrollbar
780
+ temp = ts.scroller.hasScrollBar( $tableWrap, true );
781
+ adj = temp ? scrollBarWidth : 0;
782
+ if ( !$fixedColumn.find( '.' + tscss.scrollerBarSpacer ).length && temp ) {
783
+ $temp = $( '<div class="' + tscss.scrollerBarSpacer + '">' )
784
+ .css( 'height', adj + 'px' );
785
+ $fixedColumn.find( '.' + tscss.scrollerTable ).append( $temp );
786
+ } else if ( !temp ) {
787
+ $fixedColumn.find( '.' + tscss.scrollerBarSpacer ).remove();
788
+ }
789
+
790
+ ts.scroller.updateRowHeight( c, wo );
791
+ // set fixed column height (changes with filtering)
792
+ $fixedColumn.height( $wrapper.height() );
793
+
794
+ $fixedColumn.removeClass( tscss.scrollerHideElement );
795
+
796
+ wo.scroller_isBusy = false;
797
+ },
798
+
799
+ fixHeight : function( $rows, $fixedRows ) {
800
+ var index, heightRow, heightFixed, $r, $f,
801
+ len = $rows.length;
802
+ for ( index = 0; index < len; index++ ) {
803
+ $r = $rows.eq( index );
804
+ $f = $fixedRows.eq( index );
805
+ heightRow = $r.height();
806
+ heightFixed = $f.height();
807
+ if ( heightRow > heightFixed ) {
808
+ $f.addClass( tscss.scrollerAddedHeight ).height( heightRow );
809
+ } else if ( heightRow < heightFixed ) {
810
+ $r.addClass( tscss.scrollerAddedHeight ).height( heightFixed );
811
+ }
812
+ }
813
+ },
814
+
815
+ updateRowHeight : function( c, wo ) {
816
+ var $rows, $fixed,
817
+ $fixedColumns = wo.scroller_$fixedColumns;
818
+
819
+ wo.scroller_$container
820
+ .find( '.' + tscss.scrollerAddedHeight )
821
+ .removeClass( tscss.scrollerAddedHeight )
822
+ .height( '' );
823
+
824
+ $rows = wo.scroller_$header
825
+ .children( 'thead' )
826
+ .children( 'tr' );
827
+ $fixed = $fixedColumns
828
+ .children( '.' + tscss.scrollerHeader )
829
+ .children( 'table' )
830
+ .children( 'thead' )
831
+ .children( 'tr' );
832
+ ts.scroller.fixHeight( $rows, $fixed );
833
+
834
+ $rows = wo.scroller_$footer
835
+ .children( 'tfoot' )
836
+ .children( 'tr' );
837
+ $fixed = $fixedColumns
838
+ .children( '.' + tscss.scrollerFooter )
839
+ .children( 'table' )
840
+ .children( 'tfoot' )
841
+ .children( 'tr' );
842
+ ts.scroller.fixHeight( $rows, $fixed );
843
+
844
+ if ( ts.scroller.isFirefox || ts.scroller.isOldIE ) {
845
+ // Firefox/Old IE scrollbar hack (wraps table to hide the scrollbar)
846
+ $fixedColumns = $fixedColumns.find( '.' + tscss.scrollerHack );
847
+ }
848
+ $rows = c.$table
849
+ .children( 'tbody' )
850
+ .children( 'tr' );
851
+ $fixed = $fixedColumns
852
+ .children( '.' + tscss.scrollerTable )
853
+ .children( 'table' )
854
+ .children( 'tbody' )
855
+ .children( 'tr' );
856
+ ts.scroller.fixHeight( $rows, $fixed );
617
857
 
618
858
  },
619
859
 
860
+ removeFixed : function( c, wo, removeIt ) {
861
+ var $table = c.$table,
862
+ $wrapper = wo.scroller_$container,
863
+ dir = $table.hasClass( tscss.scrollerRtl );
864
+
865
+ // remove fixed columns
866
+ if ( removeIt || typeof removeIt === 'undefined' ) {
867
+ $wrapper.find( '.' + tscss.scrollerFixed ).remove();
868
+ }
869
+
870
+ $wrapper
871
+ .find( '.' + tscss.scrollerHideColumn )
872
+ .removeClass( tscss.scrollerHideColumn );
873
+
874
+ // RTL support ( fixes column on right )
875
+ $wrapper
876
+ .children( ':not(.' + tscss.scrollerFixed + ')' )
877
+ .css( dir ? 'right' : 'left', 0 );
878
+ },
879
+
620
880
  remove : function( c, wo ) {
621
881
  var $wrap = wo.scroller_$container,
622
882
  namespace = c.namespace + 'tsscroller';
623
883
  c.$table
624
884
  .off( namespace )
625
885
  .insertBefore( $wrap )
626
- .find( 'thead' ).show().css( 'visibility', 'visible' )
627
- .children( 'tr.' + tscss.headerRow ).children().attr( 'tabindex', 0 )
886
+ .find( 'thead' )
887
+ .removeClass( tscss.scrollerHideElement )
888
+ .children( 'tr.' + tscss.headerRow )
889
+ .children()
890
+ .attr( 'tabindex', 0 )
628
891
  .end()
629
- .find( '.' + tscss.filterRow ).show().removeClass( tscss.filterRowHide );
892
+ .find( '.' + tscss.filterRow )
893
+ .removeClass( tscss.scrollerHideElement + ' ' + tscss.filterRowHide );
894
+ c.$table
895
+ .find( '.' + tscss.filter )
896
+ .not( '.' + tscss.filterDisabled )
897
+ .prop( 'disabled', false );
630
898
  $wrap.remove();
631
899
  $( window ).off( namespace );
632
900
  c.isScrolling = false;