1/*! 2 * imagesLoaded v4.1.4 3 * JavaScript is all like "You images are done yet or what?" 4 * MIT License 5 */ 6 7( function( window, factory ) { 'use strict'; 8 // universal module definition 9 10 /*global define: false, module: false, require: false */ 11 12 if ( typeof define == 'function' && define.amd ) { 13 // AMD 14 define( [ 15 'ev-emitter/ev-emitter' 16 ], function( EvEmitter ) { 17 return factory( window, EvEmitter ); 18 }); 19 } else if ( typeof module == 'object' && module.exports ) { 20 // CommonJS 21 module.exports = factory( 22 window, 23 require('ev-emitter') 24 ); 25 } else { 26 // browser global 27 window.imagesLoaded = factory( 28 window, 29 window.EvEmitter 30 ); 31 } 32 33})( typeof window !== 'undefined' ? window : this, 34 35// -------------------------- factory -------------------------- // 36 37function factory( window, EvEmitter ) { 38 39'use strict'; 40 41var $ = window.jQuery; 42var console = window.console; 43 44// -------------------------- helpers -------------------------- // 45 46// extend objects 47function extend( a, b ) { 48 for ( var prop in b ) { 49 a[ prop ] = b[ prop ]; 50 } 51 return a; 52} 53 54var arraySlice = Array.prototype.slice; 55 56// turn element or nodeList into an array 57function makeArray( obj ) { 58 if ( Array.isArray( obj ) ) { 59 // use object if already an array 60 return obj; 61 } 62 63 var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 64 if ( isArrayLike ) { 65 // convert nodeList to array 66 return arraySlice.call( obj ); 67 } 68 69 // array of single index 70 return [ obj ]; 71} 72 73// -------------------------- imagesLoaded -------------------------- // 74 75/** 76 * @param {Array, Element, NodeList, String} elem 77 * @param {Object or Function} options - if function, use as callback 78 * @param {Function} onAlways - callback function 79 */ 80function ImagesLoaded( elem, options, onAlways ) { 81 // coerce ImagesLoaded() without new, to be new ImagesLoaded() 82 if ( !( this instanceof ImagesLoaded ) ) { 83 return new ImagesLoaded( elem, options, onAlways ); 84 } 85 // use elem as selector string 86 var queryElem = elem; 87 if ( typeof elem == 'string' ) { 88 queryElem = document.querySelectorAll( elem ); 89 } 90 // bail if bad element 91 if ( !queryElem ) { 92 console.error( 'Bad element for imagesLoaded ' + ( queryElem || elem ) ); 93 return; 94 } 95 96 this.elements = makeArray( queryElem ); 97 this.options = extend( {}, this.options ); 98 // shift arguments if no options set 99 if ( typeof options == 'function' ) { 100 onAlways = options; 101 } else { 102 extend( this.options, options ); 103 } 104 105 if ( onAlways ) { 106 this.on( 'always', onAlways ); 107 } 108 109 this.getImages(); 110 111 if ( $ ) { 112 // add jQuery Deferred object 113 this.jqDeferred = new $.Deferred(); 114 } 115 116 // HACK check async to allow time to bind listeners 117 setTimeout( this.check.bind( this ) ); 118} 119 120ImagesLoaded.prototype = Object.create( EvEmitter.prototype ); 121 122ImagesLoaded.prototype.options = {}; 123 124ImagesLoaded.prototype.getImages = function() { 125 this.images = []; 126 127 // filter & find items if we have an item selector 128 this.elements.forEach( this.addElementImages, this ); 129}; 130 131/** 132 * @param {Node} element 133 */ 134ImagesLoaded.prototype.addElementImages = function( elem ) { 135 // filter siblings 136 if ( elem.nodeName == 'IMG' ) { 137 this.addImage( elem ); 138 } 139 // get background image on element 140 if ( this.options.background === true ) { 141 this.addElementBackgroundImages( elem ); 142 } 143 144 // find children 145 // no non-element nodes, #143 146 var nodeType = elem.nodeType; 147 if ( !nodeType || !elementNodeTypes[ nodeType ] ) { 148 return; 149 } 150 var childImgs = elem.querySelectorAll('img'); 151 // concat childElems to filterFound array 152 for ( var i=0; i < childImgs.length; i++ ) { 153 var img = childImgs[i]; 154 this.addImage( img ); 155 } 156 157 // get child background images 158 if ( typeof this.options.background == 'string' ) { 159 var children = elem.querySelectorAll( this.options.background ); 160 for ( i=0; i < children.length; i++ ) { 161 var child = children[i];
vendor: 6,176 bytes, lines 162-377
162 this.addElementBackgroundImages( child ); 163 } 164 } 165}; 166 167var elementNodeTypes = { 168 1: true, 169 9: true, 170 11: true 171}; 172 173ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) { 174 var style = getComputedStyle( elem ); 175 if ( !style ) { 176 // Firefox returns null if in a hidden iframe https://bugzil.la/548397 177 return; 178 } 179 // get url inside url("...") 180 var reURL = /url\((['"])?(.*?)\1\)/gi; 181 var matches = reURL.exec( style.backgroundImage ); 182 while ( matches !== null ) { 183 var url = matches && matches[2]; 184 if ( url ) { 185 this.addBackground( url, elem ); 186 } 187 matches = reURL.exec( style.backgroundImage ); 188 } 189}; 190 191/** 192 * @param {Image} img 193 */ 194ImagesLoaded.prototype.addImage = function( img ) { 195 var loadingImage = new LoadingImage( img ); 196 this.images.push( loadingImage ); 197}; 198 199ImagesLoaded.prototype.addBackground = function( url, elem ) { 200 var background = new Background( url, elem ); 201 this.images.push( background ); 202}; 203 204ImagesLoaded.prototype.check = function() { 205 var _this = this; 206 this.progressedCount = 0; 207 this.hasAnyBroken = false; 208 // complete if no images 209 if ( !this.images.length ) { 210 this.complete(); 211 return; 212 } 213 214 function onProgress( image, elem, message ) { 215 // HACK - Chrome triggers event before object properties have changed. #83 216 setTimeout( function() { 217 _this.progress( image, elem, message ); 218 }); 219 } 220 221 this.images.forEach( function( loadingImage ) { 222 loadingImage.once( 'progress', onProgress ); 223 loadingImage.check(); 224 }); 225}; 226 227ImagesLoaded.prototype.progress = function( image, elem, message ) { 228 this.progressedCount++; 229 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 230 // progress event 231 this.emitEvent( 'progress', [ this, image, elem ] ); 232 if ( this.jqDeferred && this.jqDeferred.notify ) { 233 this.jqDeferred.notify( this, image ); 234 } 235 // check if completed 236 if ( this.progressedCount == this.images.length ) { 237 this.complete(); 238 } 239 240 if ( this.options.debug && console ) { 241 console.log( 'progress: ' + message, image, elem ); 242 } 243}; 244 245ImagesLoaded.prototype.complete = function() { 246 var eventName = this.hasAnyBroken ? 'fail' : 'done'; 247 this.isComplete = true; 248 this.emitEvent( eventName, [ this ] ); 249 this.emitEvent( 'always', [ this ] ); 250 if ( this.jqDeferred ) { 251 var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; 252 this.jqDeferred[ jqMethod ]( this ); 253 } 254}; 255 256// -------------------------- -------------------------- // 257 258function LoadingImage( img ) { 259 this.img = img; 260} 261 262LoadingImage.prototype = Object.create( EvEmitter.prototype ); 263 264LoadingImage.prototype.check = function() { 265 // If complete is true and browser supports natural sizes, 266 // try to check for image status manually. 267 var isComplete = this.getIsImageComplete(); 268 if ( isComplete ) { 269 // report based on naturalWidth 270 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 271 return; 272 } 273 274 // If none of the checks above matched, simulate loading on detached element. 275 this.proxyImage = new Image(); 276 this.proxyImage.addEventListener( 'load', this ); 277 this.proxyImage.addEventListener( 'error', this ); 278 // bind to image as well for Firefox. #191 279 this.img.addEventListener( 'load', this ); 280 this.img.addEventListener( 'error', this ); 281 this.proxyImage.src = this.img.src; 282}; 283 284LoadingImage.prototype.getIsImageComplete = function() { 285 // check for non-zero, non-undefined naturalWidth 286 // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671 287 return this.img.complete && this.img.naturalWidth; 288}; 289 290LoadingImage.prototype.confirm = function( isLoaded, message ) { 291 this.isLoaded = isLoaded; 292 this.emitEvent( 'progress', [ this, this.img, message ] ); 293}; 294 295// ----- events ----- // 296 297// trigger specified handler for event type 298LoadingImage.prototype.handleEvent = function( event ) { 299 var method = 'on' + event.type; 300 if ( this[ method ] ) { 301 this[ method ]( event ); 302 } 303}; 304 305LoadingImage.prototype.onload = function() { 306 this.confirm( true, 'onload' ); 307 this.unbindEvents(); 308}; 309 310LoadingImage.prototype.onerror = function() { 311 this.confirm( false, 'onerror' ); 312 this.unbindEvents(); 313}; 314 315LoadingImage.prototype.unbindEvents = function() { 316 this.proxyImage.removeEventListener( 'load', this ); 317 this.proxyImage.removeEventListener( 'error', this ); 318 this.img.removeEventListener( 'load', this ); 319 this.img.removeEventListener( 'error', this ); 320}; 321 322// -------------------------- Background -------------------------- // 323 324function Background( url, element ) { 325 this.url = url; 326 this.element = element; 327 this.img = new Image(); 328} 329 330// inherit LoadingImage prototype 331Background.prototype = Object.create( LoadingImage.prototype ); 332 333Background.prototype.check = function() { 334 this.img.addEventListener( 'load', this ); 335 this.img.addEventListener( 'error', this ); 336 this.img.src = this.url; 337 // check if image is already complete 338 var isComplete = this.getIsImageComplete(); 339 if ( isComplete ) { 340 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 341 this.unbindEvents(); 342 } 343}; 344 345Background.prototype.unbindEvents = function() { 346 this.img.removeEventListener( 'load', this ); 347 this.img.removeEventListener( 'error', this ); 348}; 349 350Background.prototype.confirm = function( isLoaded, message ) { 351 this.isLoaded = isLoaded; 352 this.emitEvent( 'progress', [ this, this.element, message ] ); 353}; 354 355// -------------------------- jQuery -------------------------- // 356 357ImagesLoaded.makeJQueryPlugin = function( jQuery ) { 358 jQuery = jQuery || window.jQuery; 359 if ( !jQuery ) { 360 return; 361 } 362 // set local variable 363 $ = jQuery; 364 // $().imagesLoaded() 365 $.fn.imagesLoaded = function( options, callback ) { 366 var instance = new ImagesLoaded( this, options, callback ); 367 return instance.jqDeferred.promise( $(this) ); 368 }; 369}; 370// try making plugin 371ImagesLoaded.makeJQueryPlugin(); 372 373// -------------------------- -------------------------- // 374 375return ImagesLoaded; 376 377});
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.