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( function ( root, factory ) { 7 if ( typeof define === 'function' && define.amd ) { 8 define( factory ); 9 } else if ( typeof exports === 'object' ) { 10 module.exports = factory(); 11 } else { 12 root.ResizeSensor = factory(); 13 } 14} )( typeof window !== 'undefined' ? window : this, function () { 15 // Make sure it does not throw in a SSR (Server Side Rendering) situation 16 if ( typeof window === 'undefined' ) { 17 return null; 18 } 19 // https://github.com/Semantic-Org/Semantic-UI/issues/3855 20 // https://github.com/marcj/css-element-queries/issues/257 21 var globalWindow = 22 typeof window !== 'undefined' && window.Math === Math 23 ? window 24 : typeof self !== 'undefined' && self.Math === Math 25 ? self 26 : Function( 'return this' )(); 27 // Only used for the dirty checking, so the event callback count is limited to max 1 call per fps per sensor. 28 // In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and 29 // would generate too many unnecessary events. 30 var requestAnimationFrame = 31 globalWindow.requestAnimationFrame || 32 globalWindow.mozRequestAnimationFrame || 33 globalWindow.webkitRequestAnimationFrame || 34 function ( fn ) { 35 return globalWindow.setTimeout( fn, 20 ); 36 }; 37 38 var cancelAnimationFrame = 39 globalWindow.cancelAnimationFrame || 40 globalWindow.mozCancelAnimationFrame || 41 globalWindow.webkitCancelAnimationFrame || 42 function ( timer ) { 43 globalWindow.clearTimeout( timer ); 44 }; 45 46 /** 47 * Iterate over each of the provided element(s). 48 * 49 * @param {HTMLElement|HTMLElement[]} elements 50 * @param {Function} callback 51 */ 52 function forEachElement( elements, callback ) { 53 var elementsType = Object.prototype.toString.call( elements ); 54 var isCollectionTyped = 55 '[object Array]' === elementsType || 56 '[object NodeList]' === elementsType || 57 '[object HTMLCollection]' === elementsType || 58 '[object Object]' === elementsType || 59 ( 'undefined' !== typeof jQuery && elements instanceof jQuery ) || 60 ( 'undefined' !== typeof Elements && elements instanceof Elements ); 61 var i = 0, 62 j = elements.length; 63 if ( isCollectionTyped ) { 64 for ( ; i < j; i++ ) { 65 callback( elements[ i ] ); 66 } 67 } else { 68 callback( elements ); 69 } 70 } 71 72 /** 73 * Get element size 74 * @param {HTMLElement} element 75 * @returns {Object} {width, height} 76 */ 77 function getElementSize( element ) { 78 if ( ! element.getBoundingClientRect ) { 79 return { 80 width: element.offsetWidth, 81 height: element.offsetHeight, 82 }; 83 } 84 85 var rect = element.getBoundingClientRect(); 86 return { 87 width: Math.round( rect.width ), 88 height: Math.round( rect.height ), 89 }; 90 } 91 92 /** 93 * Apply CSS styles to element. 94 * 95 * @param {HTMLElement} element 96 * @param {Object} style 97 */ 98 function setStyle( element, style ) { 99 Object.keys( style ).forEach( function ( key ) { 100 element.style[ key ] = style[ key ]; 101 } ); 102 } 103 104 /** 105 * Class for dimension change detection. 106 * 107 * @param {Element|Element[]|Elements|jQuery} element 108 * @param {Function} callback 109 * 110 * @constructor 111 */ 112 var ResizeSensor = function ( element, callback ) { 113 //Is used when checking in reset() only for invisible elements 114 var lastAnimationFrameForInvisibleCheck = 0; 115 116 /** 117 * 118 * @constructor 119 */ 120 function EventQueue() { 121 var q = []; 122 this.add = function ( ev ) { 123 q.push( ev ); 124 }; 125 126 var i, j; 127 this.call = function ( sizeInfo ) { 128 for ( i = 0, j = q.length; i < j; i++ ) { 129 q[ i ].call( this, sizeInfo ); 130 } 131 }; 132 133 this.remove = function ( ev ) { 134 var newQueue = []; 135 for ( i = 0, j = q.length; i < j; i++ ) { 136 if ( q[ i ] !== ev ) newQueue.push( q[ i ] ); 137 } 138 q = newQueue; 139 }; 140 141 this.length = function () { 142 return q.length; 143 }; 144 } 145 146 /** 147 * 148 * @param {HTMLElement} element 149 * @param {Function} resized 150 */ 151 function attachResizeEvent( element, resized ) { 152 if ( ! element ) return; 153 if ( element.resizedAttached ) { 154 element.resizedAttached.add( resized ); 155 return; 156 } 157 158 element.resizedAttached = new EventQueue(); 159 element.resizedAttached.add( resized ); 160 161 element.resizeSensor = document.createElement( 'div' ); 162 element.resizeSensor.dir = 'ltr'; 163 element.resizeSensor.className = 'resize-sensor'; 164 165 var style = { 166 pointerEvents: 'none', 167 position: 'absolute', 168 left: '0px', 169 top: '0px', 170 right: '0px', 171 bottom: '0px', 172 overflow: 'hidden', 173 zIndex: '-1', 174 visibility: 'hidden', 175 maxWidth: '100%', 176 }; 177 var styleChild = { 178 position: 'absolute', 179 left: '0px', 180 top: '0px', 181 transition: '0s', 182 }; 183 184 setStyle( element.resizeSensor, style ); 185 186 var expand = document.createElement( 'div' ); 187 expand.className = 'resize-sensor-expand'; 188 setStyle( expand, style ); 189 190 var expandChild = document.createElement( 'div' ); 191 setStyle( expandChild, styleChild ); 192 expand.appendChild( expandChild ); 193 194 var shrink = document.createElement( 'div' ); 195 shrink.className = 'resize-sensor-shrink'; 196 setStyle( shrink, style ); 197 198 var shrinkChild = document.createElement( 'div' ); 199 setStyle( shrinkChild, styleChild ); 200 setStyle( shrinkChild, {width: '200%', height: '200%'} ); 201 shrink.appendChild( shrinkChild ); 202 203 element.resizeSensor.appendChild( expand ); 204 element.resizeSensor.appendChild( shrink ); 205 element.appendChild( element.resizeSensor ); 206 207 var computedStyle = window.getComputedStyle( element ); 208 var position = computedStyle 209 ? computedStyle.getPropertyValue( 'position' ) 210 : null; 211 if ( 212 'absolute' !== position && 213 'relative' !== position && 214 'fixed' !== position && 215 'sticky' !== position 216 ) { 217 element.style.position = 'relative'; 218 } 219 220 var dirty = false;
221 222 //last request animation frame id used in onscroll event 223 var rafId = 0; 224 var size = getElementSize( element ); 225 var lastWidth = 0; 226 var lastHeight = 0; 227 var initialHiddenCheck = true; 228 lastAnimationFrameForInvisibleCheck = 0; 229 230 var resetExpandShrink = function () { 231 var width = element.offsetWidth; 232 var height = element.offsetHeight; 233 234 expandChild.style.width = width + 10 + 'px'; 235 expandChild.style.height = height + 10 + 'px'; 236 237 expand.scrollLeft = width + 10; 238 expand.scrollTop = height + 10; 239 240 shrink.scrollLeft = width + 10; 241 shrink.scrollTop = height + 10; 242 }; 243 244 var reset = function () { 245 // Check if element is hidden 246 if ( initialHiddenCheck ) { 247 var invisible = 248 element.offsetWidth === 0 && element.offsetHeight === 0; 249 if ( invisible ) { 250 // Check in next frame 251 if ( ! lastAnimationFrameForInvisibleCheck ) { 252 lastAnimationFrameForInvisibleCheck = 253 requestAnimationFrame( function () { 254 lastAnimationFrameForInvisibleCheck = 0; 255 reset(); 256 } ); 257 } 258 259 return; 260 } else { 261 // Stop checking 262 initialHiddenCheck = false; 263 } 264 } 265 266 resetExpandShrink(); 267 }; 268 element.resizeSensor.resetSensor = reset; 269 270 var onResized = function () { 271 rafId = 0; 272 273 if ( ! dirty ) return; 274 275 lastWidth = size.width; 276 lastHeight = size.height; 277 278 if ( element.resizedAttached ) { 279 element.resizedAttached.call( size ); 280 } 281 }; 282 283 var onScroll = function () { 284 size = getElementSize( element ); 285 dirty = size.width !== lastWidth || size.height !== lastHeight; 286 287 if ( dirty && ! rafId ) { 288 rafId = requestAnimationFrame( onResized ); 289 } 290 291 reset(); 292 }; 293 294 var addEvent = function ( el, name, cb ) { 295 if ( el.attachEvent ) { 296 el.attachEvent( 'on' + name, cb ); 297 } else { 298 el.addEventListener( name, cb ); 299 } 300 }; 301 302 addEvent( expand, 'scroll', onScroll ); 303 addEvent( shrink, 'scroll', onScroll ); 304 305 // Fix for custom Elements and invisible elements 306 lastAnimationFrameForInvisibleCheck = requestAnimationFrame( 307 function () { 308 lastAnimationFrameForInvisibleCheck = 0; 309 reset(); 310 } 311 ); 312 } 313 314 forEachElement( element, function ( elem ) { 315 attachResizeEvent( elem, callback ); 316 } ); 317 318 this.detach = function ( ev ) { 319 // clean up the unfinished animation frame to prevent a potential endless requestAnimationFrame of reset 320 if ( lastAnimationFrameForInvisibleCheck ) { 321 cancelAnimationFrame( lastAnimationFrameForInvisibleCheck ); 322 lastAnimationFrameForInvisibleCheck = 0; 323 } 324 ResizeSensor.detach( element, ev ); 325 }; 326 327 this.reset = function () { 328 //To prevent invoking element.resizeSensor.resetSensor if it's undefined 329 if ( element.resizeSensor.resetSensor ) { 330 element.resizeSensor.resetSensor(); 331 } 332 }; 333 }; 334 335 ResizeSensor.reset = function ( element ) { 336 forEachElement( element, function ( elem ) { 337 //To prevent invoking element.resizeSensor.resetSensor if it's undefined 338 if ( element.resizeSensor.resetSensor ) { 339 elem.resizeSensor.resetSensor(); 340 } 341 } ); 342 }; 343 344 ResizeSensor.detach = function ( element, ev ) { 345 forEachElement( element, function ( elem ) { 346 if ( ! elem ) return; 347 if ( elem.resizedAttached && typeof ev === 'function' ) { 348 elem.resizedAttached.remove( ev ); 349 if ( elem.resizedAttached.length() ) return; 350 } 351 if ( elem.resizeSensor ) { 352 if ( elem.contains( elem.resizeSensor ) ) { 353 elem.removeChild( elem.resizeSensor ); 354 } 355 delete elem.resizeSensor; 356 delete elem.resizedAttached; 357 } 358 } ); 359 }; 360 361 if ( typeof MutationObserver !== 'undefined' ) { 362 var observer = new MutationObserver( function ( mutations ) { 363 for ( var i in mutations ) { 364 if ( mutations.hasOwnProperty( i ) ) { 365 var items = mutations[ i ].addedNodes; 366 for ( var j = 0; j < items.length; j++ ) { 367 if ( items[ j ].resizeSensor ) { 368 ResizeSensor.reset( items[ j ] ); 369 } 370 } 371 } 372 } 373 } ); 374 375 document.addEventListener( 'DOMContentLoaded', function () { 376 observer.observe( document.body, { 377 childList: true, 378 subtree: true, 379 } ); 380 } ); 381 } 382 383 return ResizeSensor; 384} );
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.