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