/*! * imagesloaded v3.0.2 * javascript is all like "you images are done yet or what?" */ ( function( window ) { 'use strict'; var $ = window.jquery; var console = window.console; var hasconsole = typeof console !== 'undefined'; // -------------------------- helpers -------------------------- // // extend objects function extend( a, b ) { for ( var prop in b ) { a[ prop ] = b[ prop ]; } return a; } var objtostring = object.prototype.tostring; function isarray( obj ) { return objtostring.call( obj ) === '[object array]'; } // turn element or nodelist into an array function makearray( obj ) { var ary = []; if ( isarray( obj ) ) { // use object if already an array ary = obj; } else if ( typeof obj.length === 'number' ) { // convert nodelist to array for ( var i=0, len = obj.length; i < len; i++ ) { ary.push( obj[i] ); } } else { // array of single index ary.push( obj ); } return ary; } // -------------------------- -------------------------- // function defineimagesloaded( eventemitter, eventie ) { /** * @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 ); } // 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 var _this = this; settimeout( function() { _this.check(); }); } imagesloaded.prototype = new eventemitter(); imagesloaded.prototype.options = {}; imagesloaded.prototype.getimages = function() { this.images = []; // filter & find items if we have an item selector for ( var i=0, len = this.elements.length; i < len; i++ ) { var elem = this.elements[i]; // filter siblings if ( elem.nodename === 'img' ) { this.addimage( elem ); } // find children var childelems = elem.queryselectorall('img'); // concat childelems to filterfound array for ( var j=0, jlen = childelems.length; j < jlen; j++ ) { var img = childelems[j]; this.addimage( img ); } } }; /** * @param {image} img */ imagesloaded.prototype.addimage = function( img ) { var loadingimage = new loadingimage( img ); this.images.push( loadingimage ); }; imagesloaded.prototype.check = function() { var _this = this; var checkedcount = 0; var length = this.images.length; this.hasanybroken = false; // complete if no images if ( !length ) { this.complete(); return; } function onconfirm( image, message ) { if ( _this.options.debug && hasconsole ) { console.log( 'confirm', image, message ); } _this.progress( image ); checkedcount++; if ( checkedcount === length ) { _this.complete(); } return true; // bind once } for ( var i=0; i < length; i++ ) { var loadingimage = this.images[i]; loadingimage.on( 'confirm', onconfirm ); loadingimage.check(); } }; imagesloaded.prototype.progress = function( image ) { this.hasanybroken = this.hasanybroken || !image.isloaded; this.emit( 'progress', this, image ); if ( this.jqdeferred ) { this.jqdeferred.notify( this, image ); } }; imagesloaded.prototype.complete = function() { var eventname = this.hasanybroken ? 'fail' : 'done'; this.iscomplete = true; this.emit( eventname, this ); this.emit( 'always', this ); if ( this.jqdeferred ) { var jqmethod = this.hasanybroken ? 'reject' : 'resolve'; this.jqdeferred[ jqmethod ]( this ); } }; // -------------------------- jquery -------------------------- // if ( $ ) { $.fn.imagesloaded = function( options, callback ) { var instance = new imagesloaded( this, options, callback ); return instance.jqdeferred.promise( $(this) ); }; } // -------------------------- -------------------------- // var cache = {}; function loadingimage( img ) { this.img = img; } loadingimage.prototype = new eventemitter(); loadingimage.prototype.check = function() { // first check cached any previous images that have same src var cached = cache[ this.img.src ]; if ( cached ) { this.usecached( cached ); return; } // add this to cache cache[ this.img.src ] = this; // if complete is true and browser supports natural sizes, // try to check for image status manually. if ( this.img.complete && this.img.naturalwidth !== undefined ) { // report based on naturalwidth this.confirm( this.img.naturalwidth !== 0, 'naturalwidth' ); return; } // if none of the checks above matched, simulate loading on detached element. var proxyimage = this.proxyimage = new image(); eventie.bind( proxyimage, 'load', this ); eventie.bind( proxyimage, 'error', this ); proxyimage.src = this.img.src; }; loadingimage.prototype.usecached = function( cached ) { if ( cached.isconfirmed ) { this.confirm( cached.isloaded, 'cached was confirmed' ); } else { var _this = this; cached.on( 'confirm', function( image ) { _this.confirm( image.isloaded, 'cache emitted confirmed' ); return true; // bind once }); } }; loadingimage.prototype.confirm = function( isloaded, message ) { this.isconfirmed = true; this.isloaded = isloaded; this.emit( 'confirm', this, message ); }; // 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.unbindproxyevents(); }; loadingimage.prototype.onerror = function() { this.confirm( false, 'onerror' ); this.unbindproxyevents(); }; loadingimage.prototype.unbindproxyevents = function() { eventie.unbind( this.proxyimage, 'load', this ); eventie.unbind( this.proxyimage, 'error', this ); }; // ----- ----- // return imagesloaded; } // -------------------------- transport -------------------------- // if ( typeof define === 'function' && define.amd ) { // amd define( [ 'eventemitter', 'eventie' ], defineimagesloaded ); } else { // browser global window.imagesloaded = defineimagesloaded( window.eventemitter, window.eventie ); } })( window );