/** @preserve jQuery.floatThead 2.0.3 - http://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2017 Misha Koryak **/ // @license MIT /* @author Misha Koryak * @projectDescription lock a table header in place while scrolling - without breaking styles or events bound to the header * * Dependencies: * jquery 1.9.0 + [required] OR jquery 1.7.0 + jquery UI core * * http://mkoryak.github.io/floatThead/ * * Tested on FF13+, Chrome 21+, IE8, IE9, IE10, IE11 * */ (function( $ ) { /** * provides a default config object. You can modify this after including this script if you want to change the init defaults * @type {Object} */ $.floatThead = $.floatThead || {}; $.floatThead.defaults = { headerCellSelector: 'tr:visible:first>*:visible', //thead cells are this. zIndex: 1001, //zindex of the floating thead (actually a container div) position: 'auto', // 'fixed', 'absolute', 'auto'. auto picks the best for your table scrolling type. top: 0, //String or function($table) - offset from top of window where the header should not pass above bottom: 0, //String or function($table) - offset from the bottom of the table where the header should stop scrolling scrollContainer: function($table) { // or boolean 'true' (use offsetParent) | function -> if the table has horizontal scroll bars then this is the container that has overflow:auto and causes those scroll bars return $([]); }, responsiveContainer: function($table) { // only valid if scrollContainer is not used (ie window scrolling). this is the container which will control y scrolling at some mobile breakpoints return $([]); }, getSizingRow: function($table, $cols, $fthCells){ // this is only called when using IE, // override it if the first row of the table is going to contain colgroups (any cell spans greater than one col) // it should return a jquery object containing a wrapped set of table cells comprising a row that contains no col spans and is visible return $table.find('tbody tr:visible:first>*:visible'); }, floatTableClass: 'floatThead-table', floatWrapperClass: 'floatThead-wrapper', floatContainerClass: 'floatThead-container', copyTableClass: true, //copy 'class' attribute from table into the floated table so that the styles match. autoReflow: false, //(undocumented) - use MutationObserver api to reflow automatically when internal table DOM changes debug: false, //print possible issues (that don't prevent script loading) to console, if console exists. support: { //should we bind events that expect these frameworks to be present and/or check for them? bootstrap: true, datatables: true, jqueryUI: true, perfectScrollbar: true } }; var util = (function underscoreShim(){ var that = {}; var hasOwnProperty = Object.prototype.hasOwnProperty, isThings = ['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp']; that.has = function(obj, key) { return hasOwnProperty.call(obj, key); }; that.keys = Object.keys || function(obj) { if (obj !== Object(obj)) throw new TypeError('Invalid object'); var keys = []; for (var key in obj) if (that.has(obj, key)) keys.push(key); return keys; }; var idCounter = 0; that.uniqueId = function(prefix) { var id = ++idCounter + ''; return prefix ? prefix + id : id; }; $.each(isThings, function(){ var name = this; that['is' + name] = function(obj) { return Object.prototype.toString.call(obj) == '[object ' + name + ']'; }; }); that.debounce = function(func, wait, immediate) { var timeout, args, context, timestamp, result; return function() { context = this; args = arguments; timestamp = new Date(); var later = function() { var last = (new Date()) - timestamp; if (last < wait) { timeout = setTimeout(later, wait - last); } else { timeout = null; if (!immediate) result = func.apply(context, args); } }; var callNow = immediate && !timeout; if (!timeout) { timeout = setTimeout(later, wait); } if (callNow) result = func.apply(context, args); return result; }; }; return that; })(); var canObserveMutations = typeof MutationObserver !== 'undefined'; //browser stuff var ieVersion = function(){for(var a=3,b=document.createElement("b"),c=b.all||[];a = 1+a,b.innerHTML="",c[0];);return 4').css('width', 0).append( $('
').append(
$(' ').css('min-width', 100).text('X')
)
)
)
);
$("body").append($test);
var ret = ($test.find("table").width() == 0);
$test.remove();
return ret;
}
return false;
};
var createElements = !isFF && !ieVersion; //FF can read width from ').css('overflow', 'hidden').attr('aria-hidden', 'true');
var floatTableHidden = false; //this happens when the table is hidden and we do magic when making it visible
var $newHeader = $("");
var $sizerRow = $(' ');
var $sizerCells = $([]);
var $tableCells = $([]); //used for sizing - either $sizerCells or $tableColGroup cols. $tableColGroup cols are only created in chrome for borderCollapse:collapse because of a chrome bug.
var $headerCells = $([]);
var $fthCells = $([]); //created elements
$newHeader.append($sizerRow);
$table.prepend($tableColGroup);
if(createElements){
$fthGrp.append($fthRow);
$table.append($fthGrp);
}
$floatTable.append($floatColGroup);
$floatContainer.append($floatTable);
if(opts.copyTableClass){
$floatTable.attr('class', $table.attr('class'));
}
$floatTable.attr({ //copy over some deprecated table attributes that people still like to use. Good thing people don't use colgroups...
'cellpadding': $table.attr('cellpadding'),
'cellspacing': $table.attr('cellspacing'),
'border': $table.attr('border')
});
var tableDisplayCss = $table.css('display');
$floatTable.css({
'borderCollapse': $table.css('borderCollapse'),
'border': $table.css('border'),
'display': tableDisplayCss
});
if(!locked){
$floatTable.css('width', 'auto');
}
if(tableDisplayCss == 'none'){
floatTableHidden = true;
}
$floatTable.addClass(opts.floatTableClass).css({'margin': 0, 'border-bottom-width': 0}); //must have no margins or you won't be able to click on things under floating table
if(useAbsolutePositioning){
var makeRelative = function($container, alwaysWrap){
var positionCss = $container.css('position');
var relativeToScrollContainer = (positionCss == "relative" || positionCss == "absolute");
var $containerWrap = $container;
if(!relativeToScrollContainer || alwaysWrap){
var css = {"paddingLeft": $container.css('paddingLeft'), "paddingRight": $container.css('paddingRight')};
$floatContainer.css(css);
$containerWrap = $container.data('floatThead-containerWrap') || $container.wrap(
$('').addClass(opts.floatWrapperClass).css({
'position': 'relative',
'clear': 'both'
})
).parent();
$container.data('floatThead-containerWrap', $containerWrap); //multiple tables inside one scrolling container - #242
wrappedContainer = true;
}
return $containerWrap;
};
if(locked){
$wrapper = makeRelative($scrollContainer, true);
$wrapper.prepend($floatContainer);
} else {
$wrapper = makeRelative($table);
$table.before($floatContainer);
}
} else {
$table.before($floatContainer);
}
$floatContainer.css({
position: useAbsolutePositioning ? 'absolute' : 'fixed',
marginTop: 0,
top: useAbsolutePositioning ? 0 : 'auto',
zIndex: opts.zIndex,
willChange: 'transform'
});
$floatContainer.addClass(opts.floatContainerClass);
updateScrollingOffsets();
var layoutFixed = {'table-layout': 'fixed'};
var layoutAuto = {'table-layout': $table.css('tableLayout') || 'auto'};
var originalTableWidth = $table[0].style.width || ""; //setting this to auto is bad: #70
var originalTableMinWidth = $table.css('minWidth') || "";
function eventName(name){
return name+'.fth-'+floatTheadId+'.floatTHead'
}
function setHeaderHeight(){
var headerHeight = 0;
$header.children("tr:visible").each(function(){
headerHeight += $(this).outerHeight(true);
});
if($table.css('border-collapse') == 'collapse') {
var tableBorderTopHeight = parseInt($table.css('border-top-width'), 10);
var cellBorderTopHeight = parseInt($table.find("thead tr:first").find(">*:first").css('border-top-width'), 10);
if(tableBorderTopHeight > cellBorderTopHeight) {
headerHeight -= (tableBorderTopHeight / 2); //id love to see some docs where this magic recipe is found..
}
}
$sizerRow.outerHeight(headerHeight);
$sizerCells.outerHeight(headerHeight);
}
function setFloatWidth(){
var tw = tableWidth($table, $fthCells, true);
var $container = responsive ? $responsiveContainer : $scrollContainer;
var width = $container.width() || tw;
var floatContainerWidth = $container.css("overflow-y") != 'hidden' ? width - scrollbarOffset.vertical : width;
$floatContainer.width(floatContainerWidth);
if(locked){
var percent = 100 * tw / (floatContainerWidth);
$floatTable.css('width', percent+'%');
} else {
$floatTable.outerWidth(tw);
}
}
function updateScrollingOffsets(){
scrollingTop = (util.isFunction(opts.top) ? opts.top($table) : opts.top) || 0;
scrollingBottom = (util.isFunction(opts.bottom) ? opts.bottom($table) : opts.bottom) || 0;
}
/**
* get the number of columns and also rebuild resizer rows if the count is different than the last count
*/
function columnNum(){
var count;
var $headerColumns = $header.find(opts.headerCellSelector);
if(existingColGroup){
count = $tableColGroup.find('col').length;
} else {
count = 0;
$headerColumns.each(function () {
count += parseInt(($(this).attr('colspan') || 1), 10);
});
}
if(count != lastColumnCount){
lastColumnCount = count;
var cells = [], cols = [], psuedo = [], content;
for(var x = 0; x < count; x++){
content = $headerColumns.eq(x).text();
cells.push(' ');
cols.push(' | |
---|