PluginProbe ʕ •ᴥ•ʔ
Responsive Lightbox & Gallery / 2.5.4
Responsive Lightbox & Gallery v2.5.4
2.7.8 trunk 1.0.0 1.0.1 1.0.1.1 1.0.2 1.0.3 1.0.4 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4.0 1.4.0.1 1.4.1 1.4.11 1.4.12 1.4.13 1.4.14 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3.1 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7
responsive-lightbox / assets / imagesloaded / imagesloaded.pkgd.js
responsive-lightbox / assets / imagesloaded Last commit date
LICENSE 3 years ago README.md 3 years ago imagesloaded.pkgd.js 3 years ago imagesloaded.pkgd.min.js 3 years ago
imagesloaded.pkgd.js
442 lines
1 /*!
2 * imagesLoaded PACKAGED v5.0.0
3 * JavaScript is all like "You images are done yet or what?"
4 * MIT License
5 */
6
7 /**
8 * EvEmitter v2.1.1
9 * Lil' event emitter
10 * MIT License
11 */
12
13 ( function( global, factory ) {
14 // universal module definition
15 if ( typeof module == 'object' && module.exports ) {
16 // CommonJS - Browserify, Webpack
17 module.exports = factory();
18 } else {
19 // Browser globals
20 global.EvEmitter = factory();
21 }
22
23 }( typeof window != 'undefined' ? window : this, function() {
24
25 function EvEmitter() {}
26
27 let proto = EvEmitter.prototype;
28
29 proto.on = function( eventName, listener ) {
30 if ( !eventName || !listener ) return this;
31
32 // set events hash
33 let events = this._events = this._events || {};
34 // set listeners array
35 let listeners = events[ eventName ] = events[ eventName ] || [];
36 // only add once
37 if ( !listeners.includes( listener ) ) {
38 listeners.push( listener );
39 }
40
41 return this;
42 };
43
44 proto.once = function( eventName, listener ) {
45 if ( !eventName || !listener ) return this;
46
47 // add event
48 this.on( eventName, listener );
49 // set once flag
50 // set onceEvents hash
51 let onceEvents = this._onceEvents = this._onceEvents || {};
52 // set onceListeners object
53 let onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
54 // set flag
55 onceListeners[ listener ] = true;
56
57 return this;
58 };
59
60 proto.off = function( eventName, listener ) {
61 let listeners = this._events && this._events[ eventName ];
62 if ( !listeners || !listeners.length ) return this;
63
64 let index = listeners.indexOf( listener );
65 if ( index != -1 ) {
66 listeners.splice( index, 1 );
67 }
68
69 return this;
70 };
71
72 proto.emitEvent = function( eventName, args ) {
73 let listeners = this._events && this._events[ eventName ];
74 if ( !listeners || !listeners.length ) return this;
75
76 // copy over to avoid interference if .off() in listener
77 listeners = listeners.slice( 0 );
78 args = args || [];
79 // once stuff
80 let onceListeners = this._onceEvents && this._onceEvents[ eventName ];
81
82 for ( let listener of listeners ) {
83 let isOnce = onceListeners && onceListeners[ listener ];
84 if ( isOnce ) {
85 // remove listener
86 // remove before trigger to prevent recursion
87 this.off( eventName, listener );
88 // unset once flag
89 delete onceListeners[ listener ];
90 }
91 // trigger listener
92 listener.apply( this, args );
93 }
94
95 return this;
96 };
97
98 proto.allOff = function() {
99 delete this._events;
100 delete this._onceEvents;
101 return this;
102 };
103
104 return EvEmitter;
105
106 } ) );
107 /*!
108 * imagesLoaded v5.0.0
109 * JavaScript is all like "You images are done yet or what?"
110 * MIT License
111 */
112
113 ( function( window, factory ) {
114 // universal module definition
115 if ( typeof module == 'object' && module.exports ) {
116 // CommonJS
117 module.exports = factory( window, require('ev-emitter') );
118 } else {
119 // browser global
120 window.imagesLoaded = factory( window, window.EvEmitter );
121 }
122
123 } )( typeof window !== 'undefined' ? window : this,
124 function factory( window, EvEmitter ) {
125
126 let $ = window.jQuery;
127 let console = window.console;
128
129 // -------------------------- helpers -------------------------- //
130
131 // turn element or nodeList into an array
132 function makeArray( obj ) {
133 // use object if already an array
134 if ( Array.isArray( obj ) ) return obj;
135
136 let isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
137 // convert nodeList to array
138 if ( isArrayLike ) return [ ...obj ];
139
140 // array of single index
141 return [ obj ];
142 }
143
144 // -------------------------- imagesLoaded -------------------------- //
145
146 /**
147 * @param {[Array, Element, NodeList, String]} elem
148 * @param {[Object, Function]} options - if function, use as callback
149 * @param {Function} onAlways - callback function
150 * @returns {ImagesLoaded}
151 */
152 function ImagesLoaded( elem, options, onAlways ) {
153 // coerce ImagesLoaded() without new, to be new ImagesLoaded()
154 if ( !( this instanceof ImagesLoaded ) ) {
155 return new ImagesLoaded( elem, options, onAlways );
156 }
157 // use elem as selector string
158 let queryElem = elem;
159 if ( typeof elem == 'string' ) {
160 queryElem = document.querySelectorAll( elem );
161 }
162 // bail if bad element
163 if ( !queryElem ) {
164 console.error(`Bad element for imagesLoaded ${queryElem || elem}`);
165 return;
166 }
167
168 this.elements = makeArray( queryElem );
169 this.options = {};
170 // shift arguments if no options set
171 if ( typeof options == 'function' ) {
172 onAlways = options;
173 } else {
174 Object.assign( this.options, options );
175 }
176
177 if ( onAlways ) this.on( 'always', onAlways );
178
179 this.getImages();
180 // add jQuery Deferred object
181 if ( $ ) this.jqDeferred = new $.Deferred();
182
183 // HACK check async to allow time to bind listeners
184 setTimeout( this.check.bind( this ) );
185 }
186
187 ImagesLoaded.prototype = Object.create( EvEmitter.prototype );
188
189 ImagesLoaded.prototype.getImages = function() {
190 this.images = [];
191
192 // filter & find items if we have an item selector
193 this.elements.forEach( this.addElementImages, this );
194 };
195
196 const elementNodeTypes = [ 1, 9, 11 ];
197
198 /**
199 * @param {Node} elem
200 */
201 ImagesLoaded.prototype.addElementImages = function( elem ) {
202 // filter siblings
203 if ( elem.nodeName === 'IMG' ) {
204 this.addImage( elem );
205 }
206 // get background image on element
207 if ( this.options.background === true ) {
208 this.addElementBackgroundImages( elem );
209 }
210
211 // find children
212 // no non-element nodes, #143
213 let { nodeType } = elem;
214 if ( !nodeType || !elementNodeTypes.includes( nodeType ) ) return;
215
216 let childImgs = elem.querySelectorAll('img');
217 // concat childElems to filterFound array
218 for ( let img of childImgs ) {
219 this.addImage( img );
220 }
221
222 // get child background images
223 if ( typeof this.options.background == 'string' ) {
224 let children = elem.querySelectorAll( this.options.background );
225 for ( let child of children ) {
226 this.addElementBackgroundImages( child );
227 }
228 }
229 };
230
231 const reURL = /url\((['"])?(.*?)\1\)/gi;
232
233 ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) {
234 let style = getComputedStyle( elem );
235 // Firefox returns null if in a hidden iframe https://bugzil.la/548397
236 if ( !style ) return;
237
238 // get url inside url("...")
239 let matches = reURL.exec( style.backgroundImage );
240 while ( matches !== null ) {
241 let url = matches && matches[2];
242 if ( url ) {
243 this.addBackground( url, elem );
244 }
245 matches = reURL.exec( style.backgroundImage );
246 }
247 };
248
249 /**
250 * @param {Image} img
251 */
252 ImagesLoaded.prototype.addImage = function( img ) {
253 let loadingImage = new LoadingImage( img );
254 this.images.push( loadingImage );
255 };
256
257 ImagesLoaded.prototype.addBackground = function( url, elem ) {
258 let background = new Background( url, elem );
259 this.images.push( background );
260 };
261
262 ImagesLoaded.prototype.check = function() {
263 this.progressedCount = 0;
264 this.hasAnyBroken = false;
265 // complete if no images
266 if ( !this.images.length ) {
267 this.complete();
268 return;
269 }
270
271 /* eslint-disable-next-line func-style */
272 let onProgress = ( image, elem, message ) => {
273 // HACK - Chrome triggers event before object properties have changed. #83
274 setTimeout( () => {
275 this.progress( image, elem, message );
276 } );
277 };
278
279 this.images.forEach( function( loadingImage ) {
280 loadingImage.once( 'progress', onProgress );
281 loadingImage.check();
282 } );
283 };
284
285 ImagesLoaded.prototype.progress = function( image, elem, message ) {
286 this.progressedCount++;
287 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;
288 // progress event
289 this.emitEvent( 'progress', [ this, image, elem ] );
290 if ( this.jqDeferred && this.jqDeferred.notify ) {
291 this.jqDeferred.notify( this, image );
292 }
293 // check if completed
294 if ( this.progressedCount === this.images.length ) {
295 this.complete();
296 }
297
298 if ( this.options.debug && console ) {
299 console.log( `progress: ${message}`, image, elem );
300 }
301 };
302
303 ImagesLoaded.prototype.complete = function() {
304 let eventName = this.hasAnyBroken ? 'fail' : 'done';
305 this.isComplete = true;
306 this.emitEvent( eventName, [ this ] );
307 this.emitEvent( 'always', [ this ] );
308 if ( this.jqDeferred ) {
309 let jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';
310 this.jqDeferred[ jqMethod ]( this );
311 }
312 };
313
314 // -------------------------- -------------------------- //
315
316 function LoadingImage( img ) {
317 this.img = img;
318 }
319
320 LoadingImage.prototype = Object.create( EvEmitter.prototype );
321
322 LoadingImage.prototype.check = function() {
323 // If complete is true and browser supports natural sizes,
324 // try to check for image status manually.
325 let isComplete = this.getIsImageComplete();
326 if ( isComplete ) {
327 // report based on naturalWidth
328 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
329 return;
330 }
331
332 // If none of the checks above matched, simulate loading on detached element.
333 this.proxyImage = new Image();
334 // add crossOrigin attribute. #204
335 if ( this.img.crossOrigin ) {
336 this.proxyImage.crossOrigin = this.img.crossOrigin;
337 }
338 this.proxyImage.addEventListener( 'load', this );
339 this.proxyImage.addEventListener( 'error', this );
340 // bind to image as well for Firefox. #191
341 this.img.addEventListener( 'load', this );
342 this.img.addEventListener( 'error', this );
343 this.proxyImage.src = this.img.currentSrc || this.img.src;
344 };
345
346 LoadingImage.prototype.getIsImageComplete = function() {
347 // check for non-zero, non-undefined naturalWidth
348 // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671
349 return this.img.complete && this.img.naturalWidth;
350 };
351
352 LoadingImage.prototype.confirm = function( isLoaded, message ) {
353 this.isLoaded = isLoaded;
354 let { parentNode } = this.img;
355 // emit progress with parent <picture> or self <img>
356 let elem = parentNode.nodeName === 'PICTURE' ? parentNode : this.img;
357 this.emitEvent( 'progress', [ this, elem, message ] );
358 };
359
360 // ----- events ----- //
361
362 // trigger specified handler for event type
363 LoadingImage.prototype.handleEvent = function( event ) {
364 let method = 'on' + event.type;
365 if ( this[ method ] ) {
366 this[ method ]( event );
367 }
368 };
369
370 LoadingImage.prototype.onload = function() {
371 this.confirm( true, 'onload' );
372 this.unbindEvents();
373 };
374
375 LoadingImage.prototype.onerror = function() {
376 this.confirm( false, 'onerror' );
377 this.unbindEvents();
378 };
379
380 LoadingImage.prototype.unbindEvents = function() {
381 this.proxyImage.removeEventListener( 'load', this );
382 this.proxyImage.removeEventListener( 'error', this );
383 this.img.removeEventListener( 'load', this );
384 this.img.removeEventListener( 'error', this );
385 };
386
387 // -------------------------- Background -------------------------- //
388
389 function Background( url, element ) {
390 this.url = url;
391 this.element = element;
392 this.img = new Image();
393 }
394
395 // inherit LoadingImage prototype
396 Background.prototype = Object.create( LoadingImage.prototype );
397
398 Background.prototype.check = function() {
399 this.img.addEventListener( 'load', this );
400 this.img.addEventListener( 'error', this );
401 this.img.src = this.url;
402 // check if image is already complete
403 let isComplete = this.getIsImageComplete();
404 if ( isComplete ) {
405 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
406 this.unbindEvents();
407 }
408 };
409
410 Background.prototype.unbindEvents = function() {
411 this.img.removeEventListener( 'load', this );
412 this.img.removeEventListener( 'error', this );
413 };
414
415 Background.prototype.confirm = function( isLoaded, message ) {
416 this.isLoaded = isLoaded;
417 this.emitEvent( 'progress', [ this, this.element, message ] );
418 };
419
420 // -------------------------- jQuery -------------------------- //
421
422 ImagesLoaded.makeJQueryPlugin = function( jQuery ) {
423 jQuery = jQuery || window.jQuery;
424 if ( !jQuery ) return;
425
426 // set local variable
427 $ = jQuery;
428 // $().imagesLoaded()
429 $.fn.imagesLoaded = function( options, onAlways ) {
430 let instance = new ImagesLoaded( this, options, onAlways );
431 return instance.jqDeferred.promise( $( this ) );
432 };
433 };
434 // try making plugin
435 ImagesLoaded.makeJQueryPlugin();
436
437 // -------------------------- -------------------------- //
438
439 return ImagesLoaded;
440
441 } );
442