/*! * 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);