From d5512998d43f28959e3e751f014162371cf9d2b6 Mon Sep 17 00:00:00 2001 From: Glenn Vorhes <gavorhes@wisc.edu> Date: Wed, 22 Jun 2016 13:44:40 -0500 Subject: [PATCH] add floathead as dependency --- ext/jquery.floatThead.js | 966 --------------------------------------- ext/sortable-table.js | 496 -------------------- package.json | 2 +- 3 files changed, 1 insertion(+), 1463 deletions(-) delete mode 100644 ext/jquery.floatThead.js delete mode 100644 ext/sortable-table.js diff --git a/ext/jquery.floatThead.js b/ext/jquery.floatThead.js deleted file mode 100644 index 17ed5e8..0000000 --- a/ext/jquery.floatThead.js +++ /dev/null @@ -1,966 +0,0 @@ -// @preserve jQuery.floatThead 1.3.2 - http://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2015 Misha Koryak -// @license MIT - -/* @author Misha Koryak - * @projectDescription lock a table header in place while scrolling - without breaking styles or events bound to the header - * - * Dependencies: - * jquery 1.9.0 + [required] OR jquery 1.7.0 + jquery UI core - * - * http://mkoryak.github.io/floatThead/ - * - * Tested on FF13+, Chrome 21+, IE8, IE9, IE10, IE11 - * - */ -let jQuery = require('jQuery'); - -(function( $ ) { - /** - * provides a default config object. You can modify this after including this script if you want to change the init defaults - * @type {Object} - */ - $.floatThead = $.floatThead || {}; - $.floatThead.defaults = { - headerCellSelector: 'tr:visible:first>*:visible', //thead cells are this. - zIndex: 1001, //zindex of the floating thead (actually a container div) - position: 'auto', // 'fixed', 'absolute', 'auto'. auto picks the best for your table scrolling type. - top: 0, //String or function($table) - offset from top of window where the header should not pass above - bottom: 0, //String or function($table) - offset from the bottom of the table where the header should stop scrolling - scrollContainer: function($table){ - 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 than one col) - // it should return a jquery object containing a wrapped set of table cells comprising a row that contains no col spans and is visible - return $table.find('tbody tr:visible:first>*:visible'); - }, - floatTableClass: 'floatThead-table', - floatWrapperClass: 'floatThead-wrapper', - floatContainerClass: 'floatThead-container', - copyTableClass: true, //copy 'class' attribute from table into the floated table so that the styles match. - enableAria: false, //will copy header text from the floated header back into the table for screen readers. Might cause the css styling to be off. beware! - autoReflow: false, //(undocumented) - use MutationObserver api to reflow automatically when internal table DOM changes - debug: false //print possible issues (that don't prevent script loading) to console, if console exists. - }; - - var util = window._; - - var canObserveMutations = typeof MutationObserver !== 'undefined'; - - - //browser stuff - var ieVersion = function(){for(var a=3,b=document.createElement("b"),c=b.all||[];a = 1+a,b.innerHTML="<!--[if gt IE "+ a +"]><i><![endif]-->",c[0];);return 4<a?a:document.documentMode}(); - var isFF = /Gecko\//.test(navigator.userAgent); - var isWebkit = /WebKit\//.test(navigator.userAgent); - - //safari 7 (and perhaps others) reports table width to be parent container's width if max-width is set on table. see: https://github.com/mkoryak/floatThead/issues/108 - var isTableWidthBug = function(){ - if(isWebkit) { - var $test = $('<div style="width:0px"><table style="max-width:100%"><tr><th><div style="min-width:100px;">X</div></th></tr></table></div>'); - $("body").append($test); - var ret = ($test.find("table").width() == 0); - $test.remove(); - return ret; - } - return false; - }; - - var createElements = !isFF && !ieVersion; //FF can read width from <col> elements, but webkit cannot - - var $window = $(window); - - /** - * @param debounceMs - * @param cb - */ - function windowResize(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(); - } - }, 1); - $window.on(eventName, debouncedCb); - } else { - $window.on(eventName, util.debounce(cb, 1)); - } - } - - - function debug(str){ - window && window.console && window.console.error && window.console.error("jQuery.floatThead: " + str); - } - - //returns fractional pixel widths - function getOffsetWidth(el) { - var rect = el.getBoundingClientRect(); - return rect.width || rect.right - rect.left; - } - - /** - * try to calculate the scrollbar width for your browser/os - * @return {Number} - */ - function scrollbarWidth() { - var $div = $( //borrowed from anti-scroll - '<div style="width:50px;height:50px;overflow-y:scroll;' - + 'position:absolute;top:-200px;left:-200px;"><div style="height:100px;width:100%">' - + '</div>' - ); - $('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; - } - - function tableWidth($table, $fthCells, isOuter){ - // see: https://github.com/mkoryak/floatThead/issues/108 - var fn = isOuter ? "outerWidth": "width"; - if(isTableWidthBug && $table.css("max-width")){ - var w = 0; - if(isOuter) { - w += parseInt($table.css("borderLeft"), 10); - w += parseInt($table.css("borderRight"), 10); - } - for(var i=0; i < $fthCells.length; i++){ - w += $fthCells.get(i).offsetWidth; - } - return w; - } else { - return $table[fn](); - } - } - $.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."); - } - } - - if(ieVersion < 8){ - return this; //no more crappy browser support. - } - - var mObs = null; //mutation observer lives in here if we can use it / make it - - if(util.isFunction(isTableWidthBug)) { - isTableWidthBug = isTableWidthBug(); - } - - if(util.isString(map)){ - var command = map; - var ret = this; - this.filter('table').each(function(){ - var $this = $(this); - var opts = $this.data('floatThead-lazy'); - if(opts){ - $this.floatThead(opts); - } - var obj = $this.data('floatThead-attached'); - if(obj && util.isFunction(obj[command])){ - var r = obj[command](); - if(typeof r !== 'undefined'){ - ret = r; - } - } - }); - return ret; - } - var opts = $.extend({}, $.floatThead.defaults || {}, map); - - $.each(map, function(key, val){ - if((!(key in $.floatThead.defaults)) && opts.debug){ - debug("Used ["+key+"] key to init plugin, but that param is not an option for the plugin. Valid options are: "+ (util.keys($.floatThead.defaults)).join(', ')); - } - }); - if(opts.debug){ - var v = $.fn.jquery.split("."); - if(parseInt(v[0], 10) == 1 && parseInt(v[1], 10) <= 7){ - debug("jQuery version "+$.fn.jquery+" detected! This plugin supports 1.8 or better, or 1.7.x with jQuery UI 1.8.24 -> http://jqueryui.com/resources/download/jquery-ui-1.8.24.zip") - } - } - - this.filter(':not(.'+opts.floatTableClass+')').each(function(){ - var floatTheadId = util.uniqueId(); - 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();'); - } - canObserveMutations = opts.autoReflow && canObserveMutations; //option defaults to false! - var $header = $table.children('thead:first'); - var $tbody = $table.children('tbody:first'); - if($header.length == 0 || $tbody.length == 0){ - $table.data('floatThead-lazy', opts); - $table.unbind("reflow").one('reflow', function(){ - $table.floatThead(opts); - }); - return; - } - if($table.data('floatThead-lazy')){ - $table.unbind("reflow"); - } - $table.data('floatThead-lazy', false); - - var headerFloated = true; - 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 locked = $scrollContainer.length > 0; - - var useAbsolutePositioning = null; - if(typeof opts.useAbsolutePositioning !== 'undefined'){ - opts.position = 'auto'; - if(opts.useAbsolutePositioning){ - opts.position = opts.useAbsolutePositioning ? 'absolute' : 'fixed'; - } - debug("option 'useAbsolutePositioning' has been removed in v1.3.0, use `position:'"+opts.position+"'` instead. See docs for more info: http://mkoryak.github.io/floatThead/#options") - } - if(typeof opts.scrollingTop !== 'undefined'){ - opts.top = opts.scrollingTop; - debug("option 'scrollingTop' has been renamed to 'top' in v1.3.0. See docs for more info: http://mkoryak.github.io/floatThead/#options"); - } - if(typeof opts.scrollingBottom !== 'undefined'){ - opts.bottom = opts.scrollingBottom; - debug("option 'scrollingBottom' has been renamed to 'bottom' in v1.3.0. See docs for more info: http://mkoryak.github.io/floatThead/#options"); - } - - - if (opts.position == 'auto') { - useAbsolutePositioning = null; - } else if (opts.position == 'fixed') { - useAbsolutePositioning = false; - } else if (opts.position == 'absolute'){ - useAbsolutePositioning = true; - } else if (opts.debug) { - debug('Invalid value given to "position" option, valid is "fixed", "absolute" and "auto". You passed: ', opts.position); - } - - if(useAbsolutePositioning == null){ //defaults: locked=true, !locked=false - useAbsolutePositioning = locked; - } - 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 = $('<fthfoot style="display:table-footer-group;border-spacing:0;height:0;border-collapse:collapse;visibility:hidden"/>'); - - 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 doesn't look good with window scrolling, so we change position to fixed on scroll, and then change it back to absolute when done. - var $floatTable = $("<table/>"); - var $floatColGroup = $("<colgroup/>"); - var $tableColGroup = $table.children('colgroup:first'); - var existingColGroup = true; - if($tableColGroup.length == 0){ - $tableColGroup = $("<colgroup/>"); - existingColGroup = false; - } - var $fthRow = $('<fthtr style="display:table-row;border-spacing:0;height:0;border-collapse:collapse"/>'); //created unstyled elements (used for sizing the table because chrome can't read <col> width) - var $floatContainer = $('<div style="overflow: hidden;" aria-hidden="true"></div>'); - var floatTableHidden = false; //this happens when the table is hidden and we do magic when making it visible - var $newHeader = $("<thead/>"); - var $sizerRow = $('<tr class="size-row"/>'); - var $sizerCells = $([]); - var $tableCells = $([]); //used for sizing - either $sizerCells or $tableColGroup cols. $tableColGroup cols are only created in chrome for borderCollapse:collapse because of a chrome bug. - var $headerCells = $([]); - var $fthCells = $([]); //created elements - - $newHeader.append($sizerRow); - $table.prepend($tableColGroup); - if(createElements){ - $fthGrp.append($fthRow); - $table.append($fthGrp); - } - - $floatTable.append($floatColGroup); - $floatContainer.append($floatTable); - if(opts.copyTableClass){ - $floatTable.attr('class', $table.attr('class')); - } - $floatTable.attr({ //copy over some deprecated table attributes that people still like to use. Good thing people don't use colgroups... - 'cellpadding': $table.attr('cellpadding'), - 'cellspacing': $table.attr('cellspacing'), - 'border': $table.attr('border') - }); - var tableDisplayCss = $table.css('display'); - $floatTable.css({ - 'borderCollapse': $table.css('borderCollapse'), - 'border': $table.css('border'), - 'display': tableDisplayCss - }); - if(tableDisplayCss == 'none'){ - floatTableHidden = true; - } - - $floatTable.addClass(opts.floatTableClass).css({'margin': 0, 'border-bottom-width': 0}); //must have no margins or you won't be able to click on things under floating table - - if(useAbsolutePositioning){ - var makeRelative = function($container, alwaysWrap){ - var positionCss = $container.css('position'); - var relativeToScrollContainer = (positionCss == "relative" || positionCss == "absolute"); - var $containerWrap = $container; - if(!relativeToScrollContainer || alwaysWrap){ - var css = {"paddingLeft": $container.css('paddingLeft'), "paddingRight": $container.css('paddingRight')}; - $floatContainer.css(css); - $containerWrap = $container.data('floatThead-containerWrap') || $container.wrap("<div class='"+opts.floatWrapperClass+"' style='position: relative; clear:both;'></div>").parent(); - $container.data('floatThead-containerWrap', $containerWrap); //multiple tables inside one scrolling container - #242 - wrappedContainer = true; - } - return $containerWrap; - }; - if(locked){ - $wrapper = makeRelative($scrollContainer, true); - $wrapper.prepend($floatContainer); - } else { - $wrapper = makeRelative($table); - $table.before($floatContainer); - } - } else { - $table.before($floatContainer); - } - - - $floatContainer.css({ - position: useAbsolutePositioning ? 'absolute' : 'fixed', - marginTop: 0, - top: useAbsolutePositioning ? 0 : 'auto', - zIndex: opts.zIndex - }); - $floatContainer.addClass(opts.floatContainerClass); - updateScrollingOffsets(); - - var layoutFixed = {'table-layout': 'fixed'}; - var layoutAuto = {'table-layout': $table.css('tableLayout') || 'auto'}; - var originalTableWidth = $table[0].style.width || ""; //setting this to auto is bad: #70 - var originalTableMinWidth = $table.css('minWidth') || ""; - - function eventName(name){ - return name+'.fth-'+floatTheadId+'.floatTHead' - } - - function setHeaderHeight(){ - var headerHeight = 0; - $header.children("tr:visible").each(function(){ - headerHeight += $(this).outerHeight(true); - }); - if($table.css('border-collapse') == 'collapse') { - var tableBorderTopHeight = parseInt($table.css('border-top-width'), 10); - var cellBorderTopHeight = parseInt($table.find("thead tr:first").find(">*:first").css('border-top-width'), 10); - if(tableBorderTopHeight > cellBorderTopHeight) { - headerHeight -= (tableBorderTopHeight / 2); //id love to see some docs where this magic recipe is found.. - } - } - $sizerRow.outerHeight(headerHeight); - $sizerCells.outerHeight(headerHeight); - } - - - function setFloatWidth(){ - var tw = tableWidth($table, $fthCells, true); - var width = $scrollContainer.width() || tw; - var floatContainerWidth = $scrollContainer.css("overflow-y") != 'hidden' ? width - scrollbarOffset.vertical : width; - $floatContainer.width(floatContainerWidth); - if(locked){ - var percent = 100 * tw / (floatContainerWidth); - $floatTable.css('width', percent+'%'); - } else { - $floatTable.outerWidth(tw); - } - } - - function updateScrollingOffsets(){ - scrollingTop = (util.isFunction(opts.top) ? opts.top($table) : opts.top) || 0; - scrollingBottom = (util.isFunction(opts.bottom) ? opts.bottom($table) : opts.bottom) || 0; - } - - /** - * get the number of columns and also rebuild resizer rows if the count is different than the last count - */ - function columnNum(){ - var count; - var $headerColumns = $header.find(opts.headerCellSelector); - if(existingColGroup){ - count = $tableColGroup.find('col').length; - } else { - count = 0; - $headerColumns.each(function () { - count += parseInt(($(this).attr('colspan') || 1), 10); - }); - } - if(count != lastColumnCount){ - lastColumnCount = count; - var cells = [], cols = [], psuedo = [], content; - for(var x = 0; x < count; x++){ - if (opts.enableAria && (content = $headerColumns.eq(x).text()) ) { - cells.push('<th scope="col" class="floatThead-col">' + content + '</th>'); - } else { - cells.push('<th class="floatThead-col"/>'); - } - cols.push('<col/>'); - psuedo.push("<fthtd style='display:table-cell;height:0;width:auto;'/>"); - } - - cols = cols.join(''); - cells = cells.join(''); - - if(createElements){ - 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"); - - } - return count; - } - - function refloat(){ //make the thing float - if(!headerFloated){ - headerFloated = true; - if(useAbsolutePositioning){ //#53, #56 - var tw = tableWidth($table, $fthCells, true); - var wrapperWidth = $wrapper.width(); - if(tw > wrapperWidth){ - $table.css('minWidth', tw); - } - } - $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); - $table.css('minWidth', originalTableMinWidth); //this looks weird, but it's not a bug. Think about it!! - $table.css('minWidth', tableWidth($table, $fthCells)); //#121 - } - } - var isHeaderFloatingLogical = false; //for the purpose of this event, the header is/isnt floating, even though the element - //might be in some other state. this is what the header looks like to the user - function triggerFloatEvent(isFloating){ - if(isHeaderFloatingLogical != isFloating){ - isHeaderFloatingLogical = isFloating; - $table.triggerHandler("floatThead", [isFloating, $floatContainer]) - } - } - function changePositioning(isAbsolute){ - if(useAbsolutePositioning != isAbsolute){ - useAbsolutePositioning = isAbsolute; - $floatContainer.css({ - position: useAbsolutePositioning ? 'absolute' : 'fixed' - }); - } - } - function getSizingRow($table, $cols, $fthCells, ieVersion){ - if(createElements){ - 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 changed dynamically since last time (datatables), rebuild the sizer rows and get a new count - - return function(){ - $tableCells = $tableColGroup.find('col'); - 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', ''); - } - } - unfloat(); - var widths = []; - for(i=0; i < numCols; i++){ - widths[i] = getOffsetWidth($rowCells.get(i)); - } - for(i=0; i < numCols; i++){ - $headerCells.eq(i).width(widths[i]); - $tableCells.eq(i).width(widths[i]); - } - refloat(); - } else { - $floatTable.append($header); - $table.css(layoutAuto); - $floatTable.css(layoutAuto); - setHeaderHeight(); - } - $table.triggerHandler("reflowed", [$floatContainer]); - }; - } - - function floatContainerBorderWidth(side){ - var border = $scrollContainer.css("border-"+side+"-width"); - var w = 0; - if (border && ~border.indexOf('px')) { - w = parseInt(border, 10); - } - return w; - } - /** - * 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 doesn't 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(); - var tableLeftGap = 0; //can be caused by border on container (only in locked mode) - var tableTopGap = 0; - if(locked){ - var containerOffset = $scrollContainer.offset(); - tableContainerGap = tableOffset.top - containerOffset.top + scrollingContainerTop; - if(haveCaption && captionAlignTop){ - tableContainerGap += captionHeight; - } - tableLeftGap = floatContainerBorderWidth('left'); - tableTopGap = floatContainerBorderWidth('top'); - tableContainerGap -= tableTopGap; - } else { - floatEnd = tableOffset.top - scrollingTop - floatContainerHeight + scrollingBottom + scrollbarOffset.horizontal; - } - var windowTop = $window.scrollTop(); - var windowLeft = $window.scrollLeft(); - var scrollContainerLeft = $scrollContainer.scrollLeft(); - - return function(eventType){ - var isTableHidden = $table[0].offsetWidth <= 0 && $table[0].offsetHeight <= 0; - if(!isTableHidden && floatTableHidden) { - floatTableHidden = false; - setTimeout(function(){ - $table.triggerHandler("reflow"); - }, 1); - return null; - } - if(isTableHidden){ //it's hidden - floatTableHidden = true; - if(!useAbsolutePositioning){ - return null; - } - } - - 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(isWebkit && (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; - var tableHeight = $table.outerHeight(); - - if(locked && useAbsolutePositioning){ //inner scrolling, absolute positioning - if (tableContainerGap >= scrollingContainerTop) { - var gap = tableContainerGap - scrollingContainerTop + tableTopGap; - top = gap > 0 ? gap : 0; - triggerFloatEvent(false); - } else { - top = wrappedContainer ? tableTopGap : scrollingContainerTop; - //headers stop at the top of the viewport - triggerFloatEvent(true); - } - left = tableLeftGap; - } 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(); - triggerFloatEvent(false); - } else { - top = scrollingTop + windowTop - tableOffset.top + tableContainerGap + (captionAlignTop ? captionHeight : 0); - refloat(); //scrolling within table. header floated - triggerFloatEvent(true); - } - left = 0; - } else if(locked && !useAbsolutePositioning){ //inner scrolling, fixed positioning - if (tableContainerGap > scrollingContainerTop || scrollingContainerTop - tableContainerGap > tableHeight) { - top = tableOffset.top - windowTop; - unfloat(); - triggerFloatEvent(false); - } else { - top = tableOffset.top + scrollingContainerTop - windowTop - tableContainerGap; - refloat(); - triggerFloatEvent(true); - //headers stop at the top of the viewport - } - 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(); - triggerFloatEvent(false); //this is a weird case, the header never gets unfloated and i have no no way to know - //scrolled past the top of the table - } else { - //scrolling within the table - top = scrollingTop; - triggerFloatEvent(true); - } - 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(!useAbsolutePositioning || 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){ - if($scrollContainer.data().perfectScrollbar){ - scrollbarOffset = {horizontal:0, vertical:0}; - } else { - var sw = $scrollContainer.width(), sh = $scrollContainer.height(), th = $table.height(), tw = tableWidth($table, $fthCells); - 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); - }, 1); - - var windowScrollEvent = function(){ - repositionFloatContainer(calculateFloatContainerPos('windowScroll'), false); - if(absoluteToFixedOnScroll){ - windowScrollDoneEvent(); - } - }; - var containerScrollEvent = function(){ - repositionFloatContainer(calculateFloatContainerPos('containerScroll'), false); - }; - - - var windowResizeEvent = function(){ - if($table.is(":hidden")){ - return; - } - updateScrollingOffsets(); - calculateScrollBarSize(); - ensureReflow(); - calculateFloatContainerPos = calculateFloatContainerPosFn(); - repositionFloatContainer = repositionFloatContainerFn(); - repositionFloatContainer(calculateFloatContainerPos('resize'), true, true); - }; - var reflowEvent = util.debounce(function(){ - if($table.is(":hidden")){ - return; - } - 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(eventName('resize'), windowResizeEvent); - $table.on('reflow', reflowEvent); - if(isDatatable($table)){ - $table - .on('filter', reflowEvent) - .on('sort', reflowEvent) - .on('page', reflowEvent); - } - - $window.on(eventName('shown.bs.tab'), reflowEvent); // people cant seem to figure out how to use this plugin with bs3 tabs... so this :P - $window.on(eventName('tabsactivate'), reflowEvent); // same thing for jqueryui - - - if (canObserveMutations) { - var mutationElement = null; - if(util.isFunction(opts.autoReflow)){ - mutationElement = opts.autoReflow($table, $scrollContainer) - } - if(!mutationElement) { - mutationElement = $scrollContainer.length ? $scrollContainer[0] : $table[0] - } - mObs = new MutationObserver(function(e){ - var wasTableRelated = function(nodes){ - return nodes && nodes[0] && (nodes[0].nodeName == "THEAD" || nodes[0].nodeName == "TD"|| nodes[0].nodeName == "TH"); - }; - for(var i=0; i < e.length; i++){ - if(!(wasTableRelated(e[i].addedNodes) || wasTableRelated(e[i].removedNodes))){ - reflowEvent(); - break; - } - } - }); - mObs.observe(mutationElement, { - childList: true, - subtree: true - }); - } - - //attach some useful functions to the table. - $table.data('floatThead-attached', { - destroy: function(){ - var ns = '.fth-'+floatTheadId; - unfloat(); - $table.css(layoutAuto); - $tableColGroup.remove(); - createElements && $fthGrp.remove(); - if($newHeader.parent().length){ //only if it's in the DOM - $newHeader.replaceWith($header); - } - if(canObserveMutations){ - mObs.disconnect(); - mObs = null; - } - $table.off('reflow reflowed'); - $scrollContainer.off(ns); - if (wrappedContainer) { - if ($scrollContainer.length) { - $scrollContainer.unwrap(); - } - else { - $table.unwrap(); - } - } - if(locked){ - $scrollContainer.data('floatThead-containerWrap', false); - } else { - $table.data('floatThead-containerWrap', false); - } - $table.css('minWidth', originalTableMinWidth); - $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('>table>thead').add($table.children("tbody,tfoot")); - } else { - return $table.children("thead,tbody,tfoot"); - } - } - }); - }); - return this; - }; -})(jQuery); - -/* jQuery.floatThead.utils - http://mkoryak.github.io/floatThead/ - Copyright (c) 2012 - 2014 Misha Koryak - * 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. - * - * YOU DON'T NEED TO INCLUDE THIS IF YOU ALREADY INCLUDE UNDERSCORE! - * - */ - -(function($){ - - $.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; - }; - var idCounter = 0; - that.uniqueId = function(prefix) { - var id = ++idCounter + ''; - return prefix ? prefix + id : id; - }; - $.each(isThings, function(){ - var name = this; - that['is' + name] = function(obj) { - return Object.prototype.toString.call(obj) == '[object ' + name + ']'; - }; - }); - that.debounce = function(func, wait, immediate) { - var timeout, args, context, timestamp, result; - return function() { - context = this; - args = arguments; - timestamp = new Date(); - var later = function() { - var last = (new Date()) - timestamp; - if (last < wait) { - timeout = setTimeout(later, wait - last); - } else { - timeout = null; - if (!immediate) result = func.apply(context, args); - } - }; - var callNow = immediate && !timeout; - if (!timeout) { - timeout = setTimeout(later, wait); - } - if (callNow) result = func.apply(context, args); - return result; - }; - }; - return that; - })(); -})(jQuery); - diff --git a/ext/sortable-table.js b/ext/sortable-table.js deleted file mode 100644 index 5e91d8b..0000000 --- a/ext/sortable-table.js +++ /dev/null @@ -1,496 +0,0 @@ -/* - SortTable - version 2 - 7th April 2007 - Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ - - Instructions: - Download this file - Add <script src="sorttable.js"></script> to your HTML - Add class="sortable" to any table you'd like to make sortable - Click on the headers to sort - - Thanks to many, many people for contributions and suggestions. - Licenced as X11: http://www.kryogenix.org/code/browser/licence.html - This basically means: do what you want with it. -*/ - - -var stIsIE = /*@cc_on!@*/false; - -var sorttable = { - init: function() { - // quit if this function has already been called - if (arguments.callee.done) return; - // flag this function so we don't do the same thing twice - arguments.callee.done = true; - // kill the timer - if (_timer) clearInterval(_timer); - - if (!document.createElement || !document.getElementsByTagName) return; - - sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; - - forEach(document.getElementsByTagName('table'), function(table) { - if (table.className.search(/\bsortable\b/) != -1) { - sorttable.makeSortable(table); - } - }); - - }, - - makeSortable: function(table) { - if (table.getElementsByTagName('thead').length == 0) { - // table doesn't have a tHead. Since it should have, create one and - // put the first table row in it. - the = document.createElement('thead'); - the.appendChild(table.rows[0]); - table.insertBefore(the,table.firstChild); - } - // Safari doesn't support table.tHead, sigh - if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; - - if (table.tHead.rows.length != 1) return; // can't cope with two header rows - - // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as - // "total" rows, for example). This is B&R, since what you're supposed - // to do is put them in a tfoot. So, if there are sortbottom rows, - // for backwards compatibility, move them to tfoot (creating it if needed). - sortbottomrows = []; - for (var i=0; i<table.rows.length; i++) { - if (table.rows[i].className.search(/\bsortbottom\b/) != -1) { - sortbottomrows[sortbottomrows.length] = table.rows[i]; - } - } - if (sortbottomrows) { - if (table.tFoot == null) { - // table doesn't have a tfoot. Create one. - tfo = document.createElement('tfoot'); - table.appendChild(tfo); - } - for (var i=0; i<sortbottomrows.length; i++) { - tfo.appendChild(sortbottomrows[i]); - } - delete sortbottomrows; - } - - // work through each column and calculate its type - headrow = table.tHead.rows[0].cells; - for (var i=0; i<headrow.length; i++) { - // manually override the type with a sorttable_type attribute - if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col - mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/); - if (mtch) { override = mtch[1]; } - if (mtch && typeof sorttable["sort_"+override] == 'function') { - headrow[i].sorttable_sortfunction = sorttable["sort_"+override]; - } else { - headrow[i].sorttable_sortfunction = sorttable.guessType(table,i); - } - // make it clickable to sort - headrow[i].sorttable_columnindex = i; - headrow[i].sorttable_tbody = table.tBodies[0]; - dean_addEvent(headrow[i],"click", sorttable.innerSortFunction = function(e) { - - if (this.className.search(/\bsorttable_sorted\b/) != -1) { - // if we're already sorted by this column, just - // reverse the table, which is quicker - sorttable.reverse(this.sorttable_tbody); - this.className = this.className.replace('sorttable_sorted', - 'sorttable_sorted_reverse'); - this.removeChild(document.getElementById('sorttable_sortfwdind')); - sortrevind = document.createElement('span'); - sortrevind.id = "sorttable_sortrevind"; - sortrevind.innerHTML = stIsIE ? ' <font face="webdings">5</font>' : ' ▴'; - this.appendChild(sortrevind); - return; - } - if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { - // if we're already sorted by this column in reverse, just - // re-reverse the table, which is quicker - sorttable.reverse(this.sorttable_tbody); - this.className = this.className.replace('sorttable_sorted_reverse', - 'sorttable_sorted'); - this.removeChild(document.getElementById('sorttable_sortrevind')); - sortfwdind = document.createElement('span'); - sortfwdind.id = "sorttable_sortfwdind"; - sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; - this.appendChild(sortfwdind); - return; - } - - // remove sorttable_sorted classes - theadrow = this.parentNode; - forEach(theadrow.childNodes, function(cell) { - if (cell.nodeType == 1) { // an element - cell.className = cell.className.replace('sorttable_sorted_reverse',''); - cell.className = cell.className.replace('sorttable_sorted',''); - } - }); - sortfwdind = document.getElementById('sorttable_sortfwdind'); - if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } - sortrevind = document.getElementById('sorttable_sortrevind'); - if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } - - this.className += ' sorttable_sorted'; - sortfwdind = document.createElement('span'); - sortfwdind.id = "sorttable_sortfwdind"; - sortfwdind.innerHTML = stIsIE ? ' <font face="webdings">6</font>' : ' ▾'; - this.appendChild(sortfwdind); - - // build an array to sort. This is a Schwartzian transform thing, - // i.e., we "decorate" each row with the actual sort key, - // sort based on the sort keys, and then put the rows back in order - // which is a lot faster because you only do getInnerText once per row - row_array = []; - col = this.sorttable_columnindex; - rows = this.sorttable_tbody.rows; - for (var j=0; j<rows.length; j++) { - row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]]; - } - /* If you want a stable sort, uncomment the following line */ - //sorttable.shaker_sort(row_array, this.sorttable_sortfunction); - /* and comment out this one */ - row_array.sort(this.sorttable_sortfunction); - - tb = this.sorttable_tbody; - for (var j=0; j<row_array.length; j++) { - tb.appendChild(row_array[j][1]); - } - - delete row_array; - }); - } - } - }, - - guessType: function(table, column) { - // guess the type of a column based on its first non-blank row - sortfn = sorttable.sort_alpha; - for (var i=0; i<table.tBodies[0].rows.length; i++) { - text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]); - if (text != '') { - if (text.match(/^-?[£$¤]?[\d,.]+%?$/)) { - return sorttable.sort_numeric; - } - // check for a date: dd/mm/yyyy or dd/mm/yy - // can have / or . or - as separator - // can be mm/dd as well - possdate = text.match(sorttable.DATE_RE) - if (possdate) { - // looks like a date - first = parseInt(possdate[1]); - second = parseInt(possdate[2]); - if (first > 12) { - // definitely dd/mm - return sorttable.sort_ddmm; - } else if (second > 12) { - return sorttable.sort_mmdd; - } else { - // looks like a date, but we can't tell which, so assume - // that it's dd/mm (English imperialism!) and keep looking - sortfn = sorttable.sort_ddmm; - } - } - } - } - return sortfn; - }, - - getInnerText: function(node) { - // gets the text we want to use for sorting for a cell. - // strips leading and trailing whitespace. - // this is *not* a generic getInnerText function; it's special to sorttable. - // for example, you can override the cell text with a customkey attribute. - // it also gets .value for <input> fields. - - if (!node) return ""; - - hasInputs = (typeof node.getElementsByTagName == 'function') && - node.getElementsByTagName('input').length; - - if (node.getAttribute("sorttable_customkey") != null) { - return node.getAttribute("sorttable_customkey"); - } - else if (typeof node.textContent != 'undefined' && !hasInputs) { - return node.textContent.replace(/^\s+|\s+$/g, ''); - } - else if (typeof node.innerText != 'undefined' && !hasInputs) { - return node.innerText.replace(/^\s+|\s+$/g, ''); - } - else if (typeof node.text != 'undefined' && !hasInputs) { - return node.text.replace(/^\s+|\s+$/g, ''); - } - else { - switch (node.nodeType) { - case 3: - if (node.nodeName.toLowerCase() == 'input') { - return node.value.replace(/^\s+|\s+$/g, ''); - } - case 4: - return node.nodeValue.replace(/^\s+|\s+$/g, ''); - break; - case 1: - case 11: - var innerText = ''; - for (var i = 0; i < node.childNodes.length; i++) { - innerText += sorttable.getInnerText(node.childNodes[i]); - } - return innerText.replace(/^\s+|\s+$/g, ''); - break; - default: - return ''; - } - } - }, - - reverse: function(tbody) { - // reverse the rows in a tbody - newrows = []; - for (var i=0; i<tbody.rows.length; i++) { - newrows[newrows.length] = tbody.rows[i]; - } - for (var i=newrows.length-1; i>=0; i--) { - tbody.appendChild(newrows[i]); - } - delete newrows; - }, - - /* sort functions - each sort function takes two parameters, a and b - you are comparing a[0] and b[0] */ - sort_numeric: function(a,b) { - aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); - if (isNaN(aa)) aa = 0; - bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); - if (isNaN(bb)) bb = 0; - return aa-bb; - }, - sort_alpha: function(a,b) { - if (a[0]==b[0]) return 0; - if (a[0]<b[0]) return -1; - return 1; - }, - sort_ddmm: function(a,b) { - mtch = a[0].match(sorttable.DATE_RE); - y = mtch[3]; m = mtch[2]; d = mtch[1]; - if (m.length == 1) m = '0'+m; - if (d.length == 1) d = '0'+d; - dt1 = y+m+d; - mtch = b[0].match(sorttable.DATE_RE); - y = mtch[3]; m = mtch[2]; d = mtch[1]; - if (m.length == 1) m = '0'+m; - if (d.length == 1) d = '0'+d; - dt2 = y+m+d; - if (dt1==dt2) return 0; - if (dt1<dt2) return -1; - return 1; - }, - sort_mmdd: function(a,b) { - mtch = a[0].match(sorttable.DATE_RE); - y = mtch[3]; d = mtch[2]; m = mtch[1]; - if (m.length == 1) m = '0'+m; - if (d.length == 1) d = '0'+d; - dt1 = y+m+d; - mtch = b[0].match(sorttable.DATE_RE); - y = mtch[3]; d = mtch[2]; m = mtch[1]; - if (m.length == 1) m = '0'+m; - if (d.length == 1) d = '0'+d; - dt2 = y+m+d; - if (dt1==dt2) return 0; - if (dt1<dt2) return -1; - return 1; - }, - - shaker_sort: function(list, comp_func) { - // A stable sort function to allow multi-level sorting of data - // see: http://en.wikipedia.org/wiki/Cocktail_sort - // thanks to Joseph Nahmias - var b = 0; - var t = list.length - 1; - var swap = true; - - while(swap) { - swap = false; - for(var i = b; i < t; ++i) { - if ( comp_func(list[i], list[i+1]) > 0 ) { - var q = list[i]; list[i] = list[i+1]; list[i+1] = q; - swap = true; - } - } // for - t--; - - if (!swap) break; - - for(var i = t; i > b; --i) { - if ( comp_func(list[i], list[i-1]) < 0 ) { - var q = list[i]; list[i] = list[i-1]; list[i-1] = q; - swap = true; - } - } // for - b++; - - } // while(swap) - } -} - -/* ****************************************************************** - Supporting functions: bundled here to avoid depending on a library - ****************************************************************** */ - -// Dean Edwards/Matthias Miller/John Resig - -/* for Mozilla/Opera9 */ -if (document.addEventListener) { - document.addEventListener("DOMContentLoaded", sorttable.init, false); -} - -/* for Internet Explorer */ -/*@cc_on @*/ -/*@if (@_win32) - document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>"); - var script = document.getElementById("__ie_onload"); - script.onreadystatechange = function() { - if (this.readyState == "complete") { - sorttable.init(); // call the onload handler - } - }; -/*@end @*/ - -/* for Safari */ -if (/WebKit/i.test(navigator.userAgent)) { // sniff - var _timer = setInterval(function() { - if (/loaded|complete/.test(document.readyState)) { - sorttable.init(); // call the onload handler - } - }, 10); -} - -/* for other browsers */ -window.onload = sorttable.init; - -// written by Dean Edwards, 2005 -// with input from Tino Zijdel, Matthias Miller, Diego Perini - -// http://dean.edwards.name/weblog/2005/10/add-event/ - -function dean_addEvent(element, type, handler) { - if (element.addEventListener) { - element.addEventListener(type, handler, false); - } else { - // assign each event handler a unique ID - if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++; - // create a hash table of event types for the element - if (!element.events) element.events = {}; - // create a hash table of event handlers for each element/event pair - var handlers = element.events[type]; - if (!handlers) { - handlers = element.events[type] = {}; - // store the existing event handler (if there is one) - if (element["on" + type]) { - handlers[0] = element["on" + type]; - } - } - // store the event handler in the hash table - handlers[handler.$$guid] = handler; - // assign a global event handler to do all the work - element["on" + type] = handleEvent; - } -}; -// a counter used to create unique IDs -dean_addEvent.guid = 1; - -function removeEvent(element, type, handler) { - if (element.removeEventListener) { - element.removeEventListener(type, handler, false); - } else { - // delete the event handler from the hash table - if (element.events && element.events[type]) { - delete element.events[type][handler.$$guid]; - } - } -}; - -function handleEvent(event) { - var returnValue = true; - // grab the event object (IE uses a global event object) - event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event); - // get a reference to the hash table of event handlers - var handlers = this.events[event.type]; - // execute each event handler - for (var i in handlers) { - this.$$handleEvent = handlers[i]; - if (this.$$handleEvent(event) === false) { - returnValue = false; - } - } - return returnValue; -}; - -function fixEvent(event) { - // add W3C standard event methods - event.preventDefault = fixEvent.preventDefault; - event.stopPropagation = fixEvent.stopPropagation; - return event; -}; -fixEvent.preventDefault = function() { - this.returnValue = false; -}; -fixEvent.stopPropagation = function() { - this.cancelBubble = true; -} - -// Dean's forEach: http://dean.edwards.name/base/forEach.js -/* - forEach, version 1.0 - Copyright 2006, Dean Edwards - License: http://www.opensource.org/licenses/mit-license.php -*/ - -// array-like enumeration -if (!Array.forEach) { // mozilla already supports this - Array.forEach = function(array, block, context) { - for (var i = 0; i < array.length; i++) { - block.call(context, array[i], i, array); - } - }; -} - -// generic enumeration -Function.prototype.forEach = function(object, block, context) { - for (var key in object) { - if (typeof this.prototype[key] == "undefined") { - block.call(context, object[key], key, object); - } - } -}; - -// character enumeration -String.forEach = function(string, block, context) { - Array.forEach(string.split(""), function(chr, index) { - block.call(context, chr, index, string); - }); -}; - -// globally resolve forEach enumeration -var forEach = function(object, block, context) { - if (object) { - var resolve = Object; // default - if (object instanceof Function) { - // functions have a "length" property - resolve = Function; - } else if (object.forEach instanceof Function) { - // the object implements a custom forEach method so use that - object.forEach(block, context); - return; - } else if (typeof object == "string") { - // the object is a string - resolve = String; - } else if (typeof object.length == "number") { - // the object is array-like - resolve = Array; - } - resolve.forEach(object, block, context); - } -}; - - diff --git a/package.json b/package.json index a82af1e..e3d4a67 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "babel-preset-es2015": "^6.6.0", "chai": "^3.5.0", "expect": "^1.20.1", - "floatthead": "^1.4.0", "jasmine": "^2.4.1", "jasmine-core": "^2.4.1", "karma": "^0.13.22", @@ -50,6 +49,7 @@ "babelify": "^7.3.0", "browserify": "^13.0.1", "es6-mixins": "^1.0.2", + "floatthead": "^1.4.0", "glob": "^7.0.3", "gulp": "^3.9.1", "gulp-babel": "^6.1.2", -- GitLab