PageSourceSearch

https://felderer.de/wp-content/plugins/ds-divi-extras/js/imagesloaded.js?ver=1.1.13

js felderer.de collected 2026-10-07 08:21:45 UTC 27,046 bytes, 898 lines download raw bytes

1/*
2Code in this file was copied from the Extra theme by Elegant Themes, released under the GNU General Public License version 2 or later (GPLv2+).
3Used in this project under the GNU General Public License version 3 (GPLv3).
4See ../license.txt for the GPLv3 license text, as well as other licenses referenced in this file.
5This file was modified by Jonathan Hall and/or others. Last modified 2020-04-15.
6*/
7
8/*!
9* imagesLoaded PACKAGED v3.1.8
10* JavaScript is all like "You images are done yet or what?"
11* @license MIT License
12*/
13
14/*!
15* EventEmitter v4.2.6 - git.io/ee
16* Oliver Caldwell
17* MIT license
18* @preserve
19*/
20
21(function () {
22
23	/**
24	 * Class for managing events.
25	 * Can be extended to provide event functionality in other classes.
26	 *
27	 * @class EventEmitter Manages event registering and emitting.
28	 */
29	function EventEmitter() {}
30
31	// Shortcuts to improve speed and size
32	var proto = EventEmitter.prototype;
33	var exports = this;
34	var originalGlobalValue = exports.EventEmitter;
35
36	/**
37	 * Finds the index of the listener for the event in it's storage array.
38	 *
39	 * @param {Function[]} listeners Array of listeners to search through.
40	 * @param {Function} listener Method to look for.
41	 * @return {Number} Index of the specified listener, -1 if not found
42	 * @api private
43	 */
44	function indexOfListener(listeners, listener) {
45		var i = listeners.length;
46		while (i--) {
47			if (listeners[i].listener === listener) {
48				return i;
49			}
50		}
51
52		return -1;
53	}
54
55	/**
56	 * Alias a method while keeping the context correct, to allow for overwriting of target method.
57	 *
58	 * @param {String} name The name of the target method.
59	 * @return {Function} The aliased method
60	 * @api private
61	 */
62	function alias(name) {
63		return function aliasClosure() {
64			return this[name].apply(this, arguments);
65		};
66	}
67
68	/**
69	 * Returns the listener array for the specified event.
70	 * Will initialise the event object and listener arrays if required.
71	 * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object c
vendor: 10,814 bytes, lines 71-364
71ontaining bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
72	 * Each property in the object response is an array of listener functions.
73	 *
74	 * @param {String|RegExp} evt Name of the event to return the listeners from.
75	 * @return {Function[]|Object} All listener functions for the event.
76	 */
77	proto.getListeners = function getListeners(evt) {
78		var events = this._getEvents();
79		var response;
80		var key;
81
82		// Return a concatenated array of all matching events if
83		// the selector is a regular expression.
84		if (typeof evt === 'object') {
85			response = {};
86			for (key in events) {
87				if (events.hasOwnProperty(key) && evt.test(key)) {
88					response[key] = events[key];
89				}
90			}
91		}
92		else {
93			response = events[evt] || (events[evt] = []);
94		}
95
96		return response;
97	};
98
99	/**
100	 * Takes a list of listener objects and flattens it into a list of listener functions.
101	 *
102	 * @param {Object[]} listeners Raw listener objects.
103	 * @return {Function[]} Just the listener functions.
104	 */
105	proto.flattenListeners = function flattenListeners(listeners) {
106		var flatListeners = [];
107		var i;
108
109		for (i = 0; i < listeners.length; i += 1) {
110			flatListeners.push(listeners[i].listener);
111		}
112
113		return flatListeners;
114	};
115
116	/**
117	 * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
118	 *
119	 * @param {String|RegExp} evt Name of the event to return the listeners from.
120	 * @return {Object} All listener functions for an event in an object.
121	 */
122	proto.getListenersAsObject = function getListenersAsObject(evt) {
123		var listeners = this.getListeners(evt);
124		var response;
125
126		if (listeners instanceof Array) {
127			response = {};
128			response[evt] = listeners;
129		}
130
131		return response || listeners;
132	};
133
134	/**
135	 * Adds a listener function to the specified event.
136	 * The listener will not be added if it is a duplicate.
137	 * If the listener returns true then it will be removed after it is called.
138	 * If you pass a regular expression as the event name then the listener will be added to all events that match it.
139	 *
140	 * @param {String|RegExp} evt Name of the event to attach the listener to.
141	 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
142	 * @return {Object} Current instance of EventEmitter for chaining.
143	 */
144	proto.addListener = function addListener(evt, listener) {
145		var listeners = this.getListenersAsObject(evt);
146		var listenerIsWrapped = typeof listener === 'object';
147		var key;
148
149		for (key in listeners) {
150			if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
151				listeners[key].push(listenerIsWrapped ? listener : {
152					listener: listener,
153					once: false
154				});
155			}
156		}
157
158		return this;
159	};
160
161	/**
162	 * Alias of addListener
163	 */
164	proto.on = alias('addListener');
165
166	/**
167	 * Semi-alias of addListener. It will add a listener that will be
168	 * automatically removed after it's first execution.
169	 *
170	 * @param {String|RegExp} evt Name of the event to attach the listener to.
171	 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
172	 * @return {Object} Current instance of EventEmitter for chaining.
173	 */
174	proto.addOnceListener = function addOnceListener(evt, listener) {
175		return this.addListener(evt, {
176			listener: listener,
177			once: true
178		});
179	};
180
181	/**
182	 * Alias of addOnceListener.
183	 */
184	proto.once = alias('addOnceListener');
185
186	/**
187	 * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
188	 * You need to tell it what event names should be matched by a regex.
189	 *
190	 * @param {String} evt Name of the event to create.
191	 * @return {Object} Current instance of EventEmitter for chaining.
192	 */
193	proto.defineEvent = function defineEvent(evt) {
194		this.getListeners(evt);
195		return this;
196	};
197
198	/**
199	 * Uses defineEvent to define multiple events.
200	 *
201	 * @param {String[]} evts An array of event names to define.
202	 * @return {Object} Current instance of EventEmitter for chaining.
203	 */
204	proto.defineEvents = function defineEvents(evts) {
205		for (var i = 0; i < evts.length; i += 1) {
206			this.defineEvent(evts[i]);
207		}
208		return this;
209	};
210
211	/**
212	 * Removes a listener function from the specified event.
213	 * When passed a regular expression as the event name, it will remove the listener from all events that match it.
214	 *
215	 * @param {String|RegExp} evt Name of the event to remove the listener from.
216	 * @param {Function} listener Method to remove from the event.
217	 * @return {Object} Current instance of EventEmitter for chaining.
218	 */
219	proto.removeListener = function removeListener(evt, listener) {
220		var listeners = this.getListenersAsObject(evt);
221		var index;
222		var key;
223
224		for (key in listeners) {
225			if (listeners.hasOwnProperty(key)) {
226				index = indexOfListener(listeners[key], listener);
227
228				if (index !== -1) {
229					listeners[key].splice(index, 1);
230				}
231			}
232		}
233
234		return this;
235	};
236
237	/**
238	 * Alias of removeListener
239	 */
240	proto.off = alias('removeListener');
241
242	/**
243	 * Adds listeners in bulk using the manipulateListeners method.
244	 * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
245	 * You can also pass it a regular expression to add the array of listeners to all events that match it.
246	 * Yeah, this function does quite a bit. That's probably a bad thing.
247	 *
248	 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
249	 * @param {Function[]} [listeners] An optional array of listener functions to add.
250	 * @return {Object} Current instance of EventEmitter for chaining.
251	 */
252	proto.addListeners = function addListeners(evt, listeners) {
253		// Pass through to manipulateListeners
254		return this.manipulateListeners(false, evt, listeners);
255	};
256
257	/**
258	 * Removes listeners in bulk using the manipulateListeners method.
259	 * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
260	 * You can also pass it an event name and an array of listeners to be removed.
261	 * You can also pass it a regular expression to remove the listeners from all events that match it.
262	 *
263	 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
264	 * @param {Function[]} [listeners] An optional array of listener functions to remove.
265	 * @return {Object} Current instance of EventEmitter for chaining.
266	 */
267	proto.removeListeners = function removeListeners(evt, listeners) {
268		// Pass through to manipulateListeners
269		return this.manipulateListeners(true, evt, listeners);
270	};
271
272	/**
273	 * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
274	 * The first argument will determine if the listeners are removed (true) or added (false).
275	 * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
276	 * You can also pass it an event name and an array of listeners to be added/removed.
277	 * You can also pass it a regular expression to manipulate the listeners of all events that match it.
278	 *
279	 * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
280	 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
281	 * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
282	 * @return {Object} Current instance of EventEmitter for chaining.
283	 */
284	proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
285		var i;
286		var value;
287		var single = remove ? this.removeListener : this.addListener;
288		var multiple = remove ? this.removeListeners : this.addListeners;
289
290		// If evt is an object then pass each of it's properties to this method
291		if (typeof evt === 'object' && !(evt instanceof RegExp)) {
292			for (i in evt) {
293				if (evt.hasOwnProperty(i) && (value = evt[i])) {
294					// Pass the single listener straight through to the singular method
295					if (typeof value === 'function') {
296						single.call(this, i, value);
297					}
298					else {
299						// Otherwise pass back to the multiple function
300						multiple.call(this, i, value);
301					}
302				}
303			}
304		}
305		else {
306			// So evt must be a string
307			// And listeners must be an array of listeners
308			// Loop over it and pass each one to the multiple method
309			i = listeners.length;
310			while (i--) {
311				single.call(this, evt, listeners[i]);
312			}
313		}
314
315		return this;
316	};
317
318	/**
319	 * Removes all listeners from a specified event.
320	 * If you do not specify an event then all listeners will be removed.
321	 * That means every event will be emptied.
322	 * You can also pass a regex to remove all events that match it.
323	 *
324	 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
325	 * @return {Object} Current instance of EventEmitter for chaining.
326	 */
327	proto.removeEvent = function removeEvent(evt) {
328		var type = typeof evt;
329		var events = this._getEvents();
330		var key;
331
332		// Remove different things depending on the state of evt
333		if (type === 'string') {
334			// Remove all listeners for the specified event
335			delete events[evt];
336		}
337		else if (type === 'object') {
338			// Remove all events matching the regex.
339			for (key in events) {
340				if (events.hasOwnProperty(key) && evt.test(key)) {
341					delete events[key];
342				}
343			}
344		}
345		else {
346			// Remove all listeners in all events
347			delete this._events;
348		}
349
350		return this;
351	};
352
353	/**
354	 * Alias of removeEvent.
355	 *
356	 * Added to mirror the node API.
357	 */
358	proto.removeAllListeners = alias('removeEvent');
359
360	/**
361	 * Emits an event of your choice.
362	 * When emitted, every listener attached to that event will be executed.
363	 * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
364	 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
365	 * So they will not arrive within the array on the other side, they will be separate.
366	 * You can also pass a regular expression to emit to all events that match it.
367	 *
368	 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
369	 * @param {Array} [args] Optional array of arguments to be passed to each listener.
370	 * @return {Object} Current instance of EventEmitter for chaining.
371	 */
372	proto.emitEvent = function emitEvent(evt, args) {
373		var listeners = this.getListenersAsObject(evt);
374		var listener;
375		var i;
376		var key;
377		var response;
378
379		for (key in listeners) {
380			if (listeners.hasOwnProperty(key)) {
381				i = listeners[key].length;
382
383				while (i--) {
384					// If the listener returns true then it shall be removed from the event
385					// The function is executed either with a basic call or an apply if there is an args array
386					listener = listeners[key][i];
387
388					if (listener.once === true) {
389						this.removeListener(evt, listener.listener);
390					}
391
392					response = listener.listener.apply(this, args || []);
393
394					if (response === this._getOnceReturnValue()) {
395						this.removeListener(evt, listener.listener);
396					}
397				}
398			}
399		}
400
401		return this;
402	};
403
404	/**
405	 * Alias of emitEvent
406	 */
407	proto.trigger = alias('emitEvent');
408
409	/**
410	 * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
411	 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
412	 *
413	 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
414	 * @param {...*} Optional additional arguments to be passed to each listener.
415	 * @return {Object} Current instance of EventEmitter for chaining.
416	 */
417	proto.emit = function emit(evt) {
418		var args = Array.prototype.slice.call(arguments, 1);
419		return this.emitEvent(evt, args);
420	};
421
422	/**
423	 * Sets the current value to check against when executing listeners. If a
424	 * listeners return value matches the one set here then it will be removed
425	 * after execution. This value defaults to true.
426	 *
427	 * @param {*} value The new value to check for when executing listeners.
428	 * @return {Object} Current instance of EventEmitter for chaining.
429	 */
430	proto.setOnceReturnValue = function setOnceReturnValue(value) {
431		this._onceReturnValue = value;
432		return this;
433	};
434
435	/**
436	 * Fetches the current value to check against when executing listeners. If
437	 * the listeners return value matches this one then it should be removed
438	 * automatically. It will return true by default.
439	 *
440	 * @return {*|Boolean} The current value to check for or the default, true.
441	 * @api private
442	 */
443	proto._getOnceReturnValue = function _getOnceReturnValue() {
444		if (this.hasOwnProperty('_onceReturnValue')) {
445			return this._onceReturnValue;
446		}
447		else {
448			return true;
449		}
450	};
451
452	/**
453	 * Fetches the events object and creates one if required.
454	 *
455	 * @return {Object} The events storage object.
456	 * @api private
457	 */
458	proto._getEvents = function _getEvents() {
459		return this._events || (this._events = {});
460	};
461
462	/**
463	 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
464	 *
465	 * @return {Function} Non conflicting EventEmitter class.
466	 */
467	EventEmitter.noConflict = function noConflict() {
468		exports.EventEmitter = originalGlobalValue;
469		return EventEmitter;
470	};
471
472	// Expose the class either via AMD, CommonJS or the global object
473	if (typeof define === 'function' && define.amd) {
474		define('eventEmitter/EventEmitter',[],function () {
475			return EventEmitter;
476		});
477	}
478	else if (typeof module === 'object' && module.exports){
479		module.exports = EventEmitter;
480	}
481	else {
482		this.EventEmitter = EventEmitter;
483	}
484}.call(this));
485
486/*!
487 * eventie v1.0.4
488 * event binding helper
489 *   eventie.bind( elem, 'click', myFn )
490 *   eventie.unbind( elem, 'click', myFn )
491 */
492
493/*jshint browser: true, undef: true, unused: true */
494/*global define: false */
495
496( function( window ) {
497
498
499
500var docElem = document.documentElement;
501
502var bind = function() {};
503
504function getIEEvent( obj ) {
505  var event = window.event;
506  // add event.target
507  event.target = event.target || event.srcElement || obj;
508  return event;
509}
510
511if ( docElem.addEventListener ) {
512  bind = function( obj, type, fn ) {
513    obj.addEventListener( type, fn, false );
514  };
515} else if ( docElem.attachEvent ) {
516  bind = function( obj, type, fn ) {
517    obj[ type + fn ] = fn.handleEvent ?
518      function() {
519        var event = getIEEvent( obj );
520        fn.handleEvent.call( fn, event );
521      } :
522      function() {
523        var event = getIEEvent( obj );
524        fn.call( obj, event );
525      };
526    obj.attachEvent( "on" + type, obj[ type + fn ] );
527  };
528}
529
530var unbind = function() {};
531
532if ( docElem.removeEventListener ) {
533  unbind = function( obj, type, fn ) {
534    obj.removeEventListener( type, fn, false );
535  };
536} else if ( docElem.detachEvent ) {
537  unbind = function( obj, type, fn ) {
538    obj.detachEvent( "on" + type, obj[ type + fn ] );
539    try {
540      delete obj[ type + fn ];
541    } catch ( err ) {
542      // can't delete window object properties
543      obj[ type + fn ] = undefined;
544    }
545  };
546}
547
548var eventie = {
549  bind: bind,
550  unbind: unbind
551};
552
553// transport
554if ( typeof define === 'function' && define.amd ) {
555  // AMD
556  define( 'eventie/eventie',eventie );
557} else {
558  // browser global
559  window.eventie = eventie;
560}
561
562})( this );
563
564/*!
565 * imagesLoaded v3.1.8
566 * JavaScript is all like "You images are done yet or what?"
567 * MIT License
568 */
569
570( function( window, factory ) {
571  // universal module definition
572
573  /*global define: false, module: false, require: false */
574
575  if ( typeof define === 'function' && define.amd ) {
576    // AMD
577    define( [
578      'eventEmitter/EventEmitter',
579      'eventie/eventie'
580    ], function( EventEmitter, eventie ) {
581      return factory( window, EventEmitter, eventie );
582    });
583  } else if ( typeof exports === 'object' ) {
584    // CommonJS
585    module.exports = factory(
586      window,
587      require('wolfy87-eventemitter'),
588      require('eventie')
589    );
590  } else {
591    // browser global
592    window.imagesLoaded = factory(
593      window,
594      window.EventEmitter,
595      window.eventie
596    );
597  }
598
599})( window,
600
601// --------------------------  factory -------------------------- //
602
603function factory( window, EventEmitter, eventie ) {
604
605
606
607var $ = window.jQuery;
608var console = window.console;
609var hasConsole = typeof console !== 'undefined';
610
611// -------------------------- helpers -------------------------- //
612
613// extend objects
614function extend( a, b ) {
615  for ( var prop in b ) {
616    a[ prop ] = b[ prop ];
617  }
618  return a;
619}
620
621var objToString = Object.prototype.toString;
622function isArray( obj ) {
623  return objToString.call( obj ) === '[object Array]';
624}
625
626// turn element or nodeList into an array
627function makeArray( obj ) {
628  var ary = [];
629  if ( isArray( obj ) ) {
630    // use object if already an array
631    ary = obj;
632  } else if ( typeof obj.length === 'number' ) {
633    // convert nodeList to array
634    for ( var i=0, len = obj.length; i < len; i++ ) {
635      ary.push( obj[i] );
636    }
637  } else {
638    // array of single index
639    ary.push( obj );
640  }
641  return ary;
642}
643
644  // -------------------------- imagesLoaded -------------------------- //
645
646  /**
647   * @param {Array, Element, NodeList, String} elem
648   * @param {Object or Function} options - if function, use as callback
649   * @param {Function} onAlways - callback function
650   */
651  function ImagesLoaded( elem, options, onAlways ) {
652    // coerce ImagesLoaded() without new, to be new ImagesLoaded()
653    if ( !( this instanceof ImagesLoaded ) ) {
654      return new ImagesLoaded( elem, options );
655    }
656    // use elem as selector string
657    if ( typeof elem === 'string' ) {
658      elem = document.querySelectorAll( elem );
659    }
660
661    this.elements = makeArray( elem );
662    this.options = extend( {}, this.options );
663
664    if ( typeof options === 'function' ) {
665      onAlways = options;
666    } else {
667      extend( this.options, options );
668    }
669
670    if ( onAlways ) {
671      this.on( 'always', onAlways );
672    }
673
674    this.getImages();
675
676    if ( $ ) {
677      // add jQuery Deferred object
678      this.jqDeferred = new $.Deferred();
679    }
680
681    // HACK check async to allow time to bind listeners
682    var _this = this;
683    setTimeout( function() {
684      _this.check();
685    });
686  }
687
688  ImagesLoaded.prototype = new EventEmitter();
689
690  ImagesLoaded.prototype.options = {};
691
692  ImagesLoaded.prototype.getImages = function() {
693    this.images = [];
694
695    // filter & find items if we have an item selector
696    for ( var i=0, len = this.elements.length; i < len; i++ ) {
697      var elem = this.elements[i];
698      // filter siblings
699      if ( elem.nodeName === 'IMG' ) {
700        this.addImage( elem );
701      }
702      // find children
703      // no non-element nodes, #143
704      var nodeType = elem.nodeType;
705      if ( !nodeType || !( nodeType === 1 || nodeType === 9 || nodeType === 11 ) ) {
706        continue;
707      }
708      var childElems = elem.querySelectorAll('img');
709      // concat childElems to filterFound array
710      for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
711        var img = childElems[j];
712        this.addImage( img );
713      }
714    }
715  };
716
717  /**
718   * @param {Image} img
719   */
720  ImagesLoaded.prototype.addImage = function( img ) {
721    var loadingImage = new LoadingImage( img );
722    this.images.push( loadingImage );
723  };
724
725  ImagesLoaded.prototype.check = function() {
726    var _this = this;
727    var checkedCount = 0;
728    var length = this.images.length;
729    this.hasAnyBroken = false;
730    // complete if no images
731    if ( !length ) {
732      this.complete();
733      return;
734    }
735
736    function onConfirm( image, message ) {
737      if ( _this.options.debug && hasConsole ) {
738        console.log( 'confirm', image, message );
739      }
740
741      _this.progress( image );
742      checkedCount++;
743      if ( checkedCount === length ) {
744        _this.complete();
745      }
746      return true; // bind once
747    }
748
749    for ( var i=0; i < length; i++ ) {
750      var loadingImage = this.images[i];
751      loadingImage.on( 'confirm', onConfirm );
752      loadingImage.check();
753    }
754  };
755
756  ImagesLoaded.prototype.progress = function( image ) {
757    this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;
758    // HACK - Chrome triggers event before object properties have changed. #83
759    var _this = this;
760    setTimeout( function() {
761      _this.emit( 'progress', _this, image );
762      if ( _this.jqDeferred && _this.jqDeferred.notify ) {
763        _this.jqDeferred.notify( _this, image );
764      }
765    });
766  };
767
768  ImagesLoaded.prototype.complete = function() {
769    var eventName = this.hasAnyBroken ? 'fail' : 'done';
770    this.isComplete = true;
771    var _this = this;
772    // HACK - another setTimeout so that confirm happens after progress
773    setTimeout( function() {
774      _this.emit( eventName, _this );
775      _this.emit( 'always', _this );
776      if ( _this.jqDeferred ) {
777        var jqMethod = _this.hasAnyBroken ? 'reject' : 'resolve';
778        _this.jqDeferred[ jqMethod ]( _this );
779      }
780    });
781  };
782
783  // -------------------------- jquery -------------------------- //
784
785  if ( $ ) {
786    $.fn.imagesLoaded = function( options, callback ) {
787      var instance = new ImagesLoaded( this, options, callback );
788      return instance.jqDeferred.promise( $(this) );
789    };
790  }
791
792
793  // --------------------------  -------------------------- //
794
795  function LoadingImage( img ) {
796    this.img = img;
797  }
798
799  LoadingImage.prototype = new EventEmitter();
800
801  LoadingImage.prototype.check = function() {
802    // first check cached any previous images that have same src
803    var resource = cache[ this.img.src ] || new Resource( this.img.src );
804    if ( resource.isConfirmed ) {
805      this.confirm( resource.isLoaded, 'cached was confirmed' );
806      return;
807    }
808
809    // If complete is true and browser supports natural sizes,
810    // try to check for image status manually.
811    if ( this.img.complete && this.img.naturalWidth !== undefined ) {
812      // report based on naturalWidth
813      this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
814      return;
815    }
816
817    // If none of the checks above matched, simulate loading on detached element.
818    var _this = this;
819    resource.on( 'confirm', function( resrc, message ) {
820      _this.confirm( resrc.isLoaded, message );
821      return true;
822    });
823
824    resource.check();
825  };
826
827  LoadingImage.prototype.confirm = function( isLoaded, message ) {
828    this.isLoaded = isLoaded;
829    this.emit( 'confirm', this, message );
830  };
831
832  // -------------------------- Resource -------------------------- //
833
834  // Resource checks each src, only once
835  // separate class from LoadingImage to prevent memory leaks. See #115
836
837  var cache = {};
838
839  function Resource( src ) {
840    this.src = src;
841    // add to cache
842    cache[ src ] = this;
843  }
844
845  Resource.prototype = new EventEmitter();
846
847  Resource.prototype.check = function() {
848    // only trigger checking once
849    if ( this.isChecked ) {
850      return;
851    }
852    // simulate loading on detached element
853    var proxyImage = new Image();
854    eventie.bind( proxyImage, 'load', this );
855    eventie.bind( proxyImage, 'error', this );
856    proxyImage.src = this.src;
857    // set flag
858    this.isChecked = true;
859  };
860
861  // ----- events ----- //
862
863  // trigger specified handler for event type
864  Resource.prototype.handleEvent = function( event ) {
865    var method = 'on' + event.type;
866    if ( this[ method ] ) {
867      this[ method ]( event );
868    }
869  };
870
871  Resource.prototype.onload = function( event ) {
872    this.confirm( true, 'onload' );
873    this.unbindProxyEvents( event );
874  };
875
876  Resource.prototype.onerror = function( event ) {
877    this.confirm( false, 'onerror' );
878    this.unbindProxyEvents( event );
879  };
880
881  // ----- confirm ----- //
882
883  Resource.prototype.confirm = function( isLoaded, message ) {
884    this.isConfirmed = true;
885    this.isLoaded = isLoaded;
886    this.emit( 'confirm', this, message );
887  };
888
889  Resource.prototype.unbindProxyEvents = function( event ) {
890    eventie.unbind( event.target, 'load', this );
891    eventie.unbind( event.target, 'error', this );
892  };
893
894  // -----  ----- //
895
896  return ImagesLoaded;
897
898});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.