Permalink
… cause js error (#291) Co-authored-by: akelley <achara.kelley@verizonmedia.com>
executable file
373 lines (322 sloc)
12.3 KB
| 'use strict'; | |
| /** | |
| * Copyright Marc J. Schmidt. See the LICENSE file at the top-level | |
| * directory of this distribution and at | |
| * https://github.com/marcj/css-element-queries/blob/master/LICENSE. | |
| */ | |
| (function (root, factory) { | |
| if (typeof define === "function" && define.amd) { | |
| define(factory); | |
| } else if (typeof exports === "object") { | |
| module.exports = factory(); | |
| } else { | |
| root.ResizeSensor = factory(); | |
| } | |
| }(typeof window !== 'undefined' ? window : this, function () { | |
| // Make sure it does not throw in a SSR (Server Side Rendering) situation | |
| if (typeof window === "undefined") { | |
| return null; | |
| } | |
| // https://github.com/Semantic-Org/Semantic-UI/issues/3855 | |
| // https://github.com/marcj/css-element-queries/issues/257 | |
| var globalWindow = typeof window != 'undefined' && window.Math == Math | |
| ? window | |
| : typeof self != 'undefined' && self.Math == Math | |
| ? self | |
| : Function('return this')(); | |
| // Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor. | |
| // In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and | |
| // would generate too many unnecessary events. | |
| var requestAnimationFrame = globalWindow.requestAnimationFrame || | |
| globalWindow.mozRequestAnimationFrame || | |
| globalWindow.webkitRequestAnimationFrame || | |
| function (fn) { | |
| return globalWindow.setTimeout(fn, 20); | |
| }; | |
| var cancelAnimationFrame = globalWindow.cancelAnimationFrame || | |
| globalWindow.mozCancelAnimationFrame || | |
| globalWindow.webkitCancelAnimationFrame || | |
| function (timer) { | |
| globalWindow.clearTimeout(timer); | |
| }; | |
| /** | |
| * Iterate over each of the provided element(s). | |
| * | |
| * @param {HTMLElement|HTMLElement[]} elements | |
| * @param {Function} callback | |
| */ | |
| function forEachElement(elements, callback){ | |
| var elementsType = Object.prototype.toString.call(elements); | |
| var isCollectionTyped = ('[object Array]' === elementsType | |
| || ('[object NodeList]' === elementsType) | |
| || ('[object HTMLCollection]' === elementsType) | |
| || ('[object Object]' === elementsType) | |
| || ('undefined' !== typeof jQuery && elements instanceof jQuery) //jquery | |
| || ('undefined' !== typeof Elements && elements instanceof Elements) //mootools | |
| ); | |
| var i = 0, j = elements.length; | |
| if (isCollectionTyped) { | |
| for (; i < j; i++) { | |
| callback(elements[i]); | |
| } | |
| } else { | |
| callback(elements); | |
| } | |
| } | |
| /** | |
| * Get element size | |
| * @param {HTMLElement} element | |
| * @returns {Object} {width, height} | |
| */ | |
| function getElementSize(element) { | |
| if (!element.getBoundingClientRect) { | |
| return { | |
| width: element.offsetWidth, | |
| height: element.offsetHeight | |
| } | |
| } | |
| var rect = element.getBoundingClientRect(); | |
| return { | |
| width: Math.round(rect.width), | |
| height: Math.round(rect.height) | |
| } | |
| } | |
| /** | |
| * Apply CSS styles to element. | |
| * | |
| * @param {HTMLElement} element | |
| * @param {Object} style | |
| */ | |
| function setStyle(element, style) { | |
| Object.keys(style).forEach(function(key) { | |
| element.style[key] = style[key]; | |
| }); | |
| } | |
| /** | |
| * Class for dimension change detection. | |
| * | |
| * @param {Element|Element[]|Elements|jQuery} element | |
| * @param {Function} callback | |
| * | |
| * @constructor | |
| */ | |
| var ResizeSensor = function(element, callback) { | |
| //Is used when checking in reset() only for invisible elements | |
| var lastAnimationFrameForInvisibleCheck = 0; | |
| /** | |
| * | |
| * @constructor | |
| */ | |
| function EventQueue() { | |
| var q = []; | |
| this.add = function(ev) { | |
| q.push(ev); | |
| }; | |
| var i, j; | |
| this.call = function(sizeInfo) { | |
| for (i = 0, j = q.length; i < j; i++) { | |
| q[i].call(this, sizeInfo); | |
| } | |
| }; | |
| this.remove = function(ev) { | |
| var newQueue = []; | |
| for(i = 0, j = q.length; i < j; i++) { | |
| if(q[i] !== ev) newQueue.push(q[i]); | |
| } | |
| q = newQueue; | |
| }; | |
| this.length = function() { | |
| return q.length; | |
| } | |
| } | |
| /** | |
| * | |
| * @param {HTMLElement} element | |
| * @param {Function} resized | |
| */ | |
| function attachResizeEvent(element, resized) { | |
| if (!element) return; | |
| if (element.resizedAttached) { | |
| element.resizedAttached.add(resized); | |
| return; | |
| } | |
| element.resizedAttached = new EventQueue(); | |
| element.resizedAttached.add(resized); | |
| element.resizeSensor = document.createElement('div'); | |
| element.resizeSensor.dir = 'ltr'; | |
| element.resizeSensor.className = 'resize-sensor'; | |
| var style = { | |
| pointerEvents: 'none', | |
| position: 'absolute', | |
| left: '0px', | |
| top: '0px', | |
| right: '0px', | |
| bottom: '0px', | |
| overflow: 'hidden', | |
| zIndex: '-1', | |
| visibility: 'hidden', | |
| maxWidth: '100%' | |
| }; | |
| var styleChild = { | |
| position: 'absolute', | |
| left: '0px', | |
| top: '0px', | |
| transition: '0s', | |
| }; | |
| setStyle(element.resizeSensor, style); | |
| var expand = document.createElement('div'); | |
| expand.className = 'resize-sensor-expand'; | |
| setStyle(expand, style); | |
| var expandChild = document.createElement('div'); | |
| setStyle(expandChild, styleChild); | |
| expand.appendChild(expandChild); | |
| var shrink = document.createElement('div'); | |
| shrink.className = 'resize-sensor-shrink'; | |
| setStyle(shrink, style); | |
| var shrinkChild = document.createElement('div'); | |
| setStyle(shrinkChild, styleChild); | |
| setStyle(shrinkChild, { width: '200%', height: '200%' }); | |
| shrink.appendChild(shrinkChild); | |
| element.resizeSensor.appendChild(expand); | |
| element.resizeSensor.appendChild(shrink); | |
| element.appendChild(element.resizeSensor); | |
| var computedStyle = window.getComputedStyle(element); | |
| var position = computedStyle ? computedStyle.getPropertyValue('position') : null; | |
| if ('absolute' !== position && 'relative' !== position && 'fixed' !== position && 'sticky' !== position) { | |
| element.style.position = 'relative'; | |
| } | |
| var dirty = false; | |
| //last request animation frame id used in onscroll event | |
| var rafId = 0; | |
| var size = getElementSize(element); | |
| var lastWidth = 0; | |
| var lastHeight = 0; | |
| var initialHiddenCheck = true; | |
| lastAnimationFrameForInvisibleCheck = 0; | |
| var resetExpandShrink = function () { | |
| var width = element.offsetWidth; | |
| var height = element.offsetHeight; | |
| expandChild.style.width = (width + 10) + 'px'; | |
| expandChild.style.height = (height + 10) + 'px'; | |
| expand.scrollLeft = width + 10; | |
| expand.scrollTop = height + 10; | |
| shrink.scrollLeft = width + 10; | |
| shrink.scrollTop = height + 10; | |
| }; | |
| var reset = function() { | |
| // Check if element is hidden | |
| if (initialHiddenCheck) { | |
| var invisible = element.offsetWidth === 0 && element.offsetHeight === 0; | |
| if (invisible) { | |
| // Check in next frame | |
| if (!lastAnimationFrameForInvisibleCheck){ | |
| lastAnimationFrameForInvisibleCheck = requestAnimationFrame(function(){ | |
| lastAnimationFrameForInvisibleCheck = 0; | |
| reset(); | |
| }); | |
| } | |
| return; | |
| } else { | |
| // Stop checking | |
| initialHiddenCheck = false; | |
| } | |
| } | |
| resetExpandShrink(); | |
| }; | |
| element.resizeSensor.resetSensor = reset; | |
| var onResized = function() { | |
| rafId = 0; | |
| if (!dirty) return; | |
| lastWidth = size.width; | |
| lastHeight = size.height; | |
| if (element.resizedAttached) { | |
| element.resizedAttached.call(size); | |
| } | |
| }; | |
| var onScroll = function() { | |
| size = getElementSize(element); | |
| dirty = size.width !== lastWidth || size.height !== lastHeight; | |
| if (dirty && !rafId) { | |
| rafId = requestAnimationFrame(onResized); | |
| } | |
| reset(); | |
| }; | |
| var addEvent = function(el, name, cb) { | |
| if (el.attachEvent) { | |
| el.attachEvent('on' + name, cb); | |
| } else { | |
| el.addEventListener(name, cb); | |
| } | |
| }; | |
| addEvent(expand, 'scroll', onScroll); | |
| addEvent(shrink, 'scroll', onScroll); | |
| // Fix for custom Elements and invisible elements | |
| lastAnimationFrameForInvisibleCheck = requestAnimationFrame(function(){ | |
| lastAnimationFrameForInvisibleCheck = 0; | |
| reset(); | |
| }); | |
| } | |
| forEachElement(element, function(elem){ | |
| attachResizeEvent(elem, callback); | |
| }); | |
| this.detach = function(ev) { | |
| // clean up the unfinished animation frame to prevent a potential endless requestAnimationFrame of reset | |
| if (lastAnimationFrameForInvisibleCheck) { | |
| cancelAnimationFrame(lastAnimationFrameForInvisibleCheck); | |
| lastAnimationFrameForInvisibleCheck = 0; | |
| } | |
| ResizeSensor.detach(element, ev); | |
| }; | |
| this.reset = function() { | |
| //To prevent invoking element.resizeSensor.resetSensor if it's undefined | |
| if (element.resizeSensor.resetSensor) { | |
| element.resizeSensor.resetSensor(); | |
| } | |
| }; | |
| }; | |
| ResizeSensor.reset = function(element) { | |
| forEachElement(element, function(elem){ | |
| //To prevent invoking element.resizeSensor.resetSensor if it's undefined | |
| if (element.resizeSensor.resetSensor) { | |
| elem.resizeSensor.resetSensor(); | |
| } | |
| }); | |
| }; | |
| ResizeSensor.detach = function(element, ev) { | |
| forEachElement(element, function(elem){ | |
| if (!elem) return; | |
| if(elem.resizedAttached && typeof ev === "function"){ | |
| elem.resizedAttached.remove(ev); | |
| if(elem.resizedAttached.length()) return; | |
| } | |
| if (elem.resizeSensor) { | |
| if (elem.contains(elem.resizeSensor)) { | |
| elem.removeChild(elem.resizeSensor); | |
| } | |
| delete elem.resizeSensor; | |
| delete elem.resizedAttached; | |
| } | |
| }); | |
| }; | |
| if (typeof MutationObserver !== "undefined") { | |
| var observer = new MutationObserver(function (mutations) { | |
| for (var i in mutations) { | |
| if (mutations.hasOwnProperty(i)) { | |
| var items = mutations[i].addedNodes; | |
| for (var j = 0; j < items.length; j++) { | |
| if (items[j].resizeSensor) { | |
| ResizeSensor.reset(items[j]); | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| document.addEventListener("DOMContentLoaded", function (event) { | |
| observer.observe(document.body, { | |
| childList: true, | |
| subtree: true, | |
| }); | |
| }); | |
| } | |
| return ResizeSensor; | |
| })); |