/*!
* imagesLoaded PACKAGED v4.1.2 * JavaScript is all like "You images are done yet or what?" * MIT License */
/**
* EvEmitter v1.0.3 * Lil' event emitter * MIT License */
/* jshint unused: true, undef: true, strict: true */
( function( global, factory ) {
// universal module definition /* jshint strict: false */ /* globals define, module, window */ if ( typeof define == 'function' && define.amd ) { // AMD - RequireJS define( 'ev-emitter/ev-emitter',factory ); } else if ( typeof module == 'object' && module.exports ) { // CommonJS - Browserify, Webpack module.exports = factory(); } else { // Browser globals global.EvEmitter = factory(); }
}( typeof window != 'undefined' ? window : this, function() {
function EvEmitter() {}
var proto = EvEmitter.prototype;
proto.on = function( eventName, listener ) {
if ( !eventName || !listener ) { return; } // set events hash var events = this._events = this._events || {}; // set listeners array var listeners = events[ eventName ] = events[ eventName ] || []; // only add once if ( listeners.indexOf( listener ) == -1 ) { listeners.push( listener ); }
return this;
};
proto.once = function( eventName, listener ) {
if ( !eventName || !listener ) { return; } // add event this.on( eventName, listener ); // set once flag // set onceEvents hash var onceEvents = this._onceEvents = this._onceEvents || {}; // set onceListeners object var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; // set flag onceListeners[ listener ] = true;
return this;
};
proto.off = function( eventName, listener ) {
var listeners = this._events && this._events[ eventName ]; if ( !listeners || !listeners.length ) { return; } var index = listeners.indexOf( listener ); if ( index != -1 ) { listeners.splice( index, 1 ); }
return this;
};
proto.emitEvent = function( eventName, args ) {
var listeners = this._events && this._events[ eventName ]; if ( !listeners || !listeners.length ) { return; } var i = 0; var listener = listeners[i]; args = args || []; // once stuff var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
while ( listener ) { var isOnce = onceListeners && onceListeners[ listener ]; if ( isOnce ) { // remove listener // remove before trigger to prevent recursion this.off( eventName, listener ); // unset once flag delete onceListeners[ listener ]; } // trigger listener listener.apply( this, args ); // get next listener i += isOnce ? 0 : 1; listener = listeners[i]; }
return this;
};
return EvEmitter;
}));
/*!
* imagesLoaded v4.1.2 * JavaScript is all like "You images are done yet or what?" * MIT License */
( function( window, factory ) { 'use strict';
// universal module definition
/*global define: false, module: false, require: false */
if ( typeof define == 'function' && define.amd ) { // AMD define( [ 'ev-emitter/ev-emitter' ], function( EvEmitter ) { return factory( window, EvEmitter ); }); } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( window, require('ev-emitter') ); } else { // browser global window.imagesLoaded = factory( window, window.EvEmitter ); }
})( typeof window !== 'undefined' ? window : this,
// -------------------------- factory -------------------------- //
function factory( window, EvEmitter ) {
var $ = window.jQuery; var console = window.console;
// -------------------------- helpers -------------------------- //
// extend objects function extend( a, b ) {
for ( var prop in b ) { a[ prop ] = b[ prop ]; } return a;
}
// turn element or nodeList into an array function makeArray( obj ) {
var ary = []; if ( Array.isArray( obj ) ) { // use object if already an array ary = obj; } else if ( typeof obj.length == 'number' ) { // convert nodeList to array for ( var i=0; i < obj.length; i++ ) { ary.push( obj[i] ); } } else { // array of single index ary.push( obj ); } return ary;
}
// -------------------------- imagesLoaded -------------------------- //
/**
* @param {Array, Element, NodeList, String} elem * @param {Object or Function} options - if function, use as callback * @param {Function} onAlways - callback function */
function ImagesLoaded( elem, options, onAlways ) {
// coerce ImagesLoaded() without new, to be new ImagesLoaded() if ( !( this instanceof ImagesLoaded ) ) { return new ImagesLoaded( elem, options, onAlways ); } // use elem as selector string if ( typeof elem == 'string' ) { elem = document.querySelectorAll( elem ); }
this.elements = makeArray( elem ); this.options = extend( {}, this.options );
if ( typeof options == 'function' ) { onAlways = options; } else { extend( this.options, options ); }
if ( onAlways ) { this.on( 'always', onAlways ); }
this.getImages();
if ( $ ) { // add jQuery Deferred object this.jqDeferred = new $.Deferred(); }
// HACK check async to allow time to bind listeners setTimeout( function() { this.check(); }.bind( this ));
}
ImagesLoaded.prototype = Object.create( EvEmitter.prototype );
ImagesLoaded.prototype.options = {};
ImagesLoaded.prototype.getImages = function() {
this.images = [];
// filter & find items if we have an item selector this.elements.forEach( this.addElementImages, this );
};
/**
* @param {Node} element */
ImagesLoaded.prototype.addElementImages = function( elem ) {
// filter siblings if ( elem.nodeName == 'IMG' ) { this.addImage( elem ); } // get background image on element if ( this.options.background === true ) { this.addElementBackgroundImages( elem ); }
// find children // no non-element nodes, #143 var nodeType = elem.nodeType; if ( !nodeType || !elementNodeTypes[ nodeType ] ) { return; } var childImgs = elem.querySelectorAll('img'); // concat childElems to filterFound array for ( var i=0; i < childImgs.length; i++ ) { var img = childImgs[i]; this.addImage( img ); }
// get child background images if ( typeof this.options.background == 'string' ) { var children = elem.querySelectorAll( this.options.background ); for ( i=0; i < children.length; i++ ) { var child = children[i]; this.addElementBackgroundImages( child ); } }
};
var elementNodeTypes = {
1: true, 9: true, 11: true
};
ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) {
var style = getComputedStyle( elem ); if ( !style ) { // Firefox returns null if in a hidden iframe https://bugzil.la/548397 return; } // get url inside url("...") var reURL = /url\((['"])?(.*?)\1\)/gi; var matches = reURL.exec( style.backgroundImage ); while ( matches !== null ) { var url = matches && matches[2]; if ( url ) { this.addBackground( url, elem ); } matches = reURL.exec( style.backgroundImage ); }
};
/**
* @param {Image} img */
ImagesLoaded.prototype.addImage = function( img ) {
var loadingImage = new LoadingImage( img ); this.images.push( loadingImage );
};
ImagesLoaded.prototype.addBackground = function( url, elem ) {
var background = new Background( url, elem ); this.images.push( background );
};
ImagesLoaded.prototype.check = function() {
var _this = this; this.progressedCount = 0; this.hasAnyBroken = false; // complete if no images if ( !this.images.length ) { this.complete(); return; }
function onProgress( image, elem, message ) { // HACK - Chrome triggers event before object properties have changed. #83 setTimeout( function() { _this.progress( image, elem, message ); }); }
this.images.forEach( function( loadingImage ) { loadingImage.once( 'progress', onProgress ); loadingImage.check(); });
};
ImagesLoaded.prototype.progress = function( image, elem, message ) {
this.progressedCount++; this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; // progress event this.emitEvent( 'progress', [ this, image, elem ] ); if ( this.jqDeferred && this.jqDeferred.notify ) { this.jqDeferred.notify( this, image ); } // check if completed if ( this.progressedCount == this.images.length ) { this.complete(); }
if ( this.options.debug && console ) { console.log( 'progress: ' + message, image, elem ); }
};
ImagesLoaded.prototype.complete = function() {
var eventName = this.hasAnyBroken ? 'fail' : 'done'; this.isComplete = true; this.emitEvent( eventName, [ this ] ); this.emitEvent( 'always', [ this ] ); if ( this.jqDeferred ) { var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; this.jqDeferred[ jqMethod ]( this ); }
};
// -------------------------- -------------------------- //
function LoadingImage( img ) {
this.img = img;
}
LoadingImage.prototype = Object.create( EvEmitter.prototype );
LoadingImage.prototype.check = function() {
// If complete is true and browser supports natural sizes, // try to check for image status manually. var isComplete = this.getIsImageComplete(); if ( isComplete ) { // report based on naturalWidth this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); return; }
// If none of the checks above matched, simulate loading on detached element. this.proxyImage = new Image(); this.proxyImage.addEventListener( 'load', this ); this.proxyImage.addEventListener( 'error', this ); // bind to image as well for Firefox. #191 this.img.addEventListener( 'load', this ); this.img.addEventListener( 'error', this ); this.proxyImage.src = this.img.src;
};
LoadingImage.prototype.getIsImageComplete = function() {
return this.img.complete && this.img.naturalWidth !== undefined;
};
LoadingImage.prototype.confirm = function( isLoaded, message ) {
this.isLoaded = isLoaded; this.emitEvent( 'progress', [ this, this.img, message ] );
};
// ----- events ----- //
// trigger specified handler for event type LoadingImage.prototype.handleEvent = function( event ) {
var method = 'on' + event.type; if ( this[ method ] ) { this[ method ]( event ); }
};
LoadingImage.prototype.onload = function() {
this.confirm( true, 'onload' ); this.unbindEvents();
};
LoadingImage.prototype.onerror = function() {
this.confirm( false, 'onerror' ); this.unbindEvents();
};
LoadingImage.prototype.unbindEvents = function() {
this.proxyImage.removeEventListener( 'load', this ); this.proxyImage.removeEventListener( 'error', this ); this.img.removeEventListener( 'load', this ); this.img.removeEventListener( 'error', this );
};
// -------------------------- Background -------------------------- //
function Background( url, element ) {
this.url = url; this.element = element; this.img = new Image();
}
// inherit LoadingImage prototype Background.prototype = Object.create( LoadingImage.prototype );
Background.prototype.check = function() {
this.img.addEventListener( 'load', this ); this.img.addEventListener( 'error', this ); this.img.src = this.url; // check if image is already complete var isComplete = this.getIsImageComplete(); if ( isComplete ) { this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); this.unbindEvents(); }
};
Background.prototype.unbindEvents = function() {
this.img.removeEventListener( 'load', this ); this.img.removeEventListener( 'error', this );
};
Background.prototype.confirm = function( isLoaded, message ) {
this.isLoaded = isLoaded; this.emitEvent( 'progress', [ this, this.element, message ] );
};
// -------------------------- jQuery -------------------------- //
ImagesLoaded.makeJQueryPlugin = function( jQuery ) {
jQuery = jQuery || window.jQuery; if ( !jQuery ) { return; } // set local variable $ = jQuery; // $().imagesLoaded() $.fn.imagesLoaded = function( options, callback ) { var instance = new ImagesLoaded( this, options, callback ); return instance.jqDeferred.promise( $(this) ); };
}; // try making plugin ImagesLoaded.makeJQueryPlugin();
// -------------------------- -------------------------- //
return ImagesLoaded;
});