jquery-tablesorter 1.17.1 → 1.17.2

Sign up to get free protection for your applications and to get access to all the features.
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;