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.