1/* 2 * QueryLoader v2 - A simple script to create a preloader for images 3 * 4 * For instructions read the original post: 5 * http://www.gayadesign.com/diy/queryloader2-preload-your-images-with-ease/ 6 * 7 * Copyright (c) 2011 - Gaya Kessler 8 * 9 * Licensed under the MIT license: 10 * http://www.opensource.org/licenses/mit-license.php 11 * 12 * Version: 2.9.0 13 * Last update: 2014-01-31 14 */ 15(function($){/*! 16 * eventie v1.0.5 17 * event binding helper 18 * eventie.bind( elem, 'click', myFn ) 19 * eventie.unbind( elem, 'click', myFn ) 20 * MIT license 21 */ 22 23/*jshint browser: true, undef: true, unused: true */ 24/*global define: false, module: false */ 25 26( function( window ) { 27 28'use strict'; 29 30var docElem = document.documentElement; 31 32var bind = function() {}; 33 34function getIEEvent( obj ) { 35 var event = window.event; 36 // add event.target 37 event.target = event.target || event.srcElement || obj; 38 return event; 39} 40 41if ( docElem.addEventListener ) { 42 bind = function( obj, type, fn ) { 43 obj.addEventListener( type, fn, false ); 44 }; 45} else if ( docElem.attachEvent ) { 46 bind = function( obj, type, fn ) { 47 obj[ type + fn ] = fn.handleEvent ? 48 function() { 49 var event = getIEEvent( obj ); 50 fn.handleEvent.call( fn, event ); 51 } : 52 function() { 53 var event = getIEEvent( obj ); 54 fn.call( obj, event ); 55 }; 56 obj.attachEvent( "on" + type, obj[ type + fn ] ); 57 }; 58} 59 60var unbind = function() {}; 61 62if ( docElem.removeEventListener ) { 63 unbind = function( obj, type, fn ) { 64 obj.removeEventListener( type, fn, false ); 65 }; 66} else if ( docElem.detachEvent ) { 67 unbind = function( obj, type, fn ) { 68 obj.detachEvent( "on" + type, obj[ type + fn ] ); 69 try { 70 delete obj[ type + fn ]; 71 } catch ( err ) { 72 // can't delete window object properties 73 obj[ type + fn ] = undefined; 74 } 75 }; 76} 77 78var eventie = { 79 bind: bind, 80 unbind: unbind 81}; 82 83// ----- module definition ----- // 84 85if ( typeof define === 'function' && define.amd ) { 86 // AMD 87 define( eventie ); 88} else if ( typeof exports === 'object' ) { 89 // CommonJS 90 module.exports = eventie; 91} else { 92 // browser global 93 window.eventie = eventie; 94} 95 96})( this ); 97 98/*! 99 * EventEmitter v4.2.7 - git.io/ee 100 * Oliver Caldwell 101 * MIT license 102 * @preserve 103 */ 104 105(function () { 106 'use strict'; 107 108 /** 109 * Class for managing events. 110 * Can be extended to provide event functionality in other classes. 111 * 112 * @class EventEmitter Manages event registering and emitting. 113 */ 114 function EventEmitter() {} 115 116 // Shortcuts to improve speed and size 117 var proto = EventEmitter.prototype; 118 var exports = this; 119 var originalGlobalValue = exports.EventEmitter;
vendor: 15,308 bytes, lines 119-557
119 120 121 /** 122 * Finds the index of the listener for the event in it's storage array. 123 * 124 * @param {Function[]} listeners Array of listeners to search through. 125 * @param {Function} listener Method to look for. 126 * @return {Number} Index of the specified listener, -1 if not found 127 * @api private 128 */ 129 function indexOfListener(listeners, listener) { 130 var i = listeners.length; 131 while (i--) { 132 if (listeners[i].listener === listener) { 133 return i; 134 } 135 } 136 137 return -1; 138 } 139 140 /** 141 * Alias a method while keeping the context correct, to allow for overwriting of target method. 142 * 143 * @param {String} name The name of the target method. 144 * @return {Function} The aliased method 145 * @api private 146 */ 147 function alias(name) { 148 return function aliasClosure() { 149 return this[name].apply(this, arguments); 150 }; 151 } 152 153 /** 154 * Returns the listener array for the specified event. 155 * Will initialise the event object and listener arrays if required. 156 * 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 containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them. 157 * Each property in the object response is an array of listener functions. 158 * 159 * @param {String|RegExp} evt Name of the event to return the listeners from. 160 * @return {Function[]|Object} All listener functions for the event. 161 */ 162 proto.getListeners = function getListeners(evt) { 163 var events = this._getEvents(); 164 var response; 165 var key; 166 167 // Return a concatenated array of all matching events if 168 // the selector is a regular expression. 169 if (evt instanceof RegExp) { 170 response = {}; 171 for (key in events) { 172 if (events.hasOwnProperty(key) && evt.test(key)) { 173 response[key] = events[key]; 174 } 175 } 176 } 177 else { 178 response = events[evt] || (events[evt] = []); 179 } 180 181 return response; 182 }; 183 184 /** 185 * Takes a list of listener objects and flattens it into a list of listener functions. 186 * 187 * @param {Object[]} listeners Raw listener objects. 188 * @return {Function[]} Just the listener functions. 189 */ 190 proto.flattenListeners = function flattenListeners(listeners) { 191 var flatListeners = []; 192 var i; 193 194 for (i = 0; i < listeners.length; i += 1) { 195 flatListeners.push(listeners[i].listener); 196 } 197 198 return flatListeners; 199 }; 200 201 /** 202 * 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. 203 * 204 * @param {String|RegExp} evt Name of the event to return the listeners from. 205 * @return {Object} All listener functions for an event in an object. 206 */ 207 proto.getListenersAsObject = function getListenersAsObject(evt) { 208 var listeners = this.getListeners(evt); 209 var response; 210 211 if (listeners instanceof Array) { 212 response = {}; 213 response[evt] = listeners; 214 } 215 216 return response || listeners; 217 }; 218 219 /** 220 * Adds a listener function to the specified event. 221 * The listener will not be added if it is a duplicate. 222 * If the listener returns true then it will be removed after it is called. 223 * If you pass a regular expression as the event name then the listener will be added to all events that match it. 224 * 225 * @param {String|RegExp} evt Name of the event to attach the listener to. 226 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 227 * @return {Object} Current instance of EventEmitter for chaining. 228 */ 229 proto.addListener = function addListener(evt, listener) { 230 var listeners = this.getListenersAsObject(evt); 231 var listenerIsWrapped = typeof listener === 'object'; 232 var key; 233 234 for (key in listeners) { 235 if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { 236 listeners[key].push(listenerIsWrapped ? listener : { 237 listener: listener, 238 once: false 239 }); 240 } 241 } 242 243 return this; 244 }; 245 246 /** 247 * Alias of addListener 248 */ 249 proto.on = alias('addListener'); 250 251 /** 252 * Semi-alias of addListener. It will add a listener that will be 253 * automatically removed after it's first execution. 254 * 255 * @param {String|RegExp} evt Name of the event to attach the listener to. 256 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 257 * @return {Object} Current instance of EventEmitter for chaining. 258 */ 259 proto.addOnceListener = function addOnceListener(evt, listener) { 260 return this.addListener(evt, { 261 listener: listener, 262 once: true 263 }); 264 }; 265 266 /** 267 * Alias of addOnceListener. 268 */ 269 proto.once = alias('addOnceListener'); 270 271 /** 272 * 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. 273 * You need to tell it what event names should be matched by a regex. 274 * 275 * @param {String} evt Name of the event to create. 276 * @return {Object} Current instance of EventEmitter for chaining. 277 */ 278 proto.defineEvent = function defineEvent(evt) { 279 this.getListeners(evt); 280 return this; 281 }; 282 283 /** 284 * Uses defineEvent to define multiple events. 285 * 286 * @param {String[]} evts An array of event names to define. 287 * @return {Object} Current instance of EventEmitter for chaining. 288 */ 289 proto.defineEvents = function defineEvents(evts) { 290 for (var i = 0; i < evts.length; i += 1) { 291 this.defineEvent(evts[i]); 292 } 293 return this; 294 }; 295 296 /** 297 * Removes a listener function from the specified event. 298 * When passed a regular expression as the event name, it will remove the listener from all events that match it. 299 * 300 * @param {String|RegExp} evt Name of the event to remove the listener from. 301 * @param {Function} listener Method to remove from the event. 302 * @return {Object} Current instance of EventEmitter for chaining. 303 */ 304 proto.removeListener = function removeListener(evt, listener) { 305 var listeners = this.getListenersAsObject(evt); 306 var index; 307 var key; 308 309 for (key in listeners) { 310 if (listeners.hasOwnProperty(key)) { 311 index = indexOfListener(listeners[key], listener); 312 313 if (index !== -1) { 314 listeners[key].splice(index, 1); 315 } 316 } 317 } 318 319 return this; 320 }; 321 322 /** 323 * Alias of removeListener 324 */ 325 proto.off = alias('removeListener'); 326 327 /** 328 * Adds listeners in bulk using the manipulateListeners method. 329 * 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. 330 * You can also pass it a regular expression to add the array of listeners to all events that match it. 331 * Yeah, this function does quite a bit. That's probably a bad thing. 332 * 333 * @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. 334 * @param {Function[]} [listeners] An optional array of listener functions to add. 335 * @return {Object} Current instance of EventEmitter for chaining. 336 */ 337 proto.addListeners = function addListeners(evt, listeners) { 338 // Pass through to manipulateListeners 339 return this.manipulateListeners(false, evt, listeners); 340 }; 341 342 /** 343 * Removes listeners in bulk using the manipulateListeners method. 344 * 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. 345 * You can also pass it an event name and an array of listeners to be removed. 346 * You can also pass it a regular expression to remove the listeners from all events that match it. 347 * 348 * @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. 349 * @param {Function[]} [listeners] An optional array of listener functions to remove. 350 * @return {Object} Current instance of EventEmitter for chaining. 351 */ 352 proto.removeListeners = function removeListeners(evt, listeners) { 353 // Pass through to manipulateListeners 354 return this.manipulateListeners(true, evt, listeners); 355 }; 356 357 /** 358 * 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. 359 * The first argument will determine if the listeners are removed (true) or added (false). 360 * 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. 361 * You can also pass it an event name and an array of listeners to be added/removed. 362 * You can also pass it a regular expression to manipulate the listeners of all events that match it. 363 * 364 * @param {Boolean} remove True if you want to remove listeners, false if you want to add. 365 * @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. 366 * @param {Function[]} [listeners] An optional array of listener functions to add/remove. 367 * @return {Object} Current instance of EventEmitter for chaining. 368 */ 369 proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) { 370 var i; 371 var value; 372 var single = remove ? this.removeListener : this.addListener; 373 var multiple = remove ? this.removeListeners : this.addListeners; 374 375 // If evt is an object then pass each of it's properties to this method 376 if (typeof evt === 'object' && !(evt instanceof RegExp)) { 377 for (i in evt) { 378 if (evt.hasOwnProperty(i) && (value = evt[i])) { 379 // Pass the single listener straight through to the singular method 380 if (typeof value === 'function') { 381 single.call(this, i, value); 382 } 383 else { 384 // Otherwise pass back to the multiple function 385 multiple.call(this, i, value); 386 } 387 } 388 } 389 } 390 else { 391 // So evt must be a string 392 // And listeners must be an array of listeners 393 // Loop over it and pass each one to the multiple method 394 i = listeners.length; 395 while (i--) { 396 single.call(this, evt, listeners[i]); 397 } 398 } 399 400 return this; 401 }; 402 403 /** 404 * Removes all listeners from a specified event. 405 * If you do not specify an event then all listeners will be removed. 406 * That means every event will be emptied. 407 * You can also pass a regex to remove all events that match it. 408 * 409 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. 410 * @return {Object} Current instance of EventEmitter for chaining. 411 */ 412 proto.removeEvent = function removeEvent(evt) { 413 var type = typeof evt; 414 var events = this._getEvents(); 415 var key; 416 417 // Remove different things depending on the state of evt 418 if (type === 'string') { 419 // Remove all listeners for the specified event 420 delete events[evt]; 421 } 422 else if (evt instanceof RegExp) { 423 // Remove all events matching the regex. 424 for (key in events) { 425 if (events.hasOwnProperty(key) && evt.test(key)) { 426 delete events[key]; 427 } 428 } 429 } 430 else { 431 // Remove all listeners in all events 432 delete this._events; 433 } 434 435 return this; 436 }; 437 438 /** 439 * Alias of removeEvent. 440 * 441 * Added to mirror the node API. 442 */ 443 proto.removeAllListeners = alias('removeEvent'); 444 445 /** 446 * Emits an event of your choice. 447 * When emitted, every listener attached to that event will be executed. 448 * If you pass the optional argument array then those arguments will be passed to every listener upon execution. 449 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately. 450 * So they will not arrive within the array on the other side, they will be separate. 451 * You can also pass a regular expression to emit to all events that match it. 452 * 453 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 454 * @param {Array} [args] Optional array of arguments to be passed to each listener. 455 * @return {Object} Current instance of EventEmitter for chaining. 456 */ 457 proto.emitEvent = function emitEvent(evt, args) { 458 var listeners = this.getListenersAsObject(evt); 459 var listener; 460 var i; 461 var key; 462 var response; 463 464 for (key in listeners) { 465 if (listeners.hasOwnProperty(key)) { 466 i = listeners[key].length; 467 468 while (i--) { 469 // If the listener returns true then it shall be removed from the event 470 // The function is executed either with a basic call or an apply if there is an args array 471 listener = listeners[key][i]; 472 473 if (listener.once === true) { 474 this.removeListener(evt, listener.listener); 475 } 476 477 response = listener.listener.apply(this, args || []); 478 479 if (response === this._getOnceReturnValue()) { 480 this.removeListener(evt, listener.listener); 481 } 482 } 483 } 484 } 485 486 return this; 487 }; 488 489 /** 490 * Alias of emitEvent 491 */ 492 proto.trigger = alias('emitEvent'); 493 494 /** 495 * 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. 496 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. 497 * 498 * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 499 * @param {...*} Optional additional arguments to be passed to each listener. 500 * @return {Object} Current instance of EventEmitter for chaining. 501 */ 502 proto.emit = function emit(evt) { 503 var args = Array.prototype.slice.call(arguments, 1); 504 return this.emitEvent(evt, args); 505 }; 506 507 /** 508 * Sets the current value to check against when executing listeners. If a 509 * listeners return value matches the one set here then it will be removed 510 * after execution. This value defaults to true. 511 * 512 * @param {*} value The new value to check for when executing listeners. 513 * @return {Object} Current instance of EventEmitter for chaining. 514 */ 515 proto.setOnceReturnValue = function setOnceReturnValue(value) { 516 this._onceReturnValue = value; 517 return this; 518 }; 519 520 /** 521 * Fetches the current value to check against when executing listeners. If 522 * the listeners return value matches this one then it should be removed 523 * automatically. It will return true by default. 524 * 525 * @return {*|Boolean} The current value to check for or the default, true. 526 * @api private 527 */ 528 proto._getOnceReturnValue = function _getOnceReturnValue() { 529 if (this.hasOwnProperty('_onceReturnValue')) { 530 return this._onceReturnValue; 531 } 532 else { 533 return true; 534 } 535 }; 536 537 /** 538 * Fetches the events object and creates one if required. 539 * 540 * @return {Object} The events storage object. 541 * @api private 542 */ 543 proto._getEvents = function _getEvents() { 544 return this._events || (this._events = {}); 545 }; 546 547 /** 548 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version. 549 * 550 * @return {Function} Non conflicting EventEmitter class. 551 */ 552 EventEmitter.noConflict = function noConflict() { 553 exports.EventEmitter = originalGlobalValue; 554 return EventEmitter; 555 }; 556 557
557// Expose the class either via AMD, CommonJS or the global object 558 if (typeof define === 'function' && define.amd) { 559 define(function () { 560 return EventEmitter; 561 }); 562 } 563 else if (typeof module === 'object' && module.exports){ 564 module.exports = EventEmitter; 565 } 566 else { 567 this.EventEmitter = EventEmitter; 568 } 569}.call(this)); 570 571/*! 572 * imagesLoaded v3.1.4 573 * JavaScript is all like "You images are done yet or what?" 574 * MIT License 575 */ 576 577( function( window, factory ) { 'use strict'; 578 // universal module definition 579 580 /*global define: false, module: false, require: false */ 581 582 if ( typeof define === 'function' && define.amd ) { 583 // AMD 584 define( [ 585 'eventEmitter/EventEmitter', 586 'eventie/eventie' 587 ], function( EventEmitter, eventie ) { 588 return factory( window, EventEmitter, eventie ); 589 }); 590 } else if ( typeof exports === 'object' ) { 591 // CommonJS 592 module.exports = factory( 593 window, 594 require('eventEmitter'), 595 require('eventie') 596 ); 597 } else { 598 // browser global 599 window.imagesLoaded = factory( 600 window, 601 window.EventEmitter, 602 window.eventie 603 ); 604 } 605 606})( this, 607 608// -------------------------- factory -------------------------- // 609 610function factory( window, EventEmitter, eventie ) { 611 612'use strict'; 613 614var $ = window.jQuery; 615var console = window.console; 616var hasConsole = typeof console !== 'undefined'; 617 618// -------------------------- helpers -------------------------- // 619 620// extend objects 621function extend( a, b ) { 622 for ( var prop in b ) { 623 a[ prop ] = b[ prop ]; 624 } 625 return a; 626} 627 628var objToString = Object.prototype.toString; 629function isArray( obj ) { 630 return objToString.call( obj ) === '[object Array]'; 631} 632 633// turn element or nodeList into an array 634function makeArray( obj ) { 635 var ary = []; 636 if ( isArray( obj ) ) { 637 // use object if already an array 638 ary = obj; 639 } else if ( typeof obj.length === 'number' ) { 640 // convert nodeList to array 641 for ( var i=0, len = obj.length; i < len; i++ ) { 642 ary.push( obj[i] ); 643 } 644 } else { 645 // array of single index 646 ary.push( obj ); 647 } 648 return ary; 649} 650 651 // -------------------------- imagesLoaded -------------------------- // 652 653 /** 654 * @param {Array, Element, NodeList, String} elem 655 * @param {Object or Function} options - if function, use as callback 656 * @param {Function} onAlways - callback function 657 */ 658 function ImagesLoaded( elem, options, onAlways ) { 659 // coerce ImagesLoaded() without new, to be new ImagesLoaded() 660 if ( !( this instanceof ImagesLoaded ) ) { 661 return new ImagesLoaded( elem, options ); 662 } 663 // use elem as selector string 664 if ( typeof elem === 'string' ) { 665 elem = document.querySelectorAll( elem ); 666 } 667 668 this.elements = makeArray( elem ); 669 this.options = extend( {}, this.options ); 670 671 if ( typeof options === 'function' ) { 672 onAlways = options; 673 } else { 674 extend( this.options, options ); 675 } 676 677 if ( onAlways ) { 678 this.on( 'always', onAlways ); 679 } 680 681 this.getImages(); 682 683 if ( $ ) { 684 // add jQuery Deferred object 685 this.jqDeferred = new $.Deferred(); 686 } 687 688 // HACK check async to allow time to bind listeners 689 var _this = this; 690 setTimeout( function() { 691 _this.check(); 692 }); 693 } 694 695 ImagesLoaded.prototype = new EventEmitter(); 696 697 ImagesLoaded.prototype.options = {}; 698 699 ImagesLoaded.prototype.getImages = function() { 700 this.images = []; 701 702 // filter & find items if we have an item selector 703 for ( var i=0, len = this.elements.length; i < len; i++ ) { 704 var elem = this.elements[i]; 705 // filter siblings 706 if ( elem.nodeName === 'IMG' ) { 707 this.addImage( elem ); 708 } 709 // find children 710 var childElems = elem.querySelectorAll('img'); 711 // concat childElems to filterFound array 712 for ( var j=0, jLen = childElems.length; j < jLen; j++ ) { 713 var img = childElems[j]; 714 this.addImage( img ); 715 } 716 } 717 }; 718 719 /** 720 * @param {Image} img 721 */ 722 ImagesLoaded.prototype.addImage = function( img ) { 723 var loadingImage = new LoadingImage( img ); 724 this.images.push( loadingImage ); 725 }; 726
727 ImagesLoaded.prototype.check = function() { 728 var _this = this; 729 var checkedCount = 0; 730 var length = this.images.length; 731 this.hasAnyBroken = false; 732 // complete if no images 733 if ( !length ) { 734 this.complete(); 735 return; 736 } 737 738 function onConfirm( image, message ) { 739 if ( _this.options.debug && hasConsole ) { 740 741 } 742 743 _this.progress( image ); 744 checkedCount++; 745 if ( checkedCount === length ) { 746 _this.complete(); 747 } 748 return true; // bind once 749 } 750 751 for ( var i=0; i < length; i++ ) { 752 var loadingImage = this.images[i]; 753 loadingImage.on( 'confirm', onConfirm ); 754 loadingImage.check(); 755 } 756 }; 757 758 ImagesLoaded.prototype.progress = function( image ) { 759 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 760 // HACK - Chrome triggers event before object properties have changed. #83 761 var _this = this; 762 setTimeout( function() { 763 _this.emit( 'progress', _this, image ); 764 if ( _this.jqDeferred && _this.jqDeferred.notify ) { 765 _this.jqDeferred.notify( _this, image ); 766 } 767 }); 768 }; 769 770 ImagesLoaded.prototype.complete = function() { 771 var eventName = this.hasAnyBroken ? 'fail' : 'done'; 772 this.isComplete = true; 773 var _this = this; 774 // HACK - another setTimeout so that confirm happens after progress 775 setTimeout( function() { 776 _this.emit( eventName, _this ); 777 _this.emit( 'always', _this ); 778 if ( _this.jqDeferred ) { 779 var jqMethod = _this.hasAnyBroken ? 'reject' : 'resolve'; 780 _this.jqDeferred[ jqMethod ]( _this ); 781 } 782 }); 783 }; 784 785 // -------------------------- jquery -------------------------- // 786 787 if ( $ ) { 788 $.fn.imagesLoaded = function( options, callback ) { 789 var instance = new ImagesLoaded( this, options, callback ); 790 return instance.jqDeferred.promise( $(this) ); 791 }; 792 } 793 794 795 // -------------------------- -------------------------- // 796 797 function LoadingImage( img ) { 798 this.img = img; 799 } 800 801 LoadingImage.prototype = new EventEmitter(); 802 803 LoadingImage.prototype.check = function() { 804 // first check cached any previous images that have same src 805 var resource = cache[ this.img.src ] || new Resource( this.img.src ); 806 if ( resource.isConfirmed ) { 807 this.confirm( resource.isLoaded, 'cached was confirmed' ); 808 return; 809 } 810 811 // If complete is true and browser supports natural sizes, 812 // try to check for image status manually. 813 if ( this.img.complete && this.img.naturalWidth !== undefined ) { 814 // report based on naturalWidth 815 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 816 return; 817 } 818 819 // If none of the checks above matched, simulate loading on detached element. 820 var _this = this; 821 resource.on( 'confirm', function( resrc, message ) { 822 _this.confirm( resrc.isLoaded, message ); 823 return true; 824 }); 825 826 resource.check(); 827 }; 828 829 LoadingImage.prototype.confirm = function( isLoaded, message ) { 830 this.isLoaded = isLoaded; 831 this.emit( 'confirm', this, message ); 832 }; 833 834 // -------------------------- Resource -------------------------- // 835 836 // Resource checks each src, only once 837 // separate class from LoadingImage to prevent memory leaks. See #115 838 839 var cache = {}; 840 841 function Resource( src ) { 842 this.src = src; 843 // add to cache 844 cache[ src ] = this; 845 } 846 847 Resource.prototype = new EventEmitter(); 848 849 Resource.prototype.check = function() { 850 // only trigger checking once 851 if ( this.isChecked ) { 852 return; 853 } 854 // simulate loading on detached element 855 var proxyImage = new Image(); 856 eventie.bind( proxyImage, 'load', this ); 857 eventie.bind( proxyImage, 'error', this ); 858 proxyImage.src = this.src; 859 // set flag 860 this.isChecked = true; 861 }; 862 863 // ----- events ----- // 864 865 // trigger specified handler for event type 866 Resource.prototype.handleEvent = function( event ) { 867 var method = 'on' + event.type; 868 if ( this[ method ] ) { 869 this[ method ]( event ); 870 } 871 }; 872 873 Resource.prototype.onload = function( event ) { 874 this.confirm( true, 'onload' ); 875 this.unbindProxyEvents( event ); 876 }; 877 878 Resource.prototype.onerror = function( event ) { 879 this.confirm( false, 'onerror' ); 880 this.unbindProxyEvents( event ); 881 }; 882 883 // ----- confirm ----- // 884 885 Resource.prototype.confirm = function( isLoaded, message ) { 886 this.isConfirmed = true; 887 this.isLoaded = isLoaded;
888 this.emit( 'confirm', this, message ); 889 }; 890 891 Resource.prototype.unbindProxyEvents = function( event ) { 892 eventie.unbind( event.target, 'load', this ); 893 eventie.unbind( event.target, 'error', this ); 894 }; 895 896 // ----- ----- // 897 898 return ImagesLoaded; 899 900}); 901 902function OverlayLoader(parent) { 903 this.parent = parent; 904 this.container; 905 this.loadbar; 906 this.percentageContainer; 907}; 908 909OverlayLoader.prototype.createOverlay = function () { 910 911 912 //determine postion of overlay and set parent position 913 var overlayPosition = "absolute"; 914 915 if (this.parent.element.tagName.toLowerCase() == "body") { 916 overlayPosition = "fixed"; 917 } else { 918 var pos = this.parent.$element.css("position"); 919 if (pos != "fixed" || pos != "absolute") { 920 this.parent.$element.css("position", "relative"); 921 } 922 } 923 924 //create the overlay container 925 this.container = $("<div id='" + this.parent.options.overlayId + "'></div>").css({ 926 width: "100%", 927 height: "100%", 928 backgroundColor: this.parent.options.backgroundColor, 929 backgroundPosition: "fixed", 930 position: overlayPosition, 931 zIndex: 666999, //very high! 932 top: 0, 933 left: 0 934 }).appendTo(this.parent.$element); 935 936 //create the loading bar 937 this.loadbar = $("<div id='qLbar'></div>").css({ 938 height: this.parent.options.barHeight + "px", 939 marginTop: "-" + (this.parent.options.barHeight / 2) + "px", 940 backgroundColor: this.parent.options.barColor, 941 width: "0%", 942 position: "absolute", 943 top: "50%" 944 }).appendTo(this.container); 945 946 //if percentage is on 947 if (this.parent.options.percentage == true) { 948 this.percentageContainer = $("<div id='qLpercentage'></div>").text("0%").css({ 949 height: "40px", 950 width: "100px", 951 position: "absolute", 952 fontSize: "3em", 953 top: "50%", 954 left: "50%", 955 marginTop: "-" + (59 + this.parent.options.barHeight) + "px", 956 textAlign: "center", 957 marginLeft: "-50px", 958 color: this.parent.options.barColor 959 }).appendTo(this.container); 960 } 961 962 //if no images... destroy 963 if (!this.parent.preloadContainer.toPreload.length || this.parent.alreadyLoaded == true) { 964 this.parent.destroyContainers(); 965 } 966}; 967 968OverlayLoader.prototype.updatePercentage = function (percentage) { 969 this.loadbar.stop().animate({ 970 width: percentage + "%", 971 minWidth: percentage + "%" 972 }, 200); 973 974 //update textual percentage 975 if (this.parent.options.percentage == true) { 976 this.percentageContainer.text(Math.ceil(percentage) + "%"); 977 } 978}; 979function PreloadContainer(parent) { 980 this.toPreload = []; 981 this.parent = parent; 982 this.container; 983}; 984 985PreloadContainer.prototype.create = function () { 986 this.container = $("<div></div>").appendTo("body").css({ 987 display: "none", 988 width: 0, 989 height: 0, 990 overflow: "hidden" 991 }); 992 993 //process the image queue 994 this.processQueue(); 995}; 996 997PreloadContainer.prototype.processQueue = function () { 998 //add background images for loading 999 for (var i = 0; this.toPreload.length > i; i++) { 1000 if (!this.parent.destroyed) { 1001 this.preloadImage(this.toPreload[i]); 1002 } 1003 } 1004}; 1005 1006PreloadContainer.prototype.addImage = function (src) { 1007 1008 this.toPreload.push(src); 1009}; 1010 1011PreloadContainer.prototype.preloadImage = function (url) { 1012 1013 var image = new PreloadImage(); 1014 image.addToPreloader(this, url); 1015 image.bindLoadEvent(); 1016}; 1017function PreloadImage(parent) { 1018 this.element; 1019 this.parent = parent; 1020}; 1021 1022PreloadImage.prototype.addToPreloader = function (preloader, url) { 1023 1024 this.element = $("<img />").attr("src", url); 1025 this.element.appendTo(preloader.container); 1026 this.parent = preloader.parent; 1027}; 1028 1029PreloadImage.prototype.bindLoadEvent = function () { 1030 this.parent.imageCounter++; 1031 1032 //binding 1033 this.element[0].ref = this; 1034 1035 new imagesLoaded(this.element, function (e) { 1036 e.elements[0].ref.completeLoading(); 1037 }); 1038}; 1039 1040PreloadImage.prototype.completeLoading = function () { 1041 this.parent.imageDone++; 1042 1043 var percentage = (this.parent.imageDone / this.parent.imageCounter) * 100; 1044 1045 1046 1047 //update the percentage of the loader 1048 this.parent.overlayLoader.updatePercentage(percentage); 1049 1050 //all images done! 1051 if (this.parent.imageDone == this.parent.imageCounter || percentage >= 100) { 1052 this.parent.endLoader(); 1053 } 1054}; 1055function QueryLoader2(element, options) { 1056 this.element = element; 1057 this.$element = $(element); 1058 this.options = options; 1059 this.foundUrls = []; 1060 this.destroyed = false;
1061 this.imageCounter = 0; 1062 this.imageDone = 0; 1063 this.alreadyLoaded = false; 1064 1065 //create objects 1066 this.preloadContainer = new PreloadContainer(this); 1067 this.overlayLoader = new OverlayLoader(this); 1068 1069 //The default options 1070 this.defaultOptions = { 1071 onComplete: function() {}, 1072 onLoadComplete: function() {}, 1073 backgroundColor: "#000", 1074 barColor: "#fff", 1075 overlayId: 'qLoverlay', 1076 barHeight: 1, 1077 percentage: false, 1078 deepSearch: true, 1079 completeAnimation: "fade", 1080 minimumTime: 500 1081 }; 1082 1083 //run the init 1084 this.init(); 1085}; 1086 1087QueryLoader2.prototype.init = function() { 1088 1089 1090 1091 this.options = $.extend({}, this.defaultOptions, this.options); 1092 1093 1094 var images = this.findImageInElement(this.element); 1095 if (this.options.deepSearch == true) { 1096 1097 var elements = this.$element.find("*:not(script)"); 1098 for (var i = 0; i < elements.length; i++) { 1099 this.findImageInElement(elements[i]); 1100 } 1101 } 1102 1103 //create containers 1104 this.preloadContainer.create(); 1105 this.overlayLoader.createOverlay(); 1106}; 1107 1108QueryLoader2.prototype.findImageInElement = function (element) { 1109 var url = ""; 1110 var obj = $(element); 1111 var type = "normal"; 1112 1113 if (obj.css("background-image") != "none") { 1114 //if object has background image 1115 url = obj.css("background-image"); 1116 type = "background"; 1117 } else if (typeof(obj.attr("src")) != "undefined" && element.nodeName.toLowerCase() == "img") { 1118 //if is img and has src 1119 url = obj.attr("src"); 1120 } 1121 1122 //skip if gradient 1123 if (!this.hasGradient(url)) { 1124 //remove unwanted chars 1125 url = this.stripUrl(url); 1126 1127 //split urls 1128 var urls = url.split(", "); 1129 1130 for (var i = 0; i < urls.length; i++) { 1131 if (this.validUrl(urls[i]) && this.urlIsNew(urls[i])) { 1132 1133 var extra = ""; 1134 1135 if (this.isIE() || this.isOpera()){ 1136 //filthy always no cache for IE, sorry peeps! 1137 extra = "?rand=" + Math.random(); 1138 1139 //add to preloader 1140 this.preloadContainer.addImage(urls[i] + extra); 1141 } else { 1142 if (type == "background") { 1143 //add to preloader 1144 this.preloadContainer.addImage(urls[i] + extra); 1145 } else { 1146 var image = new PreloadImage(this); 1147 image.element = obj; 1148 image.bindLoadEvent(); 1149 } 1150 } 1151 1152 //add image to found list 1153 this.foundUrls.push(urls[i]); 1154 } 1155 } 1156 } 1157}; 1158 1159QueryLoader2.prototype.hasGradient = function (url) { 1160 if (url.indexOf("gradient") == -1) { 1161 return false; 1162 } else { 1163 return true; 1164 } 1165}; 1166 1167QueryLoader2.prototype.stripUrl = function (url) { 1168 url = url.replace(/url\(\"/g, ""); 1169 url = url.replace(/url\(/g, ""); 1170 url = url.replace(/\"\)/g, ""); 1171 url = url.replace(/\)/g, ""); 1172 1173 return url; 1174}; 1175 1176QueryLoader2.prototype.isIE = function () { 1177 return navigator.userAgent.match(/msie/i); 1178}; 1179 1180QueryLoader2.prototype.isOpera = function () { 1181 return navigator.userAgent.match(/Opera/i); 1182}; 1183 1184QueryLoader2.prototype.validUrl = function (url) { 1185 if (url.length > 0 && !url.match(/^(data:)/i)) { 1186 return true; 1187 } else { 1188 return false; 1189 } 1190}; 1191 1192QueryLoader2.prototype.urlIsNew = function (url) { 1193 if (this.foundUrls.indexOf(url) == -1) { 1194 return true; 1195 } else { 1196 return false; 1197 } 1198}; 1199 1200QueryLoader2.prototype.destroyContainers = function () { 1201 this.destroyed = true; 1202 this.preloadContainer.container.remove(); 1203 this.overlayLoader.container.remove(); 1204}; 1205 1206QueryLoader2.prototype.endLoader = function () { 1207 1208 1209 this.destroyed = true; 1210 this.onLoadComplete(); 1211}; 1212 1213QueryLoader2.prototype.onLoadComplete = function() { 1214 //fire the event before end animation 1215 this.options.onLoadComplete(); 1216 1217 if (this.options.completeAnimation == "grow") { 1218 var animationTime = this.options.minimumTime; 1219 1220 this.overlayLoader.loadbar[0].parent = this; //put object in DOM element 1221 this.overlayLoader.loadbar.stop().animate({ 1222 "width": "100%" 1223 }, animationTime, function () { 1224 $(this).animate({ 1225 top: "0%", 1226 width: "100%", 1227 height: "100%" 1228 }, 500, function () { 1229 this.parent.overlayLoader.container[0].parent = this.parent; //once again... 1230 this.parent.overlayLoader.container.fadeOut(500, function () { 1231 this.parent.destroyContainers(); 1232 this.parent.options.onComplete(); 1233 }); 1234 }); 1235 }); 1236 } else { 1237 var animationTime = this.options.minimumTime; 1238 1239 this.overlayLoader.container[0].parent = this; 1240 this.overlayLoader.container.fadeOut(animationTime, function () { 1241 this.parent.destroyContainers(); 1242 this.parent.options.onComplete(); 1243 }); 1244 } 1245}; 1246//HERE COMES THE IE SHITSTORM 1247if (!Array.prototype.indexOf) { 1248 Array.prototype.indexOf = function (elt /*, from*/) { 1249 var len = this.length >>> 0; 1250 var from = Number(arguments[1]) || 0; 1251 from = (from < 0) 1252 ? Math.ceil(from) 1253 : Math.floor(from); 1254 if (from < 0) 1255 from += len; 1256 1257 for (; from < len; from++) { 1258 if (from in this && 1259 this[from] === elt) 1260 return from; 1261 } 1262 return -1; 1263 }; 1264} 1265//function binder 1266$.fn.queryLoader2 = function(options){ 1267 return this.each(function(){ 1268 (new QueryLoader2(this, options)); 1269 }); 1270}; 1271})(jQuery);
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.