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(' | ');
+ cols.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 = $("");
- 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(' | ');
- cols.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;b
td")},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,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