' );
}
$fixedTbody = $fixedColumn.find( '.' + tscss.scrollerTable );
$fixedTbody
.children( 'table' )
.addClass( c.namespace.slice( 1 ) + '_extra_table' )
.attr( 'id', '' )
.children( 'thead, tfoot' )
.remove();
wo.scroller_$fixedColumns = $fixedColumn;
// RTL support (fixes column on right)
if ( $table.hasClass( tscss.scrollerRtl ) ) {
$fixedColumn.addClass( tscss.scrollerRtl );
}
$el = $fixedColumn.find( 'tr' );
len = $el.length;
for ( index = 0; index < len; index++ ) {
$el.eq( index ).children( ':gt(' + ( fixedColumns - 1 ) + ')' ).remove();
}
$fixedColumn
.addClass( tscss.scrollerHideElement )
.prependTo( $wrapper );
// look for filter widget
if ( c.$table.hasClass( 'hasFilters' ) ) {
// make sure fixed column filters aren't disabled
$el = $fixedColumn
.find( '.' + tscss.filter )
.not( '.' + tscss.filterDisabled )
.prop( 'disabled', false );
ts.filter.bindSearch( $table, $fixedColumn.find( '.' + tscss.filter ) );
// disable/enable filters behind fixed column
$el = $wrapper
.children( '.' + tscss.scrollerHeader )
.find( '.' + tscss.filter );
len = $el.length;
for ( index = 0; index < len; index++ ) {
// previously disabled filter; don't mess with it! filterDisabled class added by filter widget
if ( !$el.eq( index ).hasClass( tscss.filterDisabled || 'disabled' ) ) {
// disable filters behind fixed column; don't disable visible filters
$el.eq( index ).prop( 'disabled', index < fixedColumns );
}
}
}
// disable/enable tab indexes behind fixed column
c.$table
.add( '.' + tscss.scrollerFooter + ' table' )
.children( 'thead' )
.children( 'tr.' + tscss.headerRow )
.children()
.attr( 'tabindex', -1 );
$el = wo.scroller_$header
.add( $fixedColumn.find( '.' + tscss.scrollerTable + ' table' ) )
.children( 'thead' )
.children( 'tr.' + tscss.headerRow );
len = $el.length;
for ( index = 0; index < len; index++ ) {
temp = $el.eq( index ).children();
for ( index2 = 0; index2 < temp.length; index2++ ) {
temp.eq( index2 ).attr( 'tabindex', index2 < fixedColumns ? -1 : 0 );
}
}
ts.bindEvents( c.table, $fixedColumn.find( '.' + tscss.header ) );
ts.scroller.bindFixedColumnEvents( c, wo );
/*** Scrollbar hack! Since we can't hide the scrollbar with css ***/
if ( ts.scroller.isFirefox || ts.scroller.isOldIE ) {
$fixedTbody.wrap( '
' );
}
},
// https://remysharp.com/2010/07/21/throttling-function-calls
throttle : function(fn, threshhold, scope) {
threshhold = threshhold || 50;
var last, deferTimer;
return function() {
var context = scope || this,
now = +(new Date()),
args = arguments;
if (last && now < last + threshhold) {
// hold on to it
clearTimeout(deferTimer);
deferTimer = setTimeout(function() {
last = now;
fn.apply(context, args);
}, threshhold);
} else {
last = now;
fn.apply(context, args);
}
};
},
bindFixedColumnEvents : function( c, wo ) {
// update thead & tbody in fixed column
var tsScroller = ts.scroller,
namespace = c.namespace + 'tsscrollerFixed',
events = 'scroll' + namespace,
$fixedTbody = wo.scroller_$fixedColumns.find( '.' + tscss.scrollerTable ),
fixedScroll = true,
tableScroll = true;
c.$table
.parent()
// *** SCROLL *** scroll fixed column along with main
.off( events )
.on( events, tsScroller.throttle(function() {
// using flags to prevent firing the scroll event excessively leading to slow scrolling in Firefox
if ( !wo.scroller_isBusy && fixedScroll ) {
tableScroll = false;
var $this = $( this );
$fixedTbody[0].scrollTop = wo.scroller_saved[1] = $this.scrollTop();
wo.scroller_saved[0] = $this.scrollLeft();
setTimeout( function() {
tableScroll = true;
}, 20 );
}
}));
// scroll main along with fixed column
$fixedTbody
.off( events )
.on( events, tsScroller.throttle(function() {
// using flags to prevent firing the scroll event excessively leading to slow scrolling in Firefox
if ( !wo.scroller_isBusy && tableScroll ) {
fixedScroll = false;
c.$table.parent()[0].scrollTop = wo.scroller_saved[1] = $( this ).scrollTop();
setTimeout( function() {
fixedScroll = true;
}, 20 );
}
}))
.scroll();
// *** ROW HIGHLIGHT ***
if ( wo.scroller_rowHighlight !== '' ) {
events = 'mouseover mouseleave '.split( ' ' ).join( namespace + ' ' );
// can't use c.$tbodies because it doesn't include info-only tbodies
c.$table
.off( events, 'tbody > tr' )
.on( events, 'tbody > tr', function( event ) {
var indx = c.$table.children( 'tbody' ).children( 'tr' ).index( this );
$fixedTbody
.children( 'table' )
.children( 'tbody' )
.children( 'tr' )
.eq( indx )
.add( this )
.toggleClass( wo.scroller_rowHighlight, event.type === 'mouseover' );
});
$fixedTbody
.find( 'table' )
.off( events, 'tbody > tr' )
.on( events, 'tbody > tr', function( event ) {
var $fixed = $fixedTbody.children( 'table' ).children( 'tbody' ).children( 'tr' ),
indx = $fixed.index( this );
c.$table
.children( 'tbody' )
.children( 'tr' )
.eq( indx )
.add( this )
.toggleClass( wo.scroller_rowHighlight, event.type === 'mouseover' );
});
}
},
adjustWidth : function( c, wo, totalWidth, adj, dir ) {
var $wrapper = wo.scroller_$container;
// RTL support (fixes column on right)
$wrapper
.children( '.' + tscss.scrollerTable )
.css( dir ? 'right' : 'left', totalWidth );
$wrapper
.children( '.' + tscss.scrollerHeader + ', .' + tscss.scrollerFooter )
// Safari needs a scrollbar width of extra adjusment to align the fixed & scrolling columns
.css( dir ? 'right' : 'left', totalWidth + ( dir && ts.scroller.isSafari ? adj : 0 ) );
},
updateFixed : function( c, wo ) {
var temp, adj,
$wrapper = wo.scroller_$container,
$hdr = wo.scroller_$header,
$foot = wo.scroller_$footer,
$table = c.$table,
$tableWrap = $table.parent(),
scrollBarWidth = wo.scroller_barSetWidth,
dir = $table.hasClass( tscss.scrollerRtl );
if ( wo.scroller_fixedColumns === 0 ) {
wo.scroller_isBusy = false;
ts.scroller.removeFixed( c, wo );
temp = $wrapper.width();
$tableWrap.width( temp );
adj = ts.scroller.hasScrollBar( $tableWrap ) ? scrollBarWidth : 0;
$hdr
.parent()
.add( $foot.parent() )
.width( temp - adj );
return;
}
if ( !c.isScrolling ) {
return;
}
wo.scroller_isBusy = true;
// Make sure the wo.scroller_$fixedColumns container exists, if not build it
if ( !$wrapper.find( '.' + tscss.scrollerFixed ).length ) {
ts.scroller.setupFixed( c, wo );
}
// scroller_fixedColumns
var index, tbodyIndex, rowIndex, $tbody, $adjCol, $fb, totalRows,
// source cells for measurement
$mainTbodies = wo.scroller_$container
.children( '.' + tscss.scrollerTable )
.children( 'table' )
.children( 'tbody' ),
// variable gets redefined
$rows = wo.scroller_$header
.children( 'thead' )
.children( '.' + tscss.headerRow ),
// hide fixed column during resize, or we get a FOUC
$fixedColumn = wo.scroller_$fixedColumns
.addClass( tscss.scrollerHideElement ),
// target cells
$fixedTbodiesTable = $fixedColumn
.find( '.' + tscss.scrollerTable )
.children( 'table' ),
$fixedTbodies = $fixedTbodiesTable
.children( 'tbody' ),
// variables
tsScroller = ts.scroller,
fixedColumns = wo.scroller_fixedColumns,
// get dimensions
$temp = $table.find( 'tbody td' ),
borderRightWidth = parseInt( $temp.css( 'border-right-width' ), 10 ) || 1,
borderSpacing = parseInt( ( $temp.css( 'border-spacing' ) || '' ).split( /\s/ )[ 0 ], 10 ) / 2 || 0,
totalWidth = parseInt( $table.css( 'padding-left' ), 10 ) +
parseInt( $table.css( 'padding-right' ), 10 ) -
borderRightWidth,
widths = wo.scroller_calcWidths;
ts.scroller.removeFixed( c, wo, false );
// calculate fixed column width
for ( index = 0; index < fixedColumns; index++ ) {
totalWidth += widths[ index ] + borderSpacing;
}
// set fixed column width
totalWidth = totalWidth + borderRightWidth * 2 - borderSpacing;
tsScroller.setWidth( $fixedColumn.add( $fixedColumn.children() ), totalWidth );
tsScroller.setWidth( $fixedColumn.children().children( 'table' ), totalWidth );
// update fixed column tbody content, set cell widths on hidden row
for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
$tbody = $mainTbodies.eq( tbodyIndex );
if ( $tbody.length ) {
// get tbody
$rows = $tbody.children();
totalRows = $rows.length;
$fb = ts.processTbody( $fixedTbodiesTable, $fixedTbodies.eq( tbodyIndex ), true );
$fb.empty();
// update tbody cells after sort/filtering
for ( rowIndex = 0; rowIndex < totalRows; rowIndex++ ) {
$adjCol = $( $rows[ rowIndex ].outerHTML );
$adjCol
.children( 'td, th' )
.slice( fixedColumns )
.remove();
$fb.append( $adjCol );
}
// restore tbody
ts.processTbody( $fixedTbodiesTable, $fb, false );
}
}
adj = ts.scroller.hasScrollBar( $tableWrap ) ? scrollBarWidth : 0;
/*** scrollbar HACK! Since we can't hide the scrollbar with css ***/
if ( tsScroller.isFirefox || tsScroller.isOldIE ) {
$fixedTbodiesTable
.css( 'width', totalWidth )
.parent()
.css( 'width', totalWidth + adj );
}
$fixedColumn.removeClass( tscss.scrollerHideElement );
for ( index = 0; index < fixedColumns; index++ ) {
$wrapper
.children( 'div' )
.children( 'table' )
.find( 'th:nth-child(' + ( index + 1 ) + '), td:nth-child(' + ( index + 1 ) + ')' )
.addClass( tscss.scrollerHideColumn );
}
totalWidth = totalWidth - borderRightWidth;
temp = $tableWrap.parent().innerWidth() - totalWidth;
$tableWrap.width( temp );
// RTL support (fixes column on right)
$wrapper
.children( '.' + tscss.scrollerTable )
.css( dir ? 'right' : 'left', totalWidth );
$wrapper
.children( '.' + tscss.scrollerHeader + ', .' + tscss.scrollerFooter )
// Safari needs a scrollbar width of extra adjusment to align the fixed & scrolling columns
.css( dir ? 'right' : 'left', totalWidth + ( dir && ts.scroller.isSafari ? adj : 0 ) );
$hdr
.parent()
.add( $foot.parent() )
.width( temp - adj );
// fix gap under the tbody for the horizontal scrollbar
temp = ts.scroller.hasScrollBar( $tableWrap, true );
adj = temp ? scrollBarWidth : 0;
if ( !$fixedColumn.find( '.' + tscss.scrollerBarSpacer ).length && temp ) {
$temp = $( '
' )
.css( 'height', adj + 'px' );
$fixedColumn.find( '.' + tscss.scrollerTable ).append( $temp );
} else if ( !temp ) {
$fixedColumn.find( '.' + tscss.scrollerBarSpacer ).remove();
}
ts.scroller.updateRowHeight( c, wo );
// set fixed column height (changes with filtering)
$fixedColumn.height( $wrapper.height() );
$fixedColumn.removeClass( tscss.scrollerHideElement );
// adjust caption height, see #1202
$fixedColumn.find('caption').height( wo.scroller_$header.find( 'caption' ).height() );
wo.scroller_isBusy = false;
},
fixHeight : function( $rows, $fixedRows ) {
var index, heightRow, heightFixed, $r, $f,
addedHt = tscss.scrollerAddedHeight,
len = $rows.length;
for ( index = 0; index < len; index++ ) {
$r = $rows.eq( index );
$f = $fixedRows.eq( index );
heightRow = $r.height();
heightFixed = $f.height();
if ( heightRow > heightFixed ) {
$f.addClass( addedHt ).height( heightRow );
} else if ( heightRow < heightFixed ) {
$r.addClass( addedHt ).height( heightFixed );
}
}
},
updateRowHeight : function( c, wo ) {
var $rows, $fixed,
$fixedColumns = wo.scroller_$fixedColumns;
wo.scroller_$container
.find( '.' + tscss.scrollerAddedHeight )
.removeClass( tscss.scrollerAddedHeight )
.height( '' );
$rows = wo.scroller_$header
.children( 'thead' )
.children( 'tr' );
$fixed = $fixedColumns
.children( '.' + tscss.scrollerHeader )
.children( 'table' )
.children( 'thead' )
.children( 'tr' );
ts.scroller.fixHeight( $rows, $fixed );
$rows = wo.scroller_$footer
.children( 'tfoot' )
.children( 'tr' );
$fixed = $fixedColumns
.children( '.' + tscss.scrollerFooter )
.children( 'table' )
.children( 'tfoot' )
.children( 'tr' );
ts.scroller.fixHeight( $rows, $fixed );
if ( ts.scroller.isFirefox || ts.scroller.isOldIE ) {
// Firefox/Old IE scrollbar hack (wraps table to hide the scrollbar)
$fixedColumns = $fixedColumns.find( '.' + tscss.scrollerHack );
}
$rows = c.$table
.children( 'tbody' )
.children( 'tr' );
$fixed = $fixedColumns
.children( '.' + tscss.scrollerTable )
.children( 'table' )
.children( 'tbody' )
.children( 'tr' );
ts.scroller.fixHeight( $rows, $fixed );
},
removeFixed : function( c, wo, removeIt ) {
var $table = c.$table,
$wrapper = wo.scroller_$container,
dir = $table.hasClass( tscss.scrollerRtl );
// remove fixed columns
if ( removeIt || typeof removeIt === 'undefined' ) {
$wrapper.find( '.' + tscss.scrollerFixed ).remove();
}
$wrapper
.find( '.' + tscss.scrollerHideColumn )
.removeClass( tscss.scrollerHideColumn );
// RTL support ( fixes column on right )
$wrapper
.children( ':not(.' + tscss.scrollerFixed + ')' )
.css( dir ? 'right' : 'left', 0 );
},
remove : function( c, wo ) {
var $wrap = wo.scroller_$container,
namespace = c.namespace + 'tsscroller';
c.$table.off( namespace );
$( window ).off( namespace );
if ( $wrap ) {
c.$table
.insertBefore( $wrap )
.find( 'thead' )
.removeClass( tscss.scrollerHideElement )
.children( 'tr.' + tscss.headerRow )
.children()
.attr( 'tabindex', 0 )
.end()
.find( '.' + tscss.filterRow )
.removeClass( tscss.scrollerHideElement + ' ' + tscss.filterRowHide );
c.$table
.find( '.' + tscss.filter )
.not( '.' + tscss.filterDisabled )
.prop( 'disabled', false );
$wrap.remove();
c.isScrolling = false;
}
}
};
})( jQuery, window );