1/** 2 * Copyright Marc J. Schmidt. See the LICENSE file at the top-level 3 * directory of this distribution and at 4 * https://github.com/marcj/css-element-queries/blob/master/LICENSE. 5 */ 6; 7(function (root, factory) { 8 if (typeof define === "function" && define.amd) { 9 define(factory); 10 } else if (typeof exports === "object") { 11 module.exports = factory(); 12 } else { 13 root.ResizeSensor = factory(); 14 } 15}(this, function () { 16 17 // Make sure it does not throw in a SSR (Server Side Rendering) situation 18 if (typeof window === "undefined") { 19 return null; 20 } 21 // Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor. 22 // In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and 23 // would generate too many unnecessary events. 24 var requestAnimationFrame = window.requestAnimationFrame || 25 window.mozRequestAnimationFrame || 26 window.webkitRequestAnimationFrame || 27 function (fn) { 28 return window.setTimeout(fn, 20); 29 }; 30 31 /** 32 * Iterate over each of the provided element(s). 33 * 34 * @param {HTMLElement|HTMLElement[]} elements 35 * @param {Function} callback 36 */ 37 function forEachElement(elements, callback){ 38 var elementsType = Object.prototype.toString.call(elements); 39 var isCollectionTyped = ('[object Array]' === elementsType 40 || ('[object NodeList]' === elementsType) 41 || ('[object HTMLCollection]' === elementsType) 42 || ('[object Object]' === elementsType) 43 || ('undefined' !== typeof jQuery && elements instanceof jQuery) //jquery 44 || ('undefined' !== typeof Elements && elements instanceof Elements) //mootools 45 ); 46 var i = 0, j = elements.length; 47 if (isCollectionTyped) { 48 for (; i < j; i++) { 49 callback(elements[i]); 50 } 51 } else { 52 callback(elements); 53 } 54 } 55 56 /** 57 * Class for dimension change detection. 58 * 59 * @param {Element|Element[]|Elements|jQuery} element 60 * @param {Function} callback 61 * 62 * @constructor 63 */ 64 var ResizeSensor = function(element, callback) { 65 /** 66 * 67 * @constructor 68 */ 69 function EventQueue() { 70 var q = []; 71 this.add = function(ev) { 72 q.push(ev); 73 }; 74 75 var i, j; 76 this.call = function() { 77 for (i = 0, j = q.length; i < j; i++) { 78 q[i].call(); 79 } 80 }; 81 82 this.remove = function(ev) { 83 var newQueue = []; 84 for(i = 0, j = q.length; i < j; i++) { 85 if(q[i] !== ev) newQueue.push(q[i]); 86 } 87 q = newQueue; 88 } 89 90 this.length = function() { 91 return q.length; 92 } 93 } 94 95 /** 96 * @param {HTMLElement} element 97 * @param {String} prop 98 * @returns {String|Number} 99 */ 100 function getComputedStyle(element, prop) { 101 if (element.currentStyle) { 102 return element.currentStyle[prop]; 103 } 104 if (window.getComputedStyle) { 105 return window.getComputedStyle(element, null).getPropertyValue(prop); 106 } 107 108 return element.style[prop]; 109 } 110 111 /** 112 * 113 * @param {HTMLElement} element 114 * @param {Function} resized 115 */ 116 function attachResizeEvent(element, resized) { 117 if (element.resizedAttached) { 118 element.resizedAttached.add(resized); 119 return; 120 } 121 122 element.resizedAttached = new EventQueue(); 123 element.resizedAttached.add(resized); 124 125 element.resizeSensor = document.createElement('div'); 126 element.resizeSensor.className = 'resize-sensor'; 127 var style = 'position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: -1; visibility: hidden;'; 128 var styleChild = 'position: absolute; left: 0; top: 0; transition: 0s;'; 129 130 element.resizeSensor.style.cssText = style; 131 element.resizeSensor.innerHTML = 132 '<div class="resize-sensor-expand" style="' + style + '">' + 133 '<div style="' + styleChild + '"></div>' + 134 '</div>' + 135 '<div class="resize-sensor-shrink" style="' + style + '">' + 136 '<div style="' + styleChild + ' width: 200%; height: 200%"></div>' + 137 '</div>'; 138 element.appendChild(element.resizeSensor); 139 140 if (getComputedStyle(element, 'position') == 'static') { 141 element.style.position = 'relative'; 142 } 143 144 var expand = element.resizeSensor.childNodes[0]; 145 var expandChild = expand.childNodes[0]; 146 var shrink = element.resizeSensor.childNodes[1]; 147 var dirty, rafId, newWidth, newHeight; 148 var lastWidth = element.offsetWidth; 149 var lastHeight = element.offsetHeight; 150 151 var reset = function() { 152 expandChild.style.width = '100000px'; 153 expandChild.style.height = '100000px'; 154 155 expand.scrollLeft = 100000; 156 expand.scrollTop = 100000; 157 158 shrink.scrollLeft = 100000; 159 shrink.scrollTop = 100000; 160 }; 161 162 reset(); 163 164 var onResized = function() { 165 rafId = 0; 166 167 if (!dirty) return; 168 169 lastWidth = newWidth; 170 lastHeight = newHeight; 171 172 if (element.resizedAttached) { 173 element.resizedAttached.call(); 174 } 175 }; 176 177 var onScroll = function() { 178 newWidth = element.offsetWidth; 179 newHeight = element.offsetHeight; 180 dirty = newWidth != lastWidth || newHeight != lastHeight; 181
182 if (dirty && !rafId) { 183 rafId = requestAnimationFrame(onResized); 184 } 185 186 reset(); 187 }; 188 189 var addEvent = function(el, name, cb) { 190 if (el.attachEvent) { 191 el.attachEvent('on' + name, cb); 192 } else { 193 el.addEventListener(name, cb); 194 } 195 }; 196 197 addEvent(expand, 'scroll', onScroll); 198 addEvent(shrink, 'scroll', onScroll); 199 } 200 201 forEachElement(element, function(elem){ 202 attachResizeEvent(elem, callback); 203 }); 204 205 this.detach = function(ev) { 206 ResizeSensor.detach(element, ev); 207 }; 208 }; 209 210 ResizeSensor.detach = function(element, ev) { 211 forEachElement(element, function(elem){ 212 if(elem.resizedAttached && typeof ev == "function"){ 213 elem.resizedAttached.remove(ev); 214 if(elem.resizedAttached.length()) return; 215 } 216 if (elem.resizeSensor) { 217 if (elem.contains(elem.resizeSensor)) { 218 elem.removeChild(elem.resizeSensor); 219 } 220 delete elem.resizeSensor; 221 delete elem.resizedAttached; 222 } 223 }); 224 }; 225 226 return ResizeSensor; 227 228}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.