|
@@ -0,0 +1,487 @@
|
|
|
+/*!
|
|
|
+ * imagesLoaded PACKAGED v4.1.0
|
|
|
+ * JavaScript is all like "You images are done yet or what?"
|
|
|
+ * MIT License
|
|
|
+ */
|
|
|
+
|
|
|
+/**
|
|
|
+ * EvEmitter v1.0.1
|
|
|
+ * Lil' event emitter
|
|
|
+ * MIT License
|
|
|
+ */
|
|
|
+
|
|
|
+/* jshint unused: true, undef: true, strict: true */
|
|
|
+
|
|
|
+( function( global, factory ) {
|
|
|
+ // universal module definition
|
|
|
+ /* jshint strict: false */ /* globals define, module */
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+
|
|
|
+}( 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 array
|
|
|
+ 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.0
|
|
|
+ * 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
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+})( window,
|
|
|
+
|
|
|
+// -------------------------- 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;
|
|
|
+
|
|
|
+});
|
|
|
+
|