1/*! 2 * imagesLoaded PACKAGED v3.0.2 3 * JavaScript is all like "You images are done yet or what?" 4 */ 5 6/*! 7 * EventEmitter v4.1.0 - git.io/ee 8 * Oliver Caldwell 9 * MIT license 10 * @preserve 11 */ 12 13(function(exports) { 14 // Place the script in strict mode 15 'use strict'; 16 17 /** 18 * Class for managing events. 19 * Can be extended to provide event functionality in other classes. 20 * 21 * @class Manages event registering and emitting. 22 */ 23 function EventEmitter() { 24 } 25 26 // Shortcuts to improve speed and size 27 28 // Easy access to the prototype 29 var proto = EventEmitter.prototype, 30 nativeIndexOf = Array.prototype.indexOf ? true : false; 31 32 /** 33 * Finds the index of the listener for the event in it's storage array. 34 * 35 * @param {Function} listener Method to look for. 36 * @param {Function[]} listeners Array of listeners to search through. 37 * @return {Number} Index of the specified listener, -1 if not found 38 * @api private 39 */ 40 function indexOfListener(listener, listeners) { 41 // Return the index via the native method if possible 42 if (nativeIndexOf) { 43 return listeners.indexOf(listener); 44 } 45 46 // There is no native method 47 // Use a manual loop to find the index 48 var i = listeners.length; 49 while (i--) { 50 // If the listener matches, return it's index 51 if (listeners[i] === listener) { 52 return i; 53 } 54 } 55 56 // Default to returning -1 57 return -1; 58 } 59 60 /** 61 * Fetches the events object and creates one if required. 62 * 63 * @return {Object} The events storage object. 64 * @api private 65 */ 66 proto._getEvents = function() { 67 return this._events || (this._events = {}); 68 }; 69 70 /** 71 * Returns the listener array for the specified event. 72 * Will initialise the event object and listener arrays if required. 73 * 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
73ontaining bar and baz. But only if you have either defined them with defineEvent or added some listeners to them. 74 * Each property in the object response is an array of listener functions. 75 * 76 * @param {String|RegExp} evt Name of the event to return the listeners from. 77 * @return {Function[]|Object} All listener functions for the event. 78 */ 79 proto.getListeners = function(evt) { 80 // Create a shortcut to the storage object 81 // Initialise it if it does not exists yet 82 var events = this._getEvents(), 83 response, 84 key; 85 86 // Return a concatenated array of all matching events if 87 // the selector is a regular expression. 88 if (typeof evt === 'object') { 89 response = {}; 90 for (key in events) { 91 if (events.hasOwnProperty(key) && evt.test(key)) { 92 response[key] = events[key]; 93 } 94 } 95 } 96 else { 97 response = events[evt] || (events[evt] = []); 98 } 99 100 return response; 101 }; 102 103 /** 104 * 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. 105 * 106 * @param {String|RegExp} evt Name of the event to return the listeners from. 107 * @return {Object} All listener functions for an event in an object. 108 */ 109 proto.getListenersAsObject = function(evt) { 110 var listeners = this.getListeners(evt), 111 response; 112 113 if (listeners instanceof Array) { 114 response = {}; 115 response[evt] = listeners; 116 } 117 118 return response || listeners; 119 }; 120 121 /** 122 * Adds a listener function to the specified event. 123 * The listener will not be added if it is a duplicate. 124 * If the listener returns true then it will be removed after it is called. 125 * If you pass a regular expression as the event name then the listener will be added to all events that match it. 126 * 127 * @param {String|RegExp} evt Name of the event to attach the listener to. 128 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 129 * @return {Object} Current instance of EventEmitter for chaining. 130 */ 131 proto.addListener = function(evt, listener) { 132 var listeners = this.getListenersAsObject(evt), 133 key; 134 135 for (key in listeners) { 136 if (listeners.hasOwnProperty(key) && 137 indexOfListener(listener, listeners[key]) === -1) { 138 listeners[key].push(listener); 139 } 140 } 141 142 // Return the instance of EventEmitter to allow chaining 143 return this; 144 }; 145 146 /** 147 * Alias of addListener 148 */ 149 proto.on = proto.addListener; 150 151 /** 152 * 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. 153 * You need to tell it what event names should be matched by a regex. 154 * 155 * @param {String} evt Name of the event to create. 156 * @return {Object} Current instance of EventEmitter for chaining. 157 */ 158 proto.defineEvent = function(evt) { 159 this.getListeners(evt); 160 return this; 161 }; 162 163 /** 164 * Uses defineEvent to define multiple events. 165 * 166 * @param {String[]} evts An array of event names to define. 167 * @return {Object} Current instance of EventEmitter for chaining. 168 */ 169 proto.defineEvents = function(evts) 170 { 171 for (var i = 0; i < evts.length; i += 1) { 172 this.defineEvent(evts[i]); 173 } 174 return this; 175 }; 176 177 /** 178 * Removes a listener function from the specified event. 179 * When passed a regular expression as the event name, it will remove the listener from all events that match it. 180 * 181 * @param {String|RegExp} evt Name of the event to remove the listener from. 182 * @param {Function} listener Method to remove from the event. 183 * @return {Object} Current instance of EventEmitter for chaining. 184 */ 185 proto.removeListener = function(evt, listener) { 186 var listeners = this.getListenersAsObject(evt), 187 index, 188 key; 189 190 for (key in listeners) { 191 if (listeners.hasOwnProperty(key)) { 192 index = indexOfListener(listener, listeners[key]); 193 194 if (index !== -1) { 195 listeners[key].splice(index, 1); 196 } 197 } 198 } 199 200 // Return the instance of EventEmitter to allow chaining 201 return this; 202 }; 203 204 /** 205 * Alias of removeListener 206 */ 207 proto.off = proto.removeListener; 208 209 /** 210 * Adds listeners in bulk using the manipulateListeners method. 211 * 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. 212 * You can also pass it a regular expression to add the array of listeners to all events that match it. 213 * Yeah, this function does quite a bit. That's probably a bad thing. 214 * 215 * @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. 216 * @param {Function[]} [listeners] An optional array of listener functions to add. 217 * @return {Object} Current instance of EventEmitter for chaining. 218 */ 219 proto.addListeners = function(evt, listeners) { 220 // Pass through to manipulateListeners 221 return this.manipulateListeners(false, evt, listeners); 222 }; 223 224 /** 225 * Removes listeners in bulk using the manipulateListeners method. 226 * 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. 227 * You can also pass it an event name and an array of listeners to be removed. 228 * You can also pass it a regular expression to remove the listeners from all events that match it. 229 * 230 * @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. 231 * @param {Function[]} [listeners] An optional array of listener functions to remove. 232 * @return {Object} Current instance of EventEmitter for chaining. 233 */ 234 proto.removeListeners = function(evt, listeners) { 235 // Pass through to manipulateListeners 236 return this.manipulateListeners(true, evt, listeners); 237 }; 238 239 /** 240 * 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. 241 * The first argument will determine if the listeners are removed (true) or added (false). 242 * 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. 243 * You can also pass it an event name and an array of listeners to be added/removed. 244 * You can also pass it a regular expression to manipulate the listeners of all events that match it. 245 * 246 * @param {Boolean} remove True if you want to remove listeners, false if you want to add. 247 * @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. 248 * @param {Function[]} [listeners] An optional array of listener functions to add/remove. 249 * @return {Object} Current instance of EventEmitter for chaining. 250 */ 251 proto.manipulateListeners = function(remove, evt, listeners) { 252 // Initialise any required variables 253 var i, 254 value, 255 single = remove ? this.removeListener : this.addListener, 256 multiple = remove ? this.removeListeners : this.addListeners; 257 258 // If evt is an object then pass each of it's properties to this method 259 if (typeof evt === 'object' && !(evt instanceof RegExp)) { 260 for (i in evt) { 261 if (evt.hasOwnProperty(i) && (value = evt[i])) { 262 // Pass the single listener straight through to the singular method 263 if (typeof value === 'function') { 264 single.call(this, i, value); 265 } 266 else { 267 // Otherwise pass back to the multiple function 268 multiple.call(this, i, value); 269 } 270 } 271 } 272 } 273 else { 274 // So evt must be a string 275 // And listeners must be an array of listeners 276 // Loop over it and pass each one to the multiple method 277 i = listeners.length; 278 while (i--) { 279 single.call(this, evt, listeners[i]); 280 } 281 } 282 283 // Return the instance of EventEmitter to allow chaining 284 return this; 285 }; 286 287 /** 288 * Removes all listeners from a specified event. 289 * If you do not specify an event then all listeners will be removed. 290 * That means every event will be emptied. 291 * You can also pass a regex to remove all events that match it. 292 * 293 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. 294 * @return {Object} Current instance of EventEmitter for chaining. 295 */ 296 proto.removeEvent = function(evt) { 297 var type = typeof evt, 298 events = this._getEvents(), 299 key; 300 301 // Remove different things depending on the state of evt 302 if (type === 'string') { 303 // Remove all listeners for the specified event 304 delete events[evt]; 305 } 306 else if (type === 'object') { 307 // Remove all events matching the regex. 308 for (key in events) { 309 if (events.hasOwnProperty(key) && evt.test(key)) { 310 delete events[key]; 311 } 312 } 313 } 314 else { 315 // Remove all listeners in all events 316 delete this._events; 317 } 318 319 // Return the instance of EventEmitter to allow chaining 320 return this; 321 }; 322 323 /** 324 * Emits an event of your choice. 325 * When emitted, every listener attached to that event will be executed. 326 * If you pass the optional argument array then those arguments will be passed to every listener upon execution. 327 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately. 328 * So they will not arrive within the array on the other side, they will be separate. 329 * You can also pass a regular expression to emit to all events that match it. 330 * 331 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 332 * @param {Array} [args] Optional array of arguments to be passed to each listener. 333 * @return {Object} Current instance of EventEmitter for chaining. 334 */ 335 proto.emitEvent = function(evt, args) { 336 var listeners = this.getListenersAsObject(evt), 337 i, 338 key, 339 response; 340 341 for (key in listeners) { 342 if (listeners.hasOwnProperty(key)) { 343 i = listeners[key].length; 344 345 while (i--) { 346 // If the listener returns true then it shall be removed from the event 347 // The function is executed either with a basic call or an apply if there is an args array 348 response = args ? listeners[key][i].apply(null, args
348) : listeners[key][i](); 349 if (response === true) { 350 this.removeListener(evt, listeners[key][i]); 351 } 352 } 353 } 354 } 355 356 // Return the instance of EventEmitter to allow chaining 357 return this; 358 }; 359 360 /** 361 * Alias of emitEvent 362 */ 363 proto.trigger = proto.emitEvent; 364 365 /** 366 * 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. 367 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. 368 * 369 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 370 * @param {...*} Optional additional arguments to be passed to each listener. 371 * @return {Object} Current instance of EventEmitter for chaining. 372 */ 373 proto.emit = function(evt) { 374 var args = Array.prototype.slice.call(arguments, 1); 375 return this.emitEvent(evt, args); 376 }; 377 378 // Expose the class either via AMD or the global object 379 if (typeof define === 'function' && define.amd) { 380 define(function() { 381 return EventEmitter; 382 }); 383 } 384 else { 385 exports.EventEmitter = EventEmitter; 386 } 387}(this)); 388/*! 389 * eventie v1.0.3 390 * event binding helper 391 * eventie.bind( elem, 'click', myFn ) 392 * eventie.unbind( elem, 'click', myFn ) 393 */ 394 395/*jshint browser: true, undef: true, unused: true */ 396/*global define: false */ 397 398(function(window) { 399 400 'use strict'; 401 402 var docElem = document.documentElement; 403 404 var bind = function() { 405 }; 406 407 if (docElem.addEventListener) { 408 bind = function(obj, type, fn) { 409 obj.addEventListener(type, fn, false); 410 }; 411 } else if (docElem.attachEvent) { 412 bind = function(obj, type, fn) { 413 obj[ type + fn ] = fn.handleEvent ? 414 function() { 415 var event = window.event; 416 // add event.target 417 event.target = event.target || event.srcElement; 418 fn.handleEvent.call(fn, event); 419 } : 420 function() { 421 var event = window.event; 422 // add event.target 423 event.target = event.target || event.srcElement; 424 fn.call(obj, event); 425 }; 426 obj.attachEvent("on" + type, obj[ type + fn ]); 427 }; 428 } 429 430 var unbind = function() { 431 }; 432 433 if (docElem.removeEventListener) { 434 unbind = function(obj, type, fn) { 435 obj.removeEventListener(type, fn, false); 436 }; 437 } else if (docElem.detachEvent) { 438 unbind = function(obj, type, fn) { 439 obj.detachEvent("on" + type, obj[ type + fn ]); 440 try { 441 delete obj[ type + fn ]; 442 } catch (err) { 443 // can't delete window object properties 444 obj[ type + fn ] = undefined; 445 } 446 }; 447 } 448 449 var eventie = { 450 bind: bind, 451 unbind: unbind 452 }; 453 454// transport 455 if (typeof define === 'function' && define.amd) { 456 // AMD 457 define(eventie); 458 } else { 459 // browser global 460 window.eventie = eventie; 461 } 462 463})(this); 464 465/*! 466 * imagesLoaded v3.0.2 467 * JavaScript is all like "You images are done yet or what?" 468 */ 469 470(function(window) { 471 472 'use strict'; 473 474 var $ = window.jQuery; 475 var console = window.console; 476 var hasConsole = typeof console !== 'undefined'; 477 478// -------------------------- helpers -------------------------- // 479 480// extend objects 481 function extend(a, b) { 482 for (var prop in b) { 483 a[ prop ] = b[ prop ]; 484 } 485 return a; 486 } 487 488 var objToString = Object.prototype.toString; 489 function isArray(obj) { 490 return objToString.call(obj) === '[object Array]'; 491 } 492 493// turn element or nodeList into an array 494 function makeArray(obj) { 495 var ary = []; 496 if (isArray(obj)) { 497 // use object if already an array 498 ary = obj; 499 } else if (typeof obj.length === 'number') { 500 // convert nodeList to array 501 for (var i = 0, len = obj.length; i < len; i++) { 502 ary.push(obj[i]); 503 } 504 } else { 505 // array of single index 506 ary.push(obj); 507 } 508 return ary; 509 } 510 511// -------------------------- -------------------------- // 512 513 function defineImagesLoaded(EventEmitter, eventie) { 514 515 /** 516 * @param {Array, Element, NodeList, String} elem 517 * @param {Object or Function} options - if function, use as callback 518 * @param {Function} onAlways - callback function 519 */ 520 function ImagesLoaded(elem, options, onAlways) { 521 // coerce ImagesLoaded() without new, to be new ImagesLoaded() 522 if (!(this instanceof ImagesLoaded)) { 523 return new ImagesLoaded(elem, options); 524 } 525 // use elem as selector string 526 if (typeof elem === 'string') { 527 elem = document.querySelectorAll(elem); 528 } 529 530 this.elements = makeArray(elem); 531 this.options = extend({}, this.options); 532 533 if (typeof options === 'function') { 534 onAlways = options; 535 } else { 536 extend(this.options, options); 537 } 538 539 if (onAlways) { 540 this.on('always', onAlways); 541 } 542 543 this.getImages(); 544 545 if ($) { 546 // add jQuery Deferred object 547 this.jqDeferred = new $.Deferred(); 548 } 549 550 // HACK check async to allow time to bind listeners 551 var _this = this; 552 setTimeout(function() { 553 _this.check(); 554 }); 555 } 556 557 ImagesLoaded.prototype = new EventEmitter(); 558 559 ImagesLoaded.prototype.options = {}; 560 561 ImagesLoaded.prototype.getImages = function() { 562 this.images = []; 563 564 // filter & find items if we have an item selector 565 for (var i = 0, len = this.elements.length; i < len; i++) { 566 var elem = this.elements[i]; 567 // filter siblings 568 if (elem.nodeName === 'IMG') { 569 this.addImage(elem); 570 } 571 // find children 572 var childElems = elem.querySelectorAll('img'); 573 // concat childElems to filterFound array 574 for (var j = 0, jLen = childElems.length; j < jLen; j++) { 575 var img = childElems[j]; 576 this.addImage(img); 577 } 578 } 579 }; 580 581 /** 582 * @param {Image} img 583 */ 584 ImagesLoaded.prototype.addImage = function(img) { 585 var loadingImage = new LoadingImage(img); 586 this.images.push(loadingImage); 587 }; 588
589 ImagesLoaded.prototype.check = function() { 590 var _this = this; 591 var checkedCount = 0; 592 var length = this.images.length; 593 this.hasAnyBroken = false; 594 // complete if no images 595 if (!length) { 596 this.complete(); 597 return; 598 } 599 600 function onConfirm(image, message) { 601 if (_this.options.debug && hasConsole) { 602 console.log('confirm', image, message); 603 } 604 605 _this.progress(image); 606 checkedCount++; 607 if (checkedCount === length) { 608 _this.complete(); 609 } 610 return true; // bind once 611 } 612 613 for (var i = 0; i < length; i++) { 614 var loadingImage = this.images[i]; 615 loadingImage.on('confirm', onConfirm); 616 loadingImage.check(); 617 } 618 }; 619 620 ImagesLoaded.prototype.progress = function(image) { 621 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 622 this.emit('progress', this, image); 623 if (this.jqDeferred) { 624 this.jqDeferred.notify(this, image); 625 } 626 }; 627 628 ImagesLoaded.prototype.complete = function() { 629 var eventName = this.hasAnyBroken ? 'fail' : 'done'; 630 this.isComplete = true; 631 this.emit(eventName, this); 632 this.emit('always', this); 633 if (this.jqDeferred) { 634 var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; 635 this.jqDeferred[ jqMethod ](this); 636 } 637 }; 638 639 // -------------------------- jquery -------------------------- // 640 641 if ($) { 642 $.fn.imagesLoaded = function(options, callback) { 643 var instance = new ImagesLoaded(this, options, callback); 644 return instance.jqDeferred.promise($(this)); 645 }; 646 } 647 648 649 // -------------------------- -------------------------- // 650 651 var cache = {}; 652 653 function LoadingImage(img) { 654 this.img = img; 655 } 656 657 LoadingImage.prototype = new EventEmitter(); 658 659 LoadingImage.prototype.check = function() { 660 // first check cached any previous images that have same src 661 var cached = cache[ this.img.src ]; 662 if (cached) { 663 this.useCached(cached); 664 return; 665 } 666 // add this to cache 667 cache[ this.img.src ] = this; 668 669 // If complete is true and browser supports natural sizes, 670 // try to check for image status manually. 671 if (this.img.complete && this.img.naturalWidth !== undefined) { 672 // report based on naturalWidth 673 this.confirm(this.img.naturalWidth !== 0, 'naturalWidth'); 674 return; 675 } 676 677 // If none of the checks above matched, simulate loading on detached element. 678 var proxyImage = this.proxyImage = new Image(); 679 eventie.bind(proxyImage, 'load', this); 680 eventie.bind(proxyImage, 'error', this); 681 proxyImage.src = this.img.src; 682 }; 683 684 LoadingImage.prototype.useCached = function(cached) { 685 if (cached.isConfirmed) { 686 this.confirm(cached.isLoaded, 'cached was confirmed'); 687 } else { 688 var _this = this; 689 cached.on('confirm', function(image) { 690 _this.confirm(image.isLoaded, 'cache emitted confirmed'); 691 return true; // bind once 692 }); 693 } 694 }; 695 696 LoadingImage.prototype.confirm = function(isLoaded, message) { 697 this.isConfirmed = true; 698 this.isLoaded = isLoaded; 699 this.emit('confirm', this, message); 700 }; 701 702 // trigger specified handler for event type 703 LoadingImage.prototype.handleEvent = function(event) { 704 var method = 'on' + event.type; 705 if (this[ method ]) { 706 this[ method ](event); 707 } 708 }; 709 710 LoadingImage.prototype.onload = function() { 711 this.confirm(true, 'onload'); 712 this.unbindProxyEvents(); 713 }; 714 715 LoadingImage.prototype.onerror = function() { 716 this.confirm(false, 'onerror'); 717 this.unbindProxyEvents(); 718 }; 719 720 LoadingImage.prototype.unbindProxyEvents = function() { 721 eventie.unbind(this.proxyImage, 'load', this); 722 eventie.unbind(this.proxyImage, 'error', this); 723 }; 724 725 // ----- ----- // 726 727 return ImagesLoaded; 728 } 729 730// -------------------------- transport -------------------------- // 731 732 if (typeof define === 'function' && define.amd) { 733 // AMD 734 define([ 735 'eventEmitter', 736 'eventie' 737 ], 738 defineImagesLoaded); 739 } else { 740 // browser global 741 window.imagesLoaded = defineImagesLoaded( 742 window.EventEmitter, 743 window.eventie 744 ); 745 } 746 747})(window);
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.