diff --git a/grid/assets/js/jquery.floatThead.js b/grid/assets/js/jquery.floatThead.js index ba29f22d..db7ff18a 100644 --- a/grid/assets/js/jquery.floatThead.js +++ b/grid/assets/js/jquery.floatThead.js @@ -1,5 +1,5 @@ -// @preserve jQuery.floatThead 1.2.4 - http://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2014 Misha Koryak -// @license Licensed under http://creativecommons.org/licenses/by-sa/4.0/ +// @preserve jQuery.floatThead 1.2.8 - http://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2014 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 @@ -12,663 +12,692 @@ * 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 = { - cellTag: 'th:visible', //thead cells are this - zIndex: 1001, //zindex of the floating thead (actually a container div) - debounceResizeMs: 1, - useAbsolutePositioning: true, //if set to NULL - defaults: has scrollContainer=true, doesn't have scrollContainer=false - scrollingTop: 0, //String or function($table) - offset from top of window where the header should not pass above - scrollingBottom: 0, //String or function($table) - offset from the bottom of the table where the header should stop scrolling - scrollContainer: function ($table) { - return $([]); //if the table has horizontal scroll bars then this is the container that has overflow:auto and causes those scroll bars - }, - 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 then 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>td'); - }, - 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. - debug: false //print possible issues (that don't prevent script loading) to console, if console exists. - }; - - var util = window._; - - //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 < a ? a : document.documentMode - }(); - var isChrome = null; - var isChromeCheck = function () { - if (ieVersion) { - return false; +(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 = { + cellTag: 'th:visible', //thead cells are this + zIndex: 1001, //zindex of the floating thead (actually a container div) + debounceResizeMs: 10, + useAbsolutePositioning: true, //if set to NULL - defaults: has scrollContainer=true, doesn't have scrollContainer=false + scrollingTop: 0, //String or function($table) - offset from top of window where the header should not pass above + scrollingBottom: 0, //String or function($table) - offset from the bottom of the table where the header should stop scrolling + scrollContainer: function($table){ + return $([]); //if the table has horizontal scroll bars then this is the container that has overflow:auto and causes those scroll bars + }, + 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 then 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>*'); + }, + 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. + debug: false //print possible issues (that don't prevent script loading) to console, if console exists. + }; + + var util = window._; + + //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"); + $('body').append($table); + var width = $table.find('col').width(); + $table.remove(); + return width == 0; + }; + + var $window = $(window); + var floatTheadCreated = 0; + + + /** + * @param debounceMs + * @param cb + */ + + function windowResize(debounceMs, eventName, cb){ + if(ieVersion == 8){ //ie8 is crap: https://github.com/mkoryak/floatThead/issues/65 + var winWidth = $window.width(); + var debouncedCb = util.debounce(function(){ + var winWidthNew = $window.width(); + if(winWidth != winWidthNew){ + winWidth = winWidthNew; + cb(); } - var $table = $("
"); - $('body').append($table); - var width = $table.find('col').width(); - $table.remove(); - return width == 0; - }; - - var $window = $(window); - var floatTheadCreated = 0; - - - /** - * @param debounceMs - * @param cb - */ - - function windowResize(debounceMs, cb) { - $window.bind('resize.floatTHead', util.debounce(cb, debounceMs)); //TODO: check if resize bug is gone in IE8 + + }, debounceMs); + $window.on(eventName, debouncedCb); + } else { + $window.on(eventName, util.debounce(cb, debounceMs)); } - - - function debug(str) { - window.console && window.console && window.console.log && window.console.log(str); + } + + + function debug(str){ + window.console && window.console && window.console.log && window.console.log(str); + } + + /** + * try to calculate the scrollbar width for your browser/os + * @return {Number} + */ + function scrollbarWidth() { + var $div = $( //borrowed from anti-scroll + '
' + + '
' + ); + $('body').append($div); + var w1 = $div.innerWidth(); + var w2 = $('div', $div).innerWidth(); + $div.remove(); + return w1 - w2; + } + /** + * Check if a given table has been datatableized (http://datatables.net) + * @param $table + * @return {Boolean} + */ + function isDatatable($table){ + if($table.dataTableSettings){ + for(var i = 0; i < $table.dataTableSettings.length; i++){ + var table = $table.dataTableSettings[i].nTable; + if($table[0] == table){ + return true; + } + } + } + return false; + } + $.fn.floatThead = function(map){ + map = map || {}; + if(!util){ //may have been included after the script? lets try to grab it again. + util = window._ || $.floatThead._; + if(!util){ + throw new Error("jquery.floatThead-slim.js requires underscore. You should use the non-lite version since you do not have underscore."); + } } - /** - * try to calculate the scrollbar width for your browser/os - * @return {Number} - */ - function scrollbarWidth() { - var $div = $( //borrowed from anti-scroll - '
' - + '
' - ); - $('body').append($div); - var w1 = $div.innerWidth(); - var w2 = $('div', $div).innerWidth(); - $div.remove(); - return w1 - w2; + if(ieVersion < 8){ + return this; //no more crappy browser support. } - /** - * Check if a given table has been datatableized (http://datatables.net) - * @param $table - * @return {Boolean} - */ - function isDatatable($table) { - if ($table.dataTableSettings) { - for (var i = 0; i < $table.dataTableSettings.length; i++) { - var table = $table.dataTableSettings[i].nTable; - if ($table[0] == table) { - return true; - } - } + if(isChrome == null){ //make sure this is done only once no matter how many times you call the plugin fn + isChrome = isChromeCheck(); //need to call this after dom ready, and now it is. + if(isChrome){ + //because chrome cant read width, these elements are used for sizing the table. Need to create new elements because they must be unstyled by user's css. + document.createElement('fthtr'); //tr + document.createElement('fthtd'); //td + document.createElement('fthfoot'); //tfoot + } + } + if(util.isString(map)){ + var command = map; + var ret = this; + this.filter('table').each(function(){ + var obj = $(this).data('floatThead-attached'); + if(obj && util.isFunction(obj[command])){ + var r = obj[command](); + if(typeof r !== 'undefined'){ + ret = r; + } } - return false; + }); + return ret; } - - $.fn.floatThead = function (map) { - map = map || {}; - if (!util) { //may have been included after the script? lets try to grab it again. - util = window._ || $.floatThead._; - if (!util) { - throw new Error("jquery.floatThead-slim.js requires underscore. You should use the non-lite version since you do not have underscore."); - } + var opts = $.extend({}, $.floatThead.defaults || {}, map); + + $.each(map, function(key, val){ + if((!(key in $.floatThead.defaults)) && opts.debug){ + debug("jQuery.floatThead: used ["+key+"] key to init plugin, but that param is not an option for the plugin. Valid options are: "+ (util.keys($.floatThead.defaults)).join(', ')); + } + }); + + this.filter(':not(.'+opts.floatTableClass+')').each(function(){ + var floatTheadId = floatTheadCreated; + var $table = $(this); + if($table.data('floatThead-attached')){ + return true; //continue the each loop + } + if(!$table.is('table')){ + throw new Error('jQuery.floatThead must be run on a table element. ex: $("table").floatThead();'); + } + var $header = $table.find('thead:first'); + var $tbody = $table.find('tbody:first'); + if($header.length == 0){ + throw new Error('jQuery.floatThead must be run on a table that contains a element'); + } + var headerFloated = false; + var scrollingTop, scrollingBottom; + var scrollbarOffset = {vertical: 0, horizontal: 0}; + var scWidth = scrollbarWidth(); + var lastColumnCount = 0; //used by columnNum() + var $scrollContainer = opts.scrollContainer($table) || $([]); //guard against returned nulls + + var useAbsolutePositioning = opts.useAbsolutePositioning; + if(useAbsolutePositioning == null){ //defaults: locked=true, !locked=false + useAbsolutePositioning = opts.scrollContainer($table).length; + } + var $caption = $table.find("caption"); + var haveCaption = $caption.length == 1; + if(haveCaption){ + var captionAlignTop = ($caption.css("caption-side") || $caption.attr("align") || "top") === "top"; + } + + var $fthGrp = $(''); + + var locked = $scrollContainer.length > 0; + var wrappedContainer = false; //used with absolute positioning enabled. did we need to wrap the scrollContainer/table with a relative div? + var $wrapper = $([]); //used when absolute positioning enabled - wraps the table and the float container + var absoluteToFixedOnScroll = ieVersion <= 9 && !locked && useAbsolutePositioning; //on ie using absolute positioning doesnt look good with window scrolling, so we change positon to fixed on scroll, and then change it back to absolute when done. + var $floatTable = $(""); + var $floatColGroup = $(""); + var $tableColGroup = $table.find('colgroup:first'); + var existingColGroup = true; + if($tableColGroup.length == 0){ + $tableColGroup = $(""); + existingColGroup = false; + } + var $fthRow = $(''); //created unstyled elements + var $floatContainer = $('
'); + 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(isChrome){ + $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 poeple dont use colgroups... + 'cellpadding': $table.attr('cellpadding'), + 'cellspacing': $table.attr('cellspacing'), + 'border': $table.attr('border') + }); + + $floatTable.addClass(opts.floatTableClass).css('margin', 0); //must have no margins or you wont 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"); + if(!relativeToScrollContainer || alwaysWrap){ + var css = {"paddingLeft": $container.css('paddingLeft'), "paddingRight": $container.css('paddingRight')}; + $floatContainer.css(css); + $container = $container.wrap("
").parent(); + wrappedContainer = true; + } + return $container; + }; + if(locked){ + $wrapper = makeRelative($scrollContainer, true); + $wrapper.append($floatContainer); + } else { + $wrapper = makeRelative($table); + $table.after($floatContainer); } - - if (ieVersion < 8) { - return this; //no more crappy browser support. + } else { + $table.after($floatContainer); + } + + + $floatContainer.css({ + position: useAbsolutePositioning ? 'absolute' : 'fixed', + marginTop: 0, + top: useAbsolutePositioning ? 0 : 'auto', + zIndex: opts.zIndex + }); + $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 + + function eventName(name){ + return name+'.fth-'+floatTheadId+'.floatTHead' + } + + function setHeaderHeight(){ + var headerHeight = 0; + $header.find("tr:visible").each(function(){ + headerHeight += $(this).outerHeight(true); + }); + $sizerRow.outerHeight(headerHeight); + $sizerCells.outerHeight(headerHeight); + } + + + function setFloatWidth(){ + var tableWidth = $table.outerWidth(); + var width = $scrollContainer.width() || tableWidth; + $floatContainer.width(width - scrollbarOffset.vertical); + if(locked){ + var percent = 100 * tableWidth / (width - scrollbarOffset.vertical); + $floatTable.css('width', percent+'%'); + } else { + $floatTable.outerWidth(tableWidth); } + } + + function updateScrollingOffsets(){ + scrollingTop = (util.isFunction(opts.scrollingTop) ? opts.scrollingTop($table) : opts.scrollingTop) || 0; + scrollingBottom = (util.isFunction(opts.scrollingBottom) ? opts.scrollingBottom($table) : opts.scrollingBottom) || 0; + } + + /** + * get the number of columns and also rebuild resizer rows if the count is different then the last count + */ + function columnNum(){ + var count, $headerColumns; + if(existingColGroup){ + count = $tableColGroup.find('col').length; + } else { + $headerColumns = $header.find('tr:first>'+opts.cellTag); + count = 0; + $headerColumns.each(function(){ + count += parseInt(($(this).attr('colspan') || 1), 10); + }); + } + if(count != lastColumnCount){ + lastColumnCount = count; + var cells = [], cols = [], psuedo = []; + for(var x = 0; x < count; x++){ + cells.push(''); + psuedo.push(""); + } + + cols = cols.join(''); + cells = cells.join(''); + + if(isChrome){ + psuedo = psuedo.join(''); + $fthRow.html(psuedo); + $fthCells = $fthRow.find('fthtd'); + } + + $sizerRow.html(cells); + $sizerCells = $sizerRow.find("th"); + if(!existingColGroup){ + $tableColGroup.html(cols); + } + $tableCells = $tableColGroup.find('col'); + $floatColGroup.html(cols); + $headerCells = $floatColGroup.find("col"); - if (isChrome == null) { //make sure this is done only once no matter how many times you call the plugin fn - isChrome = isChromeCheck(); //need to call this after dom ready, and now it is. - if (isChrome) { - //because chrome cant read width, these elements are used for sizing the table. Need to create new elements because they must be unstyled by user's css. - document.createElement('fthtr'); //tr - document.createElement('fthtd'); //td - document.createElement('fthfoot'); //tfoot + } + return count; + } + + function refloat(){ //make the thing float + if(!headerFloated){ + headerFloated = true; + if(useAbsolutePositioning){ //#53, #56 + var tableWidth = $table.width(); + var wrapperWidth = $wrapper.width(); + if(tableWidth > wrapperWidth){ + $table.css('minWidth', tableWidth); } + } + $table.css(layoutFixed); + $floatTable.css(layoutFixed); + $floatTable.append($header); //append because colgroup must go first in chrome + $tbody.before($newHeader); + setHeaderHeight(); } - if (util.isString(map)) { - var command = map; - var ret = this; - this.filter('table').each(function () { - var obj = $(this).data('floatThead-attached'); - if (obj && util.isFunction(obj[command])) { - var r = obj[command](); - if (typeof r !== 'undefined') { - ret = r; - } - } - }); - return ret; + } + function unfloat(){ //put the header back into the table + if(headerFloated){ + headerFloated = false; + if(useAbsolutePositioning){ //#53, #56 + $table.width(originalTableWidth); + } + $newHeader.detach(); + $table.prepend($header); + $table.css(layoutAuto); + $floatTable.css(layoutAuto); } - var opts = $.extend({}, $.floatThead.defaults || {}, map); - - $.each(map, function (val, key) { - if ((!(key in $.floatThead.defaults)) && opts.debug) { - debug("jQuery.floatThead: used [" + key + "] key to init plugin, but that param is not an option for the plugin. Valid options are: " + (util.keys($.floatThead.defaults)).join(', ')); - } - }); - - this.filter(':not(.' + opts.floatTableClass + ')').each(function () { - var $table = $(this); - if ($table.data('floatThead-attached')) { - return true; //continue the each loop - } - if (!$table.is('table')) { - throw new Error('jQuery.floatThead must be run on a table element. ex: $("table").floatThead();'); + } + function changePositioning(isAbsolute){ + if(useAbsolutePositioning != isAbsolute){ + useAbsolutePositioning = isAbsolute; + $floatContainer.css({ + position: useAbsolutePositioning ? 'absolute' : 'fixed' + }); + } + } + function getSizingRow($table, $cols, $fthCells, ieVersion){ + if(isChrome){ + return $fthCells; + } else if(ieVersion) { + return opts.getSizingRow($table, $cols, $fthCells); + } else { + return $cols; + } + } + + /** + * returns a function that updates the floating header's cell widths. + * @return {Function} + */ + function reflow(){ + var i; + var numCols = columnNum(); //if the tables columns change dynamically since last time (datatables) we need to rebuild the sizer rows and get new count + return function(){ + var $rowCells = getSizingRow($table, $tableCells, $fthCells, ieVersion); + if($rowCells.length == numCols && numCols > 0){ + if(!existingColGroup){ + for(i=0; i < numCols; i++){ + $tableCells.eq(i).css('width', ''); + } } - var $header = $table.find('thead:first'); - var $tbody = $table.find('tbody:first'); - if ($header.length == 0) { - throw new Error('jQuery.floatThead must be run on a table that contains a element'); + unfloat(); + for(i=0; i < numCols; i++){ + var _rowcell = $rowCells.get(i); + var rowWidth = _rowcell.offsetWidth; + $headerCells.eq(i).width(rowWidth); + $tableCells.eq(i).width(rowWidth); } - var headerFloated = false; - var scrollingTop, scrollingBottom; - var scrollbarOffset = {vertical: 0, horizontal: 0}; - var scWidth = scrollbarWidth(); - var lastColumnCount = 0; //used by columnNum() - var $scrollContainer = opts.scrollContainer($table) || $([]); //guard against returned nulls - - var useAbsolutePositioning = opts.useAbsolutePositioning; - if (useAbsolutePositioning == null) { //defaults: locked=true, !locked=false - useAbsolutePositioning = opts.scrollContainer($table).length; + refloat(); + } else { + $floatTable.append($header); + $table.css(layoutAuto); + $floatTable.css(layoutAuto); + setHeaderHeight(); + } + }; + } + + /** + * first performs initial calculations that we expect to not change when the table, window, or scrolling container are scrolled. + * returns a function that calculates the floating container's top and left coords. takes into account if we are using page scrolling or inner scrolling + * @return {Function} + */ + function calculateFloatContainerPosFn(){ + var scrollingContainerTop = $scrollContainer.scrollTop(); + + //this floatEnd calc was moved out of the returned function because we assume the table height doesnt change (otherwise we must reinit by calling calculateFloatContainerPosFn) + var floatEnd; + var tableContainerGap = 0; + var captionHeight = haveCaption ? $caption.outerHeight(true) : 0; + var captionScrollOffset = captionAlignTop ? captionHeight : -captionHeight; + + var floatContainerHeight = $floatContainer.height(); + var tableOffset = $table.offset(); + if(locked){ + var containerOffset = $scrollContainer.offset(); + tableContainerGap = tableOffset.top - containerOffset.top + scrollingContainerTop; + if(haveCaption && captionAlignTop){ + tableContainerGap += captionHeight; + } + } else { + floatEnd = tableOffset.top - scrollingTop - floatContainerHeight + scrollingBottom + scrollbarOffset.horizontal; + } + var windowTop = $window.scrollTop(); + var windowLeft = $window.scrollLeft(); + var scrollContainerLeft = $scrollContainer.scrollLeft(); + scrollingContainerTop = $scrollContainer.scrollTop(); + + + + return function(eventType){ + if(eventType == 'windowScroll'){ + windowTop = $window.scrollTop(); + windowLeft = $window.scrollLeft(); + } else if(eventType == 'containerScroll'){ + scrollingContainerTop = $scrollContainer.scrollTop(); + scrollContainerLeft = $scrollContainer.scrollLeft(); + } else if(eventType != 'init') { + windowTop = $window.scrollTop(); + windowLeft = $window.scrollLeft(); + scrollingContainerTop = $scrollContainer.scrollTop(); + scrollContainerLeft = $scrollContainer.scrollLeft(); + } + if(isChrome && (windowTop < 0 || windowLeft < 0)){ //chrome overscroll effect at the top of the page - breaks fixed positioned floated headers + return; + } + + if(absoluteToFixedOnScroll){ + if(eventType == 'windowScrollDone'){ + changePositioning(true); //change to absolute + } else { + changePositioning(false); //change to fixed } - var $caption = $table.find("caption"); - var haveCaption = $caption.length == 1; - if (haveCaption) { - var captionAlignTop = ($caption.css("caption-side") || $caption.attr("align") || "top") === "top"; + } else if(eventType == 'windowScrollDone'){ + return null; //event is fired when they stop scrolling. ignore it if not 'absoluteToFixedOnScroll' + } + + tableOffset = $table.offset(); + if(haveCaption && captionAlignTop){ + tableOffset.top += captionHeight; + } + var top, left; + var tableHeight = $table.outerHeight(); + + if(locked && useAbsolutePositioning){ //inner scrolling, absolute positioning + if (tableContainerGap >= scrollingContainerTop) { + var gap = tableContainerGap - scrollingContainerTop; + gap = gap > 0 ? gap : 0; + top = gap; + } else { + top = wrappedContainer ? 0 : scrollingContainerTop; + //headers stop at the top of the viewport } - - var $fthGrp = $(''); - - var locked = $scrollContainer.length > 0; - var wrappedContainer = false; //used with absolute positioning enabled. did we need to wrap the scrollContainer/table with a relative div? - var $wrapper = $([]); //used when absolute positioning enabled - wraps the table and the float container - var absoluteToFixedOnScroll = ieVersion <= 9 && !locked && useAbsolutePositioning; //on ie using absolute positioning doesnt look good with window scrolling, so we change positon to fixed on scroll, and then change it back to absolute when done. - var $floatTable = $("
'); + cols.push('
"); - var $floatColGroup = $(""); - var $tableColGroup = $(""); - var $fthRow = $(''); //created unstyled elements - var $floatContainer = $('
'); - 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 (isChrome) { - $fthGrp.append($fthRow); - $table.append($fthGrp); + left = 0; + } else if(!locked && useAbsolutePositioning) { //window scrolling, absolute positioning + if(windowTop > floatEnd + tableHeight + captionScrollOffset){ + top = tableHeight - floatContainerHeight + captionScrollOffset; //scrolled past table + } else if (tableOffset.top > windowTop + scrollingTop) { + top = 0; //scrolling to table + unfloat(); + } else { + top = scrollingTop + windowTop - tableOffset.top + tableContainerGap + (captionAlignTop ? captionHeight : 0); + refloat(); //scrolling within table. header floated } - - $floatTable.append($floatColGroup); - $floatContainer.append($floatTable); - if (opts.copyTableClass) { - $floatTable.attr('class', $table.attr('class')); + left = 0; + } else if(locked && !useAbsolutePositioning){ //inner scrolling, fixed positioning + if (tableContainerGap > scrollingContainerTop || scrollingContainerTop - tableContainerGap > tableHeight) { + top = tableOffset.top - windowTop; + unfloat(); + } else { + top = tableOffset.top + scrollingContainerTop - windowTop - tableContainerGap; + refloat(); + //headers stop at the top of the viewport } - $floatTable.attr({ //copy over some deprecated table attributes that people still like to use. Good thing poeple dont use colgroups... - 'cellpadding': $table.attr('cellpadding'), - 'cellspacing': $table.attr('cellspacing'), - 'border': $table.attr('border') - }); - - $floatTable.addClass(opts.floatTableClass).css('margin', 0); //must have no margins or you wont 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"); - if (!relativeToScrollContainer || alwaysWrap) { - var css = {"paddingLeft": $container.css('paddingLeft'), "paddingRight": $container.css('paddingRight')}; - $floatContainer.css(css); - $container = $container.wrap("
").parent(); - wrappedContainer = true; - } - return $container; - }; - if (locked) { - $wrapper = makeRelative($scrollContainer, true); - $wrapper.append($floatContainer); - } else { - $wrapper = makeRelative($table); - $table.after($floatContainer); - } + left = tableOffset.left + scrollContainerLeft - windowLeft; + } else if(!locked && !useAbsolutePositioning) { //window scrolling, fixed positioning + if(windowTop > floatEnd + tableHeight + captionScrollOffset){ + top = tableHeight + scrollingTop - windowTop + floatEnd + captionScrollOffset; + //scrolled past the bottom of the table + } else if (tableOffset.top > windowTop + scrollingTop) { + top = tableOffset.top - windowTop; + refloat(); + //scrolled past the top of the table } else { - $table.after($floatContainer); + //scrolling within the table + top = scrollingTop; } - - + left = tableOffset.left - windowLeft; + } + return {top: top, left: left}; + }; + } + /** + * returns a function that caches old floating container position and only updates css when the position changes + * @return {Function} + */ + function repositionFloatContainerFn(){ + var oldTop = null; + var oldLeft = null; + var oldScrollLeft = null; + return function(pos, setWidth, setHeight){ + if(pos != null && (oldTop != pos.top || oldLeft != pos.left)){ $floatContainer.css({ - position: useAbsolutePositioning ? 'absolute' : 'fixed', - marginTop: 0, - top: useAbsolutePositioning ? 0 : 'auto', - zIndex: opts.zIndex - }); - $floatContainer.addClass(opts.floatContainerClass); - updateScrollingOffsets(); - - var layoutFixed = {'table-layout': 'fixed'}; - var layoutAuto = {'table-layout': $table.css('tableLayout') || 'auto'}; - var originalTableWidth = $table[0].style.width || "auto"; - - function setHeaderHeight() { - var headerHeight = $header.find(opts.cellTag).outerHeight(true); - $sizerRow.outerHeight(headerHeight); - $sizerCells.outerHeight(headerHeight); - } - - - function setFloatWidth() { - var tableWidth = $table.outerWidth(); - var width = $scrollContainer.width() || tableWidth; - $floatContainer.width(width - scrollbarOffset.vertical); - if (locked) { - var percent = 100 * tableWidth / (width - scrollbarOffset.vertical); - $floatTable.css('width', percent + '%'); - } else { - $floatTable.outerWidth(tableWidth); - } - } - - function updateScrollingOffsets() { - scrollingTop = (util.isFunction(opts.scrollingTop) ? opts.scrollingTop($table) : opts.scrollingTop) || 0; - scrollingBottom = (util.isFunction(opts.scrollingBottom) ? opts.scrollingBottom($table) : opts.scrollingBottom) || 0; - } - - /** - * get the number of columns and also rebuild resizer rows if the count is different then the last count - */ - function columnNum() { - var $headerColumns = $header.find('tr:first>' + opts.cellTag); - var count = 0; - $headerColumns.each(function () { - count += parseInt(($(this).attr('colspan') || 1), 10); - }); - if (count != lastColumnCount) { - lastColumnCount = count; - var cells = [], cols = [], psuedo = []; - for (var x = 0; x < count; x++) { - cells.push(''); - psuedo.push(""); - } - - cols = cols.join(''); - cells = cells.join(''); - - if (isChrome) { - psuedo = psuedo.join(''); - $fthRow.html(psuedo); - $fthCells = $fthRow.find('fthtd'); - } - - $sizerRow.html(cells); - $sizerCells = $sizerRow.find("th"); - $tableColGroup.html(cols); - $tableCells = $tableColGroup.find('col'); - $floatColGroup.html(cols); - $headerCells = $floatColGroup.find("col"); - - } - return count; - } - - function refloat() { //make the thing float - if (!headerFloated) { - headerFloated = true; - if (useAbsolutePositioning) { //#53, #56 - var tableWidth = $table.width(); - var wrapperWidth = $wrapper.width(); - if (tableWidth > wrapperWidth) { - $table.css('minWidth', tableWidth); - } - } - $table.css(layoutFixed); - $floatTable.css(layoutFixed); - $floatTable.append($header); //append because colgroup must go first in chrome - $tbody.before($newHeader); - setHeaderHeight(); - } - } - - function unfloat() { //put the header back into the table - if (headerFloated) { - headerFloated = false; - if (useAbsolutePositioning) { //#53, #56 - $table.width(originalTableWidth); - } - $newHeader.detach(); - $table.prepend($header); - $table.css(layoutAuto); - $floatTable.css(layoutAuto); - } - } - - function changePositioning(isAbsolute) { - if (useAbsolutePositioning != isAbsolute) { - useAbsolutePositioning = isAbsolute; - $floatContainer.css({ - position: useAbsolutePositioning ? 'absolute' : 'fixed' - }); - } - } - - function getSizingRow($table, $cols, $fthCells, ieVersion) { - if (isChrome) { - return $fthCells; - } else if (ieVersion) { - return opts.getSizingRow($table, $cols, $fthCells); - } else { - return $cols; - } - } - - /** - * returns a function that updates the floating header's cell widths. - * @return {Function} - */ - function reflow() { - var i; - var numCols = columnNum(); //if the tables columns change dynamically since last time (datatables) we need to rebuild the sizer rows and get new count - return function () { - var $rowCells = getSizingRow($table, $tableCells, $fthCells, ieVersion); - if ($rowCells.length == numCols && numCols > 0) { - unfloat(); - for (i = 0; i < numCols; i++) { - var _rowcell = $rowCells.get(i); - var rowWidth = _rowcell.offsetWidth; - $headerCells.eq(i).width(rowWidth); - $tableCells.eq(i).width(rowWidth); - } - refloat(); - } else { - $floatTable.append($header); - $table.css(layoutAuto); - $floatTable.css(layoutAuto); - setHeaderHeight(); - } - }; - } - - /** - * first performs initial calculations that we expect to not change when the table, window, or scrolling container are scrolled. - * returns a function that calculates the floating container's top and left coords. takes into account if we are using page scrolling or inner scrolling - * @return {Function} - */ - function calculateFloatContainerPosFn() { - var scrollingContainerTop = $scrollContainer.scrollTop(); - - //this floatEnd calc was moved out of the returned function because we assume the table height doesnt change (otherwise we must reinit by calling calculateFloatContainerPosFn) - var floatEnd; - var tableContainerGap = 0; - var captionHeight = haveCaption ? $caption.outerHeight(true) : 0; - var captionScrollOffset = captionAlignTop ? captionHeight : -captionHeight; - - var floatContainerHeight = $floatContainer.height(); - var tableOffset = $table.offset(); - if (locked) { - var containerOffset = $scrollContainer.offset(); - tableContainerGap = tableOffset.top - containerOffset.top + scrollingContainerTop; - if (haveCaption && captionAlignTop) { - tableContainerGap += captionHeight; - } - } else { - floatEnd = tableOffset.top - scrollingTop - floatContainerHeight + scrollingBottom + scrollbarOffset.horizontal; - } - var windowTop = $window.scrollTop(); - var windowLeft = $window.scrollLeft(); - var scrollContainerLeft = $scrollContainer.scrollLeft(); - scrollingContainerTop = $scrollContainer.scrollTop(); - - - return function (eventType) { - if (eventType == 'windowScroll') { - windowTop = $window.scrollTop(); - windowLeft = $window.scrollLeft(); - } else if (eventType == 'containerScroll') { - scrollingContainerTop = $scrollContainer.scrollTop(); - scrollContainerLeft = $scrollContainer.scrollLeft(); - } else if (eventType != 'init') { - windowTop = $window.scrollTop(); - windowLeft = $window.scrollLeft(); - scrollingContainerTop = $scrollContainer.scrollTop(); - scrollContainerLeft = $scrollContainer.scrollLeft(); - } - if (isChrome && (windowTop < 0 || windowLeft < 0)) { //chrome overscroll effect at the top of the page - breaks fixed positioned floated headers - return; - } - - if (absoluteToFixedOnScroll) { - if (eventType == 'windowScrollDone') { - changePositioning(true); //change to absolute - } else { - changePositioning(false); //change to fixed - } - } else if (eventType == 'windowScrollDone') { - return null; //event is fired when they stop scrolling. ignore it if not 'absoluteToFixedOnScroll' - } - - tableOffset = $table.offset(); - if (haveCaption && captionAlignTop) { - tableOffset.top += captionHeight; - } - var top, left, tableHeight; - - if (locked && useAbsolutePositioning) { //inner scrolling, absolute positioning - if (tableContainerGap >= scrollingContainerTop) { - var gap = tableContainerGap - scrollingContainerTop; - gap = gap > 0 ? gap : 0; - top = gap; - } else { - top = wrappedContainer ? 0 : scrollingContainerTop; - //headers stop at the top of the viewport - } - left = 0; - } else if (!locked && useAbsolutePositioning) { //window scrolling, absolute positioning - tableHeight = $table.outerHeight(); - if (windowTop > floatEnd + tableHeight + captionScrollOffset) { - top = tableHeight - floatContainerHeight + captionScrollOffset; //scrolled past table - } else if (tableOffset.top > windowTop + scrollingTop) { - top = 0; //scrolling to table - unfloat(); - } else { - top = scrollingTop + windowTop - tableOffset.top + tableContainerGap + (captionAlignTop ? captionHeight : 0); - refloat(); //scrolling within table. header floated - } - left = 0; - } else if (locked && !useAbsolutePositioning) { //inner scrolling, fixed positioning - if (tableContainerGap > scrollingContainerTop) { - top = tableOffset.top - windowTop; - unfloat(); - } else { - top = tableOffset.top + scrollingContainerTop - windowTop - tableContainerGap; - refloat(); - //headers stop at the top of the viewport - } - left = tableOffset.left + scrollContainerLeft - windowLeft; - } else if (!locked && !useAbsolutePositioning) { //window scrolling, fixed positioning - tableHeight = $table.outerHeight(); - if (windowTop > floatEnd + tableHeight + captionScrollOffset) { - top = tableHeight + scrollingTop - windowTop + floatEnd + captionScrollOffset; - //scrolled past the bottom of the table - } else if (tableOffset.top > windowTop + scrollingTop) { - top = tableOffset.top - windowTop; - refloat(); - //scrolled past the top of the table - } else { - //scrolling within the table - top = scrollingTop; - } - left = tableOffset.left - windowLeft; - } - return {top: top, left: left}; - }; - } - - /** - * returns a function that caches old floating container position and only updates css when the position changes - * @return {Function} - */ - function repositionFloatContainerFn() { - var oldTop = null; - var oldLeft = null; - var oldScrollLeft = null; - return function (pos, setWidth, setHeight) { - if (pos != null && (oldTop != pos.top || oldLeft != pos.left)) { - $floatContainer.css({ - top: pos.top, - left: pos.left - }); - oldTop = pos.top; - oldLeft = pos.left; - } - if (setWidth) { - setFloatWidth(); - } - if (setHeight) { - setHeaderHeight(); - } - var scrollLeft = $scrollContainer.scrollLeft(); - if (oldScrollLeft != scrollLeft) { - $floatContainer.scrollLeft(scrollLeft); - oldScrollLeft = scrollLeft; - } - } - } - - /** - * checks if THIS table has scrollbars, and finds their widths - */ - function calculateScrollBarSize() { //this should happen after the floating table has been positioned - if ($scrollContainer.length) { - scrollbarOffset.horizontal = $scrollContainer.width() < $table.width() ? scWidth : 0; - scrollbarOffset.vertical = $scrollContainer.height() < $table.height() ? scWidth : 0; - } - } - - //finish up. create all calculation functions and bind them to events - calculateScrollBarSize(); - - var flow; - - var ensureReflow = function () { - flow = reflow(); - flow(); - }; - - ensureReflow(); - - var calculateFloatContainerPos = calculateFloatContainerPosFn(); - var repositionFloatContainer = repositionFloatContainerFn(); - - repositionFloatContainer(calculateFloatContainerPos('init'), true); //this must come after reflow because reflow changes scrollLeft back to 0 when it rips out the thead - - var windowScrollDoneEvent = util.debounce(function () { - repositionFloatContainer(calculateFloatContainerPos('windowScrollDone'), false); - }, 300); - - var windowScrollEvent = function () { - repositionFloatContainer(calculateFloatContainerPos('windowScroll'), false); - windowScrollDoneEvent(); - }; - var containerScrollEvent = function () { - repositionFloatContainer(calculateFloatContainerPos('containerScroll'), false); - }; - - - var windowResizeEvent = function () { - updateScrollingOffsets(); - calculateScrollBarSize(); - ensureReflow(); - calculateFloatContainerPos = calculateFloatContainerPosFn(); - repositionFloatContainer = repositionFloatContainerFn(); - repositionFloatContainer(calculateFloatContainerPos('resize'), true, true); - }; - var reflowEvent = util.debounce(function () { - calculateScrollBarSize(); - updateScrollingOffsets(); - ensureReflow(); - calculateFloatContainerPos = calculateFloatContainerPosFn(); - repositionFloatContainer(calculateFloatContainerPos('reflow'), true); - }, 1); - if (locked) { //internal scrolling - if (useAbsolutePositioning) { - $scrollContainer.bind('scroll.floatTHead', containerScrollEvent); - } else { - $scrollContainer.bind('scroll.floatTHead', containerScrollEvent); - $window.bind('scroll.floatTHead', windowScrollEvent); - } - } else { //window scrolling - $window.bind('scroll.floatTHead', windowScrollEvent); - } - - $window.bind('load.floatTHead', reflowEvent); //for tables with images - - windowResize(opts.debounceResizeMs, windowResizeEvent); - $table.bind('reflow', reflowEvent); - if (isDatatable($table)) { - $table - .bind('filter', reflowEvent) - .bind('sort', reflowEvent) - .bind('page', reflowEvent); - } - - //attach some useful functions to the table. - $table.data('floatThead-attached', { - destroy: function () { - unfloat(); - $table.css(layoutAuto); - $tableColGroup.remove(); - isChrome && $fthGrp.remove(); - if ($newHeader.parent().length) { //only if its in the dom - $newHeader.replaceWith($header); - } - $table.unbind('reflow'); - reflowEvent = windowResizeEvent = containerScrollEvent = windowScrollEvent = function () { - }; - $scrollContainer.unbind('scroll.floatTHead'); - $floatContainer.remove(); - $table.data('floatThead-attached', false); - floatTheadCreated--; - if (floatTheadCreated == 0) { - $window.unbind('scroll.floatTHead'); - $window.unbind('resize.floatTHead'); - $window.unbind('load.floatTHead'); - } - }, - reflow: function () { - reflowEvent(); - }, - setHeaderHeight: function () { - setHeaderHeight(); - }, - getFloatContainer: function () { - return $floatContainer; - }, - getRowGroups: function () { - if (headerFloated) { - return $floatContainer.find("thead").add($table.find("tbody,tfoot")); - } else { - return $table.find("thead,tbody,tfoot"); - } - } + top: pos.top, + left: pos.left }); - floatTheadCreated++; - }); - return this; - }; + oldTop = pos.top; + oldLeft = pos.left; + } + if(setWidth){ + setFloatWidth(); + } + if(setHeight){ + setHeaderHeight(); + } + var scrollLeft = $scrollContainer.scrollLeft(); + if(oldScrollLeft != scrollLeft){ + $floatContainer.scrollLeft(scrollLeft); + oldScrollLeft = scrollLeft; + } + } + } + + /** + * checks if THIS table has scrollbars, and finds their widths + */ + function calculateScrollBarSize(){ //this should happen after the floating table has been positioned + if($scrollContainer.length){ + var sw = $scrollContainer.width(), sh = $scrollContainer.height(), th = $table.height(), tw = $table.width(); + var offseth = sw < tw ? scWidth : 0; + var offsetv = sh < th ? scWidth : 0; + scrollbarOffset.horizontal = sw - offsetv < tw ? scWidth : 0; + scrollbarOffset.vertical = sh - offseth < th ? scWidth: 0; + } + } + //finish up. create all calculation functions and bind them to events + calculateScrollBarSize(); + + var flow; + + var ensureReflow = function(){ + flow = reflow(); + flow(); + }; + + ensureReflow(); + + var calculateFloatContainerPos = calculateFloatContainerPosFn(); + var repositionFloatContainer = repositionFloatContainerFn(); + + repositionFloatContainer(calculateFloatContainerPos('init'), true); //this must come after reflow because reflow changes scrollLeft back to 0 when it rips out the thead + + var windowScrollDoneEvent = util.debounce(function(){ + repositionFloatContainer(calculateFloatContainerPos('windowScrollDone'), false); + }, 300); + + var windowScrollEvent = function(){ + repositionFloatContainer(calculateFloatContainerPos('windowScroll'), false); + windowScrollDoneEvent(); + }; + var containerScrollEvent = function(){ + repositionFloatContainer(calculateFloatContainerPos('containerScroll'), false); + }; + + + var windowResizeEvent = function(){ + updateScrollingOffsets(); + calculateScrollBarSize(); + ensureReflow(); + calculateFloatContainerPos = calculateFloatContainerPosFn(); + repositionFloatContainer = repositionFloatContainerFn(); + repositionFloatContainer(calculateFloatContainerPos('resize'), true, true); + }; + var reflowEvent = util.debounce(function(){ + calculateScrollBarSize(); + updateScrollingOffsets(); + ensureReflow(); + calculateFloatContainerPos = calculateFloatContainerPosFn(); + repositionFloatContainer(calculateFloatContainerPos('reflow'), true); + }, 1); + if(locked){ //internal scrolling + if(useAbsolutePositioning){ + $scrollContainer.on(eventName('scroll'), containerScrollEvent); + } else { + $scrollContainer.on(eventName('scroll'), containerScrollEvent); + $window.on(eventName('scroll'), windowScrollEvent); + } + } else { //window scrolling + $window.on(eventName('scroll'), windowScrollEvent); + } + + $window.on(eventName('load'), reflowEvent); //for tables with images + + windowResize(opts.debounceResizeMs, eventName('resize'), windowResizeEvent); + $table.on('reflow', reflowEvent); + if(isDatatable($table)){ + $table + .on('filter', reflowEvent) + .on('sort', reflowEvent) + .on('page', reflowEvent); + } + + //attach some useful functions to the table. + $table.data('floatThead-attached', { + destroy: function(){ + var ns = '.fth-'+floatTheadId; + unfloat(); + $table.css(layoutAuto); + $tableColGroup.remove(); + isChrome && $fthGrp.remove(); + if($newHeader.parent().length){ //only if its in the dom + $newHeader.replaceWith($header); + } + $table.off('reflow'); + $scrollContainer.off(ns); + if (wrappedContainer) { + $scrollContainer.unwrap(); + } + $floatContainer.remove(); + $table.data('floatThead-attached', false); + + $window.off(ns); + }, + reflow: function(){ + reflowEvent(); + }, + setHeaderHeight: function(){ + setHeaderHeight(); + }, + getFloatContainer: function(){ + return $floatContainer; + }, + getRowGroups: function(){ + if(headerFloated){ + return $floatContainer.find("thead").add($table.find("tbody,tfoot")); + } else { + return $table.find("thead,tbody,tfoot"); + } + } + }); + floatTheadCreated++; + }); + return this; + }; })(jQuery); + /* jQuery.floatThead.utils - http://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2014 Misha Koryak - * Licensed under CC BY-SA 4.0 and MIT + * License: MIT * * This file is required if you do not use underscore in your project and you want to use floatThead. * It contains functions from underscore that the plugin uses. @@ -677,52 +706,52 @@ * */ -(function () { +(function($){ - $.floatThead = $.floatThead || {}; + $.floatThead = $.floatThead || {}; - $.floatThead._ = window._ || (function () { - 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 = 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; - }; - $.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; - }; + $.floatThead._ = window._ || (function(){ + 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 = 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; + }; + $.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); + } }; - return that; - })(); -})(); + var callNow = immediate && !timeout; + if (!timeout) { + timeout = setTimeout(later, wait); + } + if (callNow) result = func.apply(context, args); + return result; + }; + }; + return that; + })(); +})(jQuery); diff --git a/grid/assets/js/jquery.floatThead.min.js b/grid/assets/js/jquery.floatThead.min.js index 42abe3b9..9682a357 100644 --- a/grid/assets/js/jquery.floatThead.min.js +++ b/grid/assets/js/jquery.floatThead.min.js @@ -1,3 +1,3 @@ -// @preserve jQuery.floatThead 1.2.4 - http://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2014 Misha Koryak -// @license Licensed under http://creativecommons.org/licenses/by-sa/4.0/ -!function(a){function b(a,b){j.bind("resize.floatTHead",f.debounce(b,a))}function c(a){window.console&&window.console&&window.console.log&&window.console.log(a)}function d(){var b=a('
');a("body").append(b);var c=b.innerWidth(),d=a("div",b).innerWidth();return b.remove(),c-d}function e(a){if(a.dataTableSettings)for(var b=0;btd")},floatTableClass:"floatThead-table",floatWrapperClass:"floatThead-wrapper",floatContainerClass:"floatThead-container",copyTableClass:!0,debug:!1};var f=window._,g=function(){for(var a=3,b=document.createElement("b"),c=b.all||[];a=1+a,b.innerHTML="",c[0];);return a>4?a:document.documentMode}(),h=null,i=function(){if(g)return!1;var b=a("
'); - cols.push('
");a("body").append(b);var c=b.find("col").width();return b.remove(),0==c},j=a(window),k=0;a.fn.floatThead=function(l){if(l=l||{},!f&&(f=window._||a.floatThead._,!f))throw new Error("jquery.floatThead-slim.js requires underscore. You should use the non-lite version since you do not have underscore.");if(8>g)return this;if(null==h&&(h=i(),h&&(document.createElement("fthtr"),document.createElement("fthtd"),document.createElement("fthfoot"))),f.isString(l)){var m=l,n=this;return this.filter("table").each(function(){var b=a(this).data("floatThead-attached");if(b&&f.isFunction(b[m])){var c=b[m]();"undefined"!=typeof c&&(n=c)}}),n}var o=a.extend({},a.floatThead.defaults||{},l);return a.each(l,function(b,d){d in a.floatThead.defaults||!o.debug||c("jQuery.floatThead: used ["+d+"] key to init plugin, but that param is not an option for the plugin. Valid options are: "+f.keys(a.floatThead.defaults).join(", "))}),this.filter(":not(."+o.floatTableClass+")").each(function(){function c(){var a=x.find(o.cellTag).outerHeight(!0);V.outerHeight(a),W.outerHeight(a)}function i(){var a=w.outerWidth(),b=F.width()||a;if(T.width(b-C.vertical),L){var c=100*a/(b-C.vertical);P.css("width",c+"%")}else P.outerWidth(a)}function l(){z=(f.isFunction(o.scrollingTop)?o.scrollingTop(w):o.scrollingTop)||0,A=(f.isFunction(o.scrollingBottom)?o.scrollingBottom(w):o.scrollingBottom)||0}function m(){var b=x.find("tr:first>"+o.cellTag),c=0;if(b.each(function(){c+=parseInt(a(this).attr("colspan")||1,10)}),c!=E){E=c;for(var d=[],e=[],f=[],g=0;c>g;g++)d.push(''),e.push(""),f.push("");e=e.join(""),d=d.join(""),h&&(f=f.join(""),S.html(f),Z=S.find("fthtd")),V.html(d),W=V.find("th"),R.html(e),X=R.find("col"),Q.html(e),Y=Q.find("col")}return c}function n(){if(!B){if(B=!0,G){var a=w.width(),b=N.width();a>b&&w.css("minWidth",a)}w.css(_),P.css(_),P.append(x),y.before(U),c()}}function p(){B&&(B=!1,G&&w.width(bb),U.detach(),w.prepend(x),w.css(ab),P.css(ab))}function q(a){G!=a&&(G=a,T.css({position:G?"absolute":"fixed"}))}function r(a,b,c,d){return h?c:d?o.getSizingRow(a,b,c):b}function s(){var a,b=m();return function(){var d=r(w,X,Z,g);if(d.length==b&&b>0){for(p(),a=0;b>a;a++){var e=d.get(a),f=e.offsetWidth;Y.eq(a).width(f),X.eq(a).width(f)}n()}else P.append(x),w.css(ab),P.css(ab),c()}}function t(){var a,b=F.scrollTop(),c=0,d=I?H.outerHeight(!0):0,e=J?d:-d,f=T.height(),g=w.offset();if(L){var i=F.offset();c=g.top-i.top+b,I&&J&&(c+=d)}else a=g.top-z-f+A+C.horizontal;var k=j.scrollTop(),l=j.scrollLeft(),m=F.scrollLeft();return b=F.scrollTop(),function(i){if("windowScroll"==i?(k=j.scrollTop(),l=j.scrollLeft()):"containerScroll"==i?(b=F.scrollTop(),m=F.scrollLeft()):"init"!=i&&(k=j.scrollTop(),l=j.scrollLeft(),b=F.scrollTop(),m=F.scrollLeft()),!h||!(0>k||0>l)){if(O)"windowScrollDone"==i?q(!0):q(!1);else if("windowScrollDone"==i)return null;g=w.offset(),I&&J&&(g.top+=d);var o,r,s;if(L&&G){if(c>=b){var t=c-b;t=t>0?t:0,o=t}else o=M?0:b;r=0}else!L&&G?(s=w.outerHeight(),k>a+s+e?o=s-f+e:g.top>k+z?(o=0,p()):(o=z+k-g.top+c+(J?d:0),n()),r=0):L&&!G?(c>b?(o=g.top-k,p()):(o=g.top+b-k-c,n()),r=g.left+m-l):L||G||(s=w.outerHeight(),k>a+s+e?o=s+z-k+a+e:g.top>k+z?(o=g.top-k,n()):o=z,r=g.left-l);return{top:o,left:r}}}}function u(){var a=null,b=null,d=null;return function(e,f,g){null==e||a==e.top&&b==e.left||(T.css({top:e.top,left:e.left}),a=e.top,b=e.left),f&&i(),g&&c();var h=F.scrollLeft();d!=h&&(T.scrollLeft(h),d=h)}}function v(){F.length&&(C.horizontal=F.width() element");var z,A,B=!1,C={vertical:0,horizontal:0},D=d(),E=0,F=o.scrollContainer(w)||a([]),G=o.useAbsolutePositioning;null==G&&(G=o.scrollContainer(w).length);var H=w.find("caption"),I=1==H.length;if(I)var J="top"===(H.css("caption-side")||H.attr("align")||"top");var K=a(''),L=F.length>0,M=!1,N=a([]),O=9>=g&&!L&&G,P=a(""),Q=a(""),R=a(""),S=a(''),T=a('
'),U=a("
"),V=a(''),W=a([]),X=a([]),Y=a([]),Z=a([]);if(U.append(V),w.prepend(R),h&&(K.append(S),w.append(K)),P.append(Q),T.append(P),o.copyTableClass&&P.attr("class",w.attr("class")),P.attr({cellpadding:w.attr("cellpadding"),cellspacing:w.attr("cellspacing"),border:w.attr("border")}),P.addClass(o.floatTableClass).css("margin",0),G){var $=function(a,b){var c=a.css("position"),d="relative"==c||"absolute"==c;if(!d||b){var e={paddingLeft:a.css("paddingLeft"),paddingRight:a.css("paddingRight")};T.css(e),a=a.wrap("
").parent(),M=!0}return a};L?(N=$(F,!0),N.append(T)):(N=$(w),w.after(T))}else w.after(T);T.css({position:G?"absolute":"fixed",marginTop:0,top:G?0:"auto",zIndex:o.zIndex}),T.addClass(o.floatContainerClass),l();var _={"table-layout":"fixed"},ab={"table-layout":w.css("tableLayout")||"auto"},bb=w[0].style.width||"auto";v();var cb,db=function(){(cb=s())()};db();var eb=t(),fb=u();fb(eb("init"),!0);var gb=f.debounce(function(){fb(eb("windowScrollDone"),!1)},300),hb=function(){fb(eb("windowScroll"),!1),gb()},ib=function(){fb(eb("containerScroll"),!1)},jb=function(){l(),v(),db(),eb=t(),(fb=u())(eb("resize"),!0,!0)},kb=f.debounce(function(){v(),l(),db(),eb=t(),fb(eb("reflow"),!0)},1);L?G?F.bind("scroll.floatTHead",ib):(F.bind("scroll.floatTHead",ib),j.bind("scroll.floatTHead",hb)):j.bind("scroll.floatTHead",hb),j.bind("load.floatTHead",kb),b(o.debounceResizeMs,jb),w.bind("reflow",kb),e(w)&&w.bind("filter",kb).bind("sort",kb).bind("page",kb),w.data("floatThead-attached",{destroy:function(){p(),w.css(ab),R.remove(),h&&K.remove(),U.parent().length&&U.replaceWith(x),w.unbind("reflow"),kb=jb=ib=hb=function(){},F.unbind("scroll.floatTHead"),T.remove(),w.data("floatThead-attached",!1),k--,0==k&&(j.unbind("scroll.floatTHead"),j.unbind("resize.floatTHead"),j.unbind("load.floatTHead"))},reflow:function(){kb()},setHeaderHeight:function(){c()},getFloatContainer:function(){return T},getRowGroups:function(){return B?T.find("thead").add(w.find("tbody,tfoot")):w.find("thead,tbody,tfoot")}}),k++}),this}}(jQuery),function(){$.floatThead=$.floatThead||{},$.floatThead._=window._||function(){var a={},b=Object.prototype.hasOwnProperty,c=["Arguments","Function","String","Number","Date","RegExp"];return a.has=function(a,c){return b.call(a,c)},a.keys=function(b){if(b!==Object(b))throw new TypeError("Invalid object");var c=[];for(var d in b)a.has(b,d)&&c.push(d);return c},$.each(c,function(){var b=this;a["is"+b]=function(a){return Object.prototype.toString.call(a)=="[object "+b+"]"}}),a.debounce=function(a,b,c){var d,e,f,g,h;return function(){f=this,e=arguments,g=new Date;var i=function(){var j=new Date-g;b>j?d=setTimeout(i,b-j):(d=null,c||(h=a.apply(f,e)))},j=c&&!d;return d||(d=setTimeout(i,b)),j&&(h=a.apply(f,e)),h}},a}()}(); \ No newline at end of file +// @preserve jQuery.floatThead 1.2.8 - http://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2014 Misha Koryak +// @license MIT +!function(a){function b(a,b,c){if(8==g){var d=j.width(),e=f.debounce(function(){var a=j.width();d!=a&&(d=a,c())},a);j.on(b,e)}else j.on(b,f.debounce(c,a))}function c(a){window.console&&window.console&&window.console.log&&window.console.log(a)}function d(){var b=a('
');a("body").append(b);var c=b.innerWidth(),d=a("div",b).innerWidth();return b.remove(),c-d}function e(a){if(a.dataTableSettings)for(var b=0;b*")},floatTableClass:"floatThead-table",floatWrapperClass:"floatThead-wrapper",floatContainerClass:"floatThead-container",copyTableClass:!0,debug:!1};var f=window._,g=function(){for(var a=3,b=document.createElement("b"),c=b.all||[];a=1+a,b.innerHTML="",c[0];);return a>4?a:document.documentMode}(),h=null,i=function(){if(g)return!1;var b=a("
");a("body").append(b);var c=b.find("col").width();return b.remove(),0==c},j=a(window),k=0;a.fn.floatThead=function(l){if(l=l||{},!f&&(f=window._||a.floatThead._,!f))throw new Error("jquery.floatThead-slim.js requires underscore. You should use the non-lite version since you do not have underscore.");if(8>g)return this;if(null==h&&(h=i(),h&&(document.createElement("fthtr"),document.createElement("fthtd"),document.createElement("fthfoot"))),f.isString(l)){var m=l,n=this;return this.filter("table").each(function(){var b=a(this).data("floatThead-attached");if(b&&f.isFunction(b[m])){var c=b[m]();"undefined"!=typeof c&&(n=c)}}),n}var o=a.extend({},a.floatThead.defaults||{},l);return a.each(l,function(b){b in a.floatThead.defaults||!o.debug||c("jQuery.floatThead: used ["+b+"] key to init plugin, but that param is not an option for the plugin. Valid options are: "+f.keys(a.floatThead.defaults).join(", "))}),this.filter(":not(."+o.floatTableClass+")").each(function(){function c(a){return a+".fth-"+x+".floatTHead"}function i(){var b=0;z.find("tr:visible").each(function(){b+=a(this).outerHeight(!0)}),Y.outerHeight(b),Z.outerHeight(b)}function l(){var a=y.outerWidth(),b=H.width()||a;if(W.width(b-E.vertical),N){var c=100*a/(b-E.vertical);R.css("width",c+"%")}else R.outerWidth(a)}function m(){B=(f.isFunction(o.scrollingTop)?o.scrollingTop(y):o.scrollingTop)||0,C=(f.isFunction(o.scrollingBottom)?o.scrollingBottom(y):o.scrollingBottom)||0}function n(){var b,c;if(U?b=T.find("col").length:(c=z.find("tr:first>"+o.cellTag),b=0,c.each(function(){b+=parseInt(a(this).attr("colspan")||1,10)})),b!=G){G=b;for(var d=[],e=[],f=[],g=0;b>g;g++)d.push(''),e.push(""),f.push("");e=e.join(""),d=d.join(""),h&&(f=f.join(""),V.html(f),ab=V.find("fthtd")),Y.html(d),Z=Y.find("th"),U||T.html(e),$=T.find("col"),S.html(e),_=S.find("col")}return b}function p(){if(!D){if(D=!0,I){var a=y.width(),b=P.width();a>b&&y.css("minWidth",a)}y.css(cb),R.css(cb),R.append(z),A.before(X),i()}}function q(){D&&(D=!1,I&&y.width(eb),X.detach(),y.prepend(z),y.css(db),R.css(db))}function r(a){I!=a&&(I=a,W.css({position:I?"absolute":"fixed"}))}function s(a,b,c,d){return h?c:d?o.getSizingRow(a,b,c):b}function t(){var a,b=n();return function(){var c=s(y,$,ab,g);if(c.length==b&&b>0){if(!U)for(a=0;b>a;a++)$.eq(a).css("width","");for(q(),a=0;b>a;a++){var d=c.get(a),e=d.offsetWidth;_.eq(a).width(e),$.eq(a).width(e)}p()}else R.append(z),y.css(db),R.css(db),i()}}function u(){var a,b=H.scrollTop(),c=0,d=K?J.outerHeight(!0):0,e=L?d:-d,f=W.height(),g=y.offset();if(N){var i=H.offset();c=g.top-i.top+b,K&&L&&(c+=d)}else a=g.top-B-f+C+E.horizontal;var k=j.scrollTop(),l=j.scrollLeft(),m=H.scrollLeft();return b=H.scrollTop(),function(i){if("windowScroll"==i?(k=j.scrollTop(),l=j.scrollLeft()):"containerScroll"==i?(b=H.scrollTop(),m=H.scrollLeft()):"init"!=i&&(k=j.scrollTop(),l=j.scrollLeft(),b=H.scrollTop(),m=H.scrollLeft()),!h||!(0>k||0>l)){if(Q)r("windowScrollDone"==i?!0:!1);else if("windowScrollDone"==i)return null;g=y.offset(),K&&L&&(g.top+=d);var n,o,s=y.outerHeight();if(N&&I){if(c>=b){var t=c-b;t=t>0?t:0,n=t}else n=O?0:b;o=0}else!N&&I?(k>a+s+e?n=s-f+e:g.top>k+B?(n=0,q()):(n=B+k-g.top+c+(L?d:0),p()),o=0):N&&!I?(c>b||b-c>s?(n=g.top-k,q()):(n=g.top+b-k-c,p()),o=g.left+m-l):N||I||(k>a+s+e?n=s+B-k+a+e:g.top>k+B?(n=g.top-k,p()):n=B,o=g.left-l);return{top:n,left:o}}}}function v(){var a=null,b=null,c=null;return function(d,e,f){null==d||a==d.top&&b==d.left||(W.css({top:d.top,left:d.left}),a=d.top,b=d.left),e&&l(),f&&i();var g=H.scrollLeft();c!=g&&(W.scrollLeft(g),c=g)}}function w(){if(H.length){var a=H.width(),b=H.height(),c=y.height(),d=y.width(),e=d>a?F:0,f=c>b?F:0;E.horizontal=d>a-f?F:0,E.vertical=c>b-e?F:0}}var x=k,y=a(this);if(y.data("floatThead-attached"))return!0;if(!y.is("table"))throw new Error('jQuery.floatThead must be run on a table element. ex: $("table").floatThead();');var z=y.find("thead:first"),A=y.find("tbody:first");if(0==z.length)throw new Error("jQuery.floatThead must be run on a table that contains a element");var B,C,D=!1,E={vertical:0,horizontal:0},F=d(),G=0,H=o.scrollContainer(y)||a([]),I=o.useAbsolutePositioning;null==I&&(I=o.scrollContainer(y).length);var J=y.find("caption"),K=1==J.length;if(K)var L="top"===(J.css("caption-side")||J.attr("align")||"top");var M=a(''),N=H.length>0,O=!1,P=a([]),Q=9>=g&&!N&&I,R=a(""),S=a(""),T=y.find("colgroup:first"),U=!0;0==T.length&&(T=a(""),U=!1);var V=a(''),W=a('
'),X=a("
"),Y=a(''),Z=a([]),$=a([]),_=a([]),ab=a([]);if(X.append(Y),y.prepend(T),h&&(M.append(V),y.append(M)),R.append(S),W.append(R),o.copyTableClass&&R.attr("class",y.attr("class")),R.attr({cellpadding:y.attr("cellpadding"),cellspacing:y.attr("cellspacing"),border:y.attr("border")}),R.addClass(o.floatTableClass).css("margin",0),I){var bb=function(a,b){var c=a.css("position"),d="relative"==c||"absolute"==c;if(!d||b){var e={paddingLeft:a.css("paddingLeft"),paddingRight:a.css("paddingRight")};W.css(e),a=a.wrap("
").parent(),O=!0}return a};N?(P=bb(H,!0),P.append(W)):(P=bb(y),y.after(W))}else y.after(W);W.css({position:I?"absolute":"fixed",marginTop:0,top:I?0:"auto",zIndex:o.zIndex}),W.addClass(o.floatContainerClass),m();var cb={"table-layout":"fixed"},db={"table-layout":y.css("tableLayout")||"auto"},eb=y[0].style.width||"";w();var fb,gb=function(){(fb=t())()};gb();var hb=u(),ib=v();ib(hb("init"),!0);var jb=f.debounce(function(){ib(hb("windowScrollDone"),!1)},300),kb=function(){ib(hb("windowScroll"),!1),jb()},lb=function(){ib(hb("containerScroll"),!1)},mb=function(){m(),w(),gb(),hb=u(),(ib=v())(hb("resize"),!0,!0)},nb=f.debounce(function(){w(),m(),gb(),hb=u(),ib(hb("reflow"),!0)},1);N?I?H.on(c("scroll"),lb):(H.on(c("scroll"),lb),j.on(c("scroll"),kb)):j.on(c("scroll"),kb),j.on(c("load"),nb),b(o.debounceResizeMs,c("resize"),mb),y.on("reflow",nb),e(y)&&y.on("filter",nb).on("sort",nb).on("page",nb),y.data("floatThead-attached",{destroy:function(){var a=".fth-"+x;q(),y.css(db),T.remove(),h&&M.remove(),X.parent().length&&X.replaceWith(z),y.off("reflow"),H.off(a),O&&H.unwrap(),W.remove(),y.data("floatThead-attached",!1),j.off(a)},reflow:function(){nb()},setHeaderHeight:function(){i()},getFloatContainer:function(){return W},getRowGroups:function(){return D?W.find("thead").add(y.find("tbody,tfoot")):y.find("thead,tbody,tfoot")}}),k++}),this}}(jQuery),function(a){a.floatThead=a.floatThead||{},a.floatThead._=window._||function(){var b={},c=Object.prototype.hasOwnProperty,d=["Arguments","Function","String","Number","Date","RegExp"];return b.has=function(a,b){return c.call(a,b)},b.keys=function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[];for(var d in a)b.has(a,d)&&c.push(d);return c},a.each(d,function(){var a=this;b["is"+a]=function(b){return Object.prototype.toString.call(b)=="[object "+a+"]"}}),b.debounce=function(a,b,c){var d,e,f,g,h;return function(){f=this,e=arguments,g=new Date;var i=function(){var j=new Date-g;b>j?d=setTimeout(i,b-j):(d=null,c||(h=a.apply(f,e)))},j=c&&!d;return d||(d=setTimeout(i,b)),j&&(h=a.apply(f,e)),h}},b}()}(jQuery); \ No newline at end of file