/*! * imagesloaded packaged v4.1.3 * javascript is all like "you images are done yet or what?" * mit license */ /** * evemitter v1.1.0 * 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; }; proto.alloff = proto.removealllisteners = function() { delete this._events; delete this._onceevents; }; return evemitter; })); /*! * imagesloaded v4.1.3 * 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; });