From 5aac318e5cb34996f25a10e939bba498792b96c5 Mon Sep 17 00:00:00 2001 From: David DeSandro Date: Wed, 28 Oct 2015 22:55:48 -0400 Subject: [PATCH] build version 3.2.0 --- README.md | 9 +- bower.json | 2 +- imagesloaded.js | 2 +- imagesloaded.pkgd.js | 295 ++++++++++++++++++++++++--------------- imagesloaded.pkgd.min.js | 4 +- 5 files changed, 189 insertions(+), 123 deletions(-) diff --git a/README.md b/README.md index c1cf6fc..a9ee90d 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,9 @@ Detect when images have been loaded. ### CDN ``` html - - + + + ``` ### Package managers @@ -141,8 +142,6 @@ imagesLoaded( '#container', { background: '.item' }, function() { }); ``` - - ## Events ### always @@ -208,6 +207,8 @@ Triggered after each image has been loaded. + `instance` _imagesLoaded_ - the imagesLoaded instance + `image` _LoadingImage_ - the LoadingImage instance of the loaded image + + ## Properties ### LoadingImage.img diff --git a/bower.json b/bower.json index 5801d80..80130e0 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "imagesloaded", - "version": "3.1.8", + "version": "3.2.0", "description": "JavaScript is all like _You images done yet or what?_", "main": "imagesloaded.js", "dependencies": { diff --git a/imagesloaded.js b/imagesloaded.js index f8c82f8..d28a74f 100644 --- a/imagesloaded.js +++ b/imagesloaded.js @@ -1,5 +1,5 @@ /*! - * imagesLoaded v3.1.8 + * imagesLoaded v3.2.0 * JavaScript is all like "You images are done yet or what?" * MIT License */ diff --git a/imagesloaded.pkgd.js b/imagesloaded.pkgd.js index e907580..96fd969 100644 --- a/imagesloaded.pkgd.js +++ b/imagesloaded.pkgd.js @@ -1,10 +1,9 @@ /*! - * imagesLoaded PACKAGED v3.1.8 + * imagesLoaded PACKAGED v3.2.0 * JavaScript is all like "You images are done yet or what?" * MIT License */ - /*! * EventEmitter v4.2.6 - git.io/ee * Oliver Caldwell @@ -13,7 +12,7 @@ */ (function () { - + 'use strict'; /** * Class for managing events. @@ -557,17 +556,17 @@ if ( typeof define === 'function' && define.amd ) { })( this ); /*! - * imagesLoaded v3.1.8 + * imagesLoaded v3.2.0 * JavaScript is all like "You images are done yet or what?" * MIT License */ -( function( window, factory ) { +( function( window, factory ) { 'use strict'; // universal module definition /*global define: false, module: false, require: false */ - if ( typeof define === 'function' && define.amd ) { + if ( typeof define == 'function' && define.amd ) { // AMD define( [ 'eventEmitter/EventEmitter', @@ -575,7 +574,7 @@ if ( typeof define === 'function' && define.amd ) { ], function( EventEmitter, eventie ) { return factory( window, EventEmitter, eventie ); }); - } else if ( typeof exports === 'object' ) { + } else if ( typeof module == 'object' && module.exports ) { // CommonJS module.exports = factory( window, @@ -601,7 +600,6 @@ function factory( window, EventEmitter, eventie ) { var $ = window.jQuery; var console = window.console; -var hasConsole = typeof console !== 'undefined'; // -------------------------- helpers -------------------------- // @@ -615,7 +613,7 @@ function extend( a, b ) { var objToString = Object.prototype.toString; function isArray( obj ) { - return objToString.call( obj ) === '[object Array]'; + return objToString.call( obj ) == '[object Array]'; } // turn element or nodeList into an array @@ -624,9 +622,9 @@ function makeArray( obj ) { if ( isArray( obj ) ) { // use object if already an array ary = obj; - } else if ( typeof obj.length === 'number' ) { + } else if ( typeof obj.length == 'number' ) { // convert nodeList to array - for ( var i=0, len = obj.length; i < len; i++ ) { + for ( var i=0; i < obj.length; i++ ) { ary.push( obj[i] ); } } else { @@ -646,17 +644,17 @@ function makeArray( obj ) { function ImagesLoaded( elem, options, onAlways ) { // coerce ImagesLoaded() without new, to be new ImagesLoaded() if ( !( this instanceof ImagesLoaded ) ) { - return new ImagesLoaded( elem, options ); + return new ImagesLoaded( elem, options, onAlways ); } // use elem as selector string - if ( typeof elem === 'string' ) { + if ( typeof elem == 'string' ) { elem = document.querySelectorAll( elem ); } this.elements = makeArray( elem ); this.options = extend( {}, this.options ); - if ( typeof options === 'function' ) { + if ( typeof options == 'function' ) { onAlways = options; } else { extend( this.options, options ); @@ -688,27 +686,73 @@ function makeArray( obj ) { this.images = []; // filter & find items if we have an item selector - for ( var i=0, len = this.elements.length; i < len; i++ ) { + for ( var i=0; i < this.elements.length; i++ ) { var elem = this.elements[i]; - // filter siblings - if ( elem.nodeName === 'IMG' ) { - this.addImage( elem ); - } - // find children - // no non-element nodes, #143 - var nodeType = elem.nodeType; - if ( !nodeType || !( nodeType === 1 || nodeType === 9 || nodeType === 11 ) ) { - continue; + this.addElementImages( elem ); + } + }; + + /** + * @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 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 ); + } + }; + + var elementNodeTypes = { + 1: true, + 9: true, + 11: true + }; + + ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) { + var style = getStyle( elem ); + // get url inside url("...") + var reURL = /url\(['"]*([^'"\)]+)['"]*\)/gi; + var matches = reURL.exec( style.backgroundImage ); + while ( matches !== null ) { + var url = matches && matches[1]; + if ( url ) { + this.addBackground( url, elem ); } + matches = reURL.exec( style.backgroundImage ); } }; + // IE8 + var getStyle = window.getComputedStyle || function( elem ) { + return elem.currentStyle; + }; + /** * @param {Image} img */ @@ -717,74 +761,64 @@ function makeArray( obj ) { 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; - var checkedCount = 0; - var length = this.images.length; + this.progressedCount = 0; this.hasAnyBroken = false; // complete if no images - if ( !length ) { + if ( !this.images.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 + function onProgress( image, elem, message ) { + // HACK - Chrome triggers event before object properties have changed. #83 + setTimeout( function() { + _this.progress( image, elem, message ); + }); } - for ( var i=0; i < length; i++ ) { + for ( var i=0; i < this.images.length; i++ ) { var loadingImage = this.images[i]; - loadingImage.on( 'confirm', onConfirm ); + loadingImage.once( 'progress', onProgress ); loadingImage.check(); } }; - ImagesLoaded.prototype.progress = function( image ) { + ImagesLoaded.prototype.progress = function( image, elem, message ) { + this.progressedCount++; this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; - // HACK - Chrome triggers event before object properties have changed. #83 - var _this = this; - setTimeout( function() { - _this.emit( 'progress', _this, image ); - if ( _this.jqDeferred && _this.jqDeferred.notify ) { - _this.jqDeferred.notify( _this, image ); - } - }); + // progress event + this.emit( '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; - var _this = this; - // HACK - another setTimeout so that confirm happens after progress - setTimeout( function() { - _this.emit( eventName, _this ); - _this.emit( 'always', _this ); - if ( _this.jqDeferred ) { - var jqMethod = _this.hasAnyBroken ? 'reject' : 'resolve'; - _this.jqDeferred[ jqMethod ]( _this ); - } - }); + 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) ); - }; - } - - // -------------------------- -------------------------- // function LoadingImage( img ) { @@ -796,82 +830,113 @@ function makeArray( obj ) { LoadingImage.prototype.check = function() { // If complete is true and browser supports natural sizes, // try to check for image status manually. - if ( this.img.complete && this.img.naturalWidth !== undefined ) { + 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. - var resource = new Resource( this.img.src ); - var _this = this; - resource.on( 'confirm', function( resrc, message ) { - _this.confirm( resrc.isLoaded, message ); - return true; - }); + this.proxyImage = new Image(); + eventie.bind( this.proxyImage, 'load', this ); + eventie.bind( this.proxyImage, 'error', this ); + // bind to image as well for Firefox. #191 + eventie.bind( this.img, 'load', this ); + eventie.bind( this.img, 'error', this ); + this.proxyImage.src = this.img.src; + }; - resource.check(); + LoadingImage.prototype.getIsImageComplete = function() { + return this.img.complete && this.img.naturalWidth !== undefined; }; LoadingImage.prototype.confirm = function( isLoaded, message ) { this.isLoaded = isLoaded; - this.emit( 'confirm', this, message ); - }; - - // -------------------------- Resource -------------------------- // - - // Resource checks each src, only once - // separate class from LoadingImage to prevent memory leaks. See #115 - - function Resource( src ) { - this.src = src; - } - - Resource.prototype = new EventEmitter(); - - Resource.prototype.check = function() { - // simulate loading on detached element - var proxyImage = new Image(); - eventie.bind( proxyImage, 'load', this ); - eventie.bind( proxyImage, 'error', this ); - proxyImage.src = this.src; + this.emit( 'progress', this, this.img, message ); }; // ----- events ----- // // trigger specified handler for event type - Resource.prototype.handleEvent = function( event ) { + LoadingImage.prototype.handleEvent = function( event ) { var method = 'on' + event.type; if ( this[ method ] ) { this[ method ]( event ); } }; - Resource.prototype.onload = function( event ) { + LoadingImage.prototype.onload = function() { this.confirm( true, 'onload' ); - this.unbindProxyEvents( event ); + this.unbindEvents(); }; - Resource.prototype.onerror = function( event ) { + LoadingImage.prototype.onerror = function() { this.confirm( false, 'onerror' ); - this.unbindProxyEvents( event ); + this.unbindEvents(); }; - // ----- confirm ----- // + LoadingImage.prototype.unbindEvents = function() { + eventie.unbind( this.proxyImage, 'load', this ); + eventie.unbind( this.proxyImage, 'error', this ); + eventie.unbind( this.img, 'load', this ); + eventie.unbind( this.img, 'error', this ); + }; - Resource.prototype.confirm = function( isLoaded, message ) { - this.isConfirmed = true; + // -------------------------- Background -------------------------- // + + function Background( url, element ) { + this.url = url; + this.element = element; + this.img = new Image(); + } + + // inherit LoadingImage prototype + Background.prototype = new LoadingImage(); + + Background.prototype.check = function() { + eventie.bind( this.img, 'load', this ); + eventie.bind( this.img, '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() { + eventie.unbind( this.img, 'load', this ); + eventie.unbind( this.img, 'error', this ); + }; + + Background.prototype.confirm = function( isLoaded, message ) { this.isLoaded = isLoaded; - this.emit( 'confirm', this, message ); + this.emit( 'progress', this, this.element, message ); }; - Resource.prototype.unbindProxyEvents = function( event ) { - eventie.unbind( event.target, 'load', this ); - eventie.unbind( event.target, 'error', this ); + // -------------------------- 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; }); + diff --git a/imagesloaded.pkgd.min.js b/imagesloaded.pkgd.min.js index 476c950..8a65a2f 100644 --- a/imagesloaded.pkgd.min.js +++ b/imagesloaded.pkgd.min.js @@ -1,7 +1,7 @@ /*! - * imagesLoaded PACKAGED v3.1.8 + * imagesLoaded PACKAGED v3.2.0 * JavaScript is all like "You images are done yet or what?" * MIT License */ -(function(){function e(){}function t(e,t){for(var n=e.length;n--;)if(e[n].listener===t)return n;return-1}function n(e){return function(){return this[e].apply(this,arguments)}}var i=e.prototype,r=this,o=r.EventEmitter;i.getListeners=function(e){var t,n,i=this._getEvents();if("object"==typeof e){t={};for(n in i)i.hasOwnProperty(n)&&e.test(n)&&(t[n]=i[n])}else t=i[e]||(i[e]=[]);return t},i.flattenListeners=function(e){var t,n=[];for(t=0;e.length>t;t+=1)n.push(e[t].listener);return n},i.getListenersAsObject=function(e){var t,n=this.getListeners(e);return n instanceof Array&&(t={},t[e]=n),t||n},i.addListener=function(e,n){var i,r=this.getListenersAsObject(e),o="object"==typeof n;for(i in r)r.hasOwnProperty(i)&&-1===t(r[i],n)&&r[i].push(o?n:{listener:n,once:!1});return this},i.on=n("addListener"),i.addOnceListener=function(e,t){return this.addListener(e,{listener:t,once:!0})},i.once=n("addOnceListener"),i.defineEvent=function(e){return this.getListeners(e),this},i.defineEvents=function(e){for(var t=0;e.length>t;t+=1)this.defineEvent(e[t]);return this},i.removeListener=function(e,n){var i,r,o=this.getListenersAsObject(e);for(r in o)o.hasOwnProperty(r)&&(i=t(o[r],n),-1!==i&&o[r].splice(i,1));return this},i.off=n("removeListener"),i.addListeners=function(e,t){return this.manipulateListeners(!1,e,t)},i.removeListeners=function(e,t){return this.manipulateListeners(!0,e,t)},i.manipulateListeners=function(e,t,n){var i,r,o=e?this.removeListener:this.addListener,s=e?this.removeListeners:this.addListeners;if("object"!=typeof t||t instanceof RegExp)for(i=n.length;i--;)o.call(this,t,n[i]);else for(i in t)t.hasOwnProperty(i)&&(r=t[i])&&("function"==typeof r?o.call(this,i,r):s.call(this,i,r));return this},i.removeEvent=function(e){var t,n=typeof e,i=this._getEvents();if("string"===n)delete i[e];else if("object"===n)for(t in i)i.hasOwnProperty(t)&&e.test(t)&&delete i[t];else delete this._events;return this},i.removeAllListeners=n("removeEvent"),i.emitEvent=function(e,t){var n,i,r,o,s=this.getListenersAsObject(e);for(r in s)if(s.hasOwnProperty(r))for(i=s[r].length;i--;)n=s[r][i],n.once===!0&&this.removeListener(e,n.listener),o=n.listener.apply(this,t||[]),o===this._getOnceReturnValue()&&this.removeListener(e,n.listener);return this},i.trigger=n("emitEvent"),i.emit=function(e){var t=Array.prototype.slice.call(arguments,1);return this.emitEvent(e,t)},i.setOnceReturnValue=function(e){return this._onceReturnValue=e,this},i._getOnceReturnValue=function(){return this.hasOwnProperty("_onceReturnValue")?this._onceReturnValue:!0},i._getEvents=function(){return this._events||(this._events={})},e.noConflict=function(){return r.EventEmitter=o,e},"function"==typeof define&&define.amd?define("eventEmitter/EventEmitter",[],function(){return e}):"object"==typeof module&&module.exports?module.exports=e:this.EventEmitter=e}).call(this),function(e){function t(t){var n=e.event;return n.target=n.target||n.srcElement||t,n}var n=document.documentElement,i=function(){};n.addEventListener?i=function(e,t,n){e.addEventListener(t,n,!1)}:n.attachEvent&&(i=function(e,n,i){e[n+i]=i.handleEvent?function(){var n=t(e);i.handleEvent.call(i,n)}:function(){var n=t(e);i.call(e,n)},e.attachEvent("on"+n,e[n+i])});var r=function(){};n.removeEventListener?r=function(e,t,n){e.removeEventListener(t,n,!1)}:n.detachEvent&&(r=function(e,t,n){e.detachEvent("on"+t,e[t+n]);try{delete e[t+n]}catch(i){e[t+n]=void 0}});var o={bind:i,unbind:r};"function"==typeof define&&define.amd?define("eventie/eventie",o):e.eventie=o}(this),function(e,t){"function"==typeof define&&define.amd?define(["eventEmitter/EventEmitter","eventie/eventie"],function(n,i){return t(e,n,i)}):"object"==typeof exports?module.exports=t(e,require("wolfy87-eventemitter"),require("eventie")):e.imagesLoaded=t(e,e.EventEmitter,e.eventie)}(window,function(e,t,n){function i(e,t){for(var n in t)e[n]=t[n];return e}function r(e){return"[object Array]"===d.call(e)}function o(e){var t=[];if(r(e))t=e;else if("number"==typeof e.length)for(var n=0,i=e.length;i>n;n++)t.push(e[n]);else t.push(e);return t}function s(e,t,n){if(!(this instanceof s))return new s(e,t);"string"==typeof e&&(e=document.querySelectorAll(e)),this.elements=o(e),this.options=i({},this.options),"function"==typeof t?n=t:i(this.options,t),n&&this.on("always",n),this.getImages(),a&&(this.jqDeferred=new a.Deferred);var r=this;setTimeout(function(){r.check()})}function f(e){this.img=e}function c(e){this.src=e,v[e]=this}var a=e.jQuery,u=e.console,h=u!==void 0,d=Object.prototype.toString;s.prototype=new t,s.prototype.options={},s.prototype.getImages=function(){this.images=[];for(var e=0,t=this.elements.length;t>e;e++){var n=this.elements[e];"IMG"===n.nodeName&&this.addImage(n);var i=n.nodeType;if(i&&(1===i||9===i||11===i))for(var r=n.querySelectorAll("img"),o=0,s=r.length;s>o;o++){var f=r[o];this.addImage(f)}}},s.prototype.addImage=function(e){var t=new f(e);this.images.push(t)},s.prototype.check=function(){function e(e,r){return t.options.debug&&h&&u.log("confirm",e,r),t.progress(e),n++,n===i&&t.complete(),!0}var t=this,n=0,i=this.images.length;if(this.hasAnyBroken=!1,!i)return this.complete(),void 0;for(var r=0;i>r;r++){var o=this.images[r];o.on("confirm",e),o.check()}},s.prototype.progress=function(e){this.hasAnyBroken=this.hasAnyBroken||!e.isLoaded;var t=this;setTimeout(function(){t.emit("progress",t,e),t.jqDeferred&&t.jqDeferred.notify&&t.jqDeferred.notify(t,e)})},s.prototype.complete=function(){var e=this.hasAnyBroken?"fail":"done";this.isComplete=!0;var t=this;setTimeout(function(){if(t.emit(e,t),t.emit("always",t),t.jqDeferred){var n=t.hasAnyBroken?"reject":"resolve";t.jqDeferred[n](t)}})},a&&(a.fn.imagesLoaded=function(e,t){var n=new s(this,e,t);return n.jqDeferred.promise(a(this))}),f.prototype=new t,f.prototype.check=function(){var e=v[this.img.src]||new c(this.img.src);if(e.isConfirmed)return this.confirm(e.isLoaded,"cached was confirmed"),void 0;if(this.img.complete&&void 0!==this.img.naturalWidth)return this.confirm(0!==this.img.naturalWidth,"naturalWidth"),void 0;var t=this;e.on("confirm",function(e,n){return t.confirm(e.isLoaded,n),!0}),e.check()},f.prototype.confirm=function(e,t){this.isLoaded=e,this.emit("confirm",this,t)};var v={};return c.prototype=new t,c.prototype.check=function(){if(!this.isChecked){var e=new Image;n.bind(e,"load",this),n.bind(e,"error",this),e.src=this.src,this.isChecked=!0}},c.prototype.handleEvent=function(e){var t="on"+e.type;this[t]&&this[t](e)},c.prototype.onload=function(e){this.confirm(!0,"onload"),this.unbindProxyEvents(e)},c.prototype.onerror=function(e){this.confirm(!1,"onerror"),this.unbindProxyEvents(e)},c.prototype.confirm=function(e,t){this.isConfirmed=!0,this.isLoaded=e,this.emit("confirm",this,t)},c.prototype.unbindProxyEvents=function(e){n.unbind(e.target,"load",this),n.unbind(e.target,"error",this)},s}); +(function(){"use strict";function e(){}function t(e,t){for(var n=e.length;n--;)if(e[n].listener===t)return n;return-1}function n(e){return function(){return this[e].apply(this,arguments)}}var i=e.prototype,r=this,s=r.EventEmitter;i.getListeners=function(e){var t,n,i=this._getEvents();if("object"==typeof e){t={};for(n in i)i.hasOwnProperty(n)&&e.test(n)&&(t[n]=i[n])}else t=i[e]||(i[e]=[]);return t},i.flattenListeners=function(e){var t,n=[];for(t=0;t