diff --git a/examples/moduleLoaders/amd/index.html b/examples/moduleLoaders/amd/index.html new file mode 100644 index 0000000..a53430f --- /dev/null +++ b/examples/moduleLoaders/amd/index.html @@ -0,0 +1,13 @@ + + + + + Codestin Search App + + + + + + + + \ No newline at end of file diff --git a/examples/moduleLoaders/amd/main.js b/examples/moduleLoaders/amd/main.js new file mode 100644 index 0000000..e1fa0ce --- /dev/null +++ b/examples/moduleLoaders/amd/main.js @@ -0,0 +1,13 @@ +requirejs(["../build"], function(value) { + var label = document.createElement("div"); + label.innerText = "createjs exists! Its classes are: \n"+Object.keys(this.createjs).join("\n"); + document.body.appendChild(label); + + console.log(value); + + var q = new createjs.LoadQueue(); + q.addEventListener("complete", function(evt) { + console.log(evt); + }); + q.loadFile('https://www.google.ca/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png'); +}); diff --git a/examples/moduleLoaders/browserify/README.md b/examples/moduleLoaders/browserify/README.md new file mode 100644 index 0000000..9fea655 --- /dev/null +++ b/examples/moduleLoaders/browserify/README.md @@ -0,0 +1,3 @@ +The build.js file was created using: + +```browserify -s createjs main.js -o build.js``` diff --git a/examples/moduleLoaders/browserify/index.html b/examples/moduleLoaders/browserify/index.html new file mode 100644 index 0000000..ec01f65 --- /dev/null +++ b/examples/moduleLoaders/browserify/index.html @@ -0,0 +1,23 @@ + + + + + Codestin Search App + + + + + + + + + + \ No newline at end of file diff --git a/examples/moduleLoaders/browserify/main.js b/examples/moduleLoaders/browserify/main.js new file mode 100644 index 0000000..71e786f --- /dev/null +++ b/examples/moduleLoaders/browserify/main.js @@ -0,0 +1,5 @@ +var build = require('../build'); + +var label = document.createElement("div"); +label.innerText = "createjs exists! Its classes are: \n"+Object.keys(createjs).join("\n"); +document.body.appendChild(label); diff --git a/examples/moduleLoaders/browserify/main.min.js b/examples/moduleLoaders/browserify/main.min.js new file mode 100644 index 0000000..07c1736 --- /dev/null +++ b/examples/moduleLoaders/browserify/main.min.js @@ -0,0 +1,5465 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oExample + * + * myObject.addEventListener("change", createjs.proxy(myMethod, scope)); + * + * @module CreateJS + * @main CreateJS + */ +// constructor: +/** + * Contains properties and methods shared by all events for use with + * {{#crossLink "EventDispatcher"}}{{/crossLink}}. + * + * Note that Event objects are often reused, so you should never + * rely on an event object's state outside of the call stack it was received in. + * @class Event + * @param {String} type The event type. + * @param {Boolean} bubbles Indicates whether the event will bubble through the display list. + * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled. + * @constructor + **/ +function Event(type, bubbles, cancelable) { + + + // public properties: + /** + * The type of event. + * @property type + * @type String + **/ + this.type = type; + + /** + * The object that generated an event. + * @property target + * @type Object + * @default null + * @readonly + */ + this.target = null; + + /** + * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will + * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event + * is generated from childObj, then a listener on parentObj would receive the event with + * target=childObj (the original target) and currentTarget=parentObj (where the listener was added). + * @property currentTarget + * @type Object + * @default null + * @readonly + */ + this.currentTarget = null; + + /** + * For bubbling events, this indicates the current event phase:
    + *
  1. capture phase: starting from the top parent to the target
  2. + *
  3. at target phase: currently being dispatched from the target
  4. + *
  5. bubbling phase: from the target to the top parent
  6. + *
+ * @property eventPhase + * @type Number + * @default 0 + * @readonly + */ + this.eventPhase = 0; + + /** + * Indicates whether the event will bubble through the display list. + * @property bubbles + * @type Boolean + * @default false + * @readonly + */ + this.bubbles = !!bubbles; + + /** + * Indicates whether the default behaviour of this event can be cancelled via + * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor. + * @property cancelable + * @type Boolean + * @default false + * @readonly + */ + this.cancelable = !!cancelable; + + /** + * The epoch time at which this event was created. + * @property timeStamp + * @type Number + * @default 0 + * @readonly + */ + this.timeStamp = (new Date()).getTime(); + + /** + * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called + * on this event. + * @property defaultPrevented + * @type Boolean + * @default false + * @readonly + */ + this.defaultPrevented = false; + + /** + * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or + * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event. + * @property propagationStopped + * @type Boolean + * @default false + * @readonly + */ + this.propagationStopped = false; + + /** + * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called + * on this event. + * @property immediatePropagationStopped + * @type Boolean + * @default false + * @readonly + */ + this.immediatePropagationStopped = false; + + /** + * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event. + * @property removed + * @type Boolean + * @default false + * @readonly + */ + this.removed = false; +} +var p = Event.prototype; + +/** + * REMOVED. Removed in favor of using `MySuperClass_constructor`. + * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} + * for details. + * + * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. + * + * @method initialize + * @protected + * @deprecated + */ +// p.initialize = function() {}; // searchable for devs wondering where it is. + + +// public methods: +/** + * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method preventDefault + **/ +p.preventDefault = function () { + this.defaultPrevented = this.cancelable && true; +}; + +/** + * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method stopPropagation + **/ +p.stopPropagation = function () { + this.propagationStopped = true; +}; + +/** + * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and + * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method stopImmediatePropagation + **/ +p.stopImmediatePropagation = function () { + this.immediatePropagationStopped = this.propagationStopped = true; +}; + +/** + * Causes the active listener to be removed via removeEventListener(); + * + * myBtn.addEventListener("click", function(evt) { + * // do stuff... + * evt.remove(); // removes this listener. + * }); + * + * @method remove + **/ +p.remove = function () { + this.removed = true; +}; + +/** + * Returns a clone of the Event instance. + * @method clone + * @return {Event} a clone of the Event instance. + **/ +p.clone = function () { + return new Event(this.type, this.bubbles, this.cancelable); +}; + +/** + * Provides a chainable shortcut method for setting a number of properties on the instance. + * + * @method set + * @param {Object} props A generic object containing properties to copy to the instance. + * @return {Event} Returns the instance the method is called on (useful for chaining calls.) + * @chainable + */ +p.set = function (props) { + for (var n in props) { + this[n] = props[n]; + } + return this; +}; + +/** + * Returns a string representation of this object. + * @method toString + * @return {String} a string representation of the instance. + **/ +p.toString = function () { + return "[Event (type=" + this.type + ")]"; +}; + +module.exports = Event; + +},{}],3:[function(_dereq_,module,exports){ +/* + * EventDispatcher + * Visit http://createjs.com/ for documentation, updates and examples. + * + * Copyright (c) 2010 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module CreateJS + */ + + +var Event = _dereq_('./Event'); + +// constructor: +/** + * EventDispatcher provides methods for managing queues of event listeners and dispatching events. + * + * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the + * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method. + * + * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the + * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports + * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent. + * + * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier + * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The + * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to + * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}. + * + * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}} + * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also + * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener. + * + *

Example

+ * Add EventDispatcher capabilities to the "MyClass" class. + * + * EventDispatcher.initialize(MyClass.prototype); + * + * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}). + * + * instance.addEventListener("eventName", handlerMethod); + * function handlerMethod(event) { + * console.log(event.target + " Was Clicked"); + * } + * + * Maintaining proper scope
+ * Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}} + * method to subscribe to events simplifies this. + * + * instance.addEventListener("click", function(event) { + * console.log(instance == this); // false, scope is ambiguous. + * }); + * + * instance.on("click", function(event) { + * console.log(instance == this); // true, "on" uses dispatcher scope by default. + * }); + * + * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage scope. + * + * + * @class EventDispatcher + * @constructor + **/ +function EventDispatcher() { + + + // private properties: + /** + * @protected + * @property _listeners + * @type Object + **/ + this._listeners = null; + + /** + * @protected + * @property _captureListeners + * @type Object + **/ + this._captureListeners = null; +} +var p = EventDispatcher.prototype; + +/** + * REMOVED. Removed in favor of using `MySuperClass_constructor`. + * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} + * for details. + * + * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. + * + * @method initialize + * @protected + * @deprecated + */ +// p.initialize = function() {}; // searchable for devs wondering where it is. + + +// static public methods: +/** + * Static initializer to mix EventDispatcher methods into a target object or prototype. + * + * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class + * EventDispatcher.initialize(myObject); // add to a specific instance + * + * @method initialize + * @static + * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a + * prototype. + **/ +EventDispatcher.initialize = function (target) { + target.addEventListener = p.addEventListener; + target.on = p.on; + target.removeEventListener = target.off = p.removeEventListener; + target.removeAllEventListeners = p.removeAllEventListeners; + target.hasEventListener = p.hasEventListener; + target.dispatchEvent = p.dispatchEvent; + target._dispatchEvent = p._dispatchEvent; + target.willTrigger = p.willTrigger; +}; + + +// public methods: +/** + * Adds the specified event listener. Note that adding multiple listeners to the same function will result in + * multiple callbacks getting fired. + * + *

Example

+ * + * displayObject.addEventListener("click", handleClick); + * function handleClick(event) { + * // Click happened. + * } + * + * @method addEventListener + * @param {String} type The string type of the event. + * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when + * the event is dispatched. + * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + * @return {Function | Object} Returns the listener for chaining or assignment. + **/ +p.addEventListener = function (type, listener, useCapture) { + var listeners; + if (useCapture) { + listeners = this._captureListeners = this._captureListeners || {}; + } else { + listeners = this._listeners = this._listeners || {}; + } + var arr = listeners[type]; + if (arr) { + this.removeEventListener(type, listener, useCapture); + } + arr = listeners[type]; // remove may have deleted the array + if (!arr) { + listeners[type] = [listener]; + } + else { + arr.push(listener); + } + return listener; +}; + +/** + * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener + * only run once, associate arbitrary data with the listener, and remove the listener. + * + * This method works by creating an anonymous wrapper function and subscribing it with addEventListener. + * The created anonymous function is returned for use with .removeEventListener (or .off). + * + *

Example

+ * + * var listener = myBtn.on("click", handleClick, null, false, {count:3}); + * function handleClick(evt, data) { + * data.count -= 1; + * console.log(this == myBtn); // true - scope defaults to the dispatcher + * if (data.count == 0) { + * alert("clicked 3 times!"); + * myBtn.off("click", listener); + * // alternately: evt.remove(); + * } + * } + * + * @method on + * @param {String} type The string type of the event. + * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when + * the event is dispatched. + * @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent). + * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered. + * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called. + * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener. + **/ +p.on = function (type, listener, scope, once, data, useCapture) { + if (listener.handleEvent) { + scope = scope || listener; + listener = listener.handleEvent; + } + scope = scope || this; + return this.addEventListener(type, function (evt) { + listener.call(scope, evt, data); + once && evt.remove(); + }, useCapture); +}; + +/** + * Removes the specified event listener. + * + * Important Note: that you must pass the exact function reference used when the event was added. If a proxy + * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or + * closure will not work. + * + *

Example

+ * + * displayObject.removeEventListener("click", handleClick); + * + * @method removeEventListener + * @param {String} type The string type of the event. + * @param {Function | Object} listener The listener function or object. + * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + **/ +p.removeEventListener = function (type, listener, useCapture) { + var listeners = useCapture ? this._captureListeners : this._listeners; + if (!listeners) { + return; + } + var arr = listeners[type]; + if (!arr) { + return; + } + for (var i = 0, l = arr.length; i < l; i++) { + if (arr[i] == listener) { + if (l == 1) { + delete(listeners[type]); + } // allows for faster checks. + else { + arr.splice(i, 1); + } + break; + } + } +}; + +/** + * A shortcut to the removeEventListener method, with the same parameters and return value. This is a companion to the + * .on method. + * + * @method off + * @param {String} type The string type of the event. + * @param {Function | Object} listener The listener function or object. + * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + **/ +p.off = p.removeEventListener; + +/** + * Removes all listeners for the specified type, or all listeners of all types. + * + *

Example

+ * + * // Remove all listeners + * displayObject.removeAllEventListeners(); + * + * // Remove all click listeners + * displayObject.removeAllEventListeners("click"); + * + * @method removeAllEventListeners + * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed. + **/ +p.removeAllEventListeners = function (type) { + if (!type) { + this._listeners = this._captureListeners = null; + } + else { + if (this._listeners) { + delete(this._listeners[type]); + } + if (this._captureListeners) { + delete(this._captureListeners[type]); + } + } +}; + +/** + * Dispatches the specified event to all listeners. + * + *

Example

+ * + * // Use a string event + * this.dispatchEvent("complete"); + * + * // Use an Event instance + * var event = new createjs.Event("progress"); + * this.dispatchEvent(event); + * + * @method dispatchEvent + * @param {Object | String | Event} eventObj An object with a "type" property, or a string type. + * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used, + * dispatchEvent will construct an Event instance with the specified type. + * @return {Boolean} Returns the value of eventObj.defaultPrevented. + **/ +p.dispatchEvent = function (eventObj) { + if (typeof eventObj == "string") { + // won't bubble, so skip everything if there's no listeners: + var listeners = this._listeners; + if (!listeners || !listeners[eventObj]) { + return false; + } + eventObj = new Event(eventObj); + } else if (eventObj.target && eventObj.clone) { + // redispatching an active event object, so clone it: + eventObj = eventObj.clone(); + } + try { + eventObj.target = this; + } catch (e) { + } // try/catch allows redispatching of native events + + if (!eventObj.bubbles || !this.parent) { + this._dispatchEvent(eventObj, 2); + } else { + var top = this, list = [top]; + while (top.parent) { + list.push(top = top.parent); + } + var i, l = list.length; + + // capture & atTarget + for (i = l - 1; i >= 0 && !eventObj.propagationStopped; i--) { + list[i]._dispatchEvent(eventObj, 1 + (i == 0)); + } + // bubbling + for (i = 1; i < l && !eventObj.propagationStopped; i++) { + list[i]._dispatchEvent(eventObj, 3); + } + } + return eventObj.defaultPrevented; +}; + +/** + * Indicates whether there is at least one listener for the specified event type. + * @method hasEventListener + * @param {String} type The string type of the event. + * @return {Boolean} Returns true if there is at least one listener for the specified event. + **/ +p.hasEventListener = function (type) { + var listeners = this._listeners, captureListeners = this._captureListeners; + return !!((listeners && listeners[type]) || (captureListeners && captureListeners[type])); +}; + +/** + * Indicates whether there is at least one listener for the specified event type on this object or any of its + * ancestors (parent, parent's parent, etc). A return value of true indicates that if a bubbling event of the + * specified type is dispatched from this object, it will trigger at least one listener. + * + * This is similar to {{#crossLink "EventDispatcher/hasEventListener"}}{{/crossLink}}, but it searches the entire + * event flow for a listener, not just this object. + * @method willTrigger + * @param {String} type The string type of the event. + * @return {Boolean} Returns `true` if there is at least one listener for the specified event. + **/ +p.willTrigger = function (type) { + var o = this; + while (o) { + if (o.hasEventListener(type)) { + return true; + } + o = o.parent; + } + return false; +}; + +/** + * @method toString + * @return {String} a string representation of the instance. + **/ +p.toString = function () { + return "[EventDispatcher]"; +}; + + +// private methods: +/** + * @method _dispatchEvent + * @param {Object | String | Event} eventObj + * @param {Object} eventPhase + * @protected + **/ +p._dispatchEvent = function (eventObj, eventPhase) { + var l, listeners = (eventPhase == 1) ? this._captureListeners : this._listeners; + if (eventObj && listeners) { + var arr = listeners[eventObj.type]; + if (!arr || !(l = arr.length)) { + return; + } + try { + eventObj.currentTarget = this; + } catch (e) { + } + try { + eventObj.eventPhase = eventPhase; + } catch (e) { + } + eventObj.removed = false; + + arr = arr.slice(); // to avoid issues with items being removed or added during the dispatch + for (var i = 0; i < l && !eventObj.immediatePropagationStopped; i++) { + var o = arr[i]; + if (o.handleEvent) { + o.handleEvent(eventObj); + } + else { + o(eventObj); + } + if (eventObj.removed) { + this.off(eventObj.type, o, eventPhase == 1); + eventObj.removed = false; + } + } + } +}; + + +module.exports = EventDispatcher = EventDispatcher; + +},{"./Event":2}],4:[function(_dereq_,module,exports){ +/* +* extend +* Visit http://createjs.com/ for documentation, updates and examples. +* +* Copyright (c) 2010 gskinner.com, inc. +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +/** + * @module CreateJS + */ + +/** + * @class Utility Methods + */ + +/** + * Sets up the prototype chain and constructor property for a new class. + * + * This should be called right after creating the class constructor. + * + * function MySubClass() {} + * createjs.extend(MySubClass, MySuperClass); + * ClassB.prototype.doSomething = function() { } + * + * var foo = new MySubClass(); + * console.log(foo instanceof MySuperClass); // true + * console.log(foo.prototype.constructor === MySubClass); // true + * + * @method extend + * @param {Function} subclass The subclass. + * @param {Function} superclass The superclass to extend. + * @return {Function} Returns the subclass's new prototype. + */ +module.exports = function(subclass, superclass) { + "use strict"; + + function o() { this.constructor = subclass; } + o.prototype = superclass.prototype; + return (subclass.prototype = new o()); +}; + +},{}],5:[function(_dereq_,module,exports){ +/* +* promote +* Visit http://createjs.com/ for documentation, updates and examples. +* +* Copyright (c) 2010 gskinner.com, inc. +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +/** + * @module CreateJS + */ + +/** + * @class Utility Methods + */ + +/** + * Promotes any methods on the super class that were overridden, by creating an alias in the format `prefix_methodName`. + * It is recommended to use the super class's name as the prefix. + * An alias to the super class's constructor is always added in the format `prefix_constructor`. + * This allows the subclass to call super class methods without using `function.call`, providing better performance. + * + * For example, if `MySubClass` extends `MySuperClass`, and both define a `draw` method, then calling `promote(MySubClass, "MySuperClass")` + * would add a `MySuperClass_constructor` method to MySubClass and promote the `draw` method on `MySuperClass` to the + * prototype of `MySubClass` as `MySuperClass_draw`. + * + * This should be called after the class's prototype is fully defined. + * + * function ClassA(name) { + * this.name = name; + * } + * ClassA.prototype.greet = function() { + * return "Hello "+this.name; + * } + * + * function ClassB(name, punctuation) { + * this.ClassA_constructor(name); + * this.punctuation = punctuation; + * } + * createjs.extend(ClassB, ClassA); + * ClassB.prototype.greet = function() { + * return this.ClassA_greet()+this.punctuation; + * } + * createjs.promote(ClassB, "ClassA"); + * + * var foo = new ClassB("World", "!?!"); + * console.log(foo.greet()); // Hello World!?! + * + * @method promote + * @param {Function} subclass The class to promote super class methods on. + * @param {String} prefix The prefix to add to the promoted method names. Usually the name of the superclass. + * @return {Function} Returns the subclass. + */ +module.exports = function(subclass, prefix) { + "use strict"; + + var subP = subclass.prototype, supP = (Object.getPrototypeOf&&Object.getPrototypeOf(subP))||subP.__proto__; + if (supP) { + subP[(prefix+="_") + "constructor"] = supP.constructor; // constructor is not always innumerable + for (var n in supP) { + if (subP.hasOwnProperty(n) && (typeof supP[n] == "function")) { subP[prefix + n] = supP[n]; } + } + } + return subclass; +}; + +},{}],6:[function(_dereq_,module,exports){ +/* + * Proxy + * Visit http://createjs.com/ for documentation, updates and examples. + * + * Copyright (c) 2010 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module CreateJS + */ + +// namespace: + +/** + * Various utilities that the CreateJS Suite uses. Utilities are created as separate files, and will be available on the + * createjs namespace directly. + * + *

Example

+ * + * myObject.addEventListener("change", createjs.proxy(myMethod, scope)); + * + * @class Utility Methods + * @main Utility Methods + */ + + +/** + * A function proxy for methods. By default, JavaScript methods do not maintain scope, so passing a method as a + * callback will result in the method getting called in the scope of the caller. Using a proxy ensures that the + * method gets called in the correct scope. + * + * Additional arguments can be passed that will be applied to the function when it is called. + * + *

Example

+ * + * myObject.addEventListener("event", createjs.proxy(myHandler, this, arg1, arg2)); + * + * function myHandler(arg1, arg2) { + * // This gets called when myObject.myCallback is executed. + * } + * + * @method proxy + * @param {Function} method The function to call + * @param {Object} scope The scope to call the method name on + * @param {mixed} [arg] * Arguments that are appended to the callback for additional params. + * @public + * @static + */ +module.exports = function (method, scope) { + var aArgs = Array.prototype.slice.call(arguments, 2); + return function () { + return method.apply(scope, Array.prototype.slice.call(arguments, 0).concat(aArgs)); + }; +} +},{}],7:[function(_dereq_,module,exports){ +/* + * LoadQueue + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * PreloadJS provides a consistent way to preload content for use in HTML applications. Preloading can be done using + * HTML tags, as well as XHR. + * + * By default, PreloadJS will try and load content using XHR, since it provides better support for progress and + * completion events, however due to cross-domain issues, it may still be preferable to use tag-based loading + * instead. Note that some content requires XHR to work (plain text, web audio), and some requires tags (HTML audio). + * Note this is handled automatically where possible. + * + * PreloadJS currently supports all modern browsers, and we have done our best to include support for most older + * browsers. If you find an issue with any specific OS/browser combination, please visit http://community.createjs.com/ + * and report it. + * + *

Getting Started

+ * To get started, check out the {{#crossLink "LoadQueue"}}{{/crossLink}} class, which includes a quick overview of how + * to load files and process results. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.installPlugin(createjs.Sound); + * queue.on("complete", handleComplete, this); + * queue.loadFile({id:"sound", src:"http://path/to/sound.mp3"}); + * queue.loadManifest([ + * {id: "myImage", src:"path/to/myImage.jpg"} + * ]); + * function handleComplete() { + * createjs.Sound.play("sound"); + * var image = queue.getResult("myImage"); + * document.body.appendChild(image); + * } + * + * Important note on plugins: Plugins must be installed before items are added to the queue, otherwise + * they will not be processed, even if the load has not actually kicked off yet. Plugin functionality is handled when + * the items are added to the LoadQueue. + * + *

Browser Support

+ * PreloadJS is partially supported in all browsers, and fully supported in all modern browsers. Known exceptions: + * + * + *

Cross-domain Loading

+ * Most content types can be loaded cross-domain, as long as the server supports CORS. PreloadJS also has internal + * support for images served from a CORS-enabled server, via the `crossOrigin` argument on the {{#crossLink "LoadQueue"}}{{/crossLink}} + * constructor. If set to a string value (such as "Anonymous"), the "crossOrigin" property of images generated by + * PreloadJS is set to that value. Please note that setting a `crossOrigin` value on an image that is served from a + * server without CORS will cause other errors. For more info on CORS, visit https://en.wikipedia.org/wiki/Cross-origin_resource_sharing. + * + * @module PreloadJS + * @main PreloadJS + */ + +// namespace: + + +/* + TODO: WINDOWS ISSUES + * No error for HTML audio in IE 678 + * SVG no failure error in IE 67 (maybe 8) TAGS AND XHR + * No script complete handler in IE 67 TAGS (XHR is fine) + * No XML/JSON in IE6 TAGS + * Need to hide loading SVG in Opera TAGS + * No CSS onload/readystatechange in Safari or Android TAGS (requires rule checking) + * SVG no load or failure in Opera XHR + * Reported issues with IE7/8 + */ + +// constructor +/** + * The LoadQueue class is the main API for preloading content. LoadQueue is a load manager, which can preload either + * a single file, or queue of files. + * + * Creating a Queue
+ * To use LoadQueue, create a LoadQueue instance. If you want to force tag loading where possible, set the preferXHR + * argument to false. + * + * var queue = new createjs.LoadQueue(true); + * + * Listening for Events
+ * Add any listeners you want to the queue. Since PreloadJS 0.3.0, the {{#crossLink "EventDispatcher"}}{{/crossLink}} + * lets you add as many listeners as you want for events. You can subscribe to the following events: + * + * queue.on("fileload", handleFileLoad, this); + * queue.on("complete", handleComplete, this); + * + * Adding files and manifests
+ * Add files you want to load using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or add multiple files at a + * time using a list or a manifest definition using {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. Files are + * appended to the end of the active queue, so you can use these methods as many times as you like, whenever you + * like. + * + * queue.loadFile("filePath/file.jpg"); + * queue.loadFile({id:"image", src:"filePath/file.jpg"}); + * queue.loadManifest(["filePath/file.jpg", {id:"image", src:"filePath/file.jpg"}]); + * + * // Use an external manifest + * queue.loadManifest("path/to/manifest.json"); + * queue.loadManifest({src:"manifest.json", type:"manifest"}); + * + * If you pass `false` as the `loadNow` parameter, the queue will not kick of the load of the files, but it will not + * stop if it has already been started. Call the {{#crossLink "AbstractLoader/load"}}{{/crossLink}} method to begin + * a paused queue. Note that a paused queue will automatically resume when new files are added to it with a + * `loadNow` argument of `true`. + * + * queue.load(); + * + * File Types
+ * The file type of a manifest item is auto-determined by the file extension. The pattern matching in PreloadJS + * should handle the majority of standard file and url formats, and works with common file extensions. If you have + * either a non-standard file extension, or are serving the file using a proxy script, then you can pass in a + * type property with any manifest item. + * + * queue.loadFile({src:"path/to/myFile.mp3x", type:AbstractLoader.SOUND}); + * + * // Note that PreloadJS will not read a file extension from the query string + * queue.loadFile({src:"http://server.com/proxy?file=image.jpg", type:AbstractLoader.IMAGE}); + * + * Supported types are defined on the {{#crossLink "AbstractLoader"}}{{/crossLink}} class, and include: + * + * + * Note: Loader types used to be defined on LoadQueue, but have been moved to AbstractLoader for better + * portability of loader classes, which can be used individually now. The properties on LoadQueue still exist, but + * are deprecated. + * + * Handling Results
+ * When a file is finished downloading, a {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event is + * dispatched. In an example above, there is an event listener snippet for fileload. Loaded files are usually a + * formatted object that can be used immediately, including: + * + * + * function handleFileLoad(event) { + * var item = event.item; // A reference to the item that was passed in to the LoadQueue + * var type = item.type; + * + * // Add any images to the page body. + * if (type == createjs.LoadQueue.IMAGE) { + * document.body.appendChild(event.result); + * } + * } + * + * At any time after the file has been loaded (usually after the queue has completed), any result can be looked up + * via its "id" using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. If no id was provided, then the + * "src" or file path can be used instead, including the `path` defined by a manifest, but not including + * a base path defined on the LoadQueue. It is recommended to always pass an id if you want to look up content. + * + * var image = queue.getResult("image"); + * document.body.appendChild(image); + * + * Raw loaded content can be accessed using the rawResult property of the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} + * event, or can be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}, passing `true` as the 2nd + * argument. This is only applicable for content that has been parsed for the browser, specifically: JavaScript, + * CSS, XML, SVG, and JSON objects, or anything loaded with XHR. + * + * var image = queue.getResult("image", true); // load the binary image data loaded with XHR. + * + * Plugins
+ * LoadQueue has a simple plugin architecture to help process and preload content. For example, to preload audio, + * make sure to install the SoundJS Sound class, which will help load HTML audio, + * Flash audio, and WebAudio files. This should be installed before loading any audio files. + * + * queue.installPlugin(createjs.Sound); + * + *

Known Browser Issues

+ * + * + * @class LoadQueue + * @param {Boolean} [preferXHR=true] Determines whether the preload instance will favor loading with XHR (XML HTTP + * Requests), or HTML tags. When this is `false`, the queue will use tag loading when possible, and fall back on XHR + * when necessary. + * @param {String} [basePath=""] A path that will be prepended on to the source parameter of all items in the queue + * before they are loaded. Sources beginning with a protocol such as `http://` or a relative path such as `../` + * will not receive a base path. + * @param {String|Boolean} [crossOrigin=""] An optional flag to support images loaded from a CORS-enabled server. To + * use it, set this value to `true`, which will default the crossOrigin property on images to "Anonymous". Any + * string value will be passed through, but only "" and "Anonymous" are recommended. Note: The crossOrigin + * parameter is deprecated. Use LoadItem.crossOrigin instead + * + * @constructor + * @extends AbstractLoader + */ + +var ImageLoader = _dereq_('./loaders/ImageLoader'); +var extend = _dereq_('../createjs/utils/extend'); +var promote = _dereq_('../createjs/utils/promote'); +var AbstractLoader = _dereq_('./loaders/AbstractLoader'); +var Event = _dereq_('../createjs/events/Event'); +var ErrorEvent = _dereq_('../createjs/events/ErrorEvent'); +var RequestUtils = _dereq_('./utils/RequestUtils'); +var LoadItem = _dereq_('./data/LoadItem'); + +function LoadQueue(preferXHR, basePath, crossOrigin) { + this.AbstractLoader_constructor(); + + /** + * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}. + * @property _plugins + * @type {Array} + * @private + * @since 0.6.1 + */ + this._plugins = []; + + /** + * An object hash of callbacks that are fired for each file type before the file is loaded, giving plugins the + * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} + * method for more information. + * @property _typeCallbacks + * @type {Object} + * @private + */ + this._typeCallbacks = {}; + + /** + * An object hash of callbacks that are fired for each file extension before the file is loaded, giving plugins the + * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} + * method for more information. + * @property _extensionCallbacks + * @type {null} + * @private + */ + this._extensionCallbacks = {}; + + /** + * The next preload queue to process when this one is complete. If an error is thrown in the current queue, and + * {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} is `true`, the next queue will not be processed. + * @property next + * @type {LoadQueue} + * @default null + */ + this.next = null; + + /** + * Ensure loaded scripts "complete" in the order they are specified. Loaded scripts are added to the document head + * once they are loaded. Scripts loaded via tags will load one-at-a-time when this property is `true`, whereas + * scripts loaded using XHR can load in any order, but will "finish" and be added to the document in the order + * specified. + * + * Any items can be set to load in order by setting the {{#crossLink "maintainOrder:property"}}{{/crossLink}} + * property on the load item, or by ensuring that only one connection can be open at a time using + * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Note that when the `maintainScriptOrder` property + * is set to `true`, scripts items are automatically set to `maintainOrder=true`, and changing the + * `maintainScriptOrder` to `false` during a load will not change items already in a queue. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.setMaxConnections(3); // Set a higher number to load multiple items at once + * queue.maintainScriptOrder = true; // Ensure scripts are loaded in order + * queue.loadManifest([ + * "script1.js", + * "script2.js", + * "image.png", // Load any time + * {src: "image2.png", maintainOrder: true} // Will wait for script2.js + * "image3.png", + * "script3.js" // Will wait for image2.png before loading (or completing when loading with XHR) + * ]); + * + * @property maintainScriptOrder + * @type {Boolean} + * @default true + */ + this.maintainScriptOrder = true; + + /** + * Determines if the LoadQueue will stop processing the current queue when an error is encountered. + * @property stopOnError + * @type {Boolean} + * @default false + */ + this.stopOnError = false; + + /** + * The number of maximum open connections that a loadQueue tries to maintain. Please see + * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} for more information. + * @property _maxConnections + * @type {Number} + * @default 1 + * @private + */ + this._maxConnections = 1; + + /** + * An internal list of all the default Loaders that are included with PreloadJS. Before an item is loaded, the + * available loader list is iterated, in the order they are included, and as soon as a loader indicates it can + * handle the content, it will be selected. The default loader, ({{#crossLink "TextLoader"}}{{/crossLink}} is + * last in the list, so it will be used if no other match is found. Typically, loaders will match based on the + * {{#crossLink "LoadItem/type"}}{{/crossLink}}, which is automatically determined using the file extension of + * the {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. + * + * Loaders can be removed from PreloadJS by simply not including them. + * + * Custom loaders installed using {{#crossLink "registerLoader"}}{{/crossLink}} will be prepended to this list + * so that they are checked first. + * @property _availableLoaders + * @type {Array} + * @private + * @since 0.6.0 + */ + this._availableLoaders = [ + ImageLoader + /*, + createjs.JavaScriptLoader, + createjs.CSSLoader, + createjs.JSONLoader, + createjs.JSONPLoader, + createjs.SoundLoader, + createjs.ManifestLoader, + createjs.SpriteSheetLoader, + createjs.XMLLoader, + createjs.SVGLoader, + createjs.BinaryLoader, + createjs.VideoLoader, + createjs.TextLoader + */ + ]; + + /** + * The number of built in loaders, so they can't be removed by {{#crossLink "unregisterLoader"}}{{/crossLink}. + * @property _defaultLoaderLength + * @type {Number} + * @private + * @since 0.6.0 + */ + this._defaultLoaderLength = this._availableLoaders.length; + + this.init(preferXHR, basePath, crossOrigin); +} + +var p = extend(LoadQueue, AbstractLoader); +var s = LoadQueue; + +/** + * REMOVED. Removed in favor of using `MySuperClass_constructor`. + * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} + * for details. + * + * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. + * + * @method initialize + * @protected + * @deprecated + */ +// p.initialize = function() {}; // searchable for devs wondering where it is. + +/** + * An internal initialization method, which is used for initial set up, but also to reset the LoadQueue. + * @method init + * @param preferXHR + * @param basePath + * @param crossOrigin + * @private + */ +p.init = function (preferXHR, basePath, crossOrigin) { + + // public properties + /** + * @property useXHR + * @type {Boolean} + * @readonly + * @default true + * @deprecated Use preferXHR instead. + */ + this.useXHR = true; + + /** + * Try and use XMLHttpRequest (XHR) when possible. Note that LoadQueue will default to tag loading or XHR + * loading depending on the requirements for a media type. For example, HTML audio can not be loaded with XHR, + * and plain text can not be loaded with tags, so it will default the the correct type instead of using the + * user-defined type. + * @type {Boolean} + * @default true + * @since 0.6.0 + */ + this.preferXHR = true; //TODO: Get/Set + this._preferXHR = true; + this.setPreferXHR(preferXHR); + + // protected properties + /** + * Whether the queue is currently paused or not. + * @property _paused + * @type {boolean} + * @private + */ + this._paused = false; + + /** + * A path that will be prepended on to the item's {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. The + * `_basePath` property will only be used if an item's source is relative, and does not include a protocol such + * as `http://`, or a relative path such as `../`. + * @property _basePath + * @type {String} + * @private + * @since 0.3.1 + */ + this._basePath = basePath; + + /** + * An optional flag to set on images that are loaded using PreloadJS, which enables CORS support. Images loaded + * cross-domain by servers that support CORS require the crossOrigin flag to be loaded and interacted with by + * a canvas. When loading locally, or with a server with no CORS support, this flag can cause other security issues, + * so it is recommended to only set it if you are sure the server supports it. Currently, supported values are "" + * and "Anonymous". + * @property _crossOrigin + * @type {String} + * @default "" + * @private + * @since 0.4.1 + */ + this._crossOrigin = crossOrigin; + + /** + * Determines if the loadStart event was dispatched already. This event is only fired one time, when the first + * file is requested. + * @property _loadStartWasDispatched + * @type {Boolean} + * @default false + * @private + */ + this._loadStartWasDispatched = false; + + /** + * Determines if there is currently a script loading. This helps ensure that only a single script loads at once when + * using a script tag to do preloading. + * @property _currentlyLoadingScript + * @type {Boolean} + * @private + */ + this._currentlyLoadingScript = null; + + /** + * An array containing the currently downloading files. + * @property _currentLoads + * @type {Array} + * @private + */ + this._currentLoads = []; + + /** + * An array containing the queued items that have not yet started downloading. + * @property _loadQueue + * @type {Array} + * @private + */ + this._loadQueue = []; + + /** + * An array containing downloads that have not completed, so that the LoadQueue can be properly reset. + * @property _loadQueueBackup + * @type {Array} + * @private + */ + this._loadQueueBackup = []; + + /** + * An object hash of items that have finished downloading, indexed by the {{#crossLink "LoadItem"}}{{/crossLink}} + * id. + * @property _loadItemsById + * @type {Object} + * @private + */ + this._loadItemsById = {}; + + /** + * An object hash of items that have finished downloading, indexed by {{#crossLink "LoadItem"}}{{/crossLink}} + * source. + * @property _loadItemsBySrc + * @type {Object} + * @private + */ + this._loadItemsBySrc = {}; + + /** + * An object hash of loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. + * @property _loadedResults + * @type {Object} + * @private + */ + this._loadedResults = {}; + + /** + * An object hash of un-parsed loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. + * @property _loadedRawResults + * @type {Object} + * @private + */ + this._loadedRawResults = {}; + + /** + * The number of items that have been requested. This helps manage an overall progress without knowing how large + * the files are before they are downloaded. This does not include items inside of loaders such as the + * {{#crossLink "ManifestLoader"}}{{/crossLink}}. + * @property _numItems + * @type {Number} + * @default 0 + * @private + */ + this._numItems = 0; + + /** + * The number of items that have completed loaded. This helps manage an overall progress without knowing how large + * the files are before they are downloaded. + * @property _numItemsLoaded + * @type {Number} + * @default 0 + * @private + */ + this._numItemsLoaded = 0; + + /** + * A list of scripts in the order they were requested. This helps ensure that scripts are "completed" in the right + * order. + * @property _scriptOrder + * @type {Array} + * @private + */ + this._scriptOrder = []; + + /** + * A list of scripts that have been loaded. Items are added to this list as null when they are + * requested, contain the loaded item if it has completed, but not been dispatched to the user, and true + * once they are complete and have been dispatched. + * @property _loadedScripts + * @type {Array} + * @private + */ + this._loadedScripts = []; + + /** + * The last progress amount. This is used to suppress duplicate progress events. + * @property _lastProgress + * @type {Number} + * @private + * @since 0.6.0 + */ + this._lastProgress = NaN; + +}; + +// static properties +/** + * The time in milliseconds to assume a load has failed. An {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} + * event is dispatched if the timeout is reached before any data is received. + * @property loadTimeout + * @type {Number} + * @default 8000 + * @static + * @since 0.4.1 + * @deprecated In favour of {{#crossLink "LoadItem/LOAD_TIMEOUT_DEFAULT:property}}{{/crossLink}} property. + */ +s.loadTimeout = 8000; + +/** + * The time in milliseconds to assume a load has failed. + * @property LOAD_TIMEOUT + * @type {Number} + * @default 0 + * @deprecated in favor of the {{#crossLink "LoadQueue/loadTimeout:property"}}{{/crossLink}} property. + */ +s.LOAD_TIMEOUT = 0; + +// Preload Types +/** + * @property BINARY + * @type {String} + * @default binary + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}} instead. + */ +s.BINARY = AbstractLoader.BINARY; + +/** + * @property CSS + * @type {String} + * @default css + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. + */ +s.CSS = AbstractLoader.CSS; + +/** + * @property IMAGE + * @type {String} + * @default image + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. + */ +s.IMAGE = AbstractLoader.IMAGE; + +/** + * @property JAVASCRIPT + * @type {String} + * @default javascript + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ +s.JAVASCRIPT = AbstractLoader.JAVASCRIPT; + +/** + * @property JSON + * @type {String} + * @default json + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}} instead. + */ +s.JSON = AbstractLoader.JSON; + +/** + * @property JSONP + * @type {String} + * @default jsonp + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}} instead. + */ +s.JSONP = AbstractLoader.JSONP; + +/** + * @property MANIFEST + * @type {String} + * @default manifest + * @static + * @since 0.4.1 + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}} instead. + */ +s.MANIFEST = AbstractLoader.MANIFEST; + +/** + * @property SOUND + * @type {String} + * @default sound + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ +s.SOUND = AbstractLoader.SOUND; + +/** + * @property VIDEO + * @type {String} + * @default video + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ +s.VIDEO = AbstractLoader.VIDEO; + +/** + * @property SVG + * @type {String} + * @default svg + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}} instead. + */ +s.SVG = AbstractLoader.SVG; + +/** + * @property TEXT + * @type {String} + * @default text + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}} instead. + */ +s.TEXT = AbstractLoader.TEXT; + +/** + * @property XML + * @type {String} + * @default xml + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}} instead. + */ +s.XML = AbstractLoader.XML; + +/** + * @property POST + * @type {string} + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} instead. + */ +s.POST = AbstractLoader.POST; + +/** + * @property GET + * @type {string} + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} instead. + */ +s.GET = AbstractLoader.GET; + +// events +/** + * This event is fired when an individual file has loaded, and been processed. + * @event fileload + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a `src` property. + * @param {Object} result The HTML tag or parsed result of the loaded item. + * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted + * to a usable object. + * @since 0.3.0 + */ + +/** + * This {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when an an individual file's progress changes. + * @event fileprogress + * @since 0.3.0 + */ + +/** + * This event is fired when an individual file starts to load. + * @event filestart + * @param {Object} The object that dispatched the event. + * @param {String} type The event type. + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a property. + */ + +/** + * Although it extends {{#crossLink "AbstractLoader"}}{{/crossLink}}, the `initialize` event is never fired from + * a LoadQueue instance. + * @event initialize + * @private + */ + +// public methods +/** + * Register a custom loaders class. New loaders are given precedence over loaders added earlier and default loaders. + * It is recommended that loaders extend {{#crossLink "AbstractLoader"}}{{/crossLink}}. Loaders can only be added + * once, and will be prepended to the list of available loaders. + * @method registerLoader + * @param {Function|AbstractLoader} loader The AbstractLoader class to add. + * @since 0.6.0 + */ +p.registerLoader = function (loader) { + if (!loader || !loader.canLoadItem) { + throw new Error("loader is of an incorrect type."); + } else if (this._availableLoaders.indexOf(loader) != -1) { + throw new Error("loader already exists."); //LM: Maybe just silently fail here + } + + this._availableLoaders.unshift(loader); +}; + +/** + * Remove a custom loader added using {{#crossLink "registerLoader"}}{{/crossLink}}. Only custom loaders can be + * unregistered, the default loaders will always be available. + * @method unregisterLoader + * @param {Function|AbstractLoader} loader The AbstractLoader class to remove + */ +p.unregisterLoader = function (loader) { + var idx = this._availableLoaders.indexOf(loader); + if (idx != -1 && idx < this._defaultLoaderLength - 1) { + this._availableLoaders.splice(idx, 1); + } +}; + +/** + * @method setUseXHR + * @param {Boolean} value The new useXHR value to set. + * @return {Boolean} The new useXHR value. If XHR is not supported by the browser, this will return false, even if + * the provided value argument was true. + * @since 0.3.0 + * @deprecated use the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property, or the + * {{#crossLink "LoadQueue/setUseXHR"}}{{/crossLink}} method instead. + */ +p.setUseXHR = function (value) { + return this.setPreferXHR(value); +}; + +/** + * Change the {{#crossLink "preferXHR:property"}}{{/crossLink}} value. Note that if this is set to `true`, it may + * fail, or be ignored depending on the browser's capabilities and the load type. + * @method setPreferXHR + * @param {Boolean} value + * @returns {Boolean} The value of {{#crossLink "preferXHR"}}{{/crossLink}} that was successfully set. + * @since 0.6.0 + */ +p.setPreferXHR = function (value) { + // Determine if we can use XHR. XHR defaults to TRUE, but the browser may not support it. + //TODO: Should we be checking for the other XHR types? Might have to do a try/catch on the different types similar to createXHR. + this.preferXHR = (value != false && window.XMLHttpRequest != null); + return this.preferXHR; +}; + +/** + * Stops all queued and loading items, and clears the queue. This also removes all internal references to loaded + * content, and allows the queue to be used again. + * @method removeAll + * @since 0.3.0 + */ +p.removeAll = function () { + this.remove(); +}; + +/** + * Stops an item from being loaded, and removes it from the queue. If nothing is passed, all items are removed. + * This also removes internal references to loaded item(s). + * + *

Example

+ * + * queue.loadManifest([ + * {src:"test.png", id:"png"}, + * {src:"test.jpg", id:"jpg"}, + * {src:"test.mp3", id:"mp3"} + * ]); + * queue.remove("png"); // Single item by ID + * queue.remove("png", "test.jpg"); // Items as arguments. Mixed id and src. + * queue.remove(["test.png", "jpg"]); // Items in an Array. Mixed id and src. + * + * @method remove + * @param {String | Array} idsOrUrls* The id or ids to remove from this queue. You can pass an item, an array of + * items, or multiple items as arguments. + * @since 0.3.0 + */ +p.remove = function (idsOrUrls) { + var args = null; + + if (idsOrUrls && !Array.isArray(idsOrUrls)) { + args = [idsOrUrls]; + } else if (idsOrUrls) { + args = idsOrUrls; + } else if (arguments.length > 0) { + return; + } + + var itemsWereRemoved = false; + + // Destroy everything + if (!args) { + this.close(); + for (var n in this._loadItemsById) { + this._disposeItem(this._loadItemsById[n]); + } + this.init(this.preferXHR, this._basePath); + + // Remove specific items + } else { + while (args.length) { + var item = args.pop(); + var r = this.getResult(item); + + //Remove from the main load Queue + for (i = this._loadQueue.length - 1; i >= 0; i--) { + loadItem = this._loadQueue[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._loadQueue.splice(i, 1)[0].cancel(); + break; + } + } + + //Remove from the backup queue + for (i = this._loadQueueBackup.length - 1; i >= 0; i--) { + loadItem = this._loadQueueBackup[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._loadQueueBackup.splice(i, 1)[0].cancel(); + break; + } + } + + if (r) { + this._disposeItem(this.getItem(item)); + } else { + for (var i = this._currentLoads.length - 1; i >= 0; i--) { + var loadItem = this._currentLoads[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._currentLoads.splice(i, 1)[0].cancel(); + itemsWereRemoved = true; + break; + } + } + } + } + + // If this was called during a load, try to load the next item. + if (itemsWereRemoved) { + this._loadNext(); + } + } +}; + +/** + * Stops all open loads, destroys any loaded items, and resets the queue, so all items can + * be reloaded again by calling {{#crossLink "AbstractLoader/load"}}{{/crossLink}}. Items are not removed from the + * queue. To remove items use the {{#crossLink "LoadQueue/remove"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/removeAll"}}{{/crossLink}} method. + * @method reset + * @since 0.3.0 + */ +p.reset = function () { + this.close(); + for (var n in this._loadItemsById) { + this._disposeItem(this._loadItemsById[n]); + } + + //Reset the queue to its start state + var a = []; + for (var i = 0, l = this._loadQueueBackup.length; i < l; i++) { + a.push(this._loadQueueBackup[i].getItem()); + } + + this.loadManifest(a, false); +}; + +/** + * Register a plugin. Plugins can map to load types (sound, image, etc), or specific extensions (png, mp3, etc). + * Currently, only one plugin can exist per type/extension. + * + * When a plugin is installed, a getPreloadHandlers() method will be called on it. For more information + * on this method, check out the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method in the + * {{#crossLink "SamplePlugin"}}{{/crossLink}} class. + * + * Before a file is loaded, a matching plugin has an opportunity to modify the load. If a `callback` is returned + * from the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method, it will be invoked first, and its + * result may cancel or modify the item. The callback method can also return a `completeHandler` to be fired when + * the file is loaded, or a `tag` object, which will manage the actual download. For more information on these + * methods, check out the {{#crossLink "SamplePlugin/preloadHandler"}}{{/crossLink}} and {{#crossLink "SamplePlugin/fileLoadHandler"}}{{/crossLink}} + * methods on the {{#crossLink "SamplePlugin"}}{{/crossLink}}. + * + * @method installPlugin + * @param {Function} plugin The plugin class to install. + */ +p.installPlugin = function (plugin) { + if (plugin == null) { + return; + } + + if (plugin.getPreloadHandlers != null) { + this._plugins.push(plugin); + var map = plugin.getPreloadHandlers(); + map.scope = plugin; + + if (map.types != null) { + for (var i = 0, l = map.types.length; i < l; i++) { + this._typeCallbacks[map.types[i]] = map; + } + } + + if (map.extensions != null) { + for (i = 0, l = map.extensions.length; i < l; i++) { + this._extensionCallbacks[map.extensions[i]] = map; + } + } + } +}; + +/** + * Set the maximum number of concurrent connections. Note that browsers and servers may have a built-in maximum + * number of open connections, so any additional connections may remain in a pending state until the browser + * opens the connection. When loading scripts using tags, and when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} + * is `true`, only one script is loaded at a time due to browser limitations. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.setMaxConnections(10); // Allow 10 concurrent loads + * + * @method setMaxConnections + * @param {Number} value The number of concurrent loads to allow. By default, only a single connection per LoadQueue + * is open at any time. + */ +p.setMaxConnections = function (value) { + this._maxConnections = value; + if (!this._paused && this._loadQueue.length > 0) { + this._loadNext(); + } +}; + +/** + * Load a single file. To add multiple files at once, use the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * method. + * + * Files are always appended to the current queue, so this method can be used multiple times to add files. + * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. + * @method loadFile + * @param {LoadItem|Object|String} file The file object or path to load. A file can be either + * + * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default + * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}}, and the value is + * `true`, the queue will resume automatically. + * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the + * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}, + * its files will NOT use the basePath parameter. The basePath parameter is deprecated. + * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue + * constructor, or a `path` property in a manifest definition. + */ +p.loadFile = function (file, loadNow, basePath) { + if (file == null) { + var event = new ErrorEvent("PRELOAD_NO_FILE"); + this._sendError(event); + return; + } + this._addItem(file, null, basePath); + + if (loadNow !== false) { + this.setPaused(false); + } else { + this.setPaused(true); + } +}; + +/** + * Load an array of files. To load a single file, use the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} method. + * The files in the manifest are requested in the same order, but may complete in a different order if the max + * connections are set above 1 using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Scripts will load + * in the right order as long as {{#crossLink "LoadQueue/maintainScriptOrder"}}{{/crossLink}} is true (which is + * default). + * + * Files are always appended to the current queue, so this method can be used multiple times to add files. + * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. + * @method loadManifest + * @param {Array|String|Object} manifest An list of files to load. The loadManifest call supports four types of + * manifests: + *
    + *
  1. A string path, which points to a manifest file, which is a JSON file that contains a "manifest" property, + * which defines the list of files to load, and can optionally contain a "path" property, which will be + * prepended to each file in the list.
  2. + *
  3. An object which defines a "src", which is a JSON or JSONP file. A "callback" can be defined for JSONP + * file. The JSON/JSONP file should contain a "manifest" property, which defines the list of files to load, + * and can optionally contain a "path" property, which will be prepended to each file in the list.
  4. + *
  5. An object which contains a "manifest" property, which defines the list of files to load, and can + * optionally contain a "path" property, which will be prepended to each file in the list.
  6. + *
  7. An Array of files to load.
  8. + *
+ * + * Each "file" in a manifest can be either: + * + * + * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default + * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} and this value is + * `true`, the queue will resume automatically. + * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the + * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "LoadQueue/MANIFEST:property"}}{{/crossLink}}, + * its files will NOT use the basePath parameter. The basePath parameter is deprecated. + * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue + * constructor, or a `path` property in a manifest definition. + */ +p.loadManifest = function (manifest, loadNow, basePath) { + var fileList = null; + var path = null; + + // Array-based list of items + if (Array.isArray(manifest)) { + if (manifest.length == 0) { + var event = new ErrorEvent("PRELOAD_MANIFEST_EMPTY"); + this._sendError(event); + return; + } + fileList = manifest; + + // String-based. Only file manifests can be specified this way. Any other types will cause an error when loaded. + } else if (typeof(manifest) === "string") { + fileList = [ + { + src: manifest, + type: s.MANIFEST + } + ]; + + } else if (typeof(manifest) == "object") { + + // An object that defines a manifest path + if (manifest.src !== undefined) { + if (manifest.type == null) { + manifest.type = s.MANIFEST; + } else if (manifest.type != s.MANIFEST) { + var event = new ErrorEvent("PRELOAD_MANIFEST_TYPE"); + this._sendError(event); + } + fileList = [manifest]; + + // An object that defines a manifest + } else if (manifest.manifest !== undefined) { + fileList = manifest.manifest; + path = manifest.path; + } + + // Unsupported. This will throw an error. + } else { + var event = new ErrorEvent("PRELOAD_MANIFEST_NULL"); + this._sendError(event); + return; + } + + for (var i = 0, l = fileList.length; i < l; i++) { + this._addItem(fileList[i], path, basePath); + } + + if (loadNow !== false) { + this.setPaused(false); + } else { + this.setPaused(true); + } + +}; + +/** + * Start a LoadQueue that was created, but not automatically started. + * @method load + */ +p.load = function () { + this.setPaused(false); +}; + +/** + * Look up a {{#crossLink "LoadItem"}}{{/crossLink}} using either the "id" or "src" that was specified when loading it. Note that if no "id" was + * supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The + * `basePath` will not be part of the ID. + * @method getItem + * @param {String} value The id or src of the load item. + * @return {Object} The load item that was initially requested using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} + * event as the `item` parameter. + */ +p.getItem = function (value) { + return this._loadItemsById[value] || this._loadItemsBySrc[value]; +}; + +/** + * Look up a loaded result using either the "id" or "src" that was specified when loading it. Note that if no "id" + * was supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The + * `basePath` will not be part of the ID. + * @method getResult + * @param {String} value The id or src of the load item. + * @param {Boolean} [rawResult=false] Return a raw result instead of a formatted result. This applies to content + * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be + * returned instead. + * @return {Object} A result object containing the content that was loaded, such as: + * + * This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event as the 'item` + * parameter. Note that if a raw result is requested, but not found, the result will be returned instead. + */ +p.getResult = function (value, rawResult) { + var item = this._loadItemsById[value] || this._loadItemsBySrc[value]; + if (item == null) { + return null; + } + var id = item.id; + if (rawResult && this._loadedRawResults[id]) { + return this._loadedRawResults[id]; + } + return this._loadedResults[id]; +}; + +/** + * Generate an list of items loaded by this queue. + * @method getItems + * @param {Boolean} loaded Determines if only items that have been loaded should be returned. If false, in-progress + * and failed load items will also be included. + * @returns {Array} A list of objects that have been loaded. Each item includes the {{#crossLink "LoadItem"}}{{/crossLink}}, + * result, and rawResult. + * @since 0.6.0 + */ +p.getItems = function (loaded) { + var arr = []; + for (var n in this._loadItemsById) { + var item = this._loadItemsById[n]; + var result = this.getResult(n); + if (loaded === true && result == null) { + continue; + } + arr.push({ + item: item, + result: result, + rawResult: this.getResult(n, true) + }); + } + return arr; +}; + +/** + * Pause or resume the current load. Active loads will not be cancelled, but the next items in the queue will not + * be processed when active loads complete. LoadQueues are not paused by default. + * + * Note that if new items are added to the queue using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}, a paused queue will be resumed, unless the `loadNow` + * argument is `false`. + * @method setPaused + * @param {Boolean} value Whether the queue should be paused or not. + */ +p.setPaused = function (value) { + this._paused = value; + if (!this._paused) { + this._loadNext(); + } +}; + +/** + * Close the active queue. Closing a queue completely empties the queue, and prevents any remaining items from + * starting to download. Note that currently any active loads will remain open, and events may be processed. + * + * To stop and restart a queue, use the {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} method instead. + * @method close + */ +p.close = function () { + while (this._currentLoads.length) { + this._currentLoads.pop().cancel(); + } + this._scriptOrder.length = 0; + this._loadedScripts.length = 0; + this.loadStartWasDispatched = false; + this._itemCount = 0; + this._lastProgress = NaN; +}; + +// protected methods +/** + * Add an item to the queue. Items are formatted into a usable object containing all the properties necessary to + * load the content. The load queue is populated with the loader instance that handles preloading, and not the load + * item that was passed in by the user. To look up the load item by id or src, use the {{#crossLink "LoadQueue.getItem"}}{{/crossLink}} + * method. + * @method _addItem + * @param {String|Object} value The item to add to the queue. + * @param {String} [path] An optional path prepended to the `src`. The path will only be prepended if the src is + * relative, and does not start with a protocol such as `http://`, or a path like `../`. If the LoadQueue was + * provided a {{#crossLink "_basePath"}}{{/crossLink}}, then it will optionally be prepended after. + * @param {String} [basePath] DeprecatedAn optional basePath passed into a {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} call. This parameter will be removed in a future tagged + * version. + * @private + */ +p._addItem = function (value, path, basePath) { + var item = this._createLoadItem(value, path, basePath); // basePath and manifest path are added to the src. + if (item == null) { + return; + } // Sometimes plugins or types should be skipped. + var loader = this._createLoader(item); + if (loader != null) { + if ("plugins" in loader) { + loader.plugins = this._plugins; + } + item._loader = loader; + this._loadQueue.push(loader); + this._loadQueueBackup.push(loader); + + this._numItems++; + this._updateProgress(); + + // Only worry about script order when using XHR to load scripts. Tags are only loading one at a time. + if ((this.maintainScriptOrder + && item.type == LoadQueue.JAVASCRIPT + //&& loader instanceof createjs.XHRLoader //NOTE: Have to track all JS files this way + ) + || item.maintainOrder === true) { + this._scriptOrder.push(item); + this._loadedScripts.push(null); + } + } +}; + +/** + * Create a refined {{#crossLink "LoadItem"}}{{/crossLink}}, which contains all the required properties. The type of + * item is determined by browser support, requirements based on the file type, and developer settings. For example, + * XHR is only used for file types that support it in new browsers. + * + * Before the item is returned, any plugins registered to handle the type or extension will be fired, which may + * alter the load item. + * @method _createLoadItem + * @param {String | Object | HTMLAudioElement | HTMLImageElement} value The item that needs to be preloaded. + * @param {String} [path] A path to prepend to the item's source. Sources beginning with http:// or similar will + * not receive a path. Since PreloadJS 0.4.1, the src will be modified to include the `path` and {{#crossLink "LoadQueue/_basePath:property"}}{{/crossLink}} + * when it is added. + * @param {String} [basePath] Deprectated A base path to prepend to the items source in addition to + * the path argument. + * @return {Object} The loader instance that will be used. + * @private + */ +p._createLoadItem = function (value, path, basePath) { + var item = LoadItem.create(value); + if (item == null) { + return null; + } + + var bp = ""; // Store the generated basePath + var useBasePath = basePath || this._basePath; + + if (item.src instanceof Object) { + if (!item.type) { + return null; + } // the the src is an object, type is required to pass off to plugin + if (path) { + bp = path; + var pathMatch = RequestUtils.parseURI(path); + // Also append basePath + if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { + bp = useBasePath + bp; + } + } else if (useBasePath != null) { + bp = useBasePath; + } + } else { + // Determine Extension, etc. + var match = RequestUtils.parseURI(item.src); + if (match.extension) { + item.ext = match.extension; + } + if (item.type == null) { + item.type = RequestUtils.getTypeByExtension(item.ext); + } + + // Inject path & basePath + var autoId = item.src; + if (!match.absolute && !match.relative) { + if (path) { + bp = path; + var pathMatch = RequestUtils.parseURI(path); + autoId = path + autoId; + // Also append basePath + if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { + bp = useBasePath + bp; + } + } else if (useBasePath != null) { + bp = useBasePath; + } + } + item.src = bp + item.src; + } + item.path = bp; + + // If there's no id, set one now. + if (item.id === undefined || item.id === null || item.id === "") { + item.id = autoId; + } + + // Give plugins a chance to modify the loadItem: + var customHandler = this._typeCallbacks[item.type] || this._extensionCallbacks[item.ext]; + if (customHandler) { + // Plugins are now passed both the full source, as well as a combined path+basePath (appropriately) + var result = customHandler.callback.call(customHandler.scope, item, this); + + // The plugin will handle the load, or has canceled it. Ignore it. + if (result === false) { + return null; + + // Load as normal: + } else if (result === true) { + // Do Nothing + + // Result is a loader class: + } else if (result != null) { + item._loader = result; + } + + // Update the extension in case the type changed: + match = RequestUtils.parseURI(item.src); + if (match.extension != null) { + item.ext = match.extension; + } + } + + // Store the item for lookup. This also helps clean-up later. + this._loadItemsById[item.id] = item; + this._loadItemsBySrc[item.src] = item; + + if (item.crossOrigin == null) { + item.crossOrigin = this._crossOrigin; + } + + return item; +}; + +/** + * Create a loader for a load item. + * @method _createLoader + * @param {Object} item A formatted load item that can be used to generate a loader. + * @return {AbstractLoader} A loader that can be used to load content. + * @private + */ +p._createLoader = function (item) { + if (item._loader != null) { // A plugin already specified a loader + return item._loader; + } + + // Initially, try and use the provided/supported XHR mode: + var preferXHR = this.preferXHR; + + for (var i = 0; i < this._availableLoaders.length; i++) { + var loader = this._availableLoaders[i]; + if (loader && loader.canLoadItem(item)) { + return new loader(item, preferXHR); + } + } + + // TODO: Log error (requires createjs.log) + return null; +}; + +/** + * Load the next item in the queue. If the queue is empty (all items have been loaded), then the complete event + * is processed. The queue will "fill up" any empty slots, up to the max connection specified using + * {{#crossLink "LoadQueue.setMaxConnections"}}{{/crossLink}} method. The only exception is scripts that are loaded + * using tags, which have to be loaded one at a time to maintain load order. + * @method _loadNext + * @private + */ +p._loadNext = function () { + if (this._paused) { + return; + } + + // Only dispatch loadstart event when the first file is loaded. + if (!this._loadStartWasDispatched) { + this._sendLoadStart(); + this._loadStartWasDispatched = true; + } + + // The queue has completed. + if (this._numItems == this._numItemsLoaded) { + this.loaded = true; + this._sendComplete(); + + // Load the next queue, if it has been defined. + if (this.next && this.next.load) { + this.next.load(); + } + } else { + this.loaded = false; + } + + // Must iterate forwards to load in the right order. + for (var i = 0; i < this._loadQueue.length; i++) { + if (this._currentLoads.length >= this._maxConnections) { + break; + } + var loader = this._loadQueue[i]; + + // Determine if we should be only loading one tag-script at a time: + // Note: maintainOrder items don't do anything here because we can hold onto their loaded value + if (!this._canStartLoad(loader)) { + continue; + } + this._loadQueue.splice(i, 1); + i--; + this._loadItem(loader); + } +}; + +/** + * Begin loading an item. Event listeners are not added to the loaders until the load starts. + * @method _loadItem + * @param {AbstractLoader} loader The loader instance to start. Currently, this will be an XHRLoader or TagLoader. + * @private + */ +p._loadItem = function (loader) { + loader.on("fileload", this._handleFileLoad, this); + loader.on("progress", this._handleProgress, this); + loader.on("complete", this._handleFileComplete, this); + loader.on("error", this._handleError, this); + loader.on("fileerror", this._handleFileError, this); + this._currentLoads.push(loader); + this._sendFileStart(loader.getItem()); + loader.load(); +}; + +/** + * The callback that is fired when a loader loads a file. This enables loaders like {{#crossLink "ManifestLoader"}}{{/crossLink}} + * to maintain internal queues, but for this queue to dispatch the {{#crossLink "fileload:event"}}{{/crossLink}} + * events. + * @param {Event} event The {{#crossLink "AbstractLoader/fileload:event"}}{{/crossLink}} event from the loader. + * @private + * @since 0.6.0 + */ +p._handleFileLoad = function (event) { + event.target = null; + this.dispatchEvent(event); +}; + +/** + * The callback that is fired when a loader encounters an error from an internal file load operation. This enables + * loaders like M + * @param event + * @private + */ +p._handleFileError = function (event) { + var newEvent = new ErrorEvent("FILE_LOAD_ERROR", null, event.item); + this._sendError(newEvent); +}; + +/** + * The callback that is fired when a loader encounters an error. The queue will continue loading unless {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} + * is set to `true`. + * @method _handleError + * @param {ErrorEvent} event The error event, containing relevant error information. + * @private + */ +p._handleError = function (event) { + var loader = event.target; + this._numItemsLoaded++; + + this._finishOrderedItem(loader, true); + this._updateProgress(); + + var newEvent = new ErrorEvent("FILE_LOAD_ERROR", null, loader.getItem()); + // TODO: Propagate actual error message. + + this._sendError(newEvent); + + if (!this.stopOnError) { + this._removeLoadItem(loader); + this._cleanLoadItem(loader); + this._loadNext(); + } else { + this.setPaused(true); + } +}; + +/** + * An item has finished loading. We can assume that it is totally loaded, has been parsed for immediate use, and + * is available as the "result" property on the load item. The raw text result for a parsed item (such as JSON, XML, + * CSS, JavaScript, etc) is available as the "rawResult" property, and can also be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. + * @method _handleFileComplete + * @param {Event} event The event object from the loader. + * @private + */ +p._handleFileComplete = function (event) { + var loader = event.target; + var item = loader.getItem(); + + var result = loader.getResult(); + this._loadedResults[item.id] = result; + var rawResult = loader.getResult(true); + if (rawResult != null && rawResult !== result) { + this._loadedRawResults[item.id] = rawResult; + } + + this._saveLoadedItems(loader); + + // Remove the load item + this._removeLoadItem(loader); + + if (!this._finishOrderedItem(loader)) { + // The item was NOT managed, so process it now + this._processFinishedLoad(item, loader); + } + + // Clean up the load item + this._cleanLoadItem(loader); +}; + +/** + * Some loaders might load additional content, other than the item they were passed (such as {{#crossLink "ManifestLoader"}}{{/crossLink}}). + * Any items exposed by the loader using {{#crossLink "AbstractLoader/getLoadItems"}}{{/crossLink}} are added to the + * LoadQueue's look-ups, including {{#crossLink "getItem"}}{{/crossLink}} and {{#crossLink "getResult"}}{{/crossLink}} + * methods. + * @method _saveLoadedItems + * @param {AbstractLoader} loader + * @protected + * @since 0.6.0 + */ +p._saveLoadedItems = function (loader) { + // TODO: Not sure how to handle this. Would be nice to expose the items. + // Loaders may load sub-items. This adds them to this queue + var list = loader.getLoadedItems(); + if (list === null) { + return; + } + + for (var i = 0; i < list.length; i++) { + var item = list[i].item; + + // Store item lookups + this._loadItemsBySrc[item.src] = item; + this._loadItemsById[item.id] = item; + + // Store loaded content + this._loadedResults[item.id] = list[i].result; + this._loadedRawResults[item.id] = list[i].rawResult; + } +}; + +/** + * Flag an item as finished. If the item's order is being managed, then ensure that it is allowed to finish, and if + * so, trigger prior items to trigger as well. + * @method _finishOrderedItem + * @param {AbstractLoader} loader + * @param {Boolean} loadFailed + * @return {Boolean} If the item's order is being managed. This allows the caller to take an alternate + * behaviour if it is. + * @private + */ +p._finishOrderedItem = function (loader, loadFailed) { + var item = loader.getItem(); + + if ((this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) + || item.maintainOrder) { + + //TODO: Evaluate removal of the _currentlyLoadingScript + if (loader instanceof createjs.JavaScriptLoader) { + this._currentlyLoadingScript = false; + } + + var index = createjs.indexOf(this._scriptOrder, item); + if (index == -1) { + return false; + } // This loader no longer exists + this._loadedScripts[index] = (loadFailed === true) ? true : item; + + this._checkScriptLoadOrder(); + return true; + } + + return false; +}; + +/** + * Ensure the scripts load and dispatch in the correct order. When using XHR, scripts are stored in an array in the + * order they were added, but with a "null" value. When they are completed, the value is set to the load item, + * and then when they are processed and dispatched, the value is set to `true`. This method simply + * iterates the array, and ensures that any loaded items that are not preceded by a `null` value are + * dispatched. + * @method _checkScriptLoadOrder + * @private + */ +p._checkScriptLoadOrder = function () { + var l = this._loadedScripts.length; + + for (var i = 0; i < l; i++) { + var item = this._loadedScripts[i]; + if (item === null) { + break; + } // This is still loading. Do not process further. + if (item === true) { + continue; + } // This has completed, and been processed. Move on. + + var loadItem = this._loadedResults[item.id]; + if (item.type == createjs.LoadQueue.JAVASCRIPT) { + // Append script tags to the head automatically. + createjs.DomUtils.appendToHead(loadItem); + } + + var loader = item._loader; + this._processFinishedLoad(item, loader); + this._loadedScripts[i] = true; + } +}; + +/** + * A file has completed loading, and the LoadQueue can move on. This triggers the complete event, and kick-starts + * the next item. + * @method _processFinishedLoad + * @param {LoadItem|Object} item + * @param {AbstractLoader} loader + * @protected + */ +p._processFinishedLoad = function (item, loader) { + this._numItemsLoaded++; + + // Since LoadQueue needs maintain order, we can't append scripts in the loader. + // So we do it here instead. Or in _checkScriptLoadOrder(); + if (!this.maintainScriptOrder && item.type == LoadQueue.JAVASCRIPT) { + var tag = loader.getTag(); + createjs.DomUtils.appendToHead(tag); + } + + this._updateProgress(); + this._sendFileComplete(item, loader); + this._loadNext(); +}; + +/** + * Ensure items with `maintainOrder=true` that are before the specified item have loaded. This only applies to + * JavaScript items that are being loaded with a TagLoader, since they have to be loaded and completed before + * the script can even be started, since it exist in the DOM while loading. + * @method _canStartLoad + * @param {AbstractLoader} loader The loader for the item + * @return {Boolean} Whether the item can start a load or not. + * @private + */ +p._canStartLoad = function (loader) { + if (!this.maintainScriptOrder || loader.preferXHR) { + return true; + } + var item = loader.getItem(); + if (item.type != LoadQueue.JAVASCRIPT) { + return true; + } + if (this._currentlyLoadingScript) { + return false; + } + + var index = this._scriptOrder.indexOf(item); + var i = 0; + while (i < index) { + var checkItem = this._loadedScripts[i]; + if (checkItem == null) { + return false; + } + i++; + } + this._currentlyLoadingScript = true; + return true; +}; + +/** + * A load item is completed or was canceled, and needs to be removed from the LoadQueue. + * @method _removeLoadItem + * @param {AbstractLoader} loader A loader instance to remove. + * @private + */ +p._removeLoadItem = function (loader) { + var l = this._currentLoads.length; + for (var i = 0; i < l; i++) { + if (this._currentLoads[i] == loader) { + this._currentLoads.splice(i, 1); + break; + } + } +}; + +/** + * Remove unneeded references from a loader. + * + * @param loader + * @private + */ +p._cleanLoadItem = function (loader) { + var item = loader.getItem(); + if (item) { + delete item._loader; + } +} + +/** + * An item has dispatched progress. Propagate that progress, and update the LoadQueue's overall progress. + * @method _handleProgress + * @param {ProgressEvent} event The progress event from the item. + * @private + */ +p._handleProgress = function (event) { + var loader = event.target; + this._sendFileProgress(loader.getItem(), loader.progress); + this._updateProgress(); +}; + +/** + * Overall progress has changed, so determine the new progress amount and dispatch it. This changes any time an + * item dispatches progress or completes. Note that since we don't always know the actual filesize of items before + * they are loaded. In this case, we define a "slot" for each item (1 item in 10 would get 10%), and then append + * loaded progress on top of the already-loaded items. + * + * For example, if 5/10 items have loaded, and item 6 is 20% loaded, the total progress would be: + * + * @method _updateProgress + * @private + */ +p._updateProgress = function () { + var loaded = this._numItemsLoaded / this._numItems; // Fully Loaded Progress + var remaining = this._numItems - this._numItemsLoaded; + if (remaining > 0) { + var chunk = 0; + for (var i = 0, l = this._currentLoads.length; i < l; i++) { + chunk += this._currentLoads[i].progress; + } + loaded += (chunk / remaining) * (remaining / this._numItems); + } + + if (this._lastProgress != loaded) { + this._sendProgress(loaded); + this._lastProgress = loaded; + } +}; + +/** + * Clean out item results, to free them from memory. Mainly, the loaded item and results are cleared from internal + * hashes. + * @method _disposeItem + * @param {LoadItem|Object} item The item that was passed in for preloading. + * @private + */ +p._disposeItem = function (item) { + delete this._loadedResults[item.id]; + delete this._loadedRawResults[item.id]; + delete this._loadItemsById[item.id]; + delete this._loadItemsBySrc[item.src]; +}; + +/** + * Dispatch a "fileprogress" {{#crossLink "Event"}}{{/crossLink}}. Please see the LoadQueue {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendFileProgress + * @param {LoadItem|Object} item The item that is being loaded. + * @param {Number} progress The amount the item has been loaded (between 0 and 1). + * @protected + */ +p._sendFileProgress = function (item, progress) { + if (this._isCanceled() || this._paused) { + return; + } + if (!this.hasEventListener("fileprogress")) { + return; + } + + //LM: Rework ProgressEvent to support this? + var event = new Event("fileprogress"); + event.progress = progress; + event.loaded = progress; + event.total = 1; + event.item = item; + + this.dispatchEvent(event); +}; + +/** + * Dispatch a fileload {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event for + * details on the event payload. + * @method _sendFileComplete + * @param {LoadItemObject} item The item that is being loaded. + * @param {AbstractLoader} loader + * @protected + */ +p._sendFileComplete = function (item, loader) { + if (this._isCanceled() || this._paused) { + return; + } + + var event = new Event("fileload"); + event.loader = loader; + event.item = item; + event.result = this._loadedResults[item.id]; + event.rawResult = this._loadedRawResults[item.id]; + + // This calls a handler specified on the actual load item. Currently, the SoundJS plugin uses this. + if (item.completeHandler) { + item.completeHandler(event); + } + + this.hasEventListener("fileload") && this.dispatchEvent(event); +}; + +/** + * Dispatch a filestart {{#crossLink "Event"}}{{/crossLink}} immediately before a file starts to load. Please see + * the {{#crossLink "LoadQueue/filestart:event"}}{{/crossLink}} event for details on the event payload. + * @method _sendFileStart + * @param {LoadItem|Object} item The item that is being loaded. + * @protected + */ +p._sendFileStart = function (item) { + var event = new Event("filestart"); + event.item = item; + this.hasEventListener("filestart") && this.dispatchEvent(event); +}; + +p.toString = function () { + return "[PreloadJS LoadQueue]"; +}; + +var LoadQueue = promote(LoadQueue, "AbstractLoader"); + +module.exports = LoadQueue; +},{"../createjs/events/ErrorEvent":1,"../createjs/events/Event":2,"../createjs/utils/extend":4,"../createjs/utils/promote":5,"./data/LoadItem":8,"./loaders/AbstractLoader":10,"./loaders/ImageLoader":11,"./utils/RequestUtils":15}],8:[function(_dereq_,module,exports){ +/* + * LoadItem + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +// namespace: + +/** + * All loaders accept an item containing the properties defined in this class. If a raw object is passed instead, + * it will not be affected, but it must contain at least a {{#crossLink "src:property"}}{{/crossLink}} property. A + * string path or HTML tag is also acceptable, but it will be automatically converted to a LoadItem using the + * {{#crossLink "create"}}{{/crossLink}} method by {{#crossLink "AbstractLoader"}}{{/crossLink}} + * @class LoadItem + * @constructor + * @since 0.6.0 + */ +function LoadItem() { + /** + * The source of the file that is being loaded. This property is required. The source can either be a + * string (recommended), or an HTML tag. + * This can also be an object, but in that case it has to include a type and be handled by a plugin. + * @property src + * @type {String} + * @default null + */ + this.src = null; + + /** + * The type file that is being loaded. The type of the file is usually inferred by the extension, but can also + * be set manually. This is helpful in cases where a file does not have an extension. + * @property type + * @type {String} + * @default null + */ + this.type = null; + + /** + * A string identifier which can be used to reference the loaded object. If none is provided, this will be + * automatically set to the {{#crossLink "src:property"}}{{/crossLink}}. + * @property id + * @type {String} + * @default null + */ + this.id = null; + + /** + * Determines if a manifest will maintain the order of this item, in relation to other items in the manifest + * that have also set the `maintainOrder` property to `true`. This only applies when the max connections has + * been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}). Everything with this + * property set to `false` will finish as it is loaded. Ordered items are combined with script tags loading in + * order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} is set to `true`. + * @property maintainOrder + * @type {Boolean} + * @default false + */ + this.maintainOrder = false; + + /** + * A callback used by JSONP requests that defines what global method to call when the JSONP content is loaded. + * @property callback + * @type {String} + * @default null + */ + this.callback = null; + + /** + * An arbitrary data object, which is included with the loaded object. + * @property data + * @type {Object} + * @default null + */ + this.data = null; + + /** + * The request method used for HTTP calls. Both {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} or + * {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} request types are supported, and are defined as + * constants on {{#crossLink "AbstractLoader"}}{{/crossLink}}. + * @property method + * @type {String} + * @default get + */ + this.method = LoadItem.GET; + + /** + * An object hash of name/value pairs to send to the server. + * @property values + * @type {Object} + * @default null + */ + this.values = null; + + /** + * An object hash of headers to attach to an XHR request. PreloadJS will automatically attach some default + * headers when required, including "Origin", "Content-Type", and "X-Requested-With". You may override the + * default headers by including them in your headers object. + * @property headers + * @type {Object} + * @default null + */ + this.headers = null; + + /** + * Enable credentials for XHR requests. + * @property withCredentials + * @type {Boolean} + * @default false + */ + this.withCredentials = false; + + /** + * Set the mime type of XHR-based requests. This is automatically set to "text/plain; charset=utf-8" for text + * based files (json, xml, text, css, js). + * @property mimeType + * @type {String} + * @default null + */ + this.mimeType = null; + + /** + * Sets the crossOrigin attribute for CORS-enabled images loading cross-domain. + * @property crossOrigin + * @type {boolean} + * @default Anonymous + */ + this.crossOrigin = null; + + /** + * The duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR + * (level one) loading, as XHR (level 2) provides its own timeout event. + * @property loadTimeout + * @type {Number} + * @default 8000 (8 seconds) + */ + this.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; +}; + +var p = LoadItem.prototype = {}; +var s = LoadItem; + +/** + * Default duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR + * (level one) loading, as XHR (level 2) provides its own timeout event. + * @property LOAD_TIMEOUT_DEFAULT + * @type {number} + * @static + */ +s.LOAD_TIMEOUT_DEFAULT = 8000; + +/** + * Create a LoadItem. + * + * @method create + * @param {LoadItem|String|Object} value The load item value + * @returns {LoadItem|Object} + * @static + */ +s.create = function (value) { + if (typeof value == "string") { + var item = new LoadItem(); + item.src = value; + return item; + } else if (value instanceof s) { + return value; + } else if (value instanceof Object && value.src) { + if (value.loadTimeout == null) { + value.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; + } + return value; + } else { + throw new Error("Type not recognized."); + } +}; + +/** + * Provides a chainable shortcut method for setting a number of properties on the instance. + * + *

Example

+ * + * var loadItem = new createjs.LoadItem().set({src:"image.png", maintainOrder:true}); + * + * @method set + * @param {Object} props A generic object containing properties to copy to the LoadItem instance. + * @return {LoadItem} Returns the instance the method is called on (useful for chaining calls.) + */ +p.set = function (props) { + for (var n in props) { + this[n] = props[n]; + } + return this; +}; + +var LoadItem = s; +module.exports = LoadItem; + +},{}],9:[function(_dereq_,module,exports){ +/* + * ProgressEvent + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +var promote = _dereq_('../../createjs/utils/promote'); +var extend = _dereq_('../../createjs/utils/extend'); +var Event = _dereq_('../../createjs/events/Event'); + +// constructor +/** + * A CreateJS {{#crossLink "Event"}}{{/crossLink}} that is dispatched when progress changes. + * @class ProgressEvent + * @param {Number} loaded The amount that has been loaded. This can be any number relative to the total. + * @param {Number} [total=1] The total amount that will load. This will default to 1, so if the `loaded` value is + * a percentage (between 0 and 1), it can be omitted. + * @todo Consider having this event be a "fileprogress" event as well + * @constructor + */ +function ProgressEvent(loaded, total) { + this.Event_constructor("progress"); + + /** + * The amount that has been loaded (out of a total amount) + * @property loaded + * @type {Number} + */ + this.loaded = loaded; + + /** + * The total "size" of the load. + * @property total + * @type {Number} + * @default 1 + */ + this.total = (total == null) ? 1 : total; + + /** + * The percentage (out of 1) that the load has been completed. This is calculated using `loaded/total`. + * @property progress + * @type {Number} + * @default 0 + */ + this.progress = (total == 0) ? 0 : this.loaded / this.total; +}; + +var p = extend(ProgressEvent, Event); + +/** + * Returns a clone of the ProgressEvent instance. + * @method clone + * @return {ProgressEvent} a clone of the Event instance. + **/ +p.clone = function () { + return new ProgressEvent(this.loaded, this.total); +}; + +var ProgressEvent = promote(ProgressEvent, "Event"); +module.exports = ProgressEvent; + +},{"../../createjs/events/Event":2,"../../createjs/utils/extend":4,"../../createjs/utils/promote":5}],10:[function(_dereq_,module,exports){ +/* + * AbstractLoader + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +var EventDispatcher = _dereq_('../../createjs/events/EventDispatcher'); +var LoadItem = _dereq_('../data/LoadItem'); +var Event = _dereq_('../../createjs/events/Event'); +var ErrorEvent = _dereq_('../../createjs/events/ErrorEvent'); +var ProgressEvent = _dereq_('../events/ProgressEvent'); +var RequestUtils = _dereq_('../utils/RequestUtils'); +var TagRequest = _dereq_('../net/TagRequest'); +var XHRRequest = _dereq_('../net/XHRRequest'); +var proxy = _dereq_('../../createjs/utils/proxy'); +var promote = _dereq_('../../createjs/utils/promote'); +var extend = _dereq_('../../createjs/utils/extend'); + +// namespace: +// constructor +/** + * The base loader, which defines all the generic methods, properties, and events. All loaders extend this class, + * including the {{#crossLink "LoadQueue"}}{{/crossLink}}. + * @class AbstractLoader + * @param {LoadItem|object|string} loadItem The item to be loaded. + * @param {Boolean} [preferXHR] Determines if the LoadItem should try and load using XHR, or take a + * tag-based approach, which can be better in cross-domain situations. Not all loaders can load using one or the + * other, so this is a suggested directive. + * @param {String} [type] The type of loader. Loader types are defined as constants on the AbstractLoader class, + * such as {{#crossLink "IMAGE:property"}}{{/crossLink}}, {{#crossLink "CSS:property"}}{{/crossLink}}, etc. + * @extends EventDispatcher + */ +function AbstractLoader(loadItem, preferXHR, type) { + this.EventDispatcher_constructor(); + + // public properties + /** + * If the loader has completed loading. This provides a quick check, but also ensures that the different approaches + * used for loading do not pile up resulting in more than one `complete` {{#crossLink "Event"}}{{/crossLink}}. + * @property loaded + * @type {Boolean} + * @default false + */ + this.loaded = false; + + /** + * Determine if the loader was canceled. Canceled loads will not fire complete events. Note that this property + * is readonly, so {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "LoadQueue/close"}}{{/crossLink}} + * instead. + * @property canceled + * @type {Boolean} + * @default false + * @readonly + */ + this.canceled = false; + + /** + * The current load progress (percentage) for this item. This will be a number between 0 and 1. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.loadFile("largeImage.png"); + * queue.on("progress", function() { + * console.log("Progress:", queue.progress, event.progress); + * }); + * + * @property progress + * @type {Number} + * @default 0 + */ + this.progress = 0; + + /** + * The type of item this loader will load. See {{#crossLink "AbstractLoader"}}{{/crossLink}} for a full list of + * supported types. + * @property type + * @type {String} + */ + this.type = type; + + /** + * A formatter function that converts the loaded raw result into the final result. For example, the JSONLoader + * converts a string of text into a JavaScript object. Not all loaders have a resultFormatter, and this property + * can be overridden to provide custom formatting. + * + * Optionally, a resultFormatter can return a callback function in cases where the formatting needs to be + * asynchronous, such as creating a new image. The callback function is passed 2 parameters, which are callbacks + * to handle success and error conditions in the resultFormatter. Note that the resultFormatter method is + * called in the current scope, as well as the success and error callbacks. + * + *

Example asynchronous resultFormatter

+ * + * function _formatResult(loader) { + * return function(success, error) { + * if (errorCondition) { error(errorDetailEvent); } + * success(result); + * } + * } + * @property resultFormatter + * @type {Function} + * @default null + */ + this.resultFormatter = null; + + // protected properties + /** + * The {{#crossLink "LoadItem"}}{{/crossLink}} this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}}, + * but will be available on loaders such as {{#crossLink "XMLLoader"}}{{/crossLink}} and {{#crossLink "ImageLoader"}}{{/crossLink}}. + * @property _item + * @type {LoadItem|Object} + * @private + */ + if (loadItem) { + this._item = LoadItem.create(loadItem); + } else { + this._item = null; + } + + /** + * Whether the loader will try and load content using XHR (true) or HTML tags (false). + * @property _preferXHR + * @type {Boolean} + * @private + */ + this._preferXHR = preferXHR; + + /** + * The loaded result after it is formatted by an optional {{#crossLink "resultFormatter"}}{{/crossLink}}. For + * items that are not formatted, this will be the same as the {{#crossLink "_rawResult:property"}}{{/crossLink}}. + * The result is accessed using the {{#crossLink "getResult"}}{{/crossLink}} method. + * @property _result + * @type {Object|String} + * @private + */ + this._result = null; + + /** + * The loaded result before it is formatted. The rawResult is accessed using the {{#crossLink "getResult"}}{{/crossLink}} + * method, and passing `true`. + * @property _rawResult + * @type {Object|String} + * @private + */ + this._rawResult = null; + + /** + * A list of items that loaders load behind the scenes. This does not include the main item the loader is + * responsible for loading. Examples of loaders that have sub-items include the {{#crossLink "SpriteSheetLoader"}}{{/crossLink}} and + * {{#crossLink "ManifestLoader"}}{{/crossLink}}. + * @property _loadItems + * @type {null} + * @protected + */ + this._loadedItems = null; + + /** + * The attribute the items loaded using tags use for the source. + * @type {string} + * @default null + * @private + */ + this._tagSrcAttribute = null; + + /** + * An HTML tag (or similar) that a loader may use to load HTML content, such as images, scripts, etc. + * @property _tag + * @type {Object} + * @private + */ + this._tag = null; +}; + +var p = extend(AbstractLoader, EventDispatcher); +var s = AbstractLoader; + +// TODO: deprecated +// p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. + + +/** + * Defines a POST request, use for a method value when loading data. + * @property POST + * @type {string} + * @default post + * @static + */ +s.POST = "POST"; + +/** + * Defines a GET request, use for a method value when loading data. + * @property GET + * @type {string} + * @default get + * @static + */ +s.GET = "GET"; + +/** + * The preload type for generic binary types. Note that images are loaded as binary files when using XHR. + * @property BINARY + * @type {String} + * @default binary + * @static + * @since 0.6.0 + */ +s.BINARY = "binary"; + +/** + * The preload type for css files. CSS files are loaded using a <link> when loaded with XHR, or a + * <style> tag when loaded with tags. + * @property CSS + * @type {String} + * @default css + * @static + * @since 0.6.0 + */ +s.CSS = "css"; + +/** + * The preload type for image files, usually png, gif, or jpg/jpeg. Images are loaded into an <image> tag. + * @property IMAGE + * @type {String} + * @default image + * @static + * @since 0.6.0 + */ +s.IMAGE = "image"; + +/** + * The preload type for javascript files, usually with the "js" file extension. JavaScript files are loaded into a + * <script> tag. + * + * Since version 0.4.1+, due to how tag-loaded scripts work, all JavaScript files are automatically injected into + * the body of the document to maintain parity between XHR and tag-loaded scripts. In version 0.4.0 and earlier, + * only tag-loaded scripts are injected. + * @property JAVASCRIPT + * @type {String} + * @default javascript + * @static + * @since 0.6.0 + */ +s.JAVASCRIPT = "javascript"; + +/** + * The preload type for json files, usually with the "json" file extension. JSON data is loaded and parsed into a + * JavaScript object. Note that if a `callback` is present on the load item, the file will be loaded with JSONP, + * no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to, and the JSON + * must contain a matching wrapper function. + * @property JSON + * @type {String} + * @default json + * @static + * @since 0.6.0 + */ +s.JSON = "json"; + +/** + * The preload type for jsonp files, usually with the "json" file extension. JSON data is loaded and parsed into a + * JavaScript object. You are required to pass a callback parameter that matches the function wrapper in the JSON. + * Note that JSONP will always be used if there is a callback present, no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} + * property is set to. + * @property JSONP + * @type {String} + * @default jsonp + * @static + * @since 0.6.0 + */ +s.JSONP = "jsonp"; + +/** + * The preload type for json-based manifest files, usually with the "json" file extension. The JSON data is loaded + * and parsed into a JavaScript object. PreloadJS will then look for a "manifest" property in the JSON, which is an + * Array of files to load, following the same format as the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * method. If a "callback" is specified on the manifest object, then it will be loaded using JSONP instead, + * regardless of what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to. + * @property MANIFEST + * @type {String} + * @default manifest + * @static + * @since 0.6.0 + */ +s.MANIFEST = "manifest"; + +/** + * The preload type for sound files, usually mp3, ogg, or wav. When loading via tags, audio is loaded into an + * <audio> tag. + * @property SOUND + * @type {String} + * @default sound + * @static + * @since 0.6.0 + */ +s.SOUND = "sound"; + +/** + * The preload type for video files, usually mp4, ts, or ogg. When loading via tags, video is loaded into an + * <video> tag. + * @property VIDEO + * @type {String} + * @default video + * @static + * @since 0.6.0 + */ +s.VIDEO = "video"; + +/** + * The preload type for SpriteSheet files. SpriteSheet files are JSON files that contain string image paths. + * @property SPRITESHEET + * @type {String} + * @default spritesheet + * @static + * @since 0.6.0 + */ +s.SPRITESHEET = "spritesheet"; + +/** + * The preload type for SVG files. + * @property SVG + * @type {String} + * @default svg + * @static + * @since 0.6.0 + */ +s.SVG = "svg"; + +/** + * The preload type for text files, which is also the default file type if the type can not be determined. Text is + * loaded as raw text. + * @property TEXT + * @type {String} + * @default text + * @static + * @since 0.6.0 + */ +s.TEXT = "text"; + +/** + * The preload type for xml files. XML is loaded into an XML document. + * @property XML + * @type {String} + * @default xml + * @static + * @since 0.6.0 + */ +s.XML = "xml"; + +// Events +/** + * The {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when the overall progress changes. Prior to + * version 0.6.0, this was just a regular {{#crossLink "Event"}}{{/crossLink}}. + * @event progress + * @since 0.3.0 + */ + +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a load starts. + * @event loadstart + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @since 0.3.1 + */ + +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the entire queue has been loaded. + * @event complete + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @since 0.3.0 + */ + +/** + * The {{#crossLink "ErrorEvent"}}{{/crossLink}} that is fired when the loader encounters an error. If the error was + * encountered by a file, the event will contain the item that caused the error. Prior to version 0.6.0, this was + * just a regular {{#crossLink "Event"}}{{/crossLink}}. + * @event error + * @since 0.3.0 + */ + +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the loader encounters an internal file load error. + * This enables loaders to maintain internal queues, and surface file load errors. + * @event fileerror + * @param {Object} target The object that dispatched the event. + * @param {String} type The even type ("fileerror") + * @param {LoadItem|object} The item that encountered the error + * @since 0.6.0 + */ + +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a loader internally loads a file. This enables + * loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} to maintain internal {{#crossLink "LoadQueue"}}{{/crossLink}}s + * and notify when they have loaded a file. The {{#crossLink "LoadQueue"}}{{/crossLink}} class dispatches a + * slightly different {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event. + * @event fileload + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type ("fileload") + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a `src` property. + * @param {Object} result The HTML tag or parsed result of the loaded item. + * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted + * to a usable object. + * @since 0.6.0 + */ + +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired after the internal request is created, but before a load. + * This allows updates to the loader for specific loading needs, such as binary or XHR image loading. + * @event initialize + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type ("initialize") + * @param {AbstractLoader} loader The loader that has been initialized. + */ + + +/** + * Get a reference to the manifest item that is loaded by this loader. In some cases this will be the value that was + * passed into {{#crossLink "LoadQueue"}}{{/crossLink}} using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. However if only a String path was passed in, then it will + * be a {{#crossLink "LoadItem"}}{{/crossLink}}. + * @method getItem + * @return {Object} The manifest item that this loader is responsible for loading. + * @since 0.6.0 + */ +p.getItem = function () { + return this._item; +}; + +/** + * Get a reference to the content that was loaded by the loader (only available after the {{#crossLink "complete:event"}}{{/crossLink}} + * event is dispatched. + * @method getResult + * @param {Boolean} [raw=false] Determines if the returned result will be the formatted content, or the raw loaded + * data (if it exists). + * @return {Object} + * @since 0.6.0 + */ +p.getResult = function (raw) { + return raw ? this._rawResult : this._result; +}; + +/** + * Return the `tag` this object creates or uses for loading. + * @method getTag + * @return {Object} The tag instance + * @since 0.6.0 + */ +p.getTag = function () { + return this._tag; +}; + +/** + * Set the `tag` this item uses for loading. + * @method setTag + * @param {Object} tag The tag instance + * @since 0.6.0 + */ +p.setTag = function (tag) { + this._tag = tag; +}; + +/** + * Begin loading the item. This method is required when using a loader by itself. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.on("complete", handleComplete); + * queue.loadManifest(fileArray, false); // Note the 2nd argument that tells the queue not to start loading yet + * queue.load(); + * + * @method load + */ +p.load = function () { + this._createRequest(); + + this._request.on("complete", this, this); + this._request.on("progress", this, this); + this._request.on("loadStart", this, this); + this._request.on("abort", this, this); + this._request.on("timeout", this, this); + this._request.on("error", this, this); + + var evt = new Event("initialize"); + evt.loader = this._request; + this.dispatchEvent(evt); + + this._request.load(); +}; + +/** + * Close the the item. This will stop any open requests (although downloads using HTML tags may still continue in + * the background), but events will not longer be dispatched. + * @method cancel + */ +p.cancel = function () { + this.canceled = true; + this.destroy(); +}; + +/** + * Clean up the loader. + * @method destroy + */ +p.destroy = function () { + if (this._request) { + this._request.removeAllEventListeners(); + this._request.destroy(); + } + + this._request = null; + + this._item = null; + this._rawResult = null; + this._result = null; + + this._loadItems = null; + + this.removeAllEventListeners(); +}; + +/** + * Get any items loaded internally by the loader. The enables loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} + * to expose items it loads internally. + * @method getLoadedItems + * @return {Array} A list of the items loaded by the loader. + * @since 0.6.0 + */ +p.getLoadedItems = function () { + return this._loadedItems; +}; + + +// Private methods +/** + * Create an internal request used for loading. By default, an {{#crossLink "XHRRequest"}}{{/crossLink}} or + * {{#crossLink "TagRequest"}}{{/crossLink}} is created, depending on the value of {{#crossLink "preferXHR:property"}}{{/crossLink}}. + * Other loaders may override this to use different request types, such as {{#crossLink "ManifestLoader"}}{{/crossLink}}, + * which uses {{#crossLink "JSONLoader"}}{{/crossLink}} or {{#crossLink "JSONPLoader"}}{{/crossLink}} under the hood. + * @method _createRequest + * @protected + */ +p._createRequest = function () { + if (!this._preferXHR) { + this._request = new TagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); + } else { + this._request = new XHRRequest(this._item); + } +}; + +/** + * Create the HTML tag used for loading. This method does nothing by default, and needs to be implemented + * by loaders that require tag loading. + * @method _createTag + * @param {String} src The tag source + * @return {HTMLElement} The tag that was created + * @protected + */ +p._createTag = function (src) { + return null; +}; + +/** + * Dispatch a loadstart {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendLoadStart + * @protected + */ +p._sendLoadStart = function () { + if (this._isCanceled()) { + return; + } + this.dispatchEvent("loadstart"); +}; + +/** + * Dispatch a {{#crossLink "ProgressEvent"}}{{/crossLink}}. + * @method _sendProgress + * @param {Number | Object} value The progress of the loaded item, or an object containing loaded + * and total properties. + * @protected + */ +p._sendProgress = function (value) { + if (this._isCanceled()) { + return; + } + var event = null; + if (typeof(value) == "number") { + this.progress = value; + event = new ProgressEvent(this.progress); + } else { + event = value; + this.progress = value.loaded / value.total; + event.progress = this.progress; + if (isNaN(this.progress) || this.progress == Infinity) { + this.progress = 0; + } + } + this.hasEventListener("progress") && this.dispatchEvent(event); +}; + +/** + * Dispatch a complete {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event + * @method _sendComplete + * @protected + */ +p._sendComplete = function () { + if (this._isCanceled()) { + return; + } + + this.loaded = true; + + var event = new Event("complete"); + event.rawResult = this._rawResult; + + if (this._result != null) { + event.result = this._result; + } + + this.dispatchEvent(event); +}; + +/** + * Dispatch an error {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendError + * @param {ErrorEvent} event The event object containing specific error properties. + * @protected + */ +p._sendError = function (event) { + if (this._isCanceled() || !this.hasEventListener("error")) { + return; + } + if (event == null) { + event = new ErrorEvent("PRELOAD_ERROR_EMPTY"); // TODO: Populate error + } + this.dispatchEvent(event); +}; + +/** + * Determine if the load has been canceled. This is important to ensure that method calls or asynchronous events + * do not cause issues after the queue has been cleaned up. + * @method _isCanceled + * @return {Boolean} If the loader has been canceled. + * @protected + */ +p._isCanceled = function () { + if (window.createjs == null || this.canceled) { + return true; + } + return false; +}; + +/** + * A custom result formatter function, which is called just before a request dispatches its complete event. Most + * loader types already have an internal formatter, but this can be user-overridden for custom formatting. The + * formatted result will be available on Loaders using {{#crossLink "getResult"}}{{/crossLink}}, and passing `true`. + * @property resultFormatter + * @type Function + * @return {Object} The formatted result + * @since 0.6.0 + */ +p.resultFormatter = null; + +/** + * Handle events from internal requests. By default, loaders will handle, and redispatch the necessary events, but + * this method can be overridden for custom behaviours. + * @method handleEvent + * @param {Event} event The event that the internal request dispatches. + * @protected + * @since 0.6.0 + */ +p.handleEvent = function (event) { + switch (event.type) { + case "complete": + this._rawResult = event.target._response; + var result = this.resultFormatter && this.resultFormatter(this); + if (result instanceof Function) { + result.call(this, + proxy(this._resultFormatSuccess, this), + proxy(this._resultFormatFailed, this) + ); + } else { + this._result = result || this._rawResult; + this._sendComplete(); + } + break; + case "progress": + this._sendProgress(event); + break; + case "error": + this._sendError(event); + break; + case "loadstart": + this._sendLoadStart(); + break; + case "abort": + case "timeout": + if (!this._isCanceled()) { + this.dispatchEvent(new ErrorEvent("PRELOAD_" + event.type.toUpperCase() + "_ERROR")); + } + break; + } +}; + +/** + * The "success" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous + * functions. + * @method _resultFormatSuccess + * @param {Object} result The formatted result + * @private + */ +p._resultFormatSuccess = function (result) { + this._result = result; + this._sendComplete(); +}; + +/** + * The "error" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous + * functions. + * @method _resultFormatSuccess + * @param {Object} error The error event + * @private + */ +p._resultFormatFailed = function (event) { + this._sendError(event); +}; + +/** + * @method buildPath + * @protected + * @deprecated Use the {{#crossLink "RequestUtils"}}{{/crossLink}} method {{#crossLink "RequestUtils/buildPath"}}{{/crossLink}} + * instead. + */ +p.buildPath = function (src, data) { + return RequestUtils.buildPath(src, data); +}; + +/** + * @method toString + * @return {String} a string representation of the instance. + */ +p.toString = function () { + return "[PreloadJS AbstractLoader]"; +}; + +module.exports = AbstractLoader = promote(AbstractLoader, "EventDispatcher"); + +},{"../../createjs/events/ErrorEvent":1,"../../createjs/events/Event":2,"../../createjs/events/EventDispatcher":3,"../../createjs/utils/extend":4,"../../createjs/utils/promote":5,"../../createjs/utils/proxy":6,"../data/LoadItem":8,"../events/ProgressEvent":9,"../net/TagRequest":13,"../net/XHRRequest":14,"../utils/RequestUtils":15}],11:[function(_dereq_,module,exports){ +/* + * ImageLoader + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +// constructor +/** + * A loader for image files. + * @class ImageLoader + * @param {LoadItem|Object} loadItem + * @param {Boolean} preferXHR + * @extends AbstractLoader + * @constructor + */ + +var AbstractLoader = _dereq_('./AbstractLoader'); +var RequestUtils = _dereq_('../utils/RequestUtils'); +var extend = _dereq_('../../createjs/utils/extend'); +var promote = _dereq_('../../createjs/utils/promote'); +var proxy = _dereq_('../../createjs/utils/proxy'); + +function ImageLoader(loadItem, preferXHR) { + this.AbstractLoader_constructor(loadItem, preferXHR, AbstractLoader.IMAGE); + + // public properties + this.resultFormatter = this._formatResult; + + // protected properties + this._tagSrcAttribute = "src"; + + // Check if the preload item is already a tag. + if (RequestUtils.isImageTag(loadItem)) { + this._tag = loadItem; + } else if (RequestUtils.isImageTag(loadItem.src)) { + this._tag = loadItem.src; + } else if (RequestUtils.isImageTag(loadItem.tag)) { + this._tag = loadItem.tag; + } + + if (this._tag != null) { + this._preferXHR = false; + } else { + this._tag = document.createElement("img"); + } + + this.on("initialize", this._updateXHR, this); +}; + +var p = extend(ImageLoader, AbstractLoader); +var s = ImageLoader; + +// static methods +/** + * Determines if the loader can load a specific item. This loader can only load items that are of type + * {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}. + * @method canLoadItem + * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. + * @returns {Boolean} Whether the loader can load the item. + * @static + */ +s.canLoadItem = function (item) { + return item.type == AbstractLoader.IMAGE; +}; + +// public methods +p.load = function () { + if (this._tag.src != "" && this._tag.complete) { + this._sendComplete(); + return; + } + + var crossOrigin = this._item.crossOrigin; + if (crossOrigin == true) { + crossOrigin = "Anonymous"; + } + if (crossOrigin != null && !RequestUtils.isLocal(this._item.src)) { + this._tag.crossOrigin = crossOrigin; + } + + this.AbstractLoader_load(); +}; + +// protected methods +/** + * Before the item loads, set its mimeType and responseType. + * @property _updateXHR + * @param {Event} event + * @private + */ +p._updateXHR = function (event) { + event.loader.mimeType = 'text/plain; charset=x-user-defined-binary'; + + // Only exists for XHR + if (event.loader.setResponseType) { + event.loader.setResponseType("blob"); + } +}; + +/** + * The result formatter for Image files. + * @method _formatResult + * @param {AbstractLoader} loader + * @returns {HTMLImageElement} + * @private + */ +p._formatResult = function (loader) { + return this._formatImage; +}; + +/** + * The asynchronous image formatter function. This is required because images have + * a short delay before they are ready. + * @method _formatImage + * @param {Function} successCallback The method to call when the result has finished formatting + * @param {Function} errorCallback The method to call if an error occurs during formatting + * @private + */ +p._formatImage = function (successCallback, errorCallback) { + var tag = this._tag; + var URL = window.URL || window.webkitURL; + + if (!this._preferXHR) { + //document.body.removeChild(tag); + } else if (URL) { + var objURL = URL.createObjectURL(this.getResult(true)); + tag.src = objURL; + + tag.addEventListener("load", this._cleanUpURL, false); + tag.addEventListener("error", this._cleanUpURL, false); + } else { + tag.src = this._item.src; + } + + if (tag.complete) { + successCallback(tag); + } else { + tag.onload = proxy(function () { + successCallback(this._tag); + }, this); + + tag.onerror = proxy(function () { + errorCallback(_this._tag); + }, this); + } +}; + +/** + * Clean up the ObjectURL, the tag is done with it. Note that this function is run + * as an event listener without a proxy/closure, as it doesn't require it - so do not + * include any functionality that requires scope without changing it. + * @method _cleanUpURL + * @param event + * @private + */ +p._cleanUpURL = function (event) { + var URL = window.URL || window.webkitURL; + URL.revokeObjectURL(event.target.src); +}; + +var ImageLoader = promote(ImageLoader, "AbstractLoader"); +module.exports = ImageLoader; + +},{"../../createjs/utils/extend":4,"../../createjs/utils/promote":5,"../../createjs/utils/proxy":6,"../utils/RequestUtils":15,"./AbstractLoader":10}],12:[function(_dereq_,module,exports){ +/* + * AbstractRequest + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +var promote = _dereq_('../../createjs/utils/promote'); +var extend = _dereq_('../../createjs/utils/extend'); +var EventDispatcher = _dereq_('../../createjs/events/EventDispatcher'); + +/** + * A base class for actual data requests, such as {{#crossLink "XHRRequest"}}{{/crossLink}}, {{#crossLink "TagRequest"}}{{/crossLink}}, + * and {{#crossLink "MediaRequest"}}{{/crossLink}}. PreloadJS loaders will typically use a data loader under the + * hood to get data. + * @class AbstractRequest + * @param {LoadItem} item + * @constructor + */ +var AbstractRequest = function (item) { + this._item = item; +}; + +var p = extend(AbstractRequest, EventDispatcher); + +// public methods +/** + * Begin a load. + * @method load + */ +p.load = function () { +}; + +/** + * Clean up a request. + * @method destroy + */ +p.destroy = function () { +}; + +/** + * Cancel an in-progress request. + * @method cancel + */ +p.cancel = function () { +}; + +module.exports = AbstractRequest = promote(AbstractRequest, "EventDispatcher"); + +},{"../../createjs/events/EventDispatcher":3,"../../createjs/utils/extend":4,"../../createjs/utils/promote":5}],13:[function(_dereq_,module,exports){ +/* + * TagRequest + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +var proxy = _dereq_('../../createjs/utils/proxy'); +var extend = _dereq_('../../createjs/utils/extend'); +var AbstractRequest = _dereq_('./AbstractRequest'); +var Event = _dereq_('../../createjs/events/Event'); +var promote = _dereq_('../../createjs/utils/promote'); + +// constructor +/** + * An {{#crossLink "AbstractRequest"}}{{/crossLink}} that loads HTML tags, such as images and scripts. + * @class TagRequest + * @param {LoadItem} loadItem + * @param {HTMLElement} tag + * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. + */ +function TagRequest(loadItem, tag, srcAttribute) { + this.AbstractRequest_constructor(loadItem); + + // protected properties + /** + * The HTML tag instance that is used to load. + * @property _tag + * @type {HTMLElement} + * @protected + */ + this._tag = tag; + + /** + * The tag attribute that specifies the source, such as "src", "href", etc. + * @property _tagSrcAttribute + * @type {String} + * @protected + */ + this._tagSrcAttribute = srcAttribute; + + /** + * A method closure used for handling the tag load event. + * @property _loadedHandler + * @type {Function} + * @private + */ + this._loadedHandler = proxy(this._handleTagComplete, this); + + /** + * Determines if the element was added to the DOM automatically by PreloadJS, so it can be cleaned up after. + * @property _addedToDOM + * @type {Boolean} + * @private + */ + this._addedToDOM = false; + + /** + * Determines what the tags initial style.visibility was, so we can set it correctly after a load. + * + * @type {null} + * @private + */ + this._startTagVisibility = null; +}; + +var p = extend(TagRequest, AbstractRequest); + +// public methods +p.load = function () { + this._tag.onload = proxy(this._handleTagComplete, this); + this._tag.onreadystatechange = proxy(this._handleReadyStateChange, this); + this._tag.onerror = proxy(this._handleError, this); + + var evt = new Event("initialize"); + evt.loader = this._tag; + + this.dispatchEvent(evt); + + this._hideTag(); + + this._loadTimeout = setTimeout(proxy(this._handleTimeout, this), this._item.loadTimeout); + + this._tag[this._tagSrcAttribute] = this._item.src; + + // wdg:: Append the tag AFTER setting the src, or SVG loading on iOS will fail. + if (this._tag.parentNode == null) { + window.document.body.appendChild(this._tag); + this._addedToDOM = true; + } +}; + +p.destroy = function () { + this._clean(); + this._tag = null; + + this.AbstractRequest_destroy(); +}; + +// private methods +/** + * Handle the readyStateChange event from a tag. We need this in place of the `onload` callback (mainly SCRIPT + * and LINK tags), but other cases may exist. + * @method _handleReadyStateChange + * @private + */ +p._handleReadyStateChange = function () { + clearTimeout(this._loadTimeout); + // This is strictly for tags in browsers that do not support onload. + var tag = this._tag; + + // Complete is for old IE support. + if (tag.readyState == "loaded" || tag.readyState == "complete") { + this._handleTagComplete(); + } +}; + +/** + * Handle any error events from the tag. + * @method _handleError + * @protected + */ +p._handleError = function () { + this._clean(); + this.dispatchEvent("error"); +}; + +/** + * Handle the tag's onload callback. + * @method _handleTagComplete + * @private + */ +p._handleTagComplete = function () { + this._rawResult = this._tag; + this._result = this.resultFormatter && this.resultFormatter(this) || this._rawResult; + + this._clean(); + this._showTag(); + + this.dispatchEvent("complete"); +}; + +/** + * The tag request has not loaded within the time specified in loadTimeout. + * @method _handleError + * @param {Object} event The XHR error event. + * @private + */ +p._handleTimeout = function () { + this._clean(); + this.dispatchEvent(new Event("timeout")); +}; + +/** + * Remove event listeners, but don't destroy the request object + * @method _clean + * @private + */ +p._clean = function () { + this._tag.onload = null; + this._tag.onreadystatechange = null; + this._tag.onerror = null; + if (this._addedToDOM && this._tag.parentNode != null) { + this._tag.parentNode.removeChild(this._tag); + } + clearTimeout(this._loadTimeout); +}; + +p._hideTag = function () { + this._startTagVisibility = this._tag.style.visibility; + this._tag.style.visibility = "hidden"; +}; + +p._showTag = function () { + this._tag.style.visibility = this._startTagVisibility; +}; + +/** + * Handle a stalled audio event. The main place this happens is with HTMLAudio in Chrome when playing back audio + * that is already in a load, but not complete. + * @method _handleStalled + * @private + */ +p._handleStalled = function () { + //Ignore, let the timeout take care of it. Sometimes its not really stopped. +}; + +module.exports = promote(TagRequest, "AbstractRequest"); +},{"../../createjs/events/Event":2,"../../createjs/utils/extend":4,"../../createjs/utils/promote":5,"../../createjs/utils/proxy":6,"./AbstractRequest":12}],14:[function(_dereq_,module,exports){ +/* + * XHRRequest + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +var proxy = _dereq_('../../createjs/utils/proxy'); +var extend = _dereq_('../../createjs/utils/extend'); +var promote = _dereq_('../../createjs/utils/promote'); +var AbstractRequest = _dereq_('./AbstractRequest'); +var AbstractLoader = _dereq_('../loaders/AbstractLoader'); +var RequestUtils = _dereq_('../utils/RequestUtils'); +var ErrorEvent = _dereq_('../../createjs/events/ErrorEvent'); +var ProgressEvent = _dereq_('../events/ProgressEvent'); + +/** + * A preloader that loads items using XHR requests, usually XMLHttpRequest. However XDomainRequests will be used + * for cross-domain requests if possible, and older versions of IE fall back on to ActiveX objects when necessary. + * XHR requests load the content as text or binary data, provide progress and consistent completion events, and + * can be canceled during load. Note that XHR is not supported in IE 6 or earlier, and is not recommended for + * cross-domain loading. + * @class XHRRequest + * @constructor + * @param {Object} item The object that defines the file to load. Please see the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * for an overview of supported file properties. + * @extends AbstractLoader + */ +function XHRRequest(item) { + this.AbstractRequest_constructor(item); + + // protected properties + /** + * A reference to the XHR request used to load the content. + * @property _request + * @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP} + * @private + */ + this._request = null; + + /** + * A manual load timeout that is used for browsers that do not support the onTimeout event on XHR (XHR level 1, + * typically IE9). + * @property _loadTimeout + * @type {Number} + * @private + */ + this._loadTimeout = null; + + /** + * The browser's XHR (XMLHTTPRequest) version. Supported versions are 1 and 2. There is no official way to detect + * the version, so we use capabilities to make a best guess. + * @property _xhrLevel + * @type {Number} + * @default 1 + * @private + */ + this._xhrLevel = 1; + + /** + * The response of a loaded file. This is set because it is expensive to look up constantly. This property will be + * null until the file is loaded. + * @property _response + * @type {mixed} + * @private + */ + this._response = null; + + /** + * The response of the loaded file before it is modified. In most cases, content is converted from raw text to + * an HTML tag or a formatted object which is set to the result property, but the developer may still + * want to access the raw content as it was loaded. + * @property _rawResponse + * @type {String|Object} + * @private + */ + this._rawResponse = null; + + this._canceled = false; + + // Setup our event handlers now. + this._handleLoadStartProxy = proxy(this._handleLoadStart, this); + this._handleProgressProxy = proxy(this._handleProgress, this); + this._handleAbortProxy = proxy(this._handleAbort, this); + this._handleErrorProxy = proxy(this._handleError, this); + this._handleTimeoutProxy = proxy(this._handleTimeout, this); + this._handleLoadProxy = proxy(this._handleLoad, this); + this._handleReadyStateChangeProxy = proxy(this._handleReadyStateChange, this); + + if (!this._createXHR(item)) { + //TODO: Throw error? + } +}; + +var p = extend(XHRRequest, AbstractRequest); + +// static properties +/** + * A list of XMLHTTP object IDs to try when building an ActiveX object for XHR requests in earlier versions of IE. + * @property ACTIVEX_VERSIONS + * @type {Array} + * @since 0.4.2 + * @private + */ +XHRRequest.ACTIVEX_VERSIONS = [ + "Msxml2.XMLHTTP.6.0", + "Msxml2.XMLHTTP.5.0", + "Msxml2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", + "MSXML2.XMLHTTP", + "Microsoft.XMLHTTP" +]; + +// Public methods +/** + * Look up the loaded result. + * @method getResult + * @param {Boolean} [raw=false] Return a raw result instead of a formatted result. This applies to content + * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be + * returned instead. + * @return {Object} A result object containing the content that was loaded, such as: + * + * Note that if a raw result is requested, but not found, the result will be returned instead. + */ +p.getResult = function (raw) { + if (raw && this._rawResponse) { + return this._rawResponse; + } + return this._response; +}; + +// Overrides abstract method in AbstractRequest +p.cancel = function () { + this.canceled = true; + this._clean(); + this._request.abort(); +}; + +// Overrides abstract method in AbstractLoader +p.load = function () { + if (this._request == null) { + this._handleError(); + return; + } + + //Events + if (this._request.addEventListener != null) { + this._request.addEventListener("loadstart", this._handleLoadStartProxy, false); + this._request.addEventListener("progress", this._handleProgressProxy, false); + this._request.addEventListener("abort", this._handleAbortProxy, false); + this._request.addEventListener("error", this._handleErrorProxy, false); + this._request.addEventListener("timeout", this._handleTimeoutProxy, false); + + // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. + this._request.addEventListener("load", this._handleLoadProxy, false); + this._request.addEventListener("readystatechange", this._handleReadyStateChangeProxy, false); + } else { + // IE9 support + this._request.onloadstart = this._handleLoadStartProxy; + this._request.onprogress = this._handleProgressProxy; + this._request.onabort = this._handleAbortProxy; + this._request.onerror = this._handleErrorProxy; + this._request.ontimeout = this._handleTimeoutProxy; + + // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. + this._request.onload = this._handleLoadProxy; + this._request.onreadystatechange = this._handleReadyStateChangeProxy; + } + + // Set up a timeout if we don't have XHR2 + if (this._xhrLevel == 1) { + this._loadTimeout = setTimeout(proxy(this._handleTimeout, this), this._item.loadTimeout); + } + + // Sometimes we get back 404s immediately, particularly when there is a cross origin request. // note this does not catch in Chrome + try { + if (!this._item.values || this._item.method == AbstractLoader.GET) { + this._request.send(); + } else if (this._item.method == AbstractLoader.POST) { + this._request.send(RequestUtils.formatQueryString(this._item.values)); + } + } catch (error) { + this.dispatchEvent(new ErrorEvent("XHR_SEND", null, error)); + } +}; + +p.setResponseType = function (type) { + // Some old browsers doesn't support blob, so we convert arraybuffer to blob after response is downloaded + if (type === 'blob') { + type = window.URL ? 'blob' : 'arraybuffer'; + this._responseType = type; + } + this._request.responseType = type; +}; + +/** + * Get all the response headers from the XmlHttpRequest. + * + * From the docs: Return all the HTTP headers, excluding headers that are a case-insensitive match + * for Set-Cookie or Set-Cookie2, as a single string, with each header line separated by a U+000D CR U+000A LF pair, + * excluding the status line, and with each header name and header value separated by a U+003A COLON U+0020 SPACE + * pair. + * @method getAllResponseHeaders + * @return {String} + * @since 0.4.1 + */ +p.getAllResponseHeaders = function () { + if (this._request.getAllResponseHeaders instanceof Function) { + return this._request.getAllResponseHeaders(); + } else { + return null; + } +}; + +/** + * Get a specific response header from the XmlHttpRequest. + * + * From the docs: Returns the header field value from the response of which the field name matches + * header, unless the field name is Set-Cookie or Set-Cookie2. + * @method getResponseHeader + * @param {String} header The header name to retrieve. + * @return {String} + * @since 0.4.1 + */ +p.getResponseHeader = function (header) { + if (this._request.getResponseHeader instanceof Function) { + return this._request.getResponseHeader(header); + } else { + return null; + } +}; + +// protected methods +/** + * The XHR request has reported progress. + * @method _handleProgress + * @param {Object} event The XHR progress event. + * @private + */ +p._handleProgress = function (event) { + if (!event || event.loaded > 0 && event.total == 0) { + return; // Sometimes we get no "total", so just ignore the progress event. + } + + var newEvent = new ProgressEvent(event.loaded, event.total); + this.dispatchEvent(newEvent); +}; + +/** + * The XHR request has reported a load start. + * @method _handleLoadStart + * @param {Object} event The XHR loadStart event. + * @private + */ +p._handleLoadStart = function (event) { + clearTimeout(this._loadTimeout); + this.dispatchEvent("loadstart"); +}; + +/** + * The XHR request has reported an abort event. + * @method handleAbort + * @param {Object} event The XHR abort event. + * @private + */ +p._handleAbort = function (event) { + this._clean(); + this.dispatchEvent(new ErrorEvent("XHR_ABORTED", null, event)); +}; + +/** + * The XHR request has reported an error event. + * @method _handleError + * @param {Object} event The XHR error event. + * @private + */ +p._handleError = function (event) { + this._clean(); + this.dispatchEvent(new ErrorEvent(event.message)); +}; + +/** + * The XHR request has reported a readyState change. Note that older browsers (IE 7 & 8) do not provide an onload + * event, so we must monitor the readyStateChange to determine if the file is loaded. + * @method _handleReadyStateChange + * @param {Object} event The XHR readyStateChange event. + * @private + */ +p._handleReadyStateChange = function (event) { + if (this._request.readyState == 4) { + this._handleLoad(); + } +}; + +/** + * The XHR request has completed. This is called by the XHR request directly, or by a readyStateChange that has + * request.readyState == 4. Only the first call to this method will be processed. + * @method _handleLoad + * @param {Object} event The XHR load event. + * @private + */ +p._handleLoad = function (event) { + if (this.loaded) { + return; + } + this.loaded = true; + + var error = this._checkError(); + if (error) { + this._handleError(error); + return; + } + + this._response = this._getResponse(); + // Convert arraybuffer back to blob + if (this._responseType === 'arraybuffer') { + try { + this._response = new Blob([this._response]); + } catch (e) { + // Fallback to use BlobBuilder if Blob constructor is not supported + // Tested on Android 2.3 ~ 4.2 and iOS5 safari + window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; + if (e.name === 'TypeError' && window.BlobBuilder) { + var builder = new BlobBuilder(); + builder.append(this._response); + this._response = builder.getBlob(); + } + } + } + this._clean(); + + this.dispatchEvent(new Event("complete")); +}; + +/** + * The XHR request has timed out. This is called by the XHR request directly, or via a setTimeout + * callback. + * @method _handleTimeout + * @param {Object} [event] The XHR timeout event. This is occasionally null when called by the backup setTimeout. + * @private + */ +p._handleTimeout = function (event) { + this._clean(); + + this.dispatchEvent(new ErrorEvent("PRELOAD_TIMEOUT", null, event)); +}; + +// Protected +/** + * Determine if there is an error in the current load. This checks the status of the request for problem codes. Note + * that this does not check for an actual response. Currently, it only checks for 404 or 0 error code. + * @method _checkError + * @return {int} If the request status returns an error code. + * @private + */ +p._checkError = function () { + //LM: Probably need additional handlers here, maybe 501 + var status = parseInt(this._request.status); + + switch (status) { + case 404: // Not Found + case 0: // Not Loaded + return new Error(status); + } + return null; +}; + +/** + * Validate the response. Different browsers have different approaches, some of which throw errors when accessed + * in other browsers. If there is no response, the _response property will remain null. + * @method _getResponse + * @private + */ +p._getResponse = function () { + if (this._response != null) { + return this._response; + } + + if (this._request.response != null) { + return this._request.response; + } + + // Android 2.2 uses .responseText + try { + if (this._request.responseText != null) { + return this._request.responseText; + } + } catch (e) { + } + + // When loading XML, IE9 does not return .response, instead it returns responseXML.xml + try { + if (this._request.responseXML != null) { + return this._request.responseXML; + } + } catch (e) { + } + + return null; +}; + +/** + * Create an XHR request. Depending on a number of factors, we get totally different results. + *
  1. Some browsers get an XDomainRequest when loading cross-domain.
  2. + *
  3. XMLHttpRequest are created when available.
  4. + *
  5. ActiveX.XMLHTTP objects are used in older IE browsers.
  6. + *
  7. Text requests override the mime type if possible
  8. + *
  9. Origin headers are sent for crossdomain requests in some browsers.
  10. + *
  11. Binary loads set the response type to "arraybuffer"
+ * @method _createXHR + * @param {Object} item The requested item that is being loaded. + * @return {Boolean} If an XHR request or equivalent was successfully created. + * @private + */ +p._createXHR = function (item) { + // Check for cross-domain loads. We can't fully support them, but we can try. + var crossdomain = RequestUtils.isCrossDomain(item); + var headers = {}; + + // Create the request. Fallback to whatever support we have. + var req = null; + if (window.XMLHttpRequest) { + req = new XMLHttpRequest(); + // This is 8 or 9, so use XDomainRequest instead. + if (crossdomain && req.withCredentials === undefined && window.XDomainRequest) { + req = new XDomainRequest(); + } + } else { // Old IE versions use a different approach + for (var i = 0, l = s.ACTIVEX_VERSIONS.length; i < l; i++) { + var axVersion = s.ACTIVEX_VERSIONS[i]; + try { + req = new ActiveXObject(axVersion); + break; + } catch (e) { + } + } + if (req == null) { + return false; + } + } + + // Default to utf-8 for Text requests. + if (item.mimeType == null && RequestUtils.isText(item.type)) { + item.mimeType = "text/plain; charset=utf-8"; + } + + // IE9 doesn't support overrideMimeType(), so we need to check for it. + if (item.mimeType && req.overrideMimeType) { + req.overrideMimeType(item.mimeType); + } + + // Determine the XHR level + this._xhrLevel = (typeof req.responseType === "string") ? 2 : 1; + + var src = null; + if (item.method == AbstractLoader.GET) { + src = RequestUtils.buildPath(item.src, item.values); + } else { + src = item.src; + } + + // Open the request. Set cross-domain flags if it is supported (XHR level 1 only) + req.open(item.method || AbstractLoader.GET, src, true); + + if (crossdomain && req instanceof XMLHttpRequest && this._xhrLevel == 1) { + headers["Origin"] = location.origin; + } + + // To send data we need to set the Content-type header) + if (item.values && item.method == AbstractLoader.POST) { + headers["Content-Type"] = "application/x-www-form-urlencoded"; + } + + if (!crossdomain && !headers["X-Requested-With"]) { + headers["X-Requested-With"] = "XMLHttpRequest"; + } + + if (item.headers) { + for (var n in item.headers) { + headers[n] = item.headers[n]; + } + } + + for (n in headers) { + req.setRequestHeader(n, headers[n]) + } + + if (req instanceof XMLHttpRequest && item.withCredentials !== undefined) { + req.withCredentials = item.withCredentials; + } + + this._request = req; + + return true; +}; + +/** + * A request has completed (or failed or canceled), and needs to be disposed. + * @method _clean + * @private + */ +p._clean = function () { + clearTimeout(this._loadTimeout); + + if (this._request.removeEventListener != null) { + this._request.removeEventListener("loadstart", this._handleLoadStartProxy); + this._request.removeEventListener("progress", this._handleProgressProxy); + this._request.removeEventListener("abort", this._handleAbortProxy); + this._request.removeEventListener("error", this._handleErrorProxy); + this._request.removeEventListener("timeout", this._handleTimeoutProxy); + this._request.removeEventListener("load", this._handleLoadProxy); + this._request.removeEventListener("readystatechange", this._handleReadyStateChangeProxy); + } else { + this._request.onloadstart = null; + this._request.onprogress = null; + this._request.onabort = null; + this._request.onerror = null; + this._request.ontimeout = null; + this._request.onload = null; + this._request.onreadystatechange = null; + } +}; + +p.toString = function () { + return "[PreloadJS XHRRequest]"; +}; + +module.exports = XHRRequest = promote(XHRRequest, "AbstractRequest"); + +},{"../../createjs/events/ErrorEvent":1,"../../createjs/utils/extend":4,"../../createjs/utils/promote":5,"../../createjs/utils/proxy":6,"../events/ProgressEvent":9,"../loaders/AbstractLoader":10,"../utils/RequestUtils":15,"./AbstractRequest":12}],15:[function(_dereq_,module,exports){ +/* + * RequestUtils + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + + +var AbstractLoader = _dereq_('../loaders/AbstractLoader'); + +/** + * Utilities that assist with parsing load items, and determining file types, etc. + * @class RequestUtils + */ +var s = {}; + +/** + * The Regular Expression used to test file URLS for an absolute path. + * @property ABSOLUTE_PATH + * @type {RegExp} + * @static + */ +s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i; + +/** + * The Regular Expression used to test file URLS for a relative path. + * @property RELATIVE_PATH + * @type {RegExp} + * @static + */ +s.RELATIVE_PATT = (/^[./]*?\//i); + +/** + * The Regular Expression used to test file URLS for an extension. Note that URIs must already have the query string + * removed. + * @property EXTENSION_PATT + * @type {RegExp} + * @static + */ +s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i; + +/** + * Parse a file path to determine the information we need to work with it. Currently, PreloadJS needs to know: + * + * @method parseURI + * @param {String} path + * @returns {Object} An Object with an `absolute` and `relative` Boolean values, as well as an optional 'extension` + * property, which is the lowercase extension. + * @static + */ +s.parseURI = function (path) { + var info = {absolute: false, relative: false}; + if (path == null) { + return info; + } + + // Drop the query string + var queryIndex = path.indexOf("?"); + if (queryIndex > -1) { + path = path.substr(0, queryIndex); + } + + // Absolute + var match; + if (s.ABSOLUTE_PATT.test(path)) { + info.absolute = true; + + // Relative + } else if (s.RELATIVE_PATT.test(path)) { + info.relative = true; + } + + // Extension + if (match = path.match(s.EXTENSION_PATT)) { + info.extension = match[1].toLowerCase(); + } + return info; +}; + +/** + * Formats an object into a query string for either a POST or GET request. + * @method formatQueryString + * @param {Object} data The data to convert to a query string. + * @param {Array} [query] Existing name/value pairs to append on to this query. + * @static + */ +s.formatQueryString = function (data, query) { + if (data == null) { + throw new Error('You must specify data.'); + } + var params = []; + for (var n in data) { + params.push(n + '=' + escape(data[n])); + } + if (query) { + params = params.concat(query); + } + return params.join('&'); +}; + +/** + * A utility method that builds a file path using a source and a data object, and formats it into a new path. + * @method buildPath + * @param {String} src The source path to add values to. + * @param {Object} [data] Object used to append values to this request as a query string. Existing parameters on the + * path will be preserved. + * @returns {string} A formatted string that contains the path and the supplied parameters. + * @static + */ +s.buildPath = function (src, data) { + if (data == null) { + return src; + } + + var query = []; + var idx = src.indexOf('?'); + + if (idx != -1) { + var q = src.slice(idx + 1); + query = query.concat(q.split('&')); + } + + if (idx != -1) { + return src.slice(0, idx) + '?' + this._formatQueryString(data, query); + } else { + return src + '?' + this._formatQueryString(data, query); + } +}; + +/** + * @method isCrossDomain + * @param {LoadItem|Object} item A load item with a `src` property. + * @return {Boolean} If the load item is loading from a different domain than the current location. + * @static + */ +s.isCrossDomain = function (item) { + var target = document.createElement("a"); + target.href = item.src; + + var host = document.createElement("a"); + host.href = location.href; + + var crossdomain = (target.hostname != "") && + (target.port != host.port || + target.protocol != host.protocol || + target.hostname != host.hostname); + return crossdomain; +}; + +/** + * @method isLocal + * @param {LoadItem|Object} item A load item with a `src` property + * @return {Boolean} If the load item is loading from the "file:" protocol. Assume that the host must be local as + * well. + * @static + */ +s.isLocal = function (item) { + var target = document.createElement("a"); + target.href = item.src; + return target.hostname == "" && target.protocol == "file:"; +}; + +/** + * Determine if a specific type should be loaded as a binary file. Currently, only images and items marked + * specifically as "binary" are loaded as binary. Note that audio is not a binary type, as we can not play + * back using an audio tag if it is loaded as binary. Plugins can change the item type to binary to ensure they get + * a binary result to work with. Binary files are loaded using XHR2. Types are defined as static constants on + * {{#crossLink "AbstractLoader"}}{{/crossLink}}. + * @method isBinary + * @param {String} type The item type. + * @return {Boolean} If the specified type is binary. + * @static + */ +s.isBinary = function (type) { + switch (type) { + case AbstractLoader.IMAGE: + case AbstractLoader.BINARY: + return true; + default: + return false; + } +}; + +/** + * Check if item is a valid HTMLImageElement + * @method isImageTag + * @param {Object} item + * @returns {Boolean} + * @static + */ +s.isImageTag = function (item) { + return item instanceof HTMLImageElement; +}; + +/** + * Check if item is a valid HTMLAudioElement + * @method isAudioTag + * @param {Object} item + * @returns {Boolean} + * @static + */ +s.isAudioTag = function (item) { + if (window.HTMLAudioElement) { + return item instanceof HTMLAudioElement; + } else { + return false; + } +}; + +/** + * Check if item is a valid HTMLVideoElement + * @method isVideoTag + * @param {Object} item + * @returns {Boolean} + * @static + */ +s.isVideoTag = function (item) { + if (window.HTMLVideoElement) { + return item instanceof HTMLVideoElement; + } else { + return false; + } +}; + +/** + * Determine if a specific type is a text-based asset, and should be loaded as UTF-8. + * @method isText + * @param {String} type The item type. + * @return {Boolean} If the specified type is text. + * @static + */ +s.isText = function (type) { + switch (type) { + case AbstractLoader.TEXT: + case AbstractLoader.JSON: + case AbstractLoader.MANIFEST: + case AbstractLoader.XML: + case AbstractLoader.CSS: + case AbstractLoader.SVG: + case AbstractLoader.JAVASCRIPT: + case AbstractLoader.SPRITESHEET: + return true; + default: + return false; + } +}; + +/** + * Determine the type of the object using common extensions. Note that the type can be passed in with the load item + * if it is an unusual extension. + * @method getTypeByExtension + * @param {String} extension The file extension to use to determine the load type. + * @return {String} The determined load type (for example, AbstractLoader.IMAGE). Will return `null` if + * the type can not be determined by the extension. + * @static + */ +s.getTypeByExtension = function (extension) { + if (extension == null) { + return AbstractLoader.TEXT; + } + + switch (extension.toLowerCase()) { + case "jpeg": + case "jpg": + case "gif": + case "png": + case "webp": + case "bmp": + return AbstractLoader.IMAGE; + case "ogg": + case "mp3": + case "webm": + return AbstractLoader.SOUND; + case "mp4": + case "webm": + case "ts": + return AbstractLoader.VIDEO; + case "json": + return AbstractLoader.JSON; + case "xml": + return AbstractLoader.XML; + case "css": + return AbstractLoader.CSS; + case "js": + return AbstractLoader.JAVASCRIPT; + case 'svg': + return AbstractLoader.SVG; + default: + return AbstractLoader.TEXT; + } +}; + +var RequestUtils = s; +module.exports = RequestUtils; + +},{"../loaders/AbstractLoader":10}],16:[function(_dereq_,module,exports){ +// File for legacy window.createjs support. Also used for the the build process. +(function (name, definition) { + if (typeof module != 'undefined') module.exports = definition(); + else if (typeof define == 'function' && typeof define.amd == 'object') define(definition); + else this[name] = definition(); console.log(this, name); +}('createjs', function () { + console.log("createjs?"); + return { + LoadQueue: _dereq_("./LoadQueue"), + promote: _dereq_('../createjs/utils/promote'), + extend: _dereq_('../createjs/utils/extend'), + Event: _dereq_('../createjs/events/Event'), + ErrorEvent: _dereq_('../createjs/events/ErrorEvent'), + ProgressEvent: _dereq_('./events/ProgressEvent') + }; +})); + +},{"../createjs/events/ErrorEvent":1,"../createjs/events/Event":2,"../createjs/utils/extend":4,"../createjs/utils/promote":5,"./LoadQueue":7,"./events/ProgressEvent":9}]},{},[16]); + +},{}],2:[function(require,module,exports){ +var build = require('../build'); + +var label = document.createElement("div"); +label.innerText = "createjs exists! Its classes are: \n"+Object.keys(createjs).join("\n"); +document.body.appendChild(label); + +},{"../build":1}]},{},[2]); diff --git a/examples/moduleLoaders/build.js b/examples/moduleLoaders/build.js new file mode 100644 index 0000000..0e0fcf4 --- /dev/null +++ b/examples/moduleLoaders/build.js @@ -0,0 +1,5454 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oExample + * + * myObject.addEventListener("change", createjs.proxy(myMethod, scope)); + * + * @module CreateJS + * @main CreateJS + */ +// constructor: +/** + * Contains properties and methods shared by all events for use with + * {{#crossLink "EventDispatcher"}}{{/crossLink}}. + * + * Note that Event objects are often reused, so you should never + * rely on an event object's state outside of the call stack it was received in. + * @class Event + * @param {String} type The event type. + * @param {Boolean} bubbles Indicates whether the event will bubble through the display list. + * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled. + * @constructor + **/ +function Event(type, bubbles, cancelable) { + + + // public properties: + /** + * The type of event. + * @property type + * @type String + **/ + this.type = type; + + /** + * The object that generated an event. + * @property target + * @type Object + * @default null + * @readonly + */ + this.target = null; + + /** + * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will + * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event + * is generated from childObj, then a listener on parentObj would receive the event with + * target=childObj (the original target) and currentTarget=parentObj (where the listener was added). + * @property currentTarget + * @type Object + * @default null + * @readonly + */ + this.currentTarget = null; + + /** + * For bubbling events, this indicates the current event phase:
    + *
  1. capture phase: starting from the top parent to the target
  2. + *
  3. at target phase: currently being dispatched from the target
  4. + *
  5. bubbling phase: from the target to the top parent
  6. + *
+ * @property eventPhase + * @type Number + * @default 0 + * @readonly + */ + this.eventPhase = 0; + + /** + * Indicates whether the event will bubble through the display list. + * @property bubbles + * @type Boolean + * @default false + * @readonly + */ + this.bubbles = !!bubbles; + + /** + * Indicates whether the default behaviour of this event can be cancelled via + * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor. + * @property cancelable + * @type Boolean + * @default false + * @readonly + */ + this.cancelable = !!cancelable; + + /** + * The epoch time at which this event was created. + * @property timeStamp + * @type Number + * @default 0 + * @readonly + */ + this.timeStamp = (new Date()).getTime(); + + /** + * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called + * on this event. + * @property defaultPrevented + * @type Boolean + * @default false + * @readonly + */ + this.defaultPrevented = false; + + /** + * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or + * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event. + * @property propagationStopped + * @type Boolean + * @default false + * @readonly + */ + this.propagationStopped = false; + + /** + * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called + * on this event. + * @property immediatePropagationStopped + * @type Boolean + * @default false + * @readonly + */ + this.immediatePropagationStopped = false; + + /** + * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event. + * @property removed + * @type Boolean + * @default false + * @readonly + */ + this.removed = false; +} +var p = Event.prototype; + +/** + * REMOVED. Removed in favor of using `MySuperClass_constructor`. + * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} + * for details. + * + * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. + * + * @method initialize + * @protected + * @deprecated + */ +// p.initialize = function() {}; // searchable for devs wondering where it is. + + +// public methods: +/** + * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method preventDefault + **/ +p.preventDefault = function () { + this.defaultPrevented = this.cancelable && true; +}; + +/** + * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method stopPropagation + **/ +p.stopPropagation = function () { + this.propagationStopped = true; +}; + +/** + * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and + * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method stopImmediatePropagation + **/ +p.stopImmediatePropagation = function () { + this.immediatePropagationStopped = this.propagationStopped = true; +}; + +/** + * Causes the active listener to be removed via removeEventListener(); + * + * myBtn.addEventListener("click", function(evt) { + * // do stuff... + * evt.remove(); // removes this listener. + * }); + * + * @method remove + **/ +p.remove = function () { + this.removed = true; +}; + +/** + * Returns a clone of the Event instance. + * @method clone + * @return {Event} a clone of the Event instance. + **/ +p.clone = function () { + return new Event(this.type, this.bubbles, this.cancelable); +}; + +/** + * Provides a chainable shortcut method for setting a number of properties on the instance. + * + * @method set + * @param {Object} props A generic object containing properties to copy to the instance. + * @return {Event} Returns the instance the method is called on (useful for chaining calls.) + * @chainable + */ +p.set = function (props) { + for (var n in props) { + this[n] = props[n]; + } + return this; +}; + +/** + * Returns a string representation of this object. + * @method toString + * @return {String} a string representation of the instance. + **/ +p.toString = function () { + return "[Event (type=" + this.type + ")]"; +}; + +module.exports = Event; + +},{}],3:[function(_dereq_,module,exports){ +/* + * EventDispatcher + * Visit http://createjs.com/ for documentation, updates and examples. + * + * Copyright (c) 2010 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module CreateJS + */ + + +var Event = _dereq_('./Event'); + +// constructor: +/** + * EventDispatcher provides methods for managing queues of event listeners and dispatching events. + * + * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the + * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method. + * + * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the + * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports + * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent. + * + * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier + * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The + * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to + * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}. + * + * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}} + * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also + * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener. + * + *

Example

+ * Add EventDispatcher capabilities to the "MyClass" class. + * + * EventDispatcher.initialize(MyClass.prototype); + * + * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}). + * + * instance.addEventListener("eventName", handlerMethod); + * function handlerMethod(event) { + * console.log(event.target + " Was Clicked"); + * } + * + * Maintaining proper scope
+ * Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}} + * method to subscribe to events simplifies this. + * + * instance.addEventListener("click", function(event) { + * console.log(instance == this); // false, scope is ambiguous. + * }); + * + * instance.on("click", function(event) { + * console.log(instance == this); // true, "on" uses dispatcher scope by default. + * }); + * + * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage scope. + * + * + * @class EventDispatcher + * @constructor + **/ +function EventDispatcher() { + + + // private properties: + /** + * @protected + * @property _listeners + * @type Object + **/ + this._listeners = null; + + /** + * @protected + * @property _captureListeners + * @type Object + **/ + this._captureListeners = null; +} +var p = EventDispatcher.prototype; + +/** + * REMOVED. Removed in favor of using `MySuperClass_constructor`. + * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} + * for details. + * + * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. + * + * @method initialize + * @protected + * @deprecated + */ +// p.initialize = function() {}; // searchable for devs wondering where it is. + + +// static public methods: +/** + * Static initializer to mix EventDispatcher methods into a target object or prototype. + * + * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class + * EventDispatcher.initialize(myObject); // add to a specific instance + * + * @method initialize + * @static + * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a + * prototype. + **/ +EventDispatcher.initialize = function (target) { + target.addEventListener = p.addEventListener; + target.on = p.on; + target.removeEventListener = target.off = p.removeEventListener; + target.removeAllEventListeners = p.removeAllEventListeners; + target.hasEventListener = p.hasEventListener; + target.dispatchEvent = p.dispatchEvent; + target._dispatchEvent = p._dispatchEvent; + target.willTrigger = p.willTrigger; +}; + + +// public methods: +/** + * Adds the specified event listener. Note that adding multiple listeners to the same function will result in + * multiple callbacks getting fired. + * + *

Example

+ * + * displayObject.addEventListener("click", handleClick); + * function handleClick(event) { + * // Click happened. + * } + * + * @method addEventListener + * @param {String} type The string type of the event. + * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when + * the event is dispatched. + * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + * @return {Function | Object} Returns the listener for chaining or assignment. + **/ +p.addEventListener = function (type, listener, useCapture) { + var listeners; + if (useCapture) { + listeners = this._captureListeners = this._captureListeners || {}; + } else { + listeners = this._listeners = this._listeners || {}; + } + var arr = listeners[type]; + if (arr) { + this.removeEventListener(type, listener, useCapture); + } + arr = listeners[type]; // remove may have deleted the array + if (!arr) { + listeners[type] = [listener]; + } + else { + arr.push(listener); + } + return listener; +}; + +/** + * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener + * only run once, associate arbitrary data with the listener, and remove the listener. + * + * This method works by creating an anonymous wrapper function and subscribing it with addEventListener. + * The created anonymous function is returned for use with .removeEventListener (or .off). + * + *

Example

+ * + * var listener = myBtn.on("click", handleClick, null, false, {count:3}); + * function handleClick(evt, data) { + * data.count -= 1; + * console.log(this == myBtn); // true - scope defaults to the dispatcher + * if (data.count == 0) { + * alert("clicked 3 times!"); + * myBtn.off("click", listener); + * // alternately: evt.remove(); + * } + * } + * + * @method on + * @param {String} type The string type of the event. + * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when + * the event is dispatched. + * @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent). + * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered. + * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called. + * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener. + **/ +p.on = function (type, listener, scope, once, data, useCapture) { + if (listener.handleEvent) { + scope = scope || listener; + listener = listener.handleEvent; + } + scope = scope || this; + return this.addEventListener(type, function (evt) { + listener.call(scope, evt, data); + once && evt.remove(); + }, useCapture); +}; + +/** + * Removes the specified event listener. + * + * Important Note: that you must pass the exact function reference used when the event was added. If a proxy + * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or + * closure will not work. + * + *

Example

+ * + * displayObject.removeEventListener("click", handleClick); + * + * @method removeEventListener + * @param {String} type The string type of the event. + * @param {Function | Object} listener The listener function or object. + * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + **/ +p.removeEventListener = function (type, listener, useCapture) { + var listeners = useCapture ? this._captureListeners : this._listeners; + if (!listeners) { + return; + } + var arr = listeners[type]; + if (!arr) { + return; + } + for (var i = 0, l = arr.length; i < l; i++) { + if (arr[i] == listener) { + if (l == 1) { + delete(listeners[type]); + } // allows for faster checks. + else { + arr.splice(i, 1); + } + break; + } + } +}; + +/** + * A shortcut to the removeEventListener method, with the same parameters and return value. This is a companion to the + * .on method. + * + * @method off + * @param {String} type The string type of the event. + * @param {Function | Object} listener The listener function or object. + * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + **/ +p.off = p.removeEventListener; + +/** + * Removes all listeners for the specified type, or all listeners of all types. + * + *

Example

+ * + * // Remove all listeners + * displayObject.removeAllEventListeners(); + * + * // Remove all click listeners + * displayObject.removeAllEventListeners("click"); + * + * @method removeAllEventListeners + * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed. + **/ +p.removeAllEventListeners = function (type) { + if (!type) { + this._listeners = this._captureListeners = null; + } + else { + if (this._listeners) { + delete(this._listeners[type]); + } + if (this._captureListeners) { + delete(this._captureListeners[type]); + } + } +}; + +/** + * Dispatches the specified event to all listeners. + * + *

Example

+ * + * // Use a string event + * this.dispatchEvent("complete"); + * + * // Use an Event instance + * var event = new createjs.Event("progress"); + * this.dispatchEvent(event); + * + * @method dispatchEvent + * @param {Object | String | Event} eventObj An object with a "type" property, or a string type. + * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used, + * dispatchEvent will construct an Event instance with the specified type. + * @return {Boolean} Returns the value of eventObj.defaultPrevented. + **/ +p.dispatchEvent = function (eventObj) { + if (typeof eventObj == "string") { + // won't bubble, so skip everything if there's no listeners: + var listeners = this._listeners; + if (!listeners || !listeners[eventObj]) { + return false; + } + eventObj = new Event(eventObj); + } else if (eventObj.target && eventObj.clone) { + // redispatching an active event object, so clone it: + eventObj = eventObj.clone(); + } + try { + eventObj.target = this; + } catch (e) { + } // try/catch allows redispatching of native events + + if (!eventObj.bubbles || !this.parent) { + this._dispatchEvent(eventObj, 2); + } else { + var top = this, list = [top]; + while (top.parent) { + list.push(top = top.parent); + } + var i, l = list.length; + + // capture & atTarget + for (i = l - 1; i >= 0 && !eventObj.propagationStopped; i--) { + list[i]._dispatchEvent(eventObj, 1 + (i == 0)); + } + // bubbling + for (i = 1; i < l && !eventObj.propagationStopped; i++) { + list[i]._dispatchEvent(eventObj, 3); + } + } + return eventObj.defaultPrevented; +}; + +/** + * Indicates whether there is at least one listener for the specified event type. + * @method hasEventListener + * @param {String} type The string type of the event. + * @return {Boolean} Returns true if there is at least one listener for the specified event. + **/ +p.hasEventListener = function (type) { + var listeners = this._listeners, captureListeners = this._captureListeners; + return !!((listeners && listeners[type]) || (captureListeners && captureListeners[type])); +}; + +/** + * Indicates whether there is at least one listener for the specified event type on this object or any of its + * ancestors (parent, parent's parent, etc). A return value of true indicates that if a bubbling event of the + * specified type is dispatched from this object, it will trigger at least one listener. + * + * This is similar to {{#crossLink "EventDispatcher/hasEventListener"}}{{/crossLink}}, but it searches the entire + * event flow for a listener, not just this object. + * @method willTrigger + * @param {String} type The string type of the event. + * @return {Boolean} Returns `true` if there is at least one listener for the specified event. + **/ +p.willTrigger = function (type) { + var o = this; + while (o) { + if (o.hasEventListener(type)) { + return true; + } + o = o.parent; + } + return false; +}; + +/** + * @method toString + * @return {String} a string representation of the instance. + **/ +p.toString = function () { + return "[EventDispatcher]"; +}; + + +// private methods: +/** + * @method _dispatchEvent + * @param {Object | String | Event} eventObj + * @param {Object} eventPhase + * @protected + **/ +p._dispatchEvent = function (eventObj, eventPhase) { + var l, listeners = (eventPhase == 1) ? this._captureListeners : this._listeners; + if (eventObj && listeners) { + var arr = listeners[eventObj.type]; + if (!arr || !(l = arr.length)) { + return; + } + try { + eventObj.currentTarget = this; + } catch (e) { + } + try { + eventObj.eventPhase = eventPhase; + } catch (e) { + } + eventObj.removed = false; + + arr = arr.slice(); // to avoid issues with items being removed or added during the dispatch + for (var i = 0; i < l && !eventObj.immediatePropagationStopped; i++) { + var o = arr[i]; + if (o.handleEvent) { + o.handleEvent(eventObj); + } + else { + o(eventObj); + } + if (eventObj.removed) { + this.off(eventObj.type, o, eventPhase == 1); + eventObj.removed = false; + } + } + } +}; + + +module.exports = EventDispatcher = EventDispatcher; + +},{"./Event":2}],4:[function(_dereq_,module,exports){ +/* +* extend +* Visit http://createjs.com/ for documentation, updates and examples. +* +* Copyright (c) 2010 gskinner.com, inc. +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +/** + * @module CreateJS + */ + +/** + * @class Utility Methods + */ + +/** + * Sets up the prototype chain and constructor property for a new class. + * + * This should be called right after creating the class constructor. + * + * function MySubClass() {} + * createjs.extend(MySubClass, MySuperClass); + * ClassB.prototype.doSomething = function() { } + * + * var foo = new MySubClass(); + * console.log(foo instanceof MySuperClass); // true + * console.log(foo.prototype.constructor === MySubClass); // true + * + * @method extend + * @param {Function} subclass The subclass. + * @param {Function} superclass The superclass to extend. + * @return {Function} Returns the subclass's new prototype. + */ +module.exports = function(subclass, superclass) { + "use strict"; + + function o() { this.constructor = subclass; } + o.prototype = superclass.prototype; + return (subclass.prototype = new o()); +}; + +},{}],5:[function(_dereq_,module,exports){ +/* +* promote +* Visit http://createjs.com/ for documentation, updates and examples. +* +* Copyright (c) 2010 gskinner.com, inc. +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +* OTHER DEALINGS IN THE SOFTWARE. +*/ + +/** + * @module CreateJS + */ + +/** + * @class Utility Methods + */ + +/** + * Promotes any methods on the super class that were overridden, by creating an alias in the format `prefix_methodName`. + * It is recommended to use the super class's name as the prefix. + * An alias to the super class's constructor is always added in the format `prefix_constructor`. + * This allows the subclass to call super class methods without using `function.call`, providing better performance. + * + * For example, if `MySubClass` extends `MySuperClass`, and both define a `draw` method, then calling `promote(MySubClass, "MySuperClass")` + * would add a `MySuperClass_constructor` method to MySubClass and promote the `draw` method on `MySuperClass` to the + * prototype of `MySubClass` as `MySuperClass_draw`. + * + * This should be called after the class's prototype is fully defined. + * + * function ClassA(name) { + * this.name = name; + * } + * ClassA.prototype.greet = function() { + * return "Hello "+this.name; + * } + * + * function ClassB(name, punctuation) { + * this.ClassA_constructor(name); + * this.punctuation = punctuation; + * } + * createjs.extend(ClassB, ClassA); + * ClassB.prototype.greet = function() { + * return this.ClassA_greet()+this.punctuation; + * } + * createjs.promote(ClassB, "ClassA"); + * + * var foo = new ClassB("World", "!?!"); + * console.log(foo.greet()); // Hello World!?! + * + * @method promote + * @param {Function} subclass The class to promote super class methods on. + * @param {String} prefix The prefix to add to the promoted method names. Usually the name of the superclass. + * @return {Function} Returns the subclass. + */ +module.exports = function(subclass, prefix) { + "use strict"; + + var subP = subclass.prototype, supP = (Object.getPrototypeOf&&Object.getPrototypeOf(subP))||subP.__proto__; + if (supP) { + subP[(prefix+="_") + "constructor"] = supP.constructor; // constructor is not always innumerable + for (var n in supP) { + if (subP.hasOwnProperty(n) && (typeof supP[n] == "function")) { subP[prefix + n] = supP[n]; } + } + } + return subclass; +}; + +},{}],6:[function(_dereq_,module,exports){ +/* + * Proxy + * Visit http://createjs.com/ for documentation, updates and examples. + * + * Copyright (c) 2010 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module CreateJS + */ + +// namespace: + +/** + * Various utilities that the CreateJS Suite uses. Utilities are created as separate files, and will be available on the + * createjs namespace directly. + * + *

Example

+ * + * myObject.addEventListener("change", createjs.proxy(myMethod, scope)); + * + * @class Utility Methods + * @main Utility Methods + */ + + +/** + * A function proxy for methods. By default, JavaScript methods do not maintain scope, so passing a method as a + * callback will result in the method getting called in the scope of the caller. Using a proxy ensures that the + * method gets called in the correct scope. + * + * Additional arguments can be passed that will be applied to the function when it is called. + * + *

Example

+ * + * myObject.addEventListener("event", createjs.proxy(myHandler, this, arg1, arg2)); + * + * function myHandler(arg1, arg2) { + * // This gets called when myObject.myCallback is executed. + * } + * + * @method proxy + * @param {Function} method The function to call + * @param {Object} scope The scope to call the method name on + * @param {mixed} [arg] * Arguments that are appended to the callback for additional params. + * @public + * @static + */ +module.exports = function (method, scope) { + var aArgs = Array.prototype.slice.call(arguments, 2); + return function () { + return method.apply(scope, Array.prototype.slice.call(arguments, 0).concat(aArgs)); + }; +} +},{}],7:[function(_dereq_,module,exports){ +/* + * LoadQueue + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * PreloadJS provides a consistent way to preload content for use in HTML applications. Preloading can be done using + * HTML tags, as well as XHR. + * + * By default, PreloadJS will try and load content using XHR, since it provides better support for progress and + * completion events, however due to cross-domain issues, it may still be preferable to use tag-based loading + * instead. Note that some content requires XHR to work (plain text, web audio), and some requires tags (HTML audio). + * Note this is handled automatically where possible. + * + * PreloadJS currently supports all modern browsers, and we have done our best to include support for most older + * browsers. If you find an issue with any specific OS/browser combination, please visit http://community.createjs.com/ + * and report it. + * + *

Getting Started

+ * To get started, check out the {{#crossLink "LoadQueue"}}{{/crossLink}} class, which includes a quick overview of how + * to load files and process results. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.installPlugin(createjs.Sound); + * queue.on("complete", handleComplete, this); + * queue.loadFile({id:"sound", src:"http://path/to/sound.mp3"}); + * queue.loadManifest([ + * {id: "myImage", src:"path/to/myImage.jpg"} + * ]); + * function handleComplete() { + * createjs.Sound.play("sound"); + * var image = queue.getResult("myImage"); + * document.body.appendChild(image); + * } + * + * Important note on plugins: Plugins must be installed before items are added to the queue, otherwise + * they will not be processed, even if the load has not actually kicked off yet. Plugin functionality is handled when + * the items are added to the LoadQueue. + * + *

Browser Support

+ * PreloadJS is partially supported in all browsers, and fully supported in all modern browsers. Known exceptions: + *
  • XHR loading of any content will not work in many older browsers (See a matrix here: http://caniuse.com/xhr2). + * In many cases, you can fall back on tag loading (images, audio, CSS, scripts, and SVG). Text and + * WebAudio will only work with XHR.
  • + *
  • Some formats have poor support for complete events in IE 6, 7, and 8 (SVG, tag loading of scripts, XML/JSON)
  • + *
  • Opera has poor support for SVG loading with XHR
  • + *
  • CSS loading in Android and Safari will not work with tags (currently, a workaround is in progress)
  • + *
  • Local loading is not permitted with XHR, which is required by some file formats. When testing local content + * use either a local server, or enable tag loading, which is supported for most formats. See {{#crossLink "LoadQueue/setUseXHR"}}{{/crossLink}} + * for more information.
  • + *
+ * + *

Cross-domain Loading

+ * Most content types can be loaded cross-domain, as long as the server supports CORS. PreloadJS also has internal + * support for images served from a CORS-enabled server, via the `crossOrigin` argument on the {{#crossLink "LoadQueue"}}{{/crossLink}} + * constructor. If set to a string value (such as "Anonymous"), the "crossOrigin" property of images generated by + * PreloadJS is set to that value. Please note that setting a `crossOrigin` value on an image that is served from a + * server without CORS will cause other errors. For more info on CORS, visit https://en.wikipedia.org/wiki/Cross-origin_resource_sharing. + * + * @module PreloadJS + * @main PreloadJS + */ + +// namespace: + + +/* + TODO: WINDOWS ISSUES + * No error for HTML audio in IE 678 + * SVG no failure error in IE 67 (maybe 8) TAGS AND XHR + * No script complete handler in IE 67 TAGS (XHR is fine) + * No XML/JSON in IE6 TAGS + * Need to hide loading SVG in Opera TAGS + * No CSS onload/readystatechange in Safari or Android TAGS (requires rule checking) + * SVG no load or failure in Opera XHR + * Reported issues with IE7/8 + */ + +// constructor +/** + * The LoadQueue class is the main API for preloading content. LoadQueue is a load manager, which can preload either + * a single file, or queue of files. + * + * Creating a Queue
+ * To use LoadQueue, create a LoadQueue instance. If you want to force tag loading where possible, set the preferXHR + * argument to false. + * + * var queue = new createjs.LoadQueue(true); + * + * Listening for Events
+ * Add any listeners you want to the queue. Since PreloadJS 0.3.0, the {{#crossLink "EventDispatcher"}}{{/crossLink}} + * lets you add as many listeners as you want for events. You can subscribe to the following events:
    + *
  • {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}}: fired when a queue completes loading all + * files
  • + *
  • {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}: fired when the queue encounters an error with + * any file.
  • + *
  • {{#crossLink "AbstractLoader/progress:event"}}{{/crossLink}}: Progress for the entire queue has + * changed.
  • + *
  • {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}}: A single file has completed loading.
  • + *
  • {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}}: Progress for a single file has changes. Note + * that only files loaded with XHR (or possibly by plugins) will fire progress events other than 0 or 100%.
  • + *
+ * + * queue.on("fileload", handleFileLoad, this); + * queue.on("complete", handleComplete, this); + * + * Adding files and manifests
+ * Add files you want to load using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or add multiple files at a + * time using a list or a manifest definition using {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. Files are + * appended to the end of the active queue, so you can use these methods as many times as you like, whenever you + * like. + * + * queue.loadFile("filePath/file.jpg"); + * queue.loadFile({id:"image", src:"filePath/file.jpg"}); + * queue.loadManifest(["filePath/file.jpg", {id:"image", src:"filePath/file.jpg"}]); + * + * // Use an external manifest + * queue.loadManifest("path/to/manifest.json"); + * queue.loadManifest({src:"manifest.json", type:"manifest"}); + * + * If you pass `false` as the `loadNow` parameter, the queue will not kick of the load of the files, but it will not + * stop if it has already been started. Call the {{#crossLink "AbstractLoader/load"}}{{/crossLink}} method to begin + * a paused queue. Note that a paused queue will automatically resume when new files are added to it with a + * `loadNow` argument of `true`. + * + * queue.load(); + * + * File Types
+ * The file type of a manifest item is auto-determined by the file extension. The pattern matching in PreloadJS + * should handle the majority of standard file and url formats, and works with common file extensions. If you have + * either a non-standard file extension, or are serving the file using a proxy script, then you can pass in a + * type property with any manifest item. + * + * queue.loadFile({src:"path/to/myFile.mp3x", type:AbstractLoader.SOUND}); + * + * // Note that PreloadJS will not read a file extension from the query string + * queue.loadFile({src:"http://server.com/proxy?file=image.jpg", type:AbstractLoader.IMAGE}); + * + * Supported types are defined on the {{#crossLink "AbstractLoader"}}{{/crossLink}} class, and include: + *
    + *
  • {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}}: Raw binary data via XHR
  • + *
  • {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}}: CSS files
  • + *
  • {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}: Common image formats
  • + *
  • {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}}: JavaScript files
  • + *
  • {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}}: JSON data
  • + *
  • {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}}: JSON files cross-domain
  • + *
  • {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}: A list of files to load in JSON format, see + * {{#crossLink "AbstractLoader/loadManifest"}}{{/crossLink}}
  • + *
  • {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}: Audio file formats
  • + *
  • {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}: JSON SpriteSheet definitions. This + * will also load sub-images, and provide a {{#crossLink "SpriteSheet"}}{{/crossLink}} instance.
  • + *
  • {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}}: SVG files
  • + *
  • {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}}: Text files - XHR only
  • + *
  • {{#crossLink "AbstractLoader/VIDEO:property"}}{{/crossLink}}: Video objects
  • + *
  • {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}}: XML data
  • + *
+ * + * Note: Loader types used to be defined on LoadQueue, but have been moved to AbstractLoader for better + * portability of loader classes, which can be used individually now. The properties on LoadQueue still exist, but + * are deprecated. + * + * Handling Results
+ * When a file is finished downloading, a {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event is + * dispatched. In an example above, there is an event listener snippet for fileload. Loaded files are usually a + * formatted object that can be used immediately, including: + *
    + *
  • Binary: The binary loaded result
  • + *
  • CSS: A <link /> tag
  • + *
  • Image: An <img /> tag
  • + *
  • JavaScript: A <script /> tag
  • + *
  • JSON/JSONP: A formatted JavaScript Object
  • + *
  • Manifest: A JavaScript object. + *
  • Sound: An <audio /> tag + *
  • SpriteSheet: A {{#crossLink "SpriteSheet"}}{{/crossLink}} instance, containing loaded images. + *
  • SVG: An <object /> tag
  • + *
  • Text: Raw text
  • + *
  • Video: A Video DOM node
  • + *
  • XML: An XML DOM node
  • + *
+ * + * function handleFileLoad(event) { + * var item = event.item; // A reference to the item that was passed in to the LoadQueue + * var type = item.type; + * + * // Add any images to the page body. + * if (type == createjs.LoadQueue.IMAGE) { + * document.body.appendChild(event.result); + * } + * } + * + * At any time after the file has been loaded (usually after the queue has completed), any result can be looked up + * via its "id" using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. If no id was provided, then the + * "src" or file path can be used instead, including the `path` defined by a manifest, but not including + * a base path defined on the LoadQueue. It is recommended to always pass an id if you want to look up content. + * + * var image = queue.getResult("image"); + * document.body.appendChild(image); + * + * Raw loaded content can be accessed using the rawResult property of the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} + * event, or can be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}, passing `true` as the 2nd + * argument. This is only applicable for content that has been parsed for the browser, specifically: JavaScript, + * CSS, XML, SVG, and JSON objects, or anything loaded with XHR. + * + * var image = queue.getResult("image", true); // load the binary image data loaded with XHR. + * + * Plugins
+ * LoadQueue has a simple plugin architecture to help process and preload content. For example, to preload audio, + * make sure to install the SoundJS Sound class, which will help load HTML audio, + * Flash audio, and WebAudio files. This should be installed before loading any audio files. + * + * queue.installPlugin(createjs.Sound); + * + *

Known Browser Issues

+ *
    + *
  • Browsers without audio support can not load audio files.
  • + *
  • Safari on Mac OS X can only play HTML audio if QuickTime is installed
  • + *
  • HTML Audio tags will only download until their canPlayThrough event is fired. Browsers other + * than Chrome will continue to download in the background.
  • + *
  • When loading scripts using tags, they are automatically added to the document.
  • + *
  • Scripts loaded via XHR may not be properly inspectable with browser tools.
  • + *
  • IE6 and IE7 (and some other browsers) may not be able to load XML, Text, or JSON, since they require + * XHR to work.
  • + *
  • Content loaded via tags will not show progress, and will continue to download in the background when + * canceled, although no events will be dispatched.
  • + *
+ * + * @class LoadQueue + * @param {Boolean} [preferXHR=true] Determines whether the preload instance will favor loading with XHR (XML HTTP + * Requests), or HTML tags. When this is `false`, the queue will use tag loading when possible, and fall back on XHR + * when necessary. + * @param {String} [basePath=""] A path that will be prepended on to the source parameter of all items in the queue + * before they are loaded. Sources beginning with a protocol such as `http://` or a relative path such as `../` + * will not receive a base path. + * @param {String|Boolean} [crossOrigin=""] An optional flag to support images loaded from a CORS-enabled server. To + * use it, set this value to `true`, which will default the crossOrigin property on images to "Anonymous". Any + * string value will be passed through, but only "" and "Anonymous" are recommended. Note: The crossOrigin + * parameter is deprecated. Use LoadItem.crossOrigin instead + * + * @constructor + * @extends AbstractLoader + */ + +var ImageLoader = _dereq_('./loaders/ImageLoader'); +var extend = _dereq_('../createjs/utils/extend'); +var promote = _dereq_('../createjs/utils/promote'); +var AbstractLoader = _dereq_('./loaders/AbstractLoader'); +var Event = _dereq_('../createjs/events/Event'); +var ErrorEvent = _dereq_('../createjs/events/ErrorEvent'); +var RequestUtils = _dereq_('./utils/RequestUtils'); +var LoadItem = _dereq_('./data/LoadItem'); + +function LoadQueue(preferXHR, basePath, crossOrigin) { + this.AbstractLoader_constructor(); + + /** + * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}. + * @property _plugins + * @type {Array} + * @private + * @since 0.6.1 + */ + this._plugins = []; + + /** + * An object hash of callbacks that are fired for each file type before the file is loaded, giving plugins the + * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} + * method for more information. + * @property _typeCallbacks + * @type {Object} + * @private + */ + this._typeCallbacks = {}; + + /** + * An object hash of callbacks that are fired for each file extension before the file is loaded, giving plugins the + * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} + * method for more information. + * @property _extensionCallbacks + * @type {null} + * @private + */ + this._extensionCallbacks = {}; + + /** + * The next preload queue to process when this one is complete. If an error is thrown in the current queue, and + * {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} is `true`, the next queue will not be processed. + * @property next + * @type {LoadQueue} + * @default null + */ + this.next = null; + + /** + * Ensure loaded scripts "complete" in the order they are specified. Loaded scripts are added to the document head + * once they are loaded. Scripts loaded via tags will load one-at-a-time when this property is `true`, whereas + * scripts loaded using XHR can load in any order, but will "finish" and be added to the document in the order + * specified. + * + * Any items can be set to load in order by setting the {{#crossLink "maintainOrder:property"}}{{/crossLink}} + * property on the load item, or by ensuring that only one connection can be open at a time using + * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Note that when the `maintainScriptOrder` property + * is set to `true`, scripts items are automatically set to `maintainOrder=true`, and changing the + * `maintainScriptOrder` to `false` during a load will not change items already in a queue. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.setMaxConnections(3); // Set a higher number to load multiple items at once + * queue.maintainScriptOrder = true; // Ensure scripts are loaded in order + * queue.loadManifest([ + * "script1.js", + * "script2.js", + * "image.png", // Load any time + * {src: "image2.png", maintainOrder: true} // Will wait for script2.js + * "image3.png", + * "script3.js" // Will wait for image2.png before loading (or completing when loading with XHR) + * ]); + * + * @property maintainScriptOrder + * @type {Boolean} + * @default true + */ + this.maintainScriptOrder = true; + + /** + * Determines if the LoadQueue will stop processing the current queue when an error is encountered. + * @property stopOnError + * @type {Boolean} + * @default false + */ + this.stopOnError = false; + + /** + * The number of maximum open connections that a loadQueue tries to maintain. Please see + * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} for more information. + * @property _maxConnections + * @type {Number} + * @default 1 + * @private + */ + this._maxConnections = 1; + + /** + * An internal list of all the default Loaders that are included with PreloadJS. Before an item is loaded, the + * available loader list is iterated, in the order they are included, and as soon as a loader indicates it can + * handle the content, it will be selected. The default loader, ({{#crossLink "TextLoader"}}{{/crossLink}} is + * last in the list, so it will be used if no other match is found. Typically, loaders will match based on the + * {{#crossLink "LoadItem/type"}}{{/crossLink}}, which is automatically determined using the file extension of + * the {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. + * + * Loaders can be removed from PreloadJS by simply not including them. + * + * Custom loaders installed using {{#crossLink "registerLoader"}}{{/crossLink}} will be prepended to this list + * so that they are checked first. + * @property _availableLoaders + * @type {Array} + * @private + * @since 0.6.0 + */ + this._availableLoaders = [ + ImageLoader + /*, + createjs.JavaScriptLoader, + createjs.CSSLoader, + createjs.JSONLoader, + createjs.JSONPLoader, + createjs.SoundLoader, + createjs.ManifestLoader, + createjs.SpriteSheetLoader, + createjs.XMLLoader, + createjs.SVGLoader, + createjs.BinaryLoader, + createjs.VideoLoader, + createjs.TextLoader + */ + ]; + + /** + * The number of built in loaders, so they can't be removed by {{#crossLink "unregisterLoader"}}{{/crossLink}. + * @property _defaultLoaderLength + * @type {Number} + * @private + * @since 0.6.0 + */ + this._defaultLoaderLength = this._availableLoaders.length; + + this.init(preferXHR, basePath, crossOrigin); +} + +var p = extend(LoadQueue, AbstractLoader); +var s = LoadQueue; + +/** + * REMOVED. Removed in favor of using `MySuperClass_constructor`. + * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} + * for details. + * + * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. + * + * @method initialize + * @protected + * @deprecated + */ +// p.initialize = function() {}; // searchable for devs wondering where it is. + +/** + * An internal initialization method, which is used for initial set up, but also to reset the LoadQueue. + * @method init + * @param preferXHR + * @param basePath + * @param crossOrigin + * @private + */ +p.init = function (preferXHR, basePath, crossOrigin) { + + // public properties + /** + * @property useXHR + * @type {Boolean} + * @readonly + * @default true + * @deprecated Use preferXHR instead. + */ + this.useXHR = true; + + /** + * Try and use XMLHttpRequest (XHR) when possible. Note that LoadQueue will default to tag loading or XHR + * loading depending on the requirements for a media type. For example, HTML audio can not be loaded with XHR, + * and plain text can not be loaded with tags, so it will default the the correct type instead of using the + * user-defined type. + * @type {Boolean} + * @default true + * @since 0.6.0 + */ + this.preferXHR = true; //TODO: Get/Set + this._preferXHR = true; + this.setPreferXHR(preferXHR); + + // protected properties + /** + * Whether the queue is currently paused or not. + * @property _paused + * @type {boolean} + * @private + */ + this._paused = false; + + /** + * A path that will be prepended on to the item's {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. The + * `_basePath` property will only be used if an item's source is relative, and does not include a protocol such + * as `http://`, or a relative path such as `../`. + * @property _basePath + * @type {String} + * @private + * @since 0.3.1 + */ + this._basePath = basePath; + + /** + * An optional flag to set on images that are loaded using PreloadJS, which enables CORS support. Images loaded + * cross-domain by servers that support CORS require the crossOrigin flag to be loaded and interacted with by + * a canvas. When loading locally, or with a server with no CORS support, this flag can cause other security issues, + * so it is recommended to only set it if you are sure the server supports it. Currently, supported values are "" + * and "Anonymous". + * @property _crossOrigin + * @type {String} + * @default "" + * @private + * @since 0.4.1 + */ + this._crossOrigin = crossOrigin; + + /** + * Determines if the loadStart event was dispatched already. This event is only fired one time, when the first + * file is requested. + * @property _loadStartWasDispatched + * @type {Boolean} + * @default false + * @private + */ + this._loadStartWasDispatched = false; + + /** + * Determines if there is currently a script loading. This helps ensure that only a single script loads at once when + * using a script tag to do preloading. + * @property _currentlyLoadingScript + * @type {Boolean} + * @private + */ + this._currentlyLoadingScript = null; + + /** + * An array containing the currently downloading files. + * @property _currentLoads + * @type {Array} + * @private + */ + this._currentLoads = []; + + /** + * An array containing the queued items that have not yet started downloading. + * @property _loadQueue + * @type {Array} + * @private + */ + this._loadQueue = []; + + /** + * An array containing downloads that have not completed, so that the LoadQueue can be properly reset. + * @property _loadQueueBackup + * @type {Array} + * @private + */ + this._loadQueueBackup = []; + + /** + * An object hash of items that have finished downloading, indexed by the {{#crossLink "LoadItem"}}{{/crossLink}} + * id. + * @property _loadItemsById + * @type {Object} + * @private + */ + this._loadItemsById = {}; + + /** + * An object hash of items that have finished downloading, indexed by {{#crossLink "LoadItem"}}{{/crossLink}} + * source. + * @property _loadItemsBySrc + * @type {Object} + * @private + */ + this._loadItemsBySrc = {}; + + /** + * An object hash of loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. + * @property _loadedResults + * @type {Object} + * @private + */ + this._loadedResults = {}; + + /** + * An object hash of un-parsed loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. + * @property _loadedRawResults + * @type {Object} + * @private + */ + this._loadedRawResults = {}; + + /** + * The number of items that have been requested. This helps manage an overall progress without knowing how large + * the files are before they are downloaded. This does not include items inside of loaders such as the + * {{#crossLink "ManifestLoader"}}{{/crossLink}}. + * @property _numItems + * @type {Number} + * @default 0 + * @private + */ + this._numItems = 0; + + /** + * The number of items that have completed loaded. This helps manage an overall progress without knowing how large + * the files are before they are downloaded. + * @property _numItemsLoaded + * @type {Number} + * @default 0 + * @private + */ + this._numItemsLoaded = 0; + + /** + * A list of scripts in the order they were requested. This helps ensure that scripts are "completed" in the right + * order. + * @property _scriptOrder + * @type {Array} + * @private + */ + this._scriptOrder = []; + + /** + * A list of scripts that have been loaded. Items are added to this list as null when they are + * requested, contain the loaded item if it has completed, but not been dispatched to the user, and true + * once they are complete and have been dispatched. + * @property _loadedScripts + * @type {Array} + * @private + */ + this._loadedScripts = []; + + /** + * The last progress amount. This is used to suppress duplicate progress events. + * @property _lastProgress + * @type {Number} + * @private + * @since 0.6.0 + */ + this._lastProgress = NaN; + +}; + +// static properties +/** + * The time in milliseconds to assume a load has failed. An {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} + * event is dispatched if the timeout is reached before any data is received. + * @property loadTimeout + * @type {Number} + * @default 8000 + * @static + * @since 0.4.1 + * @deprecated In favour of {{#crossLink "LoadItem/LOAD_TIMEOUT_DEFAULT:property}}{{/crossLink}} property. + */ +s.loadTimeout = 8000; + +/** + * The time in milliseconds to assume a load has failed. + * @property LOAD_TIMEOUT + * @type {Number} + * @default 0 + * @deprecated in favor of the {{#crossLink "LoadQueue/loadTimeout:property"}}{{/crossLink}} property. + */ +s.LOAD_TIMEOUT = 0; + +// Preload Types +/** + * @property BINARY + * @type {String} + * @default binary + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}} instead. + */ +s.BINARY = AbstractLoader.BINARY; + +/** + * @property CSS + * @type {String} + * @default css + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. + */ +s.CSS = AbstractLoader.CSS; + +/** + * @property IMAGE + * @type {String} + * @default image + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. + */ +s.IMAGE = AbstractLoader.IMAGE; + +/** + * @property JAVASCRIPT + * @type {String} + * @default javascript + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ +s.JAVASCRIPT = AbstractLoader.JAVASCRIPT; + +/** + * @property JSON + * @type {String} + * @default json + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}} instead. + */ +s.JSON = AbstractLoader.JSON; + +/** + * @property JSONP + * @type {String} + * @default jsonp + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}} instead. + */ +s.JSONP = AbstractLoader.JSONP; + +/** + * @property MANIFEST + * @type {String} + * @default manifest + * @static + * @since 0.4.1 + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}} instead. + */ +s.MANIFEST = AbstractLoader.MANIFEST; + +/** + * @property SOUND + * @type {String} + * @default sound + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ +s.SOUND = AbstractLoader.SOUND; + +/** + * @property VIDEO + * @type {String} + * @default video + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ +s.VIDEO = AbstractLoader.VIDEO; + +/** + * @property SVG + * @type {String} + * @default svg + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}} instead. + */ +s.SVG = AbstractLoader.SVG; + +/** + * @property TEXT + * @type {String} + * @default text + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}} instead. + */ +s.TEXT = AbstractLoader.TEXT; + +/** + * @property XML + * @type {String} + * @default xml + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}} instead. + */ +s.XML = AbstractLoader.XML; + +/** + * @property POST + * @type {string} + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} instead. + */ +s.POST = AbstractLoader.POST; + +/** + * @property GET + * @type {string} + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} instead. + */ +s.GET = AbstractLoader.GET; + +// events +/** + * This event is fired when an individual file has loaded, and been processed. + * @event fileload + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a `src` property. + * @param {Object} result The HTML tag or parsed result of the loaded item. + * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted + * to a usable object. + * @since 0.3.0 + */ + +/** + * This {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when an an individual file's progress changes. + * @event fileprogress + * @since 0.3.0 + */ + +/** + * This event is fired when an individual file starts to load. + * @event filestart + * @param {Object} The object that dispatched the event. + * @param {String} type The event type. + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a property. + */ + +/** + * Although it extends {{#crossLink "AbstractLoader"}}{{/crossLink}}, the `initialize` event is never fired from + * a LoadQueue instance. + * @event initialize + * @private + */ + +// public methods +/** + * Register a custom loaders class. New loaders are given precedence over loaders added earlier and default loaders. + * It is recommended that loaders extend {{#crossLink "AbstractLoader"}}{{/crossLink}}. Loaders can only be added + * once, and will be prepended to the list of available loaders. + * @method registerLoader + * @param {Function|AbstractLoader} loader The AbstractLoader class to add. + * @since 0.6.0 + */ +p.registerLoader = function (loader) { + if (!loader || !loader.canLoadItem) { + throw new Error("loader is of an incorrect type."); + } else if (this._availableLoaders.indexOf(loader) != -1) { + throw new Error("loader already exists."); //LM: Maybe just silently fail here + } + + this._availableLoaders.unshift(loader); +}; + +/** + * Remove a custom loader added using {{#crossLink "registerLoader"}}{{/crossLink}}. Only custom loaders can be + * unregistered, the default loaders will always be available. + * @method unregisterLoader + * @param {Function|AbstractLoader} loader The AbstractLoader class to remove + */ +p.unregisterLoader = function (loader) { + var idx = this._availableLoaders.indexOf(loader); + if (idx != -1 && idx < this._defaultLoaderLength - 1) { + this._availableLoaders.splice(idx, 1); + } +}; + +/** + * @method setUseXHR + * @param {Boolean} value The new useXHR value to set. + * @return {Boolean} The new useXHR value. If XHR is not supported by the browser, this will return false, even if + * the provided value argument was true. + * @since 0.3.0 + * @deprecated use the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property, or the + * {{#crossLink "LoadQueue/setUseXHR"}}{{/crossLink}} method instead. + */ +p.setUseXHR = function (value) { + return this.setPreferXHR(value); +}; + +/** + * Change the {{#crossLink "preferXHR:property"}}{{/crossLink}} value. Note that if this is set to `true`, it may + * fail, or be ignored depending on the browser's capabilities and the load type. + * @method setPreferXHR + * @param {Boolean} value + * @returns {Boolean} The value of {{#crossLink "preferXHR"}}{{/crossLink}} that was successfully set. + * @since 0.6.0 + */ +p.setPreferXHR = function (value) { + // Determine if we can use XHR. XHR defaults to TRUE, but the browser may not support it. + //TODO: Should we be checking for the other XHR types? Might have to do a try/catch on the different types similar to createXHR. + this.preferXHR = (value != false && window.XMLHttpRequest != null); + return this.preferXHR; +}; + +/** + * Stops all queued and loading items, and clears the queue. This also removes all internal references to loaded + * content, and allows the queue to be used again. + * @method removeAll + * @since 0.3.0 + */ +p.removeAll = function () { + this.remove(); +}; + +/** + * Stops an item from being loaded, and removes it from the queue. If nothing is passed, all items are removed. + * This also removes internal references to loaded item(s). + * + *

Example

+ * + * queue.loadManifest([ + * {src:"test.png", id:"png"}, + * {src:"test.jpg", id:"jpg"}, + * {src:"test.mp3", id:"mp3"} + * ]); + * queue.remove("png"); // Single item by ID + * queue.remove("png", "test.jpg"); // Items as arguments. Mixed id and src. + * queue.remove(["test.png", "jpg"]); // Items in an Array. Mixed id and src. + * + * @method remove + * @param {String | Array} idsOrUrls* The id or ids to remove from this queue. You can pass an item, an array of + * items, or multiple items as arguments. + * @since 0.3.0 + */ +p.remove = function (idsOrUrls) { + var args = null; + + if (idsOrUrls && !Array.isArray(idsOrUrls)) { + args = [idsOrUrls]; + } else if (idsOrUrls) { + args = idsOrUrls; + } else if (arguments.length > 0) { + return; + } + + var itemsWereRemoved = false; + + // Destroy everything + if (!args) { + this.close(); + for (var n in this._loadItemsById) { + this._disposeItem(this._loadItemsById[n]); + } + this.init(this.preferXHR, this._basePath); + + // Remove specific items + } else { + while (args.length) { + var item = args.pop(); + var r = this.getResult(item); + + //Remove from the main load Queue + for (i = this._loadQueue.length - 1; i >= 0; i--) { + loadItem = this._loadQueue[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._loadQueue.splice(i, 1)[0].cancel(); + break; + } + } + + //Remove from the backup queue + for (i = this._loadQueueBackup.length - 1; i >= 0; i--) { + loadItem = this._loadQueueBackup[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._loadQueueBackup.splice(i, 1)[0].cancel(); + break; + } + } + + if (r) { + this._disposeItem(this.getItem(item)); + } else { + for (var i = this._currentLoads.length - 1; i >= 0; i--) { + var loadItem = this._currentLoads[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._currentLoads.splice(i, 1)[0].cancel(); + itemsWereRemoved = true; + break; + } + } + } + } + + // If this was called during a load, try to load the next item. + if (itemsWereRemoved) { + this._loadNext(); + } + } +}; + +/** + * Stops all open loads, destroys any loaded items, and resets the queue, so all items can + * be reloaded again by calling {{#crossLink "AbstractLoader/load"}}{{/crossLink}}. Items are not removed from the + * queue. To remove items use the {{#crossLink "LoadQueue/remove"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/removeAll"}}{{/crossLink}} method. + * @method reset + * @since 0.3.0 + */ +p.reset = function () { + this.close(); + for (var n in this._loadItemsById) { + this._disposeItem(this._loadItemsById[n]); + } + + //Reset the queue to its start state + var a = []; + for (var i = 0, l = this._loadQueueBackup.length; i < l; i++) { + a.push(this._loadQueueBackup[i].getItem()); + } + + this.loadManifest(a, false); +}; + +/** + * Register a plugin. Plugins can map to load types (sound, image, etc), or specific extensions (png, mp3, etc). + * Currently, only one plugin can exist per type/extension. + * + * When a plugin is installed, a getPreloadHandlers() method will be called on it. For more information + * on this method, check out the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method in the + * {{#crossLink "SamplePlugin"}}{{/crossLink}} class. + * + * Before a file is loaded, a matching plugin has an opportunity to modify the load. If a `callback` is returned + * from the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method, it will be invoked first, and its + * result may cancel or modify the item. The callback method can also return a `completeHandler` to be fired when + * the file is loaded, or a `tag` object, which will manage the actual download. For more information on these + * methods, check out the {{#crossLink "SamplePlugin/preloadHandler"}}{{/crossLink}} and {{#crossLink "SamplePlugin/fileLoadHandler"}}{{/crossLink}} + * methods on the {{#crossLink "SamplePlugin"}}{{/crossLink}}. + * + * @method installPlugin + * @param {Function} plugin The plugin class to install. + */ +p.installPlugin = function (plugin) { + if (plugin == null) { + return; + } + + if (plugin.getPreloadHandlers != null) { + this._plugins.push(plugin); + var map = plugin.getPreloadHandlers(); + map.scope = plugin; + + if (map.types != null) { + for (var i = 0, l = map.types.length; i < l; i++) { + this._typeCallbacks[map.types[i]] = map; + } + } + + if (map.extensions != null) { + for (i = 0, l = map.extensions.length; i < l; i++) { + this._extensionCallbacks[map.extensions[i]] = map; + } + } + } +}; + +/** + * Set the maximum number of concurrent connections. Note that browsers and servers may have a built-in maximum + * number of open connections, so any additional connections may remain in a pending state until the browser + * opens the connection. When loading scripts using tags, and when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} + * is `true`, only one script is loaded at a time due to browser limitations. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.setMaxConnections(10); // Allow 10 concurrent loads + * + * @method setMaxConnections + * @param {Number} value The number of concurrent loads to allow. By default, only a single connection per LoadQueue + * is open at any time. + */ +p.setMaxConnections = function (value) { + this._maxConnections = value; + if (!this._paused && this._loadQueue.length > 0) { + this._loadNext(); + } +}; + +/** + * Load a single file. To add multiple files at once, use the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * method. + * + * Files are always appended to the current queue, so this method can be used multiple times to add files. + * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. + * @method loadFile + * @param {LoadItem|Object|String} file The file object or path to load. A file can be either + *
    + *
  • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
  • + *
  • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
  • + *
  • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} + * in the background.
  • + *
+ * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default + * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}}, and the value is + * `true`, the queue will resume automatically. + * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the + * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}, + * its files will NOT use the basePath parameter. The basePath parameter is deprecated. + * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue + * constructor, or a `path` property in a manifest definition. + */ +p.loadFile = function (file, loadNow, basePath) { + if (file == null) { + var event = new ErrorEvent("PRELOAD_NO_FILE"); + this._sendError(event); + return; + } + this._addItem(file, null, basePath); + + if (loadNow !== false) { + this.setPaused(false); + } else { + this.setPaused(true); + } +}; + +/** + * Load an array of files. To load a single file, use the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} method. + * The files in the manifest are requested in the same order, but may complete in a different order if the max + * connections are set above 1 using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Scripts will load + * in the right order as long as {{#crossLink "LoadQueue/maintainScriptOrder"}}{{/crossLink}} is true (which is + * default). + * + * Files are always appended to the current queue, so this method can be used multiple times to add files. + * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. + * @method loadManifest + * @param {Array|String|Object} manifest An list of files to load. The loadManifest call supports four types of + * manifests: + *
    + *
  1. A string path, which points to a manifest file, which is a JSON file that contains a "manifest" property, + * which defines the list of files to load, and can optionally contain a "path" property, which will be + * prepended to each file in the list.
  2. + *
  3. An object which defines a "src", which is a JSON or JSONP file. A "callback" can be defined for JSONP + * file. The JSON/JSONP file should contain a "manifest" property, which defines the list of files to load, + * and can optionally contain a "path" property, which will be prepended to each file in the list.
  4. + *
  5. An object which contains a "manifest" property, which defines the list of files to load, and can + * optionally contain a "path" property, which will be prepended to each file in the list.
  6. + *
  7. An Array of files to load.
  8. + *
+ * + * Each "file" in a manifest can be either: + *
    + *
  • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
  • + *
  • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
  • + *
  • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} + * in the background.
  • + *
+ * + * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default + * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} and this value is + * `true`, the queue will resume automatically. + * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the + * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "LoadQueue/MANIFEST:property"}}{{/crossLink}}, + * its files will NOT use the basePath parameter. The basePath parameter is deprecated. + * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue + * constructor, or a `path` property in a manifest definition. + */ +p.loadManifest = function (manifest, loadNow, basePath) { + var fileList = null; + var path = null; + + // Array-based list of items + if (Array.isArray(manifest)) { + if (manifest.length == 0) { + var event = new ErrorEvent("PRELOAD_MANIFEST_EMPTY"); + this._sendError(event); + return; + } + fileList = manifest; + + // String-based. Only file manifests can be specified this way. Any other types will cause an error when loaded. + } else if (typeof(manifest) === "string") { + fileList = [ + { + src: manifest, + type: s.MANIFEST + } + ]; + + } else if (typeof(manifest) == "object") { + + // An object that defines a manifest path + if (manifest.src !== undefined) { + if (manifest.type == null) { + manifest.type = s.MANIFEST; + } else if (manifest.type != s.MANIFEST) { + var event = new ErrorEvent("PRELOAD_MANIFEST_TYPE"); + this._sendError(event); + } + fileList = [manifest]; + + // An object that defines a manifest + } else if (manifest.manifest !== undefined) { + fileList = manifest.manifest; + path = manifest.path; + } + + // Unsupported. This will throw an error. + } else { + var event = new ErrorEvent("PRELOAD_MANIFEST_NULL"); + this._sendError(event); + return; + } + + for (var i = 0, l = fileList.length; i < l; i++) { + this._addItem(fileList[i], path, basePath); + } + + if (loadNow !== false) { + this.setPaused(false); + } else { + this.setPaused(true); + } + +}; + +/** + * Start a LoadQueue that was created, but not automatically started. + * @method load + */ +p.load = function () { + this.setPaused(false); +}; + +/** + * Look up a {{#crossLink "LoadItem"}}{{/crossLink}} using either the "id" or "src" that was specified when loading it. Note that if no "id" was + * supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The + * `basePath` will not be part of the ID. + * @method getItem + * @param {String} value The id or src of the load item. + * @return {Object} The load item that was initially requested using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} + * event as the `item` parameter. + */ +p.getItem = function (value) { + return this._loadItemsById[value] || this._loadItemsBySrc[value]; +}; + +/** + * Look up a loaded result using either the "id" or "src" that was specified when loading it. Note that if no "id" + * was supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The + * `basePath` will not be part of the ID. + * @method getResult + * @param {String} value The id or src of the load item. + * @param {Boolean} [rawResult=false] Return a raw result instead of a formatted result. This applies to content + * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be + * returned instead. + * @return {Object} A result object containing the content that was loaded, such as: + *
    + *
  • An image tag (<image />) for images
  • + *
  • A script tag for JavaScript (<script />). Note that scripts are automatically added to the HTML + * DOM.
  • + *
  • A style tag for CSS (<style /> or <link >)
  • + *
  • Raw text for TEXT
  • + *
  • A formatted JavaScript object defined by JSON
  • + *
  • An XML document
  • + *
  • A binary arraybuffer loaded by XHR
  • + *
  • An audio tag (<audio >) for HTML audio. Note that it is recommended to use SoundJS APIs to play + * loaded audio. Specifically, audio loaded by Flash and WebAudio will return a loader object using this method + * which can not be used to play audio back.
  • + *
+ * This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event as the 'item` + * parameter. Note that if a raw result is requested, but not found, the result will be returned instead. + */ +p.getResult = function (value, rawResult) { + var item = this._loadItemsById[value] || this._loadItemsBySrc[value]; + if (item == null) { + return null; + } + var id = item.id; + if (rawResult && this._loadedRawResults[id]) { + return this._loadedRawResults[id]; + } + return this._loadedResults[id]; +}; + +/** + * Generate an list of items loaded by this queue. + * @method getItems + * @param {Boolean} loaded Determines if only items that have been loaded should be returned. If false, in-progress + * and failed load items will also be included. + * @returns {Array} A list of objects that have been loaded. Each item includes the {{#crossLink "LoadItem"}}{{/crossLink}}, + * result, and rawResult. + * @since 0.6.0 + */ +p.getItems = function (loaded) { + var arr = []; + for (var n in this._loadItemsById) { + var item = this._loadItemsById[n]; + var result = this.getResult(n); + if (loaded === true && result == null) { + continue; + } + arr.push({ + item: item, + result: result, + rawResult: this.getResult(n, true) + }); + } + return arr; +}; + +/** + * Pause or resume the current load. Active loads will not be cancelled, but the next items in the queue will not + * be processed when active loads complete. LoadQueues are not paused by default. + * + * Note that if new items are added to the queue using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}, a paused queue will be resumed, unless the `loadNow` + * argument is `false`. + * @method setPaused + * @param {Boolean} value Whether the queue should be paused or not. + */ +p.setPaused = function (value) { + this._paused = value; + if (!this._paused) { + this._loadNext(); + } +}; + +/** + * Close the active queue. Closing a queue completely empties the queue, and prevents any remaining items from + * starting to download. Note that currently any active loads will remain open, and events may be processed. + * + * To stop and restart a queue, use the {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} method instead. + * @method close + */ +p.close = function () { + while (this._currentLoads.length) { + this._currentLoads.pop().cancel(); + } + this._scriptOrder.length = 0; + this._loadedScripts.length = 0; + this.loadStartWasDispatched = false; + this._itemCount = 0; + this._lastProgress = NaN; +}; + +// protected methods +/** + * Add an item to the queue. Items are formatted into a usable object containing all the properties necessary to + * load the content. The load queue is populated with the loader instance that handles preloading, and not the load + * item that was passed in by the user. To look up the load item by id or src, use the {{#crossLink "LoadQueue.getItem"}}{{/crossLink}} + * method. + * @method _addItem + * @param {String|Object} value The item to add to the queue. + * @param {String} [path] An optional path prepended to the `src`. The path will only be prepended if the src is + * relative, and does not start with a protocol such as `http://`, or a path like `../`. If the LoadQueue was + * provided a {{#crossLink "_basePath"}}{{/crossLink}}, then it will optionally be prepended after. + * @param {String} [basePath] DeprecatedAn optional basePath passed into a {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} call. This parameter will be removed in a future tagged + * version. + * @private + */ +p._addItem = function (value, path, basePath) { + var item = this._createLoadItem(value, path, basePath); // basePath and manifest path are added to the src. + if (item == null) { + return; + } // Sometimes plugins or types should be skipped. + var loader = this._createLoader(item); + if (loader != null) { + if ("plugins" in loader) { + loader.plugins = this._plugins; + } + item._loader = loader; + this._loadQueue.push(loader); + this._loadQueueBackup.push(loader); + + this._numItems++; + this._updateProgress(); + + // Only worry about script order when using XHR to load scripts. Tags are only loading one at a time. + if ((this.maintainScriptOrder + && item.type == LoadQueue.JAVASCRIPT + //&& loader instanceof createjs.XHRLoader //NOTE: Have to track all JS files this way + ) + || item.maintainOrder === true) { + this._scriptOrder.push(item); + this._loadedScripts.push(null); + } + } +}; + +/** + * Create a refined {{#crossLink "LoadItem"}}{{/crossLink}}, which contains all the required properties. The type of + * item is determined by browser support, requirements based on the file type, and developer settings. For example, + * XHR is only used for file types that support it in new browsers. + * + * Before the item is returned, any plugins registered to handle the type or extension will be fired, which may + * alter the load item. + * @method _createLoadItem + * @param {String | Object | HTMLAudioElement | HTMLImageElement} value The item that needs to be preloaded. + * @param {String} [path] A path to prepend to the item's source. Sources beginning with http:// or similar will + * not receive a path. Since PreloadJS 0.4.1, the src will be modified to include the `path` and {{#crossLink "LoadQueue/_basePath:property"}}{{/crossLink}} + * when it is added. + * @param {String} [basePath] Deprectated A base path to prepend to the items source in addition to + * the path argument. + * @return {Object} The loader instance that will be used. + * @private + */ +p._createLoadItem = function (value, path, basePath) { + var item = LoadItem.create(value); + if (item == null) { + return null; + } + + var bp = ""; // Store the generated basePath + var useBasePath = basePath || this._basePath; + + if (item.src instanceof Object) { + if (!item.type) { + return null; + } // the the src is an object, type is required to pass off to plugin + if (path) { + bp = path; + var pathMatch = RequestUtils.parseURI(path); + // Also append basePath + if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { + bp = useBasePath + bp; + } + } else if (useBasePath != null) { + bp = useBasePath; + } + } else { + // Determine Extension, etc. + var match = RequestUtils.parseURI(item.src); + if (match.extension) { + item.ext = match.extension; + } + if (item.type == null) { + item.type = RequestUtils.getTypeByExtension(item.ext); + } + + // Inject path & basePath + var autoId = item.src; + if (!match.absolute && !match.relative) { + if (path) { + bp = path; + var pathMatch = RequestUtils.parseURI(path); + autoId = path + autoId; + // Also append basePath + if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { + bp = useBasePath + bp; + } + } else if (useBasePath != null) { + bp = useBasePath; + } + } + item.src = bp + item.src; + } + item.path = bp; + + // If there's no id, set one now. + if (item.id === undefined || item.id === null || item.id === "") { + item.id = autoId; + } + + // Give plugins a chance to modify the loadItem: + var customHandler = this._typeCallbacks[item.type] || this._extensionCallbacks[item.ext]; + if (customHandler) { + // Plugins are now passed both the full source, as well as a combined path+basePath (appropriately) + var result = customHandler.callback.call(customHandler.scope, item, this); + + // The plugin will handle the load, or has canceled it. Ignore it. + if (result === false) { + return null; + + // Load as normal: + } else if (result === true) { + // Do Nothing + + // Result is a loader class: + } else if (result != null) { + item._loader = result; + } + + // Update the extension in case the type changed: + match = RequestUtils.parseURI(item.src); + if (match.extension != null) { + item.ext = match.extension; + } + } + + // Store the item for lookup. This also helps clean-up later. + this._loadItemsById[item.id] = item; + this._loadItemsBySrc[item.src] = item; + + if (item.crossOrigin == null) { + item.crossOrigin = this._crossOrigin; + } + + return item; +}; + +/** + * Create a loader for a load item. + * @method _createLoader + * @param {Object} item A formatted load item that can be used to generate a loader. + * @return {AbstractLoader} A loader that can be used to load content. + * @private + */ +p._createLoader = function (item) { + if (item._loader != null) { // A plugin already specified a loader + return item._loader; + } + + // Initially, try and use the provided/supported XHR mode: + var preferXHR = this.preferXHR; + + for (var i = 0; i < this._availableLoaders.length; i++) { + var loader = this._availableLoaders[i]; + if (loader && loader.canLoadItem(item)) { + return new loader(item, preferXHR); + } + } + + // TODO: Log error (requires createjs.log) + return null; +}; + +/** + * Load the next item in the queue. If the queue is empty (all items have been loaded), then the complete event + * is processed. The queue will "fill up" any empty slots, up to the max connection specified using + * {{#crossLink "LoadQueue.setMaxConnections"}}{{/crossLink}} method. The only exception is scripts that are loaded + * using tags, which have to be loaded one at a time to maintain load order. + * @method _loadNext + * @private + */ +p._loadNext = function () { + if (this._paused) { + return; + } + + // Only dispatch loadstart event when the first file is loaded. + if (!this._loadStartWasDispatched) { + this._sendLoadStart(); + this._loadStartWasDispatched = true; + } + + // The queue has completed. + if (this._numItems == this._numItemsLoaded) { + this.loaded = true; + this._sendComplete(); + + // Load the next queue, if it has been defined. + if (this.next && this.next.load) { + this.next.load(); + } + } else { + this.loaded = false; + } + + // Must iterate forwards to load in the right order. + for (var i = 0; i < this._loadQueue.length; i++) { + if (this._currentLoads.length >= this._maxConnections) { + break; + } + var loader = this._loadQueue[i]; + + // Determine if we should be only loading one tag-script at a time: + // Note: maintainOrder items don't do anything here because we can hold onto their loaded value + if (!this._canStartLoad(loader)) { + continue; + } + this._loadQueue.splice(i, 1); + i--; + this._loadItem(loader); + } +}; + +/** + * Begin loading an item. Event listeners are not added to the loaders until the load starts. + * @method _loadItem + * @param {AbstractLoader} loader The loader instance to start. Currently, this will be an XHRLoader or TagLoader. + * @private + */ +p._loadItem = function (loader) { + loader.on("fileload", this._handleFileLoad, this); + loader.on("progress", this._handleProgress, this); + loader.on("complete", this._handleFileComplete, this); + loader.on("error", this._handleError, this); + loader.on("fileerror", this._handleFileError, this); + this._currentLoads.push(loader); + this._sendFileStart(loader.getItem()); + loader.load(); +}; + +/** + * The callback that is fired when a loader loads a file. This enables loaders like {{#crossLink "ManifestLoader"}}{{/crossLink}} + * to maintain internal queues, but for this queue to dispatch the {{#crossLink "fileload:event"}}{{/crossLink}} + * events. + * @param {Event} event The {{#crossLink "AbstractLoader/fileload:event"}}{{/crossLink}} event from the loader. + * @private + * @since 0.6.0 + */ +p._handleFileLoad = function (event) { + event.target = null; + this.dispatchEvent(event); +}; + +/** + * The callback that is fired when a loader encounters an error from an internal file load operation. This enables + * loaders like M + * @param event + * @private + */ +p._handleFileError = function (event) { + var newEvent = new ErrorEvent("FILE_LOAD_ERROR", null, event.item); + this._sendError(newEvent); +}; + +/** + * The callback that is fired when a loader encounters an error. The queue will continue loading unless {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} + * is set to `true`. + * @method _handleError + * @param {ErrorEvent} event The error event, containing relevant error information. + * @private + */ +p._handleError = function (event) { + var loader = event.target; + this._numItemsLoaded++; + + this._finishOrderedItem(loader, true); + this._updateProgress(); + + var newEvent = new ErrorEvent("FILE_LOAD_ERROR", null, loader.getItem()); + // TODO: Propagate actual error message. + + this._sendError(newEvent); + + if (!this.stopOnError) { + this._removeLoadItem(loader); + this._cleanLoadItem(loader); + this._loadNext(); + } else { + this.setPaused(true); + } +}; + +/** + * An item has finished loading. We can assume that it is totally loaded, has been parsed for immediate use, and + * is available as the "result" property on the load item. The raw text result for a parsed item (such as JSON, XML, + * CSS, JavaScript, etc) is available as the "rawResult" property, and can also be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. + * @method _handleFileComplete + * @param {Event} event The event object from the loader. + * @private + */ +p._handleFileComplete = function (event) { + var loader = event.target; + var item = loader.getItem(); + + var result = loader.getResult(); + this._loadedResults[item.id] = result; + var rawResult = loader.getResult(true); + if (rawResult != null && rawResult !== result) { + this._loadedRawResults[item.id] = rawResult; + } + + this._saveLoadedItems(loader); + + // Remove the load item + this._removeLoadItem(loader); + + if (!this._finishOrderedItem(loader)) { + // The item was NOT managed, so process it now + this._processFinishedLoad(item, loader); + } + + // Clean up the load item + this._cleanLoadItem(loader); +}; + +/** + * Some loaders might load additional content, other than the item they were passed (such as {{#crossLink "ManifestLoader"}}{{/crossLink}}). + * Any items exposed by the loader using {{#crossLink "AbstractLoader/getLoadItems"}}{{/crossLink}} are added to the + * LoadQueue's look-ups, including {{#crossLink "getItem"}}{{/crossLink}} and {{#crossLink "getResult"}}{{/crossLink}} + * methods. + * @method _saveLoadedItems + * @param {AbstractLoader} loader + * @protected + * @since 0.6.0 + */ +p._saveLoadedItems = function (loader) { + // TODO: Not sure how to handle this. Would be nice to expose the items. + // Loaders may load sub-items. This adds them to this queue + var list = loader.getLoadedItems(); + if (list === null) { + return; + } + + for (var i = 0; i < list.length; i++) { + var item = list[i].item; + + // Store item lookups + this._loadItemsBySrc[item.src] = item; + this._loadItemsById[item.id] = item; + + // Store loaded content + this._loadedResults[item.id] = list[i].result; + this._loadedRawResults[item.id] = list[i].rawResult; + } +}; + +/** + * Flag an item as finished. If the item's order is being managed, then ensure that it is allowed to finish, and if + * so, trigger prior items to trigger as well. + * @method _finishOrderedItem + * @param {AbstractLoader} loader + * @param {Boolean} loadFailed + * @return {Boolean} If the item's order is being managed. This allows the caller to take an alternate + * behaviour if it is. + * @private + */ +p._finishOrderedItem = function (loader, loadFailed) { + var item = loader.getItem(); + + if ((this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) + || item.maintainOrder) { + + //TODO: Evaluate removal of the _currentlyLoadingScript + if (loader instanceof createjs.JavaScriptLoader) { + this._currentlyLoadingScript = false; + } + + var index = createjs.indexOf(this._scriptOrder, item); + if (index == -1) { + return false; + } // This loader no longer exists + this._loadedScripts[index] = (loadFailed === true) ? true : item; + + this._checkScriptLoadOrder(); + return true; + } + + return false; +}; + +/** + * Ensure the scripts load and dispatch in the correct order. When using XHR, scripts are stored in an array in the + * order they were added, but with a "null" value. When they are completed, the value is set to the load item, + * and then when they are processed and dispatched, the value is set to `true`. This method simply + * iterates the array, and ensures that any loaded items that are not preceded by a `null` value are + * dispatched. + * @method _checkScriptLoadOrder + * @private + */ +p._checkScriptLoadOrder = function () { + var l = this._loadedScripts.length; + + for (var i = 0; i < l; i++) { + var item = this._loadedScripts[i]; + if (item === null) { + break; + } // This is still loading. Do not process further. + if (item === true) { + continue; + } // This has completed, and been processed. Move on. + + var loadItem = this._loadedResults[item.id]; + if (item.type == createjs.LoadQueue.JAVASCRIPT) { + // Append script tags to the head automatically. + createjs.DomUtils.appendToHead(loadItem); + } + + var loader = item._loader; + this._processFinishedLoad(item, loader); + this._loadedScripts[i] = true; + } +}; + +/** + * A file has completed loading, and the LoadQueue can move on. This triggers the complete event, and kick-starts + * the next item. + * @method _processFinishedLoad + * @param {LoadItem|Object} item + * @param {AbstractLoader} loader + * @protected + */ +p._processFinishedLoad = function (item, loader) { + this._numItemsLoaded++; + + // Since LoadQueue needs maintain order, we can't append scripts in the loader. + // So we do it here instead. Or in _checkScriptLoadOrder(); + if (!this.maintainScriptOrder && item.type == LoadQueue.JAVASCRIPT) { + var tag = loader.getTag(); + createjs.DomUtils.appendToHead(tag); + } + + this._updateProgress(); + this._sendFileComplete(item, loader); + this._loadNext(); +}; + +/** + * Ensure items with `maintainOrder=true` that are before the specified item have loaded. This only applies to + * JavaScript items that are being loaded with a TagLoader, since they have to be loaded and completed before + * the script can even be started, since it exist in the DOM while loading. + * @method _canStartLoad + * @param {AbstractLoader} loader The loader for the item + * @return {Boolean} Whether the item can start a load or not. + * @private + */ +p._canStartLoad = function (loader) { + if (!this.maintainScriptOrder || loader.preferXHR) { + return true; + } + var item = loader.getItem(); + if (item.type != LoadQueue.JAVASCRIPT) { + return true; + } + if (this._currentlyLoadingScript) { + return false; + } + + var index = this._scriptOrder.indexOf(item); + var i = 0; + while (i < index) { + var checkItem = this._loadedScripts[i]; + if (checkItem == null) { + return false; + } + i++; + } + this._currentlyLoadingScript = true; + return true; +}; + +/** + * A load item is completed or was canceled, and needs to be removed from the LoadQueue. + * @method _removeLoadItem + * @param {AbstractLoader} loader A loader instance to remove. + * @private + */ +p._removeLoadItem = function (loader) { + var l = this._currentLoads.length; + for (var i = 0; i < l; i++) { + if (this._currentLoads[i] == loader) { + this._currentLoads.splice(i, 1); + break; + } + } +}; + +/** + * Remove unneeded references from a loader. + * + * @param loader + * @private + */ +p._cleanLoadItem = function (loader) { + var item = loader.getItem(); + if (item) { + delete item._loader; + } +} + +/** + * An item has dispatched progress. Propagate that progress, and update the LoadQueue's overall progress. + * @method _handleProgress + * @param {ProgressEvent} event The progress event from the item. + * @private + */ +p._handleProgress = function (event) { + var loader = event.target; + this._sendFileProgress(loader.getItem(), loader.progress); + this._updateProgress(); +}; + +/** + * Overall progress has changed, so determine the new progress amount and dispatch it. This changes any time an + * item dispatches progress or completes. Note that since we don't always know the actual filesize of items before + * they are loaded. In this case, we define a "slot" for each item (1 item in 10 would get 10%), and then append + * loaded progress on top of the already-loaded items. + * + * For example, if 5/10 items have loaded, and item 6 is 20% loaded, the total progress would be: + *
    + *
  • 5/10 of the items in the queue (50%)
  • + *
  • plus 20% of item 6's slot (2%)
  • + *
  • equals 52%
  • + *
+ * @method _updateProgress + * @private + */ +p._updateProgress = function () { + var loaded = this._numItemsLoaded / this._numItems; // Fully Loaded Progress + var remaining = this._numItems - this._numItemsLoaded; + if (remaining > 0) { + var chunk = 0; + for (var i = 0, l = this._currentLoads.length; i < l; i++) { + chunk += this._currentLoads[i].progress; + } + loaded += (chunk / remaining) * (remaining / this._numItems); + } + + if (this._lastProgress != loaded) { + this._sendProgress(loaded); + this._lastProgress = loaded; + } +}; + +/** + * Clean out item results, to free them from memory. Mainly, the loaded item and results are cleared from internal + * hashes. + * @method _disposeItem + * @param {LoadItem|Object} item The item that was passed in for preloading. + * @private + */ +p._disposeItem = function (item) { + delete this._loadedResults[item.id]; + delete this._loadedRawResults[item.id]; + delete this._loadItemsById[item.id]; + delete this._loadItemsBySrc[item.src]; +}; + +/** + * Dispatch a "fileprogress" {{#crossLink "Event"}}{{/crossLink}}. Please see the LoadQueue {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendFileProgress + * @param {LoadItem|Object} item The item that is being loaded. + * @param {Number} progress The amount the item has been loaded (between 0 and 1). + * @protected + */ +p._sendFileProgress = function (item, progress) { + if (this._isCanceled() || this._paused) { + return; + } + if (!this.hasEventListener("fileprogress")) { + return; + } + + //LM: Rework ProgressEvent to support this? + var event = new Event("fileprogress"); + event.progress = progress; + event.loaded = progress; + event.total = 1; + event.item = item; + + this.dispatchEvent(event); +}; + +/** + * Dispatch a fileload {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event for + * details on the event payload. + * @method _sendFileComplete + * @param {LoadItemObject} item The item that is being loaded. + * @param {AbstractLoader} loader + * @protected + */ +p._sendFileComplete = function (item, loader) { + if (this._isCanceled() || this._paused) { + return; + } + + var event = new Event("fileload"); + event.loader = loader; + event.item = item; + event.result = this._loadedResults[item.id]; + event.rawResult = this._loadedRawResults[item.id]; + + // This calls a handler specified on the actual load item. Currently, the SoundJS plugin uses this. + if (item.completeHandler) { + item.completeHandler(event); + } + + this.hasEventListener("fileload") && this.dispatchEvent(event); +}; + +/** + * Dispatch a filestart {{#crossLink "Event"}}{{/crossLink}} immediately before a file starts to load. Please see + * the {{#crossLink "LoadQueue/filestart:event"}}{{/crossLink}} event for details on the event payload. + * @method _sendFileStart + * @param {LoadItem|Object} item The item that is being loaded. + * @protected + */ +p._sendFileStart = function (item) { + var event = new Event("filestart"); + event.item = item; + this.hasEventListener("filestart") && this.dispatchEvent(event); +}; + +p.toString = function () { + return "[PreloadJS LoadQueue]"; +}; + +var LoadQueue = promote(LoadQueue, "AbstractLoader"); + +module.exports = LoadQueue; +},{"../createjs/events/ErrorEvent":1,"../createjs/events/Event":2,"../createjs/utils/extend":4,"../createjs/utils/promote":5,"./data/LoadItem":8,"./loaders/AbstractLoader":10,"./loaders/ImageLoader":11,"./utils/RequestUtils":15}],8:[function(_dereq_,module,exports){ +/* + * LoadItem + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +// namespace: + +/** + * All loaders accept an item containing the properties defined in this class. If a raw object is passed instead, + * it will not be affected, but it must contain at least a {{#crossLink "src:property"}}{{/crossLink}} property. A + * string path or HTML tag is also acceptable, but it will be automatically converted to a LoadItem using the + * {{#crossLink "create"}}{{/crossLink}} method by {{#crossLink "AbstractLoader"}}{{/crossLink}} + * @class LoadItem + * @constructor + * @since 0.6.0 + */ +function LoadItem() { + /** + * The source of the file that is being loaded. This property is required. The source can either be a + * string (recommended), or an HTML tag. + * This can also be an object, but in that case it has to include a type and be handled by a plugin. + * @property src + * @type {String} + * @default null + */ + this.src = null; + + /** + * The type file that is being loaded. The type of the file is usually inferred by the extension, but can also + * be set manually. This is helpful in cases where a file does not have an extension. + * @property type + * @type {String} + * @default null + */ + this.type = null; + + /** + * A string identifier which can be used to reference the loaded object. If none is provided, this will be + * automatically set to the {{#crossLink "src:property"}}{{/crossLink}}. + * @property id + * @type {String} + * @default null + */ + this.id = null; + + /** + * Determines if a manifest will maintain the order of this item, in relation to other items in the manifest + * that have also set the `maintainOrder` property to `true`. This only applies when the max connections has + * been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}). Everything with this + * property set to `false` will finish as it is loaded. Ordered items are combined with script tags loading in + * order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} is set to `true`. + * @property maintainOrder + * @type {Boolean} + * @default false + */ + this.maintainOrder = false; + + /** + * A callback used by JSONP requests that defines what global method to call when the JSONP content is loaded. + * @property callback + * @type {String} + * @default null + */ + this.callback = null; + + /** + * An arbitrary data object, which is included with the loaded object. + * @property data + * @type {Object} + * @default null + */ + this.data = null; + + /** + * The request method used for HTTP calls. Both {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} or + * {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} request types are supported, and are defined as + * constants on {{#crossLink "AbstractLoader"}}{{/crossLink}}. + * @property method + * @type {String} + * @default get + */ + this.method = LoadItem.GET; + + /** + * An object hash of name/value pairs to send to the server. + * @property values + * @type {Object} + * @default null + */ + this.values = null; + + /** + * An object hash of headers to attach to an XHR request. PreloadJS will automatically attach some default + * headers when required, including "Origin", "Content-Type", and "X-Requested-With". You may override the + * default headers by including them in your headers object. + * @property headers + * @type {Object} + * @default null + */ + this.headers = null; + + /** + * Enable credentials for XHR requests. + * @property withCredentials + * @type {Boolean} + * @default false + */ + this.withCredentials = false; + + /** + * Set the mime type of XHR-based requests. This is automatically set to "text/plain; charset=utf-8" for text + * based files (json, xml, text, css, js). + * @property mimeType + * @type {String} + * @default null + */ + this.mimeType = null; + + /** + * Sets the crossOrigin attribute for CORS-enabled images loading cross-domain. + * @property crossOrigin + * @type {boolean} + * @default Anonymous + */ + this.crossOrigin = null; + + /** + * The duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR + * (level one) loading, as XHR (level 2) provides its own timeout event. + * @property loadTimeout + * @type {Number} + * @default 8000 (8 seconds) + */ + this.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; +}; + +var p = LoadItem.prototype = {}; +var s = LoadItem; + +/** + * Default duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR + * (level one) loading, as XHR (level 2) provides its own timeout event. + * @property LOAD_TIMEOUT_DEFAULT + * @type {number} + * @static + */ +s.LOAD_TIMEOUT_DEFAULT = 8000; + +/** + * Create a LoadItem. + *
    + *
  • String-based items are converted to a LoadItem with a populated {{#crossLink "src:property"}}{{/crossLink}}.
  • + *
  • LoadItem instances are returned as-is
  • + *
  • Objects are returned with any needed properties added
  • + *
+ * @method create + * @param {LoadItem|String|Object} value The load item value + * @returns {LoadItem|Object} + * @static + */ +s.create = function (value) { + if (typeof value == "string") { + var item = new LoadItem(); + item.src = value; + return item; + } else if (value instanceof s) { + return value; + } else if (value instanceof Object && value.src) { + if (value.loadTimeout == null) { + value.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; + } + return value; + } else { + throw new Error("Type not recognized."); + } +}; + +/** + * Provides a chainable shortcut method for setting a number of properties on the instance. + * + *

Example

+ * + * var loadItem = new createjs.LoadItem().set({src:"image.png", maintainOrder:true}); + * + * @method set + * @param {Object} props A generic object containing properties to copy to the LoadItem instance. + * @return {LoadItem} Returns the instance the method is called on (useful for chaining calls.) + */ +p.set = function (props) { + for (var n in props) { + this[n] = props[n]; + } + return this; +}; + +var LoadItem = s; +module.exports = LoadItem; + +},{}],9:[function(_dereq_,module,exports){ +/* + * ProgressEvent + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +var promote = _dereq_('../../createjs/utils/promote'); +var extend = _dereq_('../../createjs/utils/extend'); +var Event = _dereq_('../../createjs/events/Event'); + +// constructor +/** + * A CreateJS {{#crossLink "Event"}}{{/crossLink}} that is dispatched when progress changes. + * @class ProgressEvent + * @param {Number} loaded The amount that has been loaded. This can be any number relative to the total. + * @param {Number} [total=1] The total amount that will load. This will default to 1, so if the `loaded` value is + * a percentage (between 0 and 1), it can be omitted. + * @todo Consider having this event be a "fileprogress" event as well + * @constructor + */ +function ProgressEvent(loaded, total) { + this.Event_constructor("progress"); + + /** + * The amount that has been loaded (out of a total amount) + * @property loaded + * @type {Number} + */ + this.loaded = loaded; + + /** + * The total "size" of the load. + * @property total + * @type {Number} + * @default 1 + */ + this.total = (total == null) ? 1 : total; + + /** + * The percentage (out of 1) that the load has been completed. This is calculated using `loaded/total`. + * @property progress + * @type {Number} + * @default 0 + */ + this.progress = (total == 0) ? 0 : this.loaded / this.total; +}; + +var p = extend(ProgressEvent, Event); + +/** + * Returns a clone of the ProgressEvent instance. + * @method clone + * @return {ProgressEvent} a clone of the Event instance. + **/ +p.clone = function () { + return new ProgressEvent(this.loaded, this.total); +}; + +var ProgressEvent = promote(ProgressEvent, "Event"); +module.exports = ProgressEvent; + +},{"../../createjs/events/Event":2,"../../createjs/utils/extend":4,"../../createjs/utils/promote":5}],10:[function(_dereq_,module,exports){ +/* + * AbstractLoader + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +var EventDispatcher = _dereq_('../../createjs/events/EventDispatcher'); +var LoadItem = _dereq_('../data/LoadItem'); +var Event = _dereq_('../../createjs/events/Event'); +var ErrorEvent = _dereq_('../../createjs/events/ErrorEvent'); +var ProgressEvent = _dereq_('../events/ProgressEvent'); +var RequestUtils = _dereq_('../utils/RequestUtils'); +var TagRequest = _dereq_('../net/TagRequest'); +var XHRRequest = _dereq_('../net/XHRRequest'); +var proxy = _dereq_('../../createjs/utils/proxy'); +var promote = _dereq_('../../createjs/utils/promote'); +var extend = _dereq_('../../createjs/utils/extend'); + +// namespace: +// constructor +/** + * The base loader, which defines all the generic methods, properties, and events. All loaders extend this class, + * including the {{#crossLink "LoadQueue"}}{{/crossLink}}. + * @class AbstractLoader + * @param {LoadItem|object|string} loadItem The item to be loaded. + * @param {Boolean} [preferXHR] Determines if the LoadItem should try and load using XHR, or take a + * tag-based approach, which can be better in cross-domain situations. Not all loaders can load using one or the + * other, so this is a suggested directive. + * @param {String} [type] The type of loader. Loader types are defined as constants on the AbstractLoader class, + * such as {{#crossLink "IMAGE:property"}}{{/crossLink}}, {{#crossLink "CSS:property"}}{{/crossLink}}, etc. + * @extends EventDispatcher + */ +function AbstractLoader(loadItem, preferXHR, type) { + this.EventDispatcher_constructor(); + + // public properties + /** + * If the loader has completed loading. This provides a quick check, but also ensures that the different approaches + * used for loading do not pile up resulting in more than one `complete` {{#crossLink "Event"}}{{/crossLink}}. + * @property loaded + * @type {Boolean} + * @default false + */ + this.loaded = false; + + /** + * Determine if the loader was canceled. Canceled loads will not fire complete events. Note that this property + * is readonly, so {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "LoadQueue/close"}}{{/crossLink}} + * instead. + * @property canceled + * @type {Boolean} + * @default false + * @readonly + */ + this.canceled = false; + + /** + * The current load progress (percentage) for this item. This will be a number between 0 and 1. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.loadFile("largeImage.png"); + * queue.on("progress", function() { + * console.log("Progress:", queue.progress, event.progress); + * }); + * + * @property progress + * @type {Number} + * @default 0 + */ + this.progress = 0; + + /** + * The type of item this loader will load. See {{#crossLink "AbstractLoader"}}{{/crossLink}} for a full list of + * supported types. + * @property type + * @type {String} + */ + this.type = type; + + /** + * A formatter function that converts the loaded raw result into the final result. For example, the JSONLoader + * converts a string of text into a JavaScript object. Not all loaders have a resultFormatter, and this property + * can be overridden to provide custom formatting. + * + * Optionally, a resultFormatter can return a callback function in cases where the formatting needs to be + * asynchronous, such as creating a new image. The callback function is passed 2 parameters, which are callbacks + * to handle success and error conditions in the resultFormatter. Note that the resultFormatter method is + * called in the current scope, as well as the success and error callbacks. + * + *

Example asynchronous resultFormatter

+ * + * function _formatResult(loader) { + * return function(success, error) { + * if (errorCondition) { error(errorDetailEvent); } + * success(result); + * } + * } + * @property resultFormatter + * @type {Function} + * @default null + */ + this.resultFormatter = null; + + // protected properties + /** + * The {{#crossLink "LoadItem"}}{{/crossLink}} this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}}, + * but will be available on loaders such as {{#crossLink "XMLLoader"}}{{/crossLink}} and {{#crossLink "ImageLoader"}}{{/crossLink}}. + * @property _item + * @type {LoadItem|Object} + * @private + */ + if (loadItem) { + this._item = LoadItem.create(loadItem); + } else { + this._item = null; + } + + /** + * Whether the loader will try and load content using XHR (true) or HTML tags (false). + * @property _preferXHR + * @type {Boolean} + * @private + */ + this._preferXHR = preferXHR; + + /** + * The loaded result after it is formatted by an optional {{#crossLink "resultFormatter"}}{{/crossLink}}. For + * items that are not formatted, this will be the same as the {{#crossLink "_rawResult:property"}}{{/crossLink}}. + * The result is accessed using the {{#crossLink "getResult"}}{{/crossLink}} method. + * @property _result + * @type {Object|String} + * @private + */ + this._result = null; + + /** + * The loaded result before it is formatted. The rawResult is accessed using the {{#crossLink "getResult"}}{{/crossLink}} + * method, and passing `true`. + * @property _rawResult + * @type {Object|String} + * @private + */ + this._rawResult = null; + + /** + * A list of items that loaders load behind the scenes. This does not include the main item the loader is + * responsible for loading. Examples of loaders that have sub-items include the {{#crossLink "SpriteSheetLoader"}}{{/crossLink}} and + * {{#crossLink "ManifestLoader"}}{{/crossLink}}. + * @property _loadItems + * @type {null} + * @protected + */ + this._loadedItems = null; + + /** + * The attribute the items loaded using tags use for the source. + * @type {string} + * @default null + * @private + */ + this._tagSrcAttribute = null; + + /** + * An HTML tag (or similar) that a loader may use to load HTML content, such as images, scripts, etc. + * @property _tag + * @type {Object} + * @private + */ + this._tag = null; +}; + +var p = extend(AbstractLoader, EventDispatcher); +var s = AbstractLoader; + +// TODO: deprecated +// p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. + + +/** + * Defines a POST request, use for a method value when loading data. + * @property POST + * @type {string} + * @default post + * @static + */ +s.POST = "POST"; + +/** + * Defines a GET request, use for a method value when loading data. + * @property GET + * @type {string} + * @default get + * @static + */ +s.GET = "GET"; + +/** + * The preload type for generic binary types. Note that images are loaded as binary files when using XHR. + * @property BINARY + * @type {String} + * @default binary + * @static + * @since 0.6.0 + */ +s.BINARY = "binary"; + +/** + * The preload type for css files. CSS files are loaded using a <link> when loaded with XHR, or a + * <style> tag when loaded with tags. + * @property CSS + * @type {String} + * @default css + * @static + * @since 0.6.0 + */ +s.CSS = "css"; + +/** + * The preload type for image files, usually png, gif, or jpg/jpeg. Images are loaded into an <image> tag. + * @property IMAGE + * @type {String} + * @default image + * @static + * @since 0.6.0 + */ +s.IMAGE = "image"; + +/** + * The preload type for javascript files, usually with the "js" file extension. JavaScript files are loaded into a + * <script> tag. + * + * Since version 0.4.1+, due to how tag-loaded scripts work, all JavaScript files are automatically injected into + * the body of the document to maintain parity between XHR and tag-loaded scripts. In version 0.4.0 and earlier, + * only tag-loaded scripts are injected. + * @property JAVASCRIPT + * @type {String} + * @default javascript + * @static + * @since 0.6.0 + */ +s.JAVASCRIPT = "javascript"; + +/** + * The preload type for json files, usually with the "json" file extension. JSON data is loaded and parsed into a + * JavaScript object. Note that if a `callback` is present on the load item, the file will be loaded with JSONP, + * no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to, and the JSON + * must contain a matching wrapper function. + * @property JSON + * @type {String} + * @default json + * @static + * @since 0.6.0 + */ +s.JSON = "json"; + +/** + * The preload type for jsonp files, usually with the "json" file extension. JSON data is loaded and parsed into a + * JavaScript object. You are required to pass a callback parameter that matches the function wrapper in the JSON. + * Note that JSONP will always be used if there is a callback present, no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} + * property is set to. + * @property JSONP + * @type {String} + * @default jsonp + * @static + * @since 0.6.0 + */ +s.JSONP = "jsonp"; + +/** + * The preload type for json-based manifest files, usually with the "json" file extension. The JSON data is loaded + * and parsed into a JavaScript object. PreloadJS will then look for a "manifest" property in the JSON, which is an + * Array of files to load, following the same format as the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * method. If a "callback" is specified on the manifest object, then it will be loaded using JSONP instead, + * regardless of what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to. + * @property MANIFEST + * @type {String} + * @default manifest + * @static + * @since 0.6.0 + */ +s.MANIFEST = "manifest"; + +/** + * The preload type for sound files, usually mp3, ogg, or wav. When loading via tags, audio is loaded into an + * <audio> tag. + * @property SOUND + * @type {String} + * @default sound + * @static + * @since 0.6.0 + */ +s.SOUND = "sound"; + +/** + * The preload type for video files, usually mp4, ts, or ogg. When loading via tags, video is loaded into an + * <video> tag. + * @property VIDEO + * @type {String} + * @default video + * @static + * @since 0.6.0 + */ +s.VIDEO = "video"; + +/** + * The preload type for SpriteSheet files. SpriteSheet files are JSON files that contain string image paths. + * @property SPRITESHEET + * @type {String} + * @default spritesheet + * @static + * @since 0.6.0 + */ +s.SPRITESHEET = "spritesheet"; + +/** + * The preload type for SVG files. + * @property SVG + * @type {String} + * @default svg + * @static + * @since 0.6.0 + */ +s.SVG = "svg"; + +/** + * The preload type for text files, which is also the default file type if the type can not be determined. Text is + * loaded as raw text. + * @property TEXT + * @type {String} + * @default text + * @static + * @since 0.6.0 + */ +s.TEXT = "text"; + +/** + * The preload type for xml files. XML is loaded into an XML document. + * @property XML + * @type {String} + * @default xml + * @static + * @since 0.6.0 + */ +s.XML = "xml"; + +// Events +/** + * The {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when the overall progress changes. Prior to + * version 0.6.0, this was just a regular {{#crossLink "Event"}}{{/crossLink}}. + * @event progress + * @since 0.3.0 + */ + +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a load starts. + * @event loadstart + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @since 0.3.1 + */ + +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the entire queue has been loaded. + * @event complete + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @since 0.3.0 + */ + +/** + * The {{#crossLink "ErrorEvent"}}{{/crossLink}} that is fired when the loader encounters an error. If the error was + * encountered by a file, the event will contain the item that caused the error. Prior to version 0.6.0, this was + * just a regular {{#crossLink "Event"}}{{/crossLink}}. + * @event error + * @since 0.3.0 + */ + +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the loader encounters an internal file load error. + * This enables loaders to maintain internal queues, and surface file load errors. + * @event fileerror + * @param {Object} target The object that dispatched the event. + * @param {String} type The even type ("fileerror") + * @param {LoadItem|object} The item that encountered the error + * @since 0.6.0 + */ + +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a loader internally loads a file. This enables + * loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} to maintain internal {{#crossLink "LoadQueue"}}{{/crossLink}}s + * and notify when they have loaded a file. The {{#crossLink "LoadQueue"}}{{/crossLink}} class dispatches a + * slightly different {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event. + * @event fileload + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type ("fileload") + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a `src` property. + * @param {Object} result The HTML tag or parsed result of the loaded item. + * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted + * to a usable object. + * @since 0.6.0 + */ + +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired after the internal request is created, but before a load. + * This allows updates to the loader for specific loading needs, such as binary or XHR image loading. + * @event initialize + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type ("initialize") + * @param {AbstractLoader} loader The loader that has been initialized. + */ + + +/** + * Get a reference to the manifest item that is loaded by this loader. In some cases this will be the value that was + * passed into {{#crossLink "LoadQueue"}}{{/crossLink}} using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. However if only a String path was passed in, then it will + * be a {{#crossLink "LoadItem"}}{{/crossLink}}. + * @method getItem + * @return {Object} The manifest item that this loader is responsible for loading. + * @since 0.6.0 + */ +p.getItem = function () { + return this._item; +}; + +/** + * Get a reference to the content that was loaded by the loader (only available after the {{#crossLink "complete:event"}}{{/crossLink}} + * event is dispatched. + * @method getResult + * @param {Boolean} [raw=false] Determines if the returned result will be the formatted content, or the raw loaded + * data (if it exists). + * @return {Object} + * @since 0.6.0 + */ +p.getResult = function (raw) { + return raw ? this._rawResult : this._result; +}; + +/** + * Return the `tag` this object creates or uses for loading. + * @method getTag + * @return {Object} The tag instance + * @since 0.6.0 + */ +p.getTag = function () { + return this._tag; +}; + +/** + * Set the `tag` this item uses for loading. + * @method setTag + * @param {Object} tag The tag instance + * @since 0.6.0 + */ +p.setTag = function (tag) { + this._tag = tag; +}; + +/** + * Begin loading the item. This method is required when using a loader by itself. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.on("complete", handleComplete); + * queue.loadManifest(fileArray, false); // Note the 2nd argument that tells the queue not to start loading yet + * queue.load(); + * + * @method load + */ +p.load = function () { + this._createRequest(); + + this._request.on("complete", this, this); + this._request.on("progress", this, this); + this._request.on("loadStart", this, this); + this._request.on("abort", this, this); + this._request.on("timeout", this, this); + this._request.on("error", this, this); + + var evt = new Event("initialize"); + evt.loader = this._request; + this.dispatchEvent(evt); + + this._request.load(); +}; + +/** + * Close the the item. This will stop any open requests (although downloads using HTML tags may still continue in + * the background), but events will not longer be dispatched. + * @method cancel + */ +p.cancel = function () { + this.canceled = true; + this.destroy(); +}; + +/** + * Clean up the loader. + * @method destroy + */ +p.destroy = function () { + if (this._request) { + this._request.removeAllEventListeners(); + this._request.destroy(); + } + + this._request = null; + + this._item = null; + this._rawResult = null; + this._result = null; + + this._loadItems = null; + + this.removeAllEventListeners(); +}; + +/** + * Get any items loaded internally by the loader. The enables loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} + * to expose items it loads internally. + * @method getLoadedItems + * @return {Array} A list of the items loaded by the loader. + * @since 0.6.0 + */ +p.getLoadedItems = function () { + return this._loadedItems; +}; + + +// Private methods +/** + * Create an internal request used for loading. By default, an {{#crossLink "XHRRequest"}}{{/crossLink}} or + * {{#crossLink "TagRequest"}}{{/crossLink}} is created, depending on the value of {{#crossLink "preferXHR:property"}}{{/crossLink}}. + * Other loaders may override this to use different request types, such as {{#crossLink "ManifestLoader"}}{{/crossLink}}, + * which uses {{#crossLink "JSONLoader"}}{{/crossLink}} or {{#crossLink "JSONPLoader"}}{{/crossLink}} under the hood. + * @method _createRequest + * @protected + */ +p._createRequest = function () { + if (!this._preferXHR) { + this._request = new TagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); + } else { + this._request = new XHRRequest(this._item); + } +}; + +/** + * Create the HTML tag used for loading. This method does nothing by default, and needs to be implemented + * by loaders that require tag loading. + * @method _createTag + * @param {String} src The tag source + * @return {HTMLElement} The tag that was created + * @protected + */ +p._createTag = function (src) { + return null; +}; + +/** + * Dispatch a loadstart {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendLoadStart + * @protected + */ +p._sendLoadStart = function () { + if (this._isCanceled()) { + return; + } + this.dispatchEvent("loadstart"); +}; + +/** + * Dispatch a {{#crossLink "ProgressEvent"}}{{/crossLink}}. + * @method _sendProgress + * @param {Number | Object} value The progress of the loaded item, or an object containing loaded + * and total properties. + * @protected + */ +p._sendProgress = function (value) { + if (this._isCanceled()) { + return; + } + var event = null; + if (typeof(value) == "number") { + this.progress = value; + event = new ProgressEvent(this.progress); + } else { + event = value; + this.progress = value.loaded / value.total; + event.progress = this.progress; + if (isNaN(this.progress) || this.progress == Infinity) { + this.progress = 0; + } + } + this.hasEventListener("progress") && this.dispatchEvent(event); +}; + +/** + * Dispatch a complete {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event + * @method _sendComplete + * @protected + */ +p._sendComplete = function () { + if (this._isCanceled()) { + return; + } + + this.loaded = true; + + var event = new Event("complete"); + event.rawResult = this._rawResult; + + if (this._result != null) { + event.result = this._result; + } + + this.dispatchEvent(event); +}; + +/** + * Dispatch an error {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendError + * @param {ErrorEvent} event The event object containing specific error properties. + * @protected + */ +p._sendError = function (event) { + if (this._isCanceled() || !this.hasEventListener("error")) { + return; + } + if (event == null) { + event = new ErrorEvent("PRELOAD_ERROR_EMPTY"); // TODO: Populate error + } + this.dispatchEvent(event); +}; + +/** + * Determine if the load has been canceled. This is important to ensure that method calls or asynchronous events + * do not cause issues after the queue has been cleaned up. + * @method _isCanceled + * @return {Boolean} If the loader has been canceled. + * @protected + */ +p._isCanceled = function () { + if (window.createjs == null || this.canceled) { + return true; + } + return false; +}; + +/** + * A custom result formatter function, which is called just before a request dispatches its complete event. Most + * loader types already have an internal formatter, but this can be user-overridden for custom formatting. The + * formatted result will be available on Loaders using {{#crossLink "getResult"}}{{/crossLink}}, and passing `true`. + * @property resultFormatter + * @type Function + * @return {Object} The formatted result + * @since 0.6.0 + */ +p.resultFormatter = null; + +/** + * Handle events from internal requests. By default, loaders will handle, and redispatch the necessary events, but + * this method can be overridden for custom behaviours. + * @method handleEvent + * @param {Event} event The event that the internal request dispatches. + * @protected + * @since 0.6.0 + */ +p.handleEvent = function (event) { + switch (event.type) { + case "complete": + this._rawResult = event.target._response; + var result = this.resultFormatter && this.resultFormatter(this); + if (result instanceof Function) { + result.call(this, + proxy(this._resultFormatSuccess, this), + proxy(this._resultFormatFailed, this) + ); + } else { + this._result = result || this._rawResult; + this._sendComplete(); + } + break; + case "progress": + this._sendProgress(event); + break; + case "error": + this._sendError(event); + break; + case "loadstart": + this._sendLoadStart(); + break; + case "abort": + case "timeout": + if (!this._isCanceled()) { + this.dispatchEvent(new ErrorEvent("PRELOAD_" + event.type.toUpperCase() + "_ERROR")); + } + break; + } +}; + +/** + * The "success" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous + * functions. + * @method _resultFormatSuccess + * @param {Object} result The formatted result + * @private + */ +p._resultFormatSuccess = function (result) { + this._result = result; + this._sendComplete(); +}; + +/** + * The "error" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous + * functions. + * @method _resultFormatSuccess + * @param {Object} error The error event + * @private + */ +p._resultFormatFailed = function (event) { + this._sendError(event); +}; + +/** + * @method buildPath + * @protected + * @deprecated Use the {{#crossLink "RequestUtils"}}{{/crossLink}} method {{#crossLink "RequestUtils/buildPath"}}{{/crossLink}} + * instead. + */ +p.buildPath = function (src, data) { + return RequestUtils.buildPath(src, data); +}; + +/** + * @method toString + * @return {String} a string representation of the instance. + */ +p.toString = function () { + return "[PreloadJS AbstractLoader]"; +}; + +module.exports = AbstractLoader = promote(AbstractLoader, "EventDispatcher"); + +},{"../../createjs/events/ErrorEvent":1,"../../createjs/events/Event":2,"../../createjs/events/EventDispatcher":3,"../../createjs/utils/extend":4,"../../createjs/utils/promote":5,"../../createjs/utils/proxy":6,"../data/LoadItem":8,"../events/ProgressEvent":9,"../net/TagRequest":13,"../net/XHRRequest":14,"../utils/RequestUtils":15}],11:[function(_dereq_,module,exports){ +/* + * ImageLoader + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +// constructor +/** + * A loader for image files. + * @class ImageLoader + * @param {LoadItem|Object} loadItem + * @param {Boolean} preferXHR + * @extends AbstractLoader + * @constructor + */ + +var AbstractLoader = _dereq_('./AbstractLoader'); +var RequestUtils = _dereq_('../utils/RequestUtils'); +var extend = _dereq_('../../createjs/utils/extend'); +var promote = _dereq_('../../createjs/utils/promote'); +var proxy = _dereq_('../../createjs/utils/proxy'); + +function ImageLoader(loadItem, preferXHR) { + this.AbstractLoader_constructor(loadItem, preferXHR, AbstractLoader.IMAGE); + + // public properties + this.resultFormatter = this._formatResult; + + // protected properties + this._tagSrcAttribute = "src"; + + // Check if the preload item is already a tag. + if (RequestUtils.isImageTag(loadItem)) { + this._tag = loadItem; + } else if (RequestUtils.isImageTag(loadItem.src)) { + this._tag = loadItem.src; + } else if (RequestUtils.isImageTag(loadItem.tag)) { + this._tag = loadItem.tag; + } + + if (this._tag != null) { + this._preferXHR = false; + } else { + this._tag = document.createElement("img"); + } + + this.on("initialize", this._updateXHR, this); +}; + +var p = extend(ImageLoader, AbstractLoader); +var s = ImageLoader; + +// static methods +/** + * Determines if the loader can load a specific item. This loader can only load items that are of type + * {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}. + * @method canLoadItem + * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. + * @returns {Boolean} Whether the loader can load the item. + * @static + */ +s.canLoadItem = function (item) { + return item.type == AbstractLoader.IMAGE; +}; + +// public methods +p.load = function () { + if (this._tag.src != "" && this._tag.complete) { + this._sendComplete(); + return; + } + + var crossOrigin = this._item.crossOrigin; + if (crossOrigin == true) { + crossOrigin = "Anonymous"; + } + if (crossOrigin != null && !RequestUtils.isLocal(this._item.src)) { + this._tag.crossOrigin = crossOrigin; + } + + this.AbstractLoader_load(); +}; + +// protected methods +/** + * Before the item loads, set its mimeType and responseType. + * @property _updateXHR + * @param {Event} event + * @private + */ +p._updateXHR = function (event) { + event.loader.mimeType = 'text/plain; charset=x-user-defined-binary'; + + // Only exists for XHR + if (event.loader.setResponseType) { + event.loader.setResponseType("blob"); + } +}; + +/** + * The result formatter for Image files. + * @method _formatResult + * @param {AbstractLoader} loader + * @returns {HTMLImageElement} + * @private + */ +p._formatResult = function (loader) { + return this._formatImage; +}; + +/** + * The asynchronous image formatter function. This is required because images have + * a short delay before they are ready. + * @method _formatImage + * @param {Function} successCallback The method to call when the result has finished formatting + * @param {Function} errorCallback The method to call if an error occurs during formatting + * @private + */ +p._formatImage = function (successCallback, errorCallback) { + var tag = this._tag; + var URL = window.URL || window.webkitURL; + + if (!this._preferXHR) { + //document.body.removeChild(tag); + } else if (URL) { + var objURL = URL.createObjectURL(this.getResult(true)); + tag.src = objURL; + + tag.addEventListener("load", this._cleanUpURL, false); + tag.addEventListener("error", this._cleanUpURL, false); + } else { + tag.src = this._item.src; + } + + if (tag.complete) { + successCallback(tag); + } else { + tag.onload = proxy(function () { + successCallback(this._tag); + }, this); + + tag.onerror = proxy(function () { + errorCallback(_this._tag); + }, this); + } +}; + +/** + * Clean up the ObjectURL, the tag is done with it. Note that this function is run + * as an event listener without a proxy/closure, as it doesn't require it - so do not + * include any functionality that requires scope without changing it. + * @method _cleanUpURL + * @param event + * @private + */ +p._cleanUpURL = function (event) { + var URL = window.URL || window.webkitURL; + URL.revokeObjectURL(event.target.src); +}; + +var ImageLoader = promote(ImageLoader, "AbstractLoader"); +module.exports = ImageLoader; + +},{"../../createjs/utils/extend":4,"../../createjs/utils/promote":5,"../../createjs/utils/proxy":6,"../utils/RequestUtils":15,"./AbstractLoader":10}],12:[function(_dereq_,module,exports){ +/* + * AbstractRequest + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +var promote = _dereq_('../../createjs/utils/promote'); +var extend = _dereq_('../../createjs/utils/extend'); +var EventDispatcher = _dereq_('../../createjs/events/EventDispatcher'); + +/** + * A base class for actual data requests, such as {{#crossLink "XHRRequest"}}{{/crossLink}}, {{#crossLink "TagRequest"}}{{/crossLink}}, + * and {{#crossLink "MediaRequest"}}{{/crossLink}}. PreloadJS loaders will typically use a data loader under the + * hood to get data. + * @class AbstractRequest + * @param {LoadItem} item + * @constructor + */ +var AbstractRequest = function (item) { + this._item = item; +}; + +var p = extend(AbstractRequest, EventDispatcher); + +// public methods +/** + * Begin a load. + * @method load + */ +p.load = function () { +}; + +/** + * Clean up a request. + * @method destroy + */ +p.destroy = function () { +}; + +/** + * Cancel an in-progress request. + * @method cancel + */ +p.cancel = function () { +}; + +module.exports = AbstractRequest = promote(AbstractRequest, "EventDispatcher"); + +},{"../../createjs/events/EventDispatcher":3,"../../createjs/utils/extend":4,"../../createjs/utils/promote":5}],13:[function(_dereq_,module,exports){ +/* + * TagRequest + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +var proxy = _dereq_('../../createjs/utils/proxy'); +var extend = _dereq_('../../createjs/utils/extend'); +var AbstractRequest = _dereq_('./AbstractRequest'); +var Event = _dereq_('../../createjs/events/Event'); +var promote = _dereq_('../../createjs/utils/promote'); + +// constructor +/** + * An {{#crossLink "AbstractRequest"}}{{/crossLink}} that loads HTML tags, such as images and scripts. + * @class TagRequest + * @param {LoadItem} loadItem + * @param {HTMLElement} tag + * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. + */ +function TagRequest(loadItem, tag, srcAttribute) { + this.AbstractRequest_constructor(loadItem); + + // protected properties + /** + * The HTML tag instance that is used to load. + * @property _tag + * @type {HTMLElement} + * @protected + */ + this._tag = tag; + + /** + * The tag attribute that specifies the source, such as "src", "href", etc. + * @property _tagSrcAttribute + * @type {String} + * @protected + */ + this._tagSrcAttribute = srcAttribute; + + /** + * A method closure used for handling the tag load event. + * @property _loadedHandler + * @type {Function} + * @private + */ + this._loadedHandler = proxy(this._handleTagComplete, this); + + /** + * Determines if the element was added to the DOM automatically by PreloadJS, so it can be cleaned up after. + * @property _addedToDOM + * @type {Boolean} + * @private + */ + this._addedToDOM = false; + + /** + * Determines what the tags initial style.visibility was, so we can set it correctly after a load. + * + * @type {null} + * @private + */ + this._startTagVisibility = null; +}; + +var p = extend(TagRequest, AbstractRequest); + +// public methods +p.load = function () { + this._tag.onload = proxy(this._handleTagComplete, this); + this._tag.onreadystatechange = proxy(this._handleReadyStateChange, this); + this._tag.onerror = proxy(this._handleError, this); + + var evt = new Event("initialize"); + evt.loader = this._tag; + + this.dispatchEvent(evt); + + this._hideTag(); + + this._loadTimeout = setTimeout(proxy(this._handleTimeout, this), this._item.loadTimeout); + + this._tag[this._tagSrcAttribute] = this._item.src; + + // wdg:: Append the tag AFTER setting the src, or SVG loading on iOS will fail. + if (this._tag.parentNode == null) { + window.document.body.appendChild(this._tag); + this._addedToDOM = true; + } +}; + +p.destroy = function () { + this._clean(); + this._tag = null; + + this.AbstractRequest_destroy(); +}; + +// private methods +/** + * Handle the readyStateChange event from a tag. We need this in place of the `onload` callback (mainly SCRIPT + * and LINK tags), but other cases may exist. + * @method _handleReadyStateChange + * @private + */ +p._handleReadyStateChange = function () { + clearTimeout(this._loadTimeout); + // This is strictly for tags in browsers that do not support onload. + var tag = this._tag; + + // Complete is for old IE support. + if (tag.readyState == "loaded" || tag.readyState == "complete") { + this._handleTagComplete(); + } +}; + +/** + * Handle any error events from the tag. + * @method _handleError + * @protected + */ +p._handleError = function () { + this._clean(); + this.dispatchEvent("error"); +}; + +/** + * Handle the tag's onload callback. + * @method _handleTagComplete + * @private + */ +p._handleTagComplete = function () { + this._rawResult = this._tag; + this._result = this.resultFormatter && this.resultFormatter(this) || this._rawResult; + + this._clean(); + this._showTag(); + + this.dispatchEvent("complete"); +}; + +/** + * The tag request has not loaded within the time specified in loadTimeout. + * @method _handleError + * @param {Object} event The XHR error event. + * @private + */ +p._handleTimeout = function () { + this._clean(); + this.dispatchEvent(new Event("timeout")); +}; + +/** + * Remove event listeners, but don't destroy the request object + * @method _clean + * @private + */ +p._clean = function () { + this._tag.onload = null; + this._tag.onreadystatechange = null; + this._tag.onerror = null; + if (this._addedToDOM && this._tag.parentNode != null) { + this._tag.parentNode.removeChild(this._tag); + } + clearTimeout(this._loadTimeout); +}; + +p._hideTag = function () { + this._startTagVisibility = this._tag.style.visibility; + this._tag.style.visibility = "hidden"; +}; + +p._showTag = function () { + this._tag.style.visibility = this._startTagVisibility; +}; + +/** + * Handle a stalled audio event. The main place this happens is with HTMLAudio in Chrome when playing back audio + * that is already in a load, but not complete. + * @method _handleStalled + * @private + */ +p._handleStalled = function () { + //Ignore, let the timeout take care of it. Sometimes its not really stopped. +}; + +module.exports = promote(TagRequest, "AbstractRequest"); +},{"../../createjs/events/Event":2,"../../createjs/utils/extend":4,"../../createjs/utils/promote":5,"../../createjs/utils/proxy":6,"./AbstractRequest":12}],14:[function(_dereq_,module,exports){ +/* + * XHRRequest + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + +var proxy = _dereq_('../../createjs/utils/proxy'); +var extend = _dereq_('../../createjs/utils/extend'); +var promote = _dereq_('../../createjs/utils/promote'); +var AbstractRequest = _dereq_('./AbstractRequest'); +var AbstractLoader = _dereq_('../loaders/AbstractLoader'); +var RequestUtils = _dereq_('../utils/RequestUtils'); +var ErrorEvent = _dereq_('../../createjs/events/ErrorEvent'); +var ProgressEvent = _dereq_('../events/ProgressEvent'); + +/** + * A preloader that loads items using XHR requests, usually XMLHttpRequest. However XDomainRequests will be used + * for cross-domain requests if possible, and older versions of IE fall back on to ActiveX objects when necessary. + * XHR requests load the content as text or binary data, provide progress and consistent completion events, and + * can be canceled during load. Note that XHR is not supported in IE 6 or earlier, and is not recommended for + * cross-domain loading. + * @class XHRRequest + * @constructor + * @param {Object} item The object that defines the file to load. Please see the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * for an overview of supported file properties. + * @extends AbstractLoader + */ +function XHRRequest(item) { + this.AbstractRequest_constructor(item); + + // protected properties + /** + * A reference to the XHR request used to load the content. + * @property _request + * @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP} + * @private + */ + this._request = null; + + /** + * A manual load timeout that is used for browsers that do not support the onTimeout event on XHR (XHR level 1, + * typically IE9). + * @property _loadTimeout + * @type {Number} + * @private + */ + this._loadTimeout = null; + + /** + * The browser's XHR (XMLHTTPRequest) version. Supported versions are 1 and 2. There is no official way to detect + * the version, so we use capabilities to make a best guess. + * @property _xhrLevel + * @type {Number} + * @default 1 + * @private + */ + this._xhrLevel = 1; + + /** + * The response of a loaded file. This is set because it is expensive to look up constantly. This property will be + * null until the file is loaded. + * @property _response + * @type {mixed} + * @private + */ + this._response = null; + + /** + * The response of the loaded file before it is modified. In most cases, content is converted from raw text to + * an HTML tag or a formatted object which is set to the result property, but the developer may still + * want to access the raw content as it was loaded. + * @property _rawResponse + * @type {String|Object} + * @private + */ + this._rawResponse = null; + + this._canceled = false; + + // Setup our event handlers now. + this._handleLoadStartProxy = proxy(this._handleLoadStart, this); + this._handleProgressProxy = proxy(this._handleProgress, this); + this._handleAbortProxy = proxy(this._handleAbort, this); + this._handleErrorProxy = proxy(this._handleError, this); + this._handleTimeoutProxy = proxy(this._handleTimeout, this); + this._handleLoadProxy = proxy(this._handleLoad, this); + this._handleReadyStateChangeProxy = proxy(this._handleReadyStateChange, this); + + if (!this._createXHR(item)) { + //TODO: Throw error? + } +}; + +var p = extend(XHRRequest, AbstractRequest); + +// static properties +/** + * A list of XMLHTTP object IDs to try when building an ActiveX object for XHR requests in earlier versions of IE. + * @property ACTIVEX_VERSIONS + * @type {Array} + * @since 0.4.2 + * @private + */ +XHRRequest.ACTIVEX_VERSIONS = [ + "Msxml2.XMLHTTP.6.0", + "Msxml2.XMLHTTP.5.0", + "Msxml2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", + "MSXML2.XMLHTTP", + "Microsoft.XMLHTTP" +]; + +// Public methods +/** + * Look up the loaded result. + * @method getResult + * @param {Boolean} [raw=false] Return a raw result instead of a formatted result. This applies to content + * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be + * returned instead. + * @return {Object} A result object containing the content that was loaded, such as: + *
    + *
  • An image tag (<image />) for images
  • + *
  • A script tag for JavaScript (<script />). Note that scripts loaded with tags may be added to the + * HTML head.
  • + *
  • A style tag for CSS (<style />)
  • + *
  • Raw text for TEXT
  • + *
  • A formatted JavaScript object defined by JSON
  • + *
  • An XML document
  • + *
  • An binary arraybuffer loaded by XHR
  • + *
+ * Note that if a raw result is requested, but not found, the result will be returned instead. + */ +p.getResult = function (raw) { + if (raw && this._rawResponse) { + return this._rawResponse; + } + return this._response; +}; + +// Overrides abstract method in AbstractRequest +p.cancel = function () { + this.canceled = true; + this._clean(); + this._request.abort(); +}; + +// Overrides abstract method in AbstractLoader +p.load = function () { + if (this._request == null) { + this._handleError(); + return; + } + + //Events + if (this._request.addEventListener != null) { + this._request.addEventListener("loadstart", this._handleLoadStartProxy, false); + this._request.addEventListener("progress", this._handleProgressProxy, false); + this._request.addEventListener("abort", this._handleAbortProxy, false); + this._request.addEventListener("error", this._handleErrorProxy, false); + this._request.addEventListener("timeout", this._handleTimeoutProxy, false); + + // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. + this._request.addEventListener("load", this._handleLoadProxy, false); + this._request.addEventListener("readystatechange", this._handleReadyStateChangeProxy, false); + } else { + // IE9 support + this._request.onloadstart = this._handleLoadStartProxy; + this._request.onprogress = this._handleProgressProxy; + this._request.onabort = this._handleAbortProxy; + this._request.onerror = this._handleErrorProxy; + this._request.ontimeout = this._handleTimeoutProxy; + + // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. + this._request.onload = this._handleLoadProxy; + this._request.onreadystatechange = this._handleReadyStateChangeProxy; + } + + // Set up a timeout if we don't have XHR2 + if (this._xhrLevel == 1) { + this._loadTimeout = setTimeout(proxy(this._handleTimeout, this), this._item.loadTimeout); + } + + // Sometimes we get back 404s immediately, particularly when there is a cross origin request. // note this does not catch in Chrome + try { + if (!this._item.values || this._item.method == AbstractLoader.GET) { + this._request.send(); + } else if (this._item.method == AbstractLoader.POST) { + this._request.send(RequestUtils.formatQueryString(this._item.values)); + } + } catch (error) { + this.dispatchEvent(new ErrorEvent("XHR_SEND", null, error)); + } +}; + +p.setResponseType = function (type) { + // Some old browsers doesn't support blob, so we convert arraybuffer to blob after response is downloaded + if (type === 'blob') { + type = window.URL ? 'blob' : 'arraybuffer'; + this._responseType = type; + } + this._request.responseType = type; +}; + +/** + * Get all the response headers from the XmlHttpRequest. + * + * From the docs: Return all the HTTP headers, excluding headers that are a case-insensitive match + * for Set-Cookie or Set-Cookie2, as a single string, with each header line separated by a U+000D CR U+000A LF pair, + * excluding the status line, and with each header name and header value separated by a U+003A COLON U+0020 SPACE + * pair. + * @method getAllResponseHeaders + * @return {String} + * @since 0.4.1 + */ +p.getAllResponseHeaders = function () { + if (this._request.getAllResponseHeaders instanceof Function) { + return this._request.getAllResponseHeaders(); + } else { + return null; + } +}; + +/** + * Get a specific response header from the XmlHttpRequest. + * + * From the docs: Returns the header field value from the response of which the field name matches + * header, unless the field name is Set-Cookie or Set-Cookie2. + * @method getResponseHeader + * @param {String} header The header name to retrieve. + * @return {String} + * @since 0.4.1 + */ +p.getResponseHeader = function (header) { + if (this._request.getResponseHeader instanceof Function) { + return this._request.getResponseHeader(header); + } else { + return null; + } +}; + +// protected methods +/** + * The XHR request has reported progress. + * @method _handleProgress + * @param {Object} event The XHR progress event. + * @private + */ +p._handleProgress = function (event) { + if (!event || event.loaded > 0 && event.total == 0) { + return; // Sometimes we get no "total", so just ignore the progress event. + } + + var newEvent = new ProgressEvent(event.loaded, event.total); + this.dispatchEvent(newEvent); +}; + +/** + * The XHR request has reported a load start. + * @method _handleLoadStart + * @param {Object} event The XHR loadStart event. + * @private + */ +p._handleLoadStart = function (event) { + clearTimeout(this._loadTimeout); + this.dispatchEvent("loadstart"); +}; + +/** + * The XHR request has reported an abort event. + * @method handleAbort + * @param {Object} event The XHR abort event. + * @private + */ +p._handleAbort = function (event) { + this._clean(); + this.dispatchEvent(new ErrorEvent("XHR_ABORTED", null, event)); +}; + +/** + * The XHR request has reported an error event. + * @method _handleError + * @param {Object} event The XHR error event. + * @private + */ +p._handleError = function (event) { + this._clean(); + this.dispatchEvent(new ErrorEvent(event.message)); +}; + +/** + * The XHR request has reported a readyState change. Note that older browsers (IE 7 & 8) do not provide an onload + * event, so we must monitor the readyStateChange to determine if the file is loaded. + * @method _handleReadyStateChange + * @param {Object} event The XHR readyStateChange event. + * @private + */ +p._handleReadyStateChange = function (event) { + if (this._request.readyState == 4) { + this._handleLoad(); + } +}; + +/** + * The XHR request has completed. This is called by the XHR request directly, or by a readyStateChange that has + * request.readyState == 4. Only the first call to this method will be processed. + * @method _handleLoad + * @param {Object} event The XHR load event. + * @private + */ +p._handleLoad = function (event) { + if (this.loaded) { + return; + } + this.loaded = true; + + var error = this._checkError(); + if (error) { + this._handleError(error); + return; + } + + this._response = this._getResponse(); + // Convert arraybuffer back to blob + if (this._responseType === 'arraybuffer') { + try { + this._response = new Blob([this._response]); + } catch (e) { + // Fallback to use BlobBuilder if Blob constructor is not supported + // Tested on Android 2.3 ~ 4.2 and iOS5 safari + window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; + if (e.name === 'TypeError' && window.BlobBuilder) { + var builder = new BlobBuilder(); + builder.append(this._response); + this._response = builder.getBlob(); + } + } + } + this._clean(); + + this.dispatchEvent(new Event("complete")); +}; + +/** + * The XHR request has timed out. This is called by the XHR request directly, or via a setTimeout + * callback. + * @method _handleTimeout + * @param {Object} [event] The XHR timeout event. This is occasionally null when called by the backup setTimeout. + * @private + */ +p._handleTimeout = function (event) { + this._clean(); + + this.dispatchEvent(new ErrorEvent("PRELOAD_TIMEOUT", null, event)); +}; + +// Protected +/** + * Determine if there is an error in the current load. This checks the status of the request for problem codes. Note + * that this does not check for an actual response. Currently, it only checks for 404 or 0 error code. + * @method _checkError + * @return {int} If the request status returns an error code. + * @private + */ +p._checkError = function () { + //LM: Probably need additional handlers here, maybe 501 + var status = parseInt(this._request.status); + + switch (status) { + case 404: // Not Found + case 0: // Not Loaded + return new Error(status); + } + return null; +}; + +/** + * Validate the response. Different browsers have different approaches, some of which throw errors when accessed + * in other browsers. If there is no response, the _response property will remain null. + * @method _getResponse + * @private + */ +p._getResponse = function () { + if (this._response != null) { + return this._response; + } + + if (this._request.response != null) { + return this._request.response; + } + + // Android 2.2 uses .responseText + try { + if (this._request.responseText != null) { + return this._request.responseText; + } + } catch (e) { + } + + // When loading XML, IE9 does not return .response, instead it returns responseXML.xml + try { + if (this._request.responseXML != null) { + return this._request.responseXML; + } + } catch (e) { + } + + return null; +}; + +/** + * Create an XHR request. Depending on a number of factors, we get totally different results. + *
  1. Some browsers get an XDomainRequest when loading cross-domain.
  2. + *
  3. XMLHttpRequest are created when available.
  4. + *
  5. ActiveX.XMLHTTP objects are used in older IE browsers.
  6. + *
  7. Text requests override the mime type if possible
  8. + *
  9. Origin headers are sent for crossdomain requests in some browsers.
  10. + *
  11. Binary loads set the response type to "arraybuffer"
+ * @method _createXHR + * @param {Object} item The requested item that is being loaded. + * @return {Boolean} If an XHR request or equivalent was successfully created. + * @private + */ +p._createXHR = function (item) { + // Check for cross-domain loads. We can't fully support them, but we can try. + var crossdomain = RequestUtils.isCrossDomain(item); + var headers = {}; + + // Create the request. Fallback to whatever support we have. + var req = null; + if (window.XMLHttpRequest) { + req = new XMLHttpRequest(); + // This is 8 or 9, so use XDomainRequest instead. + if (crossdomain && req.withCredentials === undefined && window.XDomainRequest) { + req = new XDomainRequest(); + } + } else { // Old IE versions use a different approach + for (var i = 0, l = s.ACTIVEX_VERSIONS.length; i < l; i++) { + var axVersion = s.ACTIVEX_VERSIONS[i]; + try { + req = new ActiveXObject(axVersion); + break; + } catch (e) { + } + } + if (req == null) { + return false; + } + } + + // Default to utf-8 for Text requests. + if (item.mimeType == null && RequestUtils.isText(item.type)) { + item.mimeType = "text/plain; charset=utf-8"; + } + + // IE9 doesn't support overrideMimeType(), so we need to check for it. + if (item.mimeType && req.overrideMimeType) { + req.overrideMimeType(item.mimeType); + } + + // Determine the XHR level + this._xhrLevel = (typeof req.responseType === "string") ? 2 : 1; + + var src = null; + if (item.method == AbstractLoader.GET) { + src = RequestUtils.buildPath(item.src, item.values); + } else { + src = item.src; + } + + // Open the request. Set cross-domain flags if it is supported (XHR level 1 only) + req.open(item.method || AbstractLoader.GET, src, true); + + if (crossdomain && req instanceof XMLHttpRequest && this._xhrLevel == 1) { + headers["Origin"] = location.origin; + } + + // To send data we need to set the Content-type header) + if (item.values && item.method == AbstractLoader.POST) { + headers["Content-Type"] = "application/x-www-form-urlencoded"; + } + + if (!crossdomain && !headers["X-Requested-With"]) { + headers["X-Requested-With"] = "XMLHttpRequest"; + } + + if (item.headers) { + for (var n in item.headers) { + headers[n] = item.headers[n]; + } + } + + for (n in headers) { + req.setRequestHeader(n, headers[n]) + } + + if (req instanceof XMLHttpRequest && item.withCredentials !== undefined) { + req.withCredentials = item.withCredentials; + } + + this._request = req; + + return true; +}; + +/** + * A request has completed (or failed or canceled), and needs to be disposed. + * @method _clean + * @private + */ +p._clean = function () { + clearTimeout(this._loadTimeout); + + if (this._request.removeEventListener != null) { + this._request.removeEventListener("loadstart", this._handleLoadStartProxy); + this._request.removeEventListener("progress", this._handleProgressProxy); + this._request.removeEventListener("abort", this._handleAbortProxy); + this._request.removeEventListener("error", this._handleErrorProxy); + this._request.removeEventListener("timeout", this._handleTimeoutProxy); + this._request.removeEventListener("load", this._handleLoadProxy); + this._request.removeEventListener("readystatechange", this._handleReadyStateChangeProxy); + } else { + this._request.onloadstart = null; + this._request.onprogress = null; + this._request.onabort = null; + this._request.onerror = null; + this._request.ontimeout = null; + this._request.onload = null; + this._request.onreadystatechange = null; + } +}; + +p.toString = function () { + return "[PreloadJS XHRRequest]"; +}; + +module.exports = XHRRequest = promote(XHRRequest, "AbstractRequest"); + +},{"../../createjs/events/ErrorEvent":1,"../../createjs/utils/extend":4,"../../createjs/utils/promote":5,"../../createjs/utils/proxy":6,"../events/ProgressEvent":9,"../loaders/AbstractLoader":10,"../utils/RequestUtils":15,"./AbstractRequest":12}],15:[function(_dereq_,module,exports){ +/* + * RequestUtils + * Visit http://createjs.com/ for documentation, updates and examples. + * + * + * Copyright (c) 2012 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @module PreloadJS + */ + + +var AbstractLoader = _dereq_('../loaders/AbstractLoader'); + +/** + * Utilities that assist with parsing load items, and determining file types, etc. + * @class RequestUtils + */ +var s = {}; + +/** + * The Regular Expression used to test file URLS for an absolute path. + * @property ABSOLUTE_PATH + * @type {RegExp} + * @static + */ +s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i; + +/** + * The Regular Expression used to test file URLS for a relative path. + * @property RELATIVE_PATH + * @type {RegExp} + * @static + */ +s.RELATIVE_PATT = (/^[./]*?\//i); + +/** + * The Regular Expression used to test file URLS for an extension. Note that URIs must already have the query string + * removed. + * @property EXTENSION_PATT + * @type {RegExp} + * @static + */ +s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i; + +/** + * Parse a file path to determine the information we need to work with it. Currently, PreloadJS needs to know: + *
    + *
  • If the path is absolute. Absolute paths start with a protocol (such as `http://`, `file://`, or + * `//networkPath`)
  • + *
  • If the path is relative. Relative paths start with `../` or `/path` (or similar)
  • + *
  • The file extension. This is determined by the filename with an extension. Query strings are dropped, and + * the file path is expected to follow the format `name.ext`.
  • + *
+ * @method parseURI + * @param {String} path + * @returns {Object} An Object with an `absolute` and `relative` Boolean values, as well as an optional 'extension` + * property, which is the lowercase extension. + * @static + */ +s.parseURI = function (path) { + var info = {absolute: false, relative: false}; + if (path == null) { + return info; + } + + // Drop the query string + var queryIndex = path.indexOf("?"); + if (queryIndex > -1) { + path = path.substr(0, queryIndex); + } + + // Absolute + var match; + if (s.ABSOLUTE_PATT.test(path)) { + info.absolute = true; + + // Relative + } else if (s.RELATIVE_PATT.test(path)) { + info.relative = true; + } + + // Extension + if (match = path.match(s.EXTENSION_PATT)) { + info.extension = match[1].toLowerCase(); + } + return info; +}; + +/** + * Formats an object into a query string for either a POST or GET request. + * @method formatQueryString + * @param {Object} data The data to convert to a query string. + * @param {Array} [query] Existing name/value pairs to append on to this query. + * @static + */ +s.formatQueryString = function (data, query) { + if (data == null) { + throw new Error('You must specify data.'); + } + var params = []; + for (var n in data) { + params.push(n + '=' + escape(data[n])); + } + if (query) { + params = params.concat(query); + } + return params.join('&'); +}; + +/** + * A utility method that builds a file path using a source and a data object, and formats it into a new path. + * @method buildPath + * @param {String} src The source path to add values to. + * @param {Object} [data] Object used to append values to this request as a query string. Existing parameters on the + * path will be preserved. + * @returns {string} A formatted string that contains the path and the supplied parameters. + * @static + */ +s.buildPath = function (src, data) { + if (data == null) { + return src; + } + + var query = []; + var idx = src.indexOf('?'); + + if (idx != -1) { + var q = src.slice(idx + 1); + query = query.concat(q.split('&')); + } + + if (idx != -1) { + return src.slice(0, idx) + '?' + this._formatQueryString(data, query); + } else { + return src + '?' + this._formatQueryString(data, query); + } +}; + +/** + * @method isCrossDomain + * @param {LoadItem|Object} item A load item with a `src` property. + * @return {Boolean} If the load item is loading from a different domain than the current location. + * @static + */ +s.isCrossDomain = function (item) { + var target = document.createElement("a"); + target.href = item.src; + + var host = document.createElement("a"); + host.href = location.href; + + var crossdomain = (target.hostname != "") && + (target.port != host.port || + target.protocol != host.protocol || + target.hostname != host.hostname); + return crossdomain; +}; + +/** + * @method isLocal + * @param {LoadItem|Object} item A load item with a `src` property + * @return {Boolean} If the load item is loading from the "file:" protocol. Assume that the host must be local as + * well. + * @static + */ +s.isLocal = function (item) { + var target = document.createElement("a"); + target.href = item.src; + return target.hostname == "" && target.protocol == "file:"; +}; + +/** + * Determine if a specific type should be loaded as a binary file. Currently, only images and items marked + * specifically as "binary" are loaded as binary. Note that audio is not a binary type, as we can not play + * back using an audio tag if it is loaded as binary. Plugins can change the item type to binary to ensure they get + * a binary result to work with. Binary files are loaded using XHR2. Types are defined as static constants on + * {{#crossLink "AbstractLoader"}}{{/crossLink}}. + * @method isBinary + * @param {String} type The item type. + * @return {Boolean} If the specified type is binary. + * @static + */ +s.isBinary = function (type) { + switch (type) { + case AbstractLoader.IMAGE: + case AbstractLoader.BINARY: + return true; + default: + return false; + } +}; + +/** + * Check if item is a valid HTMLImageElement + * @method isImageTag + * @param {Object} item + * @returns {Boolean} + * @static + */ +s.isImageTag = function (item) { + return item instanceof HTMLImageElement; +}; + +/** + * Check if item is a valid HTMLAudioElement + * @method isAudioTag + * @param {Object} item + * @returns {Boolean} + * @static + */ +s.isAudioTag = function (item) { + if (window.HTMLAudioElement) { + return item instanceof HTMLAudioElement; + } else { + return false; + } +}; + +/** + * Check if item is a valid HTMLVideoElement + * @method isVideoTag + * @param {Object} item + * @returns {Boolean} + * @static + */ +s.isVideoTag = function (item) { + if (window.HTMLVideoElement) { + return item instanceof HTMLVideoElement; + } else { + return false; + } +}; + +/** + * Determine if a specific type is a text-based asset, and should be loaded as UTF-8. + * @method isText + * @param {String} type The item type. + * @return {Boolean} If the specified type is text. + * @static + */ +s.isText = function (type) { + switch (type) { + case AbstractLoader.TEXT: + case AbstractLoader.JSON: + case AbstractLoader.MANIFEST: + case AbstractLoader.XML: + case AbstractLoader.CSS: + case AbstractLoader.SVG: + case AbstractLoader.JAVASCRIPT: + case AbstractLoader.SPRITESHEET: + return true; + default: + return false; + } +}; + +/** + * Determine the type of the object using common extensions. Note that the type can be passed in with the load item + * if it is an unusual extension. + * @method getTypeByExtension + * @param {String} extension The file extension to use to determine the load type. + * @return {String} The determined load type (for example, AbstractLoader.IMAGE). Will return `null` if + * the type can not be determined by the extension. + * @static + */ +s.getTypeByExtension = function (extension) { + if (extension == null) { + return AbstractLoader.TEXT; + } + + switch (extension.toLowerCase()) { + case "jpeg": + case "jpg": + case "gif": + case "png": + case "webp": + case "bmp": + return AbstractLoader.IMAGE; + case "ogg": + case "mp3": + case "webm": + return AbstractLoader.SOUND; + case "mp4": + case "webm": + case "ts": + return AbstractLoader.VIDEO; + case "json": + return AbstractLoader.JSON; + case "xml": + return AbstractLoader.XML; + case "css": + return AbstractLoader.CSS; + case "js": + return AbstractLoader.JAVASCRIPT; + case 'svg': + return AbstractLoader.SVG; + default: + return AbstractLoader.TEXT; + } +}; + +var RequestUtils = s; +module.exports = RequestUtils; + +},{"../loaders/AbstractLoader":10}],16:[function(_dereq_,module,exports){ +// File for legacy window.createjs support. Also used for the the build process. +(function (name, definition) { + if (typeof module != 'undefined') module.exports = definition(); + else if (typeof define == 'function' && typeof define.amd == 'object') define(definition); + else this[name] = definition(); console.log(this, name); +}('createjs', function () { + return { + LoadQueue: _dereq_("./LoadQueue"), + promote: _dereq_('../createjs/utils/promote'), + extend: _dereq_('../createjs/utils/extend'), + Event: _dereq_('../createjs/events/Event'), + ErrorEvent: _dereq_('../createjs/events/ErrorEvent'), + ProgressEvent: _dereq_('./events/ProgressEvent') + }; +})); + +},{"../createjs/events/ErrorEvent":1,"../createjs/events/Event":2,"../createjs/utils/extend":4,"../createjs/utils/promote":5,"./LoadQueue":7,"./events/ProgressEvent":9}]},{},[16]); diff --git a/examples/moduleLoaders/window/index.html b/examples/moduleLoaders/window/index.html new file mode 100644 index 0000000..1acc618 --- /dev/null +++ b/examples/moduleLoaders/window/index.html @@ -0,0 +1,28 @@ + + + + + Codestin Search App + + + + + + + + + + + diff --git a/lib/preloadjs-NEXT.combined.js b/lib/preloadjs-NEXT.combined.js index 420d408..c60b6ec 100644 --- a/lib/preloadjs-NEXT.combined.js +++ b/lib/preloadjs-NEXT.combined.js @@ -31,9 +31,10 @@ // version.js //############################################################################## -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; /** @@ -56,143 +57,113 @@ this.createjs = this.createjs || {}; * @type {String} * @static **/ - s.buildDate = /*=date*/"Thu, 22 Oct 2015 16:01:29 GMT"; // injected by build process + s.buildDate = /*=date*/"Wed, 02 Dec 2015 18:53:18 GMT"; // injected by build process -})(); +})(scope.createjs); //############################################################################## // extend.js //############################################################################## -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ - -/** - * Sets up the prototype chain and constructor property for a new class. - * - * This should be called right after creating the class constructor. - * - * function MySubClass() {} - * createjs.extend(MySubClass, MySuperClass); - * ClassB.prototype.doSomething = function() { } - * - * var foo = new MySubClass(); - * console.log(foo instanceof MySuperClass); // true - * console.log(foo.prototype.constructor === MySubClass); // true - * - * @method extend - * @param {Function} subclass The subclass. - * @param {Function} superclass The superclass to extend. - * @return {Function} Returns the subclass's new prototype. - */ -createjs.extend = function(subclass, superclass) { - "use strict"; - - function o() { this.constructor = subclass; } - o.prototype = superclass.prototype; - return (subclass.prototype = new o()); +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +/** + * @class Utility Methods + */ + +/** + * Sets up the prototype chain and constructor property for a new class. + * + * This should be called right after creating the class constructor. + * + * function MySubClass() {} + * createjs.extend(MySubClass, MySuperClass); + * ClassB.prototype.doSomething = function() { } + * + * var foo = new MySubClass(); + * console.log(foo instanceof MySuperClass); // true + * console.log(foo.prototype.constructor === MySubClass); // true + * + * @method extend + * @param {Function} subclass The subclass. + * @param {Function} superclass The superclass to extend. + * @return {Function} Returns the subclass's new prototype. + */ +scope.createjs.extend = function(subclass, superclass) { + "use strict"; + + function o() { this.constructor = subclass; } + o.prototype = superclass.prototype; + return (subclass.prototype = new o()); }; //############################################################################## // promote.js //############################################################################## -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ - -/** - * Promotes any methods on the super class that were overridden, by creating an alias in the format `prefix_methodName`. - * It is recommended to use the super class's name as the prefix. - * An alias to the super class's constructor is always added in the format `prefix_constructor`. - * This allows the subclass to call super class methods without using `function.call`, providing better performance. - * - * For example, if `MySubClass` extends `MySuperClass`, and both define a `draw` method, then calling `promote(MySubClass, "MySuperClass")` - * would add a `MySuperClass_constructor` method to MySubClass and promote the `draw` method on `MySuperClass` to the - * prototype of `MySubClass` as `MySuperClass_draw`. - * - * This should be called after the class's prototype is fully defined. - * - * function ClassA(name) { - * this.name = name; - * } - * ClassA.prototype.greet = function() { - * return "Hello "+this.name; - * } - * - * function ClassB(name, punctuation) { - * this.ClassA_constructor(name); - * this.punctuation = punctuation; - * } - * createjs.extend(ClassB, ClassA); - * ClassB.prototype.greet = function() { - * return this.ClassA_greet()+this.punctuation; - * } - * createjs.promote(ClassB, "ClassA"); - * - * var foo = new ClassB("World", "!?!"); - * console.log(foo.greet()); // Hello World!?! - * - * @method promote - * @param {Function} subclass The class to promote super class methods on. - * @param {String} prefix The prefix to add to the promoted method names. Usually the name of the superclass. - * @return {Function} Returns the subclass. - */ -createjs.promote = function(subclass, prefix) { - "use strict"; - - var subP = subclass.prototype, supP = (Object.getPrototypeOf&&Object.getPrototypeOf(subP))||subP.__proto__; - if (supP) { - subP[(prefix+="_") + "constructor"] = supP.constructor; // constructor is not always innumerable - for (var n in supP) { - if (subP.hasOwnProperty(n) && (typeof supP[n] == "function")) { subP[prefix + n] = supP[n]; } - } - } - return subclass; -}; - -//############################################################################## -// indexOf.js -//############################################################################## - -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ - -/** - * Finds the first occurrence of a specified value searchElement in the passed in array, and returns the index of - * that value. Returns -1 if value is not found. - * - * var i = createjs.indexOf(myArray, myElementToFind); - * - * @method indexOf - * @param {Array} array Array to search for searchElement - * @param searchElement Element to find in array. - * @return {Number} The first index of searchElement in array. - */ -createjs.indexOf = function (array, searchElement){ - "use strict"; - - for (var i = 0,l=array.length; i < l; i++) { - if (searchElement === array[i]) { - return i; - } - } - return -1; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; +/** + * @class Utility Methods + */ + +/** + * Promotes any methods on the super class that were overridden, by creating an alias in the format `prefix_methodName`. + * It is recommended to use the super class's name as the prefix. + * An alias to the super class's constructor is always added in the format `prefix_constructor`. + * This allows the subclass to call super class methods without using `function.call`, providing better performance. + * + * For example, if `MySubClass` extends `MySuperClass`, and both define a `draw` method, then calling `promote(MySubClass, "MySuperClass")` + * would add a `MySuperClass_constructor` method to MySubClass and promote the `draw` method on `MySuperClass` to the + * prototype of `MySubClass` as `MySuperClass_draw`. + * + * This should be called after the class's prototype is fully defined. + * + * function ClassA(name) { + * this.name = name; + * } + * ClassA.prototype.greet = function() { + * return "Hello "+this.name; + * } + * + * function ClassB(name, punctuation) { + * this.ClassA_constructor(name); + * this.punctuation = punctuation; + * } + * createjs.extend(ClassB, ClassA); + * ClassB.prototype.greet = function() { + * return this.ClassA_greet()+this.punctuation; + * } + * createjs.promote(ClassB, "ClassA"); + * + * var foo = new ClassB("World", "!?!"); + * console.log(foo.greet()); // Hello World!?! + * + * @method promote + * @param {Function} subclass The class to promote super class methods on. + * @param {String} prefix The prefix to add to the promoted method names. Usually the name of the superclass. + * @return {Function} Returns the subclass. + */ +scope.createjs.promote = function(subclass, prefix) { + "use strict"; + + var subP = subclass.prototype, supP = (Object.getPrototypeOf&&Object.getPrototypeOf(subP))||subP.__proto__; + if (supP) { + subP[(prefix+="_") + "constructor"] = supP.constructor; // constructor is not always innumerable + for (var n in supP) { + if (subP.hasOwnProperty(n) && (typeof supP[n] == "function")) { subP[prefix + n] = supP[n]; } + } + } + return subclass; }; //############################################################################## // proxy.js //############################################################################## -this.createjs = this.createjs||{}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; /** * Various utilities that the CreateJS Suite uses. Utilities are created as separate files, and will be available on the @@ -206,7 +177,7 @@ this.createjs = this.createjs||{}; * @main Utility Methods */ -(function() { +(function(createjs) { "use strict"; /** @@ -238,242 +209,277 @@ this.createjs = this.createjs||{}; }; } -}()); +}(scope.createjs)); //############################################################################## -// Event.js +// indexOf.js //############################################################################## -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - -// constructor: - /** - * Contains properties and methods shared by all events for use with - * {{#crossLink "EventDispatcher"}}{{/crossLink}}. - * - * Note that Event objects are often reused, so you should never - * rely on an event object's state outside of the call stack it was received in. - * @class Event - * @param {String} type The event type. - * @param {Boolean} bubbles Indicates whether the event will bubble through the display list. - * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled. - * @constructor - **/ - function Event(type, bubbles, cancelable) { - - - // public properties: - /** - * The type of event. - * @property type - * @type String - **/ - this.type = type; - - /** - * The object that generated an event. - * @property target - * @type Object - * @default null - * @readonly - */ - this.target = null; - - /** - * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will - * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event - * is generated from childObj, then a listener on parentObj would receive the event with - * target=childObj (the original target) and currentTarget=parentObj (where the listener was added). - * @property currentTarget - * @type Object - * @default null - * @readonly - */ - this.currentTarget = null; - - /** - * For bubbling events, this indicates the current event phase:
    - *
  1. capture phase: starting from the top parent to the target
  2. - *
  3. at target phase: currently being dispatched from the target
  4. - *
  5. bubbling phase: from the target to the top parent
  6. - *
- * @property eventPhase - * @type Number - * @default 0 - * @readonly - */ - this.eventPhase = 0; - - /** - * Indicates whether the event will bubble through the display list. - * @property bubbles - * @type Boolean - * @default false - * @readonly - */ - this.bubbles = !!bubbles; - - /** - * Indicates whether the default behaviour of this event can be cancelled via - * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor. - * @property cancelable - * @type Boolean - * @default false - * @readonly - */ - this.cancelable = !!cancelable; - - /** - * The epoch time at which this event was created. - * @property timeStamp - * @type Number - * @default 0 - * @readonly - */ - this.timeStamp = (new Date()).getTime(); - - /** - * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called - * on this event. - * @property defaultPrevented - * @type Boolean - * @default false - * @readonly - */ - this.defaultPrevented = false; - - /** - * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or - * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event. - * @property propagationStopped - * @type Boolean - * @default false - * @readonly - */ - this.propagationStopped = false; - - /** - * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called - * on this event. - * @property immediatePropagationStopped - * @type Boolean - * @default false - * @readonly - */ - this.immediatePropagationStopped = false; - - /** - * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event. - * @property removed - * @type Boolean - * @default false - * @readonly - */ - this.removed = false; - } - var p = Event.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// public methods: - /** - * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method preventDefault - **/ - p.preventDefault = function() { - this.defaultPrevented = this.cancelable&&true; - }; - - /** - * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method stopPropagation - **/ - p.stopPropagation = function() { - this.propagationStopped = true; - }; - - /** - * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and - * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method stopImmediatePropagation - **/ - p.stopImmediatePropagation = function() { - this.immediatePropagationStopped = this.propagationStopped = true; - }; - - /** - * Causes the active listener to be removed via removeEventListener(); - * - * myBtn.addEventListener("click", function(evt) { - * // do stuff... - * evt.remove(); // removes this listener. - * }); - * - * @method remove - **/ - p.remove = function() { - this.removed = true; - }; - - /** - * Returns a clone of the Event instance. - * @method clone - * @return {Event} a clone of the Event instance. - **/ - p.clone = function() { - return new Event(this.type, this.bubbles, this.cancelable); - }; - - /** - * Provides a chainable shortcut method for setting a number of properties on the instance. - * - * @method set - * @param {Object} props A generic object containing properties to copy to the instance. - * @return {Event} Returns the instance the method is called on (useful for chaining calls.) - * @chainable - */ - p.set = function(props) { - for (var n in props) { this[n] = props[n]; } - return this; - }; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +/** + * @class Utility Methods + */ + +/** + * Finds the first occurrence of a specified value searchElement in the passed in array, and returns the index of + * that value. Returns -1 if value is not found. + * + * var i = createjs.indexOf(myArray, myElementToFind); + * + * @method indexOf + * @param {Array} array Array to search for searchElement + * @param searchElement Element to find in array. + * @return {Number} The first index of searchElement in array. + */ +scope.createjs.indexOf = function (array, searchElement){ + "use strict"; + + for (var i = 0,l=array.length; i < l; i++) { + if (searchElement === array[i]) { + return i; + } + } + return -1; +}; - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Event (type="+this.type+")]"; - }; +//############################################################################## +// Event.js +//############################################################################## - createjs.Event = Event; -}()); +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function(createjs) { + "use strict"; + +// constructor: + /** + * Contains properties and methods shared by all events for use with + * {{#crossLink "EventDispatcher"}}{{/crossLink}}. + * + * Note that Event objects are often reused, so you should never + * rely on an event object's state outside of the call stack it was received in. + * @class Event + * @param {String} type The event type. + * @param {Boolean} bubbles Indicates whether the event will bubble through the display list. + * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled. + * @constructor + **/ + function Event(type, bubbles, cancelable) { + + + // public properties: + /** + * The type of event. + * @property type + * @type String + **/ + this.type = type; + + /** + * The object that generated an event. + * @property target + * @type Object + * @default null + * @readonly + */ + this.target = null; + + /** + * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will + * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event + * is generated from childObj, then a listener on parentObj would receive the event with + * target=childObj (the original target) and currentTarget=parentObj (where the listener was added). + * @property currentTarget + * @type Object + * @default null + * @readonly + */ + this.currentTarget = null; + + /** + * For bubbling events, this indicates the current event phase:
    + *
  1. capture phase: starting from the top parent to the target
  2. + *
  3. at target phase: currently being dispatched from the target
  4. + *
  5. bubbling phase: from the target to the top parent
  6. + *
+ * @property eventPhase + * @type Number + * @default 0 + * @readonly + */ + this.eventPhase = 0; + + /** + * Indicates whether the event will bubble through the display list. + * @property bubbles + * @type Boolean + * @default false + * @readonly + */ + this.bubbles = !!bubbles; + + /** + * Indicates whether the default behaviour of this event can be cancelled via + * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor. + * @property cancelable + * @type Boolean + * @default false + * @readonly + */ + this.cancelable = !!cancelable; + + /** + * The epoch time at which this event was created. + * @property timeStamp + * @type Number + * @default 0 + * @readonly + */ + this.timeStamp = (new Date()).getTime(); + + /** + * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called + * on this event. + * @property defaultPrevented + * @type Boolean + * @default false + * @readonly + */ + this.defaultPrevented = false; + + /** + * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or + * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event. + * @property propagationStopped + * @type Boolean + * @default false + * @readonly + */ + this.propagationStopped = false; + + /** + * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called + * on this event. + * @property immediatePropagationStopped + * @type Boolean + * @default false + * @readonly + */ + this.immediatePropagationStopped = false; + + /** + * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event. + * @property removed + * @type Boolean + * @default false + * @readonly + */ + this.removed = false; + } + var p = Event.prototype; + + /** + * REMOVED. Removed in favor of using `MySuperClass_constructor`. + * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} + * for details. + * + * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. + * + * @method initialize + * @protected + * @deprecated + */ + // p.initialize = function() {}; // searchable for devs wondering where it is. + + +// public methods: + /** + * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method preventDefault + **/ + p.preventDefault = function() { + this.defaultPrevented = this.cancelable&&true; + }; + + /** + * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method stopPropagation + **/ + p.stopPropagation = function() { + this.propagationStopped = true; + }; + + /** + * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and + * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method stopImmediatePropagation + **/ + p.stopImmediatePropagation = function() { + this.immediatePropagationStopped = this.propagationStopped = true; + }; + + /** + * Causes the active listener to be removed via removeEventListener(); + * + * myBtn.addEventListener("click", function(evt) { + * // do stuff... + * evt.remove(); // removes this listener. + * }); + * + * @method remove + **/ + p.remove = function() { + this.removed = true; + }; + + /** + * Returns a clone of the Event instance. + * @method clone + * @return {Event} a clone of the Event instance. + **/ + p.clone = function() { + return new Event(this.type, this.bubbles, this.cancelable); + }; + + /** + * Provides a chainable shortcut method for setting a number of properties on the instance. + * + * @method set + * @param {Object} props A generic object containing properties to copy to the instance. + * @return {Event} Returns the instance the method is called on (useful for chaining calls.) + * @chainable + */ + p.set = function(props) { + for (var n in props) { this[n] = props[n]; } + return this; + }; + + /** + * Returns a string representation of this object. + * @method toString + * @return {String} a string representation of the instance. + **/ + p.toString = function() { + return "[Event (type="+this.type+")]"; + }; + + createjs.Event = Event; +}(scope.createjs)); //############################################################################## // ErrorEvent.js //############################################################################## -this.createjs = this.createjs||{}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function() { +(function(createjs) { "use strict"; /** @@ -517,36 +523,36 @@ this.createjs = this.createjs||{}; createjs.ErrorEvent = createjs.promote(ErrorEvent, "Event"); -}()); +}(scope.createjs)); //############################################################################## // EventDispatcher.js //############################################################################## -this.createjs = this.createjs||{}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function() { +(function(createjs) { "use strict"; - // constructor: /** * EventDispatcher provides methods for managing queues of event listeners and dispatching events. * * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method. - * + * * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent. - * + * * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier - * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The + * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}. - * + * * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}} - * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also + * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener. * *

Example

@@ -568,20 +574,20 @@ this.createjs = this.createjs||{}; * instance.addEventListener("click", function(event) { * console.log(instance == this); // false, scope is ambiguous. * }); - * + * * instance.on("click", function(event) { * console.log(instance == this); // true, "on" uses dispatcher scope by default. * }); - * + * * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage scope. - * + * * * @class EventDispatcher * @constructor **/ function EventDispatcher() { - - + + // private properties: /** * @protected @@ -589,7 +595,7 @@ this.createjs = this.createjs||{}; * @type Object **/ this._listeners = null; - + /** * @protected * @property _captureListeners @@ -616,10 +622,10 @@ this.createjs = this.createjs||{}; // static public methods: /** * Static initializer to mix EventDispatcher methods into a target object or prototype. - * + * * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class * EventDispatcher.initialize(myObject); // add to a specific instance - * + * * @method initialize * @static * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a @@ -635,7 +641,7 @@ this.createjs = this.createjs||{}; target._dispatchEvent = p._dispatchEvent; target.willTrigger = p.willTrigger; }; - + // public methods: /** @@ -670,16 +676,16 @@ this.createjs = this.createjs||{}; else { arr.push(listener); } return listener; }; - + /** * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener * only run once, associate arbitrary data with the listener, and remove the listener. - * + * * This method works by creating an anonymous wrapper function and subscribing it with addEventListener. * The created anonymous function is returned for use with .removeEventListener (or .off). - * + * *

Example

- * + * * var listener = myBtn.on("click", handleClick, null, false, {count:3}); * function handleClick(evt, data) { * data.count -= 1; @@ -690,7 +696,7 @@ this.createjs = this.createjs||{}; * // alternately: evt.remove(); * } * } - * + * * @method on * @param {String} type The string type of the event. * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when @@ -742,7 +748,7 @@ this.createjs = this.createjs||{}; } } }; - + /** * A shortcut to the removeEventListener method, with the same parameters and return value. This is a companion to the * .on method. @@ -835,12 +841,12 @@ this.createjs = this.createjs||{}; var listeners = this._listeners, captureListeners = this._captureListeners; return !!((listeners && listeners[type]) || (captureListeners && captureListeners[type])); }; - + /** * Indicates whether there is at least one listener for the specified event type on this object or any of its * ancestors (parent, parent's parent, etc). A return value of true indicates that if a bubbling event of the * specified type is dispatched from this object, it will trigger at least one listener. - * + * * This is similar to {{#crossLink "EventDispatcher/hasEventListener"}}{{/crossLink}}, but it searches the entire * event flow for a listener, not just this object. * @method willTrigger @@ -880,7 +886,7 @@ this.createjs = this.createjs||{}; try { eventObj.currentTarget = this; } catch (e) {} try { eventObj.eventPhase = eventPhase; } catch (e) {} eventObj.removed = false; - + arr = arr.slice(); // to avoid issues with items being removed or added during the dispatch for (var i=0; irequired. The source can either be a - * string (recommended), or an HTML tag. - * This can also be an object, but in that case it has to include a type and be handled by a plugin. - * @property src - * @type {String} - * @default null - */ - this.src = null; - - /** - * The type file that is being loaded. The type of the file is usually inferred by the extension, but can also - * be set manually. This is helpful in cases where a file does not have an extension. - * @property type - * @type {String} - * @default null - */ - this.type = null; - - /** - * A string identifier which can be used to reference the loaded object. If none is provided, this will be - * automatically set to the {{#crossLink "src:property"}}{{/crossLink}}. - * @property id - * @type {String} - * @default null - */ - this.id = null; - - /** - * Determines if a manifest will maintain the order of this item, in relation to other items in the manifest - * that have also set the `maintainOrder` property to `true`. This only applies when the max connections has - * been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}). Everything with this - * property set to `false` will finish as it is loaded. Ordered items are combined with script tags loading in - * order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} is set to `true`. - * @property maintainOrder - * @type {Boolean} - * @default false - */ - this.maintainOrder = false; - - /** - * A callback used by JSONP requests that defines what global method to call when the JSONP content is loaded. - * @property callback - * @type {String} - * @default null - */ - this.callback = null; - - /** - * An arbitrary data object, which is included with the loaded object. - * @property data - * @type {Object} - * @default null - */ - this.data = null; - - /** - * The request method used for HTTP calls. Both {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} or - * {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} request types are supported, and are defined as - * constants on {{#crossLink "AbstractLoader"}}{{/crossLink}}. - * @property method - * @type {String} - * @default get - */ - this.method = createjs.LoadItem.GET; - - /** - * An object hash of name/value pairs to send to the server. - * @property values - * @type {Object} - * @default null - */ - this.values = null; - - /** - * An object hash of headers to attach to an XHR request. PreloadJS will automatically attach some default - * headers when required, including "Origin", "Content-Type", and "X-Requested-With". You may override the - * default headers by including them in your headers object. - * @property headers - * @type {Object} - * @default null - */ - this.headers = null; - - /** - * Enable credentials for XHR requests. - * @property withCredentials - * @type {Boolean} - * @default false - */ - this.withCredentials = false; - - /** - * Set the mime type of XHR-based requests. This is automatically set to "text/plain; charset=utf-8" for text - * based files (json, xml, text, css, js). - * @property mimeType - * @type {String} - * @default null - */ - this.mimeType = null; - - /** - * Sets the crossOrigin attribute for CORS-enabled images loading cross-domain. - * @property crossOrigin - * @type {boolean} - * @default Anonymous - */ - this.crossOrigin = null; - - /** - * The duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR - * (level one) loading, as XHR (level 2) provides its own timeout event. - * @property loadTimeout - * @type {Number} - * @default 8000 (8 seconds) - */ - this.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; - }; - - var p = LoadItem.prototype = {}; - var s = LoadItem; - - /** - * Default duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR - * (level one) loading, as XHR (level 2) provides its own timeout event. - * @property LOAD_TIMEOUT_DEFAULT - * @type {number} - * @static - */ - s.LOAD_TIMEOUT_DEFAULT = 8000; - - /** - * Create a LoadItem. - *
    - *
  • String-based items are converted to a LoadItem with a populated {{#crossLink "src:property"}}{{/crossLink}}.
  • - *
  • LoadItem instances are returned as-is
  • - *
  • Objects are returned with any needed properties added
  • - *
- * @method create - * @param {LoadItem|String|Object} value The load item value - * @returns {LoadItem|Object} - * @static - */ - s.create = function (value) { - if (typeof value == "string") { - var item = new LoadItem(); - item.src = value; - return item; - } else if (value instanceof s) { - return value; - } else if (value instanceof Object && value.src) { - if (value.loadTimeout == null) { - value.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; - } - return value; - } else { - throw new Error("Type not recognized."); - } - }; - - /** - * Provides a chainable shortcut method for setting a number of properties on the instance. - * - *

Example

- * - * var loadItem = new createjs.LoadItem().set({src:"image.png", maintainOrder:true}); - * - * @method set - * @param {Object} props A generic object containing properties to copy to the LoadItem instance. - * @return {LoadItem} Returns the instance the method is called on (useful for chaining calls.) - */ - p.set = function(props) { - for (var n in props) { this[n] = props[n]; } - return this; - }; - - createjs.LoadItem = s; - -}()); +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + + /** + * All loaders accept an item containing the properties defined in this class. If a raw object is passed instead, + * it will not be affected, but it must contain at least a {{#crossLink "src:property"}}{{/crossLink}} property. A + * string path or HTML tag is also acceptable, but it will be automatically converted to a LoadItem using the + * {{#crossLink "create"}}{{/crossLink}} method by {{#crossLink "AbstractLoader"}}{{/crossLink}} + * @class LoadItem + * @constructor + * @since 0.6.0 + */ + function LoadItem() { + /** + * The source of the file that is being loaded. This property is required. The source can either be a + * string (recommended), or an HTML tag. + * This can also be an object, but in that case it has to include a type and be handled by a plugin. + * @property src + * @type {String} + * @default null + */ + this.src = null; + + /** + * The type file that is being loaded. The type of the file is usually inferred by the extension, but can also + * be set manually. This is helpful in cases where a file does not have an extension. + * @property type + * @type {String} + * @default null + */ + this.type = null; + + /** + * A string identifier which can be used to reference the loaded object. If none is provided, this will be + * automatically set to the {{#crossLink "src:property"}}{{/crossLink}}. + * @property id + * @type {String} + * @default null + */ + this.id = null; + + /** + * Determines if a manifest will maintain the order of this item, in relation to other items in the manifest + * that have also set the `maintainOrder` property to `true`. This only applies when the max connections has + * been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}). Everything with this + * property set to `false` will finish as it is loaded. Ordered items are combined with script tags loading in + * order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} is set to `true`. + * @property maintainOrder + * @type {Boolean} + * @default false + */ + this.maintainOrder = false; + + /** + * A callback used by JSONP requests that defines what global method to call when the JSONP content is loaded. + * @property callback + * @type {String} + * @default null + */ + this.callback = null; + + /** + * An arbitrary data object, which is included with the loaded object. + * @property data + * @type {Object} + * @default null + */ + this.data = null; + + /** + * The request method used for HTTP calls. Both {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} or + * {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} request types are supported, and are defined as + * constants on {{#crossLink "AbstractLoader"}}{{/crossLink}}. + * @property method + * @type {String} + * @default get + */ + this.method = createjs.LoadItem.GET; + + /** + * An object hash of name/value pairs to send to the server. + * @property values + * @type {Object} + * @default null + */ + this.values = null; + + /** + * An object hash of headers to attach to an XHR request. PreloadJS will automatically attach some default + * headers when required, including "Origin", "Content-Type", and "X-Requested-With". You may override the + * default headers by including them in your headers object. + * @property headers + * @type {Object} + * @default null + */ + this.headers = null; + + /** + * Enable credentials for XHR requests. + * @property withCredentials + * @type {Boolean} + * @default false + */ + this.withCredentials = false; + + /** + * Set the mime type of XHR-based requests. This is automatically set to "text/plain; charset=utf-8" for text + * based files (json, xml, text, css, js). + * @property mimeType + * @type {String} + * @default null + */ + this.mimeType = null; + + /** + * Sets the crossOrigin attribute for CORS-enabled images loading cross-domain. + * @property crossOrigin + * @type {boolean} + * @default Anonymous + */ + this.crossOrigin = null; + + /** + * The duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR + * (level one) loading, as XHR (level 2) provides its own timeout event. + * @property loadTimeout + * @type {Number} + * @default 8000 (8 seconds) + */ + this.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; + }; + + var p = LoadItem.prototype = {}; + var s = LoadItem; + + /** + * Default duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR + * (level one) loading, as XHR (level 2) provides its own timeout event. + * @property LOAD_TIMEOUT_DEFAULT + * @type {number} + * @static + */ + s.LOAD_TIMEOUT_DEFAULT = 8000; + + /** + * Create a LoadItem. + *
    + *
  • String-based items are converted to a LoadItem with a populated {{#crossLink "src:property"}}{{/crossLink}}.
  • + *
  • LoadItem instances are returned as-is
  • + *
  • Objects are returned with any needed properties added
  • + *
+ * @method create + * @param {LoadItem|String|Object} value The load item value + * @returns {LoadItem|Object} + * @static + */ + s.create = function (value) { + if (typeof value == "string") { + var item = new LoadItem(); + item.src = value; + return item; + } else if (value instanceof s) { + return value; + } else if (value instanceof Object && value.src) { + if (value.loadTimeout == null) { + value.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; + } + return value; + } else { + throw new Error("Type not recognized."); + } + }; + + /** + * Provides a chainable shortcut method for setting a number of properties on the instance. + * + *

Example

+ * + * var loadItem = new createjs.LoadItem().set({src:"image.png", maintainOrder:true}); + * + * @method set + * @param {Object} props A generic object containing properties to copy to the LoadItem instance. + * @return {LoadItem} Returns the instance the method is called on (useful for chaining calls.) + */ + p.set = function(props) { + for (var n in props) { this[n] = props[n]; } + return this; + }; + + createjs.LoadItem = s; + +}(scope.createjs)); //############################################################################## // RequestUtils.js //############################################################################## -(function () { - - /** - * Utilities that assist with parsing load items, and determining file types, etc. - * @class RequestUtils - */ - var s = {}; - - /** - * The Regular Expression used to test file URLS for an absolute path. - * @property ABSOLUTE_PATH - * @type {RegExp} - * @static - */ - s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i; - - /** - * The Regular Expression used to test file URLS for a relative path. - * @property RELATIVE_PATH - * @type {RegExp} - * @static - */ - s.RELATIVE_PATT = (/^[./]*?\//i); - - /** - * The Regular Expression used to test file URLS for an extension. Note that URIs must already have the query string - * removed. - * @property EXTENSION_PATT - * @type {RegExp} - * @static - */ - s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i; - - /** - * Parse a file path to determine the information we need to work with it. Currently, PreloadJS needs to know: - *
    - *
  • If the path is absolute. Absolute paths start with a protocol (such as `http://`, `file://`, or - * `//networkPath`)
  • - *
  • If the path is relative. Relative paths start with `../` or `/path` (or similar)
  • - *
  • The file extension. This is determined by the filename with an extension. Query strings are dropped, and - * the file path is expected to follow the format `name.ext`.
  • - *
- * @method parseURI - * @param {String} path - * @returns {Object} An Object with an `absolute` and `relative` Boolean values, as well as an optional 'extension` - * property, which is the lowercase extension. - * @static - */ - s.parseURI = function (path) { - var info = {absolute: false, relative: false}; - if (path == null) { return info; } - - // Drop the query string - var queryIndex = path.indexOf("?"); - if (queryIndex > -1) { - path = path.substr(0, queryIndex); - } - - // Absolute - var match; - if (s.ABSOLUTE_PATT.test(path)) { - info.absolute = true; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + + /** + * Utilities that assist with parsing load items, and determining file types, etc. + * @class RequestUtils + */ + var s = {}; + + /** + * The Regular Expression used to test file URLS for an absolute path. + * @property ABSOLUTE_PATH + * @type {RegExp} + * @static + */ + s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i; + + /** + * The Regular Expression used to test file URLS for a relative path. + * @property RELATIVE_PATH + * @type {RegExp} + * @static + */ + s.RELATIVE_PATT = (/^[./]*?\//i); + + /** + * The Regular Expression used to test file URLS for an extension. Note that URIs must already have the query string + * removed. + * @property EXTENSION_PATT + * @type {RegExp} + * @static + */ + s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i; + + /** + * Parse a file path to determine the information we need to work with it. Currently, PreloadJS needs to know: + *
    + *
  • If the path is absolute. Absolute paths start with a protocol (such as `http://`, `file://`, or + * `//networkPath`)
  • + *
  • If the path is relative. Relative paths start with `../` or `/path` (or similar)
  • + *
  • The file extension. This is determined by the filename with an extension. Query strings are dropped, and + * the file path is expected to follow the format `name.ext`.
  • + *
+ * @method parseURI + * @param {String} path + * @returns {Object} An Object with an `absolute` and `relative` Boolean values, as well as an optional 'extension` + * property, which is the lowercase extension. + * @static + */ + s.parseURI = function (path) { + var info = {absolute: false, relative: false}; + if (path == null) { return info; } + + // Drop the query string + var queryIndex = path.indexOf("?"); + if (queryIndex > -1) { + path = path.substr(0, queryIndex); + } + + // Absolute + var match; + if (s.ABSOLUTE_PATT.test(path)) { + info.absolute = true; + + // Relative + } else if (s.RELATIVE_PATT.test(path)) { + info.relative = true; + } + + // Extension + if (match = path.match(s.EXTENSION_PATT)) { + info.extension = match[1].toLowerCase(); + } + return info; + }; + + /** + * Formats an object into a query string for either a POST or GET request. + * @method formatQueryString + * @param {Object} data The data to convert to a query string. + * @param {Array} [query] Existing name/value pairs to append on to this query. + * @static + */ + s.formatQueryString = function (data, query) { + if (data == null) { + throw new Error('You must specify data.'); + } + var params = []; + for (var n in data) { + params.push(n + '=' + escape(data[n])); + } + if (query) { + params = params.concat(query); + } + return params.join('&'); + }; + + /** + * A utility method that builds a file path using a source and a data object, and formats it into a new path. + * @method buildPath + * @param {String} src The source path to add values to. + * @param {Object} [data] Object used to append values to this request as a query string. Existing parameters on the + * path will be preserved. + * @returns {string} A formatted string that contains the path and the supplied parameters. + * @static + */ + s.buildPath = function (src, data) { + if (data == null) { + return src; + } + + var query = []; + var idx = src.indexOf('?'); + + if (idx != -1) { + var q = src.slice(idx + 1); + query = query.concat(q.split('&')); + } + + if (idx != -1) { + return src.slice(0, idx) + '?' + this._formatQueryString(data, query); + } else { + return src + '?' + this._formatQueryString(data, query); + } + }; + + /** + * @method isCrossDomain + * @param {LoadItem|Object} item A load item with a `src` property. + * @return {Boolean} If the load item is loading from a different domain than the current location. + * @static + */ + s.isCrossDomain = function (item) { + var target = document.createElement("a"); + target.href = item.src; + + var host = document.createElement("a"); + host.href = location.href; + + var crossdomain = (target.hostname != "") && + (target.port != host.port || + target.protocol != host.protocol || + target.hostname != host.hostname); + return crossdomain; + }; + + /** + * @method isLocal + * @param {LoadItem|Object} item A load item with a `src` property + * @return {Boolean} If the load item is loading from the "file:" protocol. Assume that the host must be local as + * well. + * @static + */ + s.isLocal = function (item) { + var target = document.createElement("a"); + target.href = item.src; + return target.hostname == "" && target.protocol == "file:"; + }; + + /** + * Determine if a specific type should be loaded as a binary file. Currently, only images and items marked + * specifically as "binary" are loaded as binary. Note that audio is not a binary type, as we can not play + * back using an audio tag if it is loaded as binary. Plugins can change the item type to binary to ensure they get + * a binary result to work with. Binary files are loaded using XHR2. Types are defined as static constants on + * {{#crossLink "AbstractLoader"}}{{/crossLink}}. + * @method isBinary + * @param {String} type The item type. + * @return {Boolean} If the specified type is binary. + * @static + */ + s.isBinary = function (type) { + switch (type) { + case createjs.AbstractLoader.IMAGE: + case createjs.AbstractLoader.BINARY: + return true; + default: + return false; + } + }; + + /** + * Check if item is a valid HTMLImageElement + * @method isImageTag + * @param {Object} item + * @returns {Boolean} + * @static + */ + s.isImageTag = function(item) { + return item instanceof HTMLImageElement; + }; + + /** + * Check if item is a valid HTMLAudioElement + * @method isAudioTag + * @param {Object} item + * @returns {Boolean} + * @static + */ + s.isAudioTag = function(item) { + if (window.HTMLAudioElement) { + return item instanceof HTMLAudioElement; + } else { + return false; + } + }; + + /** + * Check if item is a valid HTMLVideoElement + * @method isVideoTag + * @param {Object} item + * @returns {Boolean} + * @static + */ + s.isVideoTag = function(item) { + if (window.HTMLVideoElement) { + return item instanceof HTMLVideoElement; + } else { + return false; + } + }; + + /** + * Determine if a specific type is a text-based asset, and should be loaded as UTF-8. + * @method isText + * @param {String} type The item type. + * @return {Boolean} If the specified type is text. + * @static + */ + s.isText = function (type) { + switch (type) { + case createjs.AbstractLoader.TEXT: + case createjs.AbstractLoader.JSON: + case createjs.AbstractLoader.MANIFEST: + case createjs.AbstractLoader.XML: + case createjs.AbstractLoader.CSS: + case createjs.AbstractLoader.SVG: + case createjs.AbstractLoader.JAVASCRIPT: + case createjs.AbstractLoader.SPRITESHEET: + return true; + default: + return false; + } + }; + + /** + * Determine the type of the object using common extensions. Note that the type can be passed in with the load item + * if it is an unusual extension. + * @method getTypeByExtension + * @param {String} extension The file extension to use to determine the load type. + * @return {String} The determined load type (for example, AbstractLoader.IMAGE). Will return `null` if + * the type can not be determined by the extension. + * @static + */ + s.getTypeByExtension = function (extension) { + if (extension == null) { + return createjs.AbstractLoader.TEXT; + } + + switch (extension.toLowerCase()) { + case "jpeg": + case "jpg": + case "gif": + case "png": + case "webp": + case "bmp": + return createjs.AbstractLoader.IMAGE; + case "ogg": + case "mp3": + case "webm": + return createjs.AbstractLoader.SOUND; + case "mp4": + case "webm": + case "ts": + return createjs.AbstractLoader.VIDEO; + case "json": + return createjs.AbstractLoader.JSON; + case "xml": + return createjs.AbstractLoader.XML; + case "css": + return createjs.AbstractLoader.CSS; + case "js": + return createjs.AbstractLoader.JAVASCRIPT; + case 'svg': + return createjs.AbstractLoader.SVG; + default: + return createjs.AbstractLoader.TEXT; + } + }; + + createjs.RequestUtils = s; + +}(scope.createjs)); - // Relative - } else if (s.RELATIVE_PATT.test(path)) { - info.relative = true; - } +//############################################################################## +// AbstractLoader.js +//############################################################################## - // Extension - if (match = path.match(s.EXTENSION_PATT)) { - info.extension = match[1].toLowerCase(); - } - return info; - }; - - /** - * Formats an object into a query string for either a POST or GET request. - * @method formatQueryString - * @param {Object} data The data to convert to a query string. - * @param {Array} [query] Existing name/value pairs to append on to this query. - * @static - */ - s.formatQueryString = function (data, query) { - if (data == null) { - throw new Error('You must specify data.'); - } - var params = []; - for (var n in data) { - params.push(n + '=' + escape(data[n])); - } - if (query) { - params = params.concat(query); - } - return params.join('&'); - }; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + +// constructor + /** + * The base loader, which defines all the generic methods, properties, and events. All loaders extend this class, + * including the {{#crossLink "LoadQueue"}}{{/crossLink}}. + * @class AbstractLoader + * @param {LoadItem|object|string} loadItem The item to be loaded. + * @param {Boolean} [preferXHR] Determines if the LoadItem should try and load using XHR, or take a + * tag-based approach, which can be better in cross-domain situations. Not all loaders can load using one or the + * other, so this is a suggested directive. + * @param {String} [type] The type of loader. Loader types are defined as constants on the AbstractLoader class, + * such as {{#crossLink "IMAGE:property"}}{{/crossLink}}, {{#crossLink "CSS:property"}}{{/crossLink}}, etc. + * @extends EventDispatcher + */ + function AbstractLoader(loadItem, preferXHR, type) { + this.EventDispatcher_constructor(); + + // public properties + /** + * If the loader has completed loading. This provides a quick check, but also ensures that the different approaches + * used for loading do not pile up resulting in more than one `complete` {{#crossLink "Event"}}{{/crossLink}}. + * @property loaded + * @type {Boolean} + * @default false + */ + this.loaded = false; + + /** + * Determine if the loader was canceled. Canceled loads will not fire complete events. Note that this property + * is readonly, so {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "LoadQueue/close"}}{{/crossLink}} + * instead. + * @property canceled + * @type {Boolean} + * @default false + * @readonly + */ + this.canceled = false; + + /** + * The current load progress (percentage) for this item. This will be a number between 0 and 1. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.loadFile("largeImage.png"); + * queue.on("progress", function() { + * console.log("Progress:", queue.progress, event.progress); + * }); + * + * @property progress + * @type {Number} + * @default 0 + */ + this.progress = 0; + + /** + * The type of item this loader will load. See {{#crossLink "AbstractLoader"}}{{/crossLink}} for a full list of + * supported types. + * @property type + * @type {String} + */ + this.type = type; + + /** + * A formatter function that converts the loaded raw result into the final result. For example, the JSONLoader + * converts a string of text into a JavaScript object. Not all loaders have a resultFormatter, and this property + * can be overridden to provide custom formatting. + * + * Optionally, a resultFormatter can return a callback function in cases where the formatting needs to be + * asynchronous, such as creating a new image. The callback function is passed 2 parameters, which are callbacks + * to handle success and error conditions in the resultFormatter. Note that the resultFormatter method is + * called in the current scope, as well as the success and error callbacks. + * + *

Example asynchronous resultFormatter

+ * + * function _formatResult(loader) { + * return function(success, error) { + * if (errorCondition) { error(errorDetailEvent); } + * success(result); + * } + * } + * @property resultFormatter + * @type {Function} + * @default null + */ + this.resultFormatter = null; + + // protected properties + /** + * The {{#crossLink "LoadItem"}}{{/crossLink}} this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}}, + * but will be available on loaders such as {{#crossLink "XMLLoader"}}{{/crossLink}} and {{#crossLink "ImageLoader"}}{{/crossLink}}. + * @property _item + * @type {LoadItem|Object} + * @private + */ + if (loadItem) { + this._item = createjs.LoadItem.create(loadItem); + } else { + this._item = null; + } + + /** + * Whether the loader will try and load content using XHR (true) or HTML tags (false). + * @property _preferXHR + * @type {Boolean} + * @private + */ + this._preferXHR = preferXHR; + + /** + * The loaded result after it is formatted by an optional {{#crossLink "resultFormatter"}}{{/crossLink}}. For + * items that are not formatted, this will be the same as the {{#crossLink "_rawResult:property"}}{{/crossLink}}. + * The result is accessed using the {{#crossLink "getResult"}}{{/crossLink}} method. + * @property _result + * @type {Object|String} + * @private + */ + this._result = null; + + /** + * The loaded result before it is formatted. The rawResult is accessed using the {{#crossLink "getResult"}}{{/crossLink}} + * method, and passing `true`. + * @property _rawResult + * @type {Object|String} + * @private + */ + this._rawResult = null; + + /** + * A list of items that loaders load behind the scenes. This does not include the main item the loader is + * responsible for loading. Examples of loaders that have sub-items include the {{#crossLink "SpriteSheetLoader"}}{{/crossLink}} and + * {{#crossLink "ManifestLoader"}}{{/crossLink}}. + * @property _loadItems + * @type {null} + * @protected + */ + this._loadedItems = null; + + /** + * The attribute the items loaded using tags use for the source. + * @type {string} + * @default null + * @private + */ + this._tagSrcAttribute = null; + + /** + * An HTML tag (or similar) that a loader may use to load HTML content, such as images, scripts, etc. + * @property _tag + * @type {Object} + * @private + */ + this._tag = null; + }; + + var p = createjs.extend(AbstractLoader, createjs.EventDispatcher); + var s = AbstractLoader; + + // TODO: deprecated + // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. + + + /** + * Defines a POST request, use for a method value when loading data. + * @property POST + * @type {string} + * @default post + * @static + */ + s.POST = "POST"; + + /** + * Defines a GET request, use for a method value when loading data. + * @property GET + * @type {string} + * @default get + * @static + */ + s.GET = "GET"; + + /** + * The preload type for generic binary types. Note that images are loaded as binary files when using XHR. + * @property BINARY + * @type {String} + * @default binary + * @static + * @since 0.6.0 + */ + s.BINARY = "binary"; + + /** + * The preload type for css files. CSS files are loaded using a <link> when loaded with XHR, or a + * <style> tag when loaded with tags. + * @property CSS + * @type {String} + * @default css + * @static + * @since 0.6.0 + */ + s.CSS = "css"; + + /** + * The preload type for image files, usually png, gif, or jpg/jpeg. Images are loaded into an <image> tag. + * @property IMAGE + * @type {String} + * @default image + * @static + * @since 0.6.0 + */ + s.IMAGE = "image"; + + /** + * The preload type for javascript files, usually with the "js" file extension. JavaScript files are loaded into a + * <script> tag. + * + * Since version 0.4.1+, due to how tag-loaded scripts work, all JavaScript files are automatically injected into + * the body of the document to maintain parity between XHR and tag-loaded scripts. In version 0.4.0 and earlier, + * only tag-loaded scripts are injected. + * @property JAVASCRIPT + * @type {String} + * @default javascript + * @static + * @since 0.6.0 + */ + s.JAVASCRIPT = "javascript"; + + /** + * The preload type for json files, usually with the "json" file extension. JSON data is loaded and parsed into a + * JavaScript object. Note that if a `callback` is present on the load item, the file will be loaded with JSONP, + * no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to, and the JSON + * must contain a matching wrapper function. + * @property JSON + * @type {String} + * @default json + * @static + * @since 0.6.0 + */ + s.JSON = "json"; + + /** + * The preload type for jsonp files, usually with the "json" file extension. JSON data is loaded and parsed into a + * JavaScript object. You are required to pass a callback parameter that matches the function wrapper in the JSON. + * Note that JSONP will always be used if there is a callback present, no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} + * property is set to. + * @property JSONP + * @type {String} + * @default jsonp + * @static + * @since 0.6.0 + */ + s.JSONP = "jsonp"; + + /** + * The preload type for json-based manifest files, usually with the "json" file extension. The JSON data is loaded + * and parsed into a JavaScript object. PreloadJS will then look for a "manifest" property in the JSON, which is an + * Array of files to load, following the same format as the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * method. If a "callback" is specified on the manifest object, then it will be loaded using JSONP instead, + * regardless of what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to. + * @property MANIFEST + * @type {String} + * @default manifest + * @static + * @since 0.6.0 + */ + s.MANIFEST = "manifest"; + + /** + * The preload type for sound files, usually mp3, ogg, or wav. When loading via tags, audio is loaded into an + * <audio> tag. + * @property SOUND + * @type {String} + * @default sound + * @static + * @since 0.6.0 + */ + s.SOUND = "sound"; + + /** + * The preload type for video files, usually mp4, ts, or ogg. When loading via tags, video is loaded into an + * <video> tag. + * @property VIDEO + * @type {String} + * @default video + * @static + * @since 0.6.0 + */ + s.VIDEO = "video"; + + /** + * The preload type for SpriteSheet files. SpriteSheet files are JSON files that contain string image paths. + * @property SPRITESHEET + * @type {String} + * @default spritesheet + * @static + * @since 0.6.0 + */ + s.SPRITESHEET = "spritesheet"; + + /** + * The preload type for SVG files. + * @property SVG + * @type {String} + * @default svg + * @static + * @since 0.6.0 + */ + s.SVG = "svg"; + + /** + * The preload type for text files, which is also the default file type if the type can not be determined. Text is + * loaded as raw text. + * @property TEXT + * @type {String} + * @default text + * @static + * @since 0.6.0 + */ + s.TEXT = "text"; + + /** + * The preload type for xml files. XML is loaded into an XML document. + * @property XML + * @type {String} + * @default xml + * @static + * @since 0.6.0 + */ + s.XML = "xml"; + +// Events + /** + * The {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when the overall progress changes. Prior to + * version 0.6.0, this was just a regular {{#crossLink "Event"}}{{/crossLink}}. + * @event progress + * @since 0.3.0 + */ + + /** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a load starts. + * @event loadstart + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @since 0.3.1 + */ + + /** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the entire queue has been loaded. + * @event complete + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @since 0.3.0 + */ + + /** + * The {{#crossLink "ErrorEvent"}}{{/crossLink}} that is fired when the loader encounters an error. If the error was + * encountered by a file, the event will contain the item that caused the error. Prior to version 0.6.0, this was + * just a regular {{#crossLink "Event"}}{{/crossLink}}. + * @event error + * @since 0.3.0 + */ + + /** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the loader encounters an internal file load error. + * This enables loaders to maintain internal queues, and surface file load errors. + * @event fileerror + * @param {Object} target The object that dispatched the event. + * @param {String} type The even type ("fileerror") + * @param {LoadItem|object} The item that encountered the error + * @since 0.6.0 + */ + + /** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a loader internally loads a file. This enables + * loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} to maintain internal {{#crossLink "LoadQueue"}}{{/crossLink}}s + * and notify when they have loaded a file. The {{#crossLink "LoadQueue"}}{{/crossLink}} class dispatches a + * slightly different {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event. + * @event fileload + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type ("fileload") + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a `src` property. + * @param {Object} result The HTML tag or parsed result of the loaded item. + * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted + * to a usable object. + * @since 0.6.0 + */ + + /** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired after the internal request is created, but before a load. + * This allows updates to the loader for specific loading needs, such as binary or XHR image loading. + * @event initialize + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type ("initialize") + * @param {AbstractLoader} loader The loader that has been initialized. + */ + + + /** + * Get a reference to the manifest item that is loaded by this loader. In some cases this will be the value that was + * passed into {{#crossLink "LoadQueue"}}{{/crossLink}} using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. However if only a String path was passed in, then it will + * be a {{#crossLink "LoadItem"}}{{/crossLink}}. + * @method getItem + * @return {Object} The manifest item that this loader is responsible for loading. + * @since 0.6.0 + */ + p.getItem = function () { + return this._item; + }; + + /** + * Get a reference to the content that was loaded by the loader (only available after the {{#crossLink "complete:event"}}{{/crossLink}} + * event is dispatched. + * @method getResult + * @param {Boolean} [raw=false] Determines if the returned result will be the formatted content, or the raw loaded + * data (if it exists). + * @return {Object} + * @since 0.6.0 + */ + p.getResult = function (raw) { + return raw ? this._rawResult : this._result; + }; + + /** + * Return the `tag` this object creates or uses for loading. + * @method getTag + * @return {Object} The tag instance + * @since 0.6.0 + */ + p.getTag = function () { + return this._tag; + }; + + /** + * Set the `tag` this item uses for loading. + * @method setTag + * @param {Object} tag The tag instance + * @since 0.6.0 + */ + p.setTag = function(tag) { + this._tag = tag; + }; + + /** + * Begin loading the item. This method is required when using a loader by itself. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.on("complete", handleComplete); + * queue.loadManifest(fileArray, false); // Note the 2nd argument that tells the queue not to start loading yet + * queue.load(); + * + * @method load + */ + p.load = function () { + this._createRequest(); + + this._request.on("complete", this, this); + this._request.on("progress", this, this); + this._request.on("loadStart", this, this); + this._request.on("abort", this, this); + this._request.on("timeout", this, this); + this._request.on("error", this, this); + + var evt = new createjs.Event("initialize"); + evt.loader = this._request; + this.dispatchEvent(evt); + + this._request.load(); + }; + + /** + * Close the the item. This will stop any open requests (although downloads using HTML tags may still continue in + * the background), but events will not longer be dispatched. + * @method cancel + */ + p.cancel = function () { + this.canceled = true; + this.destroy(); + }; + + /** + * Clean up the loader. + * @method destroy + */ + p.destroy = function() { + if (this._request) { + this._request.removeAllEventListeners(); + this._request.destroy(); + } + + this._request = null; + + this._item = null; + this._rawResult = null; + this._result = null; + + this._loadItems = null; + + this.removeAllEventListeners(); + }; + + /** + * Get any items loaded internally by the loader. The enables loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} + * to expose items it loads internally. + * @method getLoadedItems + * @return {Array} A list of the items loaded by the loader. + * @since 0.6.0 + */ + p.getLoadedItems = function () { + return this._loadedItems; + }; + + + // Private methods + /** + * Create an internal request used for loading. By default, an {{#crossLink "XHRRequest"}}{{/crossLink}} or + * {{#crossLink "TagRequest"}}{{/crossLink}} is created, depending on the value of {{#crossLink "preferXHR:property"}}{{/crossLink}}. + * Other loaders may override this to use different request types, such as {{#crossLink "ManifestLoader"}}{{/crossLink}}, + * which uses {{#crossLink "JSONLoader"}}{{/crossLink}} or {{#crossLink "JSONPLoader"}}{{/crossLink}} under the hood. + * @method _createRequest + * @protected + */ + p._createRequest = function() { + if (!this._preferXHR) { + this._request = new createjs.TagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); + } else { + this._request = new createjs.XHRRequest(this._item); + } + }; + + /** + * Create the HTML tag used for loading. This method does nothing by default, and needs to be implemented + * by loaders that require tag loading. + * @method _createTag + * @param {String} src The tag source + * @return {HTMLElement} The tag that was created + * @protected + */ + p._createTag = function(src) { return null; }; + + /** + * Dispatch a loadstart {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendLoadStart + * @protected + */ + p._sendLoadStart = function () { + if (this._isCanceled()) { return; } + this.dispatchEvent("loadstart"); + }; + + /** + * Dispatch a {{#crossLink "ProgressEvent"}}{{/crossLink}}. + * @method _sendProgress + * @param {Number | Object} value The progress of the loaded item, or an object containing loaded + * and total properties. + * @protected + */ + p._sendProgress = function (value) { + if (this._isCanceled()) { return; } + var event = null; + if (typeof(value) == "number") { + this.progress = value; + event = new createjs.ProgressEvent(this.progress); + } else { + event = value; + this.progress = value.loaded / value.total; + event.progress = this.progress; + if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; } + } + this.hasEventListener("progress") && this.dispatchEvent(event); + }; + + /** + * Dispatch a complete {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event + * @method _sendComplete + * @protected + */ + p._sendComplete = function () { + if (this._isCanceled()) { return; } + + this.loaded = true; + + var event = new createjs.Event("complete"); + event.rawResult = this._rawResult; + + if (this._result != null) { + event.result = this._result; + } + + this.dispatchEvent(event); + }; + + /** + * Dispatch an error {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendError + * @param {ErrorEvent} event The event object containing specific error properties. + * @protected + */ + p._sendError = function (event) { + if (this._isCanceled() || !this.hasEventListener("error")) { return; } + if (event == null) { + event = new createjs.ErrorEvent("PRELOAD_ERROR_EMPTY"); // TODO: Populate error + } + this.dispatchEvent(event); + }; + + /** + * Determine if the load has been canceled. This is important to ensure that method calls or asynchronous events + * do not cause issues after the queue has been cleaned up. + * @method _isCanceled + * @return {Boolean} If the loader has been canceled. + * @protected + */ + p._isCanceled = function () { + if (window.createjs == null || this.canceled) { + return true; + } + return false; + }; + + /** + * A custom result formatter function, which is called just before a request dispatches its complete event. Most + * loader types already have an internal formatter, but this can be user-overridden for custom formatting. The + * formatted result will be available on Loaders using {{#crossLink "getResult"}}{{/crossLink}}, and passing `true`. + * @property resultFormatter + * @type Function + * @return {Object} The formatted result + * @since 0.6.0 + */ + p.resultFormatter = null; + + /** + * Handle events from internal requests. By default, loaders will handle, and redispatch the necessary events, but + * this method can be overridden for custom behaviours. + * @method handleEvent + * @param {Event} event The event that the internal request dispatches. + * @protected + * @since 0.6.0 + */ + p.handleEvent = function (event) { + switch (event.type) { + case "complete": + this._rawResult = event.target._response; + var result = this.resultFormatter && this.resultFormatter(this); + if (result instanceof Function) { + result.call(this, + createjs.proxy(this._resultFormatSuccess, this), + createjs.proxy(this._resultFormatFailed, this) + ); + } else { + this._result = result || this._rawResult; + this._sendComplete(); + } + break; + case "progress": + this._sendProgress(event); + break; + case "error": + this._sendError(event); + break; + case "loadstart": + this._sendLoadStart(); + break; + case "abort": + case "timeout": + if (!this._isCanceled()) { + this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_" + event.type.toUpperCase() + "_ERROR")); + } + break; + } + }; + + /** + * The "success" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous + * functions. + * @method _resultFormatSuccess + * @param {Object} result The formatted result + * @private + */ + p._resultFormatSuccess = function (result) { + this._result = result; + this._sendComplete(); + }; + + /** + * The "error" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous + * functions. + * @method _resultFormatSuccess + * @param {Object} error The error event + * @private + */ + p._resultFormatFailed = function (event) { + this._sendError(event); + }; + + /** + * @method buildPath + * @protected + * @deprecated Use the {{#crossLink "RequestUtils"}}{{/crossLink}} method {{#crossLink "RequestUtils/buildPath"}}{{/crossLink}} + * instead. + */ + p.buildPath = function (src, data) { + return createjs.RequestUtils.buildPath(src, data); + }; + + /** + * @method toString + * @return {String} a string representation of the instance. + */ + p.toString = function () { + return "[PreloadJS AbstractLoader]"; + }; + + createjs.AbstractLoader = createjs.promote(AbstractLoader, "EventDispatcher"); + +}(scope.createjs)); - /** - * A utility method that builds a file path using a source and a data object, and formats it into a new path. - * @method buildPath - * @param {String} src The source path to add values to. - * @param {Object} [data] Object used to append values to this request as a query string. Existing parameters on the - * path will be preserved. - * @returns {string} A formatted string that contains the path and the supplied parameters. - * @static - */ - s.buildPath = function (src, data) { - if (data == null) { - return src; - } +//############################################################################## +// AbstractMediaLoader.js +//############################################################################## + +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + + // constructor + /** + * The AbstractMediaLoader is a base class that handles some of the shared methods and properties of loaders that + * handle HTML media elements, such as Video and Audio. + * @class AbstractMediaLoader + * @param {LoadItem|Object} loadItem + * @param {Boolean} preferXHR + * @param {String} type The type of media to load. Usually "video" or "audio". + * @extends AbstractLoader + * @constructor + */ + function AbstractMediaLoader(loadItem, preferXHR, type) { + this.AbstractLoader_constructor(loadItem, preferXHR, type); + + // public properties + this.resultFormatter = this._formatResult; + + // protected properties + this._tagSrcAttribute = "src"; + + this.on("initialize", this._updateXHR, this); + }; + + var p = createjs.extend(AbstractMediaLoader, createjs.AbstractLoader); + + // static properties + // public methods + p.load = function () { + // TagRequest will handle most of this, but Sound / Video need a few custom properties, so just handle them here. + if (!this._tag) { + this._tag = this._createTag(this._item.src); + } + + this._tag.preload = "auto"; + this._tag.load(); + + this.AbstractLoader_load(); + }; + + // protected methods + /** + * Creates a new tag for loading if it doesn't exist yet. + * @method _createTag + * @private + */ + p._createTag = function () {}; + + + p._createRequest = function() { + if (!this._preferXHR) { + this._request = new createjs.MediaTagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); + } else { + this._request = new createjs.XHRRequest(this._item); + } + }; + + // protected methods + /** + * Before the item loads, set its mimeType and responseType. + * @property _updateXHR + * @param {Event} event + * @private + */ + p._updateXHR = function (event) { + // Only exists for XHR + if (event.loader.setResponseType) { + event.loader.setResponseType("blob"); + } + }; + + /** + * The result formatter for media files. + * @method _formatResult + * @param {AbstractLoader} loader + * @returns {HTMLVideoElement|HTMLAudioElement} + * @private + */ + p._formatResult = function (loader) { + this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler); + this._tag.onstalled = null; + if (this._preferXHR) { + var URL = window.URL || window.webkitURL; + var result = loader.getResult(true); + + loader.getTag().src = URL.createObjectURL(result); + } + return loader.getTag(); + }; + + createjs.AbstractMediaLoader = createjs.promote(AbstractMediaLoader, "AbstractLoader"); + +}(scope.createjs)); - var query = []; - var idx = src.indexOf('?'); +//############################################################################## +// AbstractRequest.js +//############################################################################## - if (idx != -1) { - var q = src.slice(idx + 1); - query = query.concat(q.split('&')); - } +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; - if (idx != -1) { - return src.slice(0, idx) + '?' + this._formatQueryString(data, query); - } else { - return src + '?' + this._formatQueryString(data, query); - } - }; +(function (createjs) { + "use strict"; /** - * @method isCrossDomain - * @param {LoadItem|Object} item A load item with a `src` property. - * @return {Boolean} If the load item is loading from a different domain than the current location. - * @static + * A base class for actual data requests, such as {{#crossLink "XHRRequest"}}{{/crossLink}}, {{#crossLink "TagRequest"}}{{/crossLink}}, + * and {{#crossLink "MediaRequest"}}{{/crossLink}}. PreloadJS loaders will typically use a data loader under the + * hood to get data. + * @class AbstractRequest + * @param {LoadItem} item + * @constructor */ - s.isCrossDomain = function (item) { - var target = document.createElement("a"); - target.href = item.src; - - var host = document.createElement("a"); - host.href = location.href; - - var crossdomain = (target.hostname != "") && - (target.port != host.port || - target.protocol != host.protocol || - target.hostname != host.hostname); - return crossdomain; + var AbstractRequest = function (item) { + this._item = item; }; + var p = createjs.extend(AbstractRequest, createjs.EventDispatcher); + + // public methods /** - * @method isLocal - * @param {LoadItem|Object} item A load item with a `src` property - * @return {Boolean} If the load item is loading from the "file:" protocol. Assume that the host must be local as - * well. - * @static + * Begin a load. + * @method load */ - s.isLocal = function (item) { - var target = document.createElement("a"); - target.href = item.src; - return target.hostname == "" && target.protocol == "file:"; - }; + p.load = function() {}; /** - * Determine if a specific type should be loaded as a binary file. Currently, only images and items marked - * specifically as "binary" are loaded as binary. Note that audio is not a binary type, as we can not play - * back using an audio tag if it is loaded as binary. Plugins can change the item type to binary to ensure they get - * a binary result to work with. Binary files are loaded using XHR2. Types are defined as static constants on - * {{#crossLink "AbstractLoader"}}{{/crossLink}}. - * @method isBinary - * @param {String} type The item type. - * @return {Boolean} If the specified type is binary. - * @static + * Clean up a request. + * @method destroy */ - s.isBinary = function (type) { - switch (type) { - case createjs.AbstractLoader.IMAGE: - case createjs.AbstractLoader.BINARY: - return true; - default: - return false; - } - }; + p.destroy = function() {}; /** - * Check if item is a valid HTMLImageElement - * @method isImageTag - * @param {Object} item - * @returns {Boolean} - * @static + * Cancel an in-progress request. + * @method cancel */ - s.isImageTag = function(item) { - return item instanceof HTMLImageElement; - }; + p.cancel = function() {}; + + createjs.AbstractRequest = createjs.promote(AbstractRequest, "EventDispatcher"); + +}(scope.createjs)); + +//############################################################################## +// TagRequest.js +//############################################################################## + +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + + // constructor + /** + * An {{#crossLink "AbstractRequest"}}{{/crossLink}} that loads HTML tags, such as images and scripts. + * @class TagRequest + * @param {LoadItem} loadItem + * @param {HTMLElement} tag + * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. + */ + function TagRequest(loadItem, tag, srcAttribute) { + this.AbstractRequest_constructor(loadItem); + + // protected properties + /** + * The HTML tag instance that is used to load. + * @property _tag + * @type {HTMLElement} + * @protected + */ + this._tag = tag; + + /** + * The tag attribute that specifies the source, such as "src", "href", etc. + * @property _tagSrcAttribute + * @type {String} + * @protected + */ + this._tagSrcAttribute = srcAttribute; + + /** + * A method closure used for handling the tag load event. + * @property _loadedHandler + * @type {Function} + * @private + */ + this._loadedHandler = createjs.proxy(this._handleTagComplete, this); + + /** + * Determines if the element was added to the DOM automatically by PreloadJS, so it can be cleaned up after. + * @property _addedToDOM + * @type {Boolean} + * @private + */ + this._addedToDOM = false; + + /** + * Determines what the tags initial style.visibility was, so we can set it correctly after a load. + * + * @type {null} + * @private + */ + this._startTagVisibility = null; + }; + + var p = createjs.extend(TagRequest, createjs.AbstractRequest); + + // public methods + p.load = function () { + this._tag.onload = createjs.proxy(this._handleTagComplete, this); + this._tag.onreadystatechange = createjs.proxy(this._handleReadyStateChange, this); + this._tag.onerror = createjs.proxy(this._handleError, this); + + var evt = new createjs.Event("initialize"); + evt.loader = this._tag; + + this.dispatchEvent(evt); + + this._hideTag(); + + this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); + + this._tag[this._tagSrcAttribute] = this._item.src; + + // wdg:: Append the tag AFTER setting the src, or SVG loading on iOS will fail. + if (this._tag.parentNode == null) { + window.document.body.appendChild(this._tag); + this._addedToDOM = true; + } + }; + + p.destroy = function() { + this._clean(); + this._tag = null; + + this.AbstractRequest_destroy(); + }; + + // private methods + /** + * Handle the readyStateChange event from a tag. We need this in place of the `onload` callback (mainly SCRIPT + * and LINK tags), but other cases may exist. + * @method _handleReadyStateChange + * @private + */ + p._handleReadyStateChange = function () { + clearTimeout(this._loadTimeout); + // This is strictly for tags in browsers that do not support onload. + var tag = this._tag; + + // Complete is for old IE support. + if (tag.readyState == "loaded" || tag.readyState == "complete") { + this._handleTagComplete(); + } + }; + + /** + * Handle any error events from the tag. + * @method _handleError + * @protected + */ + p._handleError = function() { + this._clean(); + this.dispatchEvent("error"); + }; + + /** + * Handle the tag's onload callback. + * @method _handleTagComplete + * @private + */ + p._handleTagComplete = function () { + this._rawResult = this._tag; + this._result = this.resultFormatter && this.resultFormatter(this) || this._rawResult; + + this._clean(); + this._showTag(); + + this.dispatchEvent("complete"); + }; + + /** + * The tag request has not loaded within the time specified in loadTimeout. + * @method _handleError + * @param {Object} event The XHR error event. + * @private + */ + p._handleTimeout = function () { + this._clean(); + this.dispatchEvent(new createjs.Event("timeout")); + }; + + /** + * Remove event listeners, but don't destroy the request object + * @method _clean + * @private + */ + p._clean = function() { + this._tag.onload = null; + this._tag.onreadystatechange = null; + this._tag.onerror = null; + if (this._addedToDOM && this._tag.parentNode != null) { + this._tag.parentNode.removeChild(this._tag); + } + clearTimeout(this._loadTimeout); + }; + + p._hideTag = function() { + this._startTagVisibility = this._tag.style.visibility; + this._tag.style.visibility = "hidden"; + }; + + p._showTag = function() { + this._tag.style.visibility = this._startTagVisibility; + }; + + /** + * Handle a stalled audio event. The main place this happens is with HTMLAudio in Chrome when playing back audio + * that is already in a load, but not complete. + * @method _handleStalled + * @private + */ + p._handleStalled = function () { + //Ignore, let the timeout take care of it. Sometimes its not really stopped. + }; + + createjs.TagRequest = createjs.promote(TagRequest, "AbstractRequest"); + +}(scope.createjs)); + +//############################################################################## +// MediaTagRequest.js +//############################################################################## + +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + // constructor /** - * Check if item is a valid HTMLAudioElement - * @method isAudioTag - * @param {Object} item - * @returns {Boolean} - * @static + * An {{#crossLink "TagRequest"}}{{/crossLink}} that loads HTML tags for video and audio. + * @class MediaTagRequest + * @param {LoadItem} loadItem + * @param {HTMLAudioElement|HTMLVideoElement} tag + * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. + * @constructor */ - s.isAudioTag = function(item) { - if (window.HTMLAudioElement) { - return item instanceof HTMLAudioElement; - } else { - return false; - } + function MediaTagRequest(loadItem, tag, srcAttribute) { + this.AbstractRequest_constructor(loadItem); + + // protected properties + this._tag = tag; + this._tagSrcAttribute = srcAttribute; + this._loadedHandler = createjs.proxy(this._handleTagComplete, this); }; - /** - * Check if item is a valid HTMLVideoElement - * @method isVideoTag - * @param {Object} item - * @returns {Boolean} - * @static - */ - s.isVideoTag = function(item) { - if (window.HTMLVideoElement) { - return item instanceof HTMLVideoElement; - } else { - return false; - } + var p = createjs.extend(MediaTagRequest, createjs.TagRequest); + var s = MediaTagRequest; + + // public methods + p.load = function () { + var sc = createjs.proxy(this._handleStalled, this); + this._stalledCallback = sc; + + var pc = createjs.proxy(this._handleProgress, this); + this._handleProgress = pc; + + this._tag.addEventListener("stalled", sc); + this._tag.addEventListener("progress", pc); + + // This will tell us when audio is buffered enough to play through, but not when its loaded. + // The tag doesn't keep loading in Chrome once enough has buffered, and we have decided that behaviour is sufficient. + this._tag.addEventListener && this._tag.addEventListener("canplaythrough", this._loadedHandler, false); // canplaythrough callback doesn't work in Chrome, so we use an event. + + this.TagRequest_load(); }; - /** - * Determine if a specific type is a text-based asset, and should be loaded as UTF-8. - * @method isText - * @param {String} type The item type. - * @return {Boolean} If the specified type is text. - * @static - */ - s.isText = function (type) { - switch (type) { - case createjs.AbstractLoader.TEXT: - case createjs.AbstractLoader.JSON: - case createjs.AbstractLoader.MANIFEST: - case createjs.AbstractLoader.XML: - case createjs.AbstractLoader.CSS: - case createjs.AbstractLoader.SVG: - case createjs.AbstractLoader.JAVASCRIPT: - case createjs.AbstractLoader.SPRITESHEET: - return true; - default: - return false; + // private methods + p._handleReadyStateChange = function () { + clearTimeout(this._loadTimeout); + // This is strictly for tags in browsers that do not support onload. + var tag = this._tag; + + // Complete is for old IE support. + if (tag.readyState == "loaded" || tag.readyState == "complete") { + this._handleTagComplete(); } }; + p._handleStalled = function () { + //Ignore, let the timeout take care of it. Sometimes its not really stopped. + }; + /** - * Determine the type of the object using common extensions. Note that the type can be passed in with the load item - * if it is an unusual extension. - * @method getTypeByExtension - * @param {String} extension The file extension to use to determine the load type. - * @return {String} The determined load type (for example, AbstractLoader.IMAGE). Will return `null` if - * the type can not be determined by the extension. - * @static + * An XHR request has reported progress. + * @method _handleProgress + * @param {Object} event The XHR progress event. + * @private */ - s.getTypeByExtension = function (extension) { - if (extension == null) { - return createjs.AbstractLoader.TEXT; + p._handleProgress = function (event) { + if (!event || event.loaded > 0 && event.total == 0) { + return; // Sometimes we get no "total", so just ignore the progress event. } - switch (extension.toLowerCase()) { - case "jpeg": - case "jpg": - case "gif": - case "png": - case "webp": - case "bmp": - return createjs.AbstractLoader.IMAGE; - case "ogg": - case "mp3": - case "webm": - return createjs.AbstractLoader.SOUND; - case "mp4": - case "webm": - case "ts": - return createjs.AbstractLoader.VIDEO; - case "json": - return createjs.AbstractLoader.JSON; - case "xml": - return createjs.AbstractLoader.XML; - case "css": - return createjs.AbstractLoader.CSS; - case "js": - return createjs.AbstractLoader.JAVASCRIPT; - case 'svg': - return createjs.AbstractLoader.SVG; - default: - return createjs.AbstractLoader.TEXT; - } + var newEvent = new createjs.ProgressEvent(event.loaded, event.total); + this.dispatchEvent(newEvent); + }; + + // protected methods + p._clean = function () { + this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler); + this._tag.removeEventListener("stalled", this._stalledCallback); + this._tag.removeEventListener("progress", this._progressCallback); + + this.TagRequest__clean(); }; - createjs.RequestUtils = s; + createjs.MediaTagRequest = createjs.promote(MediaTagRequest, "TagRequest"); -}()); +}(scope.createjs)); //############################################################################## -// AbstractLoader.js +// XHRRequest.js //############################################################################## -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor /** - * The base loader, which defines all the generic methods, properties, and events. All loaders extend this class, - * including the {{#crossLink "LoadQueue"}}{{/crossLink}}. - * @class AbstractLoader - * @param {LoadItem|object|string} loadItem The item to be loaded. - * @param {Boolean} [preferXHR] Determines if the LoadItem should try and load using XHR, or take a - * tag-based approach, which can be better in cross-domain situations. Not all loaders can load using one or the - * other, so this is a suggested directive. - * @param {String} [type] The type of loader. Loader types are defined as constants on the AbstractLoader class, - * such as {{#crossLink "IMAGE:property"}}{{/crossLink}}, {{#crossLink "CSS:property"}}{{/crossLink}}, etc. - * @extends EventDispatcher + * A preloader that loads items using XHR requests, usually XMLHttpRequest. However XDomainRequests will be used + * for cross-domain requests if possible, and older versions of IE fall back on to ActiveX objects when necessary. + * XHR requests load the content as text or binary data, provide progress and consistent completion events, and + * can be canceled during load. Note that XHR is not supported in IE 6 or earlier, and is not recommended for + * cross-domain loading. + * @class XHRRequest + * @constructor + * @param {Object} item The object that defines the file to load. Please see the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * for an overview of supported file properties. + * @extends AbstractLoader */ - function AbstractLoader(loadItem, preferXHR, type) { - this.EventDispatcher_constructor(); + function XHRRequest (item) { + this.AbstractRequest_constructor(item); - // public properties + // protected properties /** - * If the loader has completed loading. This provides a quick check, but also ensures that the different approaches - * used for loading do not pile up resulting in more than one `complete` {{#crossLink "Event"}}{{/crossLink}}. - * @property loaded - * @type {Boolean} - * @default false - */ - this.loaded = false; - - /** - * Determine if the loader was canceled. Canceled loads will not fire complete events. Note that this property - * is readonly, so {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "LoadQueue/close"}}{{/crossLink}} - * instead. - * @property canceled - * @type {Boolean} - * @default false - * @readonly + * A reference to the XHR request used to load the content. + * @property _request + * @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP} + * @private */ - this.canceled = false; + this._request = null; /** - * The current load progress (percentage) for this item. This will be a number between 0 and 1. - * - *

Example

- * - * var queue = new createjs.LoadQueue(); - * queue.loadFile("largeImage.png"); - * queue.on("progress", function() { - * console.log("Progress:", queue.progress, event.progress); - * }); - * - * @property progress + * A manual load timeout that is used for browsers that do not support the onTimeout event on XHR (XHR level 1, + * typically IE9). + * @property _loadTimeout * @type {Number} - * @default 0 - */ - this.progress = 0; - - /** - * The type of item this loader will load. See {{#crossLink "AbstractLoader"}}{{/crossLink}} for a full list of - * supported types. - * @property type - * @type {String} - */ - this.type = type; - - /** - * A formatter function that converts the loaded raw result into the final result. For example, the JSONLoader - * converts a string of text into a JavaScript object. Not all loaders have a resultFormatter, and this property - * can be overridden to provide custom formatting. - * - * Optionally, a resultFormatter can return a callback function in cases where the formatting needs to be - * asynchronous, such as creating a new image. The callback function is passed 2 parameters, which are callbacks - * to handle success and error conditions in the resultFormatter. Note that the resultFormatter method is - * called in the current scope, as well as the success and error callbacks. - * - *

Example asynchronous resultFormatter

- * - * function _formatResult(loader) { - * return function(success, error) { - * if (errorCondition) { error(errorDetailEvent); } - * success(result); - * } - * } - * @property resultFormatter - * @type {Function} - * @default null - */ - this.resultFormatter = null; - - // protected properties - /** - * The {{#crossLink "LoadItem"}}{{/crossLink}} this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}}, - * but will be available on loaders such as {{#crossLink "XMLLoader"}}{{/crossLink}} and {{#crossLink "ImageLoader"}}{{/crossLink}}. - * @property _item - * @type {LoadItem|Object} * @private */ - if (loadItem) { - this._item = createjs.LoadItem.create(loadItem); - } else { - this._item = null; - } + this._loadTimeout = null; /** - * Whether the loader will try and load content using XHR (true) or HTML tags (false). - * @property _preferXHR - * @type {Boolean} + * The browser's XHR (XMLHTTPRequest) version. Supported versions are 1 and 2. There is no official way to detect + * the version, so we use capabilities to make a best guess. + * @property _xhrLevel + * @type {Number} + * @default 1 * @private */ - this._preferXHR = preferXHR; + this._xhrLevel = 1; /** - * The loaded result after it is formatted by an optional {{#crossLink "resultFormatter"}}{{/crossLink}}. For - * items that are not formatted, this will be the same as the {{#crossLink "_rawResult:property"}}{{/crossLink}}. - * The result is accessed using the {{#crossLink "getResult"}}{{/crossLink}} method. - * @property _result - * @type {Object|String} + * The response of a loaded file. This is set because it is expensive to look up constantly. This property will be + * null until the file is loaded. + * @property _response + * @type {mixed} * @private */ - this._result = null; + this._response = null; /** - * The loaded result before it is formatted. The rawResult is accessed using the {{#crossLink "getResult"}}{{/crossLink}} - * method, and passing `true`. - * @property _rawResult - * @type {Object|String} + * The response of the loaded file before it is modified. In most cases, content is converted from raw text to + * an HTML tag or a formatted object which is set to the result property, but the developer may still + * want to access the raw content as it was loaded. + * @property _rawResponse + * @type {String|Object} * @private */ - this._rawResult = null; + this._rawResponse = null; - /** - * A list of items that loaders load behind the scenes. This does not include the main item the loader is - * responsible for loading. Examples of loaders that have sub-items include the {{#crossLink "SpriteSheetLoader"}}{{/crossLink}} and - * {{#crossLink "ManifestLoader"}}{{/crossLink}}. - * @property _loadItems - * @type {null} - * @protected - */ - this._loadedItems = null; + this._canceled = false; - /** - * The attribute the items loaded using tags use for the source. - * @type {string} - * @default null - * @private - */ - this._tagSrcAttribute = null; + // Setup our event handlers now. + this._handleLoadStartProxy = createjs.proxy(this._handleLoadStart, this); + this._handleProgressProxy = createjs.proxy(this._handleProgress, this); + this._handleAbortProxy = createjs.proxy(this._handleAbort, this); + this._handleErrorProxy = createjs.proxy(this._handleError, this); + this._handleTimeoutProxy = createjs.proxy(this._handleTimeout, this); + this._handleLoadProxy = createjs.proxy(this._handleLoad, this); + this._handleReadyStateChangeProxy = createjs.proxy(this._handleReadyStateChange, this); - /** - * An HTML tag (or similar) that a loader may use to load HTML content, such as images, scripts, etc. - * @property _tag - * @type {Object} - * @private - */ - this._tag = null; + if (!this._createXHR(item)) { + //TODO: Throw error? + } }; - var p = createjs.extend(AbstractLoader, createjs.EventDispatcher); - var s = AbstractLoader; - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - + var p = createjs.extend(XHRRequest, createjs.AbstractRequest); +// static properties /** - * Defines a POST request, use for a method value when loading data. - * @property POST - * @type {string} - * @default post - * @static + * A list of XMLHTTP object IDs to try when building an ActiveX object for XHR requests in earlier versions of IE. + * @property ACTIVEX_VERSIONS + * @type {Array} + * @since 0.4.2 + * @private */ - s.POST = "POST"; + XHRRequest.ACTIVEX_VERSIONS = [ + "Msxml2.XMLHTTP.6.0", + "Msxml2.XMLHTTP.5.0", + "Msxml2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", + "MSXML2.XMLHTTP", + "Microsoft.XMLHTTP" + ]; +// Public methods /** - * Defines a GET request, use for a method value when loading data. - * @property GET - * @type {string} - * @default get - * @static + * Look up the loaded result. + * @method getResult + * @param {Boolean} [raw=false] Return a raw result instead of a formatted result. This applies to content + * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be + * returned instead. + * @return {Object} A result object containing the content that was loaded, such as: + *
    + *
  • An image tag (<image />) for images
  • + *
  • A script tag for JavaScript (<script />). Note that scripts loaded with tags may be added to the + * HTML head.
  • + *
  • A style tag for CSS (<style />)
  • + *
  • Raw text for TEXT
  • + *
  • A formatted JavaScript object defined by JSON
  • + *
  • An XML document
  • + *
  • An binary arraybuffer loaded by XHR
  • + *
+ * Note that if a raw result is requested, but not found, the result will be returned instead. */ - s.GET = "GET"; + p.getResult = function (raw) { + if (raw && this._rawResponse) { + return this._rawResponse; + } + return this._response; + }; - /** - * The preload type for generic binary types. Note that images are loaded as binary files when using XHR. - * @property BINARY - * @type {String} - * @default binary - * @static - * @since 0.6.0 - */ - s.BINARY = "binary"; + // Overrides abstract method in AbstractRequest + p.cancel = function () { + this.canceled = true; + this._clean(); + this._request.abort(); + }; - /** - * The preload type for css files. CSS files are loaded using a <link> when loaded with XHR, or a - * <style> tag when loaded with tags. - * @property CSS - * @type {String} - * @default css - * @static - * @since 0.6.0 - */ - s.CSS = "css"; + // Overrides abstract method in AbstractLoader + p.load = function () { + if (this._request == null) { + this._handleError(); + return; + } + + //Events + if (this._request.addEventListener != null) { + this._request.addEventListener("loadstart", this._handleLoadStartProxy, false); + this._request.addEventListener("progress", this._handleProgressProxy, false); + this._request.addEventListener("abort", this._handleAbortProxy, false); + this._request.addEventListener("error", this._handleErrorProxy, false); + this._request.addEventListener("timeout", this._handleTimeoutProxy, false); + + // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. + this._request.addEventListener("load", this._handleLoadProxy, false); + this._request.addEventListener("readystatechange", this._handleReadyStateChangeProxy, false); + } else { + // IE9 support + this._request.onloadstart = this._handleLoadStartProxy; + this._request.onprogress = this._handleProgressProxy; + this._request.onabort = this._handleAbortProxy; + this._request.onerror = this._handleErrorProxy; + this._request.ontimeout = this._handleTimeoutProxy; + + // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. + this._request.onload = this._handleLoadProxy; + this._request.onreadystatechange = this._handleReadyStateChangeProxy; + } + + // Set up a timeout if we don't have XHR2 + if (this._xhrLevel == 1) { + this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); + } + + // Sometimes we get back 404s immediately, particularly when there is a cross origin request. // note this does not catch in Chrome + try { + if (!this._item.values || this._item.method == createjs.AbstractLoader.GET) { + this._request.send(); + } else if (this._item.method == createjs.AbstractLoader.POST) { + this._request.send(createjs.RequestUtils.formatQueryString(this._item.values)); + } + } catch (error) { + this.dispatchEvent(new createjs.ErrorEvent("XHR_SEND", null, error)); + } + }; + + p.setResponseType = function (type) { + // Some old browsers doesn't support blob, so we convert arraybuffer to blob after response is downloaded + if (type === 'blob') { + type = window.URL ? 'blob' : 'arraybuffer'; + this._responseType = type; + } + this._request.responseType = type; + }; /** - * The preload type for image files, usually png, gif, or jpg/jpeg. Images are loaded into an <image> tag. - * @property IMAGE - * @type {String} - * @default image - * @static - * @since 0.6.0 + * Get all the response headers from the XmlHttpRequest. + * + * From the docs: Return all the HTTP headers, excluding headers that are a case-insensitive match + * for Set-Cookie or Set-Cookie2, as a single string, with each header line separated by a U+000D CR U+000A LF pair, + * excluding the status line, and with each header name and header value separated by a U+003A COLON U+0020 SPACE + * pair. + * @method getAllResponseHeaders + * @return {String} + * @since 0.4.1 */ - s.IMAGE = "image"; + p.getAllResponseHeaders = function () { + if (this._request.getAllResponseHeaders instanceof Function) { + return this._request.getAllResponseHeaders(); + } else { + return null; + } + }; /** - * The preload type for javascript files, usually with the "js" file extension. JavaScript files are loaded into a - * <script> tag. + * Get a specific response header from the XmlHttpRequest. * - * Since version 0.4.1+, due to how tag-loaded scripts work, all JavaScript files are automatically injected into - * the body of the document to maintain parity between XHR and tag-loaded scripts. In version 0.4.0 and earlier, - * only tag-loaded scripts are injected. - * @property JAVASCRIPT - * @type {String} - * @default javascript - * @static - * @since 0.6.0 + * From the docs: Returns the header field value from the response of which the field name matches + * header, unless the field name is Set-Cookie or Set-Cookie2. + * @method getResponseHeader + * @param {String} header The header name to retrieve. + * @return {String} + * @since 0.4.1 */ - s.JAVASCRIPT = "javascript"; + p.getResponseHeader = function (header) { + if (this._request.getResponseHeader instanceof Function) { + return this._request.getResponseHeader(header); + } else { + return null; + } + }; +// protected methods /** - * The preload type for json files, usually with the "json" file extension. JSON data is loaded and parsed into a - * JavaScript object. Note that if a `callback` is present on the load item, the file will be loaded with JSONP, - * no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to, and the JSON - * must contain a matching wrapper function. - * @property JSON - * @type {String} - * @default json - * @static - * @since 0.6.0 + * The XHR request has reported progress. + * @method _handleProgress + * @param {Object} event The XHR progress event. + * @private */ - s.JSON = "json"; + p._handleProgress = function (event) { + if (!event || event.loaded > 0 && event.total == 0) { + return; // Sometimes we get no "total", so just ignore the progress event. + } + + var newEvent = new createjs.ProgressEvent(event.loaded, event.total); + this.dispatchEvent(newEvent); + }; /** - * The preload type for jsonp files, usually with the "json" file extension. JSON data is loaded and parsed into a - * JavaScript object. You are required to pass a callback parameter that matches the function wrapper in the JSON. - * Note that JSONP will always be used if there is a callback present, no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} - * property is set to. - * @property JSONP - * @type {String} - * @default jsonp - * @static - * @since 0.6.0 + * The XHR request has reported a load start. + * @method _handleLoadStart + * @param {Object} event The XHR loadStart event. + * @private */ - s.JSONP = "jsonp"; + p._handleLoadStart = function (event) { + clearTimeout(this._loadTimeout); + this.dispatchEvent("loadstart"); + }; /** - * The preload type for json-based manifest files, usually with the "json" file extension. The JSON data is loaded - * and parsed into a JavaScript object. PreloadJS will then look for a "manifest" property in the JSON, which is an - * Array of files to load, following the same format as the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} - * method. If a "callback" is specified on the manifest object, then it will be loaded using JSONP instead, - * regardless of what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to. - * @property MANIFEST - * @type {String} - * @default manifest - * @static - * @since 0.6.0 + * The XHR request has reported an abort event. + * @method handleAbort + * @param {Object} event The XHR abort event. + * @private */ - s.MANIFEST = "manifest"; + p._handleAbort = function (event) { + this._clean(); + this.dispatchEvent(new createjs.ErrorEvent("XHR_ABORTED", null, event)); + }; /** - * The preload type for sound files, usually mp3, ogg, or wav. When loading via tags, audio is loaded into an - * <audio> tag. - * @property SOUND - * @type {String} - * @default sound - * @static - * @since 0.6.0 + * The XHR request has reported an error event. + * @method _handleError + * @param {Object} event The XHR error event. + * @private */ - s.SOUND = "sound"; + p._handleError = function (event) { + this._clean(); + this.dispatchEvent(new createjs.ErrorEvent(event.message)); + }; /** - * The preload type for video files, usually mp4, ts, or ogg. When loading via tags, video is loaded into an - * <video> tag. - * @property VIDEO - * @type {String} - * @default video - * @static - * @since 0.6.0 - */ - s.VIDEO = "video"; - - /** - * The preload type for SpriteSheet files. SpriteSheet files are JSON files that contain string image paths. - * @property SPRITESHEET - * @type {String} - * @default spritesheet - * @static - * @since 0.6.0 - */ - s.SPRITESHEET = "spritesheet"; - - /** - * The preload type for SVG files. - * @property SVG - * @type {String} - * @default svg - * @static - * @since 0.6.0 - */ - s.SVG = "svg"; - - /** - * The preload type for text files, which is also the default file type if the type can not be determined. Text is - * loaded as raw text. - * @property TEXT - * @type {String} - * @default text - * @static - * @since 0.6.0 - */ - s.TEXT = "text"; - - /** - * The preload type for xml files. XML is loaded into an XML document. - * @property XML - * @type {String} - * @default xml - * @static - * @since 0.6.0 - */ - s.XML = "xml"; - -// Events - /** - * The {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when the overall progress changes. Prior to - * version 0.6.0, this was just a regular {{#crossLink "Event"}}{{/crossLink}}. - * @event progress - * @since 0.3.0 - */ - - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a load starts. - * @event loadstart - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.3.1 + * The XHR request has reported a readyState change. Note that older browsers (IE 7 & 8) do not provide an onload + * event, so we must monitor the readyStateChange to determine if the file is loaded. + * @method _handleReadyStateChange + * @param {Object} event The XHR readyStateChange event. + * @private */ + p._handleReadyStateChange = function (event) { + if (this._request.readyState == 4) { + this._handleLoad(); + } + }; /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the entire queue has been loaded. - * @event complete - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.3.0 + * The XHR request has completed. This is called by the XHR request directly, or by a readyStateChange that has + * request.readyState == 4. Only the first call to this method will be processed. + * @method _handleLoad + * @param {Object} event The XHR load event. + * @private */ + p._handleLoad = function (event) { + if (this.loaded) { + return; + } + this.loaded = true; - /** - * The {{#crossLink "ErrorEvent"}}{{/crossLink}} that is fired when the loader encounters an error. If the error was - * encountered by a file, the event will contain the item that caused the error. Prior to version 0.6.0, this was - * just a regular {{#crossLink "Event"}}{{/crossLink}}. - * @event error - * @since 0.3.0 - */ + var error = this._checkError(); + if (error) { + this._handleError(error); + return; + } - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the loader encounters an internal file load error. - * This enables loaders to maintain internal queues, and surface file load errors. - * @event fileerror - * @param {Object} target The object that dispatched the event. - * @param {String} type The even type ("fileerror") - * @param {LoadItem|object} The item that encountered the error - * @since 0.6.0 - */ + this._response = this._getResponse(); + // Convert arraybuffer back to blob + if (this._responseType === 'arraybuffer') { + try { + this._response = new Blob([this._response]); + } catch (e) { + // Fallback to use BlobBuilder if Blob constructor is not supported + // Tested on Android 2.3 ~ 4.2 and iOS5 safari + window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; + if (e.name === 'TypeError' && window.BlobBuilder) { + var builder = new BlobBuilder(); + builder.append(this._response); + this._response = builder.getBlob(); + } + } + } + this._clean(); - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a loader internally loads a file. This enables - * loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} to maintain internal {{#crossLink "LoadQueue"}}{{/crossLink}}s - * and notify when they have loaded a file. The {{#crossLink "LoadQueue"}}{{/crossLink}} class dispatches a - * slightly different {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event. - * @event fileload - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type ("fileload") - * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the - * object will contain that value as a `src` property. - * @param {Object} result The HTML tag or parsed result of the loaded item. - * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted - * to a usable object. - * @since 0.6.0 - */ + this.dispatchEvent(new createjs.Event("complete")); + }; /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired after the internal request is created, but before a load. - * This allows updates to the loader for specific loading needs, such as binary or XHR image loading. - * @event initialize - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type ("initialize") - * @param {AbstractLoader} loader The loader that has been initialized. + * The XHR request has timed out. This is called by the XHR request directly, or via a setTimeout + * callback. + * @method _handleTimeout + * @param {Object} [event] The XHR timeout event. This is occasionally null when called by the backup setTimeout. + * @private */ + p._handleTimeout = function (event) { + this._clean(); - - /** - * Get a reference to the manifest item that is loaded by this loader. In some cases this will be the value that was - * passed into {{#crossLink "LoadQueue"}}{{/crossLink}} using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or - * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. However if only a String path was passed in, then it will - * be a {{#crossLink "LoadItem"}}{{/crossLink}}. - * @method getItem - * @return {Object} The manifest item that this loader is responsible for loading. - * @since 0.6.0 - */ - p.getItem = function () { - return this._item; + this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_TIMEOUT", null, event)); }; +// Protected /** - * Get a reference to the content that was loaded by the loader (only available after the {{#crossLink "complete:event"}}{{/crossLink}} - * event is dispatched. - * @method getResult - * @param {Boolean} [raw=false] Determines if the returned result will be the formatted content, or the raw loaded - * data (if it exists). - * @return {Object} - * @since 0.6.0 + * Determine if there is an error in the current load. This checks the status of the request for problem codes. Note + * that this does not check for an actual response. Currently, it only checks for 404 or 0 error code. + * @method _checkError + * @return {int} If the request status returns an error code. + * @private */ - p.getResult = function (raw) { - return raw ? this._rawResult : this._result; - }; + p._checkError = function () { + //LM: Probably need additional handlers here, maybe 501 + var status = parseInt(this._request.status); - /** - * Return the `tag` this object creates or uses for loading. - * @method getTag - * @return {Object} The tag instance - * @since 0.6.0 - */ - p.getTag = function () { - return this._tag; + switch (status) { + case 404: // Not Found + case 0: // Not Loaded + return new Error(status); + } + return null; }; /** - * Set the `tag` this item uses for loading. - * @method setTag - * @param {Object} tag The tag instance - * @since 0.6.0 + * Validate the response. Different browsers have different approaches, some of which throw errors when accessed + * in other browsers. If there is no response, the _response property will remain null. + * @method _getResponse + * @private */ - p.setTag = function(tag) { - this._tag = tag; - }; + p._getResponse = function () { + if (this._response != null) { + return this._response; + } - /** - * Begin loading the item. This method is required when using a loader by itself. - * - *

Example

- * - * var queue = new createjs.LoadQueue(); - * queue.on("complete", handleComplete); - * queue.loadManifest(fileArray, false); // Note the 2nd argument that tells the queue not to start loading yet - * queue.load(); - * - * @method load - */ - p.load = function () { - this._createRequest(); + if (this._request.response != null) { + return this._request.response; + } - this._request.on("complete", this, this); - this._request.on("progress", this, this); - this._request.on("loadStart", this, this); - this._request.on("abort", this, this); - this._request.on("timeout", this, this); - this._request.on("error", this, this); + // Android 2.2 uses .responseText + try { + if (this._request.responseText != null) { + return this._request.responseText; + } + } catch (e) { + } - var evt = new createjs.Event("initialize"); - evt.loader = this._request; - this.dispatchEvent(evt); + // When loading XML, IE9 does not return .response, instead it returns responseXML.xml + try { + if (this._request.responseXML != null) { + return this._request.responseXML; + } + } catch (e) { + } - this._request.load(); + return null; }; /** - * Close the the item. This will stop any open requests (although downloads using HTML tags may still continue in - * the background), but events will not longer be dispatched. - * @method cancel + * Create an XHR request. Depending on a number of factors, we get totally different results. + *
  1. Some browsers get an XDomainRequest when loading cross-domain.
  2. + *
  3. XMLHttpRequest are created when available.
  4. + *
  5. ActiveX.XMLHTTP objects are used in older IE browsers.
  6. + *
  7. Text requests override the mime type if possible
  8. + *
  9. Origin headers are sent for crossdomain requests in some browsers.
  10. + *
  11. Binary loads set the response type to "arraybuffer"
+ * @method _createXHR + * @param {Object} item The requested item that is being loaded. + * @return {Boolean} If an XHR request or equivalent was successfully created. + * @private */ - p.cancel = function () { - this.canceled = true; - this.destroy(); - }; + p._createXHR = function (item) { + // Check for cross-domain loads. We can't fully support them, but we can try. + var crossdomain = createjs.RequestUtils.isCrossDomain(item); + var headers = {}; - /** - * Clean up the loader. - * @method destroy - */ - p.destroy = function() { - if (this._request) { - this._request.removeAllEventListeners(); - this._request.destroy(); + // Create the request. Fallback to whatever support we have. + var req = null; + if (window.XMLHttpRequest) { + req = new XMLHttpRequest(); + // This is 8 or 9, so use XDomainRequest instead. + if (crossdomain && req.withCredentials === undefined && window.XDomainRequest) { + req = new XDomainRequest(); + } + } else { // Old IE versions use a different approach + for (var i = 0, l = s.ACTIVEX_VERSIONS.length; i < l; i++) { + var axVersion = s.ACTIVEX_VERSIONS[i]; + try { + req = new ActiveXObject(axVersion); + break; + } catch (e) { + } + } + if (req == null) { + return false; + } } - this._request = null; - - this._item = null; - this._rawResult = null; - this._result = null; - - this._loadItems = null; - - this.removeAllEventListeners(); - }; + // Default to utf-8 for Text requests. + if (item.mimeType == null && createjs.RequestUtils.isText(item.type)) { + item.mimeType = "text/plain; charset=utf-8"; + } - /** - * Get any items loaded internally by the loader. The enables loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} - * to expose items it loads internally. - * @method getLoadedItems - * @return {Array} A list of the items loaded by the loader. - * @since 0.6.0 - */ - p.getLoadedItems = function () { - return this._loadedItems; - }; + // IE9 doesn't support overrideMimeType(), so we need to check for it. + if (item.mimeType && req.overrideMimeType) { + req.overrideMimeType(item.mimeType); + } + // Determine the XHR level + this._xhrLevel = (typeof req.responseType === "string") ? 2 : 1; - // Private methods - /** - * Create an internal request used for loading. By default, an {{#crossLink "XHRRequest"}}{{/crossLink}} or - * {{#crossLink "TagRequest"}}{{/crossLink}} is created, depending on the value of {{#crossLink "preferXHR:property"}}{{/crossLink}}. - * Other loaders may override this to use different request types, such as {{#crossLink "ManifestLoader"}}{{/crossLink}}, - * which uses {{#crossLink "JSONLoader"}}{{/crossLink}} or {{#crossLink "JSONPLoader"}}{{/crossLink}} under the hood. - * @method _createRequest - * @protected - */ - p._createRequest = function() { - if (!this._preferXHR) { - this._request = new createjs.TagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); + var src = null; + if (item.method == createjs.AbstractLoader.GET) { + src = createjs.RequestUtils.buildPath(item.src, item.values); } else { - this._request = new createjs.XHRRequest(this._item); + src = item.src; } - }; - /** - * Create the HTML tag used for loading. This method does nothing by default, and needs to be implemented - * by loaders that require tag loading. - * @method _createTag - * @param {String} src The tag source - * @return {HTMLElement} The tag that was created - * @protected - */ - p._createTag = function(src) { return null; }; + // Open the request. Set cross-domain flags if it is supported (XHR level 1 only) + req.open(item.method || createjs.AbstractLoader.GET, src, true); - /** - * Dispatch a loadstart {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}} - * event for details on the event payload. - * @method _sendLoadStart - * @protected - */ - p._sendLoadStart = function () { - if (this._isCanceled()) { return; } - this.dispatchEvent("loadstart"); - }; + if (crossdomain && req instanceof XMLHttpRequest && this._xhrLevel == 1) { + headers["Origin"] = location.origin; + } - /** - * Dispatch a {{#crossLink "ProgressEvent"}}{{/crossLink}}. - * @method _sendProgress - * @param {Number | Object} value The progress of the loaded item, or an object containing loaded - * and total properties. - * @protected - */ - p._sendProgress = function (value) { - if (this._isCanceled()) { return; } - var event = null; - if (typeof(value) == "number") { - this.progress = value; - event = new createjs.ProgressEvent(this.progress); - } else { - event = value; - this.progress = value.loaded / value.total; - event.progress = this.progress; - if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; } + // To send data we need to set the Content-type header) + if (item.values && item.method == createjs.AbstractLoader.POST) { + headers["Content-Type"] = "application/x-www-form-urlencoded"; } - this.hasEventListener("progress") && this.dispatchEvent(event); - }; - /** - * Dispatch a complete {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event - * @method _sendComplete - * @protected - */ - p._sendComplete = function () { - if (this._isCanceled()) { return; } + if (!crossdomain && !headers["X-Requested-With"]) { + headers["X-Requested-With"] = "XMLHttpRequest"; + } - this.loaded = true; + if (item.headers) { + for (var n in item.headers) { + headers[n] = item.headers[n]; + } + } - var event = new createjs.Event("complete"); - event.rawResult = this._rawResult; + for (n in headers) { + req.setRequestHeader(n, headers[n]) + } - if (this._result != null) { - event.result = this._result; + if (req instanceof XMLHttpRequest && item.withCredentials !== undefined) { + req.withCredentials = item.withCredentials; } - this.dispatchEvent(event); - }; + this._request = req; - /** - * Dispatch an error {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} - * event for details on the event payload. - * @method _sendError - * @param {ErrorEvent} event The event object containing specific error properties. - * @protected - */ - p._sendError = function (event) { - if (this._isCanceled() || !this.hasEventListener("error")) { return; } - if (event == null) { - event = new createjs.ErrorEvent("PRELOAD_ERROR_EMPTY"); // TODO: Populate error - } - this.dispatchEvent(event); + return true; }; /** - * Determine if the load has been canceled. This is important to ensure that method calls or asynchronous events - * do not cause issues after the queue has been cleaned up. - * @method _isCanceled - * @return {Boolean} If the loader has been canceled. - * @protected - */ - p._isCanceled = function () { - if (window.createjs == null || this.canceled) { - return true; - } - return false; - }; - - /** - * A custom result formatter function, which is called just before a request dispatches its complete event. Most - * loader types already have an internal formatter, but this can be user-overridden for custom formatting. The - * formatted result will be available on Loaders using {{#crossLink "getResult"}}{{/crossLink}}, and passing `true`. - * @property resultFormatter - * @type Function - * @return {Object} The formatted result - * @since 0.6.0 - */ - p.resultFormatter = null; - - /** - * Handle events from internal requests. By default, loaders will handle, and redispatch the necessary events, but - * this method can be overridden for custom behaviours. - * @method handleEvent - * @param {Event} event The event that the internal request dispatches. - * @protected - * @since 0.6.0 - */ - p.handleEvent = function (event) { - switch (event.type) { - case "complete": - this._rawResult = event.target._response; - var result = this.resultFormatter && this.resultFormatter(this); - if (result instanceof Function) { - result.call(this, - createjs.proxy(this._resultFormatSuccess, this), - createjs.proxy(this._resultFormatFailed, this) - ); - } else { - this._result = result || this._rawResult; - this._sendComplete(); - } - break; - case "progress": - this._sendProgress(event); - break; - case "error": - this._sendError(event); - break; - case "loadstart": - this._sendLoadStart(); - break; - case "abort": - case "timeout": - if (!this._isCanceled()) { - this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_" + event.type.toUpperCase() + "_ERROR")); - } - break; - } - }; - - /** - * The "success" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous - * functions. - * @method _resultFormatSuccess - * @param {Object} result The formatted result - * @private - */ - p._resultFormatSuccess = function (result) { - this._result = result; - this._sendComplete(); - }; - - /** - * The "error" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous - * functions. - * @method _resultFormatSuccess - * @param {Object} error The error event - * @private - */ - p._resultFormatFailed = function (event) { - this._sendError(event); - }; - - /** - * @method buildPath - * @protected - * @deprecated Use the {{#crossLink "RequestUtils"}}{{/crossLink}} method {{#crossLink "RequestUtils/buildPath"}}{{/crossLink}} - * instead. - */ - p.buildPath = function (src, data) { - return createjs.RequestUtils.buildPath(src, data); - }; - - /** - * @method toString - * @return {String} a string representation of the instance. - */ - p.toString = function () { - return "[PreloadJS AbstractLoader]"; - }; - - createjs.AbstractLoader = createjs.promote(AbstractLoader, "EventDispatcher"); - -}()); - -//############################################################################## -// AbstractMediaLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * The AbstractMediaLoader is a base class that handles some of the shared methods and properties of loaders that - * handle HTML media elements, such as Video and Audio. - * @class AbstractMediaLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @param {String} type The type of media to load. Usually "video" or "audio". - * @extends AbstractLoader - * @constructor - */ - function AbstractMediaLoader(loadItem, preferXHR, type) { - this.AbstractLoader_constructor(loadItem, preferXHR, type); - - // public properties - this.resultFormatter = this._formatResult; - - // protected properties - this._tagSrcAttribute = "src"; - - this.on("initialize", this._updateXHR, this); - }; - - var p = createjs.extend(AbstractMediaLoader, createjs.AbstractLoader); - - // static properties - // public methods - p.load = function () { - // TagRequest will handle most of this, but Sound / Video need a few custom properties, so just handle them here. - if (!this._tag) { - this._tag = this._createTag(this._item.src); - } - - this._tag.preload = "auto"; - this._tag.load(); - - this.AbstractLoader_load(); - }; - - // protected methods - /** - * Creates a new tag for loading if it doesn't exist yet. - * @method _createTag + * A request has completed (or failed or canceled), and needs to be disposed. + * @method _clean * @private */ - p._createTag = function () {}; - + p._clean = function () { + clearTimeout(this._loadTimeout); - p._createRequest = function() { - if (!this._preferXHR) { - this._request = new createjs.MediaTagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); + if (this._request.removeEventListener != null) { + this._request.removeEventListener("loadstart", this._handleLoadStartProxy); + this._request.removeEventListener("progress", this._handleProgressProxy); + this._request.removeEventListener("abort", this._handleAbortProxy); + this._request.removeEventListener("error", this._handleErrorProxy); + this._request.removeEventListener("timeout", this._handleTimeoutProxy); + this._request.removeEventListener("load", this._handleLoadProxy); + this._request.removeEventListener("readystatechange", this._handleReadyStateChangeProxy); } else { - this._request = new createjs.XHRRequest(this._item); - } - }; - - // protected methods - /** - * Before the item loads, set its mimeType and responseType. - * @property _updateXHR - * @param {Event} event - * @private - */ - p._updateXHR = function (event) { - // Only exists for XHR - if (event.loader.setResponseType) { - event.loader.setResponseType("blob"); - } - }; - - /** - * The result formatter for media files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLVideoElement|HTMLAudioElement} - * @private - */ - p._formatResult = function (loader) { - this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler); - this._tag.onstalled = null; - if (this._preferXHR) { - var URL = window.URL || window.webkitURL; - var result = loader.getResult(true); - - loader.getTag().src = URL.createObjectURL(result); + this._request.onloadstart = null; + this._request.onprogress = null; + this._request.onabort = null; + this._request.onerror = null; + this._request.ontimeout = null; + this._request.onload = null; + this._request.onreadystatechange = null; } - return loader.getTag(); }; - createjs.AbstractMediaLoader = createjs.promote(AbstractMediaLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// AbstractRequest.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - /** - * A base class for actual data requests, such as {{#crossLink "XHRRequest"}}{{/crossLink}}, {{#crossLink "TagRequest"}}{{/crossLink}}, - * and {{#crossLink "MediaRequest"}}{{/crossLink}}. PreloadJS loaders will typically use a data loader under the - * hood to get data. - * @class AbstractRequest - * @param {LoadItem} item - * @constructor - */ - var AbstractRequest = function (item) { - this._item = item; + p.toString = function () { + return "[PreloadJS XHRRequest]"; }; - var p = createjs.extend(AbstractRequest, createjs.EventDispatcher); - - // public methods - /** - * Begin a load. - * @method load - */ - p.load = function() {}; - - /** - * Clean up a request. - * @method destroy - */ - p.destroy = function() {}; - - /** - * Cancel an in-progress request. - * @method cancel - */ - p.cancel = function() {}; - - createjs.AbstractRequest = createjs.promote(AbstractRequest, "EventDispatcher"); + createjs.XHRRequest = createjs.promote(XHRRequest, "AbstractRequest"); -}()); +}(scope.createjs)); //############################################################################## -// TagRequest.js +// LoadQueue.js //############################################################################## -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * An {{#crossLink "AbstractRequest"}}{{/crossLink}} that loads HTML tags, such as images and scripts. - * @class TagRequest - * @param {LoadItem} loadItem - * @param {HTMLElement} tag - * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. - */ - function TagRequest(loadItem, tag, srcAttribute) { - this.AbstractRequest_constructor(loadItem); - - // protected properties - /** - * The HTML tag instance that is used to load. - * @property _tag - * @type {HTMLElement} - * @protected - */ - this._tag = tag; - - /** - * The tag attribute that specifies the source, such as "src", "href", etc. - * @property _tagSrcAttribute - * @type {String} - * @protected - */ - this._tagSrcAttribute = srcAttribute; - - /** - * A method closure used for handling the tag load event. - * @property _loadedHandler - * @type {Function} - * @private - */ - this._loadedHandler = createjs.proxy(this._handleTagComplete, this); - - /** - * Determines if the element was added to the DOM automatically by PreloadJS, so it can be cleaned up after. - * @property _addedToDOM - * @type {Boolean} - * @private - */ - this._addedToDOM = false; - - /** - * Determines what the tags initial style.visibility was, so we can set it correctly after a load. - * - * @type {null} - * @private - */ - this._startTagVisibility = null; - }; - - var p = createjs.extend(TagRequest, createjs.AbstractRequest); - - // public methods - p.load = function () { - this._tag.onload = createjs.proxy(this._handleTagComplete, this); - this._tag.onreadystatechange = createjs.proxy(this._handleReadyStateChange, this); - this._tag.onerror = createjs.proxy(this._handleError, this); - - var evt = new createjs.Event("initialize"); - evt.loader = this._tag; - - this.dispatchEvent(evt); - - this._hideTag(); - - this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); - - this._tag[this._tagSrcAttribute] = this._item.src; - - // wdg:: Append the tag AFTER setting the src, or SVG loading on iOS will fail. - if (this._tag.parentNode == null) { - window.document.body.appendChild(this._tag); - this._addedToDOM = true; - } - }; - - p.destroy = function() { - this._clean(); - this._tag = null; - - this.AbstractRequest_destroy(); - }; - - // private methods - /** - * Handle the readyStateChange event from a tag. We need this in place of the `onload` callback (mainly SCRIPT - * and LINK tags), but other cases may exist. - * @method _handleReadyStateChange - * @private - */ - p._handleReadyStateChange = function () { - clearTimeout(this._loadTimeout); - // This is strictly for tags in browsers that do not support onload. - var tag = this._tag; - - // Complete is for old IE support. - if (tag.readyState == "loaded" || tag.readyState == "complete") { - this._handleTagComplete(); - } - }; - - /** - * Handle any error events from the tag. - * @method _handleError - * @protected - */ - p._handleError = function() { - this._clean(); - this.dispatchEvent("error"); - }; - - /** - * Handle the tag's onload callback. - * @method _handleTagComplete - * @private - */ - p._handleTagComplete = function () { - this._rawResult = this._tag; - this._result = this.resultFormatter && this.resultFormatter(this) || this._rawResult; - - this._clean(); - this._showTag(); - - this.dispatchEvent("complete"); - }; - - /** - * The tag request has not loaded within the time specified in loadTimeout. - * @method _handleError - * @param {Object} event The XHR error event. - * @private - */ - p._handleTimeout = function () { - this._clean(); - this.dispatchEvent(new createjs.Event("timeout")); - }; - - /** - * Remove event listeners, but don't destroy the request object - * @method _clean - * @private - */ - p._clean = function() { - this._tag.onload = null; - this._tag.onreadystatechange = null; - this._tag.onerror = null; - if (this._addedToDOM && this._tag.parentNode != null) { - this._tag.parentNode.removeChild(this._tag); - } - clearTimeout(this._loadTimeout); - }; - - p._hideTag = function() { - this._startTagVisibility = this._tag.style.visibility; - this._tag.style.visibility = "hidden"; - }; - - p._showTag = function() { - this._tag.style.visibility = this._startTagVisibility; - }; - - /** - * Handle a stalled audio event. The main place this happens is with HTMLAudio in Chrome when playing back audio - * that is already in a load, but not complete. - * @method _handleStalled - * @private - */ - p._handleStalled = function () { - //Ignore, let the timeout take care of it. Sometimes its not really stopped. - }; - - createjs.TagRequest = createjs.promote(TagRequest, "AbstractRequest"); - -}()); - -//############################################################################## -// MediaTagRequest.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * An {{#crossLink "TagRequest"}}{{/crossLink}} that loads HTML tags for video and audio. - * @class MediaTagRequest - * @param {LoadItem} loadItem - * @param {HTMLAudioElement|HTMLVideoElement} tag - * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. - * @constructor - */ - function MediaTagRequest(loadItem, tag, srcAttribute) { - this.AbstractRequest_constructor(loadItem); - - // protected properties - this._tag = tag; - this._tagSrcAttribute = srcAttribute; - this._loadedHandler = createjs.proxy(this._handleTagComplete, this); - }; - - var p = createjs.extend(MediaTagRequest, createjs.TagRequest); - var s = MediaTagRequest; - - // public methods - p.load = function () { - var sc = createjs.proxy(this._handleStalled, this); - this._stalledCallback = sc; - - var pc = createjs.proxy(this._handleProgress, this); - this._handleProgress = pc; - - this._tag.addEventListener("stalled", sc); - this._tag.addEventListener("progress", pc); - - // This will tell us when audio is buffered enough to play through, but not when its loaded. - // The tag doesn't keep loading in Chrome once enough has buffered, and we have decided that behaviour is sufficient. - this._tag.addEventListener && this._tag.addEventListener("canplaythrough", this._loadedHandler, false); // canplaythrough callback doesn't work in Chrome, so we use an event. - - this.TagRequest_load(); - }; - - // private methods - p._handleReadyStateChange = function () { - clearTimeout(this._loadTimeout); - // This is strictly for tags in browsers that do not support onload. - var tag = this._tag; - - // Complete is for old IE support. - if (tag.readyState == "loaded" || tag.readyState == "complete") { - this._handleTagComplete(); - } - }; - - p._handleStalled = function () { - //Ignore, let the timeout take care of it. Sometimes its not really stopped. - }; - - /** - * An XHR request has reported progress. - * @method _handleProgress - * @param {Object} event The XHR progress event. - * @private - */ - p._handleProgress = function (event) { - if (!event || event.loaded > 0 && event.total == 0) { - return; // Sometimes we get no "total", so just ignore the progress event. - } - - var newEvent = new createjs.ProgressEvent(event.loaded, event.total); - this.dispatchEvent(newEvent); - }; - - // protected methods - p._clean = function () { - this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler); - this._tag.removeEventListener("stalled", this._stalledCallback); - this._tag.removeEventListener("progress", this._progressCallback); - - this.TagRequest__clean(); - }; - - createjs.MediaTagRequest = createjs.promote(MediaTagRequest, "TagRequest"); - -}()); - -//############################################################################## -// XHRRequest.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - -// constructor - /** - * A preloader that loads items using XHR requests, usually XMLHttpRequest. However XDomainRequests will be used - * for cross-domain requests if possible, and older versions of IE fall back on to ActiveX objects when necessary. - * XHR requests load the content as text or binary data, provide progress and consistent completion events, and - * can be canceled during load. Note that XHR is not supported in IE 6 or earlier, and is not recommended for - * cross-domain loading. - * @class XHRRequest - * @constructor - * @param {Object} item The object that defines the file to load. Please see the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * for an overview of supported file properties. - * @extends AbstractLoader - */ - function XHRRequest (item) { - this.AbstractRequest_constructor(item); - - // protected properties - /** - * A reference to the XHR request used to load the content. - * @property _request - * @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP} - * @private - */ - this._request = null; - - /** - * A manual load timeout that is used for browsers that do not support the onTimeout event on XHR (XHR level 1, - * typically IE9). - * @property _loadTimeout - * @type {Number} - * @private - */ - this._loadTimeout = null; - - /** - * The browser's XHR (XMLHTTPRequest) version. Supported versions are 1 and 2. There is no official way to detect - * the version, so we use capabilities to make a best guess. - * @property _xhrLevel - * @type {Number} - * @default 1 - * @private - */ - this._xhrLevel = 1; - - /** - * The response of a loaded file. This is set because it is expensive to look up constantly. This property will be - * null until the file is loaded. - * @property _response - * @type {mixed} - * @private - */ - this._response = null; - - /** - * The response of the loaded file before it is modified. In most cases, content is converted from raw text to - * an HTML tag or a formatted object which is set to the result property, but the developer may still - * want to access the raw content as it was loaded. - * @property _rawResponse - * @type {String|Object} - * @private - */ - this._rawResponse = null; - - this._canceled = false; - - // Setup our event handlers now. - this._handleLoadStartProxy = createjs.proxy(this._handleLoadStart, this); - this._handleProgressProxy = createjs.proxy(this._handleProgress, this); - this._handleAbortProxy = createjs.proxy(this._handleAbort, this); - this._handleErrorProxy = createjs.proxy(this._handleError, this); - this._handleTimeoutProxy = createjs.proxy(this._handleTimeout, this); - this._handleLoadProxy = createjs.proxy(this._handleLoad, this); - this._handleReadyStateChangeProxy = createjs.proxy(this._handleReadyStateChange, this); - - if (!this._createXHR(item)) { - //TODO: Throw error? - } - }; - - var p = createjs.extend(XHRRequest, createjs.AbstractRequest); - -// static properties - /** - * A list of XMLHTTP object IDs to try when building an ActiveX object for XHR requests in earlier versions of IE. - * @property ACTIVEX_VERSIONS - * @type {Array} - * @since 0.4.2 - * @private - */ - XHRRequest.ACTIVEX_VERSIONS = [ - "Msxml2.XMLHTTP.6.0", - "Msxml2.XMLHTTP.5.0", - "Msxml2.XMLHTTP.4.0", - "MSXML2.XMLHTTP.3.0", - "MSXML2.XMLHTTP", - "Microsoft.XMLHTTP" - ]; - -// Public methods - /** - * Look up the loaded result. - * @method getResult - * @param {Boolean} [raw=false] Return a raw result instead of a formatted result. This applies to content - * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be - * returned instead. - * @return {Object} A result object containing the content that was loaded, such as: - *
    - *
  • An image tag (<image />) for images
  • - *
  • A script tag for JavaScript (<script />). Note that scripts loaded with tags may be added to the - * HTML head.
  • - *
  • A style tag for CSS (<style />)
  • - *
  • Raw text for TEXT
  • - *
  • A formatted JavaScript object defined by JSON
  • - *
  • An XML document
  • - *
  • An binary arraybuffer loaded by XHR
  • - *
- * Note that if a raw result is requested, but not found, the result will be returned instead. - */ - p.getResult = function (raw) { - if (raw && this._rawResponse) { - return this._rawResponse; - } - return this._response; - }; - - // Overrides abstract method in AbstractRequest - p.cancel = function () { - this.canceled = true; - this._clean(); - this._request.abort(); - }; - - // Overrides abstract method in AbstractLoader - p.load = function () { - if (this._request == null) { - this._handleError(); - return; - } - - //Events - if (this._request.addEventListener != null) { - this._request.addEventListener("loadstart", this._handleLoadStartProxy, false); - this._request.addEventListener("progress", this._handleProgressProxy, false); - this._request.addEventListener("abort", this._handleAbortProxy, false); - this._request.addEventListener("error", this._handleErrorProxy, false); - this._request.addEventListener("timeout", this._handleTimeoutProxy, false); - - // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. - this._request.addEventListener("load", this._handleLoadProxy, false); - this._request.addEventListener("readystatechange", this._handleReadyStateChangeProxy, false); - } else { - // IE9 support - this._request.onloadstart = this._handleLoadStartProxy; - this._request.onprogress = this._handleProgressProxy; - this._request.onabort = this._handleAbortProxy; - this._request.onerror = this._handleErrorProxy; - this._request.ontimeout = this._handleTimeoutProxy; - - // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. - this._request.onload = this._handleLoadProxy; - this._request.onreadystatechange = this._handleReadyStateChangeProxy; - } - - // Set up a timeout if we don't have XHR2 - if (this._xhrLevel == 1) { - this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); - } - - // Sometimes we get back 404s immediately, particularly when there is a cross origin request. // note this does not catch in Chrome - try { - if (!this._item.values || this._item.method == createjs.AbstractLoader.GET) { - this._request.send(); - } else if (this._item.method == createjs.AbstractLoader.POST) { - this._request.send(createjs.RequestUtils.formatQueryString(this._item.values)); - } - } catch (error) { - this.dispatchEvent(new createjs.ErrorEvent("XHR_SEND", null, error)); - } - }; - - p.setResponseType = function (type) { - // Some old browsers doesn't support blob, so we convert arraybuffer to blob after response is downloaded - if (type === 'blob') { - type = window.URL ? 'blob' : 'arraybuffer'; - this._responseType = type; - } - this._request.responseType = type; - }; - - /** - * Get all the response headers from the XmlHttpRequest. - * - * From the docs: Return all the HTTP headers, excluding headers that are a case-insensitive match - * for Set-Cookie or Set-Cookie2, as a single string, with each header line separated by a U+000D CR U+000A LF pair, - * excluding the status line, and with each header name and header value separated by a U+003A COLON U+0020 SPACE - * pair. - * @method getAllResponseHeaders - * @return {String} - * @since 0.4.1 - */ - p.getAllResponseHeaders = function () { - if (this._request.getAllResponseHeaders instanceof Function) { - return this._request.getAllResponseHeaders(); - } else { - return null; - } - }; - - /** - * Get a specific response header from the XmlHttpRequest. - * - * From the docs: Returns the header field value from the response of which the field name matches - * header, unless the field name is Set-Cookie or Set-Cookie2. - * @method getResponseHeader - * @param {String} header The header name to retrieve. - * @return {String} - * @since 0.4.1 - */ - p.getResponseHeader = function (header) { - if (this._request.getResponseHeader instanceof Function) { - return this._request.getResponseHeader(header); - } else { - return null; - } - }; - -// protected methods - /** - * The XHR request has reported progress. - * @method _handleProgress - * @param {Object} event The XHR progress event. - * @private - */ - p._handleProgress = function (event) { - if (!event || event.loaded > 0 && event.total == 0) { - return; // Sometimes we get no "total", so just ignore the progress event. - } - - var newEvent = new createjs.ProgressEvent(event.loaded, event.total); - this.dispatchEvent(newEvent); - }; - - /** - * The XHR request has reported a load start. - * @method _handleLoadStart - * @param {Object} event The XHR loadStart event. - * @private - */ - p._handleLoadStart = function (event) { - clearTimeout(this._loadTimeout); - this.dispatchEvent("loadstart"); - }; - - /** - * The XHR request has reported an abort event. - * @method handleAbort - * @param {Object} event The XHR abort event. - * @private - */ - p._handleAbort = function (event) { - this._clean(); - this.dispatchEvent(new createjs.ErrorEvent("XHR_ABORTED", null, event)); - }; - - /** - * The XHR request has reported an error event. - * @method _handleError - * @param {Object} event The XHR error event. - * @private - */ - p._handleError = function (event) { - this._clean(); - this.dispatchEvent(new createjs.ErrorEvent(event.message)); - }; - - /** - * The XHR request has reported a readyState change. Note that older browsers (IE 7 & 8) do not provide an onload - * event, so we must monitor the readyStateChange to determine if the file is loaded. - * @method _handleReadyStateChange - * @param {Object} event The XHR readyStateChange event. - * @private - */ - p._handleReadyStateChange = function (event) { - if (this._request.readyState == 4) { - this._handleLoad(); - } - }; - - /** - * The XHR request has completed. This is called by the XHR request directly, or by a readyStateChange that has - * request.readyState == 4. Only the first call to this method will be processed. - * @method _handleLoad - * @param {Object} event The XHR load event. - * @private - */ - p._handleLoad = function (event) { - if (this.loaded) { - return; - } - this.loaded = true; - - var error = this._checkError(); - if (error) { - this._handleError(error); - return; - } - - this._response = this._getResponse(); - // Convert arraybuffer back to blob - if (this._responseType === 'arraybuffer') { - try { - this._response = new Blob([this._response]); - } catch (e) { - // Fallback to use BlobBuilder if Blob constructor is not supported - // Tested on Android 2.3 ~ 4.2 and iOS5 safari - window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; - if (e.name === 'TypeError' && window.BlobBuilder) { - var builder = new BlobBuilder(); - builder.append(this._response); - this._response = builder.getBlob(); - } - } - } - this._clean(); - - this.dispatchEvent(new createjs.Event("complete")); - }; - - /** - * The XHR request has timed out. This is called by the XHR request directly, or via a setTimeout - * callback. - * @method _handleTimeout - * @param {Object} [event] The XHR timeout event. This is occasionally null when called by the backup setTimeout. - * @private - */ - p._handleTimeout = function (event) { - this._clean(); - - this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_TIMEOUT", null, event)); - }; - -// Protected - /** - * Determine if there is an error in the current load. This checks the status of the request for problem codes. Note - * that this does not check for an actual response. Currently, it only checks for 404 or 0 error code. - * @method _checkError - * @return {int} If the request status returns an error code. - * @private - */ - p._checkError = function () { - //LM: Probably need additional handlers here, maybe 501 - var status = parseInt(this._request.status); - - switch (status) { - case 404: // Not Found - case 0: // Not Loaded - return new Error(status); - } - return null; - }; - - /** - * Validate the response. Different browsers have different approaches, some of which throw errors when accessed - * in other browsers. If there is no response, the _response property will remain null. - * @method _getResponse - * @private - */ - p._getResponse = function () { - if (this._response != null) { - return this._response; - } - - if (this._request.response != null) { - return this._request.response; - } - - // Android 2.2 uses .responseText - try { - if (this._request.responseText != null) { - return this._request.responseText; - } - } catch (e) { - } - - // When loading XML, IE9 does not return .response, instead it returns responseXML.xml - try { - if (this._request.responseXML != null) { - return this._request.responseXML; - } - } catch (e) { - } - - return null; - }; - - /** - * Create an XHR request. Depending on a number of factors, we get totally different results. - *
  1. Some browsers get an XDomainRequest when loading cross-domain.
  2. - *
  3. XMLHttpRequest are created when available.
  4. - *
  5. ActiveX.XMLHTTP objects are used in older IE browsers.
  6. - *
  7. Text requests override the mime type if possible
  8. - *
  9. Origin headers are sent for crossdomain requests in some browsers.
  10. - *
  11. Binary loads set the response type to "arraybuffer"
- * @method _createXHR - * @param {Object} item The requested item that is being loaded. - * @return {Boolean} If an XHR request or equivalent was successfully created. - * @private - */ - p._createXHR = function (item) { - // Check for cross-domain loads. We can't fully support them, but we can try. - var crossdomain = createjs.RequestUtils.isCrossDomain(item); - var headers = {}; - - // Create the request. Fallback to whatever support we have. - var req = null; - if (window.XMLHttpRequest) { - req = new XMLHttpRequest(); - // This is 8 or 9, so use XDomainRequest instead. - if (crossdomain && req.withCredentials === undefined && window.XDomainRequest) { - req = new XDomainRequest(); - } - } else { // Old IE versions use a different approach - for (var i = 0, l = s.ACTIVEX_VERSIONS.length; i < l; i++) { - var axVersion = s.ACTIVEX_VERSIONS[i]; - try { - req = new ActiveXObject(axVersion); - break; - } catch (e) { - } - } - if (req == null) { - return false; - } - } - - // Default to utf-8 for Text requests. - if (item.mimeType == null && createjs.RequestUtils.isText(item.type)) { - item.mimeType = "text/plain; charset=utf-8"; - } - - // IE9 doesn't support overrideMimeType(), so we need to check for it. - if (item.mimeType && req.overrideMimeType) { - req.overrideMimeType(item.mimeType); - } - - // Determine the XHR level - this._xhrLevel = (typeof req.responseType === "string") ? 2 : 1; - - var src = null; - if (item.method == createjs.AbstractLoader.GET) { - src = createjs.RequestUtils.buildPath(item.src, item.values); - } else { - src = item.src; - } - - // Open the request. Set cross-domain flags if it is supported (XHR level 1 only) - req.open(item.method || createjs.AbstractLoader.GET, src, true); - - if (crossdomain && req instanceof XMLHttpRequest && this._xhrLevel == 1) { - headers["Origin"] = location.origin; - } - - // To send data we need to set the Content-type header) - if (item.values && item.method == createjs.AbstractLoader.POST) { - headers["Content-Type"] = "application/x-www-form-urlencoded"; - } - - if (!crossdomain && !headers["X-Requested-With"]) { - headers["X-Requested-With"] = "XMLHttpRequest"; - } - - if (item.headers) { - for (var n in item.headers) { - headers[n] = item.headers[n]; - } - } - - for (n in headers) { - req.setRequestHeader(n, headers[n]) - } - - if (req instanceof XMLHttpRequest && item.withCredentials !== undefined) { - req.withCredentials = item.withCredentials; - } - - this._request = req; - - return true; - }; - - /** - * A request has completed (or failed or canceled), and needs to be disposed. - * @method _clean - * @private - */ - p._clean = function () { - clearTimeout(this._loadTimeout); - - if (this._request.removeEventListener != null) { - this._request.removeEventListener("loadstart", this._handleLoadStartProxy); - this._request.removeEventListener("progress", this._handleProgressProxy); - this._request.removeEventListener("abort", this._handleAbortProxy); - this._request.removeEventListener("error", this._handleErrorProxy); - this._request.removeEventListener("timeout", this._handleTimeoutProxy); - this._request.removeEventListener("load", this._handleLoadProxy); - this._request.removeEventListener("readystatechange", this._handleReadyStateChangeProxy); - } else { - this._request.onloadstart = null; - this._request.onprogress = null; - this._request.onabort = null; - this._request.onerror = null; - this._request.ontimeout = null; - this._request.onload = null; - this._request.onreadystatechange = null; - } - }; - - p.toString = function () { - return "[PreloadJS XHRRequest]"; - }; - - createjs.XHRRequest = createjs.promote(XHRRequest, "AbstractRequest"); - -}()); - -//############################################################################## -// LoadQueue.js -//############################################################################## - -this.createjs = this.createjs || {}; - -/* - TODO: WINDOWS ISSUES - * No error for HTML audio in IE 678 - * SVG no failure error in IE 67 (maybe 8) TAGS AND XHR - * No script complete handler in IE 67 TAGS (XHR is fine) - * No XML/JSON in IE6 TAGS - * Need to hide loading SVG in Opera TAGS - * No CSS onload/readystatechange in Safari or Android TAGS (requires rule checking) - * SVG no load or failure in Opera XHR - * Reported issues with IE7/8 - */ - -(function () { - "use strict"; - -// constructor - /** - * The LoadQueue class is the main API for preloading content. LoadQueue is a load manager, which can preload either - * a single file, or queue of files. - * - * Creating a Queue
- * To use LoadQueue, create a LoadQueue instance. If you want to force tag loading where possible, set the preferXHR - * argument to false. - * - * var queue = new createjs.LoadQueue(true); - * - * Listening for Events
- * Add any listeners you want to the queue. Since PreloadJS 0.3.0, the {{#crossLink "EventDispatcher"}}{{/crossLink}} - * lets you add as many listeners as you want for events. You can subscribe to the following events:
    - *
  • {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}}: fired when a queue completes loading all - * files
  • - *
  • {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}: fired when the queue encounters an error with - * any file.
  • - *
  • {{#crossLink "AbstractLoader/progress:event"}}{{/crossLink}}: Progress for the entire queue has - * changed.
  • - *
  • {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}}: A single file has completed loading.
  • - *
  • {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}}: Progress for a single file has changes. Note - * that only files loaded with XHR (or possibly by plugins) will fire progress events other than 0 or 100%.
  • - *
- * - * queue.on("fileload", handleFileLoad, this); - * queue.on("complete", handleComplete, this); - * - * Adding files and manifests
- * Add files you want to load using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or add multiple files at a - * time using a list or a manifest definition using {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. Files are - * appended to the end of the active queue, so you can use these methods as many times as you like, whenever you - * like. - * - * queue.loadFile("filePath/file.jpg"); - * queue.loadFile({id:"image", src:"filePath/file.jpg"}); - * queue.loadManifest(["filePath/file.jpg", {id:"image", src:"filePath/file.jpg"}]); - * - * // Use an external manifest - * queue.loadManifest("path/to/manifest.json"); - * queue.loadManifest({src:"manifest.json", type:"manifest"}); - * - * If you pass `false` as the `loadNow` parameter, the queue will not kick of the load of the files, but it will not - * stop if it has already been started. Call the {{#crossLink "AbstractLoader/load"}}{{/crossLink}} method to begin - * a paused queue. Note that a paused queue will automatically resume when new files are added to it with a - * `loadNow` argument of `true`. - * - * queue.load(); - * - * File Types
- * The file type of a manifest item is auto-determined by the file extension. The pattern matching in PreloadJS - * should handle the majority of standard file and url formats, and works with common file extensions. If you have - * either a non-standard file extension, or are serving the file using a proxy script, then you can pass in a - * type property with any manifest item. - * - * queue.loadFile({src:"path/to/myFile.mp3x", type:createjs.AbstractLoader.SOUND}); - * - * // Note that PreloadJS will not read a file extension from the query string - * queue.loadFile({src:"http://server.com/proxy?file=image.jpg", type:createjs.AbstractLoader.IMAGE}); - * - * Supported types are defined on the {{#crossLink "AbstractLoader"}}{{/crossLink}} class, and include: - *
    - *
  • {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}}: Raw binary data via XHR
  • - *
  • {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}}: CSS files
  • - *
  • {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}: Common image formats
  • - *
  • {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}}: JavaScript files
  • - *
  • {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}}: JSON data
  • - *
  • {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}}: JSON files cross-domain
  • - *
  • {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}: A list of files to load in JSON format, see - * {{#crossLink "AbstractLoader/loadManifest"}}{{/crossLink}}
  • - *
  • {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}: Audio file formats
  • - *
  • {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}: JSON SpriteSheet definitions. This - * will also load sub-images, and provide a {{#crossLink "SpriteSheet"}}{{/crossLink}} instance.
  • - *
  • {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}}: SVG files
  • - *
  • {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}}: Text files - XHR only
  • - *
  • {{#crossLink "AbstractLoader/VIDEO:property"}}{{/crossLink}}: Video objects
  • - *
  • {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}}: XML data
  • - *
- * - * Note: Loader types used to be defined on LoadQueue, but have been moved to AbstractLoader for better - * portability of loader classes, which can be used individually now. The properties on LoadQueue still exist, but - * are deprecated. - * - * Handling Results
- * When a file is finished downloading, a {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event is - * dispatched. In an example above, there is an event listener snippet for fileload. Loaded files are usually a - * formatted object that can be used immediately, including: - *
    - *
  • Binary: The binary loaded result
  • - *
  • CSS: A <link /> tag
  • - *
  • Image: An <img /> tag
  • - *
  • JavaScript: A <script /> tag
  • - *
  • JSON/JSONP: A formatted JavaScript Object
  • - *
  • Manifest: A JavaScript object. - *
  • Sound: An <audio /> tag - *
  • SpriteSheet: A {{#crossLink "SpriteSheet"}}{{/crossLink}} instance, containing loaded images. - *
  • SVG: An <object /> tag
  • - *
  • Text: Raw text
  • - *
  • Video: A Video DOM node
  • - *
  • XML: An XML DOM node
  • - *
- * - * function handleFileLoad(event) { - * var item = event.item; // A reference to the item that was passed in to the LoadQueue - * var type = item.type; - * - * // Add any images to the page body. - * if (type == createjs.LoadQueue.IMAGE) { - * document.body.appendChild(event.result); - * } - * } - * - * At any time after the file has been loaded (usually after the queue has completed), any result can be looked up - * via its "id" using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. If no id was provided, then the - * "src" or file path can be used instead, including the `path` defined by a manifest, but not including - * a base path defined on the LoadQueue. It is recommended to always pass an id if you want to look up content. - * - * var image = queue.getResult("image"); - * document.body.appendChild(image); - * - * Raw loaded content can be accessed using the rawResult property of the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} - * event, or can be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}, passing `true` as the 2nd - * argument. This is only applicable for content that has been parsed for the browser, specifically: JavaScript, - * CSS, XML, SVG, and JSON objects, or anything loaded with XHR. - * - * var image = queue.getResult("image", true); // load the binary image data loaded with XHR. - * - * Plugins
- * LoadQueue has a simple plugin architecture to help process and preload content. For example, to preload audio, - * make sure to install the SoundJS Sound class, which will help load HTML audio, - * Flash audio, and WebAudio files. This should be installed before loading any audio files. - * - * queue.installPlugin(createjs.Sound); - * - *

Known Browser Issues

- *
    - *
  • Browsers without audio support can not load audio files.
  • - *
  • Safari on Mac OS X can only play HTML audio if QuickTime is installed
  • - *
  • HTML Audio tags will only download until their canPlayThrough event is fired. Browsers other - * than Chrome will continue to download in the background.
  • - *
  • When loading scripts using tags, they are automatically added to the document.
  • - *
  • Scripts loaded via XHR may not be properly inspectable with browser tools.
  • - *
  • IE6 and IE7 (and some other browsers) may not be able to load XML, Text, or JSON, since they require - * XHR to work.
  • - *
  • Content loaded via tags will not show progress, and will continue to download in the background when - * canceled, although no events will be dispatched.
  • - *
- * - * @class LoadQueue - * @param {Boolean} [preferXHR=true] Determines whether the preload instance will favor loading with XHR (XML HTTP - * Requests), or HTML tags. When this is `false`, the queue will use tag loading when possible, and fall back on XHR - * when necessary. - * @param {String} [basePath=""] A path that will be prepended on to the source parameter of all items in the queue - * before they are loaded. Sources beginning with a protocol such as `http://` or a relative path such as `../` - * will not receive a base path. - * @param {String|Boolean} [crossOrigin=""] An optional flag to support images loaded from a CORS-enabled server. To - * use it, set this value to `true`, which will default the crossOrigin property on images to "Anonymous". Any - * string value will be passed through, but only "" and "Anonymous" are recommended. Note: The crossOrigin - * parameter is deprecated. Use LoadItem.crossOrigin instead - * - * @constructor - * @extends AbstractLoader - */ - function LoadQueue (preferXHR, basePath, crossOrigin) { - this.AbstractLoader_constructor(); - - /** - * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}. - * @property _plugins - * @type {Array} - * @private - * @since 0.6.1 - */ - this._plugins = []; - - /** - * An object hash of callbacks that are fired for each file type before the file is loaded, giving plugins the - * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} - * method for more information. - * @property _typeCallbacks - * @type {Object} - * @private - */ - this._typeCallbacks = {}; - - /** - * An object hash of callbacks that are fired for each file extension before the file is loaded, giving plugins the - * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} - * method for more information. - * @property _extensionCallbacks - * @type {null} - * @private - */ - this._extensionCallbacks = {}; - - /** - * The next preload queue to process when this one is complete. If an error is thrown in the current queue, and - * {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} is `true`, the next queue will not be processed. - * @property next - * @type {LoadQueue} - * @default null - */ - this.next = null; - - /** - * Ensure loaded scripts "complete" in the order they are specified. Loaded scripts are added to the document head - * once they are loaded. Scripts loaded via tags will load one-at-a-time when this property is `true`, whereas - * scripts loaded using XHR can load in any order, but will "finish" and be added to the document in the order - * specified. - * - * Any items can be set to load in order by setting the {{#crossLink "maintainOrder:property"}}{{/crossLink}} - * property on the load item, or by ensuring that only one connection can be open at a time using - * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Note that when the `maintainScriptOrder` property - * is set to `true`, scripts items are automatically set to `maintainOrder=true`, and changing the - * `maintainScriptOrder` to `false` during a load will not change items already in a queue. - * - *

Example

- * - * var queue = new createjs.LoadQueue(); - * queue.setMaxConnections(3); // Set a higher number to load multiple items at once - * queue.maintainScriptOrder = true; // Ensure scripts are loaded in order - * queue.loadManifest([ - * "script1.js", - * "script2.js", - * "image.png", // Load any time - * {src: "image2.png", maintainOrder: true} // Will wait for script2.js - * "image3.png", - * "script3.js" // Will wait for image2.png before loading (or completing when loading with XHR) - * ]); - * - * @property maintainScriptOrder - * @type {Boolean} - * @default true - */ - this.maintainScriptOrder = true; - - /** - * Determines if the LoadQueue will stop processing the current queue when an error is encountered. - * @property stopOnError - * @type {Boolean} - * @default false - */ - this.stopOnError = false; - - /** - * The number of maximum open connections that a loadQueue tries to maintain. Please see - * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} for more information. - * @property _maxConnections - * @type {Number} - * @default 1 - * @private - */ - this._maxConnections = 1; - - /** - * An internal list of all the default Loaders that are included with PreloadJS. Before an item is loaded, the - * available loader list is iterated, in the order they are included, and as soon as a loader indicates it can - * handle the content, it will be selected. The default loader, ({{#crossLink "TextLoader"}}{{/crossLink}} is - * last in the list, so it will be used if no other match is found. Typically, loaders will match based on the - * {{#crossLink "LoadItem/type"}}{{/crossLink}}, which is automatically determined using the file extension of - * the {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. - * - * Loaders can be removed from PreloadJS by simply not including them. - * - * Custom loaders installed using {{#crossLink "registerLoader"}}{{/crossLink}} will be prepended to this list - * so that they are checked first. - * @property _availableLoaders - * @type {Array} - * @private - * @since 0.6.0 - */ - this._availableLoaders = [ - createjs.ImageLoader, - createjs.JavaScriptLoader, - createjs.CSSLoader, - createjs.JSONLoader, - createjs.JSONPLoader, - createjs.SoundLoader, - createjs.ManifestLoader, - createjs.SpriteSheetLoader, - createjs.XMLLoader, - createjs.SVGLoader, - createjs.BinaryLoader, - createjs.VideoLoader, - createjs.TextLoader - ]; - - /** - * The number of built in loaders, so they can't be removed by {{#crossLink "unregisterLoader"}}{{/crossLink}. - * @property _defaultLoaderLength - * @type {Number} - * @private - * @since 0.6.0 - */ - this._defaultLoaderLength = this._availableLoaders.length; - - this.init(preferXHR, basePath, crossOrigin); - } - - var p = createjs.extend(LoadQueue, createjs.AbstractLoader); - var s = LoadQueue; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - /** - * An internal initialization method, which is used for initial set up, but also to reset the LoadQueue. - * @method init - * @param preferXHR - * @param basePath - * @param crossOrigin - * @private - */ - p.init = function (preferXHR, basePath, crossOrigin) { - - // public properties - /** - * @property useXHR - * @type {Boolean} - * @readonly - * @default true - * @deprecated Use preferXHR instead. - */ - this.useXHR = true; - - /** - * Try and use XMLHttpRequest (XHR) when possible. Note that LoadQueue will default to tag loading or XHR - * loading depending on the requirements for a media type. For example, HTML audio can not be loaded with XHR, - * and plain text can not be loaded with tags, so it will default the the correct type instead of using the - * user-defined type. - * @type {Boolean} - * @default true - * @since 0.6.0 - */ - this.preferXHR = true; //TODO: Get/Set - this._preferXHR = true; - this.setPreferXHR(preferXHR); - - // protected properties - /** - * Whether the queue is currently paused or not. - * @property _paused - * @type {boolean} - * @private - */ - this._paused = false; - - /** - * A path that will be prepended on to the item's {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. The - * `_basePath` property will only be used if an item's source is relative, and does not include a protocol such - * as `http://`, or a relative path such as `../`. - * @property _basePath - * @type {String} - * @private - * @since 0.3.1 - */ - this._basePath = basePath; - - /** - * An optional flag to set on images that are loaded using PreloadJS, which enables CORS support. Images loaded - * cross-domain by servers that support CORS require the crossOrigin flag to be loaded and interacted with by - * a canvas. When loading locally, or with a server with no CORS support, this flag can cause other security issues, - * so it is recommended to only set it if you are sure the server supports it. Currently, supported values are "" - * and "Anonymous". - * @property _crossOrigin - * @type {String} - * @default "" - * @private - * @since 0.4.1 - */ - this._crossOrigin = crossOrigin; - - /** - * Determines if the loadStart event was dispatched already. This event is only fired one time, when the first - * file is requested. - * @property _loadStartWasDispatched - * @type {Boolean} - * @default false - * @private - */ - this._loadStartWasDispatched = false; - - /** - * Determines if there is currently a script loading. This helps ensure that only a single script loads at once when - * using a script tag to do preloading. - * @property _currentlyLoadingScript - * @type {Boolean} - * @private - */ - this._currentlyLoadingScript = null; - - /** - * An array containing the currently downloading files. - * @property _currentLoads - * @type {Array} - * @private - */ - this._currentLoads = []; - - /** - * An array containing the queued items that have not yet started downloading. - * @property _loadQueue - * @type {Array} - * @private - */ - this._loadQueue = []; - - /** - * An array containing downloads that have not completed, so that the LoadQueue can be properly reset. - * @property _loadQueueBackup - * @type {Array} - * @private - */ - this._loadQueueBackup = []; - - /** - * An object hash of items that have finished downloading, indexed by the {{#crossLink "LoadItem"}}{{/crossLink}} - * id. - * @property _loadItemsById - * @type {Object} - * @private - */ - this._loadItemsById = {}; - - /** - * An object hash of items that have finished downloading, indexed by {{#crossLink "LoadItem"}}{{/crossLink}} - * source. - * @property _loadItemsBySrc - * @type {Object} - * @private - */ - this._loadItemsBySrc = {}; - - /** - * An object hash of loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. - * @property _loadedResults - * @type {Object} - * @private - */ - this._loadedResults = {}; - - /** - * An object hash of un-parsed loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. - * @property _loadedRawResults - * @type {Object} - * @private - */ - this._loadedRawResults = {}; - - /** - * The number of items that have been requested. This helps manage an overall progress without knowing how large - * the files are before they are downloaded. This does not include items inside of loaders such as the - * {{#crossLink "ManifestLoader"}}{{/crossLink}}. - * @property _numItems - * @type {Number} - * @default 0 - * @private - */ - this._numItems = 0; - - /** - * The number of items that have completed loaded. This helps manage an overall progress without knowing how large - * the files are before they are downloaded. - * @property _numItemsLoaded - * @type {Number} - * @default 0 - * @private - */ - this._numItemsLoaded = 0; - - /** - * A list of scripts in the order they were requested. This helps ensure that scripts are "completed" in the right - * order. - * @property _scriptOrder - * @type {Array} - * @private - */ - this._scriptOrder = []; - - /** - * A list of scripts that have been loaded. Items are added to this list as null when they are - * requested, contain the loaded item if it has completed, but not been dispatched to the user, and true - * once they are complete and have been dispatched. - * @property _loadedScripts - * @type {Array} - * @private - */ - this._loadedScripts = []; - - /** - * The last progress amount. This is used to suppress duplicate progress events. - * @property _lastProgress - * @type {Number} - * @private - * @since 0.6.0 - */ - this._lastProgress = NaN; - - }; - -// static properties - /** - * The time in milliseconds to assume a load has failed. An {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} - * event is dispatched if the timeout is reached before any data is received. - * @property loadTimeout - * @type {Number} - * @default 8000 - * @static - * @since 0.4.1 - * @deprecated In favour of {{#crossLink "LoadItem/LOAD_TIMEOUT_DEFAULT:property}}{{/crossLink}} property. - */ - s.loadTimeout = 8000; - - /** - * The time in milliseconds to assume a load has failed. - * @property LOAD_TIMEOUT - * @type {Number} - * @default 0 - * @deprecated in favor of the {{#crossLink "LoadQueue/loadTimeout:property"}}{{/crossLink}} property. - */ - s.LOAD_TIMEOUT = 0; - -// Preload Types - /** - * @property BINARY - * @type {String} - * @default binary - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}} instead. - */ - s.BINARY = createjs.AbstractLoader.BINARY; - - /** - * @property CSS - * @type {String} - * @default css - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. - */ - s.CSS = createjs.AbstractLoader.CSS; - - /** - * @property IMAGE - * @type {String} - * @default image - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. - */ - s.IMAGE = createjs.AbstractLoader.IMAGE; - - /** - * @property JAVASCRIPT - * @type {String} - * @default javascript - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. - */ - s.JAVASCRIPT = createjs.AbstractLoader.JAVASCRIPT; - - /** - * @property JSON - * @type {String} - * @default json - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}} instead. - */ - s.JSON = createjs.AbstractLoader.JSON; - - /** - * @property JSONP - * @type {String} - * @default jsonp - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}} instead. - */ - s.JSONP = createjs.AbstractLoader.JSONP; - - /** - * @property MANIFEST - * @type {String} - * @default manifest - * @static - * @since 0.4.1 - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}} instead. - */ - s.MANIFEST = createjs.AbstractLoader.MANIFEST; - - /** - * @property SOUND - * @type {String} - * @default sound - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. - */ - s.SOUND = createjs.AbstractLoader.SOUND; - - /** - * @property VIDEO - * @type {String} - * @default video - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. - */ - s.VIDEO = createjs.AbstractLoader.VIDEO; - - /** - * @property SVG - * @type {String} - * @default svg - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}} instead. - */ - s.SVG = createjs.AbstractLoader.SVG; - - /** - * @property TEXT - * @type {String} - * @default text - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}} instead. - */ - s.TEXT = createjs.AbstractLoader.TEXT; - - /** - * @property XML - * @type {String} - * @default xml - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}} instead. - */ - s.XML = createjs.AbstractLoader.XML; - - /** - * @property POST - * @type {string} - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} instead. - */ - s.POST = createjs.AbstractLoader.POST; - - /** - * @property GET - * @type {string} - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} instead. - */ - s.GET = createjs.AbstractLoader.GET; - -// events - /** - * This event is fired when an individual file has loaded, and been processed. - * @event fileload - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the - * object will contain that value as a `src` property. - * @param {Object} result The HTML tag or parsed result of the loaded item. - * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted - * to a usable object. - * @since 0.3.0 - */ - - /** - * This {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when an an individual file's progress changes. - * @event fileprogress - * @since 0.3.0 - */ - - /** - * This event is fired when an individual file starts to load. - * @event filestart - * @param {Object} The object that dispatched the event. - * @param {String} type The event type. - * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the - * object will contain that value as a property. - */ - - /** - * Although it extends {{#crossLink "AbstractLoader"}}{{/crossLink}}, the `initialize` event is never fired from - * a LoadQueue instance. - * @event initialize - * @private - */ - -// public methods - /** - * Register a custom loaders class. New loaders are given precedence over loaders added earlier and default loaders. - * It is recommended that loaders extend {{#crossLink "AbstractLoader"}}{{/crossLink}}. Loaders can only be added - * once, and will be prepended to the list of available loaders. - * @method registerLoader - * @param {Function|AbstractLoader} loader The AbstractLoader class to add. - * @since 0.6.0 - */ - p.registerLoader = function (loader) { - if (!loader || !loader.canLoadItem) { - throw new Error("loader is of an incorrect type."); - } else if (this._availableLoaders.indexOf(loader) != -1) { - throw new Error("loader already exists."); //LM: Maybe just silently fail here - } - - this._availableLoaders.unshift(loader); - }; - - /** - * Remove a custom loader added using {{#crossLink "registerLoader"}}{{/crossLink}}. Only custom loaders can be - * unregistered, the default loaders will always be available. - * @method unregisterLoader - * @param {Function|AbstractLoader} loader The AbstractLoader class to remove - */ - p.unregisterLoader = function (loader) { - var idx = this._availableLoaders.indexOf(loader); - if (idx != -1 && idx < this._defaultLoaderLength - 1) { - this._availableLoaders.splice(idx, 1); - } - }; - - /** - * @method setUseXHR - * @param {Boolean} value The new useXHR value to set. - * @return {Boolean} The new useXHR value. If XHR is not supported by the browser, this will return false, even if - * the provided value argument was true. - * @since 0.3.0 - * @deprecated use the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property, or the - * {{#crossLink "LoadQueue/setUseXHR"}}{{/crossLink}} method instead. - */ - p.setUseXHR = function (value) { - return this.setPreferXHR(value); - }; - - /** - * Change the {{#crossLink "preferXHR:property"}}{{/crossLink}} value. Note that if this is set to `true`, it may - * fail, or be ignored depending on the browser's capabilities and the load type. - * @method setPreferXHR - * @param {Boolean} value - * @returns {Boolean} The value of {{#crossLink "preferXHR"}}{{/crossLink}} that was successfully set. - * @since 0.6.0 - */ - p.setPreferXHR = function (value) { - // Determine if we can use XHR. XHR defaults to TRUE, but the browser may not support it. - //TODO: Should we be checking for the other XHR types? Might have to do a try/catch on the different types similar to createXHR. - this.preferXHR = (value != false && window.XMLHttpRequest != null); - return this.preferXHR; - }; - - /** - * Stops all queued and loading items, and clears the queue. This also removes all internal references to loaded - * content, and allows the queue to be used again. - * @method removeAll - * @since 0.3.0 - */ - p.removeAll = function () { - this.remove(); - }; - - /** - * Stops an item from being loaded, and removes it from the queue. If nothing is passed, all items are removed. - * This also removes internal references to loaded item(s). - * - *

Example

- * - * queue.loadManifest([ - * {src:"test.png", id:"png"}, - * {src:"test.jpg", id:"jpg"}, - * {src:"test.mp3", id:"mp3"} - * ]); - * queue.remove("png"); // Single item by ID - * queue.remove("png", "test.jpg"); // Items as arguments. Mixed id and src. - * queue.remove(["test.png", "jpg"]); // Items in an Array. Mixed id and src. - * - * @method remove - * @param {String | Array} idsOrUrls* The id or ids to remove from this queue. You can pass an item, an array of - * items, or multiple items as arguments. - * @since 0.3.0 - */ - p.remove = function (idsOrUrls) { - var args = null; - - if (idsOrUrls && !Array.isArray(idsOrUrls)) { - args = [idsOrUrls]; - } else if (idsOrUrls) { - args = idsOrUrls; - } else if (arguments.length > 0) { - return; - } - - var itemsWereRemoved = false; - - // Destroy everything - if (!args) { - this.close(); - for (var n in this._loadItemsById) { - this._disposeItem(this._loadItemsById[n]); - } - this.init(this.preferXHR, this._basePath); - - // Remove specific items - } else { - while (args.length) { - var item = args.pop(); - var r = this.getResult(item); - - //Remove from the main load Queue - for (i = this._loadQueue.length - 1; i >= 0; i--) { - loadItem = this._loadQueue[i].getItem(); - if (loadItem.id == item || loadItem.src == item) { - this._loadQueue.splice(i, 1)[0].cancel(); - break; - } - } - - //Remove from the backup queue - for (i = this._loadQueueBackup.length - 1; i >= 0; i--) { - loadItem = this._loadQueueBackup[i].getItem(); - if (loadItem.id == item || loadItem.src == item) { - this._loadQueueBackup.splice(i, 1)[0].cancel(); - break; - } - } - - if (r) { - this._disposeItem(this.getItem(item)); - } else { - for (var i = this._currentLoads.length - 1; i >= 0; i--) { - var loadItem = this._currentLoads[i].getItem(); - if (loadItem.id == item || loadItem.src == item) { - this._currentLoads.splice(i, 1)[0].cancel(); - itemsWereRemoved = true; - break; - } - } - } - } - - // If this was called during a load, try to load the next item. - if (itemsWereRemoved) { - this._loadNext(); - } - } - }; - - /** - * Stops all open loads, destroys any loaded items, and resets the queue, so all items can - * be reloaded again by calling {{#crossLink "AbstractLoader/load"}}{{/crossLink}}. Items are not removed from the - * queue. To remove items use the {{#crossLink "LoadQueue/remove"}}{{/crossLink}} or - * {{#crossLink "LoadQueue/removeAll"}}{{/crossLink}} method. - * @method reset - * @since 0.3.0 - */ - p.reset = function () { - this.close(); - for (var n in this._loadItemsById) { - this._disposeItem(this._loadItemsById[n]); - } - - //Reset the queue to its start state - var a = []; - for (var i = 0, l = this._loadQueueBackup.length; i < l; i++) { - a.push(this._loadQueueBackup[i].getItem()); - } - - this.loadManifest(a, false); - }; - - /** - * Register a plugin. Plugins can map to load types (sound, image, etc), or specific extensions (png, mp3, etc). - * Currently, only one plugin can exist per type/extension. - * - * When a plugin is installed, a getPreloadHandlers() method will be called on it. For more information - * on this method, check out the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method in the - * {{#crossLink "SamplePlugin"}}{{/crossLink}} class. - * - * Before a file is loaded, a matching plugin has an opportunity to modify the load. If a `callback` is returned - * from the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method, it will be invoked first, and its - * result may cancel or modify the item. The callback method can also return a `completeHandler` to be fired when - * the file is loaded, or a `tag` object, which will manage the actual download. For more information on these - * methods, check out the {{#crossLink "SamplePlugin/preloadHandler"}}{{/crossLink}} and {{#crossLink "SamplePlugin/fileLoadHandler"}}{{/crossLink}} - * methods on the {{#crossLink "SamplePlugin"}}{{/crossLink}}. - * - * @method installPlugin - * @param {Function} plugin The plugin class to install. - */ - p.installPlugin = function (plugin) { - if (plugin == null) { - return; - } - - if (plugin.getPreloadHandlers != null) { - this._plugins.push(plugin); - var map = plugin.getPreloadHandlers(); - map.scope = plugin; - - if (map.types != null) { - for (var i = 0, l = map.types.length; i < l; i++) { - this._typeCallbacks[map.types[i]] = map; - } - } - - if (map.extensions != null) { - for (i = 0, l = map.extensions.length; i < l; i++) { - this._extensionCallbacks[map.extensions[i]] = map; - } - } - } - }; - - /** - * Set the maximum number of concurrent connections. Note that browsers and servers may have a built-in maximum - * number of open connections, so any additional connections may remain in a pending state until the browser - * opens the connection. When loading scripts using tags, and when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} - * is `true`, only one script is loaded at a time due to browser limitations. - * - *

Example

- * - * var queue = new createjs.LoadQueue(); - * queue.setMaxConnections(10); // Allow 10 concurrent loads - * - * @method setMaxConnections - * @param {Number} value The number of concurrent loads to allow. By default, only a single connection per LoadQueue - * is open at any time. - */ - p.setMaxConnections = function (value) { - this._maxConnections = value; - if (!this._paused && this._loadQueue.length > 0) { - this._loadNext(); - } - }; - - /** - * Load a single file. To add multiple files at once, use the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} - * method. - * - * Files are always appended to the current queue, so this method can be used multiple times to add files. - * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. - * @method loadFile - * @param {LoadItem|Object|String} file The file object or path to load. A file can be either - *
    - *
  • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
  • - *
  • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
  • - *
  • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} - * in the background.
  • - *
- * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default - * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}}, and the value is - * `true`, the queue will resume automatically. - * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the - * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}, - * its files will NOT use the basePath parameter. The basePath parameter is deprecated. - * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue - * constructor, or a `path` property in a manifest definition. - */ - p.loadFile = function (file, loadNow, basePath) { - if (file == null) { - var event = new createjs.ErrorEvent("PRELOAD_NO_FILE"); - this._sendError(event); - return; - } - this._addItem(file, null, basePath); - - if (loadNow !== false) { - this.setPaused(false); - } else { - this.setPaused(true); - } - }; - - /** - * Load an array of files. To load a single file, use the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} method. - * The files in the manifest are requested in the same order, but may complete in a different order if the max - * connections are set above 1 using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Scripts will load - * in the right order as long as {{#crossLink "LoadQueue/maintainScriptOrder"}}{{/crossLink}} is true (which is - * default). - * - * Files are always appended to the current queue, so this method can be used multiple times to add files. - * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. - * @method loadManifest - * @param {Array|String|Object} manifest An list of files to load. The loadManifest call supports four types of - * manifests: - *
    - *
  1. A string path, which points to a manifest file, which is a JSON file that contains a "manifest" property, - * which defines the list of files to load, and can optionally contain a "path" property, which will be - * prepended to each file in the list.
  2. - *
  3. An object which defines a "src", which is a JSON or JSONP file. A "callback" can be defined for JSONP - * file. The JSON/JSONP file should contain a "manifest" property, which defines the list of files to load, - * and can optionally contain a "path" property, which will be prepended to each file in the list.
  4. - *
  5. An object which contains a "manifest" property, which defines the list of files to load, and can - * optionally contain a "path" property, which will be prepended to each file in the list.
  6. - *
  7. An Array of files to load.
  8. - *
- * - * Each "file" in a manifest can be either: - *
    - *
  • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
  • - *
  • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
  • - *
  • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} - * in the background.
  • - *
- * - * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default - * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} and this value is - * `true`, the queue will resume automatically. - * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the - * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "LoadQueue/MANIFEST:property"}}{{/crossLink}}, - * its files will NOT use the basePath parameter. The basePath parameter is deprecated. - * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue - * constructor, or a `path` property in a manifest definition. - */ - p.loadManifest = function (manifest, loadNow, basePath) { - var fileList = null; - var path = null; - - // Array-based list of items - if (Array.isArray(manifest)) { - if (manifest.length == 0) { - var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_EMPTY"); - this._sendError(event); - return; - } - fileList = manifest; - - // String-based. Only file manifests can be specified this way. Any other types will cause an error when loaded. - } else if (typeof(manifest) === "string") { - fileList = [ - { - src: manifest, - type: s.MANIFEST - } - ]; - - } else if (typeof(manifest) == "object") { - - // An object that defines a manifest path - if (manifest.src !== undefined) { - if (manifest.type == null) { - manifest.type = s.MANIFEST; - } else if (manifest.type != s.MANIFEST) { - var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_TYPE"); - this._sendError(event); - } - fileList = [manifest]; - - // An object that defines a manifest - } else if (manifest.manifest !== undefined) { - fileList = manifest.manifest; - path = manifest.path; - } - - // Unsupported. This will throw an error. - } else { - var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_NULL"); - this._sendError(event); - return; - } - - for (var i = 0, l = fileList.length; i < l; i++) { - this._addItem(fileList[i], path, basePath); - } - - if (loadNow !== false) { - this.setPaused(false); - } else { - this.setPaused(true); - } - - }; - - /** - * Start a LoadQueue that was created, but not automatically started. - * @method load - */ - p.load = function () { - this.setPaused(false); - }; - - /** - * Look up a {{#crossLink "LoadItem"}}{{/crossLink}} using either the "id" or "src" that was specified when loading it. Note that if no "id" was - * supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The - * `basePath` will not be part of the ID. - * @method getItem - * @param {String} value The id or src of the load item. - * @return {Object} The load item that was initially requested using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} - * event as the `item` parameter. - */ - p.getItem = function (value) { - return this._loadItemsById[value] || this._loadItemsBySrc[value]; - }; - - /** - * Look up a loaded result using either the "id" or "src" that was specified when loading it. Note that if no "id" - * was supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The - * `basePath` will not be part of the ID. - * @method getResult - * @param {String} value The id or src of the load item. - * @param {Boolean} [rawResult=false] Return a raw result instead of a formatted result. This applies to content - * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be - * returned instead. - * @return {Object} A result object containing the content that was loaded, such as: - *
    - *
  • An image tag (<image />) for images
  • - *
  • A script tag for JavaScript (<script />). Note that scripts are automatically added to the HTML - * DOM.
  • - *
  • A style tag for CSS (<style /> or <link >)
  • - *
  • Raw text for TEXT
  • - *
  • A formatted JavaScript object defined by JSON
  • - *
  • An XML document
  • - *
  • A binary arraybuffer loaded by XHR
  • - *
  • An audio tag (<audio >) for HTML audio. Note that it is recommended to use SoundJS APIs to play - * loaded audio. Specifically, audio loaded by Flash and WebAudio will return a loader object using this method - * which can not be used to play audio back.
  • - *
- * This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event as the 'item` - * parameter. Note that if a raw result is requested, but not found, the result will be returned instead. - */ - p.getResult = function (value, rawResult) { - var item = this._loadItemsById[value] || this._loadItemsBySrc[value]; - if (item == null) { - return null; - } - var id = item.id; - if (rawResult && this._loadedRawResults[id]) { - return this._loadedRawResults[id]; - } - return this._loadedResults[id]; - }; - - /** - * Generate an list of items loaded by this queue. - * @method getItems - * @param {Boolean} loaded Determines if only items that have been loaded should be returned. If false, in-progress - * and failed load items will also be included. - * @returns {Array} A list of objects that have been loaded. Each item includes the {{#crossLink "LoadItem"}}{{/crossLink}}, - * result, and rawResult. - * @since 0.6.0 - */ - p.getItems = function (loaded) { - var arr = []; - for (var n in this._loadItemsById) { - var item = this._loadItemsById[n]; - var result = this.getResult(n); - if (loaded === true && result == null) { - continue; - } - arr.push({ - item: item, - result: result, - rawResult: this.getResult(n, true) - }); - } - return arr; - }; - - /** - * Pause or resume the current load. Active loads will not be cancelled, but the next items in the queue will not - * be processed when active loads complete. LoadQueues are not paused by default. - * - * Note that if new items are added to the queue using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or - * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}, a paused queue will be resumed, unless the `loadNow` - * argument is `false`. - * @method setPaused - * @param {Boolean} value Whether the queue should be paused or not. - */ - p.setPaused = function (value) { - this._paused = value; - if (!this._paused) { - this._loadNext(); - } - }; - - /** - * Close the active queue. Closing a queue completely empties the queue, and prevents any remaining items from - * starting to download. Note that currently any active loads will remain open, and events may be processed. - * - * To stop and restart a queue, use the {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} method instead. - * @method close - */ - p.close = function () { - while (this._currentLoads.length) { - this._currentLoads.pop().cancel(); - } - this._scriptOrder.length = 0; - this._loadedScripts.length = 0; - this.loadStartWasDispatched = false; - this._itemCount = 0; - this._lastProgress = NaN; - }; - -// protected methods - /** - * Add an item to the queue. Items are formatted into a usable object containing all the properties necessary to - * load the content. The load queue is populated with the loader instance that handles preloading, and not the load - * item that was passed in by the user. To look up the load item by id or src, use the {{#crossLink "LoadQueue.getItem"}}{{/crossLink}} - * method. - * @method _addItem - * @param {String|Object} value The item to add to the queue. - * @param {String} [path] An optional path prepended to the `src`. The path will only be prepended if the src is - * relative, and does not start with a protocol such as `http://`, or a path like `../`. If the LoadQueue was - * provided a {{#crossLink "_basePath"}}{{/crossLink}}, then it will optionally be prepended after. - * @param {String} [basePath] DeprecatedAn optional basePath passed into a {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} call. This parameter will be removed in a future tagged - * version. - * @private - */ - p._addItem = function (value, path, basePath) { - var item = this._createLoadItem(value, path, basePath); // basePath and manifest path are added to the src. - if (item == null) { - return; - } // Sometimes plugins or types should be skipped. - var loader = this._createLoader(item); - if (loader != null) { - if ("plugins" in loader) { - loader.plugins = this._plugins; - } - item._loader = loader; - this._loadQueue.push(loader); - this._loadQueueBackup.push(loader); - - this._numItems++; - this._updateProgress(); - - // Only worry about script order when using XHR to load scripts. Tags are only loading one at a time. - if ((this.maintainScriptOrder - && item.type == createjs.LoadQueue.JAVASCRIPT - //&& loader instanceof createjs.XHRLoader //NOTE: Have to track all JS files this way - ) - || item.maintainOrder === true) { - this._scriptOrder.push(item); - this._loadedScripts.push(null); - } - } - }; - - /** - * Create a refined {{#crossLink "LoadItem"}}{{/crossLink}}, which contains all the required properties. The type of - * item is determined by browser support, requirements based on the file type, and developer settings. For example, - * XHR is only used for file types that support it in new browsers. - * - * Before the item is returned, any plugins registered to handle the type or extension will be fired, which may - * alter the load item. - * @method _createLoadItem - * @param {String | Object | HTMLAudioElement | HTMLImageElement} value The item that needs to be preloaded. - * @param {String} [path] A path to prepend to the item's source. Sources beginning with http:// or similar will - * not receive a path. Since PreloadJS 0.4.1, the src will be modified to include the `path` and {{#crossLink "LoadQueue/_basePath:property"}}{{/crossLink}} - * when it is added. - * @param {String} [basePath] Deprectated A base path to prepend to the items source in addition to - * the path argument. - * @return {Object} The loader instance that will be used. - * @private - */ - p._createLoadItem = function (value, path, basePath) { - var item = createjs.LoadItem.create(value); - if (item == null) { - return null; - } - - var bp = ""; // Store the generated basePath - var useBasePath = basePath || this._basePath; - - if (item.src instanceof Object) { - if (!item.type) { - return null; - } // the the src is an object, type is required to pass off to plugin - if (path) { - bp = path; - var pathMatch = createjs.RequestUtils.parseURI(path); - // Also append basePath - if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { - bp = useBasePath + bp; - } - } else if (useBasePath != null) { - bp = useBasePath; - } - } else { - // Determine Extension, etc. - var match = createjs.RequestUtils.parseURI(item.src); - if (match.extension) { - item.ext = match.extension; - } - if (item.type == null) { - item.type = createjs.RequestUtils.getTypeByExtension(item.ext); - } - - // Inject path & basePath - var autoId = item.src; - if (!match.absolute && !match.relative) { - if (path) { - bp = path; - var pathMatch = createjs.RequestUtils.parseURI(path); - autoId = path + autoId; - // Also append basePath - if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { - bp = useBasePath + bp; - } - } else if (useBasePath != null) { - bp = useBasePath; - } - } - item.src = bp + item.src; - } - item.path = bp; - - // If there's no id, set one now. - if (item.id === undefined || item.id === null || item.id === "") { - item.id = autoId; - } - - // Give plugins a chance to modify the loadItem: - var customHandler = this._typeCallbacks[item.type] || this._extensionCallbacks[item.ext]; - if (customHandler) { - // Plugins are now passed both the full source, as well as a combined path+basePath (appropriately) - var result = customHandler.callback.call(customHandler.scope, item, this); - - // The plugin will handle the load, or has canceled it. Ignore it. - if (result === false) { - return null; - - // Load as normal: - } else if (result === true) { - // Do Nothing - - // Result is a loader class: - } else if (result != null) { - item._loader = result; - } - - // Update the extension in case the type changed: - match = createjs.RequestUtils.parseURI(item.src); - if (match.extension != null) { - item.ext = match.extension; - } - } - - // Store the item for lookup. This also helps clean-up later. - this._loadItemsById[item.id] = item; - this._loadItemsBySrc[item.src] = item; - - if (item.crossOrigin == null) { - item.crossOrigin = this._crossOrigin; - } - - return item; - }; - - /** - * Create a loader for a load item. - * @method _createLoader - * @param {Object} item A formatted load item that can be used to generate a loader. - * @return {AbstractLoader} A loader that can be used to load content. - * @private - */ - p._createLoader = function (item) { - if (item._loader != null) { // A plugin already specified a loader - return item._loader; - } - - // Initially, try and use the provided/supported XHR mode: - var preferXHR = this.preferXHR; - - for (var i = 0; i < this._availableLoaders.length; i++) { - var loader = this._availableLoaders[i]; - if (loader && loader.canLoadItem(item)) { - return new loader(item, preferXHR); - } - } - - // TODO: Log error (requires createjs.log) - return null; - }; - - /** - * Load the next item in the queue. If the queue is empty (all items have been loaded), then the complete event - * is processed. The queue will "fill up" any empty slots, up to the max connection specified using - * {{#crossLink "LoadQueue.setMaxConnections"}}{{/crossLink}} method. The only exception is scripts that are loaded - * using tags, which have to be loaded one at a time to maintain load order. - * @method _loadNext - * @private - */ - p._loadNext = function () { - if (this._paused) { - return; - } - - // Only dispatch loadstart event when the first file is loaded. - if (!this._loadStartWasDispatched) { - this._sendLoadStart(); - this._loadStartWasDispatched = true; - } - - // The queue has completed. - if (this._numItems == this._numItemsLoaded) { - this.loaded = true; - this._sendComplete(); - - // Load the next queue, if it has been defined. - if (this.next && this.next.load) { - this.next.load(); - } - } else { - this.loaded = false; - } - - // Must iterate forwards to load in the right order. - for (var i = 0; i < this._loadQueue.length; i++) { - if (this._currentLoads.length >= this._maxConnections) { - break; - } - var loader = this._loadQueue[i]; - - // Determine if we should be only loading one tag-script at a time: - // Note: maintainOrder items don't do anything here because we can hold onto their loaded value - if (!this._canStartLoad(loader)) { - continue; - } - this._loadQueue.splice(i, 1); - i--; - this._loadItem(loader); - } - }; - - /** - * Begin loading an item. Event listeners are not added to the loaders until the load starts. - * @method _loadItem - * @param {AbstractLoader} loader The loader instance to start. Currently, this will be an XHRLoader or TagLoader. - * @private - */ - p._loadItem = function (loader) { - loader.on("fileload", this._handleFileLoad, this); - loader.on("progress", this._handleProgress, this); - loader.on("complete", this._handleFileComplete, this); - loader.on("error", this._handleError, this); - loader.on("fileerror", this._handleFileError, this); - this._currentLoads.push(loader); - this._sendFileStart(loader.getItem()); - loader.load(); - }; - - /** - * The callback that is fired when a loader loads a file. This enables loaders like {{#crossLink "ManifestLoader"}}{{/crossLink}} - * to maintain internal queues, but for this queue to dispatch the {{#crossLink "fileload:event"}}{{/crossLink}} - * events. - * @param {Event} event The {{#crossLink "AbstractLoader/fileload:event"}}{{/crossLink}} event from the loader. - * @private - * @since 0.6.0 - */ - p._handleFileLoad = function (event) { - event.target = null; - this.dispatchEvent(event); - }; - - /** - * The callback that is fired when a loader encounters an error from an internal file load operation. This enables - * loaders like M - * @param event - * @private - */ - p._handleFileError = function (event) { - var newEvent = new createjs.ErrorEvent("FILE_LOAD_ERROR", null, event.item); - this._sendError(newEvent); - }; - - /** - * The callback that is fired when a loader encounters an error. The queue will continue loading unless {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} - * is set to `true`. - * @method _handleError - * @param {ErrorEvent} event The error event, containing relevant error information. - * @private - */ - p._handleError = function (event) { - var loader = event.target; - this._numItemsLoaded++; - - this._finishOrderedItem(loader, true); - this._updateProgress(); - - var newEvent = new createjs.ErrorEvent("FILE_LOAD_ERROR", null, loader.getItem()); - // TODO: Propagate actual error message. - - this._sendError(newEvent); - - if (!this.stopOnError) { - this._removeLoadItem(loader); - this._cleanLoadItem(loader); - this._loadNext(); - } else { - this.setPaused(true); - } - }; - - /** - * An item has finished loading. We can assume that it is totally loaded, has been parsed for immediate use, and - * is available as the "result" property on the load item. The raw text result for a parsed item (such as JSON, XML, - * CSS, JavaScript, etc) is available as the "rawResult" property, and can also be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. - * @method _handleFileComplete - * @param {Event} event The event object from the loader. - * @private - */ - p._handleFileComplete = function (event) { - var loader = event.target; - var item = loader.getItem(); - - var result = loader.getResult(); - this._loadedResults[item.id] = result; - var rawResult = loader.getResult(true); - if (rawResult != null && rawResult !== result) { - this._loadedRawResults[item.id] = rawResult; - } - - this._saveLoadedItems(loader); - - // Remove the load item - this._removeLoadItem(loader); - - if (!this._finishOrderedItem(loader)) { - // The item was NOT managed, so process it now - this._processFinishedLoad(item, loader); - } - - // Clean up the load item - this._cleanLoadItem(loader); - }; - - /** - * Some loaders might load additional content, other than the item they were passed (such as {{#crossLink "ManifestLoader"}}{{/crossLink}}). - * Any items exposed by the loader using {{#crossLink "AbstractLoader/getLoadItems"}}{{/crossLink}} are added to the - * LoadQueue's look-ups, including {{#crossLink "getItem"}}{{/crossLink}} and {{#crossLink "getResult"}}{{/crossLink}} - * methods. - * @method _saveLoadedItems - * @param {AbstractLoader} loader - * @protected - * @since 0.6.0 - */ - p._saveLoadedItems = function (loader) { - // TODO: Not sure how to handle this. Would be nice to expose the items. - // Loaders may load sub-items. This adds them to this queue - var list = loader.getLoadedItems(); - if (list === null) { - return; - } - - for (var i = 0; i < list.length; i++) { - var item = list[i].item; - - // Store item lookups - this._loadItemsBySrc[item.src] = item; - this._loadItemsById[item.id] = item; - - // Store loaded content - this._loadedResults[item.id] = list[i].result; - this._loadedRawResults[item.id] = list[i].rawResult; - } - }; - - /** - * Flag an item as finished. If the item's order is being managed, then ensure that it is allowed to finish, and if - * so, trigger prior items to trigger as well. - * @method _finishOrderedItem - * @param {AbstractLoader} loader - * @param {Boolean} loadFailed - * @return {Boolean} If the item's order is being managed. This allows the caller to take an alternate - * behaviour if it is. - * @private - */ - p._finishOrderedItem = function (loader, loadFailed) { - var item = loader.getItem(); - - if ((this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) - || item.maintainOrder) { - - //TODO: Evaluate removal of the _currentlyLoadingScript - if (loader instanceof createjs.JavaScriptLoader) { - this._currentlyLoadingScript = false; - } - - var index = createjs.indexOf(this._scriptOrder, item); - if (index == -1) { - return false; - } // This loader no longer exists - this._loadedScripts[index] = (loadFailed === true) ? true : item; - - this._checkScriptLoadOrder(); - return true; - } - - return false; - }; - - /** - * Ensure the scripts load and dispatch in the correct order. When using XHR, scripts are stored in an array in the - * order they were added, but with a "null" value. When they are completed, the value is set to the load item, - * and then when they are processed and dispatched, the value is set to `true`. This method simply - * iterates the array, and ensures that any loaded items that are not preceded by a `null` value are - * dispatched. - * @method _checkScriptLoadOrder - * @private - */ - p._checkScriptLoadOrder = function () { - var l = this._loadedScripts.length; - - for (var i = 0; i < l; i++) { - var item = this._loadedScripts[i]; - if (item === null) { - break; - } // This is still loading. Do not process further. - if (item === true) { - continue; - } // This has completed, and been processed. Move on. - - var loadItem = this._loadedResults[item.id]; - if (item.type == createjs.LoadQueue.JAVASCRIPT) { - // Append script tags to the head automatically. - createjs.DomUtils.appendToHead(loadItem); - } - - var loader = item._loader; - this._processFinishedLoad(item, loader); - this._loadedScripts[i] = true; - } - }; - - /** - * A file has completed loading, and the LoadQueue can move on. This triggers the complete event, and kick-starts - * the next item. - * @method _processFinishedLoad - * @param {LoadItem|Object} item - * @param {AbstractLoader} loader - * @protected - */ - p._processFinishedLoad = function (item, loader) { - this._numItemsLoaded++; - - // Since LoadQueue needs maintain order, we can't append scripts in the loader. - // So we do it here instead. Or in _checkScriptLoadOrder(); - if (!this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) { - var tag = loader.getTag(); - createjs.DomUtils.appendToHead(tag); - } - - this._updateProgress(); - this._sendFileComplete(item, loader); - this._loadNext(); - }; - - /** - * Ensure items with `maintainOrder=true` that are before the specified item have loaded. This only applies to - * JavaScript items that are being loaded with a TagLoader, since they have to be loaded and completed before - * the script can even be started, since it exist in the DOM while loading. - * @method _canStartLoad - * @param {AbstractLoader} loader The loader for the item - * @return {Boolean} Whether the item can start a load or not. - * @private - */ - p._canStartLoad = function (loader) { - if (!this.maintainScriptOrder || loader.preferXHR) { - return true; - } - var item = loader.getItem(); - if (item.type != createjs.LoadQueue.JAVASCRIPT) { - return true; - } - if (this._currentlyLoadingScript) { - return false; - } - - var index = this._scriptOrder.indexOf(item); - var i = 0; - while (i < index) { - var checkItem = this._loadedScripts[i]; - if (checkItem == null) { - return false; - } - i++; - } - this._currentlyLoadingScript = true; - return true; - }; - - /** - * A load item is completed or was canceled, and needs to be removed from the LoadQueue. - * @method _removeLoadItem - * @param {AbstractLoader} loader A loader instance to remove. - * @private - */ - p._removeLoadItem = function (loader) { - var l = this._currentLoads.length; - for (var i = 0; i < l; i++) { - if (this._currentLoads[i] == loader) { - this._currentLoads.splice(i, 1); - break; - } - } - }; - - /** - * Remove unneeded references from a loader. - * - * @param loader - * @private - */ - p._cleanLoadItem = function(loader) { - var item = loader.getItem(); - if (item) { - delete item._loader; - } - } - - /** - * An item has dispatched progress. Propagate that progress, and update the LoadQueue's overall progress. - * @method _handleProgress - * @param {ProgressEvent} event The progress event from the item. - * @private - */ - p._handleProgress = function (event) { - var loader = event.target; - this._sendFileProgress(loader.getItem(), loader.progress); - this._updateProgress(); - }; - - /** - * Overall progress has changed, so determine the new progress amount and dispatch it. This changes any time an - * item dispatches progress or completes. Note that since we don't always know the actual filesize of items before - * they are loaded. In this case, we define a "slot" for each item (1 item in 10 would get 10%), and then append - * loaded progress on top of the already-loaded items. - * - * For example, if 5/10 items have loaded, and item 6 is 20% loaded, the total progress would be: - *
    - *
  • 5/10 of the items in the queue (50%)
  • - *
  • plus 20% of item 6's slot (2%)
  • - *
  • equals 52%
  • - *
- * @method _updateProgress - * @private - */ - p._updateProgress = function () { - var loaded = this._numItemsLoaded / this._numItems; // Fully Loaded Progress - var remaining = this._numItems - this._numItemsLoaded; - if (remaining > 0) { - var chunk = 0; - for (var i = 0, l = this._currentLoads.length; i < l; i++) { - chunk += this._currentLoads[i].progress; - } - loaded += (chunk / remaining) * (remaining / this._numItems); - } - - if (this._lastProgress != loaded) { - this._sendProgress(loaded); - this._lastProgress = loaded; - } - }; - - /** - * Clean out item results, to free them from memory. Mainly, the loaded item and results are cleared from internal - * hashes. - * @method _disposeItem - * @param {LoadItem|Object} item The item that was passed in for preloading. - * @private - */ - p._disposeItem = function (item) { - delete this._loadedResults[item.id]; - delete this._loadedRawResults[item.id]; - delete this._loadItemsById[item.id]; - delete this._loadItemsBySrc[item.src]; - }; - - /** - * Dispatch a "fileprogress" {{#crossLink "Event"}}{{/crossLink}}. Please see the LoadQueue {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}} - * event for details on the event payload. - * @method _sendFileProgress - * @param {LoadItem|Object} item The item that is being loaded. - * @param {Number} progress The amount the item has been loaded (between 0 and 1). - * @protected - */ - p._sendFileProgress = function (item, progress) { - if (this._isCanceled() || this._paused) { - return; - } - if (!this.hasEventListener("fileprogress")) { - return; - } - - //LM: Rework ProgressEvent to support this? - var event = new createjs.Event("fileprogress"); - event.progress = progress; - event.loaded = progress; - event.total = 1; - event.item = item; - - this.dispatchEvent(event); - }; - - /** - * Dispatch a fileload {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event for - * details on the event payload. - * @method _sendFileComplete - * @param {LoadItemObject} item The item that is being loaded. - * @param {AbstractLoader} loader - * @protected - */ - p._sendFileComplete = function (item, loader) { - if (this._isCanceled() || this._paused) { - return; - } - - var event = new createjs.Event("fileload"); - event.loader = loader; - event.item = item; - event.result = this._loadedResults[item.id]; - event.rawResult = this._loadedRawResults[item.id]; - - // This calls a handler specified on the actual load item. Currently, the SoundJS plugin uses this. - if (item.completeHandler) { - item.completeHandler(event); - } - - this.hasEventListener("fileload") && this.dispatchEvent(event); - }; - - /** - * Dispatch a filestart {{#crossLink "Event"}}{{/crossLink}} immediately before a file starts to load. Please see - * the {{#crossLink "LoadQueue/filestart:event"}}{{/crossLink}} event for details on the event payload. - * @method _sendFileStart - * @param {LoadItem|Object} item The item that is being loaded. - * @protected - */ - p._sendFileStart = function (item) { - var event = new createjs.Event("filestart"); - event.item = item; - this.hasEventListener("filestart") && this.dispatchEvent(event); - }; - - p.toString = function () { - return "[PreloadJS LoadQueue]"; - }; - - createjs.LoadQueue = createjs.promote(LoadQueue, "AbstractLoader"); -}()); - -//############################################################################## -// TextLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for Text files. - * @class TextLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function TextLoader(loadItem) { - this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.TEXT); - }; - - var p = createjs.extend(TextLoader, createjs.AbstractLoader); - var s = TextLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader loads items that are of type {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}}, - * but is also the default loader if a file type can not be determined. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.TEXT; - }; - - createjs.TextLoader = createjs.promote(TextLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// BinaryLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for binary files. This is useful for loading web audio, or content that requires an ArrayBuffer. - * @class BinaryLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function BinaryLoader(loadItem) { - this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.BINARY); - this.on("initialize", this._updateXHR, this); - }; - - var p = createjs.extend(BinaryLoader, createjs.AbstractLoader); - var s = BinaryLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}} - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.BINARY; - }; - - // private methods - /** - * Before the item loads, set the response type to "arraybuffer" - * @property _updateXHR - * @param {Event} event - * @private - */ - p._updateXHR = function (event) { - event.loader.setResponseType("arraybuffer"); - }; - - createjs.BinaryLoader = createjs.promote(BinaryLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// CSSLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for CSS files. - * @class CSSLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractLoader - * @constructor - */ - function CSSLoader(loadItem, preferXHR) { - this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.CSS); - - // public properties - this.resultFormatter = this._formatResult; - - // protected properties - this._tagSrcAttribute = "href"; - - if (preferXHR) { - this._tag = document.createElement("style"); - } else { - this._tag = document.createElement("link"); - } - - this._tag.rel = "stylesheet"; - this._tag.type = "text/css"; - }; - - var p = createjs.extend(CSSLoader, createjs.AbstractLoader); - var s = CSSLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.CSS; - }; - - // protected methods - /** - * The result formatter for CSS files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLLinkElement|HTMLStyleElement} - * @private - */ - p._formatResult = function (loader) { - if (this._preferXHR) { - var tag = loader.getTag(); - - if (tag.styleSheet) { // IE - tag.styleSheet.cssText = loader.getResult(true); - } else { - var textNode = document.createTextNode(loader.getResult(true)); - tag.appendChild(textNode); - } - } else { - tag = this._tag; - } - - createjs.DomUtils.appendToHead(tag); - - return tag; - }; - - createjs.CSSLoader = createjs.promote(CSSLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// ImageLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for image files. - * @class ImageLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractLoader - * @constructor - */ - function ImageLoader (loadItem, preferXHR) { - this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.IMAGE); - - // public properties - this.resultFormatter = this._formatResult; - - // protected properties - this._tagSrcAttribute = "src"; - - // Check if the preload item is already a tag. - if (createjs.RequestUtils.isImageTag(loadItem)) { - this._tag = loadItem; - } else if (createjs.RequestUtils.isImageTag(loadItem.src)) { - this._tag = loadItem.src; - } else if (createjs.RequestUtils.isImageTag(loadItem.tag)) { - this._tag = loadItem.tag; - } - - if (this._tag != null) { - this._preferXHR = false; - } else { - this._tag = document.createElement("img"); - } - - this.on("initialize", this._updateXHR, this); - }; - - var p = createjs.extend(ImageLoader, createjs.AbstractLoader); - var s = ImageLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.IMAGE; - }; - - // public methods - p.load = function () { - if (this._tag.src != "" && this._tag.complete) { - this._sendComplete(); - return; - } - - var crossOrigin = this._item.crossOrigin; - if (crossOrigin == true) { crossOrigin = "Anonymous"; } - if (crossOrigin != null && !createjs.RequestUtils.isLocal(this._item.src)) { - this._tag.crossOrigin = crossOrigin; - } - - this.AbstractLoader_load(); - }; - - // protected methods - /** - * Before the item loads, set its mimeType and responseType. - * @property _updateXHR - * @param {Event} event - * @private - */ - p._updateXHR = function (event) { - event.loader.mimeType = 'text/plain; charset=x-user-defined-binary'; - - // Only exists for XHR - if (event.loader.setResponseType) { - event.loader.setResponseType("blob"); - } - }; - - /** - * The result formatter for Image files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLImageElement} - * @private - */ - p._formatResult = function (loader) { - return this._formatImage; - }; - - /** - * The asynchronous image formatter function. This is required because images have - * a short delay before they are ready. - * @method _formatImage - * @param {Function} successCallback The method to call when the result has finished formatting - * @param {Function} errorCallback The method to call if an error occurs during formatting - * @private - */ - p._formatImage = function (successCallback, errorCallback) { - var tag = this._tag; - var URL = window.URL || window.webkitURL; - - if (!this._preferXHR) { - //document.body.removeChild(tag); - } else if (URL) { - var objURL = URL.createObjectURL(this.getResult(true)); - tag.src = objURL; - - tag.addEventListener("load", this._cleanUpURL, false); - tag.addEventListener("error", this._cleanUpURL, false); - } else { - tag.src = loader.getItem().src; - } - - if (tag.complete) { - successCallback(tag); - } else { - tag.addEventListener("load", createjs.proxy(function(event) { - successCallback(this._tag); - }, this), false); - tag.addEventListener("error", createjs.proxy(function(event) { - errorCallback(this._tag); - }, this), false); - } - }; - - /** - * Clean up the ObjectURL, the tag is done with it. Note that this function is run - * as an event listener without a proxy/closure, as it doesn't require it - so do not - * include any functionality that requires scope without changing it. - * @method _cleanUpURL - * @param event - * @private - */ - p._cleanUpURL = function (event) { - var URL = window.URL || window.webkitURL; - URL.revokeObjectURL(event.target.src); - }; - - createjs.ImageLoader = createjs.promote(ImageLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// JavaScriptLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for JavaScript files. - * @class JavaScriptLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractLoader - * @constructor - */ - function JavaScriptLoader(loadItem, preferXHR) { - this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.JAVASCRIPT); - - // public properties - this.resultFormatter = this._formatResult; - - // protected properties - this._tagSrcAttribute = "src"; - this.setTag(document.createElement("script")); - }; - - var p = createjs.extend(JavaScriptLoader, createjs.AbstractLoader); - var s = JavaScriptLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.JAVASCRIPT; - }; - - // protected methods - /** - * The result formatter for JavaScript files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLLinkElement|HTMLStyleElement} - * @private - */ - p._formatResult = function (loader) { - var tag = loader.getTag(); - if (this._preferXHR) { - tag.text = loader.getResult(true); - } - return tag; - }; - - createjs.JavaScriptLoader = createjs.promote(JavaScriptLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// JSONLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for JSON files. To load JSON cross-domain, use JSONP and the {{#crossLink "JSONPLoader"}}{{/crossLink}} - * instead. To load JSON-formatted manifests, use {{#crossLink "ManifestLoader"}}{{/crossLink}}, and to - * load EaselJS SpriteSheets, use {{#crossLink "SpriteSheetLoader"}}{{/crossLink}}. - * @class JSONLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function JSONLoader(loadItem) { - this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.JSON); - - // public properties - this.resultFormatter = this._formatResult; - }; - - var p = createjs.extend(JSONLoader, createjs.AbstractLoader); - var s = JSONLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.JSON; - }; - - // protected methods - /** - * The result formatter for JSON files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLLinkElement|HTMLStyleElement} - * @private - */ - p._formatResult = function (loader) { - var json = null; - try { - json = createjs.DataUtils.parseJSON(loader.getResult(true)); - } catch (e) { - var event = new createjs.ErrorEvent("JSON_FORMAT", null, e); - this._sendError(event); - return e; - } - - return json; - }; - - createjs.JSONLoader = createjs.promote(JSONLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// JSONPLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for JSONP files, which are JSON-formatted text files, wrapped in a callback. To load regular JSON - * without a callback use the {{#crossLink "JSONLoader"}}{{/crossLink}} instead. To load JSON-formatted manifests, - * use {{#crossLink "ManifestLoader"}}{{/crossLink}}, and to load EaselJS SpriteSheets, use - * {{#crossLink "SpriteSheetLoader"}}{{/crossLink}}. - * - * Note that JSONP files loaded concurrently require a unique callback. To ensure JSONP files are loaded - * in order, either use the {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} method (set to 1), - * or set {{#crossLink "LoadItem/maintainOrder:property"}}{{/crossLink}} on items with the same callback. - * @class JSONPLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function JSONPLoader(loadItem) { - this.AbstractLoader_constructor(loadItem, false, createjs.AbstractLoader.JSONP); - this.setTag(document.createElement("script")); - this.getTag().type = "text/javascript"; - }; - - var p = createjs.extend(JSONPLoader, createjs.AbstractLoader); - var s = JSONPLoader; - - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.JSONP; - }; - - // public methods - p.cancel = function () { - this.AbstractLoader_cancel(); - this._dispose(); - }; - - /** - * Loads the JSONp file. Because of the unique loading needs of JSONp - * we don't use the AbstractLoader.load() method. - * - * @method load - * - */ - p.load = function () { - if (this._item.callback == null) { - throw new Error('callback is required for loading JSONP requests.'); - } - - // TODO: Look into creating our own iFrame to handle the load - // In the first attempt, FF did not get the result - // result instanceof Object did not work either - // so we would need to clone the result. - if (window[this._item.callback] != null) { - throw new Error( - "JSONP callback '" + - this._item.callback + - "' already exists on window. You need to specify a different callback or re-name the current one."); - } - - window[this._item.callback] = createjs.proxy(this._handleLoad, this); - window.document.body.appendChild(this._tag); - - this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); - - // Load the tag - this._tag.src = this._item.src; - }; - - // private methods - /** - * Handle the JSONP callback, which is a public method defined on `window`. - * @method _handleLoad - * @param {Object} data The formatted JSON data. - * @private - */ - p._handleLoad = function (data) { - this._result = this._rawResult = data; - this._sendComplete(); - - this._dispose(); - }; - - /** - * The tag request has not loaded within the time specfied in loadTimeout. - * @method _handleError - * @param {Object} event The XHR error event. - * @private - */ - p._handleTimeout = function () { - this._dispose(); - this.dispatchEvent(new createjs.ErrorEvent("timeout")); - }; - - /** - * Clean up the JSONP load. This clears out the callback and script tag that this loader creates. - * @method _dispose - * @private - */ - p._dispose = function () { - window.document.body.removeChild(this._tag); - delete window[this._item.callback]; - - clearTimeout(this._loadTimeout); - }; - - createjs.JSONPLoader = createjs.promote(JSONPLoader, "AbstractLoader"); - -}()); +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +/* + TODO: WINDOWS ISSUES + * No error for HTML audio in IE 678 + * SVG no failure error in IE 67 (maybe 8) TAGS AND XHR + * No script complete handler in IE 67 TAGS (XHR is fine) + * No XML/JSON in IE6 TAGS + * Need to hide loading SVG in Opera TAGS + * No CSS onload/readystatechange in Safari or Android TAGS (requires rule checking) + * SVG no load or failure in Opera XHR + * Reported issues with IE7/8 + */ + +(function (createjs) { + "use strict"; + +// constructor + /** + * The LoadQueue class is the main API for preloading content. LoadQueue is a load manager, which can preload either + * a single file, or queue of files. + * + * Creating a Queue
+ * To use LoadQueue, create a LoadQueue instance. If you want to force tag loading where possible, set the preferXHR + * argument to false. + * + * var queue = new createjs.LoadQueue(true); + * + * Listening for Events
+ * Add any listeners you want to the queue. Since PreloadJS 0.3.0, the {{#crossLink "EventDispatcher"}}{{/crossLink}} + * lets you add as many listeners as you want for events. You can subscribe to the following events:
    + *
  • {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}}: fired when a queue completes loading all + * files
  • + *
  • {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}: fired when the queue encounters an error with + * any file.
  • + *
  • {{#crossLink "AbstractLoader/progress:event"}}{{/crossLink}}: Progress for the entire queue has + * changed.
  • + *
  • {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}}: A single file has completed loading.
  • + *
  • {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}}: Progress for a single file has changes. Note + * that only files loaded with XHR (or possibly by plugins) will fire progress events other than 0 or 100%.
  • + *
+ * + * queue.on("fileload", handleFileLoad, this); + * queue.on("complete", handleComplete, this); + * + * Adding files and manifests
+ * Add files you want to load using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or add multiple files at a + * time using a list or a manifest definition using {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. Files are + * appended to the end of the active queue, so you can use these methods as many times as you like, whenever you + * like. + * + * queue.loadFile("filePath/file.jpg"); + * queue.loadFile({id:"image", src:"filePath/file.jpg"}); + * queue.loadManifest(["filePath/file.jpg", {id:"image", src:"filePath/file.jpg"}]); + * + * // Use an external manifest + * queue.loadManifest("path/to/manifest.json"); + * queue.loadManifest({src:"manifest.json", type:"manifest"}); + * + * If you pass `false` as the `loadNow` parameter, the queue will not kick of the load of the files, but it will not + * stop if it has already been started. Call the {{#crossLink "AbstractLoader/load"}}{{/crossLink}} method to begin + * a paused queue. Note that a paused queue will automatically resume when new files are added to it with a + * `loadNow` argument of `true`. + * + * queue.load(); + * + * File Types
+ * The file type of a manifest item is auto-determined by the file extension. The pattern matching in PreloadJS + * should handle the majority of standard file and url formats, and works with common file extensions. If you have + * either a non-standard file extension, or are serving the file using a proxy script, then you can pass in a + * type property with any manifest item. + * + * queue.loadFile({src:"path/to/myFile.mp3x", type:createjs.AbstractLoader.SOUND}); + * + * // Note that PreloadJS will not read a file extension from the query string + * queue.loadFile({src:"http://server.com/proxy?file=image.jpg", type:createjs.AbstractLoader.IMAGE}); + * + * Supported types are defined on the {{#crossLink "AbstractLoader"}}{{/crossLink}} class, and include: + *
    + *
  • {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}}: Raw binary data via XHR
  • + *
  • {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}}: CSS files
  • + *
  • {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}: Common image formats
  • + *
  • {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}}: JavaScript files
  • + *
  • {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}}: JSON data
  • + *
  • {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}}: JSON files cross-domain
  • + *
  • {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}: A list of files to load in JSON format, see + * {{#crossLink "AbstractLoader/loadManifest"}}{{/crossLink}}
  • + *
  • {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}: Audio file formats
  • + *
  • {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}: JSON SpriteSheet definitions. This + * will also load sub-images, and provide a {{#crossLink "SpriteSheet"}}{{/crossLink}} instance.
  • + *
  • {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}}: SVG files
  • + *
  • {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}}: Text files - XHR only
  • + *
  • {{#crossLink "AbstractLoader/VIDEO:property"}}{{/crossLink}}: Video objects
  • + *
  • {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}}: XML data
  • + *
+ * + * Note: Loader types used to be defined on LoadQueue, but have been moved to AbstractLoader for better + * portability of loader classes, which can be used individually now. The properties on LoadQueue still exist, but + * are deprecated. + * + * Handling Results
+ * When a file is finished downloading, a {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event is + * dispatched. In an example above, there is an event listener snippet for fileload. Loaded files are usually a + * formatted object that can be used immediately, including: + *
    + *
  • Binary: The binary loaded result
  • + *
  • CSS: A <link /> tag
  • + *
  • Image: An <img /> tag
  • + *
  • JavaScript: A <script /> tag
  • + *
  • JSON/JSONP: A formatted JavaScript Object
  • + *
  • Manifest: A JavaScript object. + *
  • Sound: An <audio /> tag + *
  • SpriteSheet: A {{#crossLink "SpriteSheet"}}{{/crossLink}} instance, containing loaded images. + *
  • SVG: An <object /> tag
  • + *
  • Text: Raw text
  • + *
  • Video: A Video DOM node
  • + *
  • XML: An XML DOM node
  • + *
+ * + * function handleFileLoad(event) { + * var item = event.item; // A reference to the item that was passed in to the LoadQueue + * var type = item.type; + * + * // Add any images to the page body. + * if (type == createjs.LoadQueue.IMAGE) { + * document.body.appendChild(event.result); + * } + * } + * + * At any time after the file has been loaded (usually after the queue has completed), any result can be looked up + * via its "id" using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. If no id was provided, then the + * "src" or file path can be used instead, including the `path` defined by a manifest, but not including + * a base path defined on the LoadQueue. It is recommended to always pass an id if you want to look up content. + * + * var image = queue.getResult("image"); + * document.body.appendChild(image); + * + * Raw loaded content can be accessed using the rawResult property of the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} + * event, or can be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}, passing `true` as the 2nd + * argument. This is only applicable for content that has been parsed for the browser, specifically: JavaScript, + * CSS, XML, SVG, and JSON objects, or anything loaded with XHR. + * + * var image = queue.getResult("image", true); // load the binary image data loaded with XHR. + * + * Plugins
+ * LoadQueue has a simple plugin architecture to help process and preload content. For example, to preload audio, + * make sure to install the SoundJS Sound class, which will help load HTML audio, + * Flash audio, and WebAudio files. This should be installed before loading any audio files. + * + * queue.installPlugin(createjs.Sound); + * + *

Known Browser Issues

+ *
    + *
  • Browsers without audio support can not load audio files.
  • + *
  • Safari on Mac OS X can only play HTML audio if QuickTime is installed
  • + *
  • HTML Audio tags will only download until their canPlayThrough event is fired. Browsers other + * than Chrome will continue to download in the background.
  • + *
  • When loading scripts using tags, they are automatically added to the document.
  • + *
  • Scripts loaded via XHR may not be properly inspectable with browser tools.
  • + *
  • IE6 and IE7 (and some other browsers) may not be able to load XML, Text, or JSON, since they require + * XHR to work.
  • + *
  • Content loaded via tags will not show progress, and will continue to download in the background when + * canceled, although no events will be dispatched.
  • + *
+ * + * @class LoadQueue + * @param {Boolean} [preferXHR=true] Determines whether the preload instance will favor loading with XHR (XML HTTP + * Requests), or HTML tags. When this is `false`, the queue will use tag loading when possible, and fall back on XHR + * when necessary. + * @param {String} [basePath=""] A path that will be prepended on to the source parameter of all items in the queue + * before they are loaded. Sources beginning with a protocol such as `http://` or a relative path such as `../` + * will not receive a base path. + * @param {String|Boolean} [crossOrigin=""] An optional flag to support images loaded from a CORS-enabled server. To + * use it, set this value to `true`, which will default the crossOrigin property on images to "Anonymous". Any + * string value will be passed through, but only "" and "Anonymous" are recommended. Note: The crossOrigin + * parameter is deprecated. Use LoadItem.crossOrigin instead + * + * @constructor + * @extends AbstractLoader + */ + function LoadQueue (preferXHR, basePath, crossOrigin) { + this.AbstractLoader_constructor(); + + /** + * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}. + * @property _plugins + * @type {Array} + * @private + * @since 0.6.1 + */ + this._plugins = []; + + /** + * An object hash of callbacks that are fired for each file type before the file is loaded, giving plugins the + * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} + * method for more information. + * @property _typeCallbacks + * @type {Object} + * @private + */ + this._typeCallbacks = {}; + + /** + * An object hash of callbacks that are fired for each file extension before the file is loaded, giving plugins the + * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} + * method for more information. + * @property _extensionCallbacks + * @type {null} + * @private + */ + this._extensionCallbacks = {}; + + /** + * The next preload queue to process when this one is complete. If an error is thrown in the current queue, and + * {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} is `true`, the next queue will not be processed. + * @property next + * @type {LoadQueue} + * @default null + */ + this.next = null; + + /** + * Ensure loaded scripts "complete" in the order they are specified. Loaded scripts are added to the document head + * once they are loaded. Scripts loaded via tags will load one-at-a-time when this property is `true`, whereas + * scripts loaded using XHR can load in any order, but will "finish" and be added to the document in the order + * specified. + * + * Any items can be set to load in order by setting the {{#crossLink "maintainOrder:property"}}{{/crossLink}} + * property on the load item, or by ensuring that only one connection can be open at a time using + * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Note that when the `maintainScriptOrder` property + * is set to `true`, scripts items are automatically set to `maintainOrder=true`, and changing the + * `maintainScriptOrder` to `false` during a load will not change items already in a queue. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.setMaxConnections(3); // Set a higher number to load multiple items at once + * queue.maintainScriptOrder = true; // Ensure scripts are loaded in order + * queue.loadManifest([ + * "script1.js", + * "script2.js", + * "image.png", // Load any time + * {src: "image2.png", maintainOrder: true} // Will wait for script2.js + * "image3.png", + * "script3.js" // Will wait for image2.png before loading (or completing when loading with XHR) + * ]); + * + * @property maintainScriptOrder + * @type {Boolean} + * @default true + */ + this.maintainScriptOrder = true; + + /** + * Determines if the LoadQueue will stop processing the current queue when an error is encountered. + * @property stopOnError + * @type {Boolean} + * @default false + */ + this.stopOnError = false; + + /** + * The number of maximum open connections that a loadQueue tries to maintain. Please see + * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} for more information. + * @property _maxConnections + * @type {Number} + * @default 1 + * @private + */ + this._maxConnections = 1; + + /** + * An internal list of all the default Loaders that are included with PreloadJS. Before an item is loaded, the + * available loader list is iterated, in the order they are included, and as soon as a loader indicates it can + * handle the content, it will be selected. The default loader, ({{#crossLink "TextLoader"}}{{/crossLink}} is + * last in the list, so it will be used if no other match is found. Typically, loaders will match based on the + * {{#crossLink "LoadItem/type"}}{{/crossLink}}, which is automatically determined using the file extension of + * the {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. + * + * Loaders can be removed from PreloadJS by simply not including them. + * + * Custom loaders installed using {{#crossLink "registerLoader"}}{{/crossLink}} will be prepended to this list + * so that they are checked first. + * @property _availableLoaders + * @type {Array} + * @private + * @since 0.6.0 + */ + this._availableLoaders = [ + createjs.ImageLoader, + createjs.JavaScriptLoader, + createjs.CSSLoader, + createjs.JSONLoader, + createjs.JSONPLoader, + createjs.SoundLoader, + createjs.ManifestLoader, + createjs.SpriteSheetLoader, + createjs.XMLLoader, + createjs.SVGLoader, + createjs.BinaryLoader, + createjs.VideoLoader, + createjs.TextLoader + ]; + + /** + * The number of built in loaders, so they can't be removed by {{#crossLink "unregisterLoader"}}{{/crossLink}. + * @property _defaultLoaderLength + * @type {Number} + * @private + * @since 0.6.0 + */ + this._defaultLoaderLength = this._availableLoaders.length; + + this.init(preferXHR, basePath, crossOrigin); + } + + var p = createjs.extend(LoadQueue, createjs.AbstractLoader); + var s = LoadQueue; + + /** + * REMOVED. Removed in favor of using `MySuperClass_constructor`. + * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} + * for details. + * + * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. + * + * @method initialize + * @protected + * @deprecated + */ + // p.initialize = function() {}; // searchable for devs wondering where it is. + + /** + * An internal initialization method, which is used for initial set up, but also to reset the LoadQueue. + * @method init + * @param preferXHR + * @param basePath + * @param crossOrigin + * @private + */ + p.init = function (preferXHR, basePath, crossOrigin) { + + // public properties + /** + * @property useXHR + * @type {Boolean} + * @readonly + * @default true + * @deprecated Use preferXHR instead. + */ + this.useXHR = true; + + /** + * Try and use XMLHttpRequest (XHR) when possible. Note that LoadQueue will default to tag loading or XHR + * loading depending on the requirements for a media type. For example, HTML audio can not be loaded with XHR, + * and plain text can not be loaded with tags, so it will default the the correct type instead of using the + * user-defined type. + * @type {Boolean} + * @default true + * @since 0.6.0 + */ + this.preferXHR = true; //TODO: Get/Set + this._preferXHR = true; + this.setPreferXHR(preferXHR); + + // protected properties + /** + * Whether the queue is currently paused or not. + * @property _paused + * @type {boolean} + * @private + */ + this._paused = false; + + /** + * A path that will be prepended on to the item's {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. The + * `_basePath` property will only be used if an item's source is relative, and does not include a protocol such + * as `http://`, or a relative path such as `../`. + * @property _basePath + * @type {String} + * @private + * @since 0.3.1 + */ + this._basePath = basePath; + + /** + * An optional flag to set on images that are loaded using PreloadJS, which enables CORS support. Images loaded + * cross-domain by servers that support CORS require the crossOrigin flag to be loaded and interacted with by + * a canvas. When loading locally, or with a server with no CORS support, this flag can cause other security issues, + * so it is recommended to only set it if you are sure the server supports it. Currently, supported values are "" + * and "Anonymous". + * @property _crossOrigin + * @type {String} + * @default "" + * @private + * @since 0.4.1 + */ + this._crossOrigin = crossOrigin; + + /** + * Determines if the loadStart event was dispatched already. This event is only fired one time, when the first + * file is requested. + * @property _loadStartWasDispatched + * @type {Boolean} + * @default false + * @private + */ + this._loadStartWasDispatched = false; + + /** + * Determines if there is currently a script loading. This helps ensure that only a single script loads at once when + * using a script tag to do preloading. + * @property _currentlyLoadingScript + * @type {Boolean} + * @private + */ + this._currentlyLoadingScript = null; + + /** + * An array containing the currently downloading files. + * @property _currentLoads + * @type {Array} + * @private + */ + this._currentLoads = []; + + /** + * An array containing the queued items that have not yet started downloading. + * @property _loadQueue + * @type {Array} + * @private + */ + this._loadQueue = []; + + /** + * An array containing downloads that have not completed, so that the LoadQueue can be properly reset. + * @property _loadQueueBackup + * @type {Array} + * @private + */ + this._loadQueueBackup = []; + + /** + * An object hash of items that have finished downloading, indexed by the {{#crossLink "LoadItem"}}{{/crossLink}} + * id. + * @property _loadItemsById + * @type {Object} + * @private + */ + this._loadItemsById = {}; + + /** + * An object hash of items that have finished downloading, indexed by {{#crossLink "LoadItem"}}{{/crossLink}} + * source. + * @property _loadItemsBySrc + * @type {Object} + * @private + */ + this._loadItemsBySrc = {}; + + /** + * An object hash of loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. + * @property _loadedResults + * @type {Object} + * @private + */ + this._loadedResults = {}; + + /** + * An object hash of un-parsed loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. + * @property _loadedRawResults + * @type {Object} + * @private + */ + this._loadedRawResults = {}; + + /** + * The number of items that have been requested. This helps manage an overall progress without knowing how large + * the files are before they are downloaded. This does not include items inside of loaders such as the + * {{#crossLink "ManifestLoader"}}{{/crossLink}}. + * @property _numItems + * @type {Number} + * @default 0 + * @private + */ + this._numItems = 0; + + /** + * The number of items that have completed loaded. This helps manage an overall progress without knowing how large + * the files are before they are downloaded. + * @property _numItemsLoaded + * @type {Number} + * @default 0 + * @private + */ + this._numItemsLoaded = 0; + + /** + * A list of scripts in the order they were requested. This helps ensure that scripts are "completed" in the right + * order. + * @property _scriptOrder + * @type {Array} + * @private + */ + this._scriptOrder = []; + + /** + * A list of scripts that have been loaded. Items are added to this list as null when they are + * requested, contain the loaded item if it has completed, but not been dispatched to the user, and true + * once they are complete and have been dispatched. + * @property _loadedScripts + * @type {Array} + * @private + */ + this._loadedScripts = []; + + /** + * The last progress amount. This is used to suppress duplicate progress events. + * @property _lastProgress + * @type {Number} + * @private + * @since 0.6.0 + */ + this._lastProgress = NaN; + + }; + +// static properties + /** + * The time in milliseconds to assume a load has failed. An {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} + * event is dispatched if the timeout is reached before any data is received. + * @property loadTimeout + * @type {Number} + * @default 8000 + * @static + * @since 0.4.1 + * @deprecated In favour of {{#crossLink "LoadItem/LOAD_TIMEOUT_DEFAULT:property}}{{/crossLink}} property. + */ + s.loadTimeout = 8000; + + /** + * The time in milliseconds to assume a load has failed. + * @property LOAD_TIMEOUT + * @type {Number} + * @default 0 + * @deprecated in favor of the {{#crossLink "LoadQueue/loadTimeout:property"}}{{/crossLink}} property. + */ + s.LOAD_TIMEOUT = 0; + +// Preload Types + /** + * @property BINARY + * @type {String} + * @default binary + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}} instead. + */ + s.BINARY = createjs.AbstractLoader.BINARY; + + /** + * @property CSS + * @type {String} + * @default css + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. + */ + s.CSS = createjs.AbstractLoader.CSS; + + /** + * @property IMAGE + * @type {String} + * @default image + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. + */ + s.IMAGE = createjs.AbstractLoader.IMAGE; + + /** + * @property JAVASCRIPT + * @type {String} + * @default javascript + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ + s.JAVASCRIPT = createjs.AbstractLoader.JAVASCRIPT; + + /** + * @property JSON + * @type {String} + * @default json + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}} instead. + */ + s.JSON = createjs.AbstractLoader.JSON; + + /** + * @property JSONP + * @type {String} + * @default jsonp + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}} instead. + */ + s.JSONP = createjs.AbstractLoader.JSONP; + + /** + * @property MANIFEST + * @type {String} + * @default manifest + * @static + * @since 0.4.1 + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}} instead. + */ + s.MANIFEST = createjs.AbstractLoader.MANIFEST; + + /** + * @property SOUND + * @type {String} + * @default sound + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ + s.SOUND = createjs.AbstractLoader.SOUND; + + /** + * @property VIDEO + * @type {String} + * @default video + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ + s.VIDEO = createjs.AbstractLoader.VIDEO; + + /** + * @property SVG + * @type {String} + * @default svg + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}} instead. + */ + s.SVG = createjs.AbstractLoader.SVG; + + /** + * @property TEXT + * @type {String} + * @default text + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}} instead. + */ + s.TEXT = createjs.AbstractLoader.TEXT; + + /** + * @property XML + * @type {String} + * @default xml + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}} instead. + */ + s.XML = createjs.AbstractLoader.XML; + + /** + * @property POST + * @type {string} + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} instead. + */ + s.POST = createjs.AbstractLoader.POST; + + /** + * @property GET + * @type {string} + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} instead. + */ + s.GET = createjs.AbstractLoader.GET; + +// events + /** + * This event is fired when an individual file has loaded, and been processed. + * @event fileload + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a `src` property. + * @param {Object} result The HTML tag or parsed result of the loaded item. + * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted + * to a usable object. + * @since 0.3.0 + */ + + /** + * This {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when an an individual file's progress changes. + * @event fileprogress + * @since 0.3.0 + */ + + /** + * This event is fired when an individual file starts to load. + * @event filestart + * @param {Object} The object that dispatched the event. + * @param {String} type The event type. + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a property. + */ + + /** + * Although it extends {{#crossLink "AbstractLoader"}}{{/crossLink}}, the `initialize` event is never fired from + * a LoadQueue instance. + * @event initialize + * @private + */ + +// public methods + /** + * Register a custom loaders class. New loaders are given precedence over loaders added earlier and default loaders. + * It is recommended that loaders extend {{#crossLink "AbstractLoader"}}{{/crossLink}}. Loaders can only be added + * once, and will be prepended to the list of available loaders. + * @method registerLoader + * @param {Function|AbstractLoader} loader The AbstractLoader class to add. + * @since 0.6.0 + */ + p.registerLoader = function (loader) { + if (!loader || !loader.canLoadItem) { + throw new Error("loader is of an incorrect type."); + } else if (this._availableLoaders.indexOf(loader) != -1) { + throw new Error("loader already exists."); //LM: Maybe just silently fail here + } + + this._availableLoaders.unshift(loader); + }; + + /** + * Remove a custom loader added using {{#crossLink "registerLoader"}}{{/crossLink}}. Only custom loaders can be + * unregistered, the default loaders will always be available. + * @method unregisterLoader + * @param {Function|AbstractLoader} loader The AbstractLoader class to remove + */ + p.unregisterLoader = function (loader) { + var idx = this._availableLoaders.indexOf(loader); + if (idx != -1 && idx < this._defaultLoaderLength - 1) { + this._availableLoaders.splice(idx, 1); + } + }; + + /** + * @method setUseXHR + * @param {Boolean} value The new useXHR value to set. + * @return {Boolean} The new useXHR value. If XHR is not supported by the browser, this will return false, even if + * the provided value argument was true. + * @since 0.3.0 + * @deprecated use the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property, or the + * {{#crossLink "LoadQueue/setUseXHR"}}{{/crossLink}} method instead. + */ + p.setUseXHR = function (value) { + return this.setPreferXHR(value); + }; + + /** + * Change the {{#crossLink "preferXHR:property"}}{{/crossLink}} value. Note that if this is set to `true`, it may + * fail, or be ignored depending on the browser's capabilities and the load type. + * @method setPreferXHR + * @param {Boolean} value + * @returns {Boolean} The value of {{#crossLink "preferXHR"}}{{/crossLink}} that was successfully set. + * @since 0.6.0 + */ + p.setPreferXHR = function (value) { + // Determine if we can use XHR. XHR defaults to TRUE, but the browser may not support it. + //TODO: Should we be checking for the other XHR types? Might have to do a try/catch on the different types similar to createXHR. + this.preferXHR = (value != false && window.XMLHttpRequest != null); + return this.preferXHR; + }; + + /** + * Stops all queued and loading items, and clears the queue. This also removes all internal references to loaded + * content, and allows the queue to be used again. + * @method removeAll + * @since 0.3.0 + */ + p.removeAll = function () { + this.remove(); + }; + + /** + * Stops an item from being loaded, and removes it from the queue. If nothing is passed, all items are removed. + * This also removes internal references to loaded item(s). + * + *

Example

+ * + * queue.loadManifest([ + * {src:"test.png", id:"png"}, + * {src:"test.jpg", id:"jpg"}, + * {src:"test.mp3", id:"mp3"} + * ]); + * queue.remove("png"); // Single item by ID + * queue.remove("png", "test.jpg"); // Items as arguments. Mixed id and src. + * queue.remove(["test.png", "jpg"]); // Items in an Array. Mixed id and src. + * + * @method remove + * @param {String | Array} idsOrUrls* The id or ids to remove from this queue. You can pass an item, an array of + * items, or multiple items as arguments. + * @since 0.3.0 + */ + p.remove = function (idsOrUrls) { + var args = null; + + if (idsOrUrls && !Array.isArray(idsOrUrls)) { + args = [idsOrUrls]; + } else if (idsOrUrls) { + args = idsOrUrls; + } else if (arguments.length > 0) { + return; + } + + var itemsWereRemoved = false; + + // Destroy everything + if (!args) { + this.close(); + for (var n in this._loadItemsById) { + this._disposeItem(this._loadItemsById[n]); + } + this.init(this.preferXHR, this._basePath); + + // Remove specific items + } else { + while (args.length) { + var item = args.pop(); + var r = this.getResult(item); + + //Remove from the main load Queue + for (i = this._loadQueue.length - 1; i >= 0; i--) { + loadItem = this._loadQueue[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._loadQueue.splice(i, 1)[0].cancel(); + break; + } + } + + //Remove from the backup queue + for (i = this._loadQueueBackup.length - 1; i >= 0; i--) { + loadItem = this._loadQueueBackup[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._loadQueueBackup.splice(i, 1)[0].cancel(); + break; + } + } + + if (r) { + this._disposeItem(this.getItem(item)); + } else { + for (var i = this._currentLoads.length - 1; i >= 0; i--) { + var loadItem = this._currentLoads[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._currentLoads.splice(i, 1)[0].cancel(); + itemsWereRemoved = true; + break; + } + } + } + } + + // If this was called during a load, try to load the next item. + if (itemsWereRemoved) { + this._loadNext(); + } + } + }; + + /** + * Stops all open loads, destroys any loaded items, and resets the queue, so all items can + * be reloaded again by calling {{#crossLink "AbstractLoader/load"}}{{/crossLink}}. Items are not removed from the + * queue. To remove items use the {{#crossLink "LoadQueue/remove"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/removeAll"}}{{/crossLink}} method. + * @method reset + * @since 0.3.0 + */ + p.reset = function () { + this.close(); + for (var n in this._loadItemsById) { + this._disposeItem(this._loadItemsById[n]); + } + + //Reset the queue to its start state + var a = []; + for (var i = 0, l = this._loadQueueBackup.length; i < l; i++) { + a.push(this._loadQueueBackup[i].getItem()); + } + + this.loadManifest(a, false); + }; + + /** + * Register a plugin. Plugins can map to load types (sound, image, etc), or specific extensions (png, mp3, etc). + * Currently, only one plugin can exist per type/extension. + * + * When a plugin is installed, a getPreloadHandlers() method will be called on it. For more information + * on this method, check out the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method in the + * {{#crossLink "SamplePlugin"}}{{/crossLink}} class. + * + * Before a file is loaded, a matching plugin has an opportunity to modify the load. If a `callback` is returned + * from the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method, it will be invoked first, and its + * result may cancel or modify the item. The callback method can also return a `completeHandler` to be fired when + * the file is loaded, or a `tag` object, which will manage the actual download. For more information on these + * methods, check out the {{#crossLink "SamplePlugin/preloadHandler"}}{{/crossLink}} and {{#crossLink "SamplePlugin/fileLoadHandler"}}{{/crossLink}} + * methods on the {{#crossLink "SamplePlugin"}}{{/crossLink}}. + * + * @method installPlugin + * @param {Function} plugin The plugin class to install. + */ + p.installPlugin = function (plugin) { + if (plugin == null) { + return; + } + + if (plugin.getPreloadHandlers != null) { + this._plugins.push(plugin); + var map = plugin.getPreloadHandlers(); + map.scope = plugin; + + if (map.types != null) { + for (var i = 0, l = map.types.length; i < l; i++) { + this._typeCallbacks[map.types[i]] = map; + } + } + + if (map.extensions != null) { + for (i = 0, l = map.extensions.length; i < l; i++) { + this._extensionCallbacks[map.extensions[i]] = map; + } + } + } + }; + + /** + * Set the maximum number of concurrent connections. Note that browsers and servers may have a built-in maximum + * number of open connections, so any additional connections may remain in a pending state until the browser + * opens the connection. When loading scripts using tags, and when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} + * is `true`, only one script is loaded at a time due to browser limitations. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.setMaxConnections(10); // Allow 10 concurrent loads + * + * @method setMaxConnections + * @param {Number} value The number of concurrent loads to allow. By default, only a single connection per LoadQueue + * is open at any time. + */ + p.setMaxConnections = function (value) { + this._maxConnections = value; + if (!this._paused && this._loadQueue.length > 0) { + this._loadNext(); + } + }; + + /** + * Load a single file. To add multiple files at once, use the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * method. + * + * Files are always appended to the current queue, so this method can be used multiple times to add files. + * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. + * @method loadFile + * @param {LoadItem|Object|String} file The file object or path to load. A file can be either + *
    + *
  • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
  • + *
  • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
  • + *
  • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} + * in the background.
  • + *
+ * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default + * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}}, and the value is + * `true`, the queue will resume automatically. + * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the + * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}, + * its files will NOT use the basePath parameter. The basePath parameter is deprecated. + * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue + * constructor, or a `path` property in a manifest definition. + */ + p.loadFile = function (file, loadNow, basePath) { + if (file == null) { + var event = new createjs.ErrorEvent("PRELOAD_NO_FILE"); + this._sendError(event); + return; + } + this._addItem(file, null, basePath); + + if (loadNow !== false) { + this.setPaused(false); + } else { + this.setPaused(true); + } + }; + + /** + * Load an array of files. To load a single file, use the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} method. + * The files in the manifest are requested in the same order, but may complete in a different order if the max + * connections are set above 1 using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Scripts will load + * in the right order as long as {{#crossLink "LoadQueue/maintainScriptOrder"}}{{/crossLink}} is true (which is + * default). + * + * Files are always appended to the current queue, so this method can be used multiple times to add files. + * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. + * @method loadManifest + * @param {Array|String|Object} manifest An list of files to load. The loadManifest call supports four types of + * manifests: + *
    + *
  1. A string path, which points to a manifest file, which is a JSON file that contains a "manifest" property, + * which defines the list of files to load, and can optionally contain a "path" property, which will be + * prepended to each file in the list.
  2. + *
  3. An object which defines a "src", which is a JSON or JSONP file. A "callback" can be defined for JSONP + * file. The JSON/JSONP file should contain a "manifest" property, which defines the list of files to load, + * and can optionally contain a "path" property, which will be prepended to each file in the list.
  4. + *
  5. An object which contains a "manifest" property, which defines the list of files to load, and can + * optionally contain a "path" property, which will be prepended to each file in the list.
  6. + *
  7. An Array of files to load.
  8. + *
+ * + * Each "file" in a manifest can be either: + *
    + *
  • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
  • + *
  • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
  • + *
  • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} + * in the background.
  • + *
+ * + * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default + * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} and this value is + * `true`, the queue will resume automatically. + * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the + * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "LoadQueue/MANIFEST:property"}}{{/crossLink}}, + * its files will NOT use the basePath parameter. The basePath parameter is deprecated. + * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue + * constructor, or a `path` property in a manifest definition. + */ + p.loadManifest = function (manifest, loadNow, basePath) { + var fileList = null; + var path = null; + + // Array-based list of items + if (Array.isArray(manifest)) { + if (manifest.length == 0) { + var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_EMPTY"); + this._sendError(event); + return; + } + fileList = manifest; + + // String-based. Only file manifests can be specified this way. Any other types will cause an error when loaded. + } else if (typeof(manifest) === "string") { + fileList = [ + { + src: manifest, + type: s.MANIFEST + } + ]; + + } else if (typeof(manifest) == "object") { + + // An object that defines a manifest path + if (manifest.src !== undefined) { + if (manifest.type == null) { + manifest.type = s.MANIFEST; + } else if (manifest.type != s.MANIFEST) { + var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_TYPE"); + this._sendError(event); + } + fileList = [manifest]; + + // An object that defines a manifest + } else if (manifest.manifest !== undefined) { + fileList = manifest.manifest; + path = manifest.path; + } + + // Unsupported. This will throw an error. + } else { + var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_NULL"); + this._sendError(event); + return; + } + + for (var i = 0, l = fileList.length; i < l; i++) { + this._addItem(fileList[i], path, basePath); + } + + if (loadNow !== false) { + this.setPaused(false); + } else { + this.setPaused(true); + } + + }; + + /** + * Start a LoadQueue that was created, but not automatically started. + * @method load + */ + p.load = function () { + this.setPaused(false); + }; + + /** + * Look up a {{#crossLink "LoadItem"}}{{/crossLink}} using either the "id" or "src" that was specified when loading it. Note that if no "id" was + * supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The + * `basePath` will not be part of the ID. + * @method getItem + * @param {String} value The id or src of the load item. + * @return {Object} The load item that was initially requested using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} + * event as the `item` parameter. + */ + p.getItem = function (value) { + return this._loadItemsById[value] || this._loadItemsBySrc[value]; + }; + + /** + * Look up a loaded result using either the "id" or "src" that was specified when loading it. Note that if no "id" + * was supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The + * `basePath` will not be part of the ID. + * @method getResult + * @param {String} value The id or src of the load item. + * @param {Boolean} [rawResult=false] Return a raw result instead of a formatted result. This applies to content + * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be + * returned instead. + * @return {Object} A result object containing the content that was loaded, such as: + *
    + *
  • An image tag (<image />) for images
  • + *
  • A script tag for JavaScript (<script />). Note that scripts are automatically added to the HTML + * DOM.
  • + *
  • A style tag for CSS (<style /> or <link >)
  • + *
  • Raw text for TEXT
  • + *
  • A formatted JavaScript object defined by JSON
  • + *
  • An XML document
  • + *
  • A binary arraybuffer loaded by XHR
  • + *
  • An audio tag (<audio >) for HTML audio. Note that it is recommended to use SoundJS APIs to play + * loaded audio. Specifically, audio loaded by Flash and WebAudio will return a loader object using this method + * which can not be used to play audio back.
  • + *
+ * This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event as the 'item` + * parameter. Note that if a raw result is requested, but not found, the result will be returned instead. + */ + p.getResult = function (value, rawResult) { + var item = this._loadItemsById[value] || this._loadItemsBySrc[value]; + if (item == null) { + return null; + } + var id = item.id; + if (rawResult && this._loadedRawResults[id]) { + return this._loadedRawResults[id]; + } + return this._loadedResults[id]; + }; + + /** + * Generate an list of items loaded by this queue. + * @method getItems + * @param {Boolean} loaded Determines if only items that have been loaded should be returned. If false, in-progress + * and failed load items will also be included. + * @returns {Array} A list of objects that have been loaded. Each item includes the {{#crossLink "LoadItem"}}{{/crossLink}}, + * result, and rawResult. + * @since 0.6.0 + */ + p.getItems = function (loaded) { + var arr = []; + for (var n in this._loadItemsById) { + var item = this._loadItemsById[n]; + var result = this.getResult(n); + if (loaded === true && result == null) { + continue; + } + arr.push({ + item: item, + result: result, + rawResult: this.getResult(n, true) + }); + } + return arr; + }; + + /** + * Pause or resume the current load. Active loads will not be cancelled, but the next items in the queue will not + * be processed when active loads complete. LoadQueues are not paused by default. + * + * Note that if new items are added to the queue using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}, a paused queue will be resumed, unless the `loadNow` + * argument is `false`. + * @method setPaused + * @param {Boolean} value Whether the queue should be paused or not. + */ + p.setPaused = function (value) { + this._paused = value; + if (!this._paused) { + this._loadNext(); + } + }; + + /** + * Close the active queue. Closing a queue completely empties the queue, and prevents any remaining items from + * starting to download. Note that currently any active loads will remain open, and events may be processed. + * + * To stop and restart a queue, use the {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} method instead. + * @method close + */ + p.close = function () { + while (this._currentLoads.length) { + this._currentLoads.pop().cancel(); + } + this._scriptOrder.length = 0; + this._loadedScripts.length = 0; + this.loadStartWasDispatched = false; + this._itemCount = 0; + this._lastProgress = NaN; + }; + +// protected methods + /** + * Add an item to the queue. Items are formatted into a usable object containing all the properties necessary to + * load the content. The load queue is populated with the loader instance that handles preloading, and not the load + * item that was passed in by the user. To look up the load item by id or src, use the {{#crossLink "LoadQueue.getItem"}}{{/crossLink}} + * method. + * @method _addItem + * @param {String|Object} value The item to add to the queue. + * @param {String} [path] An optional path prepended to the `src`. The path will only be prepended if the src is + * relative, and does not start with a protocol such as `http://`, or a path like `../`. If the LoadQueue was + * provided a {{#crossLink "_basePath"}}{{/crossLink}}, then it will optionally be prepended after. + * @param {String} [basePath] DeprecatedAn optional basePath passed into a {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} call. This parameter will be removed in a future tagged + * version. + * @private + */ + p._addItem = function (value, path, basePath) { + var item = this._createLoadItem(value, path, basePath); // basePath and manifest path are added to the src. + if (item == null) { + return; + } // Sometimes plugins or types should be skipped. + var loader = this._createLoader(item); + if (loader != null) { + if ("plugins" in loader) { + loader.plugins = this._plugins; + } + item._loader = loader; + this._loadQueue.push(loader); + this._loadQueueBackup.push(loader); + + this._numItems++; + this._updateProgress(); + + // Only worry about script order when using XHR to load scripts. Tags are only loading one at a time. + if ((this.maintainScriptOrder + && item.type == createjs.LoadQueue.JAVASCRIPT + //&& loader instanceof createjs.XHRLoader //NOTE: Have to track all JS files this way + ) + || item.maintainOrder === true) { + this._scriptOrder.push(item); + this._loadedScripts.push(null); + } + } + }; + + /** + * Create a refined {{#crossLink "LoadItem"}}{{/crossLink}}, which contains all the required properties. The type of + * item is determined by browser support, requirements based on the file type, and developer settings. For example, + * XHR is only used for file types that support it in new browsers. + * + * Before the item is returned, any plugins registered to handle the type or extension will be fired, which may + * alter the load item. + * @method _createLoadItem + * @param {String | Object | HTMLAudioElement | HTMLImageElement} value The item that needs to be preloaded. + * @param {String} [path] A path to prepend to the item's source. Sources beginning with http:// or similar will + * not receive a path. Since PreloadJS 0.4.1, the src will be modified to include the `path` and {{#crossLink "LoadQueue/_basePath:property"}}{{/crossLink}} + * when it is added. + * @param {String} [basePath] Deprectated A base path to prepend to the items source in addition to + * the path argument. + * @return {Object} The loader instance that will be used. + * @private + */ + p._createLoadItem = function (value, path, basePath) { + var item = createjs.LoadItem.create(value); + if (item == null) { + return null; + } + + var bp = ""; // Store the generated basePath + var useBasePath = basePath || this._basePath; + + if (item.src instanceof Object) { + if (!item.type) { + return null; + } // the the src is an object, type is required to pass off to plugin + if (path) { + bp = path; + var pathMatch = createjs.RequestUtils.parseURI(path); + // Also append basePath + if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { + bp = useBasePath + bp; + } + } else if (useBasePath != null) { + bp = useBasePath; + } + } else { + // Determine Extension, etc. + var match = createjs.RequestUtils.parseURI(item.src); + if (match.extension) { + item.ext = match.extension; + } + if (item.type == null) { + item.type = createjs.RequestUtils.getTypeByExtension(item.ext); + } + + // Inject path & basePath + var autoId = item.src; + if (!match.absolute && !match.relative) { + if (path) { + bp = path; + var pathMatch = createjs.RequestUtils.parseURI(path); + autoId = path + autoId; + // Also append basePath + if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { + bp = useBasePath + bp; + } + } else if (useBasePath != null) { + bp = useBasePath; + } + } + item.src = bp + item.src; + } + item.path = bp; + + // If there's no id, set one now. + if (item.id === undefined || item.id === null || item.id === "") { + item.id = autoId; + } + + // Give plugins a chance to modify the loadItem: + var customHandler = this._typeCallbacks[item.type] || this._extensionCallbacks[item.ext]; + if (customHandler) { + // Plugins are now passed both the full source, as well as a combined path+basePath (appropriately) + var result = customHandler.callback.call(customHandler.scope, item, this); + + // The plugin will handle the load, or has canceled it. Ignore it. + if (result === false) { + return null; + + // Load as normal: + } else if (result === true) { + // Do Nothing + + // Result is a loader class: + } else if (result != null) { + item._loader = result; + } + + // Update the extension in case the type changed: + match = createjs.RequestUtils.parseURI(item.src); + if (match.extension != null) { + item.ext = match.extension; + } + } + + // Store the item for lookup. This also helps clean-up later. + this._loadItemsById[item.id] = item; + this._loadItemsBySrc[item.src] = item; + + if (item.crossOrigin == null) { + item.crossOrigin = this._crossOrigin; + } + + return item; + }; + + /** + * Create a loader for a load item. + * @method _createLoader + * @param {Object} item A formatted load item that can be used to generate a loader. + * @return {AbstractLoader} A loader that can be used to load content. + * @private + */ + p._createLoader = function (item) { + if (item._loader != null) { // A plugin already specified a loader + return item._loader; + } + + // Initially, try and use the provided/supported XHR mode: + var preferXHR = this.preferXHR; + + for (var i = 0; i < this._availableLoaders.length; i++) { + var loader = this._availableLoaders[i]; + if (loader && loader.canLoadItem(item)) { + return new loader(item, preferXHR); + } + } + + // TODO: Log error (requires createjs.log) + return null; + }; + + /** + * Load the next item in the queue. If the queue is empty (all items have been loaded), then the complete event + * is processed. The queue will "fill up" any empty slots, up to the max connection specified using + * {{#crossLink "LoadQueue.setMaxConnections"}}{{/crossLink}} method. The only exception is scripts that are loaded + * using tags, which have to be loaded one at a time to maintain load order. + * @method _loadNext + * @private + */ + p._loadNext = function () { + if (this._paused) { + return; + } + + // Only dispatch loadstart event when the first file is loaded. + if (!this._loadStartWasDispatched) { + this._sendLoadStart(); + this._loadStartWasDispatched = true; + } + + // The queue has completed. + if (this._numItems == this._numItemsLoaded) { + this.loaded = true; + this._sendComplete(); + + // Load the next queue, if it has been defined. + if (this.next && this.next.load) { + this.next.load(); + } + } else { + this.loaded = false; + } + + // Must iterate forwards to load in the right order. + for (var i = 0; i < this._loadQueue.length; i++) { + if (this._currentLoads.length >= this._maxConnections) { + break; + } + var loader = this._loadQueue[i]; + + // Determine if we should be only loading one tag-script at a time: + // Note: maintainOrder items don't do anything here because we can hold onto their loaded value + if (!this._canStartLoad(loader)) { + continue; + } + this._loadQueue.splice(i, 1); + i--; + this._loadItem(loader); + } + }; + + /** + * Begin loading an item. Event listeners are not added to the loaders until the load starts. + * @method _loadItem + * @param {AbstractLoader} loader The loader instance to start. Currently, this will be an XHRLoader or TagLoader. + * @private + */ + p._loadItem = function (loader) { + loader.on("fileload", this._handleFileLoad, this); + loader.on("progress", this._handleProgress, this); + loader.on("complete", this._handleFileComplete, this); + loader.on("error", this._handleError, this); + loader.on("fileerror", this._handleFileError, this); + this._currentLoads.push(loader); + this._sendFileStart(loader.getItem()); + loader.load(); + }; + + /** + * The callback that is fired when a loader loads a file. This enables loaders like {{#crossLink "ManifestLoader"}}{{/crossLink}} + * to maintain internal queues, but for this queue to dispatch the {{#crossLink "fileload:event"}}{{/crossLink}} + * events. + * @param {Event} event The {{#crossLink "AbstractLoader/fileload:event"}}{{/crossLink}} event from the loader. + * @private + * @since 0.6.0 + */ + p._handleFileLoad = function (event) { + event.target = null; + this.dispatchEvent(event); + }; + + /** + * The callback that is fired when a loader encounters an error from an internal file load operation. This enables + * loaders like M + * @param event + * @private + */ + p._handleFileError = function (event) { + var newEvent = new createjs.ErrorEvent("FILE_LOAD_ERROR", null, event.item); + this._sendError(newEvent); + }; + + /** + * The callback that is fired when a loader encounters an error. The queue will continue loading unless {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} + * is set to `true`. + * @method _handleError + * @param {ErrorEvent} event The error event, containing relevant error information. + * @private + */ + p._handleError = function (event) { + var loader = event.target; + this._numItemsLoaded++; + + this._finishOrderedItem(loader, true); + this._updateProgress(); + + var newEvent = new createjs.ErrorEvent("FILE_LOAD_ERROR", null, loader.getItem()); + // TODO: Propagate actual error message. + + this._sendError(newEvent); + + if (!this.stopOnError) { + this._removeLoadItem(loader); + this._cleanLoadItem(loader); + this._loadNext(); + } else { + this.setPaused(true); + } + }; + + /** + * An item has finished loading. We can assume that it is totally loaded, has been parsed for immediate use, and + * is available as the "result" property on the load item. The raw text result for a parsed item (such as JSON, XML, + * CSS, JavaScript, etc) is available as the "rawResult" property, and can also be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. + * @method _handleFileComplete + * @param {Event} event The event object from the loader. + * @private + */ + p._handleFileComplete = function (event) { + var loader = event.target; + var item = loader.getItem(); + + var result = loader.getResult(); + this._loadedResults[item.id] = result; + var rawResult = loader.getResult(true); + if (rawResult != null && rawResult !== result) { + this._loadedRawResults[item.id] = rawResult; + } + + this._saveLoadedItems(loader); + + // Remove the load item + this._removeLoadItem(loader); + + if (!this._finishOrderedItem(loader)) { + // The item was NOT managed, so process it now + this._processFinishedLoad(item, loader); + } + + // Clean up the load item + this._cleanLoadItem(loader); + }; + + /** + * Some loaders might load additional content, other than the item they were passed (such as {{#crossLink "ManifestLoader"}}{{/crossLink}}). + * Any items exposed by the loader using {{#crossLink "AbstractLoader/getLoadItems"}}{{/crossLink}} are added to the + * LoadQueue's look-ups, including {{#crossLink "getItem"}}{{/crossLink}} and {{#crossLink "getResult"}}{{/crossLink}} + * methods. + * @method _saveLoadedItems + * @param {AbstractLoader} loader + * @protected + * @since 0.6.0 + */ + p._saveLoadedItems = function (loader) { + // TODO: Not sure how to handle this. Would be nice to expose the items. + // Loaders may load sub-items. This adds them to this queue + var list = loader.getLoadedItems(); + if (list === null) { + return; + } + + for (var i = 0; i < list.length; i++) { + var item = list[i].item; + + // Store item lookups + this._loadItemsBySrc[item.src] = item; + this._loadItemsById[item.id] = item; + + // Store loaded content + this._loadedResults[item.id] = list[i].result; + this._loadedRawResults[item.id] = list[i].rawResult; + } + }; + + /** + * Flag an item as finished. If the item's order is being managed, then ensure that it is allowed to finish, and if + * so, trigger prior items to trigger as well. + * @method _finishOrderedItem + * @param {AbstractLoader} loader + * @param {Boolean} loadFailed + * @return {Boolean} If the item's order is being managed. This allows the caller to take an alternate + * behaviour if it is. + * @private + */ + p._finishOrderedItem = function (loader, loadFailed) { + var item = loader.getItem(); + + if ((this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) + || item.maintainOrder) { + + //TODO: Evaluate removal of the _currentlyLoadingScript + if (loader instanceof createjs.JavaScriptLoader) { + this._currentlyLoadingScript = false; + } + + var index = createjs.indexOf(this._scriptOrder, item); + if (index == -1) { + return false; + } // This loader no longer exists + this._loadedScripts[index] = (loadFailed === true) ? true : item; + + this._checkScriptLoadOrder(); + return true; + } + + return false; + }; + + /** + * Ensure the scripts load and dispatch in the correct order. When using XHR, scripts are stored in an array in the + * order they were added, but with a "null" value. When they are completed, the value is set to the load item, + * and then when they are processed and dispatched, the value is set to `true`. This method simply + * iterates the array, and ensures that any loaded items that are not preceded by a `null` value are + * dispatched. + * @method _checkScriptLoadOrder + * @private + */ + p._checkScriptLoadOrder = function () { + var l = this._loadedScripts.length; + + for (var i = 0; i < l; i++) { + var item = this._loadedScripts[i]; + if (item === null) { + break; + } // This is still loading. Do not process further. + if (item === true) { + continue; + } // This has completed, and been processed. Move on. + + var loadItem = this._loadedResults[item.id]; + if (item.type == createjs.LoadQueue.JAVASCRIPT) { + // Append script tags to the head automatically. + createjs.DomUtils.appendToHead(loadItem); + } + + var loader = item._loader; + this._processFinishedLoad(item, loader); + this._loadedScripts[i] = true; + } + }; + + /** + * A file has completed loading, and the LoadQueue can move on. This triggers the complete event, and kick-starts + * the next item. + * @method _processFinishedLoad + * @param {LoadItem|Object} item + * @param {AbstractLoader} loader + * @protected + */ + p._processFinishedLoad = function (item, loader) { + this._numItemsLoaded++; + + // Since LoadQueue needs maintain order, we can't append scripts in the loader. + // So we do it here instead. Or in _checkScriptLoadOrder(); + if (!this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) { + var tag = loader.getTag(); + createjs.DomUtils.appendToHead(tag); + } + + this._updateProgress(); + this._sendFileComplete(item, loader); + this._loadNext(); + }; + + /** + * Ensure items with `maintainOrder=true` that are before the specified item have loaded. This only applies to + * JavaScript items that are being loaded with a TagLoader, since they have to be loaded and completed before + * the script can even be started, since it exist in the DOM while loading. + * @method _canStartLoad + * @param {AbstractLoader} loader The loader for the item + * @return {Boolean} Whether the item can start a load or not. + * @private + */ + p._canStartLoad = function (loader) { + if (!this.maintainScriptOrder || loader.preferXHR) { + return true; + } + var item = loader.getItem(); + if (item.type != createjs.LoadQueue.JAVASCRIPT) { + return true; + } + if (this._currentlyLoadingScript) { + return false; + } + + var index = this._scriptOrder.indexOf(item); + var i = 0; + while (i < index) { + var checkItem = this._loadedScripts[i]; + if (checkItem == null) { + return false; + } + i++; + } + this._currentlyLoadingScript = true; + return true; + }; + + /** + * A load item is completed or was canceled, and needs to be removed from the LoadQueue. + * @method _removeLoadItem + * @param {AbstractLoader} loader A loader instance to remove. + * @private + */ + p._removeLoadItem = function (loader) { + var l = this._currentLoads.length; + for (var i = 0; i < l; i++) { + if (this._currentLoads[i] == loader) { + this._currentLoads.splice(i, 1); + break; + } + } + }; + + /** + * Remove unneeded references from a loader. + * + * @param loader + * @private + */ + p._cleanLoadItem = function(loader) { + var item = loader.getItem(); + if (item) { + delete item._loader; + } + } + + /** + * An item has dispatched progress. Propagate that progress, and update the LoadQueue's overall progress. + * @method _handleProgress + * @param {ProgressEvent} event The progress event from the item. + * @private + */ + p._handleProgress = function (event) { + var loader = event.target; + this._sendFileProgress(loader.getItem(), loader.progress); + this._updateProgress(); + }; + + /** + * Overall progress has changed, so determine the new progress amount and dispatch it. This changes any time an + * item dispatches progress or completes. Note that since we don't always know the actual filesize of items before + * they are loaded. In this case, we define a "slot" for each item (1 item in 10 would get 10%), and then append + * loaded progress on top of the already-loaded items. + * + * For example, if 5/10 items have loaded, and item 6 is 20% loaded, the total progress would be: + *
    + *
  • 5/10 of the items in the queue (50%)
  • + *
  • plus 20% of item 6's slot (2%)
  • + *
  • equals 52%
  • + *
+ * @method _updateProgress + * @private + */ + p._updateProgress = function () { + var loaded = this._numItemsLoaded / this._numItems; // Fully Loaded Progress + var remaining = this._numItems - this._numItemsLoaded; + if (remaining > 0) { + var chunk = 0; + for (var i = 0, l = this._currentLoads.length; i < l; i++) { + chunk += this._currentLoads[i].progress; + } + loaded += (chunk / remaining) * (remaining / this._numItems); + } + + if (this._lastProgress != loaded) { + this._sendProgress(loaded); + this._lastProgress = loaded; + } + }; + + /** + * Clean out item results, to free them from memory. Mainly, the loaded item and results are cleared from internal + * hashes. + * @method _disposeItem + * @param {LoadItem|Object} item The item that was passed in for preloading. + * @private + */ + p._disposeItem = function (item) { + delete this._loadedResults[item.id]; + delete this._loadedRawResults[item.id]; + delete this._loadItemsById[item.id]; + delete this._loadItemsBySrc[item.src]; + }; + + /** + * Dispatch a "fileprogress" {{#crossLink "Event"}}{{/crossLink}}. Please see the LoadQueue {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendFileProgress + * @param {LoadItem|Object} item The item that is being loaded. + * @param {Number} progress The amount the item has been loaded (between 0 and 1). + * @protected + */ + p._sendFileProgress = function (item, progress) { + if (this._isCanceled() || this._paused) { + return; + } + if (!this.hasEventListener("fileprogress")) { + return; + } + + //LM: Rework ProgressEvent to support this? + var event = new createjs.Event("fileprogress"); + event.progress = progress; + event.loaded = progress; + event.total = 1; + event.item = item; + + this.dispatchEvent(event); + }; + + /** + * Dispatch a fileload {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event for + * details on the event payload. + * @method _sendFileComplete + * @param {LoadItemObject} item The item that is being loaded. + * @param {AbstractLoader} loader + * @protected + */ + p._sendFileComplete = function (item, loader) { + if (this._isCanceled() || this._paused) { + return; + } + + var event = new createjs.Event("fileload"); + event.loader = loader; + event.item = item; + event.result = this._loadedResults[item.id]; + event.rawResult = this._loadedRawResults[item.id]; + + // This calls a handler specified on the actual load item. Currently, the SoundJS plugin uses this. + if (item.completeHandler) { + item.completeHandler(event); + } + + this.hasEventListener("fileload") && this.dispatchEvent(event); + }; + + /** + * Dispatch a filestart {{#crossLink "Event"}}{{/crossLink}} immediately before a file starts to load. Please see + * the {{#crossLink "LoadQueue/filestart:event"}}{{/crossLink}} event for details on the event payload. + * @method _sendFileStart + * @param {LoadItem|Object} item The item that is being loaded. + * @protected + */ + p._sendFileStart = function (item) { + var event = new createjs.Event("filestart"); + event.item = item; + this.hasEventListener("filestart") && this.dispatchEvent(event); + }; + + p.toString = function () { + return "[PreloadJS LoadQueue]"; + }; + + createjs.LoadQueue = createjs.promote(LoadQueue, "AbstractLoader"); +}(scope.createjs)); //############################################################################## -// ManifestLoader.js +// TextLoader.js //############################################################################## -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for JSON manifests. Items inside the manifest are loaded before the loader completes. To load manifests - * using JSONP, specify a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}} as part of the - * {{#crossLink "LoadItem"}}{{/crossLink}}. - * - * The list of files in the manifest must be defined on the top-level JSON object in a `manifest` property. This - * example shows a sample manifest definition, as well as how to to include a sub-manifest. - * - * { - * "path": "assets/", - * "manifest": [ - * "image.png", - * {"src": "image2.png", "id":"image2"}, - * {"src": "sub-manifest.json", "type":"manifest", "callback":"jsonCallback"} - * ] - * } - * - * When a ManifestLoader has completed loading, the parent loader (usually a {{#crossLink "LoadQueue"}}{{/crossLink}}, - * but could also be another ManifestLoader) will inherit all the loaded items, so you can access them directly. - * - * Note that the {{#crossLink "JSONLoader"}}{{/crossLink}} and {{#crossLink "JSONPLoader"}}{{/crossLink}} are - * higher priority loaders, so manifests must set the {{#crossLink "LoadItem"}}{{/crossLink}} - * {{#crossLink "LoadItem/type:property"}}{{/crossLink}} property to {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}. - * @class ManifestLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function ManifestLoader(loadItem) { - this.AbstractLoader_constructor(loadItem, null, createjs.AbstractLoader.MANIFEST); - - // Public Properties - /** - * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}, - * used to pass plugins to new LoadQueues that may be created. - * @property _plugins - * @type {Array} - * @private - * @since 0.6.1 - */ - this.plugins = null; - - - // Protected Properties - /** - * An internal {{#crossLink "LoadQueue"}}{{/crossLink}} that loads the contents of the manifest. - * @property _manifestQueue - * @type {LoadQueue} - * @private - */ - this._manifestQueue = null; - }; - - var p = createjs.extend(ManifestLoader, createjs.AbstractLoader); - var s = ManifestLoader; - - // static properties - /** - * The amount of progress that the manifest itself takes up. - * @property MANIFEST_PROGRESS - * @type {number} - * @default 0.25 (25%) - * @private - * @static - */ - s.MANIFEST_PROGRESS = 0.25; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}} - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.MANIFEST; - }; - - // public methods - p.load = function () { - this.AbstractLoader_load(); - }; - - // protected methods - p._createRequest = function() { - var callback = this._item.callback; - if (callback != null) { - this._request = new createjs.JSONPLoader(this._item); - } else { - this._request = new createjs.JSONLoader(this._item); - } - }; - - p.handleEvent = function (event) { - switch (event.type) { - case "complete": - this._rawResult = event.target.getResult(true); - this._result = event.target.getResult(); - this._sendProgress(s.MANIFEST_PROGRESS); - this._loadManifest(this._result); - return; - case "progress": - event.loaded *= s.MANIFEST_PROGRESS; - this.progress = event.loaded / event.total; - if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; } - this._sendProgress(event); - return; - } - this.AbstractLoader_handleEvent(event); - }; - - p.destroy = function() { - this.AbstractLoader_destroy(); - this._manifestQueue.close(); - }; - - /** - * Create and load the manifest items once the actual manifest has been loaded. - * @method _loadManifest - * @param {Object} json - * @private - */ - p._loadManifest = function (json) { - if (json && json.manifest) { - var queue = this._manifestQueue = new createjs.LoadQueue(); - queue.on("fileload", this._handleManifestFileLoad, this); - queue.on("progress", this._handleManifestProgress, this); - queue.on("complete", this._handleManifestComplete, this, true); - queue.on("error", this._handleManifestError, this, true); - for(var i = 0, l = this.plugins.length; i < l; i++) { // conserve order of plugins - queue.installPlugin(this.plugins[i]); - } - queue.loadManifest(json); - } else { - this._sendComplete(); - } - }; - - /** - * An item from the {{#crossLink "_manifestQueue:property"}}{{/crossLink}} has completed. - * @method _handleManifestFileLoad - * @param {Event} event - * @private - */ - p._handleManifestFileLoad = function (event) { - event.target = null; - this.dispatchEvent(event); - }; - - /** - * The manifest has completed loading. This triggers the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} - * {{#crossLink "Event"}}{{/crossLink}} from the ManifestLoader. - * @method _handleManifestComplete - * @param {Event} event - * @private - */ - p._handleManifestComplete = function (event) { - this._loadedItems = this._manifestQueue.getItems(true); - this._sendComplete(); - }; - - /** - * The manifest has reported progress. - * @method _handleManifestProgress - * @param {ProgressEvent} event - * @private - */ - p._handleManifestProgress = function (event) { - this.progress = event.progress * (1 - s.MANIFEST_PROGRESS) + s.MANIFEST_PROGRESS; - this._sendProgress(this.progress); - }; - - /** - * The manifest has reported an error with one of the files. - * @method _handleManifestError - * @param {ErrorEvent} event - * @private - */ - p._handleManifestError = function (event) { - var newEvent = new createjs.Event("fileerror"); - newEvent.item = event.data; - this.dispatchEvent(newEvent); - }; - - createjs.ManifestLoader = createjs.promote(ManifestLoader, "AbstractLoader"); - -}()); +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + + // constructor + /** + * A loader for Text files. + * @class TextLoader + * @param {LoadItem|Object} loadItem + * @extends AbstractLoader + * @constructor + */ + function TextLoader(loadItem) { + this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.TEXT); + }; + + var p = createjs.extend(TextLoader, createjs.AbstractLoader); + var s = TextLoader; + + // static methods + /** + * Determines if the loader can load a specific item. This loader loads items that are of type {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}}, + * but is also the default loader if a file type can not be determined. + * @method canLoadItem + * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. + * @returns {Boolean} Whether the loader can load the item. + * @static + */ + s.canLoadItem = function (item) { + return item.type == createjs.AbstractLoader.TEXT; + }; + + createjs.TextLoader = createjs.promote(TextLoader, "AbstractLoader"); + +}(scope.createjs)); //############################################################################## -// SoundLoader.js +// BinaryLoader.js //############################################################################## -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor /** - * A loader for HTML audio files. PreloadJS can not load WebAudio files, as a WebAudio context is required, which - * should be created by either a library playing the sound (such as SoundJS, or an - * external framework that handles audio playback. To load content that can be played by WebAudio, use the - * {{#crossLink "BinaryLoader"}}{{/crossLink}}, and handle the audio context decoding manually. - * @class SoundLoader + * A loader for binary files. This is useful for loading web audio, or content that requires an ArrayBuffer. + * @class BinaryLoader * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractMediaLoader + * @extends AbstractLoader * @constructor */ - function SoundLoader(loadItem, preferXHR) { - this.AbstractMediaLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SOUND); - - // protected properties - if (createjs.RequestUtils.isAudioTag(loadItem)) { - this._tag = loadItem; - } else if (createjs.RequestUtils.isAudioTag(loadItem.src)) { - this._tag = loadItem; - } else if (createjs.RequestUtils.isAudioTag(loadItem.tag)) { - this._tag = createjs.RequestUtils.isAudioTag(loadItem) ? loadItem : loadItem.src; - } - - if (this._tag != null) { - this._preferXHR = false; - } + function BinaryLoader(loadItem) { + this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.BINARY); + this.on("initialize", this._updateXHR, this); }; - var p = createjs.extend(SoundLoader, createjs.AbstractMediaLoader); - var s = SoundLoader; + var p = createjs.extend(BinaryLoader, createjs.AbstractLoader); + var s = BinaryLoader; // static methods /** * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}. + * {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}} * @method canLoadItem * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. * @returns {Boolean} Whether the loader can load the item. * @static */ s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.SOUND; + return item.type == createjs.AbstractLoader.BINARY; }; - // protected methods - p._createTag = function (src) { - var tag = document.createElement("audio"); - tag.autoplay = false; - tag.preload = "none"; - - //LM: Firefox fails when this the preload="none" for other tags, but it needs to be "none" to ensure PreloadJS works. - tag.src = src; - return tag; + // private methods + /** + * Before the item loads, set the response type to "arraybuffer" + * @property _updateXHR + * @param {Event} event + * @private + */ + p._updateXHR = function (event) { + event.loader.setResponseType("arraybuffer"); }; - createjs.SoundLoader = createjs.promote(SoundLoader, "AbstractMediaLoader"); + createjs.BinaryLoader = createjs.promote(BinaryLoader, "AbstractLoader"); -}()); +}(scope.createjs)); //############################################################################## -// VideoLoader.js +// CSSLoader.js +//############################################################################## + +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + + // constructor + /** + * A loader for CSS files. + * @class CSSLoader + * @param {LoadItem|Object} loadItem + * @param {Boolean} preferXHR + * @extends AbstractLoader + * @constructor + */ + function CSSLoader(loadItem, preferXHR) { + this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.CSS); + + // public properties + this.resultFormatter = this._formatResult; + + // protected properties + this._tagSrcAttribute = "href"; + + if (preferXHR) { + this._tag = document.createElement("style"); + } else { + this._tag = document.createElement("link"); + } + + this._tag.rel = "stylesheet"; + this._tag.type = "text/css"; + }; + + var p = createjs.extend(CSSLoader, createjs.AbstractLoader); + var s = CSSLoader; + + // static methods + /** + * Determines if the loader can load a specific item. This loader can only load items that are of type + * {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}}. + * @method canLoadItem + * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. + * @returns {Boolean} Whether the loader can load the item. + * @static + */ + s.canLoadItem = function (item) { + return item.type == createjs.AbstractLoader.CSS; + }; + + // protected methods + /** + * The result formatter for CSS files. + * @method _formatResult + * @param {AbstractLoader} loader + * @returns {HTMLLinkElement|HTMLStyleElement} + * @private + */ + p._formatResult = function (loader) { + if (this._preferXHR) { + var tag = loader.getTag(); + + if (tag.styleSheet) { // IE + tag.styleSheet.cssText = loader.getResult(true); + } else { + var textNode = document.createTextNode(loader.getResult(true)); + tag.appendChild(textNode); + } + } else { + tag = this._tag; + } + + createjs.DomUtils.appendToHead(tag); + + return tag; + }; + + createjs.CSSLoader = createjs.promote(CSSLoader, "AbstractLoader"); + +}(scope.createjs)); + +//############################################################################## +// ImageLoader.js +//############################################################################## + +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + + // constructor + /** + * A loader for image files. + * @class ImageLoader + * @param {LoadItem|Object} loadItem + * @param {Boolean} preferXHR + * @extends AbstractLoader + * @constructor + */ + function ImageLoader (loadItem, preferXHR) { + this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.IMAGE); + + // public properties + this.resultFormatter = this._formatResult; + + // protected properties + this._tagSrcAttribute = "src"; + + // Check if the preload item is already a tag. + if (createjs.RequestUtils.isImageTag(loadItem)) { + this._tag = loadItem; + } else if (createjs.RequestUtils.isImageTag(loadItem.src)) { + this._tag = loadItem.src; + } else if (createjs.RequestUtils.isImageTag(loadItem.tag)) { + this._tag = loadItem.tag; + } + + if (this._tag != null) { + this._preferXHR = false; + } else { + this._tag = document.createElement("img"); + } + + this.on("initialize", this._updateXHR, this); + }; + + var p = createjs.extend(ImageLoader, createjs.AbstractLoader); + var s = ImageLoader; + + // static methods + /** + * Determines if the loader can load a specific item. This loader can only load items that are of type + * {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}. + * @method canLoadItem + * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. + * @returns {Boolean} Whether the loader can load the item. + * @static + */ + s.canLoadItem = function (item) { + return item.type == createjs.AbstractLoader.IMAGE; + }; + + // public methods + p.load = function () { + if (this._tag.src != "" && this._tag.complete) { + this._sendComplete(); + return; + } + + var crossOrigin = this._item.crossOrigin; + if (crossOrigin == true) { crossOrigin = "Anonymous"; } + if (crossOrigin != null && !createjs.RequestUtils.isLocal(this._item.src)) { + this._tag.crossOrigin = crossOrigin; + } + + this.AbstractLoader_load(); + }; + + // protected methods + /** + * Before the item loads, set its mimeType and responseType. + * @property _updateXHR + * @param {Event} event + * @private + */ + p._updateXHR = function (event) { + event.loader.mimeType = 'text/plain; charset=x-user-defined-binary'; + + // Only exists for XHR + if (event.loader.setResponseType) { + event.loader.setResponseType("blob"); + } + }; + + /** + * The result formatter for Image files. + * @method _formatResult + * @param {AbstractLoader} loader + * @returns {HTMLImageElement} + * @private + */ + p._formatResult = function (loader) { + return this._formatImage; + }; + + /** + * The asynchronous image formatter function. This is required because images have + * a short delay before they are ready. + * @method _formatImage + * @param {Function} successCallback The method to call when the result has finished formatting + * @param {Function} errorCallback The method to call if an error occurs during formatting + * @private + */ + p._formatImage = function (successCallback, errorCallback) { + var tag = this._tag; + var URL = window.URL || window.webkitURL; + + if (!this._preferXHR) { + //document.body.removeChild(tag); + } else if (URL) { + var objURL = URL.createObjectURL(this.getResult(true)); + tag.src = objURL; + + tag.addEventListener("load", this._cleanUpURL, false); + tag.addEventListener("error", this._cleanUpURL, false); + } else { + tag.src = this._item.src; + } + + if (tag.complete) { + successCallback(tag); + } else { + tag.onload = createjs.proxy(function() { + successCallback(this._tag); + }, this); + + tag.onerror = createjs.proxy(function() { + errorCallback(_this._tag); + }, this); + } + }; + + /** + * Clean up the ObjectURL, the tag is done with it. Note that this function is run + * as an event listener without a proxy/closure, as it doesn't require it - so do not + * include any functionality that requires scope without changing it. + * @method _cleanUpURL + * @param event + * @private + */ + p._cleanUpURL = function (event) { + var URL = window.URL || window.webkitURL; + URL.revokeObjectURL(event.target.src); + }; + + createjs.ImageLoader = createjs.promote(ImageLoader, "AbstractLoader"); + +}(scope.createjs)); + +//############################################################################## +// JavaScriptLoader.js //############################################################################## -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor /** - * A loader for video files. - * @class VideoLoader + * A loader for JavaScript files. + * @class JavaScriptLoader * @param {LoadItem|Object} loadItem * @param {Boolean} preferXHR - * @extends AbstractMediaLoader + * @extends AbstractLoader * @constructor */ - function VideoLoader(loadItem, preferXHR) { - this.AbstractMediaLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.VIDEO); + function JavaScriptLoader(loadItem, preferXHR) { + this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.JAVASCRIPT); - if (createjs.RequestUtils.isVideoTag(loadItem) || createjs.RequestUtils.isVideoTag(loadItem.src)) { - this.setTag(createjs.RequestUtils.isVideoTag(loadItem)?loadItem:loadItem.src); + // public properties + this.resultFormatter = this._formatResult; - // We can't use XHR for a tag that's passed in. - this._preferXHR = false; - } else { - this.setTag(this._createTag()); - } + // protected properties + this._tagSrcAttribute = "src"; + this.setTag(document.createElement("script")); }; - var p = createjs.extend(VideoLoader, createjs.AbstractMediaLoader); - var s = VideoLoader; - - /** - * Create a new video tag - * - * @returns {HTMLElement} - * @private - */ - p._createTag = function () { - return document.createElement("video"); - }; + var p = createjs.extend(JavaScriptLoader, createjs.AbstractLoader); + var s = JavaScriptLoader; // static methods /** * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/VIDEO:property"}}{{/crossLink}}. + * {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} * @method canLoadItem * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. * @returns {Boolean} Whether the loader can load the item. * @static */ s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.VIDEO; + return item.type == createjs.AbstractLoader.JAVASCRIPT; }; - createjs.VideoLoader = createjs.promote(VideoLoader, "AbstractMediaLoader"); + // protected methods + /** + * The result formatter for JavaScript files. + * @method _formatResult + * @param {AbstractLoader} loader + * @returns {HTMLLinkElement|HTMLStyleElement} + * @private + */ + p._formatResult = function (loader) { + var tag = loader.getTag(); + if (this._preferXHR) { + tag.text = loader.getResult(true); + } + return tag; + }; + + createjs.JavaScriptLoader = createjs.promote(JavaScriptLoader, "AbstractLoader"); + +}(scope.createjs)); + +//############################################################################## +// JSONLoader.js +//############################################################################## -}()); +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + + // constructor + /** + * A loader for JSON files. To load JSON cross-domain, use JSONP and the {{#crossLink "JSONPLoader"}}{{/crossLink}} + * instead. To load JSON-formatted manifests, use {{#crossLink "ManifestLoader"}}{{/crossLink}}, and to + * load EaselJS SpriteSheets, use {{#crossLink "SpriteSheetLoader"}}{{/crossLink}}. + * @class JSONLoader + * @param {LoadItem|Object} loadItem + * @extends AbstractLoader + * @constructor + */ + function JSONLoader(loadItem) { + this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.JSON); + + // public properties + this.resultFormatter = this._formatResult; + }; + + var p = createjs.extend(JSONLoader, createjs.AbstractLoader); + var s = JSONLoader; + + // static methods + /** + * Determines if the loader can load a specific item. This loader can only load items that are of type + * {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}}. + * @method canLoadItem + * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. + * @returns {Boolean} Whether the loader can load the item. + * @static + */ + s.canLoadItem = function (item) { + return item.type == createjs.AbstractLoader.JSON; + }; + + // protected methods + /** + * The result formatter for JSON files. + * @method _formatResult + * @param {AbstractLoader} loader + * @returns {HTMLLinkElement|HTMLStyleElement} + * @private + */ + p._formatResult = function (loader) { + var json = null; + try { + json = createjs.DataUtils.parseJSON(loader.getResult(true)); + } catch (e) { + var event = new createjs.ErrorEvent("JSON_FORMAT", null, e); + this._sendError(event); + return e; + } + + return json; + }; + + createjs.JSONLoader = createjs.promote(JSONLoader, "AbstractLoader"); + +}(scope.createjs)); + +//############################################################################## +// JSONPLoader.js +//############################################################################## + +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + + // constructor + /** + * A loader for JSONP files, which are JSON-formatted text files, wrapped in a callback. To load regular JSON + * without a callback use the {{#crossLink "JSONLoader"}}{{/crossLink}} instead. To load JSON-formatted manifests, + * use {{#crossLink "ManifestLoader"}}{{/crossLink}}, and to load EaselJS SpriteSheets, use + * {{#crossLink "SpriteSheetLoader"}}{{/crossLink}}. + * + * JSONP is a format that provides a solution for loading JSON files cross-domain without requiring CORS. + * JSONP files are loaded as JavaScript, and the "callback" is executed once they are loaded. The callback in the + * JSONP must match the callback passed to the loadItem. + * + *

Example JSONP

+ * + * callbackName({ + * "name": "value", + * "num": 3, + * "obj": { "bool":true } + * }); + * + *

Example

+ * + * var loadItem = {id:"json", type:"jsonp", src:"http://server.com/text.json", callback:"callbackName"} + * var queue = new createjs.LoadQueue(); + * queue.on("complete", handleComplete); + * queue.loadItem(loadItem); + * + * function handleComplete(event) } + * var json = queue.getResult("json"); + * console.log(json.obj.bool); // true + * } + * + * Note that JSONP files loaded concurrently require a unique callback. To ensure JSONP files are loaded + * in order, either use the {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} method (set to 1), + * or set {{#crossLink "LoadItem/maintainOrder:property"}}{{/crossLink}} on items with the same callback. + * + * @class JSONPLoader + * @param {LoadItem|Object} loadItem + * @extends AbstractLoader + * @constructor + */ + function JSONPLoader(loadItem) { + this.AbstractLoader_constructor(loadItem, false, createjs.AbstractLoader.JSONP); + this.setTag(document.createElement("script")); + this.getTag().type = "text/javascript"; + }; + + var p = createjs.extend(JSONPLoader, createjs.AbstractLoader); + var s = JSONPLoader; + + + // static methods + /** + * Determines if the loader can load a specific item. This loader can only load items that are of type + * {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}}. + * @method canLoadItem + * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. + * @returns {Boolean} Whether the loader can load the item. + * @static + */ + s.canLoadItem = function (item) { + return item.type == createjs.AbstractLoader.JSONP; + }; + + // public methods + p.cancel = function () { + this.AbstractLoader_cancel(); + this._dispose(); + }; + + /** + * Loads the JSONp file. Because of the unique loading needs of JSONp + * we don't use the AbstractLoader.load() method. + * + * @method load + * + */ + p.load = function () { + if (this._item.callback == null) { + throw new Error('callback is required for loading JSONP requests.'); + } + + // TODO: Look into creating our own iFrame to handle the load + // In the first attempt, FF did not get the result + // result instanceof Object did not work either + // so we would need to clone the result. + if (window[this._item.callback] != null) { + throw new Error( + "JSONP callback '" + + this._item.callback + + "' already exists on window. You need to specify a different callback or re-name the current one."); + } + + window[this._item.callback] = createjs.proxy(this._handleLoad, this); + window.document.body.appendChild(this._tag); + + this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); + + // Load the tag + this._tag.src = this._item.src; + }; + + // private methods + /** + * Handle the JSONP callback, which is a public method defined on `window`. + * @method _handleLoad + * @param {Object} data The formatted JSON data. + * @private + */ + p._handleLoad = function (data) { + this._result = this._rawResult = data; + this._sendComplete(); + + this._dispose(); + }; + + /** + * The tag request has not loaded within the time specfied in loadTimeout. + * @method _handleError + * @param {Object} event The XHR error event. + * @private + */ + p._handleTimeout = function () { + this._dispose(); + this.dispatchEvent(new createjs.ErrorEvent("timeout")); + }; + + /** + * Clean up the JSONP load. This clears out the callback and script tag that this loader creates. + * @method _dispose + * @private + */ + p._dispose = function () { + window.document.body.removeChild(this._tag); + delete window[this._item.callback]; + + clearTimeout(this._loadTimeout); + }; + + createjs.JSONPLoader = createjs.promote(JSONPLoader, "AbstractLoader"); + +}(scope.createjs)); //############################################################################## -// SpriteSheetLoader.js +// ManifestLoader.js //############################################################################## -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor /** - * A loader for EaselJS SpriteSheets. Images inside the spritesheet definition are loaded before the loader - * completes. To load SpriteSheets using JSONP, specify a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}} - * as part of the {{#crossLink "LoadItem"}}{{/crossLink}}. Note that the {{#crossLink "JSONLoader"}}{{/crossLink}} - * and {{#crossLink "JSONPLoader"}}{{/crossLink}} are higher priority loaders, so SpriteSheets must - * set the {{#crossLink "LoadItem"}}{{/crossLink}} {{#crossLink "LoadItem/type:property"}}{{/crossLink}} property - * to {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}. + * A loader for JSON manifests. Items inside the manifest are loaded before the loader completes. To load manifests + * using JSONP, specify a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}} as part of the + * {{#crossLink "LoadItem"}}{{/crossLink}}. + * + * The list of files in the manifest must be defined on the top-level JSON object in a `manifest` property. This + * example shows a sample manifest definition, as well as how to to include a sub-manifest. + * + * { + * "path": "assets/", + * "manifest": [ + * "image.png", + * {"src": "image2.png", "id":"image2"}, + * {"src": "sub-manifest.json", "type":"manifest", "callback":"jsonCallback"} + * ] + * } * - * The {{#crossLink "LoadItem"}}{{/crossLink}} {{#crossLink "LoadItem/crossOrigin:property"}}{{/crossLink}} as well - * as the {{#crossLink "LoadQueue's"}}{{/crossLink}} `basePath` argument and {{#crossLink "LoadQueue/_preferXHR"}}{{/crossLink}} - * property supplied to the {{#crossLink "LoadQueue"}}{{/crossLink}} are passed on to the sub-manifest that loads - * the SpriteSheet images. + * When a ManifestLoader has completed loading, the parent loader (usually a {{#crossLink "LoadQueue"}}{{/crossLink}}, + * but could also be another ManifestLoader) will inherit all the loaded items, so you can access them directly. * - * Note that the SpriteSheet JSON does not respect the {{#crossLink "LoadQueue/_preferXHR:property"}}{{/crossLink}} - * property, which should instead be determined by the presence of a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}} - * property on the SpriteSheet load item. This is because the JSON loaded will have a different format depending on - * if it is loaded as JSON, so just changing `preferXHR` is not enough to change how it is loaded. - * @class SpriteSheetLoader + * Note that the {{#crossLink "JSONLoader"}}{{/crossLink}} and {{#crossLink "JSONPLoader"}}{{/crossLink}} are + * higher priority loaders, so manifests must set the {{#crossLink "LoadItem"}}{{/crossLink}} + * {{#crossLink "LoadItem/type:property"}}{{/crossLink}} property to {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}. + * @class ManifestLoader * @param {LoadItem|Object} loadItem * @extends AbstractLoader * @constructor */ - function SpriteSheetLoader(loadItem, preferXHR) { - this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SPRITESHEET); + function ManifestLoader(loadItem) { + this.AbstractLoader_constructor(loadItem, null, createjs.AbstractLoader.MANIFEST); - // protected properties + // Public Properties + /** + * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}, + * used to pass plugins to new LoadQueues that may be created. + * @property _plugins + * @type {Array} + * @private + * @since 0.6.1 + */ + this.plugins = null; + + + // Protected Properties /** - * An internal queue which loads the SpriteSheet's images. - * @method _manifestQueue + * An internal {{#crossLink "LoadQueue"}}{{/crossLink}} that loads the contents of the manifest. + * @property _manifestQueue * @type {LoadQueue} * @private */ this._manifestQueue = null; - } + }; - var p = createjs.extend(SpriteSheetLoader, createjs.AbstractLoader); - var s = SpriteSheetLoader; + var p = createjs.extend(ManifestLoader, createjs.AbstractLoader); + var s = ManifestLoader; // static properties /** * The amount of progress that the manifest itself takes up. - * @property SPRITESHEET_PROGRESS + * @property MANIFEST_PROGRESS * @type {number} * @default 0.25 (25%) * @private * @static */ - s.SPRITESHEET_PROGRESS = 0.25; + s.MANIFEST_PROGRESS = 0.25; // static methods /** * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}} + * {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}} * @method canLoadItem * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. * @returns {Boolean} Whether the loader can load the item. * @static */ s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.SPRITESHEET; + return item.type == createjs.AbstractLoader.MANIFEST; }; // public methods - p.destroy = function() { - this.AbstractLoader_destroy; - this._manifestQueue.close(); + p.load = function () { + this.AbstractLoader_load(); }; // protected methods @@ -7034,11 +6779,11 @@ this.createjs = this.createjs || {}; case "complete": this._rawResult = event.target.getResult(true); this._result = event.target.getResult(); - this._sendProgress(s.SPRITESHEET_PROGRESS); + this._sendProgress(s.MANIFEST_PROGRESS); this._loadManifest(this._result); return; case "progress": - event.loaded *= s.SPRITESHEET_PROGRESS; + event.loaded *= s.MANIFEST_PROGRESS; this.progress = event.loaded / event.total; if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; } this._sendProgress(event); @@ -7047,20 +6792,30 @@ this.createjs = this.createjs || {}; this.AbstractLoader_handleEvent(event); }; + p.destroy = function() { + this.AbstractLoader_destroy(); + this._manifestQueue.close(); + }; + /** - * Create and load the images once the SpriteSheet JSON has been loaded. + * Create and load the manifest items once the actual manifest has been loaded. * @method _loadManifest * @param {Object} json * @private */ p._loadManifest = function (json) { - if (json && json.images) { - var queue = this._manifestQueue = new createjs.LoadQueue(this._preferXHR, this._item.path, this._item.crossOrigin); - queue.on("complete", this._handleManifestComplete, this, true); + if (json && json.manifest) { + var queue = this._manifestQueue = new createjs.LoadQueue(); queue.on("fileload", this._handleManifestFileLoad, this); queue.on("progress", this._handleManifestProgress, this); + queue.on("complete", this._handleManifestComplete, this, true); queue.on("error", this._handleManifestError, this, true); - queue.loadManifest(json.images); + for(var i = 0, l = this.plugins.length; i < l; i++) { // conserve order of plugins + queue.installPlugin(this.plugins[i]); + } + queue.loadManifest(json); + } else { + this._sendComplete(); } }; @@ -7071,40 +6826,35 @@ this.createjs = this.createjs || {}; * @private */ p._handleManifestFileLoad = function (event) { - var image = event.result; - if (image != null) { - var images = this.getResult().images; - var pos = images.indexOf(event.item.src); - images[pos] = image; - } + event.target = null; + this.dispatchEvent(event); }; /** - * The images have completed loading. This triggers the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} - * {{#crossLink "Event"}}{{/crossLink}} from the SpriteSheetLoader. + * The manifest has completed loading. This triggers the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} + * {{#crossLink "Event"}}{{/crossLink}} from the ManifestLoader. * @method _handleManifestComplete * @param {Event} event * @private */ p._handleManifestComplete = function (event) { - this._result = new createjs.SpriteSheet(this._result); this._loadedItems = this._manifestQueue.getItems(true); this._sendComplete(); }; /** - * The images {{#crossLink "LoadQueue"}}{{/crossLink}} has reported progress. + * The manifest has reported progress. * @method _handleManifestProgress * @param {ProgressEvent} event * @private */ p._handleManifestProgress = function (event) { - this.progress = event.progress * (1 - s.SPRITESHEET_PROGRESS) + s.SPRITESHEET_PROGRESS; + this.progress = event.progress * (1 - s.MANIFEST_PROGRESS) + s.MANIFEST_PROGRESS; this._sendProgress(this.progress); }; /** - * An image has reported an error. + * The manifest has reported an error with one of the files. * @method _handleManifestError * @param {ErrorEvent} event * @private @@ -7115,98 +6865,411 @@ this.createjs = this.createjs || {}; this.dispatchEvent(newEvent); }; - createjs.SpriteSheetLoader = createjs.promote(SpriteSheetLoader, "AbstractLoader"); + createjs.ManifestLoader = createjs.promote(ManifestLoader, "AbstractLoader"); -}()); +}(scope.createjs)); //############################################################################## -// SVGLoader.js +// SoundLoader.js +//############################################################################## + +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + + // constructor + /** + * A loader for HTML audio files. PreloadJS can not load WebAudio files, as a WebAudio context is required, which + * should be created by either a library playing the sound (such as SoundJS, or an + * external framework that handles audio playback. To load content that can be played by WebAudio, use the + * {{#crossLink "BinaryLoader"}}{{/crossLink}}, and handle the audio context decoding manually. + * @class SoundLoader + * @param {LoadItem|Object} loadItem + * @param {Boolean} preferXHR + * @extends AbstractMediaLoader + * @constructor + */ + function SoundLoader(loadItem, preferXHR) { + this.AbstractMediaLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SOUND); + + // protected properties + if (createjs.RequestUtils.isAudioTag(loadItem)) { + this._tag = loadItem; + } else if (createjs.RequestUtils.isAudioTag(loadItem.src)) { + this._tag = loadItem; + } else if (createjs.RequestUtils.isAudioTag(loadItem.tag)) { + this._tag = createjs.RequestUtils.isAudioTag(loadItem) ? loadItem : loadItem.src; + } + + if (this._tag != null) { + this._preferXHR = false; + } + }; + + var p = createjs.extend(SoundLoader, createjs.AbstractMediaLoader); + var s = SoundLoader; + + // static methods + /** + * Determines if the loader can load a specific item. This loader can only load items that are of type + * {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}. + * @method canLoadItem + * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. + * @returns {Boolean} Whether the loader can load the item. + * @static + */ + s.canLoadItem = function (item) { + return item.type == createjs.AbstractLoader.SOUND; + }; + + // protected methods + p._createTag = function (src) { + var tag = document.createElement("audio"); + tag.autoplay = false; + tag.preload = "none"; + + //LM: Firefox fails when this the preload="none" for other tags, but it needs to be "none" to ensure PreloadJS works. + tag.src = src; + return tag; + }; + + createjs.SoundLoader = createjs.promote(SoundLoader, "AbstractMediaLoader"); + +}(scope.createjs)); + +//############################################################################## +// VideoLoader.js //############################################################################## -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor /** - * A loader for SVG files. - * @class SVGLoader + * A loader for video files. + * @class VideoLoader * @param {LoadItem|Object} loadItem * @param {Boolean} preferXHR - * @extends AbstractLoader + * @extends AbstractMediaLoader * @constructor */ - function SVGLoader(loadItem, preferXHR) { - this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SVG); - - // public properties - this.resultFormatter = this._formatResult; + function VideoLoader(loadItem, preferXHR) { + this.AbstractMediaLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.VIDEO); - // protected properties - this._tagSrcAttribute = "data"; + if (createjs.RequestUtils.isVideoTag(loadItem) || createjs.RequestUtils.isVideoTag(loadItem.src)) { + this.setTag(createjs.RequestUtils.isVideoTag(loadItem)?loadItem:loadItem.src); - if (preferXHR) { - this.setTag(document.createElement("svg")); + // We can't use XHR for a tag that's passed in. + this._preferXHR = false; } else { - this.setTag(document.createElement("object")); - this.getTag().type = "image/svg+xml"; + this.setTag(this._createTag()); } }; - var p = createjs.extend(SVGLoader, createjs.AbstractLoader); - var s = SVGLoader; + var p = createjs.extend(VideoLoader, createjs.AbstractMediaLoader); + var s = VideoLoader; + + /** + * Create a new video tag + * + * @returns {HTMLElement} + * @private + */ + p._createTag = function () { + return document.createElement("video"); + }; // static methods /** * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}} + * {{#crossLink "AbstractLoader/VIDEO:property"}}{{/crossLink}}. * @method canLoadItem * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. * @returns {Boolean} Whether the loader can load the item. * @static */ s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.SVG; + return item.type == createjs.AbstractLoader.VIDEO; }; - // protected methods - /** - * The result formatter for SVG files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {Object} - * @private - */ - p._formatResult = function (loader) { - // mime should be image/svg+xml, but Opera requires text/xml - var xml = createjs.DataUtils.parseXML(loader.getResult(true), "text/xml"); - var tag = loader.getTag(); + createjs.VideoLoader = createjs.promote(VideoLoader, "AbstractMediaLoader"); - if (!this._preferXHR && document.body.contains(tag)) { - document.body.removeChild(tag); - } +}(scope.createjs)); - if (xml.documentElement != null) { - tag.appendChild(xml.documentElement); - tag.style.visibility = "visible"; - return tag; - } else { // For browsers that don't support SVG, just give them the XML. (IE 9-8) - return xml; - } - }; +//############################################################################## +// SpriteSheetLoader.js +//############################################################################## + +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + + // constructor + /** + * A loader for EaselJS SpriteSheets. Images inside the spritesheet definition are loaded before the loader + * completes. To load SpriteSheets using JSONP, specify a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}} + * as part of the {{#crossLink "LoadItem"}}{{/crossLink}}. Note that the {{#crossLink "JSONLoader"}}{{/crossLink}} + * and {{#crossLink "JSONPLoader"}}{{/crossLink}} are higher priority loaders, so SpriteSheets must + * set the {{#crossLink "LoadItem"}}{{/crossLink}} {{#crossLink "LoadItem/type:property"}}{{/crossLink}} property + * to {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}. + * + * The {{#crossLink "LoadItem"}}{{/crossLink}} {{#crossLink "LoadItem/crossOrigin:property"}}{{/crossLink}} as well + * as the {{#crossLink "LoadQueue's"}}{{/crossLink}} `basePath` argument and {{#crossLink "LoadQueue/_preferXHR"}}{{/crossLink}} + * property supplied to the {{#crossLink "LoadQueue"}}{{/crossLink}} are passed on to the sub-manifest that loads + * the SpriteSheet images. + * + * Note that the SpriteSheet JSON does not respect the {{#crossLink "LoadQueue/_preferXHR:property"}}{{/crossLink}} + * property, which should instead be determined by the presence of a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}} + * property on the SpriteSheet load item. This is because the JSON loaded will have a different format depending on + * if it is loaded as JSON, so just changing `preferXHR` is not enough to change how it is loaded. + * @class SpriteSheetLoader + * @param {LoadItem|Object} loadItem + * @extends AbstractLoader + * @constructor + */ + function SpriteSheetLoader(loadItem, preferXHR) { + this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SPRITESHEET); + + // protected properties + /** + * An internal queue which loads the SpriteSheet's images. + * @method _manifestQueue + * @type {LoadQueue} + * @private + */ + this._manifestQueue = null; + } + + var p = createjs.extend(SpriteSheetLoader, createjs.AbstractLoader); + var s = SpriteSheetLoader; + + // static properties + /** + * The amount of progress that the manifest itself takes up. + * @property SPRITESHEET_PROGRESS + * @type {number} + * @default 0.25 (25%) + * @private + * @static + */ + s.SPRITESHEET_PROGRESS = 0.25; + + // static methods + /** + * Determines if the loader can load a specific item. This loader can only load items that are of type + * {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}} + * @method canLoadItem + * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. + * @returns {Boolean} Whether the loader can load the item. + * @static + */ + s.canLoadItem = function (item) { + return item.type == createjs.AbstractLoader.SPRITESHEET; + }; + + // public methods + p.destroy = function() { + this.AbstractLoader_destroy; + this._manifestQueue.close(); + }; + + // protected methods + p._createRequest = function() { + var callback = this._item.callback; + if (callback != null) { + this._request = new createjs.JSONPLoader(this._item); + } else { + this._request = new createjs.JSONLoader(this._item); + } + }; + + p.handleEvent = function (event) { + switch (event.type) { + case "complete": + this._rawResult = event.target.getResult(true); + this._result = event.target.getResult(); + this._sendProgress(s.SPRITESHEET_PROGRESS); + this._loadManifest(this._result); + return; + case "progress": + event.loaded *= s.SPRITESHEET_PROGRESS; + this.progress = event.loaded / event.total; + if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; } + this._sendProgress(event); + return; + } + this.AbstractLoader_handleEvent(event); + }; + + /** + * Create and load the images once the SpriteSheet JSON has been loaded. + * @method _loadManifest + * @param {Object} json + * @private + */ + p._loadManifest = function (json) { + if (json && json.images) { + var queue = this._manifestQueue = new createjs.LoadQueue(this._preferXHR, this._item.path, this._item.crossOrigin); + queue.on("complete", this._handleManifestComplete, this, true); + queue.on("fileload", this._handleManifestFileLoad, this); + queue.on("progress", this._handleManifestProgress, this); + queue.on("error", this._handleManifestError, this, true); + queue.loadManifest(json.images); + } + }; + + /** + * An item from the {{#crossLink "_manifestQueue:property"}}{{/crossLink}} has completed. + * @method _handleManifestFileLoad + * @param {Event} event + * @private + */ + p._handleManifestFileLoad = function (event) { + var image = event.result; + if (image != null) { + var images = this.getResult().images; + var pos = images.indexOf(event.item.src); + images[pos] = image; + } + }; + + /** + * The images have completed loading. This triggers the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} + * {{#crossLink "Event"}}{{/crossLink}} from the SpriteSheetLoader. + * @method _handleManifestComplete + * @param {Event} event + * @private + */ + p._handleManifestComplete = function (event) { + this._result = new createjs.SpriteSheet(this._result); + this._loadedItems = this._manifestQueue.getItems(true); + this._sendComplete(); + }; + + /** + * The images {{#crossLink "LoadQueue"}}{{/crossLink}} has reported progress. + * @method _handleManifestProgress + * @param {ProgressEvent} event + * @private + */ + p._handleManifestProgress = function (event) { + this.progress = event.progress * (1 - s.SPRITESHEET_PROGRESS) + s.SPRITESHEET_PROGRESS; + this._sendProgress(this.progress); + }; + + /** + * An image has reported an error. + * @method _handleManifestError + * @param {ErrorEvent} event + * @private + */ + p._handleManifestError = function (event) { + var newEvent = new createjs.Event("fileerror"); + newEvent.item = event.data; + this.dispatchEvent(newEvent); + }; + + createjs.SpriteSheetLoader = createjs.promote(SpriteSheetLoader, "AbstractLoader"); + +}(scope.createjs)); - createjs.SVGLoader = createjs.promote(SVGLoader, "AbstractLoader"); +//############################################################################## +// SVGLoader.js +//############################################################################## -}()); +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { + "use strict"; + + // constructor + /** + * A loader for SVG files. + * @class SVGLoader + * @param {LoadItem|Object} loadItem + * @param {Boolean} preferXHR + * @extends AbstractLoader + * @constructor + */ + function SVGLoader(loadItem, preferXHR) { + this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SVG); + + // public properties + this.resultFormatter = this._formatResult; + + // protected properties + this._tagSrcAttribute = "data"; + + if (preferXHR) { + this.setTag(document.createElement("svg")); + } else { + this.setTag(document.createElement("object")); + this.getTag().type = "image/svg+xml"; + } + }; + + var p = createjs.extend(SVGLoader, createjs.AbstractLoader); + var s = SVGLoader; + + // static methods + /** + * Determines if the loader can load a specific item. This loader can only load items that are of type + * {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}} + * @method canLoadItem + * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. + * @returns {Boolean} Whether the loader can load the item. + * @static + */ + s.canLoadItem = function (item) { + return item.type == createjs.AbstractLoader.SVG; + }; + + // protected methods + /** + * The result formatter for SVG files. + * @method _formatResult + * @param {AbstractLoader} loader + * @returns {Object} + * @private + */ + p._formatResult = function (loader) { + // mime should be image/svg+xml, but Opera requires text/xml + var xml = createjs.DataUtils.parseXML(loader.getResult(true), "text/xml"); + var tag = loader.getTag(); + + if (!this._preferXHR && document.body.contains(tag)) { + document.body.removeChild(tag); + } + + if (xml.documentElement != null) { + tag.appendChild(xml.documentElement); + tag.style.visibility = "visible"; + return tag; + } else { // For browsers that don't support SVG, just give them the XML. (IE 9-8) + return xml; + } + }; + + createjs.SVGLoader = createjs.promote(SVGLoader, "AbstractLoader"); + +}(scope.createjs)); //############################################################################## // XMLLoader.js //############################################################################## -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -7254,4 +7317,4 @@ this.createjs = this.createjs || {}; createjs.XMLLoader = createjs.promote(XMLLoader, "AbstractLoader"); -}()); \ No newline at end of file +}(scope.createjs)); \ No newline at end of file diff --git a/lib/preloadjs-NEXT.min.js b/lib/preloadjs-NEXT.min.js index 545d6e9..02415a9 100644 --- a/lib/preloadjs-NEXT.min.js +++ b/lib/preloadjs-NEXT.min.js @@ -9,5 +9,5 @@ * * This notice shall be included in all copies or substantial portions of the Software. */ -this.createjs=this.createjs||{},function(){"use strict";var a=createjs.PreloadJS=createjs.PreloadJS||{};a.version="NEXT",a.buildDate="Thu, 22 Oct 2015 16:01:29 GMT"}(),this.createjs=this.createjs||{},createjs.extend=function(a,b){"use strict";function c(){this.constructor=a}return c.prototype=b.prototype,a.prototype=new c},this.createjs=this.createjs||{},createjs.promote=function(a,b){"use strict";var c=a.prototype,d=Object.getPrototypeOf&&Object.getPrototypeOf(c)||c.__proto__;if(d){c[(b+="_")+"constructor"]=d.constructor;for(var e in d)c.hasOwnProperty(e)&&"function"==typeof d[e]&&(c[b+e]=d[e])}return a},this.createjs=this.createjs||{},createjs.indexOf=function(a,b){"use strict";for(var c=0,d=a.length;d>c;c++)if(b===a[c])return c;return-1},this.createjs=this.createjs||{},function(){"use strict";createjs.proxy=function(a,b){var c=Array.prototype.slice.call(arguments,2);return function(){return a.apply(b,Array.prototype.slice.call(arguments,0).concat(c))}}}(),this.createjs=this.createjs||{},function(){"use strict";function Event(a,b,c){this.type=a,this.target=null,this.currentTarget=null,this.eventPhase=0,this.bubbles=!!b,this.cancelable=!!c,this.timeStamp=(new Date).getTime(),this.defaultPrevented=!1,this.propagationStopped=!1,this.immediatePropagationStopped=!1,this.removed=!1}var a=Event.prototype;a.preventDefault=function(){this.defaultPrevented=this.cancelable&&!0},a.stopPropagation=function(){this.propagationStopped=!0},a.stopImmediatePropagation=function(){this.immediatePropagationStopped=this.propagationStopped=!0},a.remove=function(){this.removed=!0},a.clone=function(){return new Event(this.type,this.bubbles,this.cancelable)},a.set=function(a){for(var b in a)this[b]=a[b];return this},a.toString=function(){return"[Event (type="+this.type+")]"},createjs.Event=Event}(),this.createjs=this.createjs||{},function(){"use strict";function ErrorEvent(a,b,c){this.Event_constructor("error"),this.title=a,this.message=b,this.data=c}var a=createjs.extend(ErrorEvent,createjs.Event);a.clone=function(){return new createjs.ErrorEvent(this.title,this.message,this.data)},createjs.ErrorEvent=createjs.promote(ErrorEvent,"Event")}(),this.createjs=this.createjs||{},function(){"use strict";function EventDispatcher(){this._listeners=null,this._captureListeners=null}var a=EventDispatcher.prototype;EventDispatcher.initialize=function(b){b.addEventListener=a.addEventListener,b.on=a.on,b.removeEventListener=b.off=a.removeEventListener,b.removeAllEventListeners=a.removeAllEventListeners,b.hasEventListener=a.hasEventListener,b.dispatchEvent=a.dispatchEvent,b._dispatchEvent=a._dispatchEvent,b.willTrigger=a.willTrigger},a.addEventListener=function(a,b,c){var d;d=c?this._captureListeners=this._captureListeners||{}:this._listeners=this._listeners||{};var e=d[a];return e&&this.removeEventListener(a,b,c),e=d[a],e?e.push(b):d[a]=[b],b},a.on=function(a,b,c,d,e,f){return b.handleEvent&&(c=c||b,b=b.handleEvent),c=c||this,this.addEventListener(a,function(a){b.call(c,a,e),d&&a.remove()},f)},a.removeEventListener=function(a,b,c){var d=c?this._captureListeners:this._listeners;if(d){var e=d[a];if(e)for(var f=0,g=e.length;g>f;f++)if(e[f]==b){1==g?delete d[a]:e.splice(f,1);break}}},a.off=a.removeEventListener,a.removeAllEventListeners=function(a){a?(this._listeners&&delete this._listeners[a],this._captureListeners&&delete this._captureListeners[a]):this._listeners=this._captureListeners=null},a.dispatchEvent=function(a){if("string"==typeof a){var b=this._listeners;if(!b||!b[a])return!1;a=new createjs.Event(a)}else a.target&&a.clone&&(a=a.clone());try{a.target=this}catch(c){}if(a.bubbles&&this.parent){for(var d=this,e=[d];d.parent;)e.push(d=d.parent);var f,g=e.length;for(f=g-1;f>=0&&!a.propagationStopped;f--)e[f]._dispatchEvent(a,1+(0==f));for(f=1;g>f&&!a.propagationStopped;f++)e[f]._dispatchEvent(a,3)}else this._dispatchEvent(a,2);return a.defaultPrevented},a.hasEventListener=function(a){var b=this._listeners,c=this._captureListeners;return!!(b&&b[a]||c&&c[a])},a.willTrigger=function(a){for(var b=this;b;){if(b.hasEventListener(a))return!0;b=b.parent}return!1},a.toString=function(){return"[EventDispatcher]"},a._dispatchEvent=function(a,b){var c,d=1==b?this._captureListeners:this._listeners;if(a&&d){var e=d[a.type];if(!e||!(c=e.length))return;try{a.currentTarget=this}catch(f){}try{a.eventPhase=b}catch(f){}a.removed=!1,e=e.slice();for(var g=0;c>g&&!a.immediatePropagationStopped;g++){var h=e[g];h.handleEvent?h.handleEvent(a):h(a),a.removed&&(this.off(a.type,h,1==b),a.removed=!1)}}},createjs.EventDispatcher=EventDispatcher}(),this.createjs=this.createjs||{},function(){"use strict";function ProgressEvent(a,b){this.Event_constructor("progress"),this.loaded=a,this.total=null==b?1:b,this.progress=0==b?0:this.loaded/this.total}var a=createjs.extend(ProgressEvent,createjs.Event);a.clone=function(){return new createjs.ProgressEvent(this.loaded,this.total)},createjs.ProgressEvent=createjs.promote(ProgressEvent,"Event")}(window),function(){function a(b,d){function f(a){if(f[a]!==q)return f[a];var b;if("bug-string-char-index"==a)b="a"!="a"[0];else if("json"==a)b=f("json-stringify")&&f("json-parse");else{var c,e='{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}';if("json-stringify"==a){var i=d.stringify,k="function"==typeof i&&t;if(k){(c=function(){return 1}).toJSON=c;try{k="0"===i(0)&&"0"===i(new g)&&'""'==i(new h)&&i(s)===q&&i(q)===q&&i()===q&&"1"===i(c)&&"[1]"==i([c])&&"[null]"==i([q])&&"null"==i(null)&&"[null,null,null]"==i([q,s,null])&&i({a:[c,!0,!1,null,"\x00\b\n\f\r "]})==e&&"1"===i(null,c)&&"[\n 1,\n 2\n]"==i([1,2],null,1)&&'"-271821-04-20T00:00:00.000Z"'==i(new j(-864e13))&&'"+275760-09-13T00:00:00.000Z"'==i(new j(864e13))&&'"-000001-01-01T00:00:00.000Z"'==i(new j(-621987552e5))&&'"1969-12-31T23:59:59.999Z"'==i(new j(-1))}catch(l){k=!1}}b=k}if("json-parse"==a){var m=d.parse;if("function"==typeof m)try{if(0===m("0")&&!m(!1)){c=m(e);var n=5==c.a.length&&1===c.a[0];if(n){try{n=!m('" "')}catch(l){}if(n)try{n=1!==m("01")}catch(l){}if(n)try{n=1!==m("1.")}catch(l){}}}}catch(l){n=!1}b=n}}return f[a]=!!b}b||(b=e.Object()),d||(d=e.Object());var g=b.Number||e.Number,h=b.String||e.String,i=b.Object||e.Object,j=b.Date||e.Date,k=b.SyntaxError||e.SyntaxError,l=b.TypeError||e.TypeError,m=b.Math||e.Math,n=b.JSON||e.JSON;"object"==typeof n&&n&&(d.stringify=n.stringify,d.parse=n.parse);var o,p,q,r=i.prototype,s=r.toString,t=new j(-0xc782b5b800cec);try{t=-109252==t.getUTCFullYear()&&0===t.getUTCMonth()&&1===t.getUTCDate()&&10==t.getUTCHours()&&37==t.getUTCMinutes()&&6==t.getUTCSeconds()&&708==t.getUTCMilliseconds()}catch(u){}if(!f("json")){var v="[object Function]",w="[object Date]",x="[object Number]",y="[object String]",z="[object Array]",A="[object Boolean]",B=f("bug-string-char-index");if(!t)var C=m.floor,D=[0,31,59,90,120,151,181,212,243,273,304,334],E=function(a,b){return D[b]+365*(a-1970)+C((a-1969+(b=+(b>1)))/4)-C((a-1901+b)/100)+C((a-1601+b)/400)};if((o=r.hasOwnProperty)||(o=function(a){var b,c={};return(c.__proto__=null,c.__proto__={toString:1},c).toString!=s?o=function(a){var b=this.__proto__,c=a in(this.__proto__=null,this);return this.__proto__=b,c}:(b=c.constructor,o=function(a){var c=(this.constructor||b).prototype;return a in this&&!(a in c&&this[a]===c[a])}),c=null,o.call(this,a)}),p=function(a,b){var d,e,f,g=0;(d=function(){this.valueOf=0}).prototype.valueOf=0,e=new d;for(f in e)o.call(e,f)&&g++;return d=e=null,g?p=2==g?function(a,b){var c,d={},e=s.call(a)==v;for(c in a)e&&"prototype"==c||o.call(d,c)||!(d[c]=1)||!o.call(a,c)||b(c)}:function(a,b){var c,d,e=s.call(a)==v;for(c in a)e&&"prototype"==c||!o.call(a,c)||(d="constructor"===c)||b(c);(d||o.call(a,c="constructor"))&&b(c)}:(e=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"],p=function(a,b){var d,f,g=s.call(a)==v,h=!g&&"function"!=typeof a.constructor&&c[typeof a.hasOwnProperty]&&a.hasOwnProperty||o;for(d in a)g&&"prototype"==d||!h.call(a,d)||b(d);for(f=e.length;d=e[--f];h.call(a,d)&&b(d));}),p(a,b)},!f("json-stringify")){var F={92:"\\\\",34:'\\"',8:"\\b",12:"\\f",10:"\\n",13:"\\r",9:"\\t"},G="000000",H=function(a,b){return(G+(b||0)).slice(-a)},I="\\u00",J=function(a){for(var b='"',c=0,d=a.length,e=!B||d>10,f=e&&(B?a.split(""):a);d>c;c++){var g=a.charCodeAt(c);switch(g){case 8:case 9:case 10:case 12:case 13:case 34:case 92:b+=F[g];break;default:if(32>g){b+=I+H(2,g.toString(16));break}b+=e?f[c]:a.charAt(c)}}return b+'"'},K=function(a,b,c,d,e,f,g){var h,i,j,k,m,n,r,t,u,v,B,D,F,G,I,L;try{h=b[a]}catch(M){}if("object"==typeof h&&h)if(i=s.call(h),i!=w||o.call(h,"toJSON"))"function"==typeof h.toJSON&&(i!=x&&i!=y&&i!=z||o.call(h,"toJSON"))&&(h=h.toJSON(a));else if(h>-1/0&&1/0>h){if(E){for(m=C(h/864e5),j=C(m/365.2425)+1970-1;E(j+1,0)<=m;j++);for(k=C((m-E(j,0))/30.42);E(j,k+1)<=m;k++);m=1+m-E(j,k),n=(h%864e5+864e5)%864e5,r=C(n/36e5)%24,t=C(n/6e4)%60,u=C(n/1e3)%60,v=n%1e3}else j=h.getUTCFullYear(),k=h.getUTCMonth(),m=h.getUTCDate(),r=h.getUTCHours(),t=h.getUTCMinutes(),u=h.getUTCSeconds(),v=h.getUTCMilliseconds();h=(0>=j||j>=1e4?(0>j?"-":"+")+H(6,0>j?-j:j):H(4,j))+"-"+H(2,k+1)+"-"+H(2,m)+"T"+H(2,r)+":"+H(2,t)+":"+H(2,u)+"."+H(3,v)+"Z"}else h=null;if(c&&(h=c.call(b,a,h)),null===h)return"null";if(i=s.call(h),i==A)return""+h;if(i==x)return h>-1/0&&1/0>h?""+h:"null";if(i==y)return J(""+h);if("object"==typeof h){for(G=g.length;G--;)if(g[G]===h)throw l();if(g.push(h),B=[],I=f,f+=e,i==z){for(F=0,G=h.length;G>F;F++)D=K(F,h,c,d,e,f,g),B.push(D===q?"null":D);L=B.length?e?"[\n"+f+B.join(",\n"+f)+"\n"+I+"]":"["+B.join(",")+"]":"[]"}else p(d||h,function(a){var b=K(a,h,c,d,e,f,g);b!==q&&B.push(J(a)+":"+(e?" ":"")+b)}),L=B.length?e?"{\n"+f+B.join(",\n"+f)+"\n"+I+"}":"{"+B.join(",")+"}":"{}";return g.pop(),L}};d.stringify=function(a,b,d){var e,f,g,h;if(c[typeof b]&&b)if((h=s.call(b))==v)f=b;else if(h==z){g={};for(var i,j=0,k=b.length;k>j;i=b[j++],h=s.call(i),(h==y||h==x)&&(g[i]=1));}if(d)if((h=s.call(d))==x){if((d-=d%1)>0)for(e="",d>10&&(d=10);e.lengthL;)switch(e=f.charCodeAt(L)){case 9:case 10:case 13:case 32:L++;break;case 123:case 125:case 91:case 93:case 58:case 44:return a=B?f.charAt(L):f[L],L++,a;case 34:for(a="@",L++;g>L;)if(e=f.charCodeAt(L),32>e)P();else if(92==e)switch(e=f.charCodeAt(++L)){case 92:case 34:case 47:case 98:case 116:case 110:case 102:case 114:a+=O[e],L++;break;case 117:for(b=++L,c=L+4;c>L;L++)e=f.charCodeAt(L),e>=48&&57>=e||e>=97&&102>=e||e>=65&&70>=e||P();a+=N("0x"+f.slice(b,L));break;default:P()}else{if(34==e)break;for(e=f.charCodeAt(L),b=L;e>=32&&92!=e&&34!=e;)e=f.charCodeAt(++L);a+=f.slice(b,L)}if(34==f.charCodeAt(L))return L++,a;P();default:if(b=L,45==e&&(d=!0,e=f.charCodeAt(++L)),e>=48&&57>=e){for(48==e&&(e=f.charCodeAt(L+1),e>=48&&57>=e)&&P(),d=!1;g>L&&(e=f.charCodeAt(L),e>=48&&57>=e);L++);if(46==f.charCodeAt(L)){for(c=++L;g>c&&(e=f.charCodeAt(c),e>=48&&57>=e);c++);c==L&&P(),L=c}if(e=f.charCodeAt(L),101==e||69==e){for(e=f.charCodeAt(++L),(43==e||45==e)&&L++,c=L;g>c&&(e=f.charCodeAt(c),e>=48&&57>=e);c++);c==L&&P(),L=c}return+f.slice(b,L)}if(d&&P(),"true"==f.slice(L,L+4))return L+=4,!0;if("false"==f.slice(L,L+5))return L+=5,!1;if("null"==f.slice(L,L+4))return L+=4,null;P()}return"$"},R=function(a){var b,c;if("$"==a&&P(),"string"==typeof a){if("@"==(B?a.charAt(0):a[0]))return a.slice(1);if("["==a){for(b=[];a=Q(),"]"!=a;c||(c=!0))c&&(","==a?(a=Q(),"]"==a&&P()):P()),","==a&&P(),b.push(R(a));return b}if("{"==a){for(b={};a=Q(),"}"!=a;c||(c=!0))c&&(","==a?(a=Q(),"}"==a&&P()):P()),(","==a||"string"!=typeof a||"@"!=(B?a.charAt(0):a[0])||":"!=Q())&&P(),b[a.slice(1)]=R(Q());return b}P()}return a},S=function(a,b,c){var d=T(a,b,c);d===q?delete a[b]:a[b]=d},T=function(a,b,c){var d,e=a[b];if("object"==typeof e&&e)if(s.call(e)==z)for(d=e.length;d--;)S(e,d,c);else p(e,function(a){S(e,a,c)});return c.call(a,b,e)};d.parse=function(a,b){var c,d;return L=0,M=""+a,c=R(Q()),"$"!=Q()&&P(),L=M=null,b&&s.call(b)==v?T((d={},d[""]=c,d),"",b):c}}}return d.runInContext=a,d}var b="function"==typeof define&&define.amd,c={"function":!0,object:!0},d=c[typeof exports]&&exports&&!exports.nodeType&&exports,e=c[typeof window]&&window||this,f=d&&c[typeof module]&&module&&!module.nodeType&&"object"==typeof global&&global;if(!f||f.global!==f&&f.window!==f&&f.self!==f||(e=f),d&&!b)a(e,d);else{var g=e.JSON,h=e.JSON3,i=!1,j=a(e,e.JSON3={noConflict:function(){return i||(i=!0,e.JSON=g,e.JSON3=h,g=h=null),j}});e.JSON={parse:j.parse,stringify:j.stringify}}b&&define(function(){return j})}.call(this),function(){var a={};a.appendToHead=function(b){a.getHead().appendChild(b)},a.getHead=function(){return document.head||document.getElementsByTagName("head")[0]},a.getBody=function(){return document.body||document.getElementsByTagName("body")[0]},createjs.DomUtils=a}(),function(){var a={};a.parseXML=function(a,b){var c=null;try{if(window.DOMParser){var d=new DOMParser;c=d.parseFromString(a,b)}}catch(e){}if(!c)try{c=new ActiveXObject("Microsoft.XMLDOM"),c.async=!1,c.loadXML(a)}catch(e){c=null}return c},a.parseJSON=function(a){if(null==a)return null;try{return JSON.parse(a)}catch(b){throw b}},createjs.DataUtils=a}(),this.createjs=this.createjs||{},function(){"use strict";function LoadItem(){this.src=null,this.type=null,this.id=null,this.maintainOrder=!1,this.callback=null,this.data=null,this.method=createjs.LoadItem.GET,this.values=null,this.headers=null,this.withCredentials=!1,this.mimeType=null,this.crossOrigin=null,this.loadTimeout=b.LOAD_TIMEOUT_DEFAULT}var a=LoadItem.prototype={},b=LoadItem;b.LOAD_TIMEOUT_DEFAULT=8e3,b.create=function(a){if("string"==typeof a){var c=new LoadItem;return c.src=a,c}if(a instanceof b)return a;if(a instanceof Object&&a.src)return null==a.loadTimeout&&(a.loadTimeout=b.LOAD_TIMEOUT_DEFAULT),a;throw new Error("Type not recognized.")},a.set=function(a){for(var b in a)this[b]=a[b];return this},createjs.LoadItem=b}(),function(){var a={};a.ABSOLUTE_PATT=/^(?:\w+:)?\/{2}/i,a.RELATIVE_PATT=/^[.\/]*?\//i,a.EXTENSION_PATT=/\/?[^\/]+\.(\w{1,5})$/i,a.parseURI=function(b){var c={absolute:!1,relative:!1};if(null==b)return c;var d=b.indexOf("?");d>-1&&(b=b.substr(0,d));var e;return a.ABSOLUTE_PATT.test(b)?c.absolute=!0:a.RELATIVE_PATT.test(b)&&(c.relative=!0),(e=b.match(a.EXTENSION_PATT))&&(c.extension=e[1].toLowerCase()),c},a.formatQueryString=function(a,b){if(null==a)throw new Error("You must specify data.");var c=[];for(var d in a)c.push(d+"="+escape(a[d]));return b&&(c=c.concat(b)),c.join("&")},a.buildPath=function(a,b){if(null==b)return a;var c=[],d=a.indexOf("?");if(-1!=d){var e=a.slice(d+1);c=c.concat(e.split("&"))}return-1!=d?a.slice(0,d)+"?"+this._formatQueryString(b,c):a+"?"+this._formatQueryString(b,c)},a.isCrossDomain=function(a){var b=document.createElement("a");b.href=a.src;var c=document.createElement("a");c.href=location.href;var d=""!=b.hostname&&(b.port!=c.port||b.protocol!=c.protocol||b.hostname!=c.hostname);return d},a.isLocal=function(a){var b=document.createElement("a");return b.href=a.src,""==b.hostname&&"file:"==b.protocol},a.isBinary=function(a){switch(a){case createjs.AbstractLoader.IMAGE:case createjs.AbstractLoader.BINARY:return!0;default:return!1}},a.isImageTag=function(a){return a instanceof HTMLImageElement},a.isAudioTag=function(a){return window.HTMLAudioElement?a instanceof HTMLAudioElement:!1},a.isVideoTag=function(a){return window.HTMLVideoElement?a instanceof HTMLVideoElement:!1},a.isText=function(a){switch(a){case createjs.AbstractLoader.TEXT:case createjs.AbstractLoader.JSON:case createjs.AbstractLoader.MANIFEST:case createjs.AbstractLoader.XML:case createjs.AbstractLoader.CSS:case createjs.AbstractLoader.SVG:case createjs.AbstractLoader.JAVASCRIPT:case createjs.AbstractLoader.SPRITESHEET:return!0;default:return!1}},a.getTypeByExtension=function(a){if(null==a)return createjs.AbstractLoader.TEXT;switch(a.toLowerCase()){case"jpeg":case"jpg":case"gif":case"png":case"webp":case"bmp":return createjs.AbstractLoader.IMAGE;case"ogg":case"mp3":case"webm":return createjs.AbstractLoader.SOUND;case"mp4":case"webm":case"ts":return createjs.AbstractLoader.VIDEO;case"json":return createjs.AbstractLoader.JSON;case"xml":return createjs.AbstractLoader.XML;case"css":return createjs.AbstractLoader.CSS;case"js":return createjs.AbstractLoader.JAVASCRIPT;case"svg":return createjs.AbstractLoader.SVG;default:return createjs.AbstractLoader.TEXT}},createjs.RequestUtils=a}(),this.createjs=this.createjs||{},function(){"use strict";function AbstractLoader(a,b,c){this.EventDispatcher_constructor(),this.loaded=!1,this.canceled=!1,this.progress=0,this.type=c,this.resultFormatter=null,this._item=a?createjs.LoadItem.create(a):null,this._preferXHR=b,this._result=null,this._rawResult=null,this._loadedItems=null,this._tagSrcAttribute=null,this._tag=null}var a=createjs.extend(AbstractLoader,createjs.EventDispatcher),b=AbstractLoader;b.POST="POST",b.GET="GET",b.BINARY="binary",b.CSS="css",b.IMAGE="image",b.JAVASCRIPT="javascript",b.JSON="json",b.JSONP="jsonp",b.MANIFEST="manifest",b.SOUND="sound",b.VIDEO="video",b.SPRITESHEET="spritesheet",b.SVG="svg",b.TEXT="text",b.XML="xml",a.getItem=function(){return this._item},a.getResult=function(a){return a?this._rawResult:this._result},a.getTag=function(){return this._tag},a.setTag=function(a){this._tag=a},a.load=function(){this._createRequest(),this._request.on("complete",this,this),this._request.on("progress",this,this),this._request.on("loadStart",this,this),this._request.on("abort",this,this),this._request.on("timeout",this,this),this._request.on("error",this,this);var a=new createjs.Event("initialize");a.loader=this._request,this.dispatchEvent(a),this._request.load()},a.cancel=function(){this.canceled=!0,this.destroy()},a.destroy=function(){this._request&&(this._request.removeAllEventListeners(),this._request.destroy()),this._request=null,this._item=null,this._rawResult=null,this._result=null,this._loadItems=null,this.removeAllEventListeners()},a.getLoadedItems=function(){return this._loadedItems},a._createRequest=function(){this._request=this._preferXHR?new createjs.XHRRequest(this._item):new createjs.TagRequest(this._item,this._tag||this._createTag(),this._tagSrcAttribute)},a._createTag=function(){return null},a._sendLoadStart=function(){this._isCanceled()||this.dispatchEvent("loadstart")},a._sendProgress=function(a){if(!this._isCanceled()){var b=null;"number"==typeof a?(this.progress=a,b=new createjs.ProgressEvent(this.progress)):(b=a,this.progress=a.loaded/a.total,b.progress=this.progress,(isNaN(this.progress)||1/0==this.progress)&&(this.progress=0)),this.hasEventListener("progress")&&this.dispatchEvent(b)}},a._sendComplete=function(){if(!this._isCanceled()){this.loaded=!0;var a=new createjs.Event("complete");a.rawResult=this._rawResult,null!=this._result&&(a.result=this._result),this.dispatchEvent(a)}},a._sendError=function(a){!this._isCanceled()&&this.hasEventListener("error")&&(null==a&&(a=new createjs.ErrorEvent("PRELOAD_ERROR_EMPTY")),this.dispatchEvent(a))},a._isCanceled=function(){return null==window.createjs||this.canceled?!0:!1},a.resultFormatter=null,a.handleEvent=function(a){switch(a.type){case"complete":this._rawResult=a.target._response;var b=this.resultFormatter&&this.resultFormatter(this);b instanceof Function?b.call(this,createjs.proxy(this._resultFormatSuccess,this),createjs.proxy(this._resultFormatFailed,this)):(this._result=b||this._rawResult,this._sendComplete());break;case"progress":this._sendProgress(a);break;case"error":this._sendError(a);break;case"loadstart":this._sendLoadStart();break;case"abort":case"timeout":this._isCanceled()||this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_"+a.type.toUpperCase()+"_ERROR"))}},a._resultFormatSuccess=function(a){this._result=a,this._sendComplete()},a._resultFormatFailed=function(a){this._sendError(a)},a.buildPath=function(a,b){return createjs.RequestUtils.buildPath(a,b)},a.toString=function(){return"[PreloadJS AbstractLoader]"},createjs.AbstractLoader=createjs.promote(AbstractLoader,"EventDispatcher")}(),this.createjs=this.createjs||{},function(){"use strict";function AbstractMediaLoader(a,b,c){this.AbstractLoader_constructor(a,b,c),this.resultFormatter=this._formatResult,this._tagSrcAttribute="src",this.on("initialize",this._updateXHR,this)}var a=createjs.extend(AbstractMediaLoader,createjs.AbstractLoader);a.load=function(){this._tag||(this._tag=this._createTag(this._item.src)),this._tag.preload="auto",this._tag.load(),this.AbstractLoader_load()},a._createTag=function(){},a._createRequest=function(){this._request=this._preferXHR?new createjs.XHRRequest(this._item):new createjs.MediaTagRequest(this._item,this._tag||this._createTag(),this._tagSrcAttribute)},a._updateXHR=function(a){a.loader.setResponseType&&a.loader.setResponseType("blob")},a._formatResult=function(a){if(this._tag.removeEventListener&&this._tag.removeEventListener("canplaythrough",this._loadedHandler),this._tag.onstalled=null,this._preferXHR){var b=window.URL||window.webkitURL,c=a.getResult(!0);a.getTag().src=b.createObjectURL(c)}return a.getTag()},createjs.AbstractMediaLoader=createjs.promote(AbstractMediaLoader,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";var AbstractRequest=function(a){this._item=a},a=createjs.extend(AbstractRequest,createjs.EventDispatcher);a.load=function(){},a.destroy=function(){},a.cancel=function(){},createjs.AbstractRequest=createjs.promote(AbstractRequest,"EventDispatcher")}(),this.createjs=this.createjs||{},function(){"use strict";function TagRequest(a,b,c){this.AbstractRequest_constructor(a),this._tag=b,this._tagSrcAttribute=c,this._loadedHandler=createjs.proxy(this._handleTagComplete,this),this._addedToDOM=!1,this._startTagVisibility=null}var a=createjs.extend(TagRequest,createjs.AbstractRequest);a.load=function(){this._tag.onload=createjs.proxy(this._handleTagComplete,this),this._tag.onreadystatechange=createjs.proxy(this._handleReadyStateChange,this),this._tag.onerror=createjs.proxy(this._handleError,this);var a=new createjs.Event("initialize");a.loader=this._tag,this.dispatchEvent(a),this._hideTag(),this._loadTimeout=setTimeout(createjs.proxy(this._handleTimeout,this),this._item.loadTimeout),this._tag[this._tagSrcAttribute]=this._item.src,null==this._tag.parentNode&&(window.document.body.appendChild(this._tag),this._addedToDOM=!0)},a.destroy=function(){this._clean(),this._tag=null,this.AbstractRequest_destroy()},a._handleReadyStateChange=function(){clearTimeout(this._loadTimeout);var a=this._tag;("loaded"==a.readyState||"complete"==a.readyState)&&this._handleTagComplete()},a._handleError=function(){this._clean(),this.dispatchEvent("error")},a._handleTagComplete=function(){this._rawResult=this._tag,this._result=this.resultFormatter&&this.resultFormatter(this)||this._rawResult,this._clean(),this._showTag(),this.dispatchEvent("complete")},a._handleTimeout=function(){this._clean(),this.dispatchEvent(new createjs.Event("timeout"))},a._clean=function(){this._tag.onload=null,this._tag.onreadystatechange=null,this._tag.onerror=null,this._addedToDOM&&null!=this._tag.parentNode&&this._tag.parentNode.removeChild(this._tag),clearTimeout(this._loadTimeout)},a._hideTag=function(){this._startTagVisibility=this._tag.style.visibility,this._tag.style.visibility="hidden"},a._showTag=function(){this._tag.style.visibility=this._startTagVisibility},a._handleStalled=function(){},createjs.TagRequest=createjs.promote(TagRequest,"AbstractRequest")}(),this.createjs=this.createjs||{},function(){"use strict";function MediaTagRequest(a,b,c){this.AbstractRequest_constructor(a),this._tag=b,this._tagSrcAttribute=c,this._loadedHandler=createjs.proxy(this._handleTagComplete,this)}var a=createjs.extend(MediaTagRequest,createjs.TagRequest);a.load=function(){var a=createjs.proxy(this._handleStalled,this);this._stalledCallback=a;var b=createjs.proxy(this._handleProgress,this);this._handleProgress=b,this._tag.addEventListener("stalled",a),this._tag.addEventListener("progress",b),this._tag.addEventListener&&this._tag.addEventListener("canplaythrough",this._loadedHandler,!1),this.TagRequest_load()},a._handleReadyStateChange=function(){clearTimeout(this._loadTimeout);var a=this._tag;("loaded"==a.readyState||"complete"==a.readyState)&&this._handleTagComplete()},a._handleStalled=function(){},a._handleProgress=function(a){if(a&&!(a.loaded>0&&0==a.total)){var b=new createjs.ProgressEvent(a.loaded,a.total);this.dispatchEvent(b)}},a._clean=function(){this._tag.removeEventListener&&this._tag.removeEventListener("canplaythrough",this._loadedHandler),this._tag.removeEventListener("stalled",this._stalledCallback),this._tag.removeEventListener("progress",this._progressCallback),this.TagRequest__clean()},createjs.MediaTagRequest=createjs.promote(MediaTagRequest,"TagRequest")}(),this.createjs=this.createjs||{},function(){"use strict";function XHRRequest(a){this.AbstractRequest_constructor(a),this._request=null,this._loadTimeout=null,this._xhrLevel=1,this._response=null,this._rawResponse=null,this._canceled=!1,this._handleLoadStartProxy=createjs.proxy(this._handleLoadStart,this),this._handleProgressProxy=createjs.proxy(this._handleProgress,this),this._handleAbortProxy=createjs.proxy(this._handleAbort,this),this._handleErrorProxy=createjs.proxy(this._handleError,this),this._handleTimeoutProxy=createjs.proxy(this._handleTimeout,this),this._handleLoadProxy=createjs.proxy(this._handleLoad,this),this._handleReadyStateChangeProxy=createjs.proxy(this._handleReadyStateChange,this),!this._createXHR(a)}var a=createjs.extend(XHRRequest,createjs.AbstractRequest);XHRRequest.ACTIVEX_VERSIONS=["Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.5.0","Msxml2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],a.getResult=function(a){return a&&this._rawResponse?this._rawResponse:this._response},a.cancel=function(){this.canceled=!0,this._clean(),this._request.abort()},a.load=function(){if(null==this._request)return void this._handleError();null!=this._request.addEventListener?(this._request.addEventListener("loadstart",this._handleLoadStartProxy,!1),this._request.addEventListener("progress",this._handleProgressProxy,!1),this._request.addEventListener("abort",this._handleAbortProxy,!1),this._request.addEventListener("error",this._handleErrorProxy,!1),this._request.addEventListener("timeout",this._handleTimeoutProxy,!1),this._request.addEventListener("load",this._handleLoadProxy,!1),this._request.addEventListener("readystatechange",this._handleReadyStateChangeProxy,!1)):(this._request.onloadstart=this._handleLoadStartProxy,this._request.onprogress=this._handleProgressProxy,this._request.onabort=this._handleAbortProxy,this._request.onerror=this._handleErrorProxy,this._request.ontimeout=this._handleTimeoutProxy,this._request.onload=this._handleLoadProxy,this._request.onreadystatechange=this._handleReadyStateChangeProxy),1==this._xhrLevel&&(this._loadTimeout=setTimeout(createjs.proxy(this._handleTimeout,this),this._item.loadTimeout));try{this._item.values&&this._item.method!=createjs.AbstractLoader.GET?this._item.method==createjs.AbstractLoader.POST&&this._request.send(createjs.RequestUtils.formatQueryString(this._item.values)):this._request.send()}catch(a){this.dispatchEvent(new createjs.ErrorEvent("XHR_SEND",null,a))}},a.setResponseType=function(a){"blob"===a&&(a=window.URL?"blob":"arraybuffer",this._responseType=a),this._request.responseType=a},a.getAllResponseHeaders=function(){return this._request.getAllResponseHeaders instanceof Function?this._request.getAllResponseHeaders():null},a.getResponseHeader=function(a){return this._request.getResponseHeader instanceof Function?this._request.getResponseHeader(a):null},a._handleProgress=function(a){if(a&&!(a.loaded>0&&0==a.total)){var b=new createjs.ProgressEvent(a.loaded,a.total);this.dispatchEvent(b)}},a._handleLoadStart=function(){clearTimeout(this._loadTimeout),this.dispatchEvent("loadstart")},a._handleAbort=function(a){this._clean(),this.dispatchEvent(new createjs.ErrorEvent("XHR_ABORTED",null,a))},a._handleError=function(a){this._clean(),this.dispatchEvent(new createjs.ErrorEvent(a.message))},a._handleReadyStateChange=function(){4==this._request.readyState&&this._handleLoad()},a._handleLoad=function(){if(!this.loaded){this.loaded=!0;var a=this._checkError();if(a)return void this._handleError(a);if(this._response=this._getResponse(),"arraybuffer"===this._responseType)try{this._response=new Blob([this._response])}catch(b){if(window.BlobBuilder=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,"TypeError"===b.name&&window.BlobBuilder){var c=new BlobBuilder;c.append(this._response),this._response=c.getBlob()}}this._clean(),this.dispatchEvent(new createjs.Event("complete"))}},a._handleTimeout=function(a){this._clean(),this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_TIMEOUT",null,a))},a._checkError=function(){var a=parseInt(this._request.status);switch(a){case 404:case 0:return new Error(a)}return null},a._getResponse=function(){if(null!=this._response)return this._response;if(null!=this._request.response)return this._request.response;try{if(null!=this._request.responseText)return this._request.responseText}catch(a){}try{if(null!=this._request.responseXML)return this._request.responseXML}catch(a){}return null},a._createXHR=function(a){var b=createjs.RequestUtils.isCrossDomain(a),c={},d=null;if(window.XMLHttpRequest)d=new XMLHttpRequest,b&&void 0===d.withCredentials&&window.XDomainRequest&&(d=new XDomainRequest);else{for(var e=0,f=s.ACTIVEX_VERSIONS.length;f>e;e++){var g=s.ACTIVEX_VERSIONS[e];try{d=new ActiveXObject(g);break}catch(h){}}if(null==d)return!1}null==a.mimeType&&createjs.RequestUtils.isText(a.type)&&(a.mimeType="text/plain; charset=utf-8"),a.mimeType&&d.overrideMimeType&&d.overrideMimeType(a.mimeType),this._xhrLevel="string"==typeof d.responseType?2:1;var i=null;if(i=a.method==createjs.AbstractLoader.GET?createjs.RequestUtils.buildPath(a.src,a.values):a.src,d.open(a.method||createjs.AbstractLoader.GET,i,!0),b&&d instanceof XMLHttpRequest&&1==this._xhrLevel&&(c.Origin=location.origin),a.values&&a.method==createjs.AbstractLoader.POST&&(c["Content-Type"]="application/x-www-form-urlencoded"),b||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest"),a.headers)for(var j in a.headers)c[j]=a.headers[j];for(j in c)d.setRequestHeader(j,c[j]);return d instanceof XMLHttpRequest&&void 0!==a.withCredentials&&(d.withCredentials=a.withCredentials),this._request=d,!0},a._clean=function(){clearTimeout(this._loadTimeout),null!=this._request.removeEventListener?(this._request.removeEventListener("loadstart",this._handleLoadStartProxy),this._request.removeEventListener("progress",this._handleProgressProxy),this._request.removeEventListener("abort",this._handleAbortProxy),this._request.removeEventListener("error",this._handleErrorProxy),this._request.removeEventListener("timeout",this._handleTimeoutProxy),this._request.removeEventListener("load",this._handleLoadProxy),this._request.removeEventListener("readystatechange",this._handleReadyStateChangeProxy)):(this._request.onloadstart=null,this._request.onprogress=null,this._request.onabort=null,this._request.onerror=null,this._request.ontimeout=null,this._request.onload=null,this._request.onreadystatechange=null)},a.toString=function(){return"[PreloadJS XHRRequest]"},createjs.XHRRequest=createjs.promote(XHRRequest,"AbstractRequest")}(),this.createjs=this.createjs||{},function(){"use strict";function LoadQueue(a,b,c){this.AbstractLoader_constructor(),this._plugins=[],this._typeCallbacks={},this._extensionCallbacks={},this.next=null,this.maintainScriptOrder=!0,this.stopOnError=!1,this._maxConnections=1,this._availableLoaders=[createjs.ImageLoader,createjs.JavaScriptLoader,createjs.CSSLoader,createjs.JSONLoader,createjs.JSONPLoader,createjs.SoundLoader,createjs.ManifestLoader,createjs.SpriteSheetLoader,createjs.XMLLoader,createjs.SVGLoader,createjs.BinaryLoader,createjs.VideoLoader,createjs.TextLoader],this._defaultLoaderLength=this._availableLoaders.length,this.init(a,b,c) -}var a=createjs.extend(LoadQueue,createjs.AbstractLoader),b=LoadQueue;a.init=function(a,b,c){this.useXHR=!0,this.preferXHR=!0,this._preferXHR=!0,this.setPreferXHR(a),this._paused=!1,this._basePath=b,this._crossOrigin=c,this._loadStartWasDispatched=!1,this._currentlyLoadingScript=null,this._currentLoads=[],this._loadQueue=[],this._loadQueueBackup=[],this._loadItemsById={},this._loadItemsBySrc={},this._loadedResults={},this._loadedRawResults={},this._numItems=0,this._numItemsLoaded=0,this._scriptOrder=[],this._loadedScripts=[],this._lastProgress=0/0},b.loadTimeout=8e3,b.LOAD_TIMEOUT=0,b.BINARY=createjs.AbstractLoader.BINARY,b.CSS=createjs.AbstractLoader.CSS,b.IMAGE=createjs.AbstractLoader.IMAGE,b.JAVASCRIPT=createjs.AbstractLoader.JAVASCRIPT,b.JSON=createjs.AbstractLoader.JSON,b.JSONP=createjs.AbstractLoader.JSONP,b.MANIFEST=createjs.AbstractLoader.MANIFEST,b.SOUND=createjs.AbstractLoader.SOUND,b.VIDEO=createjs.AbstractLoader.VIDEO,b.SVG=createjs.AbstractLoader.SVG,b.TEXT=createjs.AbstractLoader.TEXT,b.XML=createjs.AbstractLoader.XML,b.POST=createjs.AbstractLoader.POST,b.GET=createjs.AbstractLoader.GET,a.registerLoader=function(a){if(!a||!a.canLoadItem)throw new Error("loader is of an incorrect type.");if(-1!=this._availableLoaders.indexOf(a))throw new Error("loader already exists.");this._availableLoaders.unshift(a)},a.unregisterLoader=function(a){var b=this._availableLoaders.indexOf(a);-1!=b&&b0)return;var c=!1;if(b){for(;b.length;){var d=b.pop(),e=this.getResult(d);for(f=this._loadQueue.length-1;f>=0;f--)if(g=this._loadQueue[f].getItem(),g.id==d||g.src==d){this._loadQueue.splice(f,1)[0].cancel();break}for(f=this._loadQueueBackup.length-1;f>=0;f--)if(g=this._loadQueueBackup[f].getItem(),g.id==d||g.src==d){this._loadQueueBackup.splice(f,1)[0].cancel();break}if(e)this._disposeItem(this.getItem(d));else for(var f=this._currentLoads.length-1;f>=0;f--){var g=this._currentLoads[f].getItem();if(g.id==d||g.src==d){this._currentLoads.splice(f,1)[0].cancel(),c=!0;break}}}c&&this._loadNext()}else{this.close();for(var h in this._loadItemsById)this._disposeItem(this._loadItemsById[h]);this.init(this.preferXHR,this._basePath)}},a.reset=function(){this.close();for(var a in this._loadItemsById)this._disposeItem(this._loadItemsById[a]);for(var b=[],c=0,d=this._loadQueueBackup.length;d>c;c++)b.push(this._loadQueueBackup[c].getItem());this.loadManifest(b,!1)},a.installPlugin=function(a){if(null!=a&&null!=a.getPreloadHandlers){this._plugins.push(a);var b=a.getPreloadHandlers();if(b.scope=a,null!=b.types)for(var c=0,d=b.types.length;d>c;c++)this._typeCallbacks[b.types[c]]=b;if(null!=b.extensions)for(c=0,d=b.extensions.length;d>c;c++)this._extensionCallbacks[b.extensions[c]]=b}},a.setMaxConnections=function(a){this._maxConnections=a,!this._paused&&this._loadQueue.length>0&&this._loadNext()},a.loadFile=function(a,b,c){if(null==a){var d=new createjs.ErrorEvent("PRELOAD_NO_FILE");return void this._sendError(d)}this._addItem(a,null,c),this.setPaused(b!==!1?!1:!0)},a.loadManifest=function(a,c,d){var e=null,f=null;if(Array.isArray(a)){if(0==a.length){var g=new createjs.ErrorEvent("PRELOAD_MANIFEST_EMPTY");return void this._sendError(g)}e=a}else if("string"==typeof a)e=[{src:a,type:b.MANIFEST}];else{if("object"!=typeof a){var g=new createjs.ErrorEvent("PRELOAD_MANIFEST_NULL");return void this._sendError(g)}if(void 0!==a.src){if(null==a.type)a.type=b.MANIFEST;else if(a.type!=b.MANIFEST){var g=new createjs.ErrorEvent("PRELOAD_MANIFEST_TYPE");this._sendError(g)}e=[a]}else void 0!==a.manifest&&(e=a.manifest,f=a.path)}for(var h=0,i=e.length;i>h;h++)this._addItem(e[h],f,d);this.setPaused(c!==!1?!1:!0)},a.load=function(){this.setPaused(!1)},a.getItem=function(a){return this._loadItemsById[a]||this._loadItemsBySrc[a]},a.getResult=function(a,b){var c=this._loadItemsById[a]||this._loadItemsBySrc[a];if(null==c)return null;var d=c.id;return b&&this._loadedRawResults[d]?this._loadedRawResults[d]:this._loadedResults[d]},a.getItems=function(a){var b=[];for(var c in this._loadItemsById){var d=this._loadItemsById[c],e=this.getResult(c);(a!==!0||null!=e)&&b.push({item:d,result:e,rawResult:this.getResult(c,!0)})}return b},a.setPaused=function(a){this._paused=a,this._paused||this._loadNext()},a.close=function(){for(;this._currentLoads.length;)this._currentLoads.pop().cancel();this._scriptOrder.length=0,this._loadedScripts.length=0,this.loadStartWasDispatched=!1,this._itemCount=0,this._lastProgress=0/0},a._addItem=function(a,b,c){var d=this._createLoadItem(a,b,c);if(null!=d){var e=this._createLoader(d);null!=e&&("plugins"in e&&(e.plugins=this._plugins),d._loader=e,this._loadQueue.push(e),this._loadQueueBackup.push(e),this._numItems++,this._updateProgress(),(this.maintainScriptOrder&&d.type==createjs.LoadQueue.JAVASCRIPT||d.maintainOrder===!0)&&(this._scriptOrder.push(d),this._loadedScripts.push(null)))}},a._createLoadItem=function(a,b,c){var d=createjs.LoadItem.create(a);if(null==d)return null;var e="",f=c||this._basePath;if(d.src instanceof Object){if(!d.type)return null;if(b){e=b;var g=createjs.RequestUtils.parseURI(b);null==f||g.absolute||g.relative||(e=f+e)}else null!=f&&(e=f)}else{var h=createjs.RequestUtils.parseURI(d.src);h.extension&&(d.ext=h.extension),null==d.type&&(d.type=createjs.RequestUtils.getTypeByExtension(d.ext));var i=d.src;if(!h.absolute&&!h.relative)if(b){e=b;var g=createjs.RequestUtils.parseURI(b);i=b+i,null==f||g.absolute||g.relative||(e=f+e)}else null!=f&&(e=f);d.src=e+d.src}d.path=e,(void 0===d.id||null===d.id||""===d.id)&&(d.id=i);var j=this._typeCallbacks[d.type]||this._extensionCallbacks[d.ext];if(j){var k=j.callback.call(j.scope,d,this);if(k===!1)return null;k===!0||null!=k&&(d._loader=k),h=createjs.RequestUtils.parseURI(d.src),null!=h.extension&&(d.ext=h.extension)}return this._loadItemsById[d.id]=d,this._loadItemsBySrc[d.src]=d,null==d.crossOrigin&&(d.crossOrigin=this._crossOrigin),d},a._createLoader=function(a){if(null!=a._loader)return a._loader;for(var b=this.preferXHR,c=0;c=this._maxConnections);a++){var b=this._loadQueue[a];this._canStartLoad(b)&&(this._loadQueue.splice(a,1),a--,this._loadItem(b))}}},a._loadItem=function(a){a.on("fileload",this._handleFileLoad,this),a.on("progress",this._handleProgress,this),a.on("complete",this._handleFileComplete,this),a.on("error",this._handleError,this),a.on("fileerror",this._handleFileError,this),this._currentLoads.push(a),this._sendFileStart(a.getItem()),a.load()},a._handleFileLoad=function(a){a.target=null,this.dispatchEvent(a)},a._handleFileError=function(a){var b=new createjs.ErrorEvent("FILE_LOAD_ERROR",null,a.item);this._sendError(b)},a._handleError=function(a){var b=a.target;this._numItemsLoaded++,this._finishOrderedItem(b,!0),this._updateProgress();var c=new createjs.ErrorEvent("FILE_LOAD_ERROR",null,b.getItem());this._sendError(c),this.stopOnError?this.setPaused(!0):(this._removeLoadItem(b),this._cleanLoadItem(b),this._loadNext())},a._handleFileComplete=function(a){var b=a.target,c=b.getItem(),d=b.getResult();this._loadedResults[c.id]=d;var e=b.getResult(!0);null!=e&&e!==d&&(this._loadedRawResults[c.id]=e),this._saveLoadedItems(b),this._removeLoadItem(b),this._finishOrderedItem(b)||this._processFinishedLoad(c,b),this._cleanLoadItem(b)},a._saveLoadedItems=function(a){var b=a.getLoadedItems();if(null!==b)for(var c=0;cb;b++){var c=this._loadedScripts[b];if(null===c)break;if(c!==!0){var d=this._loadedResults[c.id];c.type==createjs.LoadQueue.JAVASCRIPT&&createjs.DomUtils.appendToHead(d);var e=c._loader;this._processFinishedLoad(c,e),this._loadedScripts[b]=!0}}},a._processFinishedLoad=function(a,b){if(this._numItemsLoaded++,!this.maintainScriptOrder&&a.type==createjs.LoadQueue.JAVASCRIPT){var c=b.getTag();createjs.DomUtils.appendToHead(c)}this._updateProgress(),this._sendFileComplete(a,b),this._loadNext()},a._canStartLoad=function(a){if(!this.maintainScriptOrder||a.preferXHR)return!0;var b=a.getItem();if(b.type!=createjs.LoadQueue.JAVASCRIPT)return!0;if(this._currentlyLoadingScript)return!1;for(var c=this._scriptOrder.indexOf(b),d=0;c>d;){var e=this._loadedScripts[d];if(null==e)return!1;d++}return this._currentlyLoadingScript=!0,!0},a._removeLoadItem=function(a){for(var b=this._currentLoads.length,c=0;b>c;c++)if(this._currentLoads[c]==a){this._currentLoads.splice(c,1);break}},a._cleanLoadItem=function(a){var b=a.getItem();b&&delete b._loader},a._handleProgress=function(a){var b=a.target;this._sendFileProgress(b.getItem(),b.progress),this._updateProgress()},a._updateProgress=function(){var a=this._numItemsLoaded/this._numItems,b=this._numItems-this._numItemsLoaded;if(b>0){for(var c=0,d=0,e=this._currentLoads.length;e>d;d++)c+=this._currentLoads[d].progress;a+=c/b*(b/this._numItems)}this._lastProgress!=a&&(this._sendProgress(a),this._lastProgress=a)},a._disposeItem=function(a){delete this._loadedResults[a.id],delete this._loadedRawResults[a.id],delete this._loadItemsById[a.id],delete this._loadItemsBySrc[a.src]},a._sendFileProgress=function(a,b){if(!this._isCanceled()&&!this._paused&&this.hasEventListener("fileprogress")){var c=new createjs.Event("fileprogress");c.progress=b,c.loaded=b,c.total=1,c.item=a,this.dispatchEvent(c)}},a._sendFileComplete=function(a,b){if(!this._isCanceled()&&!this._paused){var c=new createjs.Event("fileload");c.loader=b,c.item=a,c.result=this._loadedResults[a.id],c.rawResult=this._loadedRawResults[a.id],a.completeHandler&&a.completeHandler(c),this.hasEventListener("fileload")&&this.dispatchEvent(c)}},a._sendFileStart=function(a){var b=new createjs.Event("filestart");b.item=a,this.hasEventListener("filestart")&&this.dispatchEvent(b)},a.toString=function(){return"[PreloadJS LoadQueue]"},createjs.LoadQueue=createjs.promote(LoadQueue,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function TextLoader(a){this.AbstractLoader_constructor(a,!0,createjs.AbstractLoader.TEXT)}var a=(createjs.extend(TextLoader,createjs.AbstractLoader),TextLoader);a.canLoadItem=function(a){return a.type==createjs.AbstractLoader.TEXT},createjs.TextLoader=createjs.promote(TextLoader,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function BinaryLoader(a){this.AbstractLoader_constructor(a,!0,createjs.AbstractLoader.BINARY),this.on("initialize",this._updateXHR,this)}var a=createjs.extend(BinaryLoader,createjs.AbstractLoader),b=BinaryLoader;b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.BINARY},a._updateXHR=function(a){a.loader.setResponseType("arraybuffer")},createjs.BinaryLoader=createjs.promote(BinaryLoader,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function CSSLoader(a,b){this.AbstractLoader_constructor(a,b,createjs.AbstractLoader.CSS),this.resultFormatter=this._formatResult,this._tagSrcAttribute="href",this._tag=document.createElement(b?"style":"link"),this._tag.rel="stylesheet",this._tag.type="text/css"}var a=createjs.extend(CSSLoader,createjs.AbstractLoader),b=CSSLoader;b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.CSS},a._formatResult=function(a){if(this._preferXHR){var b=a.getTag();if(b.styleSheet)b.styleSheet.cssText=a.getResult(!0);else{var c=document.createTextNode(a.getResult(!0));b.appendChild(c)}}else b=this._tag;return createjs.DomUtils.appendToHead(b),b},createjs.CSSLoader=createjs.promote(CSSLoader,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function ImageLoader(a,b){this.AbstractLoader_constructor(a,b,createjs.AbstractLoader.IMAGE),this.resultFormatter=this._formatResult,this._tagSrcAttribute="src",createjs.RequestUtils.isImageTag(a)?this._tag=a:createjs.RequestUtils.isImageTag(a.src)?this._tag=a.src:createjs.RequestUtils.isImageTag(a.tag)&&(this._tag=a.tag),null!=this._tag?this._preferXHR=!1:this._tag=document.createElement("img"),this.on("initialize",this._updateXHR,this)}var a=createjs.extend(ImageLoader,createjs.AbstractLoader),b=ImageLoader;b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.IMAGE},a.load=function(){if(""!=this._tag.src&&this._tag.complete)return void this._sendComplete();var a=this._item.crossOrigin;1==a&&(a="Anonymous"),null==a||createjs.RequestUtils.isLocal(this._item.src)||(this._tag.crossOrigin=a),this.AbstractLoader_load()},a._updateXHR=function(a){a.loader.mimeType="text/plain; charset=x-user-defined-binary",a.loader.setResponseType&&a.loader.setResponseType("blob")},a._formatResult=function(){return this._formatImage},a._formatImage=function(a,b){var c=this._tag,d=window.URL||window.webkitURL;if(this._preferXHR)if(d){var e=d.createObjectURL(this.getResult(!0));c.src=e,c.addEventListener("load",this._cleanUpURL,!1),c.addEventListener("error",this._cleanUpURL,!1)}else c.src=loader.getItem().src;else;c.complete?a(c):(c.addEventListener("load",createjs.proxy(function(){a(this._tag)},this),!1),c.addEventListener("error",createjs.proxy(function(){b(this._tag)},this),!1))},a._cleanUpURL=function(a){var b=window.URL||window.webkitURL;b.revokeObjectURL(a.target.src)},createjs.ImageLoader=createjs.promote(ImageLoader,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function JavaScriptLoader(a,b){this.AbstractLoader_constructor(a,b,createjs.AbstractLoader.JAVASCRIPT),this.resultFormatter=this._formatResult,this._tagSrcAttribute="src",this.setTag(document.createElement("script"))}var a=createjs.extend(JavaScriptLoader,createjs.AbstractLoader),b=JavaScriptLoader;b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.JAVASCRIPT},a._formatResult=function(a){var b=a.getTag();return this._preferXHR&&(b.text=a.getResult(!0)),b},createjs.JavaScriptLoader=createjs.promote(JavaScriptLoader,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function JSONLoader(a){this.AbstractLoader_constructor(a,!0,createjs.AbstractLoader.JSON),this.resultFormatter=this._formatResult}var a=createjs.extend(JSONLoader,createjs.AbstractLoader),b=JSONLoader;b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.JSON},a._formatResult=function(a){var b=null;try{b=createjs.DataUtils.parseJSON(a.getResult(!0))}catch(c){var d=new createjs.ErrorEvent("JSON_FORMAT",null,c);return this._sendError(d),c}return b},createjs.JSONLoader=createjs.promote(JSONLoader,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function JSONPLoader(a){this.AbstractLoader_constructor(a,!1,createjs.AbstractLoader.JSONP),this.setTag(document.createElement("script")),this.getTag().type="text/javascript"}var a=createjs.extend(JSONPLoader,createjs.AbstractLoader),b=JSONPLoader;b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.JSONP},a.cancel=function(){this.AbstractLoader_cancel(),this._dispose()},a.load=function(){if(null==this._item.callback)throw new Error("callback is required for loading JSONP requests.");if(null!=window[this._item.callback])throw new Error("JSONP callback '"+this._item.callback+"' already exists on window. You need to specify a different callback or re-name the current one.");window[this._item.callback]=createjs.proxy(this._handleLoad,this),window.document.body.appendChild(this._tag),this._loadTimeout=setTimeout(createjs.proxy(this._handleTimeout,this),this._item.loadTimeout),this._tag.src=this._item.src},a._handleLoad=function(a){this._result=this._rawResult=a,this._sendComplete(),this._dispose()},a._handleTimeout=function(){this._dispose(),this.dispatchEvent(new createjs.ErrorEvent("timeout"))},a._dispose=function(){window.document.body.removeChild(this._tag),delete window[this._item.callback],clearTimeout(this._loadTimeout)},createjs.JSONPLoader=createjs.promote(JSONPLoader,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function ManifestLoader(a){this.AbstractLoader_constructor(a,null,createjs.AbstractLoader.MANIFEST),this.plugins=null,this._manifestQueue=null}var a=createjs.extend(ManifestLoader,createjs.AbstractLoader),b=ManifestLoader;b.MANIFEST_PROGRESS=.25,b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.MANIFEST},a.load=function(){this.AbstractLoader_load()},a._createRequest=function(){var a=this._item.callback;this._request=null!=a?new createjs.JSONPLoader(this._item):new createjs.JSONLoader(this._item)},a.handleEvent=function(a){switch(a.type){case"complete":return this._rawResult=a.target.getResult(!0),this._result=a.target.getResult(),this._sendProgress(b.MANIFEST_PROGRESS),void this._loadManifest(this._result);case"progress":return a.loaded*=b.MANIFEST_PROGRESS,this.progress=a.loaded/a.total,(isNaN(this.progress)||1/0==this.progress)&&(this.progress=0),void this._sendProgress(a)}this.AbstractLoader_handleEvent(a)},a.destroy=function(){this.AbstractLoader_destroy(),this._manifestQueue.close()},a._loadManifest=function(a){if(a&&a.manifest){var b=this._manifestQueue=new createjs.LoadQueue;b.on("fileload",this._handleManifestFileLoad,this),b.on("progress",this._handleManifestProgress,this),b.on("complete",this._handleManifestComplete,this,!0),b.on("error",this._handleManifestError,this,!0);for(var c=0,d=this.plugins.length;d>c;c++)b.installPlugin(this.plugins[c]);b.loadManifest(a)}else this._sendComplete()},a._handleManifestFileLoad=function(a){a.target=null,this.dispatchEvent(a)},a._handleManifestComplete=function(){this._loadedItems=this._manifestQueue.getItems(!0),this._sendComplete()},a._handleManifestProgress=function(a){this.progress=a.progress*(1-b.MANIFEST_PROGRESS)+b.MANIFEST_PROGRESS,this._sendProgress(this.progress)},a._handleManifestError=function(a){var b=new createjs.Event("fileerror");b.item=a.data,this.dispatchEvent(b)},createjs.ManifestLoader=createjs.promote(ManifestLoader,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function SoundLoader(a,b){this.AbstractMediaLoader_constructor(a,b,createjs.AbstractLoader.SOUND),createjs.RequestUtils.isAudioTag(a)?this._tag=a:createjs.RequestUtils.isAudioTag(a.src)?this._tag=a:createjs.RequestUtils.isAudioTag(a.tag)&&(this._tag=createjs.RequestUtils.isAudioTag(a)?a:a.src),null!=this._tag&&(this._preferXHR=!1)}var a=createjs.extend(SoundLoader,createjs.AbstractMediaLoader),b=SoundLoader;b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.SOUND},a._createTag=function(a){var b=document.createElement("audio");return b.autoplay=!1,b.preload="none",b.src=a,b},createjs.SoundLoader=createjs.promote(SoundLoader,"AbstractMediaLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function VideoLoader(a,b){this.AbstractMediaLoader_constructor(a,b,createjs.AbstractLoader.VIDEO),createjs.RequestUtils.isVideoTag(a)||createjs.RequestUtils.isVideoTag(a.src)?(this.setTag(createjs.RequestUtils.isVideoTag(a)?a:a.src),this._preferXHR=!1):this.setTag(this._createTag())}var a=createjs.extend(VideoLoader,createjs.AbstractMediaLoader),b=VideoLoader;a._createTag=function(){return document.createElement("video")},b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.VIDEO},createjs.VideoLoader=createjs.promote(VideoLoader,"AbstractMediaLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function SpriteSheetLoader(a,b){this.AbstractLoader_constructor(a,b,createjs.AbstractLoader.SPRITESHEET),this._manifestQueue=null}var a=createjs.extend(SpriteSheetLoader,createjs.AbstractLoader),b=SpriteSheetLoader;b.SPRITESHEET_PROGRESS=.25,b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.SPRITESHEET},a.destroy=function(){this.AbstractLoader_destroy,this._manifestQueue.close()},a._createRequest=function(){var a=this._item.callback;this._request=null!=a?new createjs.JSONPLoader(this._item):new createjs.JSONLoader(this._item)},a.handleEvent=function(a){switch(a.type){case"complete":return this._rawResult=a.target.getResult(!0),this._result=a.target.getResult(),this._sendProgress(b.SPRITESHEET_PROGRESS),void this._loadManifest(this._result);case"progress":return a.loaded*=b.SPRITESHEET_PROGRESS,this.progress=a.loaded/a.total,(isNaN(this.progress)||1/0==this.progress)&&(this.progress=0),void this._sendProgress(a)}this.AbstractLoader_handleEvent(a)},a._loadManifest=function(a){if(a&&a.images){var b=this._manifestQueue=new createjs.LoadQueue(this._preferXHR,this._item.path,this._item.crossOrigin);b.on("complete",this._handleManifestComplete,this,!0),b.on("fileload",this._handleManifestFileLoad,this),b.on("progress",this._handleManifestProgress,this),b.on("error",this._handleManifestError,this,!0),b.loadManifest(a.images)}},a._handleManifestFileLoad=function(a){var b=a.result;if(null!=b){var c=this.getResult().images,d=c.indexOf(a.item.src);c[d]=b}},a._handleManifestComplete=function(){this._result=new createjs.SpriteSheet(this._result),this._loadedItems=this._manifestQueue.getItems(!0),this._sendComplete()},a._handleManifestProgress=function(a){this.progress=a.progress*(1-b.SPRITESHEET_PROGRESS)+b.SPRITESHEET_PROGRESS,this._sendProgress(this.progress)},a._handleManifestError=function(a){var b=new createjs.Event("fileerror");b.item=a.data,this.dispatchEvent(b)},createjs.SpriteSheetLoader=createjs.promote(SpriteSheetLoader,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function SVGLoader(a,b){this.AbstractLoader_constructor(a,b,createjs.AbstractLoader.SVG),this.resultFormatter=this._formatResult,this._tagSrcAttribute="data",b?this.setTag(document.createElement("svg")):(this.setTag(document.createElement("object")),this.getTag().type="image/svg+xml")}var a=createjs.extend(SVGLoader,createjs.AbstractLoader),b=SVGLoader;b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.SVG},a._formatResult=function(a){var b=createjs.DataUtils.parseXML(a.getResult(!0),"text/xml"),c=a.getTag();return!this._preferXHR&&document.body.contains(c)&&document.body.removeChild(c),null!=b.documentElement?(c.appendChild(b.documentElement),c.style.visibility="visible",c):b},createjs.SVGLoader=createjs.promote(SVGLoader,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function XMLLoader(a){this.AbstractLoader_constructor(a,!0,createjs.AbstractLoader.XML),this.resultFormatter=this._formatResult}var a=createjs.extend(XMLLoader,createjs.AbstractLoader),b=XMLLoader;b.canLoadItem=function(a){return a.type==createjs.AbstractLoader.XML},a._formatResult=function(a){return createjs.DataUtils.parseXML(a.getResult(!0),"text/xml")},createjs.XMLLoader=createjs.promote(XMLLoader,"AbstractLoader")}(); \ No newline at end of file +var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";var b=a.PreloadJS=a.PreloadJS||{};b.version="NEXT",b.buildDate="Wed, 02 Dec 2015 18:53:18 GMT"}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},scope.createjs.extend=function(a,b){"use strict";function c(){this.constructor=a}return c.prototype=b.prototype,a.prototype=new c};var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},scope.createjs.promote=function(a,b){"use strict";var c=a.prototype,d=Object.getPrototypeOf&&Object.getPrototypeOf(c)||c.__proto__;if(d){c[(b+="_")+"constructor"]=d.constructor;for(var e in d)c.hasOwnProperty(e)&&"function"==typeof d[e]&&(c[b+e]=d[e])}return a};var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";a.proxy=function(a,b){var c=Array.prototype.slice.call(arguments,2);return function(){return a.apply(b,Array.prototype.slice.call(arguments,0).concat(c))}}}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},scope.createjs.indexOf=function(a,b){"use strict";for(var c=0,d=a.length;d>c;c++)if(b===a[c])return c;return-1};var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function Event(a,b,c){this.type=a,this.target=null,this.currentTarget=null,this.eventPhase=0,this.bubbles=!!b,this.cancelable=!!c,this.timeStamp=(new Date).getTime(),this.defaultPrevented=!1,this.propagationStopped=!1,this.immediatePropagationStopped=!1,this.removed=!1}var b=Event.prototype;b.preventDefault=function(){this.defaultPrevented=this.cancelable&&!0},b.stopPropagation=function(){this.propagationStopped=!0},b.stopImmediatePropagation=function(){this.immediatePropagationStopped=this.propagationStopped=!0},b.remove=function(){this.removed=!0},b.clone=function(){return new Event(this.type,this.bubbles,this.cancelable)},b.set=function(a){for(var b in a)this[b]=a[b];return this},b.toString=function(){return"[Event (type="+this.type+")]"},a.Event=Event}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function ErrorEvent(a,b,c){this.Event_constructor("error"),this.title=a,this.message=b,this.data=c}var b=a.extend(ErrorEvent,a.Event);b.clone=function(){return new a.ErrorEvent(this.title,this.message,this.data)},a.ErrorEvent=a.promote(ErrorEvent,"Event")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function EventDispatcher(){this._listeners=null,this._captureListeners=null}var b=EventDispatcher.prototype;EventDispatcher.initialize=function(a){a.addEventListener=b.addEventListener,a.on=b.on,a.removeEventListener=a.off=b.removeEventListener,a.removeAllEventListeners=b.removeAllEventListeners,a.hasEventListener=b.hasEventListener,a.dispatchEvent=b.dispatchEvent,a._dispatchEvent=b._dispatchEvent,a.willTrigger=b.willTrigger},b.addEventListener=function(a,b,c){var d;d=c?this._captureListeners=this._captureListeners||{}:this._listeners=this._listeners||{};var e=d[a];return e&&this.removeEventListener(a,b,c),e=d[a],e?e.push(b):d[a]=[b],b},b.on=function(a,b,c,d,e,f){return b.handleEvent&&(c=c||b,b=b.handleEvent),c=c||this,this.addEventListener(a,function(a){b.call(c,a,e),d&&a.remove()},f)},b.removeEventListener=function(a,b,c){var d=c?this._captureListeners:this._listeners;if(d){var e=d[a];if(e)for(var f=0,g=e.length;g>f;f++)if(e[f]==b){1==g?delete d[a]:e.splice(f,1);break}}},b.off=b.removeEventListener,b.removeAllEventListeners=function(a){a?(this._listeners&&delete this._listeners[a],this._captureListeners&&delete this._captureListeners[a]):this._listeners=this._captureListeners=null},b.dispatchEvent=function(b){if("string"==typeof b){var c=this._listeners;if(!c||!c[b])return!1;b=new a.Event(b)}else b.target&&b.clone&&(b=b.clone());try{b.target=this}catch(d){}if(b.bubbles&&this.parent){for(var e=this,f=[e];e.parent;)f.push(e=e.parent);var g,h=f.length;for(g=h-1;g>=0&&!b.propagationStopped;g--)f[g]._dispatchEvent(b,1+(0==g));for(g=1;h>g&&!b.propagationStopped;g++)f[g]._dispatchEvent(b,3)}else this._dispatchEvent(b,2);return b.defaultPrevented},b.hasEventListener=function(a){var b=this._listeners,c=this._captureListeners;return!!(b&&b[a]||c&&c[a])},b.willTrigger=function(a){for(var b=this;b;){if(b.hasEventListener(a))return!0;b=b.parent}return!1},b.toString=function(){return"[EventDispatcher]"},b._dispatchEvent=function(a,b){var c,d=1==b?this._captureListeners:this._listeners;if(a&&d){var e=d[a.type];if(!e||!(c=e.length))return;try{a.currentTarget=this}catch(f){}try{a.eventPhase=b}catch(f){}a.removed=!1,e=e.slice();for(var g=0;c>g&&!a.immediatePropagationStopped;g++){var h=e[g];h.handleEvent?h.handleEvent(a):h(a),a.removed&&(this.off(a.type,h,1==b),a.removed=!1)}}},a.EventDispatcher=EventDispatcher}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function ProgressEvent(a,b){this.Event_constructor("progress"),this.loaded=a,this.total=null==b?1:b,this.progress=0==b?0:this.loaded/this.total}var b=a.extend(ProgressEvent,a.Event);b.clone=function(){return new a.ProgressEvent(this.loaded,this.total)},a.ProgressEvent=a.promote(ProgressEvent,"Event")}(scope.createjs),function(){function a(b,d){function f(a){if(f[a]!==q)return f[a];var b;if("bug-string-char-index"==a)b="a"!="a"[0];else if("json"==a)b=f("json-stringify")&&f("json-parse");else{var c,e='{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}';if("json-stringify"==a){var i=d.stringify,k="function"==typeof i&&t;if(k){(c=function(){return 1}).toJSON=c;try{k="0"===i(0)&&"0"===i(new g)&&'""'==i(new h)&&i(s)===q&&i(q)===q&&i()===q&&"1"===i(c)&&"[1]"==i([c])&&"[null]"==i([q])&&"null"==i(null)&&"[null,null,null]"==i([q,s,null])&&i({a:[c,!0,!1,null,"\x00\b\n\f\r "]})==e&&"1"===i(null,c)&&"[\n 1,\n 2\n]"==i([1,2],null,1)&&'"-271821-04-20T00:00:00.000Z"'==i(new j(-864e13))&&'"+275760-09-13T00:00:00.000Z"'==i(new j(864e13))&&'"-000001-01-01T00:00:00.000Z"'==i(new j(-621987552e5))&&'"1969-12-31T23:59:59.999Z"'==i(new j(-1))}catch(l){k=!1}}b=k}if("json-parse"==a){var m=d.parse;if("function"==typeof m)try{if(0===m("0")&&!m(!1)){c=m(e);var n=5==c.a.length&&1===c.a[0];if(n){try{n=!m('" "')}catch(l){}if(n)try{n=1!==m("01")}catch(l){}if(n)try{n=1!==m("1.")}catch(l){}}}}catch(l){n=!1}b=n}}return f[a]=!!b}b||(b=e.Object()),d||(d=e.Object());var g=b.Number||e.Number,h=b.String||e.String,i=b.Object||e.Object,j=b.Date||e.Date,k=b.SyntaxError||e.SyntaxError,l=b.TypeError||e.TypeError,m=b.Math||e.Math,n=b.JSON||e.JSON;"object"==typeof n&&n&&(d.stringify=n.stringify,d.parse=n.parse);var o,p,q,r=i.prototype,s=r.toString,t=new j(-0xc782b5b800cec);try{t=-109252==t.getUTCFullYear()&&0===t.getUTCMonth()&&1===t.getUTCDate()&&10==t.getUTCHours()&&37==t.getUTCMinutes()&&6==t.getUTCSeconds()&&708==t.getUTCMilliseconds()}catch(u){}if(!f("json")){var v="[object Function]",w="[object Date]",x="[object Number]",y="[object String]",z="[object Array]",A="[object Boolean]",B=f("bug-string-char-index");if(!t)var C=m.floor,D=[0,31,59,90,120,151,181,212,243,273,304,334],E=function(a,b){return D[b]+365*(a-1970)+C((a-1969+(b=+(b>1)))/4)-C((a-1901+b)/100)+C((a-1601+b)/400)};if((o=r.hasOwnProperty)||(o=function(a){var b,c={};return(c.__proto__=null,c.__proto__={toString:1},c).toString!=s?o=function(a){var b=this.__proto__,c=a in(this.__proto__=null,this);return this.__proto__=b,c}:(b=c.constructor,o=function(a){var c=(this.constructor||b).prototype;return a in this&&!(a in c&&this[a]===c[a])}),c=null,o.call(this,a)}),p=function(a,b){var d,e,f,g=0;(d=function(){this.valueOf=0}).prototype.valueOf=0,e=new d;for(f in e)o.call(e,f)&&g++;return d=e=null,g?p=2==g?function(a,b){var c,d={},e=s.call(a)==v;for(c in a)e&&"prototype"==c||o.call(d,c)||!(d[c]=1)||!o.call(a,c)||b(c)}:function(a,b){var c,d,e=s.call(a)==v;for(c in a)e&&"prototype"==c||!o.call(a,c)||(d="constructor"===c)||b(c);(d||o.call(a,c="constructor"))&&b(c)}:(e=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"],p=function(a,b){var d,f,g=s.call(a)==v,h=!g&&"function"!=typeof a.constructor&&c[typeof a.hasOwnProperty]&&a.hasOwnProperty||o;for(d in a)g&&"prototype"==d||!h.call(a,d)||b(d);for(f=e.length;d=e[--f];h.call(a,d)&&b(d));}),p(a,b)},!f("json-stringify")){var F={92:"\\\\",34:'\\"',8:"\\b",12:"\\f",10:"\\n",13:"\\r",9:"\\t"},G="000000",H=function(a,b){return(G+(b||0)).slice(-a)},I="\\u00",J=function(a){for(var b='"',c=0,d=a.length,e=!B||d>10,f=e&&(B?a.split(""):a);d>c;c++){var g=a.charCodeAt(c);switch(g){case 8:case 9:case 10:case 12:case 13:case 34:case 92:b+=F[g];break;default:if(32>g){b+=I+H(2,g.toString(16));break}b+=e?f[c]:a.charAt(c)}}return b+'"'},K=function(a,b,c,d,e,f,g){var h,i,j,k,m,n,r,t,u,v,B,D,F,G,I,L;try{h=b[a]}catch(M){}if("object"==typeof h&&h)if(i=s.call(h),i!=w||o.call(h,"toJSON"))"function"==typeof h.toJSON&&(i!=x&&i!=y&&i!=z||o.call(h,"toJSON"))&&(h=h.toJSON(a));else if(h>-1/0&&1/0>h){if(E){for(m=C(h/864e5),j=C(m/365.2425)+1970-1;E(j+1,0)<=m;j++);for(k=C((m-E(j,0))/30.42);E(j,k+1)<=m;k++);m=1+m-E(j,k),n=(h%864e5+864e5)%864e5,r=C(n/36e5)%24,t=C(n/6e4)%60,u=C(n/1e3)%60,v=n%1e3}else j=h.getUTCFullYear(),k=h.getUTCMonth(),m=h.getUTCDate(),r=h.getUTCHours(),t=h.getUTCMinutes(),u=h.getUTCSeconds(),v=h.getUTCMilliseconds();h=(0>=j||j>=1e4?(0>j?"-":"+")+H(6,0>j?-j:j):H(4,j))+"-"+H(2,k+1)+"-"+H(2,m)+"T"+H(2,r)+":"+H(2,t)+":"+H(2,u)+"."+H(3,v)+"Z"}else h=null;if(c&&(h=c.call(b,a,h)),null===h)return"null";if(i=s.call(h),i==A)return""+h;if(i==x)return h>-1/0&&1/0>h?""+h:"null";if(i==y)return J(""+h);if("object"==typeof h){for(G=g.length;G--;)if(g[G]===h)throw l();if(g.push(h),B=[],I=f,f+=e,i==z){for(F=0,G=h.length;G>F;F++)D=K(F,h,c,d,e,f,g),B.push(D===q?"null":D);L=B.length?e?"[\n"+f+B.join(",\n"+f)+"\n"+I+"]":"["+B.join(",")+"]":"[]"}else p(d||h,function(a){var b=K(a,h,c,d,e,f,g);b!==q&&B.push(J(a)+":"+(e?" ":"")+b)}),L=B.length?e?"{\n"+f+B.join(",\n"+f)+"\n"+I+"}":"{"+B.join(",")+"}":"{}";return g.pop(),L}};d.stringify=function(a,b,d){var e,f,g,h;if(c[typeof b]&&b)if((h=s.call(b))==v)f=b;else if(h==z){g={};for(var i,j=0,k=b.length;k>j;i=b[j++],h=s.call(i),(h==y||h==x)&&(g[i]=1));}if(d)if((h=s.call(d))==x){if((d-=d%1)>0)for(e="",d>10&&(d=10);e.lengthL;)switch(e=f.charCodeAt(L)){case 9:case 10:case 13:case 32:L++;break;case 123:case 125:case 91:case 93:case 58:case 44:return a=B?f.charAt(L):f[L],L++,a;case 34:for(a="@",L++;g>L;)if(e=f.charCodeAt(L),32>e)P();else if(92==e)switch(e=f.charCodeAt(++L)){case 92:case 34:case 47:case 98:case 116:case 110:case 102:case 114:a+=O[e],L++;break;case 117:for(b=++L,c=L+4;c>L;L++)e=f.charCodeAt(L),e>=48&&57>=e||e>=97&&102>=e||e>=65&&70>=e||P();a+=N("0x"+f.slice(b,L));break;default:P()}else{if(34==e)break;for(e=f.charCodeAt(L),b=L;e>=32&&92!=e&&34!=e;)e=f.charCodeAt(++L);a+=f.slice(b,L)}if(34==f.charCodeAt(L))return L++,a;P();default:if(b=L,45==e&&(d=!0,e=f.charCodeAt(++L)),e>=48&&57>=e){for(48==e&&(e=f.charCodeAt(L+1),e>=48&&57>=e)&&P(),d=!1;g>L&&(e=f.charCodeAt(L),e>=48&&57>=e);L++);if(46==f.charCodeAt(L)){for(c=++L;g>c&&(e=f.charCodeAt(c),e>=48&&57>=e);c++);c==L&&P(),L=c}if(e=f.charCodeAt(L),101==e||69==e){for(e=f.charCodeAt(++L),(43==e||45==e)&&L++,c=L;g>c&&(e=f.charCodeAt(c),e>=48&&57>=e);c++);c==L&&P(),L=c}return+f.slice(b,L)}if(d&&P(),"true"==f.slice(L,L+4))return L+=4,!0;if("false"==f.slice(L,L+5))return L+=5,!1;if("null"==f.slice(L,L+4))return L+=4,null;P()}return"$"},R=function(a){var b,c;if("$"==a&&P(),"string"==typeof a){if("@"==(B?a.charAt(0):a[0]))return a.slice(1);if("["==a){for(b=[];a=Q(),"]"!=a;c||(c=!0))c&&(","==a?(a=Q(),"]"==a&&P()):P()),","==a&&P(),b.push(R(a));return b}if("{"==a){for(b={};a=Q(),"}"!=a;c||(c=!0))c&&(","==a?(a=Q(),"}"==a&&P()):P()),(","==a||"string"!=typeof a||"@"!=(B?a.charAt(0):a[0])||":"!=Q())&&P(),b[a.slice(1)]=R(Q());return b}P()}return a},S=function(a,b,c){var d=T(a,b,c);d===q?delete a[b]:a[b]=d},T=function(a,b,c){var d,e=a[b];if("object"==typeof e&&e)if(s.call(e)==z)for(d=e.length;d--;)S(e,d,c);else p(e,function(a){S(e,a,c)});return c.call(a,b,e)};d.parse=function(a,b){var c,d;return L=0,M=""+a,c=R(Q()),"$"!=Q()&&P(),L=M=null,b&&s.call(b)==v?T((d={},d[""]=c,d),"",b):c}}}return d.runInContext=a,d}var b="function"==typeof define&&define.amd,c={"function":!0,object:!0},d=c[typeof exports]&&exports&&!exports.nodeType&&exports,e=c[typeof window]&&window||this,f=d&&c[typeof module]&&module&&!module.nodeType&&"object"==typeof global&&global;if(!f||f.global!==f&&f.window!==f&&f.self!==f||(e=f),d&&!b)a(e,d);else{var g=e.JSON,h=e.JSON3,i=!1,j=a(e,e.JSON3={noConflict:function(){return i||(i=!0,e.JSON=g,e.JSON3=h,g=h=null),j}});e.JSON={parse:j.parse,stringify:j.stringify}}b&&define(function(){return j})}.call(this);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){var b={};b.appendToHead=function(a){b.getHead().appendChild(a)},b.getHead=function(){return document.head||document.getElementsByTagName("head")[0]},b.getBody=function(){return document.body||document.getElementsByTagName("body")[0]},a.DomUtils=b}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){var b={};b.parseXML=function(a,b){var c=null;try{if(window.DOMParser){var d=new DOMParser;c=d.parseFromString(a,b)}}catch(e){}if(!c)try{c=new ActiveXObject("Microsoft.XMLDOM"),c.async=!1,c.loadXML(a)}catch(e){c=null}return c},b.parseJSON=function(a){if(null==a)return null;try{return JSON.parse(a)}catch(b){throw b}},a.DataUtils=b}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function LoadItem(){this.src=null,this.type=null,this.id=null,this.maintainOrder=!1,this.callback=null,this.data=null,this.method=a.LoadItem.GET,this.values=null,this.headers=null,this.withCredentials=!1,this.mimeType=null,this.crossOrigin=null,this.loadTimeout=c.LOAD_TIMEOUT_DEFAULT}var b=LoadItem.prototype={},c=LoadItem;c.LOAD_TIMEOUT_DEFAULT=8e3,c.create=function(a){if("string"==typeof a){var b=new LoadItem;return b.src=a,b}if(a instanceof c)return a;if(a instanceof Object&&a.src)return null==a.loadTimeout&&(a.loadTimeout=c.LOAD_TIMEOUT_DEFAULT),a;throw new Error("Type not recognized.")},b.set=function(a){for(var b in a)this[b]=a[b];return this},a.LoadItem=c}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){var b={};b.ABSOLUTE_PATT=/^(?:\w+:)?\/{2}/i,b.RELATIVE_PATT=/^[.\/]*?\//i,b.EXTENSION_PATT=/\/?[^\/]+\.(\w{1,5})$/i,b.parseURI=function(a){var c={absolute:!1,relative:!1};if(null==a)return c;var d=a.indexOf("?");d>-1&&(a=a.substr(0,d));var e;return b.ABSOLUTE_PATT.test(a)?c.absolute=!0:b.RELATIVE_PATT.test(a)&&(c.relative=!0),(e=a.match(b.EXTENSION_PATT))&&(c.extension=e[1].toLowerCase()),c},b.formatQueryString=function(a,b){if(null==a)throw new Error("You must specify data.");var c=[];for(var d in a)c.push(d+"="+escape(a[d]));return b&&(c=c.concat(b)),c.join("&")},b.buildPath=function(a,b){if(null==b)return a;var c=[],d=a.indexOf("?");if(-1!=d){var e=a.slice(d+1);c=c.concat(e.split("&"))}return-1!=d?a.slice(0,d)+"?"+this._formatQueryString(b,c):a+"?"+this._formatQueryString(b,c)},b.isCrossDomain=function(a){var b=document.createElement("a");b.href=a.src;var c=document.createElement("a");c.href=location.href;var d=""!=b.hostname&&(b.port!=c.port||b.protocol!=c.protocol||b.hostname!=c.hostname);return d},b.isLocal=function(a){var b=document.createElement("a");return b.href=a.src,""==b.hostname&&"file:"==b.protocol},b.isBinary=function(b){switch(b){case a.AbstractLoader.IMAGE:case a.AbstractLoader.BINARY:return!0;default:return!1}},b.isImageTag=function(a){return a instanceof HTMLImageElement},b.isAudioTag=function(a){return window.HTMLAudioElement?a instanceof HTMLAudioElement:!1},b.isVideoTag=function(a){return window.HTMLVideoElement?a instanceof HTMLVideoElement:!1},b.isText=function(b){switch(b){case a.AbstractLoader.TEXT:case a.AbstractLoader.JSON:case a.AbstractLoader.MANIFEST:case a.AbstractLoader.XML:case a.AbstractLoader.CSS:case a.AbstractLoader.SVG:case a.AbstractLoader.JAVASCRIPT:case a.AbstractLoader.SPRITESHEET:return!0;default:return!1}},b.getTypeByExtension=function(b){if(null==b)return a.AbstractLoader.TEXT;switch(b.toLowerCase()){case"jpeg":case"jpg":case"gif":case"png":case"webp":case"bmp":return a.AbstractLoader.IMAGE;case"ogg":case"mp3":case"webm":return a.AbstractLoader.SOUND;case"mp4":case"webm":case"ts":return a.AbstractLoader.VIDEO;case"json":return a.AbstractLoader.JSON;case"xml":return a.AbstractLoader.XML;case"css":return a.AbstractLoader.CSS;case"js":return a.AbstractLoader.JAVASCRIPT;case"svg":return a.AbstractLoader.SVG;default:return a.AbstractLoader.TEXT}},a.RequestUtils=b}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function AbstractLoader(b,c,d){this.EventDispatcher_constructor(),this.loaded=!1,this.canceled=!1,this.progress=0,this.type=d,this.resultFormatter=null,this._item=b?a.LoadItem.create(b):null,this._preferXHR=c,this._result=null,this._rawResult=null,this._loadedItems=null,this._tagSrcAttribute=null,this._tag=null}var b=a.extend(AbstractLoader,a.EventDispatcher),c=AbstractLoader;c.POST="POST",c.GET="GET",c.BINARY="binary",c.CSS="css",c.IMAGE="image",c.JAVASCRIPT="javascript",c.JSON="json",c.JSONP="jsonp",c.MANIFEST="manifest",c.SOUND="sound",c.VIDEO="video",c.SPRITESHEET="spritesheet",c.SVG="svg",c.TEXT="text",c.XML="xml",b.getItem=function(){return this._item},b.getResult=function(a){return a?this._rawResult:this._result},b.getTag=function(){return this._tag},b.setTag=function(a){this._tag=a},b.load=function(){this._createRequest(),this._request.on("complete",this,this),this._request.on("progress",this,this),this._request.on("loadStart",this,this),this._request.on("abort",this,this),this._request.on("timeout",this,this),this._request.on("error",this,this);var b=new a.Event("initialize");b.loader=this._request,this.dispatchEvent(b),this._request.load()},b.cancel=function(){this.canceled=!0,this.destroy()},b.destroy=function(){this._request&&(this._request.removeAllEventListeners(),this._request.destroy()),this._request=null,this._item=null,this._rawResult=null,this._result=null,this._loadItems=null,this.removeAllEventListeners()},b.getLoadedItems=function(){return this._loadedItems},b._createRequest=function(){this._request=this._preferXHR?new a.XHRRequest(this._item):new a.TagRequest(this._item,this._tag||this._createTag(),this._tagSrcAttribute)},b._createTag=function(){return null},b._sendLoadStart=function(){this._isCanceled()||this.dispatchEvent("loadstart")},b._sendProgress=function(b){if(!this._isCanceled()){var c=null;"number"==typeof b?(this.progress=b,c=new a.ProgressEvent(this.progress)):(c=b,this.progress=b.loaded/b.total,c.progress=this.progress,(isNaN(this.progress)||1/0==this.progress)&&(this.progress=0)),this.hasEventListener("progress")&&this.dispatchEvent(c)}},b._sendComplete=function(){if(!this._isCanceled()){this.loaded=!0;var b=new a.Event("complete");b.rawResult=this._rawResult,null!=this._result&&(b.result=this._result),this.dispatchEvent(b)}},b._sendError=function(b){!this._isCanceled()&&this.hasEventListener("error")&&(null==b&&(b=new a.ErrorEvent("PRELOAD_ERROR_EMPTY")),this.dispatchEvent(b))},b._isCanceled=function(){return null==window.createjs||this.canceled?!0:!1},b.resultFormatter=null,b.handleEvent=function(b){switch(b.type){case"complete":this._rawResult=b.target._response;var c=this.resultFormatter&&this.resultFormatter(this);c instanceof Function?c.call(this,a.proxy(this._resultFormatSuccess,this),a.proxy(this._resultFormatFailed,this)):(this._result=c||this._rawResult,this._sendComplete());break;case"progress":this._sendProgress(b);break;case"error":this._sendError(b);break;case"loadstart":this._sendLoadStart();break;case"abort":case"timeout":this._isCanceled()||this.dispatchEvent(new a.ErrorEvent("PRELOAD_"+b.type.toUpperCase()+"_ERROR"))}},b._resultFormatSuccess=function(a){this._result=a,this._sendComplete()},b._resultFormatFailed=function(a){this._sendError(a)},b.buildPath=function(b,c){return a.RequestUtils.buildPath(b,c)},b.toString=function(){return"[PreloadJS AbstractLoader]"},a.AbstractLoader=a.promote(AbstractLoader,"EventDispatcher")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function AbstractMediaLoader(a,b,c){this.AbstractLoader_constructor(a,b,c),this.resultFormatter=this._formatResult,this._tagSrcAttribute="src",this.on("initialize",this._updateXHR,this)}var b=a.extend(AbstractMediaLoader,a.AbstractLoader);b.load=function(){this._tag||(this._tag=this._createTag(this._item.src)),this._tag.preload="auto",this._tag.load(),this.AbstractLoader_load()},b._createTag=function(){},b._createRequest=function(){this._request=this._preferXHR?new a.XHRRequest(this._item):new a.MediaTagRequest(this._item,this._tag||this._createTag(),this._tagSrcAttribute)},b._updateXHR=function(a){a.loader.setResponseType&&a.loader.setResponseType("blob")},b._formatResult=function(a){if(this._tag.removeEventListener&&this._tag.removeEventListener("canplaythrough",this._loadedHandler),this._tag.onstalled=null,this._preferXHR){var b=window.URL||window.webkitURL,c=a.getResult(!0);a.getTag().src=b.createObjectURL(c)}return a.getTag()},a.AbstractMediaLoader=a.promote(AbstractMediaLoader,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";var AbstractRequest=function(a){this._item=a},b=a.extend(AbstractRequest,a.EventDispatcher);b.load=function(){},b.destroy=function(){},b.cancel=function(){},a.AbstractRequest=a.promote(AbstractRequest,"EventDispatcher")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function TagRequest(b,c,d){this.AbstractRequest_constructor(b),this._tag=c,this._tagSrcAttribute=d,this._loadedHandler=a.proxy(this._handleTagComplete,this),this._addedToDOM=!1,this._startTagVisibility=null}var b=a.extend(TagRequest,a.AbstractRequest);b.load=function(){this._tag.onload=a.proxy(this._handleTagComplete,this),this._tag.onreadystatechange=a.proxy(this._handleReadyStateChange,this),this._tag.onerror=a.proxy(this._handleError,this);var b=new a.Event("initialize");b.loader=this._tag,this.dispatchEvent(b),this._hideTag(),this._loadTimeout=setTimeout(a.proxy(this._handleTimeout,this),this._item.loadTimeout),this._tag[this._tagSrcAttribute]=this._item.src,null==this._tag.parentNode&&(window.document.body.appendChild(this._tag),this._addedToDOM=!0)},b.destroy=function(){this._clean(),this._tag=null,this.AbstractRequest_destroy()},b._handleReadyStateChange=function(){clearTimeout(this._loadTimeout);var a=this._tag;("loaded"==a.readyState||"complete"==a.readyState)&&this._handleTagComplete()},b._handleError=function(){this._clean(),this.dispatchEvent("error")},b._handleTagComplete=function(){this._rawResult=this._tag,this._result=this.resultFormatter&&this.resultFormatter(this)||this._rawResult,this._clean(),this._showTag(),this.dispatchEvent("complete")},b._handleTimeout=function(){this._clean(),this.dispatchEvent(new a.Event("timeout"))},b._clean=function(){this._tag.onload=null,this._tag.onreadystatechange=null,this._tag.onerror=null,this._addedToDOM&&null!=this._tag.parentNode&&this._tag.parentNode.removeChild(this._tag),clearTimeout(this._loadTimeout)},b._hideTag=function(){this._startTagVisibility=this._tag.style.visibility,this._tag.style.visibility="hidden"},b._showTag=function(){this._tag.style.visibility=this._startTagVisibility},b._handleStalled=function(){},a.TagRequest=a.promote(TagRequest,"AbstractRequest")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function MediaTagRequest(b,c,d){this.AbstractRequest_constructor(b),this._tag=c,this._tagSrcAttribute=d,this._loadedHandler=a.proxy(this._handleTagComplete,this)}var b=a.extend(MediaTagRequest,a.TagRequest);b.load=function(){var b=a.proxy(this._handleStalled,this);this._stalledCallback=b;var c=a.proxy(this._handleProgress,this);this._handleProgress=c,this._tag.addEventListener("stalled",b),this._tag.addEventListener("progress",c),this._tag.addEventListener&&this._tag.addEventListener("canplaythrough",this._loadedHandler,!1),this.TagRequest_load()},b._handleReadyStateChange=function(){clearTimeout(this._loadTimeout);var a=this._tag;("loaded"==a.readyState||"complete"==a.readyState)&&this._handleTagComplete()},b._handleStalled=function(){},b._handleProgress=function(b){if(b&&!(b.loaded>0&&0==b.total)){var c=new a.ProgressEvent(b.loaded,b.total);this.dispatchEvent(c)}},b._clean=function(){this._tag.removeEventListener&&this._tag.removeEventListener("canplaythrough",this._loadedHandler),this._tag.removeEventListener("stalled",this._stalledCallback),this._tag.removeEventListener("progress",this._progressCallback),this.TagRequest__clean()},a.MediaTagRequest=a.promote(MediaTagRequest,"TagRequest")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function XHRRequest(b){this.AbstractRequest_constructor(b),this._request=null,this._loadTimeout=null,this._xhrLevel=1,this._response=null,this._rawResponse=null,this._canceled=!1,this._handleLoadStartProxy=a.proxy(this._handleLoadStart,this),this._handleProgressProxy=a.proxy(this._handleProgress,this),this._handleAbortProxy=a.proxy(this._handleAbort,this),this._handleErrorProxy=a.proxy(this._handleError,this),this._handleTimeoutProxy=a.proxy(this._handleTimeout,this),this._handleLoadProxy=a.proxy(this._handleLoad,this),this._handleReadyStateChangeProxy=a.proxy(this._handleReadyStateChange,this),!this._createXHR(b)}var b=a.extend(XHRRequest,a.AbstractRequest);XHRRequest.ACTIVEX_VERSIONS=["Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.5.0","Msxml2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],b.getResult=function(a){return a&&this._rawResponse?this._rawResponse:this._response},b.cancel=function(){this.canceled=!0,this._clean(),this._request.abort()},b.load=function(){if(null==this._request)return void this._handleError();null!=this._request.addEventListener?(this._request.addEventListener("loadstart",this._handleLoadStartProxy,!1),this._request.addEventListener("progress",this._handleProgressProxy,!1),this._request.addEventListener("abort",this._handleAbortProxy,!1),this._request.addEventListener("error",this._handleErrorProxy,!1),this._request.addEventListener("timeout",this._handleTimeoutProxy,!1),this._request.addEventListener("load",this._handleLoadProxy,!1),this._request.addEventListener("readystatechange",this._handleReadyStateChangeProxy,!1)):(this._request.onloadstart=this._handleLoadStartProxy,this._request.onprogress=this._handleProgressProxy,this._request.onabort=this._handleAbortProxy,this._request.onerror=this._handleErrorProxy,this._request.ontimeout=this._handleTimeoutProxy,this._request.onload=this._handleLoadProxy,this._request.onreadystatechange=this._handleReadyStateChangeProxy),1==this._xhrLevel&&(this._loadTimeout=setTimeout(a.proxy(this._handleTimeout,this),this._item.loadTimeout));try{this._item.values&&this._item.method!=a.AbstractLoader.GET?this._item.method==a.AbstractLoader.POST&&this._request.send(a.RequestUtils.formatQueryString(this._item.values)):this._request.send()}catch(b){this.dispatchEvent(new a.ErrorEvent("XHR_SEND",null,b))}},b.setResponseType=function(a){"blob"===a&&(a=window.URL?"blob":"arraybuffer",this._responseType=a),this._request.responseType=a},b.getAllResponseHeaders=function(){return this._request.getAllResponseHeaders instanceof Function?this._request.getAllResponseHeaders():null},b.getResponseHeader=function(a){return this._request.getResponseHeader instanceof Function?this._request.getResponseHeader(a):null},b._handleProgress=function(b){if(b&&!(b.loaded>0&&0==b.total)){var c=new a.ProgressEvent(b.loaded,b.total);this.dispatchEvent(c)}},b._handleLoadStart=function(){clearTimeout(this._loadTimeout),this.dispatchEvent("loadstart")},b._handleAbort=function(b){this._clean(),this.dispatchEvent(new a.ErrorEvent("XHR_ABORTED",null,b))},b._handleError=function(b){this._clean(),this.dispatchEvent(new a.ErrorEvent(b.message))},b._handleReadyStateChange=function(){4==this._request.readyState&&this._handleLoad()},b._handleLoad=function(){if(!this.loaded){this.loaded=!0;var b=this._checkError();if(b)return void this._handleError(b);if(this._response=this._getResponse(),"arraybuffer"===this._responseType)try{this._response=new Blob([this._response])}catch(c){if(window.BlobBuilder=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder||window.MSBlobBuilder,"TypeError"===c.name&&window.BlobBuilder){var d=new BlobBuilder;d.append(this._response),this._response=d.getBlob()}}this._clean(),this.dispatchEvent(new a.Event("complete"))}},b._handleTimeout=function(b){this._clean(),this.dispatchEvent(new a.ErrorEvent("PRELOAD_TIMEOUT",null,b))},b._checkError=function(){var a=parseInt(this._request.status);switch(a){case 404:case 0:return new Error(a)}return null},b._getResponse=function(){if(null!=this._response)return this._response;if(null!=this._request.response)return this._request.response;try{if(null!=this._request.responseText)return this._request.responseText}catch(a){}try{if(null!=this._request.responseXML)return this._request.responseXML}catch(a){}return null},b._createXHR=function(b){var c=a.RequestUtils.isCrossDomain(b),d={},e=null;if(window.XMLHttpRequest)e=new XMLHttpRequest,c&&void 0===e.withCredentials&&window.XDomainRequest&&(e=new XDomainRequest);else{for(var f=0,g=s.ACTIVEX_VERSIONS.length;g>f;f++){var h=s.ACTIVEX_VERSIONS[f];try{e=new ActiveXObject(h);break}catch(i){}}if(null==e)return!1}null==b.mimeType&&a.RequestUtils.isText(b.type)&&(b.mimeType="text/plain; charset=utf-8"),b.mimeType&&e.overrideMimeType&&e.overrideMimeType(b.mimeType),this._xhrLevel="string"==typeof e.responseType?2:1;var j=null;if(j=b.method==a.AbstractLoader.GET?a.RequestUtils.buildPath(b.src,b.values):b.src,e.open(b.method||a.AbstractLoader.GET,j,!0),c&&e instanceof XMLHttpRequest&&1==this._xhrLevel&&(d.Origin=location.origin),b.values&&b.method==a.AbstractLoader.POST&&(d["Content-Type"]="application/x-www-form-urlencoded"),c||d["X-Requested-With"]||(d["X-Requested-With"]="XMLHttpRequest"),b.headers)for(var k in b.headers)d[k]=b.headers[k];for(k in d)e.setRequestHeader(k,d[k]);return e instanceof XMLHttpRequest&&void 0!==b.withCredentials&&(e.withCredentials=b.withCredentials),this._request=e,!0},b._clean=function(){clearTimeout(this._loadTimeout),null!=this._request.removeEventListener?(this._request.removeEventListener("loadstart",this._handleLoadStartProxy),this._request.removeEventListener("progress",this._handleProgressProxy),this._request.removeEventListener("abort",this._handleAbortProxy),this._request.removeEventListener("error",this._handleErrorProxy),this._request.removeEventListener("timeout",this._handleTimeoutProxy),this._request.removeEventListener("load",this._handleLoadProxy),this._request.removeEventListener("readystatechange",this._handleReadyStateChangeProxy)):(this._request.onloadstart=null,this._request.onprogress=null,this._request.onabort=null,this._request.onerror=null,this._request.ontimeout=null,this._request.onload=null,this._request.onreadystatechange=null)},b.toString=function(){return"[PreloadJS XHRRequest]" +},a.XHRRequest=a.promote(XHRRequest,"AbstractRequest")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function LoadQueue(b,c,d){this.AbstractLoader_constructor(),this._plugins=[],this._typeCallbacks={},this._extensionCallbacks={},this.next=null,this.maintainScriptOrder=!0,this.stopOnError=!1,this._maxConnections=1,this._availableLoaders=[a.ImageLoader,a.JavaScriptLoader,a.CSSLoader,a.JSONLoader,a.JSONPLoader,a.SoundLoader,a.ManifestLoader,a.SpriteSheetLoader,a.XMLLoader,a.SVGLoader,a.BinaryLoader,a.VideoLoader,a.TextLoader],this._defaultLoaderLength=this._availableLoaders.length,this.init(b,c,d)}var b=a.extend(LoadQueue,a.AbstractLoader),c=LoadQueue;b.init=function(a,b,c){this.useXHR=!0,this.preferXHR=!0,this._preferXHR=!0,this.setPreferXHR(a),this._paused=!1,this._basePath=b,this._crossOrigin=c,this._loadStartWasDispatched=!1,this._currentlyLoadingScript=null,this._currentLoads=[],this._loadQueue=[],this._loadQueueBackup=[],this._loadItemsById={},this._loadItemsBySrc={},this._loadedResults={},this._loadedRawResults={},this._numItems=0,this._numItemsLoaded=0,this._scriptOrder=[],this._loadedScripts=[],this._lastProgress=0/0},c.loadTimeout=8e3,c.LOAD_TIMEOUT=0,c.BINARY=a.AbstractLoader.BINARY,c.CSS=a.AbstractLoader.CSS,c.IMAGE=a.AbstractLoader.IMAGE,c.JAVASCRIPT=a.AbstractLoader.JAVASCRIPT,c.JSON=a.AbstractLoader.JSON,c.JSONP=a.AbstractLoader.JSONP,c.MANIFEST=a.AbstractLoader.MANIFEST,c.SOUND=a.AbstractLoader.SOUND,c.VIDEO=a.AbstractLoader.VIDEO,c.SVG=a.AbstractLoader.SVG,c.TEXT=a.AbstractLoader.TEXT,c.XML=a.AbstractLoader.XML,c.POST=a.AbstractLoader.POST,c.GET=a.AbstractLoader.GET,b.registerLoader=function(a){if(!a||!a.canLoadItem)throw new Error("loader is of an incorrect type.");if(-1!=this._availableLoaders.indexOf(a))throw new Error("loader already exists.");this._availableLoaders.unshift(a)},b.unregisterLoader=function(a){var b=this._availableLoaders.indexOf(a);-1!=b&&b0)return;var c=!1;if(b){for(;b.length;){var d=b.pop(),e=this.getResult(d);for(f=this._loadQueue.length-1;f>=0;f--)if(g=this._loadQueue[f].getItem(),g.id==d||g.src==d){this._loadQueue.splice(f,1)[0].cancel();break}for(f=this._loadQueueBackup.length-1;f>=0;f--)if(g=this._loadQueueBackup[f].getItem(),g.id==d||g.src==d){this._loadQueueBackup.splice(f,1)[0].cancel();break}if(e)this._disposeItem(this.getItem(d));else for(var f=this._currentLoads.length-1;f>=0;f--){var g=this._currentLoads[f].getItem();if(g.id==d||g.src==d){this._currentLoads.splice(f,1)[0].cancel(),c=!0;break}}}c&&this._loadNext()}else{this.close();for(var h in this._loadItemsById)this._disposeItem(this._loadItemsById[h]);this.init(this.preferXHR,this._basePath)}},b.reset=function(){this.close();for(var a in this._loadItemsById)this._disposeItem(this._loadItemsById[a]);for(var b=[],c=0,d=this._loadQueueBackup.length;d>c;c++)b.push(this._loadQueueBackup[c].getItem());this.loadManifest(b,!1)},b.installPlugin=function(a){if(null!=a&&null!=a.getPreloadHandlers){this._plugins.push(a);var b=a.getPreloadHandlers();if(b.scope=a,null!=b.types)for(var c=0,d=b.types.length;d>c;c++)this._typeCallbacks[b.types[c]]=b;if(null!=b.extensions)for(c=0,d=b.extensions.length;d>c;c++)this._extensionCallbacks[b.extensions[c]]=b}},b.setMaxConnections=function(a){this._maxConnections=a,!this._paused&&this._loadQueue.length>0&&this._loadNext()},b.loadFile=function(b,c,d){if(null==b){var e=new a.ErrorEvent("PRELOAD_NO_FILE");return void this._sendError(e)}this._addItem(b,null,d),this.setPaused(c!==!1?!1:!0)},b.loadManifest=function(b,d,e){var f=null,g=null;if(Array.isArray(b)){if(0==b.length){var h=new a.ErrorEvent("PRELOAD_MANIFEST_EMPTY");return void this._sendError(h)}f=b}else if("string"==typeof b)f=[{src:b,type:c.MANIFEST}];else{if("object"!=typeof b){var h=new a.ErrorEvent("PRELOAD_MANIFEST_NULL");return void this._sendError(h)}if(void 0!==b.src){if(null==b.type)b.type=c.MANIFEST;else if(b.type!=c.MANIFEST){var h=new a.ErrorEvent("PRELOAD_MANIFEST_TYPE");this._sendError(h)}f=[b]}else void 0!==b.manifest&&(f=b.manifest,g=b.path)}for(var i=0,j=f.length;j>i;i++)this._addItem(f[i],g,e);this.setPaused(d!==!1?!1:!0)},b.load=function(){this.setPaused(!1)},b.getItem=function(a){return this._loadItemsById[a]||this._loadItemsBySrc[a]},b.getResult=function(a,b){var c=this._loadItemsById[a]||this._loadItemsBySrc[a];if(null==c)return null;var d=c.id;return b&&this._loadedRawResults[d]?this._loadedRawResults[d]:this._loadedResults[d]},b.getItems=function(a){var b=[];for(var c in this._loadItemsById){var d=this._loadItemsById[c],e=this.getResult(c);(a!==!0||null!=e)&&b.push({item:d,result:e,rawResult:this.getResult(c,!0)})}return b},b.setPaused=function(a){this._paused=a,this._paused||this._loadNext()},b.close=function(){for(;this._currentLoads.length;)this._currentLoads.pop().cancel();this._scriptOrder.length=0,this._loadedScripts.length=0,this.loadStartWasDispatched=!1,this._itemCount=0,this._lastProgress=0/0},b._addItem=function(b,c,d){var e=this._createLoadItem(b,c,d);if(null!=e){var f=this._createLoader(e);null!=f&&("plugins"in f&&(f.plugins=this._plugins),e._loader=f,this._loadQueue.push(f),this._loadQueueBackup.push(f),this._numItems++,this._updateProgress(),(this.maintainScriptOrder&&e.type==a.LoadQueue.JAVASCRIPT||e.maintainOrder===!0)&&(this._scriptOrder.push(e),this._loadedScripts.push(null)))}},b._createLoadItem=function(b,c,d){var e=a.LoadItem.create(b);if(null==e)return null;var f="",g=d||this._basePath;if(e.src instanceof Object){if(!e.type)return null;if(c){f=c;var h=a.RequestUtils.parseURI(c);null==g||h.absolute||h.relative||(f=g+f)}else null!=g&&(f=g)}else{var i=a.RequestUtils.parseURI(e.src);i.extension&&(e.ext=i.extension),null==e.type&&(e.type=a.RequestUtils.getTypeByExtension(e.ext));var j=e.src;if(!i.absolute&&!i.relative)if(c){f=c;var h=a.RequestUtils.parseURI(c);j=c+j,null==g||h.absolute||h.relative||(f=g+f)}else null!=g&&(f=g);e.src=f+e.src}e.path=f,(void 0===e.id||null===e.id||""===e.id)&&(e.id=j);var k=this._typeCallbacks[e.type]||this._extensionCallbacks[e.ext];if(k){var l=k.callback.call(k.scope,e,this);if(l===!1)return null;l===!0||null!=l&&(e._loader=l),i=a.RequestUtils.parseURI(e.src),null!=i.extension&&(e.ext=i.extension)}return this._loadItemsById[e.id]=e,this._loadItemsBySrc[e.src]=e,null==e.crossOrigin&&(e.crossOrigin=this._crossOrigin),e},b._createLoader=function(a){if(null!=a._loader)return a._loader;for(var b=this.preferXHR,c=0;c=this._maxConnections);a++){var b=this._loadQueue[a];this._canStartLoad(b)&&(this._loadQueue.splice(a,1),a--,this._loadItem(b))}}},b._loadItem=function(a){a.on("fileload",this._handleFileLoad,this),a.on("progress",this._handleProgress,this),a.on("complete",this._handleFileComplete,this),a.on("error",this._handleError,this),a.on("fileerror",this._handleFileError,this),this._currentLoads.push(a),this._sendFileStart(a.getItem()),a.load()},b._handleFileLoad=function(a){a.target=null,this.dispatchEvent(a)},b._handleFileError=function(b){var c=new a.ErrorEvent("FILE_LOAD_ERROR",null,b.item);this._sendError(c)},b._handleError=function(b){var c=b.target;this._numItemsLoaded++,this._finishOrderedItem(c,!0),this._updateProgress();var d=new a.ErrorEvent("FILE_LOAD_ERROR",null,c.getItem());this._sendError(d),this.stopOnError?this.setPaused(!0):(this._removeLoadItem(c),this._cleanLoadItem(c),this._loadNext())},b._handleFileComplete=function(a){var b=a.target,c=b.getItem(),d=b.getResult();this._loadedResults[c.id]=d;var e=b.getResult(!0);null!=e&&e!==d&&(this._loadedRawResults[c.id]=e),this._saveLoadedItems(b),this._removeLoadItem(b),this._finishOrderedItem(b)||this._processFinishedLoad(c,b),this._cleanLoadItem(b)},b._saveLoadedItems=function(a){var b=a.getLoadedItems();if(null!==b)for(var c=0;cc;c++){var d=this._loadedScripts[c];if(null===d)break;if(d!==!0){var e=this._loadedResults[d.id];d.type==a.LoadQueue.JAVASCRIPT&&a.DomUtils.appendToHead(e);var f=d._loader;this._processFinishedLoad(d,f),this._loadedScripts[c]=!0}}},b._processFinishedLoad=function(b,c){if(this._numItemsLoaded++,!this.maintainScriptOrder&&b.type==a.LoadQueue.JAVASCRIPT){var d=c.getTag();a.DomUtils.appendToHead(d)}this._updateProgress(),this._sendFileComplete(b,c),this._loadNext()},b._canStartLoad=function(b){if(!this.maintainScriptOrder||b.preferXHR)return!0;var c=b.getItem();if(c.type!=a.LoadQueue.JAVASCRIPT)return!0;if(this._currentlyLoadingScript)return!1;for(var d=this._scriptOrder.indexOf(c),e=0;d>e;){var f=this._loadedScripts[e];if(null==f)return!1;e++}return this._currentlyLoadingScript=!0,!0},b._removeLoadItem=function(a){for(var b=this._currentLoads.length,c=0;b>c;c++)if(this._currentLoads[c]==a){this._currentLoads.splice(c,1);break}},b._cleanLoadItem=function(a){var b=a.getItem();b&&delete b._loader},b._handleProgress=function(a){var b=a.target;this._sendFileProgress(b.getItem(),b.progress),this._updateProgress()},b._updateProgress=function(){var a=this._numItemsLoaded/this._numItems,b=this._numItems-this._numItemsLoaded;if(b>0){for(var c=0,d=0,e=this._currentLoads.length;e>d;d++)c+=this._currentLoads[d].progress;a+=c/b*(b/this._numItems)}this._lastProgress!=a&&(this._sendProgress(a),this._lastProgress=a)},b._disposeItem=function(a){delete this._loadedResults[a.id],delete this._loadedRawResults[a.id],delete this._loadItemsById[a.id],delete this._loadItemsBySrc[a.src]},b._sendFileProgress=function(b,c){if(!this._isCanceled()&&!this._paused&&this.hasEventListener("fileprogress")){var d=new a.Event("fileprogress");d.progress=c,d.loaded=c,d.total=1,d.item=b,this.dispatchEvent(d)}},b._sendFileComplete=function(b,c){if(!this._isCanceled()&&!this._paused){var d=new a.Event("fileload");d.loader=c,d.item=b,d.result=this._loadedResults[b.id],d.rawResult=this._loadedRawResults[b.id],b.completeHandler&&b.completeHandler(d),this.hasEventListener("fileload")&&this.dispatchEvent(d)}},b._sendFileStart=function(b){var c=new a.Event("filestart");c.item=b,this.hasEventListener("filestart")&&this.dispatchEvent(c)},b.toString=function(){return"[PreloadJS LoadQueue]"},a.LoadQueue=a.promote(LoadQueue,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function TextLoader(b){this.AbstractLoader_constructor(b,!0,a.AbstractLoader.TEXT)}var b=(a.extend(TextLoader,a.AbstractLoader),TextLoader);b.canLoadItem=function(b){return b.type==a.AbstractLoader.TEXT},a.TextLoader=a.promote(TextLoader,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function BinaryLoader(b){this.AbstractLoader_constructor(b,!0,a.AbstractLoader.BINARY),this.on("initialize",this._updateXHR,this)}var b=a.extend(BinaryLoader,a.AbstractLoader),c=BinaryLoader;c.canLoadItem=function(b){return b.type==a.AbstractLoader.BINARY},b._updateXHR=function(a){a.loader.setResponseType("arraybuffer")},a.BinaryLoader=a.promote(BinaryLoader,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function CSSLoader(b,c){this.AbstractLoader_constructor(b,c,a.AbstractLoader.CSS),this.resultFormatter=this._formatResult,this._tagSrcAttribute="href",this._tag=document.createElement(c?"style":"link"),this._tag.rel="stylesheet",this._tag.type="text/css"}var b=a.extend(CSSLoader,a.AbstractLoader),c=CSSLoader;c.canLoadItem=function(b){return b.type==a.AbstractLoader.CSS},b._formatResult=function(b){if(this._preferXHR){var c=b.getTag();if(c.styleSheet)c.styleSheet.cssText=b.getResult(!0);else{var d=document.createTextNode(b.getResult(!0));c.appendChild(d)}}else c=this._tag;return a.DomUtils.appendToHead(c),c},a.CSSLoader=a.promote(CSSLoader,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function ImageLoader(b,c){this.AbstractLoader_constructor(b,c,a.AbstractLoader.IMAGE),this.resultFormatter=this._formatResult,this._tagSrcAttribute="src",a.RequestUtils.isImageTag(b)?this._tag=b:a.RequestUtils.isImageTag(b.src)?this._tag=b.src:a.RequestUtils.isImageTag(b.tag)&&(this._tag=b.tag),null!=this._tag?this._preferXHR=!1:this._tag=document.createElement("img"),this.on("initialize",this._updateXHR,this)}var b=a.extend(ImageLoader,a.AbstractLoader),c=ImageLoader;c.canLoadItem=function(b){return b.type==a.AbstractLoader.IMAGE},b.load=function(){if(""!=this._tag.src&&this._tag.complete)return void this._sendComplete();var b=this._item.crossOrigin;1==b&&(b="Anonymous"),null==b||a.RequestUtils.isLocal(this._item.src)||(this._tag.crossOrigin=b),this.AbstractLoader_load()},b._updateXHR=function(a){a.loader.mimeType="text/plain; charset=x-user-defined-binary",a.loader.setResponseType&&a.loader.setResponseType("blob")},b._formatResult=function(){return this._formatImage},b._formatImage=function(b,c){var d=this._tag,e=window.URL||window.webkitURL;if(this._preferXHR)if(e){var f=e.createObjectURL(this.getResult(!0));d.src=f,d.addEventListener("load",this._cleanUpURL,!1),d.addEventListener("error",this._cleanUpURL,!1)}else d.src=this._item.src;else;d.complete?b(d):(d.onload=a.proxy(function(){b(this._tag)},this),d.onerror=a.proxy(function(){c(_this._tag)},this))},b._cleanUpURL=function(a){var b=window.URL||window.webkitURL;b.revokeObjectURL(a.target.src)},a.ImageLoader=a.promote(ImageLoader,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function JavaScriptLoader(b,c){this.AbstractLoader_constructor(b,c,a.AbstractLoader.JAVASCRIPT),this.resultFormatter=this._formatResult,this._tagSrcAttribute="src",this.setTag(document.createElement("script"))}var b=a.extend(JavaScriptLoader,a.AbstractLoader),c=JavaScriptLoader;c.canLoadItem=function(b){return b.type==a.AbstractLoader.JAVASCRIPT},b._formatResult=function(a){var b=a.getTag();return this._preferXHR&&(b.text=a.getResult(!0)),b},a.JavaScriptLoader=a.promote(JavaScriptLoader,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function JSONLoader(b){this.AbstractLoader_constructor(b,!0,a.AbstractLoader.JSON),this.resultFormatter=this._formatResult}var b=a.extend(JSONLoader,a.AbstractLoader),c=JSONLoader;c.canLoadItem=function(b){return b.type==a.AbstractLoader.JSON},b._formatResult=function(b){var c=null;try{c=a.DataUtils.parseJSON(b.getResult(!0))}catch(d){var e=new a.ErrorEvent("JSON_FORMAT",null,d);return this._sendError(e),d}return c},a.JSONLoader=a.promote(JSONLoader,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function JSONPLoader(b){this.AbstractLoader_constructor(b,!1,a.AbstractLoader.JSONP),this.setTag(document.createElement("script")),this.getTag().type="text/javascript"}var b=a.extend(JSONPLoader,a.AbstractLoader),c=JSONPLoader;c.canLoadItem=function(b){return b.type==a.AbstractLoader.JSONP},b.cancel=function(){this.AbstractLoader_cancel(),this._dispose()},b.load=function(){if(null==this._item.callback)throw new Error("callback is required for loading JSONP requests.");if(null!=window[this._item.callback])throw new Error("JSONP callback '"+this._item.callback+"' already exists on window. You need to specify a different callback or re-name the current one.");window[this._item.callback]=a.proxy(this._handleLoad,this),window.document.body.appendChild(this._tag),this._loadTimeout=setTimeout(a.proxy(this._handleTimeout,this),this._item.loadTimeout),this._tag.src=this._item.src},b._handleLoad=function(a){this._result=this._rawResult=a,this._sendComplete(),this._dispose()},b._handleTimeout=function(){this._dispose(),this.dispatchEvent(new a.ErrorEvent("timeout"))},b._dispose=function(){window.document.body.removeChild(this._tag),delete window[this._item.callback],clearTimeout(this._loadTimeout)},a.JSONPLoader=a.promote(JSONPLoader,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function ManifestLoader(b){this.AbstractLoader_constructor(b,null,a.AbstractLoader.MANIFEST),this.plugins=null,this._manifestQueue=null}var b=a.extend(ManifestLoader,a.AbstractLoader),c=ManifestLoader;c.MANIFEST_PROGRESS=.25,c.canLoadItem=function(b){return b.type==a.AbstractLoader.MANIFEST},b.load=function(){this.AbstractLoader_load()},b._createRequest=function(){var b=this._item.callback;this._request=null!=b?new a.JSONPLoader(this._item):new a.JSONLoader(this._item)},b.handleEvent=function(a){switch(a.type){case"complete":return this._rawResult=a.target.getResult(!0),this._result=a.target.getResult(),this._sendProgress(c.MANIFEST_PROGRESS),void this._loadManifest(this._result);case"progress":return a.loaded*=c.MANIFEST_PROGRESS,this.progress=a.loaded/a.total,(isNaN(this.progress)||1/0==this.progress)&&(this.progress=0),void this._sendProgress(a)}this.AbstractLoader_handleEvent(a)},b.destroy=function(){this.AbstractLoader_destroy(),this._manifestQueue.close()},b._loadManifest=function(b){if(b&&b.manifest){var c=this._manifestQueue=new a.LoadQueue;c.on("fileload",this._handleManifestFileLoad,this),c.on("progress",this._handleManifestProgress,this),c.on("complete",this._handleManifestComplete,this,!0),c.on("error",this._handleManifestError,this,!0);for(var d=0,e=this.plugins.length;e>d;d++)c.installPlugin(this.plugins[d]);c.loadManifest(b)}else this._sendComplete()},b._handleManifestFileLoad=function(a){a.target=null,this.dispatchEvent(a)},b._handleManifestComplete=function(){this._loadedItems=this._manifestQueue.getItems(!0),this._sendComplete()},b._handleManifestProgress=function(a){this.progress=a.progress*(1-c.MANIFEST_PROGRESS)+c.MANIFEST_PROGRESS,this._sendProgress(this.progress)},b._handleManifestError=function(b){var c=new a.Event("fileerror");c.item=b.data,this.dispatchEvent(c)},a.ManifestLoader=a.promote(ManifestLoader,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function SoundLoader(b,c){this.AbstractMediaLoader_constructor(b,c,a.AbstractLoader.SOUND),a.RequestUtils.isAudioTag(b)?this._tag=b:a.RequestUtils.isAudioTag(b.src)?this._tag=b:a.RequestUtils.isAudioTag(b.tag)&&(this._tag=a.RequestUtils.isAudioTag(b)?b:b.src),null!=this._tag&&(this._preferXHR=!1)}var b=a.extend(SoundLoader,a.AbstractMediaLoader),c=SoundLoader;c.canLoadItem=function(b){return b.type==a.AbstractLoader.SOUND},b._createTag=function(a){var b=document.createElement("audio");return b.autoplay=!1,b.preload="none",b.src=a,b},a.SoundLoader=a.promote(SoundLoader,"AbstractMediaLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function VideoLoader(b,c){this.AbstractMediaLoader_constructor(b,c,a.AbstractLoader.VIDEO),a.RequestUtils.isVideoTag(b)||a.RequestUtils.isVideoTag(b.src)?(this.setTag(a.RequestUtils.isVideoTag(b)?b:b.src),this._preferXHR=!1):this.setTag(this._createTag())}var b=a.extend(VideoLoader,a.AbstractMediaLoader),c=VideoLoader;b._createTag=function(){return document.createElement("video")},c.canLoadItem=function(b){return b.type==a.AbstractLoader.VIDEO},a.VideoLoader=a.promote(VideoLoader,"AbstractMediaLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function SpriteSheetLoader(b,c){this.AbstractLoader_constructor(b,c,a.AbstractLoader.SPRITESHEET),this._manifestQueue=null}var b=a.extend(SpriteSheetLoader,a.AbstractLoader),c=SpriteSheetLoader;c.SPRITESHEET_PROGRESS=.25,c.canLoadItem=function(b){return b.type==a.AbstractLoader.SPRITESHEET},b.destroy=function(){this.AbstractLoader_destroy,this._manifestQueue.close()},b._createRequest=function(){var b=this._item.callback;this._request=null!=b?new a.JSONPLoader(this._item):new a.JSONLoader(this._item)},b.handleEvent=function(a){switch(a.type){case"complete":return this._rawResult=a.target.getResult(!0),this._result=a.target.getResult(),this._sendProgress(c.SPRITESHEET_PROGRESS),void this._loadManifest(this._result);case"progress":return a.loaded*=c.SPRITESHEET_PROGRESS,this.progress=a.loaded/a.total,(isNaN(this.progress)||1/0==this.progress)&&(this.progress=0),void this._sendProgress(a)}this.AbstractLoader_handleEvent(a)},b._loadManifest=function(b){if(b&&b.images){var c=this._manifestQueue=new a.LoadQueue(this._preferXHR,this._item.path,this._item.crossOrigin);c.on("complete",this._handleManifestComplete,this,!0),c.on("fileload",this._handleManifestFileLoad,this),c.on("progress",this._handleManifestProgress,this),c.on("error",this._handleManifestError,this,!0),c.loadManifest(b.images)}},b._handleManifestFileLoad=function(a){var b=a.result;if(null!=b){var c=this.getResult().images,d=c.indexOf(a.item.src);c[d]=b}},b._handleManifestComplete=function(){this._result=new a.SpriteSheet(this._result),this._loadedItems=this._manifestQueue.getItems(!0),this._sendComplete()},b._handleManifestProgress=function(a){this.progress=a.progress*(1-c.SPRITESHEET_PROGRESS)+c.SPRITESHEET_PROGRESS,this._sendProgress(this.progress)},b._handleManifestError=function(b){var c=new a.Event("fileerror");c.item=b.data,this.dispatchEvent(c)},a.SpriteSheetLoader=a.promote(SpriteSheetLoader,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function SVGLoader(b,c){this.AbstractLoader_constructor(b,c,a.AbstractLoader.SVG),this.resultFormatter=this._formatResult,this._tagSrcAttribute="data",c?this.setTag(document.createElement("svg")):(this.setTag(document.createElement("object")),this.getTag().type="image/svg+xml")}var b=a.extend(SVGLoader,a.AbstractLoader),c=SVGLoader;c.canLoadItem=function(b){return b.type==a.AbstractLoader.SVG},b._formatResult=function(b){var c=a.DataUtils.parseXML(b.getResult(!0),"text/xml"),d=b.getTag();return!this._preferXHR&&document.body.contains(d)&&document.body.removeChild(d),null!=c.documentElement?(d.appendChild(c.documentElement),d.style.visibility="visible",d):c},a.SVGLoader=a.promote(SVGLoader,"AbstractLoader")}(scope.createjs);var scope="undefined"==typeof window?this:window;scope.createjs=scope.createjs||{},function(a){"use strict";function XMLLoader(b){this.AbstractLoader_constructor(b,!0,a.AbstractLoader.XML),this.resultFormatter=this._formatResult}var b=a.extend(XMLLoader,a.AbstractLoader),c=XMLLoader;c.canLoadItem=function(b){return b.type==a.AbstractLoader.XML},b._formatResult=function(b){return a.DataUtils.parseXML(b.getResult(!0),"text/xml")},a.XMLLoader=a.promote(XMLLoader,"AbstractLoader")}(scope.createjs); \ No newline at end of file diff --git a/src/createjs/events/ErrorEvent.js b/src/createjs/events/ErrorEvent.js index 88ed99b..0e7a46e 100644 --- a/src/createjs/events/ErrorEvent.js +++ b/src/createjs/events/ErrorEvent.js @@ -1,80 +1,78 @@ /* -* Event -* Visit http://createjs.com/ for documentation, updates and examples. -* -* Copyright (c) 2010 gskinner.com, inc. -* -* Permission is hereby granted, free of charge, to any person -* obtaining a copy of this software and associated documentation -* files (the "Software"), to deal in the Software without -* restriction, including without limitation the rights to use, -* copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following -* conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -*/ + * Event + * Visit http://createjs.com/ for documentation, updates and examples. + * + * Copyright (c) 2010 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ /** * @module CreateJS */ -// namespace: -this.createjs = this.createjs||{}; +var extend = require('../utils/extend'); +var promote = require('../utils/promote'); +var Event = require('./Event'); -(function() { - "use strict"; +// namespace: +/** + * A general error {{#crossLink "Event"}}{{/crossLink}}, that describes an error that occurred, as well as any details. + * @class ErrorEvent + * @param {String} [title] The error title + * @param {String} [message] The error description + * @param {Object} [data] Additional error data + * @constructor + */ +function ErrorEvent(title, message, data) { + this.Event_constructor("error"); /** - * A general error {{#crossLink "Event"}}{{/crossLink}}, that describes an error that occurred, as well as any details. - * @class ErrorEvent - * @param {String} [title] The error title - * @param {String} [message] The error description - * @param {Object} [data] Additional error data - * @constructor + * The short error title, which indicates the type of error that occurred. + * @property title + * @type String */ - function ErrorEvent(title, message, data) { - this.Event_constructor("error"); - - /** - * The short error title, which indicates the type of error that occurred. - * @property title - * @type String - */ - this.title = title; + this.title = title; - /** - * The verbose error message, containing details about the error. - * @property message - * @type String - */ - this.message = message; - - /** - * Additional data attached to an error. - * @property data - * @type {Object} - */ - this.data = data; - } + /** + * The verbose error message, containing details about the error. + * @property message + * @type String + */ + this.message = message; - var p = createjs.extend(ErrorEvent, createjs.Event); + /** + * Additional data attached to an error. + * @property data + * @type {Object} + */ + this.data = data; +} - p.clone = function() { - return new createjs.ErrorEvent(this.title, this.message, this.data); - }; +var p = extend(ErrorEvent, Event); - createjs.ErrorEvent = createjs.promote(ErrorEvent, "Event"); +p.clone = function () { + return new ErrorEvent(this.title, this.message, this.data); +}; -}()); \ No newline at end of file +var ErrorEvent = promote(ErrorEvent, "Event"); +module.exports = ErrorEvent; \ No newline at end of file diff --git a/src/createjs/events/Event.js b/src/createjs/events/Event.js index 76b6a1d..5075f88 100644 --- a/src/createjs/events/Event.js +++ b/src/createjs/events/Event.js @@ -1,30 +1,30 @@ /* -* Event -* Visit http://createjs.com/ for documentation, updates and examples. -* -* Copyright (c) 2010 gskinner.com, inc. -* -* Permission is hereby granted, free of charge, to any person -* obtaining a copy of this software and associated documentation -* files (the "Software"), to deal in the Software without -* restriction, including without limitation the rights to use, -* copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following -* conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -*/ + * Event + * Visit http://createjs.com/ for documentation, updates and examples. + * + * Copyright (c) 2010 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ /** * A collection of Classes that are shared across all the CreateJS libraries. The classes are included in the minified @@ -37,227 +37,221 @@ * @module CreateJS * @main CreateJS */ +// constructor: +/** + * Contains properties and methods shared by all events for use with + * {{#crossLink "EventDispatcher"}}{{/crossLink}}. + * + * Note that Event objects are often reused, so you should never + * rely on an event object's state outside of the call stack it was received in. + * @class Event + * @param {String} type The event type. + * @param {Boolean} bubbles Indicates whether the event will bubble through the display list. + * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled. + * @constructor + **/ +function Event(type, bubbles, cancelable) { -// namespace: -this.createjs = this.createjs||{}; - -(function() { - "use strict"; -// constructor: + // public properties: /** - * Contains properties and methods shared by all events for use with - * {{#crossLink "EventDispatcher"}}{{/crossLink}}. - * - * Note that Event objects are often reused, so you should never - * rely on an event object's state outside of the call stack it was received in. - * @class Event - * @param {String} type The event type. - * @param {Boolean} bubbles Indicates whether the event will bubble through the display list. - * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled. - * @constructor + * The type of event. + * @property type + * @type String **/ - function Event(type, bubbles, cancelable) { - - - // public properties: - /** - * The type of event. - * @property type - * @type String - **/ - this.type = type; - - /** - * The object that generated an event. - * @property target - * @type Object - * @default null - * @readonly - */ - this.target = null; - - /** - * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will - * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event - * is generated from childObj, then a listener on parentObj would receive the event with - * target=childObj (the original target) and currentTarget=parentObj (where the listener was added). - * @property currentTarget - * @type Object - * @default null - * @readonly - */ - this.currentTarget = null; - - /** - * For bubbling events, this indicates the current event phase:
    - *
  1. capture phase: starting from the top parent to the target
  2. - *
  3. at target phase: currently being dispatched from the target
  4. - *
  5. bubbling phase: from the target to the top parent
  6. - *
- * @property eventPhase - * @type Number - * @default 0 - * @readonly - */ - this.eventPhase = 0; - - /** - * Indicates whether the event will bubble through the display list. - * @property bubbles - * @type Boolean - * @default false - * @readonly - */ - this.bubbles = !!bubbles; - - /** - * Indicates whether the default behaviour of this event can be cancelled via - * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor. - * @property cancelable - * @type Boolean - * @default false - * @readonly - */ - this.cancelable = !!cancelable; - - /** - * The epoch time at which this event was created. - * @property timeStamp - * @type Number - * @default 0 - * @readonly - */ - this.timeStamp = (new Date()).getTime(); - - /** - * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called - * on this event. - * @property defaultPrevented - * @type Boolean - * @default false - * @readonly - */ - this.defaultPrevented = false; - - /** - * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or - * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event. - * @property propagationStopped - * @type Boolean - * @default false - * @readonly - */ - this.propagationStopped = false; - - /** - * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called - * on this event. - * @property immediatePropagationStopped - * @type Boolean - * @default false - * @readonly - */ - this.immediatePropagationStopped = false; - - /** - * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event. - * @property removed - * @type Boolean - * @default false - * @readonly - */ - this.removed = false; - } - var p = Event.prototype; + this.type = type; /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated + * The object that generated an event. + * @property target + * @type Object + * @default null + * @readonly */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - + this.target = null; -// public methods: /** - * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method preventDefault - **/ - p.preventDefault = function() { - this.defaultPrevented = this.cancelable&&true; - }; + * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will + * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event + * is generated from childObj, then a listener on parentObj would receive the event with + * target=childObj (the original target) and currentTarget=parentObj (where the listener was added). + * @property currentTarget + * @type Object + * @default null + * @readonly + */ + this.currentTarget = null; /** - * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method stopPropagation - **/ - p.stopPropagation = function() { - this.propagationStopped = true; - }; + * For bubbling events, this indicates the current event phase:
    + *
  1. capture phase: starting from the top parent to the target
  2. + *
  3. at target phase: currently being dispatched from the target
  4. + *
  5. bubbling phase: from the target to the top parent
  6. + *
+ * @property eventPhase + * @type Number + * @default 0 + * @readonly + */ + this.eventPhase = 0; /** - * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and - * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method stopImmediatePropagation - **/ - p.stopImmediatePropagation = function() { - this.immediatePropagationStopped = this.propagationStopped = true; - }; - + * Indicates whether the event will bubble through the display list. + * @property bubbles + * @type Boolean + * @default false + * @readonly + */ + this.bubbles = !!bubbles; + /** - * Causes the active listener to be removed via removeEventListener(); - * - * myBtn.addEventListener("click", function(evt) { - * // do stuff... - * evt.remove(); // removes this listener. - * }); - * - * @method remove - **/ - p.remove = function() { - this.removed = true; - }; - + * Indicates whether the default behaviour of this event can be cancelled via + * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor. + * @property cancelable + * @type Boolean + * @default false + * @readonly + */ + this.cancelable = !!cancelable; + /** - * Returns a clone of the Event instance. - * @method clone - * @return {Event} a clone of the Event instance. - **/ - p.clone = function() { - return new Event(this.type, this.bubbles, this.cancelable); - }; - + * The epoch time at which this event was created. + * @property timeStamp + * @type Number + * @default 0 + * @readonly + */ + this.timeStamp = (new Date()).getTime(); + /** - * Provides a chainable shortcut method for setting a number of properties on the instance. - * - * @method set - * @param {Object} props A generic object containing properties to copy to the instance. - * @return {Event} Returns the instance the method is called on (useful for chaining calls.) - * @chainable - */ - p.set = function(props) { - for (var n in props) { this[n] = props[n]; } - return this; - }; + * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called + * on this event. + * @property defaultPrevented + * @type Boolean + * @default false + * @readonly + */ + this.defaultPrevented = false; /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Event (type="+this.type+")]"; - }; + * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or + * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event. + * @property propagationStopped + * @type Boolean + * @default false + * @readonly + */ + this.propagationStopped = false; + + /** + * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called + * on this event. + * @property immediatePropagationStopped + * @type Boolean + * @default false + * @readonly + */ + this.immediatePropagationStopped = false; + + /** + * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event. + * @property removed + * @type Boolean + * @default false + * @readonly + */ + this.removed = false; +} +var p = Event.prototype; + +/** + * REMOVED. Removed in favor of using `MySuperClass_constructor`. + * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} + * for details. + * + * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. + * + * @method initialize + * @protected + * @deprecated + */ +// p.initialize = function() {}; // searchable for devs wondering where it is. + + +// public methods: +/** + * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method preventDefault + **/ +p.preventDefault = function () { + this.defaultPrevented = this.cancelable && true; +}; + +/** + * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method stopPropagation + **/ +p.stopPropagation = function () { + this.propagationStopped = true; +}; + +/** + * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and + * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true. + * Mirrors the DOM event standard. + * @method stopImmediatePropagation + **/ +p.stopImmediatePropagation = function () { + this.immediatePropagationStopped = this.propagationStopped = true; +}; + +/** + * Causes the active listener to be removed via removeEventListener(); + * + * myBtn.addEventListener("click", function(evt) { + * // do stuff... + * evt.remove(); // removes this listener. + * }); + * + * @method remove + **/ +p.remove = function () { + this.removed = true; +}; + +/** + * Returns a clone of the Event instance. + * @method clone + * @return {Event} a clone of the Event instance. + **/ +p.clone = function () { + return new Event(this.type, this.bubbles, this.cancelable); +}; + +/** + * Provides a chainable shortcut method for setting a number of properties on the instance. + * + * @method set + * @param {Object} props A generic object containing properties to copy to the instance. + * @return {Event} Returns the instance the method is called on (useful for chaining calls.) + * @chainable + */ +p.set = function (props) { + for (var n in props) { + this[n] = props[n]; + } + return this; +}; + +/** + * Returns a string representation of this object. + * @method toString + * @return {String} a string representation of the instance. + **/ +p.toString = function () { + return "[Event (type=" + this.type + ")]"; +}; - createjs.Event = Event; -}()); +module.exports = Event; diff --git a/src/createjs/events/EventDispatcher.js b/src/createjs/events/EventDispatcher.js index 0ae4781..533820b 100644 --- a/src/createjs/events/EventDispatcher.js +++ b/src/createjs/events/EventDispatcher.js @@ -1,195 +1,197 @@ /* -* EventDispatcher -* Visit http://createjs.com/ for documentation, updates and examples. -* -* Copyright (c) 2010 gskinner.com, inc. -* -* Permission is hereby granted, free of charge, to any person -* obtaining a copy of this software and associated documentation -* files (the "Software"), to deal in the Software without -* restriction, including without limitation the rights to use, -* copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following -* conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -*/ + * EventDispatcher + * Visit http://createjs.com/ for documentation, updates and examples. + * + * Copyright (c) 2010 gskinner.com, inc. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ /** * @module CreateJS */ -// namespace: -this.createjs = this.createjs||{}; - -(function() { - "use strict"; +var Event = require('./Event'); // constructor: - /** - * EventDispatcher provides methods for managing queues of event listeners and dispatching events. - * - * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the - * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method. - * - * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the - * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports - * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent. - * - * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier - * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The - * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to - * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}. - * - * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}} - * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also - * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener. - * - *

Example

- * Add EventDispatcher capabilities to the "MyClass" class. - * - * EventDispatcher.initialize(MyClass.prototype); - * - * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}). - * - * instance.addEventListener("eventName", handlerMethod); - * function handlerMethod(event) { +/** + * EventDispatcher provides methods for managing queues of event listeners and dispatching events. + * + * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the + * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method. + * + * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the + * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports + * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent. + * + * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier + * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The + * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to + * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}. + * + * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}} + * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also + * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener. + * + *

Example

+ * Add EventDispatcher capabilities to the "MyClass" class. + * + * EventDispatcher.initialize(MyClass.prototype); + * + * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}). + * + * instance.addEventListener("eventName", handlerMethod); + * function handlerMethod(event) { * console.log(event.target + " Was Clicked"); * } - * - * Maintaining proper scope
- * Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}} - * method to subscribe to events simplifies this. - * - * instance.addEventListener("click", function(event) { + * + * Maintaining proper scope
+ * Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}} + * method to subscribe to events simplifies this. + * + * instance.addEventListener("click", function(event) { * console.log(instance == this); // false, scope is ambiguous. * }); - * - * instance.on("click", function(event) { + * + * instance.on("click", function(event) { * console.log(instance == this); // true, "on" uses dispatcher scope by default. * }); - * - * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage scope. - * - * - * @class EventDispatcher - * @constructor - **/ - function EventDispatcher() { - - + * + * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage scope. + * + * + * @class EventDispatcher + * @constructor + **/ +function EventDispatcher() { + + // private properties: - /** - * @protected - * @property _listeners - * @type Object - **/ - this._listeners = null; - - /** - * @protected - * @property _captureListeners - * @type Object - **/ - this._captureListeners = null; - } - var p = EventDispatcher.prototype; + /** + * @protected + * @property _listeners + * @type Object + **/ + this._listeners = null; /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. + * @property _captureListeners + * @type Object + **/ + this._captureListeners = null; +} +var p = EventDispatcher.prototype; + +/** + * REMOVED. Removed in favor of using `MySuperClass_constructor`. + * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} + * for details. + * + * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. + * + * @method initialize + * @protected + * @deprecated + */ +// p.initialize = function() {}; // searchable for devs wondering where it is. // static public methods: - /** - * Static initializer to mix EventDispatcher methods into a target object or prototype. - * - * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class - * EventDispatcher.initialize(myObject); // add to a specific instance - * - * @method initialize - * @static - * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a - * prototype. - **/ - EventDispatcher.initialize = function(target) { - target.addEventListener = p.addEventListener; - target.on = p.on; - target.removeEventListener = target.off = p.removeEventListener; - target.removeAllEventListeners = p.removeAllEventListeners; - target.hasEventListener = p.hasEventListener; - target.dispatchEvent = p.dispatchEvent; - target._dispatchEvent = p._dispatchEvent; - target.willTrigger = p.willTrigger; - }; - +/** + * Static initializer to mix EventDispatcher methods into a target object or prototype. + * + * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class + * EventDispatcher.initialize(myObject); // add to a specific instance + * + * @method initialize + * @static + * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a + * prototype. + **/ +EventDispatcher.initialize = function (target) { + target.addEventListener = p.addEventListener; + target.on = p.on; + target.removeEventListener = target.off = p.removeEventListener; + target.removeAllEventListeners = p.removeAllEventListeners; + target.hasEventListener = p.hasEventListener; + target.dispatchEvent = p.dispatchEvent; + target._dispatchEvent = p._dispatchEvent; + target.willTrigger = p.willTrigger; +}; + // public methods: - /** - * Adds the specified event listener. Note that adding multiple listeners to the same function will result in - * multiple callbacks getting fired. - * - *

Example

- * - * displayObject.addEventListener("click", handleClick); - * function handleClick(event) { +/** + * Adds the specified event listener. Note that adding multiple listeners to the same function will result in + * multiple callbacks getting fired. + * + *

Example

+ * + * displayObject.addEventListener("click", handleClick); + * function handleClick(event) { * // Click happened. * } - * - * @method addEventListener - * @param {String} type The string type of the event. - * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when - * the event is dispatched. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - * @return {Function | Object} Returns the listener for chaining or assignment. - **/ - p.addEventListener = function(type, listener, useCapture) { - var listeners; - if (useCapture) { - listeners = this._captureListeners = this._captureListeners||{}; - } else { - listeners = this._listeners = this._listeners||{}; - } - var arr = listeners[type]; - if (arr) { this.removeEventListener(type, listener, useCapture); } - arr = listeners[type]; // remove may have deleted the array - if (!arr) { listeners[type] = [listener]; } - else { arr.push(listener); } - return listener; - }; - - /** - * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener - * only run once, associate arbitrary data with the listener, and remove the listener. - * - * This method works by creating an anonymous wrapper function and subscribing it with addEventListener. - * The created anonymous function is returned for use with .removeEventListener (or .off). - * - *

Example

- * - * var listener = myBtn.on("click", handleClick, null, false, {count:3}); - * function handleClick(evt, data) { + * + * @method addEventListener + * @param {String} type The string type of the event. + * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when + * the event is dispatched. + * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + * @return {Function | Object} Returns the listener for chaining or assignment. + **/ +p.addEventListener = function (type, listener, useCapture) { + var listeners; + if (useCapture) { + listeners = this._captureListeners = this._captureListeners || {}; + } else { + listeners = this._listeners = this._listeners || {}; + } + var arr = listeners[type]; + if (arr) { + this.removeEventListener(type, listener, useCapture); + } + arr = listeners[type]; // remove may have deleted the array + if (!arr) { + listeners[type] = [listener]; + } + else { + arr.push(listener); + } + return listener; +}; + +/** + * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener + * only run once, associate arbitrary data with the listener, and remove the listener. + * + * This method works by creating an anonymous wrapper function and subscribing it with addEventListener. + * The created anonymous function is returned for use with .removeEventListener (or .off). + * + *

Example

+ * + * var listener = myBtn.on("click", handleClick, null, false, {count:3}); + * function handleClick(evt, data) { * data.count -= 1; * console.log(this == myBtn); // true - scope defaults to the dispatcher * if (data.count == 0) { @@ -198,210 +200,244 @@ this.createjs = this.createjs||{}; * // alternately: evt.remove(); * } * } - * - * @method on - * @param {String} type The string type of the event. - * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when - * the event is dispatched. - * @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent). - * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered. - * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called. - * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener. - **/ - p.on = function(type, listener, scope, once, data, useCapture) { - if (listener.handleEvent) { - scope = scope||listener; - listener = listener.handleEvent; - } - scope = scope||this; - return this.addEventListener(type, function(evt) { - listener.call(scope, evt, data); - once&&evt.remove(); - }, useCapture); - }; + * + * @method on + * @param {String} type The string type of the event. + * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when + * the event is dispatched. + * @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent). + * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered. + * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called. + * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener. + **/ +p.on = function (type, listener, scope, once, data, useCapture) { + if (listener.handleEvent) { + scope = scope || listener; + listener = listener.handleEvent; + } + scope = scope || this; + return this.addEventListener(type, function (evt) { + listener.call(scope, evt, data); + once && evt.remove(); + }, useCapture); +}; - /** - * Removes the specified event listener. - * - * Important Note: that you must pass the exact function reference used when the event was added. If a proxy - * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or - * closure will not work. - * - *

Example

- * - * displayObject.removeEventListener("click", handleClick); - * - * @method removeEventListener - * @param {String} type The string type of the event. - * @param {Function | Object} listener The listener function or object. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - **/ - p.removeEventListener = function(type, listener, useCapture) { - var listeners = useCapture ? this._captureListeners : this._listeners; - if (!listeners) { return; } - var arr = listeners[type]; - if (!arr) { return; } - for (var i=0,l=arr.length; iImportant Note: that you must pass the exact function reference used when the event was added. If a proxy + * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or + * closure will not work. + * + *

Example

+ * + * displayObject.removeEventListener("click", handleClick); + * + * @method removeEventListener + * @param {String} type The string type of the event. + * @param {Function | Object} listener The listener function or object. + * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + **/ +p.removeEventListener = function (type, listener, useCapture) { + var listeners = useCapture ? this._captureListeners : this._listeners; + if (!listeners) { + return; + } + var arr = listeners[type]; + if (!arr) { + return; + } + for (var i = 0, l = arr.length; i < l; i++) { + if (arr[i] == listener) { + if (l == 1) { + delete(listeners[type]); + } // allows for faster checks. + else { + arr.splice(i, 1); } + break; } - }; - - /** - * A shortcut to the removeEventListener method, with the same parameters and return value. This is a companion to the - * .on method. - * - * @method off - * @param {String} type The string type of the event. - * @param {Function | Object} listener The listener function or object. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - **/ - p.off = p.removeEventListener; + } +}; - /** - * Removes all listeners for the specified type, or all listeners of all types. - * - *

Example

- * - * // Remove all listeners - * displayObject.removeAllEventListeners(); - * - * // Remove all click listeners - * displayObject.removeAllEventListeners("click"); - * - * @method removeAllEventListeners - * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed. - **/ - p.removeAllEventListeners = function(type) { - if (!type) { this._listeners = this._captureListeners = null; } - else { - if (this._listeners) { delete(this._listeners[type]); } - if (this._captureListeners) { delete(this._captureListeners[type]); } +/** + * A shortcut to the removeEventListener method, with the same parameters and return value. This is a companion to the + * .on method. + * + * @method off + * @param {String} type The string type of the event. + * @param {Function | Object} listener The listener function or object. + * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. + **/ +p.off = p.removeEventListener; + +/** + * Removes all listeners for the specified type, or all listeners of all types. + * + *

Example

+ * + * // Remove all listeners + * displayObject.removeAllEventListeners(); + * + * // Remove all click listeners + * displayObject.removeAllEventListeners("click"); + * + * @method removeAllEventListeners + * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed. + **/ +p.removeAllEventListeners = function (type) { + if (!type) { + this._listeners = this._captureListeners = null; + } + else { + if (this._listeners) { + delete(this._listeners[type]); + } + if (this._captureListeners) { + delete(this._captureListeners[type]); } - }; + } +}; - /** - * Dispatches the specified event to all listeners. - * - *

Example

- * - * // Use a string event - * this.dispatchEvent("complete"); - * - * // Use an Event instance - * var event = new createjs.Event("progress"); - * this.dispatchEvent(event); - * - * @method dispatchEvent - * @param {Object | String | Event} eventObj An object with a "type" property, or a string type. - * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used, - * dispatchEvent will construct an Event instance with the specified type. - * @return {Boolean} Returns the value of eventObj.defaultPrevented. - **/ - p.dispatchEvent = function(eventObj) { - if (typeof eventObj == "string") { - // won't bubble, so skip everything if there's no listeners: - var listeners = this._listeners; - if (!listeners || !listeners[eventObj]) { return false; } - eventObj = new createjs.Event(eventObj); - } else if (eventObj.target && eventObj.clone) { - // redispatching an active event object, so clone it: - eventObj = eventObj.clone(); +/** + * Dispatches the specified event to all listeners. + * + *

Example

+ * + * // Use a string event + * this.dispatchEvent("complete"); + * + * // Use an Event instance + * var event = new createjs.Event("progress"); + * this.dispatchEvent(event); + * + * @method dispatchEvent + * @param {Object | String | Event} eventObj An object with a "type" property, or a string type. + * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used, + * dispatchEvent will construct an Event instance with the specified type. + * @return {Boolean} Returns the value of eventObj.defaultPrevented. + **/ +p.dispatchEvent = function (eventObj) { + if (typeof eventObj == "string") { + // won't bubble, so skip everything if there's no listeners: + var listeners = this._listeners; + if (!listeners || !listeners[eventObj]) { + return false; } - try { eventObj.target = this; } catch (e) {} // try/catch allows redispatching of native events + eventObj = new Event(eventObj); + } else if (eventObj.target && eventObj.clone) { + // redispatching an active event object, so clone it: + eventObj = eventObj.clone(); + } + try { + eventObj.target = this; + } catch (e) { + } // try/catch allows redispatching of native events - if (!eventObj.bubbles || !this.parent) { - this._dispatchEvent(eventObj, 2); - } else { - var top=this, list=[top]; - while (top.parent) { list.push(top = top.parent); } - var i, l=list.length; + if (!eventObj.bubbles || !this.parent) { + this._dispatchEvent(eventObj, 2); + } else { + var top = this, list = [top]; + while (top.parent) { + list.push(top = top.parent); + } + var i, l = list.length; - // capture & atTarget - for (i=l-1; i>=0 && !eventObj.propagationStopped; i--) { - list[i]._dispatchEvent(eventObj, 1+(i==0)); - } - // bubbling - for (i=1; i= 0 && !eventObj.propagationStopped; i--) { + list[i]._dispatchEvent(eventObj, 1 + (i == 0)); + } + // bubbling + for (i = 1; i < l && !eventObj.propagationStopped; i++) { + list[i]._dispatchEvent(eventObj, 3); } - return eventObj.defaultPrevented; - }; + } + return eventObj.defaultPrevented; +}; - /** - * Indicates whether there is at least one listener for the specified event type. - * @method hasEventListener - * @param {String} type The string type of the event. - * @return {Boolean} Returns true if there is at least one listener for the specified event. - **/ - p.hasEventListener = function(type) { - var listeners = this._listeners, captureListeners = this._captureListeners; - return !!((listeners && listeners[type]) || (captureListeners && captureListeners[type])); - }; - - /** - * Indicates whether there is at least one listener for the specified event type on this object or any of its - * ancestors (parent, parent's parent, etc). A return value of true indicates that if a bubbling event of the - * specified type is dispatched from this object, it will trigger at least one listener. - * - * This is similar to {{#crossLink "EventDispatcher/hasEventListener"}}{{/crossLink}}, but it searches the entire - * event flow for a listener, not just this object. - * @method willTrigger - * @param {String} type The string type of the event. - * @return {Boolean} Returns `true` if there is at least one listener for the specified event. - **/ - p.willTrigger = function(type) { - var o = this; - while (o) { - if (o.hasEventListener(type)) { return true; } - o = o.parent; +/** + * Indicates whether there is at least one listener for the specified event type. + * @method hasEventListener + * @param {String} type The string type of the event. + * @return {Boolean} Returns true if there is at least one listener for the specified event. + **/ +p.hasEventListener = function (type) { + var listeners = this._listeners, captureListeners = this._captureListeners; + return !!((listeners && listeners[type]) || (captureListeners && captureListeners[type])); +}; + +/** + * Indicates whether there is at least one listener for the specified event type on this object or any of its + * ancestors (parent, parent's parent, etc). A return value of true indicates that if a bubbling event of the + * specified type is dispatched from this object, it will trigger at least one listener. + * + * This is similar to {{#crossLink "EventDispatcher/hasEventListener"}}{{/crossLink}}, but it searches the entire + * event flow for a listener, not just this object. + * @method willTrigger + * @param {String} type The string type of the event. + * @return {Boolean} Returns `true` if there is at least one listener for the specified event. + **/ +p.willTrigger = function (type) { + var o = this; + while (o) { + if (o.hasEventListener(type)) { + return true; } - return false; - }; + o = o.parent; + } + return false; +}; - /** - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[EventDispatcher]"; - }; +/** + * @method toString + * @return {String} a string representation of the instance. + **/ +p.toString = function () { + return "[EventDispatcher]"; +}; // private methods: - /** - * @method _dispatchEvent - * @param {Object | String | Event} eventObj - * @param {Object} eventPhase - * @protected - **/ - p._dispatchEvent = function(eventObj, eventPhase) { - var l, listeners = (eventPhase==1) ? this._captureListeners : this._listeners; - if (eventObj && listeners) { - var arr = listeners[eventObj.type]; - if (!arr||!(l=arr.length)) { return; } - try { eventObj.currentTarget = this; } catch (e) {} - try { eventObj.eventPhase = eventPhase; } catch (e) {} - eventObj.removed = false; - - arr = arr.slice(); // to avoid issues with items being removed or added during the dispatch - for (var i=0; iExample - * - * myObject.addEventListener("event", createjs.proxy(myHandler, this, arg1, arg2)); - * - * function myHandler(arg1, arg2) { +/** + * A function proxy for methods. By default, JavaScript methods do not maintain scope, so passing a method as a + * callback will result in the method getting called in the scope of the caller. Using a proxy ensures that the + * method gets called in the correct scope. + * + * Additional arguments can be passed that will be applied to the function when it is called. + * + *

Example

+ * + * myObject.addEventListener("event", createjs.proxy(myHandler, this, arg1, arg2)); + * + * function myHandler(arg1, arg2) { * // This gets called when myObject.myCallback is executed. * } - * - * @method proxy - * @param {Function} method The function to call - * @param {Object} scope The scope to call the method name on - * @param {mixed} [arg] * Arguments that are appended to the callback for additional params. - * @public - * @static - */ - createjs.proxy = function (method, scope) { - var aArgs = Array.prototype.slice.call(arguments, 2); - return function () { - return method.apply(scope, Array.prototype.slice.call(arguments, 0).concat(aArgs)); - }; - } - -}()); + * + * @method proxy + * @param {Function} method The function to call + * @param {Object} scope The scope to call the method name on + * @param {mixed} [arg] * Arguments that are appended to the callback for additional params. + * @public + * @static + */ +module.exports = function (method, scope) { + var aArgs = Array.prototype.slice.call(arguments, 2); + return function () { + return method.apply(scope, Array.prototype.slice.call(arguments, 0).concat(aArgs)); + }; +} \ No newline at end of file diff --git a/src/preloadjs/LoadQueue.js b/src/preloadjs/LoadQueue.js index 6e4e1e2..0aa512b 100644 --- a/src/preloadjs/LoadQueue.js +++ b/src/preloadjs/LoadQueue.js @@ -88,7 +88,7 @@ */ // namespace: -this.createjs = this.createjs || {}; + /* TODO: WINDOWS ISSUES @@ -102,112 +102,109 @@ this.createjs = this.createjs || {}; * Reported issues with IE7/8 */ -(function () { - "use strict"; - // constructor - /** - * The LoadQueue class is the main API for preloading content. LoadQueue is a load manager, which can preload either - * a single file, or queue of files. - * - * Creating a Queue
- * To use LoadQueue, create a LoadQueue instance. If you want to force tag loading where possible, set the preferXHR - * argument to false. - * - * var queue = new createjs.LoadQueue(true); - * - * Listening for Events
- * Add any listeners you want to the queue. Since PreloadJS 0.3.0, the {{#crossLink "EventDispatcher"}}{{/crossLink}} - * lets you add as many listeners as you want for events. You can subscribe to the following events:
    - *
  • {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}}: fired when a queue completes loading all - * files
  • - *
  • {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}: fired when the queue encounters an error with - * any file.
  • - *
  • {{#crossLink "AbstractLoader/progress:event"}}{{/crossLink}}: Progress for the entire queue has - * changed.
  • - *
  • {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}}: A single file has completed loading.
  • - *
  • {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}}: Progress for a single file has changes. Note - * that only files loaded with XHR (or possibly by plugins) will fire progress events other than 0 or 100%.
  • - *
- * - * queue.on("fileload", handleFileLoad, this); - * queue.on("complete", handleComplete, this); - * - * Adding files and manifests
- * Add files you want to load using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or add multiple files at a - * time using a list or a manifest definition using {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. Files are - * appended to the end of the active queue, so you can use these methods as many times as you like, whenever you - * like. - * - * queue.loadFile("filePath/file.jpg"); - * queue.loadFile({id:"image", src:"filePath/file.jpg"}); - * queue.loadManifest(["filePath/file.jpg", {id:"image", src:"filePath/file.jpg"}]); - * - * // Use an external manifest - * queue.loadManifest("path/to/manifest.json"); - * queue.loadManifest({src:"manifest.json", type:"manifest"}); - * - * If you pass `false` as the `loadNow` parameter, the queue will not kick of the load of the files, but it will not - * stop if it has already been started. Call the {{#crossLink "AbstractLoader/load"}}{{/crossLink}} method to begin - * a paused queue. Note that a paused queue will automatically resume when new files are added to it with a - * `loadNow` argument of `true`. - * - * queue.load(); - * - * File Types
- * The file type of a manifest item is auto-determined by the file extension. The pattern matching in PreloadJS - * should handle the majority of standard file and url formats, and works with common file extensions. If you have - * either a non-standard file extension, or are serving the file using a proxy script, then you can pass in a - * type property with any manifest item. - * - * queue.loadFile({src:"path/to/myFile.mp3x", type:createjs.AbstractLoader.SOUND}); - * - * // Note that PreloadJS will not read a file extension from the query string - * queue.loadFile({src:"http://server.com/proxy?file=image.jpg", type:createjs.AbstractLoader.IMAGE}); - * - * Supported types are defined on the {{#crossLink "AbstractLoader"}}{{/crossLink}} class, and include: - *
    - *
  • {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}}: Raw binary data via XHR
  • - *
  • {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}}: CSS files
  • - *
  • {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}: Common image formats
  • - *
  • {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}}: JavaScript files
  • - *
  • {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}}: JSON data
  • - *
  • {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}}: JSON files cross-domain
  • - *
  • {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}: A list of files to load in JSON format, see - * {{#crossLink "AbstractLoader/loadManifest"}}{{/crossLink}}
  • - *
  • {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}: Audio file formats
  • - *
  • {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}: JSON SpriteSheet definitions. This - * will also load sub-images, and provide a {{#crossLink "SpriteSheet"}}{{/crossLink}} instance.
  • - *
  • {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}}: SVG files
  • - *
  • {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}}: Text files - XHR only
  • - *
  • {{#crossLink "AbstractLoader/VIDEO:property"}}{{/crossLink}}: Video objects
  • - *
  • {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}}: XML data
  • - *
- * - * Note: Loader types used to be defined on LoadQueue, but have been moved to AbstractLoader for better - * portability of loader classes, which can be used individually now. The properties on LoadQueue still exist, but - * are deprecated. - * - * Handling Results
- * When a file is finished downloading, a {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event is - * dispatched. In an example above, there is an event listener snippet for fileload. Loaded files are usually a - * formatted object that can be used immediately, including: - *
    - *
  • Binary: The binary loaded result
  • - *
  • CSS: A <link /> tag
  • - *
  • Image: An <img /> tag
  • - *
  • JavaScript: A <script /> tag
  • - *
  • JSON/JSONP: A formatted JavaScript Object
  • - *
  • Manifest: A JavaScript object. - *
  • Sound: An <audio /> tag - *
  • SpriteSheet: A {{#crossLink "SpriteSheet"}}{{/crossLink}} instance, containing loaded images. - *
  • SVG: An <object /> tag
  • - *
  • Text: Raw text
  • - *
  • Video: A Video DOM node
  • - *
  • XML: An XML DOM node
  • - *
- * - * function handleFileLoad(event) { +/** + * The LoadQueue class is the main API for preloading content. LoadQueue is a load manager, which can preload either + * a single file, or queue of files. + * + * Creating a Queue
+ * To use LoadQueue, create a LoadQueue instance. If you want to force tag loading where possible, set the preferXHR + * argument to false. + * + * var queue = new createjs.LoadQueue(true); + * + * Listening for Events
+ * Add any listeners you want to the queue. Since PreloadJS 0.3.0, the {{#crossLink "EventDispatcher"}}{{/crossLink}} + * lets you add as many listeners as you want for events. You can subscribe to the following events:
    + *
  • {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}}: fired when a queue completes loading all + * files
  • + *
  • {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}: fired when the queue encounters an error with + * any file.
  • + *
  • {{#crossLink "AbstractLoader/progress:event"}}{{/crossLink}}: Progress for the entire queue has + * changed.
  • + *
  • {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}}: A single file has completed loading.
  • + *
  • {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}}: Progress for a single file has changes. Note + * that only files loaded with XHR (or possibly by plugins) will fire progress events other than 0 or 100%.
  • + *
+ * + * queue.on("fileload", handleFileLoad, this); + * queue.on("complete", handleComplete, this); + * + * Adding files and manifests
+ * Add files you want to load using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or add multiple files at a + * time using a list or a manifest definition using {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. Files are + * appended to the end of the active queue, so you can use these methods as many times as you like, whenever you + * like. + * + * queue.loadFile("filePath/file.jpg"); + * queue.loadFile({id:"image", src:"filePath/file.jpg"}); + * queue.loadManifest(["filePath/file.jpg", {id:"image", src:"filePath/file.jpg"}]); + * + * // Use an external manifest + * queue.loadManifest("path/to/manifest.json"); + * queue.loadManifest({src:"manifest.json", type:"manifest"}); + * + * If you pass `false` as the `loadNow` parameter, the queue will not kick of the load of the files, but it will not + * stop if it has already been started. Call the {{#crossLink "AbstractLoader/load"}}{{/crossLink}} method to begin + * a paused queue. Note that a paused queue will automatically resume when new files are added to it with a + * `loadNow` argument of `true`. + * + * queue.load(); + * + * File Types
+ * The file type of a manifest item is auto-determined by the file extension. The pattern matching in PreloadJS + * should handle the majority of standard file and url formats, and works with common file extensions. If you have + * either a non-standard file extension, or are serving the file using a proxy script, then you can pass in a + * type property with any manifest item. + * + * queue.loadFile({src:"path/to/myFile.mp3x", type:AbstractLoader.SOUND}); + * + * // Note that PreloadJS will not read a file extension from the query string + * queue.loadFile({src:"http://server.com/proxy?file=image.jpg", type:AbstractLoader.IMAGE}); + * + * Supported types are defined on the {{#crossLink "AbstractLoader"}}{{/crossLink}} class, and include: + *
    + *
  • {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}}: Raw binary data via XHR
  • + *
  • {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}}: CSS files
  • + *
  • {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}: Common image formats
  • + *
  • {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}}: JavaScript files
  • + *
  • {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}}: JSON data
  • + *
  • {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}}: JSON files cross-domain
  • + *
  • {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}: A list of files to load in JSON format, see + * {{#crossLink "AbstractLoader/loadManifest"}}{{/crossLink}}
  • + *
  • {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}: Audio file formats
  • + *
  • {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}: JSON SpriteSheet definitions. This + * will also load sub-images, and provide a {{#crossLink "SpriteSheet"}}{{/crossLink}} instance.
  • + *
  • {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}}: SVG files
  • + *
  • {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}}: Text files - XHR only
  • + *
  • {{#crossLink "AbstractLoader/VIDEO:property"}}{{/crossLink}}: Video objects
  • + *
  • {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}}: XML data
  • + *
+ * + * Note: Loader types used to be defined on LoadQueue, but have been moved to AbstractLoader for better + * portability of loader classes, which can be used individually now. The properties on LoadQueue still exist, but + * are deprecated. + * + * Handling Results
+ * When a file is finished downloading, a {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event is + * dispatched. In an example above, there is an event listener snippet for fileload. Loaded files are usually a + * formatted object that can be used immediately, including: + *
    + *
  • Binary: The binary loaded result
  • + *
  • CSS: A <link /> tag
  • + *
  • Image: An <img /> tag
  • + *
  • JavaScript: A <script /> tag
  • + *
  • JSON/JSONP: A formatted JavaScript Object
  • + *
  • Manifest: A JavaScript object. + *
  • Sound: An <audio /> tag + *
  • SpriteSheet: A {{#crossLink "SpriteSheet"}}{{/crossLink}} instance, containing loaded images. + *
  • SVG: An <object /> tag
  • + *
  • Text: Raw text
  • + *
  • Video: A Video DOM node
  • + *
  • XML: An XML DOM node
  • + *
+ * + * function handleFileLoad(event) { * var item = event.item; // A reference to the item that was passed in to the LoadQueue * var type = item.type; * @@ -216,1736 +213,1749 @@ this.createjs = this.createjs || {}; * document.body.appendChild(event.result); * } * } - * - * At any time after the file has been loaded (usually after the queue has completed), any result can be looked up - * via its "id" using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. If no id was provided, then the - * "src" or file path can be used instead, including the `path` defined by a manifest, but not including - * a base path defined on the LoadQueue. It is recommended to always pass an id if you want to look up content. - * - * var image = queue.getResult("image"); - * document.body.appendChild(image); - * - * Raw loaded content can be accessed using the rawResult property of the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} - * event, or can be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}, passing `true` as the 2nd - * argument. This is only applicable for content that has been parsed for the browser, specifically: JavaScript, - * CSS, XML, SVG, and JSON objects, or anything loaded with XHR. - * - * var image = queue.getResult("image", true); // load the binary image data loaded with XHR. - * - * Plugins
- * LoadQueue has a simple plugin architecture to help process and preload content. For example, to preload audio, - * make sure to install the SoundJS Sound class, which will help load HTML audio, - * Flash audio, and WebAudio files. This should be installed before loading any audio files. - * - * queue.installPlugin(createjs.Sound); - * - *

Known Browser Issues

- *
    - *
  • Browsers without audio support can not load audio files.
  • - *
  • Safari on Mac OS X can only play HTML audio if QuickTime is installed
  • - *
  • HTML Audio tags will only download until their canPlayThrough event is fired. Browsers other - * than Chrome will continue to download in the background.
  • - *
  • When loading scripts using tags, they are automatically added to the document.
  • - *
  • Scripts loaded via XHR may not be properly inspectable with browser tools.
  • - *
  • IE6 and IE7 (and some other browsers) may not be able to load XML, Text, or JSON, since they require - * XHR to work.
  • - *
  • Content loaded via tags will not show progress, and will continue to download in the background when - * canceled, although no events will be dispatched.
  • - *
- * - * @class LoadQueue - * @param {Boolean} [preferXHR=true] Determines whether the preload instance will favor loading with XHR (XML HTTP - * Requests), or HTML tags. When this is `false`, the queue will use tag loading when possible, and fall back on XHR - * when necessary. - * @param {String} [basePath=""] A path that will be prepended on to the source parameter of all items in the queue - * before they are loaded. Sources beginning with a protocol such as `http://` or a relative path such as `../` - * will not receive a base path. - * @param {String|Boolean} [crossOrigin=""] An optional flag to support images loaded from a CORS-enabled server. To - * use it, set this value to `true`, which will default the crossOrigin property on images to "Anonymous". Any - * string value will be passed through, but only "" and "Anonymous" are recommended. Note: The crossOrigin - * parameter is deprecated. Use LoadItem.crossOrigin instead - * - * @constructor - * @extends AbstractLoader - */ - function LoadQueue (preferXHR, basePath, crossOrigin) { - this.AbstractLoader_constructor(); - - /** - * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}. - * @property _plugins - * @type {Array} - * @private - * @since 0.6.1 - */ - this._plugins = []; - - /** - * An object hash of callbacks that are fired for each file type before the file is loaded, giving plugins the - * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} - * method for more information. - * @property _typeCallbacks - * @type {Object} - * @private - */ - this._typeCallbacks = {}; - - /** - * An object hash of callbacks that are fired for each file extension before the file is loaded, giving plugins the - * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} - * method for more information. - * @property _extensionCallbacks - * @type {null} - * @private - */ - this._extensionCallbacks = {}; - - /** - * The next preload queue to process when this one is complete. If an error is thrown in the current queue, and - * {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} is `true`, the next queue will not be processed. - * @property next - * @type {LoadQueue} - * @default null - */ - this.next = null; - - /** - * Ensure loaded scripts "complete" in the order they are specified. Loaded scripts are added to the document head - * once they are loaded. Scripts loaded via tags will load one-at-a-time when this property is `true`, whereas - * scripts loaded using XHR can load in any order, but will "finish" and be added to the document in the order - * specified. - * - * Any items can be set to load in order by setting the {{#crossLink "maintainOrder:property"}}{{/crossLink}} - * property on the load item, or by ensuring that only one connection can be open at a time using - * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Note that when the `maintainScriptOrder` property - * is set to `true`, scripts items are automatically set to `maintainOrder=true`, and changing the - * `maintainScriptOrder` to `false` during a load will not change items already in a queue. - * - *

Example

- * - * var queue = new createjs.LoadQueue(); - * queue.setMaxConnections(3); // Set a higher number to load multiple items at once - * queue.maintainScriptOrder = true; // Ensure scripts are loaded in order - * queue.loadManifest([ - * "script1.js", - * "script2.js", - * "image.png", // Load any time - * {src: "image2.png", maintainOrder: true} // Will wait for script2.js - * "image3.png", - * "script3.js" // Will wait for image2.png before loading (or completing when loading with XHR) - * ]); - * - * @property maintainScriptOrder - * @type {Boolean} - * @default true - */ - this.maintainScriptOrder = true; - - /** - * Determines if the LoadQueue will stop processing the current queue when an error is encountered. - * @property stopOnError - * @type {Boolean} - * @default false - */ - this.stopOnError = false; - - /** - * The number of maximum open connections that a loadQueue tries to maintain. Please see - * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} for more information. - * @property _maxConnections - * @type {Number} - * @default 1 - * @private - */ - this._maxConnections = 1; - - /** - * An internal list of all the default Loaders that are included with PreloadJS. Before an item is loaded, the - * available loader list is iterated, in the order they are included, and as soon as a loader indicates it can - * handle the content, it will be selected. The default loader, ({{#crossLink "TextLoader"}}{{/crossLink}} is - * last in the list, so it will be used if no other match is found. Typically, loaders will match based on the - * {{#crossLink "LoadItem/type"}}{{/crossLink}}, which is automatically determined using the file extension of - * the {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. - * - * Loaders can be removed from PreloadJS by simply not including them. - * - * Custom loaders installed using {{#crossLink "registerLoader"}}{{/crossLink}} will be prepended to this list - * so that they are checked first. - * @property _availableLoaders - * @type {Array} - * @private - * @since 0.6.0 - */ - this._availableLoaders = [ - createjs.ImageLoader, - createjs.JavaScriptLoader, - createjs.CSSLoader, - createjs.JSONLoader, - createjs.JSONPLoader, - createjs.SoundLoader, - createjs.ManifestLoader, - createjs.SpriteSheetLoader, - createjs.XMLLoader, - createjs.SVGLoader, - createjs.BinaryLoader, - createjs.VideoLoader, - createjs.TextLoader - ]; - - /** - * The number of built in loaders, so they can't be removed by {{#crossLink "unregisterLoader"}}{{/crossLink}. - * @property _defaultLoaderLength - * @type {Number} - * @private - * @since 0.6.0 - */ - this._defaultLoaderLength = this._availableLoaders.length; + * + * At any time after the file has been loaded (usually after the queue has completed), any result can be looked up + * via its "id" using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. If no id was provided, then the + * "src" or file path can be used instead, including the `path` defined by a manifest, but not including + * a base path defined on the LoadQueue. It is recommended to always pass an id if you want to look up content. + * + * var image = queue.getResult("image"); + * document.body.appendChild(image); + * + * Raw loaded content can be accessed using the rawResult property of the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} + * event, or can be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}, passing `true` as the 2nd + * argument. This is only applicable for content that has been parsed for the browser, specifically: JavaScript, + * CSS, XML, SVG, and JSON objects, or anything loaded with XHR. + * + * var image = queue.getResult("image", true); // load the binary image data loaded with XHR. + * + * Plugins
+ * LoadQueue has a simple plugin architecture to help process and preload content. For example, to preload audio, + * make sure to install the SoundJS Sound class, which will help load HTML audio, + * Flash audio, and WebAudio files. This should be installed before loading any audio files. + * + * queue.installPlugin(createjs.Sound); + * + *

Known Browser Issues

+ *
    + *
  • Browsers without audio support can not load audio files.
  • + *
  • Safari on Mac OS X can only play HTML audio if QuickTime is installed
  • + *
  • HTML Audio tags will only download until their canPlayThrough event is fired. Browsers other + * than Chrome will continue to download in the background.
  • + *
  • When loading scripts using tags, they are automatically added to the document.
  • + *
  • Scripts loaded via XHR may not be properly inspectable with browser tools.
  • + *
  • IE6 and IE7 (and some other browsers) may not be able to load XML, Text, or JSON, since they require + * XHR to work.
  • + *
  • Content loaded via tags will not show progress, and will continue to download in the background when + * canceled, although no events will be dispatched.
  • + *
+ * + * @class LoadQueue + * @param {Boolean} [preferXHR=true] Determines whether the preload instance will favor loading with XHR (XML HTTP + * Requests), or HTML tags. When this is `false`, the queue will use tag loading when possible, and fall back on XHR + * when necessary. + * @param {String} [basePath=""] A path that will be prepended on to the source parameter of all items in the queue + * before they are loaded. Sources beginning with a protocol such as `http://` or a relative path such as `../` + * will not receive a base path. + * @param {String|Boolean} [crossOrigin=""] An optional flag to support images loaded from a CORS-enabled server. To + * use it, set this value to `true`, which will default the crossOrigin property on images to "Anonymous". Any + * string value will be passed through, but only "" and "Anonymous" are recommended. Note: The crossOrigin + * parameter is deprecated. Use LoadItem.crossOrigin instead + * + * @constructor + * @extends AbstractLoader + */ - this.init(preferXHR, basePath, crossOrigin); - } +var ImageLoader = require('./loaders/ImageLoader'); +var extend = require('../createjs/utils/extend'); +var promote = require('../createjs/utils/promote'); +var AbstractLoader = require('./loaders/AbstractLoader'); +var Event = require('../createjs/events/Event'); +var ErrorEvent = require('../createjs/events/ErrorEvent'); +var RequestUtils = require('./utils/RequestUtils'); +var LoadItem = require('./data/LoadItem'); - var p = createjs.extend(LoadQueue, createjs.AbstractLoader); - var s = LoadQueue; +function LoadQueue(preferXHR, basePath, crossOrigin) { + this.AbstractLoader_constructor(); /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated + * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}. + * @property _plugins + * @type {Array} + * @private + * @since 0.6.1 */ - // p.initialize = function() {}; // searchable for devs wondering where it is. + this._plugins = []; /** - * An internal initialization method, which is used for initial set up, but also to reset the LoadQueue. - * @method init - * @param preferXHR - * @param basePath - * @param crossOrigin + * An object hash of callbacks that are fired for each file type before the file is loaded, giving plugins the + * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} + * method for more information. + * @property _typeCallbacks + * @type {Object} * @private */ - p.init = function (preferXHR, basePath, crossOrigin) { - - // public properties - /** - * @property useXHR - * @type {Boolean} - * @readonly - * @default true - * @deprecated Use preferXHR instead. - */ - this.useXHR = true; - - /** - * Try and use XMLHttpRequest (XHR) when possible. Note that LoadQueue will default to tag loading or XHR - * loading depending on the requirements for a media type. For example, HTML audio can not be loaded with XHR, - * and plain text can not be loaded with tags, so it will default the the correct type instead of using the - * user-defined type. - * @type {Boolean} - * @default true - * @since 0.6.0 - */ - this.preferXHR = true; //TODO: Get/Set - this._preferXHR = true; - this.setPreferXHR(preferXHR); - - // protected properties - /** - * Whether the queue is currently paused or not. - * @property _paused - * @type {boolean} - * @private - */ - this._paused = false; - - /** - * A path that will be prepended on to the item's {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. The - * `_basePath` property will only be used if an item's source is relative, and does not include a protocol such - * as `http://`, or a relative path such as `../`. - * @property _basePath - * @type {String} - * @private - * @since 0.3.1 - */ - this._basePath = basePath; - - /** - * An optional flag to set on images that are loaded using PreloadJS, which enables CORS support. Images loaded - * cross-domain by servers that support CORS require the crossOrigin flag to be loaded and interacted with by - * a canvas. When loading locally, or with a server with no CORS support, this flag can cause other security issues, - * so it is recommended to only set it if you are sure the server supports it. Currently, supported values are "" - * and "Anonymous". - * @property _crossOrigin - * @type {String} - * @default "" - * @private - * @since 0.4.1 - */ - this._crossOrigin = crossOrigin; - - /** - * Determines if the loadStart event was dispatched already. This event is only fired one time, when the first - * file is requested. - * @property _loadStartWasDispatched - * @type {Boolean} - * @default false - * @private - */ - this._loadStartWasDispatched = false; - - /** - * Determines if there is currently a script loading. This helps ensure that only a single script loads at once when - * using a script tag to do preloading. - * @property _currentlyLoadingScript - * @type {Boolean} - * @private - */ - this._currentlyLoadingScript = null; - - /** - * An array containing the currently downloading files. - * @property _currentLoads - * @type {Array} - * @private - */ - this._currentLoads = []; - - /** - * An array containing the queued items that have not yet started downloading. - * @property _loadQueue - * @type {Array} - * @private - */ - this._loadQueue = []; - - /** - * An array containing downloads that have not completed, so that the LoadQueue can be properly reset. - * @property _loadQueueBackup - * @type {Array} - * @private - */ - this._loadQueueBackup = []; - - /** - * An object hash of items that have finished downloading, indexed by the {{#crossLink "LoadItem"}}{{/crossLink}} - * id. - * @property _loadItemsById - * @type {Object} - * @private - */ - this._loadItemsById = {}; - - /** - * An object hash of items that have finished downloading, indexed by {{#crossLink "LoadItem"}}{{/crossLink}} - * source. - * @property _loadItemsBySrc - * @type {Object} - * @private - */ - this._loadItemsBySrc = {}; - - /** - * An object hash of loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. - * @property _loadedResults - * @type {Object} - * @private - */ - this._loadedResults = {}; - - /** - * An object hash of un-parsed loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. - * @property _loadedRawResults - * @type {Object} - * @private - */ - this._loadedRawResults = {}; - - /** - * The number of items that have been requested. This helps manage an overall progress without knowing how large - * the files are before they are downloaded. This does not include items inside of loaders such as the - * {{#crossLink "ManifestLoader"}}{{/crossLink}}. - * @property _numItems - * @type {Number} - * @default 0 - * @private - */ - this._numItems = 0; - - /** - * The number of items that have completed loaded. This helps manage an overall progress without knowing how large - * the files are before they are downloaded. - * @property _numItemsLoaded - * @type {Number} - * @default 0 - * @private - */ - this._numItemsLoaded = 0; - - /** - * A list of scripts in the order they were requested. This helps ensure that scripts are "completed" in the right - * order. - * @property _scriptOrder - * @type {Array} - * @private - */ - this._scriptOrder = []; - - /** - * A list of scripts that have been loaded. Items are added to this list as null when they are - * requested, contain the loaded item if it has completed, but not been dispatched to the user, and true - * once they are complete and have been dispatched. - * @property _loadedScripts - * @type {Array} - * @private - */ - this._loadedScripts = []; - - /** - * The last progress amount. This is used to suppress duplicate progress events. - * @property _lastProgress - * @type {Number} - * @private - * @since 0.6.0 - */ - this._lastProgress = NaN; - - }; + this._typeCallbacks = {}; -// static properties /** - * The time in milliseconds to assume a load has failed. An {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} - * event is dispatched if the timeout is reached before any data is received. - * @property loadTimeout - * @type {Number} - * @default 8000 - * @static - * @since 0.4.1 - * @deprecated In favour of {{#crossLink "LoadItem/LOAD_TIMEOUT_DEFAULT:property}}{{/crossLink}} property. + * An object hash of callbacks that are fired for each file extension before the file is loaded, giving plugins the + * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} + * method for more information. + * @property _extensionCallbacks + * @type {null} + * @private */ - s.loadTimeout = 8000; + this._extensionCallbacks = {}; /** - * The time in milliseconds to assume a load has failed. - * @property LOAD_TIMEOUT - * @type {Number} - * @default 0 - * @deprecated in favor of the {{#crossLink "LoadQueue/loadTimeout:property"}}{{/crossLink}} property. + * The next preload queue to process when this one is complete. If an error is thrown in the current queue, and + * {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} is `true`, the next queue will not be processed. + * @property next + * @type {LoadQueue} + * @default null */ - s.LOAD_TIMEOUT = 0; + this.next = null; -// Preload Types /** - * @property BINARY - * @type {String} - * @default binary - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}} instead. + * Ensure loaded scripts "complete" in the order they are specified. Loaded scripts are added to the document head + * once they are loaded. Scripts loaded via tags will load one-at-a-time when this property is `true`, whereas + * scripts loaded using XHR can load in any order, but will "finish" and be added to the document in the order + * specified. + * + * Any items can be set to load in order by setting the {{#crossLink "maintainOrder:property"}}{{/crossLink}} + * property on the load item, or by ensuring that only one connection can be open at a time using + * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Note that when the `maintainScriptOrder` property + * is set to `true`, scripts items are automatically set to `maintainOrder=true`, and changing the + * `maintainScriptOrder` to `false` during a load will not change items already in a queue. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.setMaxConnections(3); // Set a higher number to load multiple items at once + * queue.maintainScriptOrder = true; // Ensure scripts are loaded in order + * queue.loadManifest([ + * "script1.js", + * "script2.js", + * "image.png", // Load any time + * {src: "image2.png", maintainOrder: true} // Will wait for script2.js + * "image3.png", + * "script3.js" // Will wait for image2.png before loading (or completing when loading with XHR) + * ]); + * + * @property maintainScriptOrder + * @type {Boolean} + * @default true */ - s.BINARY = createjs.AbstractLoader.BINARY; + this.maintainScriptOrder = true; /** - * @property CSS - * @type {String} - * @default css - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. + * Determines if the LoadQueue will stop processing the current queue when an error is encountered. + * @property stopOnError + * @type {Boolean} + * @default false */ - s.CSS = createjs.AbstractLoader.CSS; + this.stopOnError = false; /** - * @property IMAGE - * @type {String} - * @default image - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. + * The number of maximum open connections that a loadQueue tries to maintain. Please see + * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} for more information. + * @property _maxConnections + * @type {Number} + * @default 1 + * @private */ - s.IMAGE = createjs.AbstractLoader.IMAGE; + this._maxConnections = 1; /** - * @property JAVASCRIPT - * @type {String} - * @default javascript - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + * An internal list of all the default Loaders that are included with PreloadJS. Before an item is loaded, the + * available loader list is iterated, in the order they are included, and as soon as a loader indicates it can + * handle the content, it will be selected. The default loader, ({{#crossLink "TextLoader"}}{{/crossLink}} is + * last in the list, so it will be used if no other match is found. Typically, loaders will match based on the + * {{#crossLink "LoadItem/type"}}{{/crossLink}}, which is automatically determined using the file extension of + * the {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. + * + * Loaders can be removed from PreloadJS by simply not including them. + * + * Custom loaders installed using {{#crossLink "registerLoader"}}{{/crossLink}} will be prepended to this list + * so that they are checked first. + * @property _availableLoaders + * @type {Array} + * @private + * @since 0.6.0 */ - s.JAVASCRIPT = createjs.AbstractLoader.JAVASCRIPT; + this._availableLoaders = [ + ImageLoader + /*, + createjs.JavaScriptLoader, + createjs.CSSLoader, + createjs.JSONLoader, + createjs.JSONPLoader, + createjs.SoundLoader, + createjs.ManifestLoader, + createjs.SpriteSheetLoader, + createjs.XMLLoader, + createjs.SVGLoader, + createjs.BinaryLoader, + createjs.VideoLoader, + createjs.TextLoader + */ + ]; /** - * @property JSON - * @type {String} - * @default json - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}} instead. + * The number of built in loaders, so they can't be removed by {{#crossLink "unregisterLoader"}}{{/crossLink}. + * @property _defaultLoaderLength + * @type {Number} + * @private + * @since 0.6.0 */ - s.JSON = createjs.AbstractLoader.JSON; + this._defaultLoaderLength = this._availableLoaders.length; + + this.init(preferXHR, basePath, crossOrigin); +} + +var p = extend(LoadQueue, AbstractLoader); +var s = LoadQueue; + +/** + * REMOVED. Removed in favor of using `MySuperClass_constructor`. + * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} + * for details. + * + * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. + * + * @method initialize + * @protected + * @deprecated + */ +// p.initialize = function() {}; // searchable for devs wondering where it is. +/** + * An internal initialization method, which is used for initial set up, but also to reset the LoadQueue. + * @method init + * @param preferXHR + * @param basePath + * @param crossOrigin + * @private + */ +p.init = function (preferXHR, basePath, crossOrigin) { + + // public properties /** - * @property JSONP - * @type {String} - * @default jsonp - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}} instead. + * @property useXHR + * @type {Boolean} + * @readonly + * @default true + * @deprecated Use preferXHR instead. */ - s.JSONP = createjs.AbstractLoader.JSONP; + this.useXHR = true; /** - * @property MANIFEST - * @type {String} - * @default manifest - * @static - * @since 0.4.1 - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}} instead. + * Try and use XMLHttpRequest (XHR) when possible. Note that LoadQueue will default to tag loading or XHR + * loading depending on the requirements for a media type. For example, HTML audio can not be loaded with XHR, + * and plain text can not be loaded with tags, so it will default the the correct type instead of using the + * user-defined type. + * @type {Boolean} + * @default true + * @since 0.6.0 */ - s.MANIFEST = createjs.AbstractLoader.MANIFEST; + this.preferXHR = true; //TODO: Get/Set + this._preferXHR = true; + this.setPreferXHR(preferXHR); + // protected properties /** - * @property SOUND - * @type {String} - * @default sound - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + * Whether the queue is currently paused or not. + * @property _paused + * @type {boolean} + * @private */ - s.SOUND = createjs.AbstractLoader.SOUND; + this._paused = false; /** - * @property VIDEO + * A path that will be prepended on to the item's {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. The + * `_basePath` property will only be used if an item's source is relative, and does not include a protocol such + * as `http://`, or a relative path such as `../`. + * @property _basePath * @type {String} - * @default video - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + * @private + * @since 0.3.1 */ - s.VIDEO = createjs.AbstractLoader.VIDEO; + this._basePath = basePath; /** - * @property SVG + * An optional flag to set on images that are loaded using PreloadJS, which enables CORS support. Images loaded + * cross-domain by servers that support CORS require the crossOrigin flag to be loaded and interacted with by + * a canvas. When loading locally, or with a server with no CORS support, this flag can cause other security issues, + * so it is recommended to only set it if you are sure the server supports it. Currently, supported values are "" + * and "Anonymous". + * @property _crossOrigin * @type {String} - * @default svg - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}} instead. + * @default "" + * @private + * @since 0.4.1 */ - s.SVG = createjs.AbstractLoader.SVG; + this._crossOrigin = crossOrigin; /** - * @property TEXT - * @type {String} - * @default text - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}} instead. + * Determines if the loadStart event was dispatched already. This event is only fired one time, when the first + * file is requested. + * @property _loadStartWasDispatched + * @type {Boolean} + * @default false + * @private */ - s.TEXT = createjs.AbstractLoader.TEXT; + this._loadStartWasDispatched = false; /** - * @property XML - * @type {String} - * @default xml - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}} instead. + * Determines if there is currently a script loading. This helps ensure that only a single script loads at once when + * using a script tag to do preloading. + * @property _currentlyLoadingScript + * @type {Boolean} + * @private */ - s.XML = createjs.AbstractLoader.XML; + this._currentlyLoadingScript = null; /** - * @property POST - * @type {string} - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} instead. + * An array containing the currently downloading files. + * @property _currentLoads + * @type {Array} + * @private */ - s.POST = createjs.AbstractLoader.POST; + this._currentLoads = []; /** - * @property GET - * @type {string} - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} instead. + * An array containing the queued items that have not yet started downloading. + * @property _loadQueue + * @type {Array} + * @private */ - s.GET = createjs.AbstractLoader.GET; + this._loadQueue = []; -// events /** - * This event is fired when an individual file has loaded, and been processed. - * @event fileload - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the - * object will contain that value as a `src` property. - * @param {Object} result The HTML tag or parsed result of the loaded item. - * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted - * to a usable object. - * @since 0.3.0 + * An array containing downloads that have not completed, so that the LoadQueue can be properly reset. + * @property _loadQueueBackup + * @type {Array} + * @private */ + this._loadQueueBackup = []; /** - * This {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when an an individual file's progress changes. - * @event fileprogress - * @since 0.3.0 + * An object hash of items that have finished downloading, indexed by the {{#crossLink "LoadItem"}}{{/crossLink}} + * id. + * @property _loadItemsById + * @type {Object} + * @private */ + this._loadItemsById = {}; /** - * This event is fired when an individual file starts to load. - * @event filestart - * @param {Object} The object that dispatched the event. - * @param {String} type The event type. - * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the - * object will contain that value as a property. + * An object hash of items that have finished downloading, indexed by {{#crossLink "LoadItem"}}{{/crossLink}} + * source. + * @property _loadItemsBySrc + * @type {Object} + * @private */ + this._loadItemsBySrc = {}; /** - * Although it extends {{#crossLink "AbstractLoader"}}{{/crossLink}}, the `initialize` event is never fired from - * a LoadQueue instance. - * @event initialize + * An object hash of loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. + * @property _loadedResults + * @type {Object} * @private */ + this._loadedResults = {}; -// public methods /** - * Register a custom loaders class. New loaders are given precedence over loaders added earlier and default loaders. - * It is recommended that loaders extend {{#crossLink "AbstractLoader"}}{{/crossLink}}. Loaders can only be added - * once, and will be prepended to the list of available loaders. - * @method registerLoader - * @param {Function|AbstractLoader} loader The AbstractLoader class to add. - * @since 0.6.0 + * An object hash of un-parsed loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. + * @property _loadedRawResults + * @type {Object} + * @private */ - p.registerLoader = function (loader) { - if (!loader || !loader.canLoadItem) { - throw new Error("loader is of an incorrect type."); - } else if (this._availableLoaders.indexOf(loader) != -1) { - throw new Error("loader already exists."); //LM: Maybe just silently fail here - } - - this._availableLoaders.unshift(loader); - }; + this._loadedRawResults = {}; /** - * Remove a custom loader added using {{#crossLink "registerLoader"}}{{/crossLink}}. Only custom loaders can be - * unregistered, the default loaders will always be available. - * @method unregisterLoader - * @param {Function|AbstractLoader} loader The AbstractLoader class to remove + * The number of items that have been requested. This helps manage an overall progress without knowing how large + * the files are before they are downloaded. This does not include items inside of loaders such as the + * {{#crossLink "ManifestLoader"}}{{/crossLink}}. + * @property _numItems + * @type {Number} + * @default 0 + * @private */ - p.unregisterLoader = function (loader) { - var idx = this._availableLoaders.indexOf(loader); - if (idx != -1 && idx < this._defaultLoaderLength - 1) { - this._availableLoaders.splice(idx, 1); - } - }; + this._numItems = 0; /** - * @method setUseXHR - * @param {Boolean} value The new useXHR value to set. - * @return {Boolean} The new useXHR value. If XHR is not supported by the browser, this will return false, even if - * the provided value argument was true. - * @since 0.3.0 - * @deprecated use the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property, or the - * {{#crossLink "LoadQueue/setUseXHR"}}{{/crossLink}} method instead. + * The number of items that have completed loaded. This helps manage an overall progress without knowing how large + * the files are before they are downloaded. + * @property _numItemsLoaded + * @type {Number} + * @default 0 + * @private */ - p.setUseXHR = function (value) { - return this.setPreferXHR(value); - }; + this._numItemsLoaded = 0; /** - * Change the {{#crossLink "preferXHR:property"}}{{/crossLink}} value. Note that if this is set to `true`, it may - * fail, or be ignored depending on the browser's capabilities and the load type. - * @method setPreferXHR - * @param {Boolean} value - * @returns {Boolean} The value of {{#crossLink "preferXHR"}}{{/crossLink}} that was successfully set. - * @since 0.6.0 + * A list of scripts in the order they were requested. This helps ensure that scripts are "completed" in the right + * order. + * @property _scriptOrder + * @type {Array} + * @private */ - p.setPreferXHR = function (value) { - // Determine if we can use XHR. XHR defaults to TRUE, but the browser may not support it. - //TODO: Should we be checking for the other XHR types? Might have to do a try/catch on the different types similar to createXHR. - this.preferXHR = (value != false && window.XMLHttpRequest != null); - return this.preferXHR; - }; + this._scriptOrder = []; /** - * Stops all queued and loading items, and clears the queue. This also removes all internal references to loaded - * content, and allows the queue to be used again. - * @method removeAll - * @since 0.3.0 + * A list of scripts that have been loaded. Items are added to this list as null when they are + * requested, contain the loaded item if it has completed, but not been dispatched to the user, and true + * once they are complete and have been dispatched. + * @property _loadedScripts + * @type {Array} + * @private */ - p.removeAll = function () { - this.remove(); - }; + this._loadedScripts = []; /** - * Stops an item from being loaded, and removes it from the queue. If nothing is passed, all items are removed. - * This also removes internal references to loaded item(s). - * - *

Example

- * - * queue.loadManifest([ - * {src:"test.png", id:"png"}, - * {src:"test.jpg", id:"jpg"}, - * {src:"test.mp3", id:"mp3"} - * ]); - * queue.remove("png"); // Single item by ID - * queue.remove("png", "test.jpg"); // Items as arguments. Mixed id and src. - * queue.remove(["test.png", "jpg"]); // Items in an Array. Mixed id and src. - * - * @method remove - * @param {String | Array} idsOrUrls* The id or ids to remove from this queue. You can pass an item, an array of - * items, or multiple items as arguments. - * @since 0.3.0 + * The last progress amount. This is used to suppress duplicate progress events. + * @property _lastProgress + * @type {Number} + * @private + * @since 0.6.0 */ - p.remove = function (idsOrUrls) { - var args = null; - - if (idsOrUrls && !Array.isArray(idsOrUrls)) { - args = [idsOrUrls]; - } else if (idsOrUrls) { - args = idsOrUrls; - } else if (arguments.length > 0) { - return; - } + this._lastProgress = NaN; - var itemsWereRemoved = false; +}; - // Destroy everything - if (!args) { - this.close(); - for (var n in this._loadItemsById) { - this._disposeItem(this._loadItemsById[n]); - } - this.init(this.preferXHR, this._basePath); +// static properties +/** + * The time in milliseconds to assume a load has failed. An {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} + * event is dispatched if the timeout is reached before any data is received. + * @property loadTimeout + * @type {Number} + * @default 8000 + * @static + * @since 0.4.1 + * @deprecated In favour of {{#crossLink "LoadItem/LOAD_TIMEOUT_DEFAULT:property}}{{/crossLink}} property. + */ +s.loadTimeout = 8000; - // Remove specific items - } else { - while (args.length) { - var item = args.pop(); - var r = this.getResult(item); +/** + * The time in milliseconds to assume a load has failed. + * @property LOAD_TIMEOUT + * @type {Number} + * @default 0 + * @deprecated in favor of the {{#crossLink "LoadQueue/loadTimeout:property"}}{{/crossLink}} property. + */ +s.LOAD_TIMEOUT = 0; - //Remove from the main load Queue - for (i = this._loadQueue.length - 1; i >= 0; i--) { - loadItem = this._loadQueue[i].getItem(); - if (loadItem.id == item || loadItem.src == item) { - this._loadQueue.splice(i, 1)[0].cancel(); - break; - } - } +// Preload Types +/** + * @property BINARY + * @type {String} + * @default binary + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}} instead. + */ +s.BINARY = AbstractLoader.BINARY; - //Remove from the backup queue - for (i = this._loadQueueBackup.length - 1; i >= 0; i--) { - loadItem = this._loadQueueBackup[i].getItem(); - if (loadItem.id == item || loadItem.src == item) { - this._loadQueueBackup.splice(i, 1)[0].cancel(); - break; - } - } +/** + * @property CSS + * @type {String} + * @default css + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. + */ +s.CSS = AbstractLoader.CSS; - if (r) { - this._disposeItem(this.getItem(item)); - } else { - for (var i = this._currentLoads.length - 1; i >= 0; i--) { - var loadItem = this._currentLoads[i].getItem(); - if (loadItem.id == item || loadItem.src == item) { - this._currentLoads.splice(i, 1)[0].cancel(); - itemsWereRemoved = true; - break; - } - } - } - } +/** + * @property IMAGE + * @type {String} + * @default image + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. + */ +s.IMAGE = AbstractLoader.IMAGE; - // If this was called during a load, try to load the next item. - if (itemsWereRemoved) { - this._loadNext(); - } - } - }; +/** + * @property JAVASCRIPT + * @type {String} + * @default javascript + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ +s.JAVASCRIPT = AbstractLoader.JAVASCRIPT; - /** - * Stops all open loads, destroys any loaded items, and resets the queue, so all items can - * be reloaded again by calling {{#crossLink "AbstractLoader/load"}}{{/crossLink}}. Items are not removed from the - * queue. To remove items use the {{#crossLink "LoadQueue/remove"}}{{/crossLink}} or - * {{#crossLink "LoadQueue/removeAll"}}{{/crossLink}} method. - * @method reset - * @since 0.3.0 - */ - p.reset = function () { - this.close(); - for (var n in this._loadItemsById) { - this._disposeItem(this._loadItemsById[n]); - } +/** + * @property JSON + * @type {String} + * @default json + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}} instead. + */ +s.JSON = AbstractLoader.JSON; - //Reset the queue to its start state - var a = []; - for (var i = 0, l = this._loadQueueBackup.length; i < l; i++) { - a.push(this._loadQueueBackup[i].getItem()); - } +/** + * @property JSONP + * @type {String} + * @default jsonp + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}} instead. + */ +s.JSONP = AbstractLoader.JSONP; - this.loadManifest(a, false); - }; +/** + * @property MANIFEST + * @type {String} + * @default manifest + * @static + * @since 0.4.1 + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}} instead. + */ +s.MANIFEST = AbstractLoader.MANIFEST; - /** - * Register a plugin. Plugins can map to load types (sound, image, etc), or specific extensions (png, mp3, etc). - * Currently, only one plugin can exist per type/extension. - * - * When a plugin is installed, a getPreloadHandlers() method will be called on it. For more information - * on this method, check out the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method in the - * {{#crossLink "SamplePlugin"}}{{/crossLink}} class. - * - * Before a file is loaded, a matching plugin has an opportunity to modify the load. If a `callback` is returned - * from the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method, it will be invoked first, and its - * result may cancel or modify the item. The callback method can also return a `completeHandler` to be fired when - * the file is loaded, or a `tag` object, which will manage the actual download. For more information on these - * methods, check out the {{#crossLink "SamplePlugin/preloadHandler"}}{{/crossLink}} and {{#crossLink "SamplePlugin/fileLoadHandler"}}{{/crossLink}} - * methods on the {{#crossLink "SamplePlugin"}}{{/crossLink}}. - * - * @method installPlugin - * @param {Function} plugin The plugin class to install. - */ - p.installPlugin = function (plugin) { - if (plugin == null) { - return; - } +/** + * @property SOUND + * @type {String} + * @default sound + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ +s.SOUND = AbstractLoader.SOUND; - if (plugin.getPreloadHandlers != null) { - this._plugins.push(plugin); - var map = plugin.getPreloadHandlers(); - map.scope = plugin; +/** + * @property VIDEO + * @type {String} + * @default video + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. + */ +s.VIDEO = AbstractLoader.VIDEO; - if (map.types != null) { - for (var i = 0, l = map.types.length; i < l; i++) { - this._typeCallbacks[map.types[i]] = map; - } - } +/** + * @property SVG + * @type {String} + * @default svg + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}} instead. + */ +s.SVG = AbstractLoader.SVG; - if (map.extensions != null) { - for (i = 0, l = map.extensions.length; i < l; i++) { - this._extensionCallbacks[map.extensions[i]] = map; - } - } - } - }; +/** + * @property TEXT + * @type {String} + * @default text + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}} instead. + */ +s.TEXT = AbstractLoader.TEXT; - /** - * Set the maximum number of concurrent connections. Note that browsers and servers may have a built-in maximum - * number of open connections, so any additional connections may remain in a pending state until the browser - * opens the connection. When loading scripts using tags, and when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} - * is `true`, only one script is loaded at a time due to browser limitations. - * - *

Example

- * - * var queue = new createjs.LoadQueue(); - * queue.setMaxConnections(10); // Allow 10 concurrent loads - * - * @method setMaxConnections - * @param {Number} value The number of concurrent loads to allow. By default, only a single connection per LoadQueue - * is open at any time. - */ - p.setMaxConnections = function (value) { - this._maxConnections = value; - if (!this._paused && this._loadQueue.length > 0) { - this._loadNext(); - } - }; +/** + * @property XML + * @type {String} + * @default xml + * @static + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}} instead. + */ +s.XML = AbstractLoader.XML; - /** - * Load a single file. To add multiple files at once, use the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} - * method. - * - * Files are always appended to the current queue, so this method can be used multiple times to add files. - * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. - * @method loadFile - * @param {LoadItem|Object|String} file The file object or path to load. A file can be either - *
    - *
  • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
  • - *
  • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
  • - *
  • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} - * in the background.
  • - *
- * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default - * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}}, and the value is - * `true`, the queue will resume automatically. - * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the - * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}, - * its files will NOT use the basePath parameter. The basePath parameter is deprecated. - * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue - * constructor, or a `path` property in a manifest definition. - */ - p.loadFile = function (file, loadNow, basePath) { - if (file == null) { - var event = new createjs.ErrorEvent("PRELOAD_NO_FILE"); - this._sendError(event); - return; - } - this._addItem(file, null, basePath); +/** + * @property POST + * @type {string} + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} instead. + */ +s.POST = AbstractLoader.POST; - if (loadNow !== false) { - this.setPaused(false); - } else { - this.setPaused(true); - } - }; +/** + * @property GET + * @type {string} + * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} instead. + */ +s.GET = AbstractLoader.GET; - /** - * Load an array of files. To load a single file, use the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} method. - * The files in the manifest are requested in the same order, but may complete in a different order if the max - * connections are set above 1 using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Scripts will load - * in the right order as long as {{#crossLink "LoadQueue/maintainScriptOrder"}}{{/crossLink}} is true (which is - * default). - * - * Files are always appended to the current queue, so this method can be used multiple times to add files. - * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. - * @method loadManifest - * @param {Array|String|Object} manifest An list of files to load. The loadManifest call supports four types of - * manifests: - *
    - *
  1. A string path, which points to a manifest file, which is a JSON file that contains a "manifest" property, - * which defines the list of files to load, and can optionally contain a "path" property, which will be - * prepended to each file in the list.
  2. - *
  3. An object which defines a "src", which is a JSON or JSONP file. A "callback" can be defined for JSONP - * file. The JSON/JSONP file should contain a "manifest" property, which defines the list of files to load, - * and can optionally contain a "path" property, which will be prepended to each file in the list.
  4. - *
  5. An object which contains a "manifest" property, which defines the list of files to load, and can - * optionally contain a "path" property, which will be prepended to each file in the list.
  6. - *
  7. An Array of files to load.
  8. - *
- * - * Each "file" in a manifest can be either: - *
    - *
  • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
  • - *
  • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
  • - *
  • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} - * in the background.
  • - *
- * - * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default - * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} and this value is - * `true`, the queue will resume automatically. - * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the - * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "LoadQueue/MANIFEST:property"}}{{/crossLink}}, - * its files will NOT use the basePath parameter. The basePath parameter is deprecated. - * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue - * constructor, or a `path` property in a manifest definition. - */ - p.loadManifest = function (manifest, loadNow, basePath) { - var fileList = null; - var path = null; - - // Array-based list of items - if (Array.isArray(manifest)) { - if (manifest.length == 0) { - var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_EMPTY"); - this._sendError(event); - return; - } - fileList = manifest; - - // String-based. Only file manifests can be specified this way. Any other types will cause an error when loaded. - } else if (typeof(manifest) === "string") { - fileList = [ - { - src: manifest, - type: s.MANIFEST - } - ]; +// events +/** + * This event is fired when an individual file has loaded, and been processed. + * @event fileload + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a `src` property. + * @param {Object} result The HTML tag or parsed result of the loaded item. + * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted + * to a usable object. + * @since 0.3.0 + */ - } else if (typeof(manifest) == "object") { +/** + * This {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when an an individual file's progress changes. + * @event fileprogress + * @since 0.3.0 + */ - // An object that defines a manifest path - if (manifest.src !== undefined) { - if (manifest.type == null) { - manifest.type = s.MANIFEST; - } else if (manifest.type != s.MANIFEST) { - var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_TYPE"); - this._sendError(event); - } - fileList = [manifest]; +/** + * This event is fired when an individual file starts to load. + * @event filestart + * @param {Object} The object that dispatched the event. + * @param {String} type The event type. + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a property. + */ - // An object that defines a manifest - } else if (manifest.manifest !== undefined) { - fileList = manifest.manifest; - path = manifest.path; - } +/** + * Although it extends {{#crossLink "AbstractLoader"}}{{/crossLink}}, the `initialize` event is never fired from + * a LoadQueue instance. + * @event initialize + * @private + */ - // Unsupported. This will throw an error. - } else { - var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_NULL"); - this._sendError(event); - return; - } - - for (var i = 0, l = fileList.length; i < l; i++) { - this._addItem(fileList[i], path, basePath); - } +// public methods +/** + * Register a custom loaders class. New loaders are given precedence over loaders added earlier and default loaders. + * It is recommended that loaders extend {{#crossLink "AbstractLoader"}}{{/crossLink}}. Loaders can only be added + * once, and will be prepended to the list of available loaders. + * @method registerLoader + * @param {Function|AbstractLoader} loader The AbstractLoader class to add. + * @since 0.6.0 + */ +p.registerLoader = function (loader) { + if (!loader || !loader.canLoadItem) { + throw new Error("loader is of an incorrect type."); + } else if (this._availableLoaders.indexOf(loader) != -1) { + throw new Error("loader already exists."); //LM: Maybe just silently fail here + } - if (loadNow !== false) { - this.setPaused(false); - } else { - this.setPaused(true); - } + this._availableLoaders.unshift(loader); +}; - }; +/** + * Remove a custom loader added using {{#crossLink "registerLoader"}}{{/crossLink}}. Only custom loaders can be + * unregistered, the default loaders will always be available. + * @method unregisterLoader + * @param {Function|AbstractLoader} loader The AbstractLoader class to remove + */ +p.unregisterLoader = function (loader) { + var idx = this._availableLoaders.indexOf(loader); + if (idx != -1 && idx < this._defaultLoaderLength - 1) { + this._availableLoaders.splice(idx, 1); + } +}; - /** - * Start a LoadQueue that was created, but not automatically started. - * @method load - */ - p.load = function () { - this.setPaused(false); - }; +/** + * @method setUseXHR + * @param {Boolean} value The new useXHR value to set. + * @return {Boolean} The new useXHR value. If XHR is not supported by the browser, this will return false, even if + * the provided value argument was true. + * @since 0.3.0 + * @deprecated use the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property, or the + * {{#crossLink "LoadQueue/setUseXHR"}}{{/crossLink}} method instead. + */ +p.setUseXHR = function (value) { + return this.setPreferXHR(value); +}; - /** - * Look up a {{#crossLink "LoadItem"}}{{/crossLink}} using either the "id" or "src" that was specified when loading it. Note that if no "id" was - * supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The - * `basePath` will not be part of the ID. - * @method getItem - * @param {String} value The id or src of the load item. - * @return {Object} The load item that was initially requested using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} - * event as the `item` parameter. - */ - p.getItem = function (value) { - return this._loadItemsById[value] || this._loadItemsBySrc[value]; - }; +/** + * Change the {{#crossLink "preferXHR:property"}}{{/crossLink}} value. Note that if this is set to `true`, it may + * fail, or be ignored depending on the browser's capabilities and the load type. + * @method setPreferXHR + * @param {Boolean} value + * @returns {Boolean} The value of {{#crossLink "preferXHR"}}{{/crossLink}} that was successfully set. + * @since 0.6.0 + */ +p.setPreferXHR = function (value) { + // Determine if we can use XHR. XHR defaults to TRUE, but the browser may not support it. + //TODO: Should we be checking for the other XHR types? Might have to do a try/catch on the different types similar to createXHR. + this.preferXHR = (value != false && window.XMLHttpRequest != null); + return this.preferXHR; +}; - /** - * Look up a loaded result using either the "id" or "src" that was specified when loading it. Note that if no "id" - * was supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The - * `basePath` will not be part of the ID. - * @method getResult - * @param {String} value The id or src of the load item. - * @param {Boolean} [rawResult=false] Return a raw result instead of a formatted result. This applies to content - * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be - * returned instead. - * @return {Object} A result object containing the content that was loaded, such as: - *
    - *
  • An image tag (<image />) for images
  • - *
  • A script tag for JavaScript (<script />). Note that scripts are automatically added to the HTML - * DOM.
  • - *
  • A style tag for CSS (<style /> or <link >)
  • - *
  • Raw text for TEXT
  • - *
  • A formatted JavaScript object defined by JSON
  • - *
  • An XML document
  • - *
  • A binary arraybuffer loaded by XHR
  • - *
  • An audio tag (<audio >) for HTML audio. Note that it is recommended to use SoundJS APIs to play - * loaded audio. Specifically, audio loaded by Flash and WebAudio will return a loader object using this method - * which can not be used to play audio back.
  • - *
- * This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event as the 'item` - * parameter. Note that if a raw result is requested, but not found, the result will be returned instead. - */ - p.getResult = function (value, rawResult) { - var item = this._loadItemsById[value] || this._loadItemsBySrc[value]; - if (item == null) { - return null; - } - var id = item.id; - if (rawResult && this._loadedRawResults[id]) { - return this._loadedRawResults[id]; - } - return this._loadedResults[id]; - }; +/** + * Stops all queued and loading items, and clears the queue. This also removes all internal references to loaded + * content, and allows the queue to be used again. + * @method removeAll + * @since 0.3.0 + */ +p.removeAll = function () { + this.remove(); +}; - /** - * Generate an list of items loaded by this queue. - * @method getItems - * @param {Boolean} loaded Determines if only items that have been loaded should be returned. If false, in-progress - * and failed load items will also be included. - * @returns {Array} A list of objects that have been loaded. Each item includes the {{#crossLink "LoadItem"}}{{/crossLink}}, - * result, and rawResult. - * @since 0.6.0 - */ - p.getItems = function (loaded) { - var arr = []; - for (var n in this._loadItemsById) { - var item = this._loadItemsById[n]; - var result = this.getResult(n); - if (loaded === true && result == null) { - continue; - } - arr.push({ - item: item, - result: result, - rawResult: this.getResult(n, true) - }); - } - return arr; - }; +/** + * Stops an item from being loaded, and removes it from the queue. If nothing is passed, all items are removed. + * This also removes internal references to loaded item(s). + * + *

Example

+ * + * queue.loadManifest([ + * {src:"test.png", id:"png"}, + * {src:"test.jpg", id:"jpg"}, + * {src:"test.mp3", id:"mp3"} + * ]); + * queue.remove("png"); // Single item by ID + * queue.remove("png", "test.jpg"); // Items as arguments. Mixed id and src. + * queue.remove(["test.png", "jpg"]); // Items in an Array. Mixed id and src. + * + * @method remove + * @param {String | Array} idsOrUrls* The id or ids to remove from this queue. You can pass an item, an array of + * items, or multiple items as arguments. + * @since 0.3.0 + */ +p.remove = function (idsOrUrls) { + var args = null; + + if (idsOrUrls && !Array.isArray(idsOrUrls)) { + args = [idsOrUrls]; + } else if (idsOrUrls) { + args = idsOrUrls; + } else if (arguments.length > 0) { + return; + } - /** - * Pause or resume the current load. Active loads will not be cancelled, but the next items in the queue will not - * be processed when active loads complete. LoadQueues are not paused by default. - * - * Note that if new items are added to the queue using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or - * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}, a paused queue will be resumed, unless the `loadNow` - * argument is `false`. - * @method setPaused - * @param {Boolean} value Whether the queue should be paused or not. - */ - p.setPaused = function (value) { - this._paused = value; - if (!this._paused) { - this._loadNext(); - } - }; + var itemsWereRemoved = false; - /** - * Close the active queue. Closing a queue completely empties the queue, and prevents any remaining items from - * starting to download. Note that currently any active loads will remain open, and events may be processed. - * - * To stop and restart a queue, use the {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} method instead. - * @method close - */ - p.close = function () { - while (this._currentLoads.length) { - this._currentLoads.pop().cancel(); + // Destroy everything + if (!args) { + this.close(); + for (var n in this._loadItemsById) { + this._disposeItem(this._loadItemsById[n]); } - this._scriptOrder.length = 0; - this._loadedScripts.length = 0; - this.loadStartWasDispatched = false; - this._itemCount = 0; - this._lastProgress = NaN; - }; - -// protected methods - /** - * Add an item to the queue. Items are formatted into a usable object containing all the properties necessary to - * load the content. The load queue is populated with the loader instance that handles preloading, and not the load - * item that was passed in by the user. To look up the load item by id or src, use the {{#crossLink "LoadQueue.getItem"}}{{/crossLink}} - * method. - * @method _addItem - * @param {String|Object} value The item to add to the queue. - * @param {String} [path] An optional path prepended to the `src`. The path will only be prepended if the src is - * relative, and does not start with a protocol such as `http://`, or a path like `../`. If the LoadQueue was - * provided a {{#crossLink "_basePath"}}{{/crossLink}}, then it will optionally be prepended after. - * @param {String} [basePath] DeprecatedAn optional basePath passed into a {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} call. This parameter will be removed in a future tagged - * version. - * @private - */ - p._addItem = function (value, path, basePath) { - var item = this._createLoadItem(value, path, basePath); // basePath and manifest path are added to the src. - if (item == null) { - return; - } // Sometimes plugins or types should be skipped. - var loader = this._createLoader(item); - if (loader != null) { - if ("plugins" in loader) { - loader.plugins = this._plugins; - } - item._loader = loader; - this._loadQueue.push(loader); - this._loadQueueBackup.push(loader); - - this._numItems++; - this._updateProgress(); - - // Only worry about script order when using XHR to load scripts. Tags are only loading one at a time. - if ((this.maintainScriptOrder - && item.type == createjs.LoadQueue.JAVASCRIPT - //&& loader instanceof createjs.XHRLoader //NOTE: Have to track all JS files this way - ) - || item.maintainOrder === true) { - this._scriptOrder.push(item); - this._loadedScripts.push(null); + this.init(this.preferXHR, this._basePath); + + // Remove specific items + } else { + while (args.length) { + var item = args.pop(); + var r = this.getResult(item); + + //Remove from the main load Queue + for (i = this._loadQueue.length - 1; i >= 0; i--) { + loadItem = this._loadQueue[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._loadQueue.splice(i, 1)[0].cancel(); + break; + } } - } - }; - - /** - * Create a refined {{#crossLink "LoadItem"}}{{/crossLink}}, which contains all the required properties. The type of - * item is determined by browser support, requirements based on the file type, and developer settings. For example, - * XHR is only used for file types that support it in new browsers. - * - * Before the item is returned, any plugins registered to handle the type or extension will be fired, which may - * alter the load item. - * @method _createLoadItem - * @param {String | Object | HTMLAudioElement | HTMLImageElement} value The item that needs to be preloaded. - * @param {String} [path] A path to prepend to the item's source. Sources beginning with http:// or similar will - * not receive a path. Since PreloadJS 0.4.1, the src will be modified to include the `path` and {{#crossLink "LoadQueue/_basePath:property"}}{{/crossLink}} - * when it is added. - * @param {String} [basePath] Deprectated A base path to prepend to the items source in addition to - * the path argument. - * @return {Object} The loader instance that will be used. - * @private - */ - p._createLoadItem = function (value, path, basePath) { - var item = createjs.LoadItem.create(value); - if (item == null) { - return null; - } - var bp = ""; // Store the generated basePath - var useBasePath = basePath || this._basePath; - - if (item.src instanceof Object) { - if (!item.type) { - return null; - } // the the src is an object, type is required to pass off to plugin - if (path) { - bp = path; - var pathMatch = createjs.RequestUtils.parseURI(path); - // Also append basePath - if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { - bp = useBasePath + bp; + //Remove from the backup queue + for (i = this._loadQueueBackup.length - 1; i >= 0; i--) { + loadItem = this._loadQueueBackup[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._loadQueueBackup.splice(i, 1)[0].cancel(); + break; } - } else if (useBasePath != null) { - bp = useBasePath; - } - } else { - // Determine Extension, etc. - var match = createjs.RequestUtils.parseURI(item.src); - if (match.extension) { - item.ext = match.extension; - } - if (item.type == null) { - item.type = createjs.RequestUtils.getTypeByExtension(item.ext); } - // Inject path & basePath - var autoId = item.src; - if (!match.absolute && !match.relative) { - if (path) { - bp = path; - var pathMatch = createjs.RequestUtils.parseURI(path); - autoId = path + autoId; - // Also append basePath - if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { - bp = useBasePath + bp; + if (r) { + this._disposeItem(this.getItem(item)); + } else { + for (var i = this._currentLoads.length - 1; i >= 0; i--) { + var loadItem = this._currentLoads[i].getItem(); + if (loadItem.id == item || loadItem.src == item) { + this._currentLoads.splice(i, 1)[0].cancel(); + itemsWereRemoved = true; + break; } - } else if (useBasePath != null) { - bp = useBasePath; } } - item.src = bp + item.src; } - item.path = bp; - // If there's no id, set one now. - if (item.id === undefined || item.id === null || item.id === "") { - item.id = autoId; + // If this was called during a load, try to load the next item. + if (itemsWereRemoved) { + this._loadNext(); } + } +}; + +/** + * Stops all open loads, destroys any loaded items, and resets the queue, so all items can + * be reloaded again by calling {{#crossLink "AbstractLoader/load"}}{{/crossLink}}. Items are not removed from the + * queue. To remove items use the {{#crossLink "LoadQueue/remove"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/removeAll"}}{{/crossLink}} method. + * @method reset + * @since 0.3.0 + */ +p.reset = function () { + this.close(); + for (var n in this._loadItemsById) { + this._disposeItem(this._loadItemsById[n]); + } - // Give plugins a chance to modify the loadItem: - var customHandler = this._typeCallbacks[item.type] || this._extensionCallbacks[item.ext]; - if (customHandler) { - // Plugins are now passed both the full source, as well as a combined path+basePath (appropriately) - var result = customHandler.callback.call(customHandler.scope, item, this); + //Reset the queue to its start state + var a = []; + for (var i = 0, l = this._loadQueueBackup.length; i < l; i++) { + a.push(this._loadQueueBackup[i].getItem()); + } + + this.loadManifest(a, false); +}; - // The plugin will handle the load, or has canceled it. Ignore it. - if (result === false) { - return null; +/** + * Register a plugin. Plugins can map to load types (sound, image, etc), or specific extensions (png, mp3, etc). + * Currently, only one plugin can exist per type/extension. + * + * When a plugin is installed, a getPreloadHandlers() method will be called on it. For more information + * on this method, check out the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method in the + * {{#crossLink "SamplePlugin"}}{{/crossLink}} class. + * + * Before a file is loaded, a matching plugin has an opportunity to modify the load. If a `callback` is returned + * from the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method, it will be invoked first, and its + * result may cancel or modify the item. The callback method can also return a `completeHandler` to be fired when + * the file is loaded, or a `tag` object, which will manage the actual download. For more information on these + * methods, check out the {{#crossLink "SamplePlugin/preloadHandler"}}{{/crossLink}} and {{#crossLink "SamplePlugin/fileLoadHandler"}}{{/crossLink}} + * methods on the {{#crossLink "SamplePlugin"}}{{/crossLink}}. + * + * @method installPlugin + * @param {Function} plugin The plugin class to install. + */ +p.installPlugin = function (plugin) { + if (plugin == null) { + return; + } - // Load as normal: - } else if (result === true) { - // Do Nothing + if (plugin.getPreloadHandlers != null) { + this._plugins.push(plugin); + var map = plugin.getPreloadHandlers(); + map.scope = plugin; - // Result is a loader class: - } else if (result != null) { - item._loader = result; + if (map.types != null) { + for (var i = 0, l = map.types.length; i < l; i++) { + this._typeCallbacks[map.types[i]] = map; } + } - // Update the extension in case the type changed: - match = createjs.RequestUtils.parseURI(item.src); - if (match.extension != null) { - item.ext = match.extension; + if (map.extensions != null) { + for (i = 0, l = map.extensions.length; i < l; i++) { + this._extensionCallbacks[map.extensions[i]] = map; } } + } +}; - // Store the item for lookup. This also helps clean-up later. - this._loadItemsById[item.id] = item; - this._loadItemsBySrc[item.src] = item; +/** + * Set the maximum number of concurrent connections. Note that browsers and servers may have a built-in maximum + * number of open connections, so any additional connections may remain in a pending state until the browser + * opens the connection. When loading scripts using tags, and when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} + * is `true`, only one script is loaded at a time due to browser limitations. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.setMaxConnections(10); // Allow 10 concurrent loads + * + * @method setMaxConnections + * @param {Number} value The number of concurrent loads to allow. By default, only a single connection per LoadQueue + * is open at any time. + */ +p.setMaxConnections = function (value) { + this._maxConnections = value; + if (!this._paused && this._loadQueue.length > 0) { + this._loadNext(); + } +}; - if (item.crossOrigin == null) { - item.crossOrigin = this._crossOrigin; - } +/** + * Load a single file. To add multiple files at once, use the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * method. + * + * Files are always appended to the current queue, so this method can be used multiple times to add files. + * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. + * @method loadFile + * @param {LoadItem|Object|String} file The file object or path to load. A file can be either + *
    + *
  • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
  • + *
  • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
  • + *
  • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} + * in the background.
  • + *
+ * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default + * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}}, and the value is + * `true`, the queue will resume automatically. + * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the + * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}, + * its files will NOT use the basePath parameter. The basePath parameter is deprecated. + * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue + * constructor, or a `path` property in a manifest definition. + */ +p.loadFile = function (file, loadNow, basePath) { + if (file == null) { + var event = new ErrorEvent("PRELOAD_NO_FILE"); + this._sendError(event); + return; + } + this._addItem(file, null, basePath); - return item; - }; + if (loadNow !== false) { + this.setPaused(false); + } else { + this.setPaused(true); + } +}; - /** - * Create a loader for a load item. - * @method _createLoader - * @param {Object} item A formatted load item that can be used to generate a loader. - * @return {AbstractLoader} A loader that can be used to load content. - * @private - */ - p._createLoader = function (item) { - if (item._loader != null) { // A plugin already specified a loader - return item._loader; +/** + * Load an array of files. To load a single file, use the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} method. + * The files in the manifest are requested in the same order, but may complete in a different order if the max + * connections are set above 1 using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Scripts will load + * in the right order as long as {{#crossLink "LoadQueue/maintainScriptOrder"}}{{/crossLink}} is true (which is + * default). + * + * Files are always appended to the current queue, so this method can be used multiple times to add files. + * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. + * @method loadManifest + * @param {Array|String|Object} manifest An list of files to load. The loadManifest call supports four types of + * manifests: + *
    + *
  1. A string path, which points to a manifest file, which is a JSON file that contains a "manifest" property, + * which defines the list of files to load, and can optionally contain a "path" property, which will be + * prepended to each file in the list.
  2. + *
  3. An object which defines a "src", which is a JSON or JSONP file. A "callback" can be defined for JSONP + * file. The JSON/JSONP file should contain a "manifest" property, which defines the list of files to load, + * and can optionally contain a "path" property, which will be prepended to each file in the list.
  4. + *
  5. An object which contains a "manifest" property, which defines the list of files to load, and can + * optionally contain a "path" property, which will be prepended to each file in the list.
  6. + *
  7. An Array of files to load.
  8. + *
+ * + * Each "file" in a manifest can be either: + *
    + *
  • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
  • + *
  • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
  • + *
  • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} + * in the background.
  • + *
+ * + * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default + * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} and this value is + * `true`, the queue will resume automatically. + * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the + * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "LoadQueue/MANIFEST:property"}}{{/crossLink}}, + * its files will NOT use the basePath parameter. The basePath parameter is deprecated. + * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue + * constructor, or a `path` property in a manifest definition. + */ +p.loadManifest = function (manifest, loadNow, basePath) { + var fileList = null; + var path = null; + + // Array-based list of items + if (Array.isArray(manifest)) { + if (manifest.length == 0) { + var event = new ErrorEvent("PRELOAD_MANIFEST_EMPTY"); + this._sendError(event); + return; } + fileList = manifest; + + // String-based. Only file manifests can be specified this way. Any other types will cause an error when loaded. + } else if (typeof(manifest) === "string") { + fileList = [ + { + src: manifest, + type: s.MANIFEST + } + ]; - // Initially, try and use the provided/supported XHR mode: - var preferXHR = this.preferXHR; + } else if (typeof(manifest) == "object") { - for (var i = 0; i < this._availableLoaders.length; i++) { - var loader = this._availableLoaders[i]; - if (loader && loader.canLoadItem(item)) { - return new loader(item, preferXHR); + // An object that defines a manifest path + if (manifest.src !== undefined) { + if (manifest.type == null) { + manifest.type = s.MANIFEST; + } else if (manifest.type != s.MANIFEST) { + var event = new ErrorEvent("PRELOAD_MANIFEST_TYPE"); + this._sendError(event); } + fileList = [manifest]; + + // An object that defines a manifest + } else if (manifest.manifest !== undefined) { + fileList = manifest.manifest; + path = manifest.path; } - // TODO: Log error (requires createjs.log) + // Unsupported. This will throw an error. + } else { + var event = new ErrorEvent("PRELOAD_MANIFEST_NULL"); + this._sendError(event); + return; + } + + for (var i = 0, l = fileList.length; i < l; i++) { + this._addItem(fileList[i], path, basePath); + } + + if (loadNow !== false) { + this.setPaused(false); + } else { + this.setPaused(true); + } + +}; + +/** + * Start a LoadQueue that was created, but not automatically started. + * @method load + */ +p.load = function () { + this.setPaused(false); +}; + +/** + * Look up a {{#crossLink "LoadItem"}}{{/crossLink}} using either the "id" or "src" that was specified when loading it. Note that if no "id" was + * supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The + * `basePath` will not be part of the ID. + * @method getItem + * @param {String} value The id or src of the load item. + * @return {Object} The load item that was initially requested using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} + * event as the `item` parameter. + */ +p.getItem = function (value) { + return this._loadItemsById[value] || this._loadItemsBySrc[value]; +}; + +/** + * Look up a loaded result using either the "id" or "src" that was specified when loading it. Note that if no "id" + * was supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The + * `basePath` will not be part of the ID. + * @method getResult + * @param {String} value The id or src of the load item. + * @param {Boolean} [rawResult=false] Return a raw result instead of a formatted result. This applies to content + * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be + * returned instead. + * @return {Object} A result object containing the content that was loaded, such as: + *
    + *
  • An image tag (<image />) for images
  • + *
  • A script tag for JavaScript (<script />). Note that scripts are automatically added to the HTML + * DOM.
  • + *
  • A style tag for CSS (<style /> or <link >)
  • + *
  • Raw text for TEXT
  • + *
  • A formatted JavaScript object defined by JSON
  • + *
  • An XML document
  • + *
  • A binary arraybuffer loaded by XHR
  • + *
  • An audio tag (<audio >) for HTML audio. Note that it is recommended to use SoundJS APIs to play + * loaded audio. Specifically, audio loaded by Flash and WebAudio will return a loader object using this method + * which can not be used to play audio back.
  • + *
+ * This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event as the 'item` + * parameter. Note that if a raw result is requested, but not found, the result will be returned instead. + */ +p.getResult = function (value, rawResult) { + var item = this._loadItemsById[value] || this._loadItemsBySrc[value]; + if (item == null) { return null; - }; + } + var id = item.id; + if (rawResult && this._loadedRawResults[id]) { + return this._loadedRawResults[id]; + } + return this._loadedResults[id]; +}; - /** - * Load the next item in the queue. If the queue is empty (all items have been loaded), then the complete event - * is processed. The queue will "fill up" any empty slots, up to the max connection specified using - * {{#crossLink "LoadQueue.setMaxConnections"}}{{/crossLink}} method. The only exception is scripts that are loaded - * using tags, which have to be loaded one at a time to maintain load order. - * @method _loadNext - * @private - */ - p._loadNext = function () { - if (this._paused) { - return; +/** + * Generate an list of items loaded by this queue. + * @method getItems + * @param {Boolean} loaded Determines if only items that have been loaded should be returned. If false, in-progress + * and failed load items will also be included. + * @returns {Array} A list of objects that have been loaded. Each item includes the {{#crossLink "LoadItem"}}{{/crossLink}}, + * result, and rawResult. + * @since 0.6.0 + */ +p.getItems = function (loaded) { + var arr = []; + for (var n in this._loadItemsById) { + var item = this._loadItemsById[n]; + var result = this.getResult(n); + if (loaded === true && result == null) { + continue; } + arr.push({ + item: item, + result: result, + rawResult: this.getResult(n, true) + }); + } + return arr; +}; + +/** + * Pause or resume the current load. Active loads will not be cancelled, but the next items in the queue will not + * be processed when active loads complete. LoadQueues are not paused by default. + * + * Note that if new items are added to the queue using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}, a paused queue will be resumed, unless the `loadNow` + * argument is `false`. + * @method setPaused + * @param {Boolean} value Whether the queue should be paused or not. + */ +p.setPaused = function (value) { + this._paused = value; + if (!this._paused) { + this._loadNext(); + } +}; + +/** + * Close the active queue. Closing a queue completely empties the queue, and prevents any remaining items from + * starting to download. Note that currently any active loads will remain open, and events may be processed. + * + * To stop and restart a queue, use the {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} method instead. + * @method close + */ +p.close = function () { + while (this._currentLoads.length) { + this._currentLoads.pop().cancel(); + } + this._scriptOrder.length = 0; + this._loadedScripts.length = 0; + this.loadStartWasDispatched = false; + this._itemCount = 0; + this._lastProgress = NaN; +}; - // Only dispatch loadstart event when the first file is loaded. - if (!this._loadStartWasDispatched) { - this._sendLoadStart(); - this._loadStartWasDispatched = true; +// protected methods +/** + * Add an item to the queue. Items are formatted into a usable object containing all the properties necessary to + * load the content. The load queue is populated with the loader instance that handles preloading, and not the load + * item that was passed in by the user. To look up the load item by id or src, use the {{#crossLink "LoadQueue.getItem"}}{{/crossLink}} + * method. + * @method _addItem + * @param {String|Object} value The item to add to the queue. + * @param {String} [path] An optional path prepended to the `src`. The path will only be prepended if the src is + * relative, and does not start with a protocol such as `http://`, or a path like `../`. If the LoadQueue was + * provided a {{#crossLink "_basePath"}}{{/crossLink}}, then it will optionally be prepended after. + * @param {String} [basePath] DeprecatedAn optional basePath passed into a {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} call. This parameter will be removed in a future tagged + * version. + * @private + */ +p._addItem = function (value, path, basePath) { + var item = this._createLoadItem(value, path, basePath); // basePath and manifest path are added to the src. + if (item == null) { + return; + } // Sometimes plugins or types should be skipped. + var loader = this._createLoader(item); + if (loader != null) { + if ("plugins" in loader) { + loader.plugins = this._plugins; } + item._loader = loader; + this._loadQueue.push(loader); + this._loadQueueBackup.push(loader); - // The queue has completed. - if (this._numItems == this._numItemsLoaded) { - this.loaded = true; - this._sendComplete(); + this._numItems++; + this._updateProgress(); - // Load the next queue, if it has been defined. - if (this.next && this.next.load) { - this.next.load(); - } - } else { - this.loaded = false; + // Only worry about script order when using XHR to load scripts. Tags are only loading one at a time. + if ((this.maintainScriptOrder + && item.type == LoadQueue.JAVASCRIPT + //&& loader instanceof createjs.XHRLoader //NOTE: Have to track all JS files this way + ) + || item.maintainOrder === true) { + this._scriptOrder.push(item); + this._loadedScripts.push(null); } + } +}; + +/** + * Create a refined {{#crossLink "LoadItem"}}{{/crossLink}}, which contains all the required properties. The type of + * item is determined by browser support, requirements based on the file type, and developer settings. For example, + * XHR is only used for file types that support it in new browsers. + * + * Before the item is returned, any plugins registered to handle the type or extension will be fired, which may + * alter the load item. + * @method _createLoadItem + * @param {String | Object | HTMLAudioElement | HTMLImageElement} value The item that needs to be preloaded. + * @param {String} [path] A path to prepend to the item's source. Sources beginning with http:// or similar will + * not receive a path. Since PreloadJS 0.4.1, the src will be modified to include the `path` and {{#crossLink "LoadQueue/_basePath:property"}}{{/crossLink}} + * when it is added. + * @param {String} [basePath] Deprectated A base path to prepend to the items source in addition to + * the path argument. + * @return {Object} The loader instance that will be used. + * @private + */ +p._createLoadItem = function (value, path, basePath) { + var item = LoadItem.create(value); + if (item == null) { + return null; + } - // Must iterate forwards to load in the right order. - for (var i = 0; i < this._loadQueue.length; i++) { - if (this._currentLoads.length >= this._maxConnections) { - break; + var bp = ""; // Store the generated basePath + var useBasePath = basePath || this._basePath; + + if (item.src instanceof Object) { + if (!item.type) { + return null; + } // the the src is an object, type is required to pass off to plugin + if (path) { + bp = path; + var pathMatch = RequestUtils.parseURI(path); + // Also append basePath + if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { + bp = useBasePath + bp; } - var loader = this._loadQueue[i]; + } else if (useBasePath != null) { + bp = useBasePath; + } + } else { + // Determine Extension, etc. + var match = RequestUtils.parseURI(item.src); + if (match.extension) { + item.ext = match.extension; + } + if (item.type == null) { + item.type = RequestUtils.getTypeByExtension(item.ext); + } - // Determine if we should be only loading one tag-script at a time: - // Note: maintainOrder items don't do anything here because we can hold onto their loaded value - if (!this._canStartLoad(loader)) { - continue; + // Inject path & basePath + var autoId = item.src; + if (!match.absolute && !match.relative) { + if (path) { + bp = path; + var pathMatch = RequestUtils.parseURI(path); + autoId = path + autoId; + // Also append basePath + if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { + bp = useBasePath + bp; + } + } else if (useBasePath != null) { + bp = useBasePath; } - this._loadQueue.splice(i, 1); - i--; - this._loadItem(loader); } - }; + item.src = bp + item.src; + } + item.path = bp; - /** - * Begin loading an item. Event listeners are not added to the loaders until the load starts. - * @method _loadItem - * @param {AbstractLoader} loader The loader instance to start. Currently, this will be an XHRLoader or TagLoader. - * @private - */ - p._loadItem = function (loader) { - loader.on("fileload", this._handleFileLoad, this); - loader.on("progress", this._handleProgress, this); - loader.on("complete", this._handleFileComplete, this); - loader.on("error", this._handleError, this); - loader.on("fileerror", this._handleFileError, this); - this._currentLoads.push(loader); - this._sendFileStart(loader.getItem()); - loader.load(); - }; + // If there's no id, set one now. + if (item.id === undefined || item.id === null || item.id === "") { + item.id = autoId; + } - /** - * The callback that is fired when a loader loads a file. This enables loaders like {{#crossLink "ManifestLoader"}}{{/crossLink}} - * to maintain internal queues, but for this queue to dispatch the {{#crossLink "fileload:event"}}{{/crossLink}} - * events. - * @param {Event} event The {{#crossLink "AbstractLoader/fileload:event"}}{{/crossLink}} event from the loader. - * @private - * @since 0.6.0 - */ - p._handleFileLoad = function (event) { - event.target = null; - this.dispatchEvent(event); - }; + // Give plugins a chance to modify the loadItem: + var customHandler = this._typeCallbacks[item.type] || this._extensionCallbacks[item.ext]; + if (customHandler) { + // Plugins are now passed both the full source, as well as a combined path+basePath (appropriately) + var result = customHandler.callback.call(customHandler.scope, item, this); - /** - * The callback that is fired when a loader encounters an error from an internal file load operation. This enables - * loaders like M - * @param event - * @private - */ - p._handleFileError = function (event) { - var newEvent = new createjs.ErrorEvent("FILE_LOAD_ERROR", null, event.item); - this._sendError(newEvent); - }; + // The plugin will handle the load, or has canceled it. Ignore it. + if (result === false) { + return null; - /** - * The callback that is fired when a loader encounters an error. The queue will continue loading unless {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} - * is set to `true`. - * @method _handleError - * @param {ErrorEvent} event The error event, containing relevant error information. - * @private - */ - p._handleError = function (event) { - var loader = event.target; - this._numItemsLoaded++; + // Load as normal: + } else if (result === true) { + // Do Nothing - this._finishOrderedItem(loader, true); - this._updateProgress(); + // Result is a loader class: + } else if (result != null) { + item._loader = result; + } - var newEvent = new createjs.ErrorEvent("FILE_LOAD_ERROR", null, loader.getItem()); - // TODO: Propagate actual error message. + // Update the extension in case the type changed: + match = RequestUtils.parseURI(item.src); + if (match.extension != null) { + item.ext = match.extension; + } + } - this._sendError(newEvent); + // Store the item for lookup. This also helps clean-up later. + this._loadItemsById[item.id] = item; + this._loadItemsBySrc[item.src] = item; - if (!this.stopOnError) { - this._removeLoadItem(loader); - this._cleanLoadItem(loader); - this._loadNext(); - } else { - this.setPaused(true); - } - }; + if (item.crossOrigin == null) { + item.crossOrigin = this._crossOrigin; + } - /** - * An item has finished loading. We can assume that it is totally loaded, has been parsed for immediate use, and - * is available as the "result" property on the load item. The raw text result for a parsed item (such as JSON, XML, - * CSS, JavaScript, etc) is available as the "rawResult" property, and can also be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. - * @method _handleFileComplete - * @param {Event} event The event object from the loader. - * @private - */ - p._handleFileComplete = function (event) { - var loader = event.target; - var item = loader.getItem(); - - var result = loader.getResult(); - this._loadedResults[item.id] = result; - var rawResult = loader.getResult(true); - if (rawResult != null && rawResult !== result) { - this._loadedRawResults[item.id] = rawResult; - } + return item; +}; - this._saveLoadedItems(loader); +/** + * Create a loader for a load item. + * @method _createLoader + * @param {Object} item A formatted load item that can be used to generate a loader. + * @return {AbstractLoader} A loader that can be used to load content. + * @private + */ +p._createLoader = function (item) { + if (item._loader != null) { // A plugin already specified a loader + return item._loader; + } - // Remove the load item - this._removeLoadItem(loader); + // Initially, try and use the provided/supported XHR mode: + var preferXHR = this.preferXHR; - if (!this._finishOrderedItem(loader)) { - // The item was NOT managed, so process it now - this._processFinishedLoad(item, loader); + for (var i = 0; i < this._availableLoaders.length; i++) { + var loader = this._availableLoaders[i]; + if (loader && loader.canLoadItem(item)) { + return new loader(item, preferXHR); } + } - // Clean up the load item - this._cleanLoadItem(loader); - }; + // TODO: Log error (requires createjs.log) + return null; +}; - /** - * Some loaders might load additional content, other than the item they were passed (such as {{#crossLink "ManifestLoader"}}{{/crossLink}}). - * Any items exposed by the loader using {{#crossLink "AbstractLoader/getLoadItems"}}{{/crossLink}} are added to the - * LoadQueue's look-ups, including {{#crossLink "getItem"}}{{/crossLink}} and {{#crossLink "getResult"}}{{/crossLink}} - * methods. - * @method _saveLoadedItems - * @param {AbstractLoader} loader - * @protected - * @since 0.6.0 - */ - p._saveLoadedItems = function (loader) { - // TODO: Not sure how to handle this. Would be nice to expose the items. - // Loaders may load sub-items. This adds them to this queue - var list = loader.getLoadedItems(); - if (list === null) { - return; - } +/** + * Load the next item in the queue. If the queue is empty (all items have been loaded), then the complete event + * is processed. The queue will "fill up" any empty slots, up to the max connection specified using + * {{#crossLink "LoadQueue.setMaxConnections"}}{{/crossLink}} method. The only exception is scripts that are loaded + * using tags, which have to be loaded one at a time to maintain load order. + * @method _loadNext + * @private + */ +p._loadNext = function () { + if (this._paused) { + return; + } - for (var i = 0; i < list.length; i++) { - var item = list[i].item; + // Only dispatch loadstart event when the first file is loaded. + if (!this._loadStartWasDispatched) { + this._sendLoadStart(); + this._loadStartWasDispatched = true; + } - // Store item lookups - this._loadItemsBySrc[item.src] = item; - this._loadItemsById[item.id] = item; + // The queue has completed. + if (this._numItems == this._numItemsLoaded) { + this.loaded = true; + this._sendComplete(); - // Store loaded content - this._loadedResults[item.id] = list[i].result; - this._loadedRawResults[item.id] = list[i].rawResult; + // Load the next queue, if it has been defined. + if (this.next && this.next.load) { + this.next.load(); } - }; + } else { + this.loaded = false; + } - /** - * Flag an item as finished. If the item's order is being managed, then ensure that it is allowed to finish, and if - * so, trigger prior items to trigger as well. - * @method _finishOrderedItem - * @param {AbstractLoader} loader - * @param {Boolean} loadFailed - * @return {Boolean} If the item's order is being managed. This allows the caller to take an alternate - * behaviour if it is. - * @private - */ - p._finishOrderedItem = function (loader, loadFailed) { - var item = loader.getItem(); + // Must iterate forwards to load in the right order. + for (var i = 0; i < this._loadQueue.length; i++) { + if (this._currentLoads.length >= this._maxConnections) { + break; + } + var loader = this._loadQueue[i]; - if ((this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) - || item.maintainOrder) { + // Determine if we should be only loading one tag-script at a time: + // Note: maintainOrder items don't do anything here because we can hold onto their loaded value + if (!this._canStartLoad(loader)) { + continue; + } + this._loadQueue.splice(i, 1); + i--; + this._loadItem(loader); + } +}; - //TODO: Evaluate removal of the _currentlyLoadingScript - if (loader instanceof createjs.JavaScriptLoader) { - this._currentlyLoadingScript = false; - } +/** + * Begin loading an item. Event listeners are not added to the loaders until the load starts. + * @method _loadItem + * @param {AbstractLoader} loader The loader instance to start. Currently, this will be an XHRLoader or TagLoader. + * @private + */ +p._loadItem = function (loader) { + loader.on("fileload", this._handleFileLoad, this); + loader.on("progress", this._handleProgress, this); + loader.on("complete", this._handleFileComplete, this); + loader.on("error", this._handleError, this); + loader.on("fileerror", this._handleFileError, this); + this._currentLoads.push(loader); + this._sendFileStart(loader.getItem()); + loader.load(); +}; - var index = createjs.indexOf(this._scriptOrder, item); - if (index == -1) { - return false; - } // This loader no longer exists - this._loadedScripts[index] = (loadFailed === true) ? true : item; +/** + * The callback that is fired when a loader loads a file. This enables loaders like {{#crossLink "ManifestLoader"}}{{/crossLink}} + * to maintain internal queues, but for this queue to dispatch the {{#crossLink "fileload:event"}}{{/crossLink}} + * events. + * @param {Event} event The {{#crossLink "AbstractLoader/fileload:event"}}{{/crossLink}} event from the loader. + * @private + * @since 0.6.0 + */ +p._handleFileLoad = function (event) { + event.target = null; + this.dispatchEvent(event); +}; - this._checkScriptLoadOrder(); - return true; - } +/** + * The callback that is fired when a loader encounters an error from an internal file load operation. This enables + * loaders like M + * @param event + * @private + */ +p._handleFileError = function (event) { + var newEvent = new ErrorEvent("FILE_LOAD_ERROR", null, event.item); + this._sendError(newEvent); +}; - return false; - }; +/** + * The callback that is fired when a loader encounters an error. The queue will continue loading unless {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} + * is set to `true`. + * @method _handleError + * @param {ErrorEvent} event The error event, containing relevant error information. + * @private + */ +p._handleError = function (event) { + var loader = event.target; + this._numItemsLoaded++; - /** - * Ensure the scripts load and dispatch in the correct order. When using XHR, scripts are stored in an array in the - * order they were added, but with a "null" value. When they are completed, the value is set to the load item, - * and then when they are processed and dispatched, the value is set to `true`. This method simply - * iterates the array, and ensures that any loaded items that are not preceded by a `null` value are - * dispatched. - * @method _checkScriptLoadOrder - * @private - */ - p._checkScriptLoadOrder = function () { - var l = this._loadedScripts.length; - - for (var i = 0; i < l; i++) { - var item = this._loadedScripts[i]; - if (item === null) { - break; - } // This is still loading. Do not process further. - if (item === true) { - continue; - } // This has completed, and been processed. Move on. - - var loadItem = this._loadedResults[item.id]; - if (item.type == createjs.LoadQueue.JAVASCRIPT) { - // Append script tags to the head automatically. - createjs.DomUtils.appendToHead(loadItem); - } + this._finishOrderedItem(loader, true); + this._updateProgress(); - var loader = item._loader; - this._processFinishedLoad(item, loader); - this._loadedScripts[i] = true; - } - }; + var newEvent = new ErrorEvent("FILE_LOAD_ERROR", null, loader.getItem()); + // TODO: Propagate actual error message. - /** - * A file has completed loading, and the LoadQueue can move on. This triggers the complete event, and kick-starts - * the next item. - * @method _processFinishedLoad - * @param {LoadItem|Object} item - * @param {AbstractLoader} loader - * @protected - */ - p._processFinishedLoad = function (item, loader) { - this._numItemsLoaded++; - - // Since LoadQueue needs maintain order, we can't append scripts in the loader. - // So we do it here instead. Or in _checkScriptLoadOrder(); - if (!this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) { - var tag = loader.getTag(); - createjs.DomUtils.appendToHead(tag); - } + this._sendError(newEvent); - this._updateProgress(); - this._sendFileComplete(item, loader); + if (!this.stopOnError) { + this._removeLoadItem(loader); + this._cleanLoadItem(loader); this._loadNext(); - }; + } else { + this.setPaused(true); + } +}; - /** - * Ensure items with `maintainOrder=true` that are before the specified item have loaded. This only applies to - * JavaScript items that are being loaded with a TagLoader, since they have to be loaded and completed before - * the script can even be started, since it exist in the DOM while loading. - * @method _canStartLoad - * @param {AbstractLoader} loader The loader for the item - * @return {Boolean} Whether the item can start a load or not. - * @private - */ - p._canStartLoad = function (loader) { - if (!this.maintainScriptOrder || loader.preferXHR) { - return true; - } - var item = loader.getItem(); - if (item.type != createjs.LoadQueue.JAVASCRIPT) { - return true; +/** + * An item has finished loading. We can assume that it is totally loaded, has been parsed for immediate use, and + * is available as the "result" property on the load item. The raw text result for a parsed item (such as JSON, XML, + * CSS, JavaScript, etc) is available as the "rawResult" property, and can also be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. + * @method _handleFileComplete + * @param {Event} event The event object from the loader. + * @private + */ +p._handleFileComplete = function (event) { + var loader = event.target; + var item = loader.getItem(); + + var result = loader.getResult(); + this._loadedResults[item.id] = result; + var rawResult = loader.getResult(true); + if (rawResult != null && rawResult !== result) { + this._loadedRawResults[item.id] = rawResult; + } + + this._saveLoadedItems(loader); + + // Remove the load item + this._removeLoadItem(loader); + + if (!this._finishOrderedItem(loader)) { + // The item was NOT managed, so process it now + this._processFinishedLoad(item, loader); + } + + // Clean up the load item + this._cleanLoadItem(loader); +}; + +/** + * Some loaders might load additional content, other than the item they were passed (such as {{#crossLink "ManifestLoader"}}{{/crossLink}}). + * Any items exposed by the loader using {{#crossLink "AbstractLoader/getLoadItems"}}{{/crossLink}} are added to the + * LoadQueue's look-ups, including {{#crossLink "getItem"}}{{/crossLink}} and {{#crossLink "getResult"}}{{/crossLink}} + * methods. + * @method _saveLoadedItems + * @param {AbstractLoader} loader + * @protected + * @since 0.6.0 + */ +p._saveLoadedItems = function (loader) { + // TODO: Not sure how to handle this. Would be nice to expose the items. + // Loaders may load sub-items. This adds them to this queue + var list = loader.getLoadedItems(); + if (list === null) { + return; + } + + for (var i = 0; i < list.length; i++) { + var item = list[i].item; + + // Store item lookups + this._loadItemsBySrc[item.src] = item; + this._loadItemsById[item.id] = item; + + // Store loaded content + this._loadedResults[item.id] = list[i].result; + this._loadedRawResults[item.id] = list[i].rawResult; + } +}; + +/** + * Flag an item as finished. If the item's order is being managed, then ensure that it is allowed to finish, and if + * so, trigger prior items to trigger as well. + * @method _finishOrderedItem + * @param {AbstractLoader} loader + * @param {Boolean} loadFailed + * @return {Boolean} If the item's order is being managed. This allows the caller to take an alternate + * behaviour if it is. + * @private + */ +p._finishOrderedItem = function (loader, loadFailed) { + var item = loader.getItem(); + + if ((this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) + || item.maintainOrder) { + + //TODO: Evaluate removal of the _currentlyLoadingScript + if (loader instanceof createjs.JavaScriptLoader) { + this._currentlyLoadingScript = false; } - if (this._currentlyLoadingScript) { + + var index = createjs.indexOf(this._scriptOrder, item); + if (index == -1) { return false; - } + } // This loader no longer exists + this._loadedScripts[index] = (loadFailed === true) ? true : item; - var index = this._scriptOrder.indexOf(item); - var i = 0; - while (i < index) { - var checkItem = this._loadedScripts[i]; - if (checkItem == null) { - return false; - } - i++; - } - this._currentlyLoadingScript = true; + this._checkScriptLoadOrder(); return true; - }; + } - /** - * A load item is completed or was canceled, and needs to be removed from the LoadQueue. - * @method _removeLoadItem - * @param {AbstractLoader} loader A loader instance to remove. - * @private - */ - p._removeLoadItem = function (loader) { - var l = this._currentLoads.length; - for (var i = 0; i < l; i++) { - if (this._currentLoads[i] == loader) { - this._currentLoads.splice(i, 1); - break; - } - } - }; + return false; +}; - /** - * Remove unneeded references from a loader. - * - * @param loader - * @private - */ - p._cleanLoadItem = function(loader) { - var item = loader.getItem(); - if (item) { - delete item._loader; +/** + * Ensure the scripts load and dispatch in the correct order. When using XHR, scripts are stored in an array in the + * order they were added, but with a "null" value. When they are completed, the value is set to the load item, + * and then when they are processed and dispatched, the value is set to `true`. This method simply + * iterates the array, and ensures that any loaded items that are not preceded by a `null` value are + * dispatched. + * @method _checkScriptLoadOrder + * @private + */ +p._checkScriptLoadOrder = function () { + var l = this._loadedScripts.length; + + for (var i = 0; i < l; i++) { + var item = this._loadedScripts[i]; + if (item === null) { + break; + } // This is still loading. Do not process further. + if (item === true) { + continue; + } // This has completed, and been processed. Move on. + + var loadItem = this._loadedResults[item.id]; + if (item.type == createjs.LoadQueue.JAVASCRIPT) { + // Append script tags to the head automatically. + createjs.DomUtils.appendToHead(loadItem); } + + var loader = item._loader; + this._processFinishedLoad(item, loader); + this._loadedScripts[i] = true; } +}; - /** - * An item has dispatched progress. Propagate that progress, and update the LoadQueue's overall progress. - * @method _handleProgress - * @param {ProgressEvent} event The progress event from the item. - * @private - */ - p._handleProgress = function (event) { - var loader = event.target; - this._sendFileProgress(loader.getItem(), loader.progress); - this._updateProgress(); - }; +/** + * A file has completed loading, and the LoadQueue can move on. This triggers the complete event, and kick-starts + * the next item. + * @method _processFinishedLoad + * @param {LoadItem|Object} item + * @param {AbstractLoader} loader + * @protected + */ +p._processFinishedLoad = function (item, loader) { + this._numItemsLoaded++; + + // Since LoadQueue needs maintain order, we can't append scripts in the loader. + // So we do it here instead. Or in _checkScriptLoadOrder(); + if (!this.maintainScriptOrder && item.type == LoadQueue.JAVASCRIPT) { + var tag = loader.getTag(); + createjs.DomUtils.appendToHead(tag); + } - /** - * Overall progress has changed, so determine the new progress amount and dispatch it. This changes any time an - * item dispatches progress or completes. Note that since we don't always know the actual filesize of items before - * they are loaded. In this case, we define a "slot" for each item (1 item in 10 would get 10%), and then append - * loaded progress on top of the already-loaded items. - * - * For example, if 5/10 items have loaded, and item 6 is 20% loaded, the total progress would be: - *
    - *
  • 5/10 of the items in the queue (50%)
  • - *
  • plus 20% of item 6's slot (2%)
  • - *
  • equals 52%
  • - *
- * @method _updateProgress - * @private - */ - p._updateProgress = function () { - var loaded = this._numItemsLoaded / this._numItems; // Fully Loaded Progress - var remaining = this._numItems - this._numItemsLoaded; - if (remaining > 0) { - var chunk = 0; - for (var i = 0, l = this._currentLoads.length; i < l; i++) { - chunk += this._currentLoads[i].progress; - } - loaded += (chunk / remaining) * (remaining / this._numItems); + this._updateProgress(); + this._sendFileComplete(item, loader); + this._loadNext(); +}; + +/** + * Ensure items with `maintainOrder=true` that are before the specified item have loaded. This only applies to + * JavaScript items that are being loaded with a TagLoader, since they have to be loaded and completed before + * the script can even be started, since it exist in the DOM while loading. + * @method _canStartLoad + * @param {AbstractLoader} loader The loader for the item + * @return {Boolean} Whether the item can start a load or not. + * @private + */ +p._canStartLoad = function (loader) { + if (!this.maintainScriptOrder || loader.preferXHR) { + return true; + } + var item = loader.getItem(); + if (item.type != LoadQueue.JAVASCRIPT) { + return true; + } + if (this._currentlyLoadingScript) { + return false; + } + + var index = this._scriptOrder.indexOf(item); + var i = 0; + while (i < index) { + var checkItem = this._loadedScripts[i]; + if (checkItem == null) { + return false; } + i++; + } + this._currentlyLoadingScript = true; + return true; +}; - if (this._lastProgress != loaded) { - this._sendProgress(loaded); - this._lastProgress = loaded; +/** + * A load item is completed or was canceled, and needs to be removed from the LoadQueue. + * @method _removeLoadItem + * @param {AbstractLoader} loader A loader instance to remove. + * @private + */ +p._removeLoadItem = function (loader) { + var l = this._currentLoads.length; + for (var i = 0; i < l; i++) { + if (this._currentLoads[i] == loader) { + this._currentLoads.splice(i, 1); + break; } - }; + } +}; - /** - * Clean out item results, to free them from memory. Mainly, the loaded item and results are cleared from internal - * hashes. - * @method _disposeItem - * @param {LoadItem|Object} item The item that was passed in for preloading. - * @private - */ - p._disposeItem = function (item) { - delete this._loadedResults[item.id]; - delete this._loadedRawResults[item.id]; - delete this._loadItemsById[item.id]; - delete this._loadItemsBySrc[item.src]; - }; +/** + * Remove unneeded references from a loader. + * + * @param loader + * @private + */ +p._cleanLoadItem = function (loader) { + var item = loader.getItem(); + if (item) { + delete item._loader; + } +} - /** - * Dispatch a "fileprogress" {{#crossLink "Event"}}{{/crossLink}}. Please see the LoadQueue {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}} - * event for details on the event payload. - * @method _sendFileProgress - * @param {LoadItem|Object} item The item that is being loaded. - * @param {Number} progress The amount the item has been loaded (between 0 and 1). - * @protected - */ - p._sendFileProgress = function (item, progress) { - if (this._isCanceled() || this._paused) { - return; - } - if (!this.hasEventListener("fileprogress")) { - return; +/** + * An item has dispatched progress. Propagate that progress, and update the LoadQueue's overall progress. + * @method _handleProgress + * @param {ProgressEvent} event The progress event from the item. + * @private + */ +p._handleProgress = function (event) { + var loader = event.target; + this._sendFileProgress(loader.getItem(), loader.progress); + this._updateProgress(); +}; + +/** + * Overall progress has changed, so determine the new progress amount and dispatch it. This changes any time an + * item dispatches progress or completes. Note that since we don't always know the actual filesize of items before + * they are loaded. In this case, we define a "slot" for each item (1 item in 10 would get 10%), and then append + * loaded progress on top of the already-loaded items. + * + * For example, if 5/10 items have loaded, and item 6 is 20% loaded, the total progress would be: + *
    + *
  • 5/10 of the items in the queue (50%)
  • + *
  • plus 20% of item 6's slot (2%)
  • + *
  • equals 52%
  • + *
+ * @method _updateProgress + * @private + */ +p._updateProgress = function () { + var loaded = this._numItemsLoaded / this._numItems; // Fully Loaded Progress + var remaining = this._numItems - this._numItemsLoaded; + if (remaining > 0) { + var chunk = 0; + for (var i = 0, l = this._currentLoads.length; i < l; i++) { + chunk += this._currentLoads[i].progress; } + loaded += (chunk / remaining) * (remaining / this._numItems); + } - //LM: Rework ProgressEvent to support this? - var event = new createjs.Event("fileprogress"); - event.progress = progress; - event.loaded = progress; - event.total = 1; - event.item = item; + if (this._lastProgress != loaded) { + this._sendProgress(loaded); + this._lastProgress = loaded; + } +}; - this.dispatchEvent(event); - }; +/** + * Clean out item results, to free them from memory. Mainly, the loaded item and results are cleared from internal + * hashes. + * @method _disposeItem + * @param {LoadItem|Object} item The item that was passed in for preloading. + * @private + */ +p._disposeItem = function (item) { + delete this._loadedResults[item.id]; + delete this._loadedRawResults[item.id]; + delete this._loadItemsById[item.id]; + delete this._loadItemsBySrc[item.src]; +}; - /** - * Dispatch a fileload {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event for - * details on the event payload. - * @method _sendFileComplete - * @param {LoadItemObject} item The item that is being loaded. - * @param {AbstractLoader} loader - * @protected - */ - p._sendFileComplete = function (item, loader) { - if (this._isCanceled() || this._paused) { - return; - } +/** + * Dispatch a "fileprogress" {{#crossLink "Event"}}{{/crossLink}}. Please see the LoadQueue {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendFileProgress + * @param {LoadItem|Object} item The item that is being loaded. + * @param {Number} progress The amount the item has been loaded (between 0 and 1). + * @protected + */ +p._sendFileProgress = function (item, progress) { + if (this._isCanceled() || this._paused) { + return; + } + if (!this.hasEventListener("fileprogress")) { + return; + } - var event = new createjs.Event("fileload"); - event.loader = loader; - event.item = item; - event.result = this._loadedResults[item.id]; - event.rawResult = this._loadedRawResults[item.id]; + //LM: Rework ProgressEvent to support this? + var event = new Event("fileprogress"); + event.progress = progress; + event.loaded = progress; + event.total = 1; + event.item = item; - // This calls a handler specified on the actual load item. Currently, the SoundJS plugin uses this. - if (item.completeHandler) { - item.completeHandler(event); - } + this.dispatchEvent(event); +}; - this.hasEventListener("fileload") && this.dispatchEvent(event); - }; +/** + * Dispatch a fileload {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event for + * details on the event payload. + * @method _sendFileComplete + * @param {LoadItemObject} item The item that is being loaded. + * @param {AbstractLoader} loader + * @protected + */ +p._sendFileComplete = function (item, loader) { + if (this._isCanceled() || this._paused) { + return; + } - /** - * Dispatch a filestart {{#crossLink "Event"}}{{/crossLink}} immediately before a file starts to load. Please see - * the {{#crossLink "LoadQueue/filestart:event"}}{{/crossLink}} event for details on the event payload. - * @method _sendFileStart - * @param {LoadItem|Object} item The item that is being loaded. - * @protected - */ - p._sendFileStart = function (item) { - var event = new createjs.Event("filestart"); - event.item = item; - this.hasEventListener("filestart") && this.dispatchEvent(event); - }; - - p.toString = function () { - return "[PreloadJS LoadQueue]"; - }; - - createjs.LoadQueue = createjs.promote(LoadQueue, "AbstractLoader"); -}()); + var event = new Event("fileload"); + event.loader = loader; + event.item = item; + event.result = this._loadedResults[item.id]; + event.rawResult = this._loadedRawResults[item.id]; + + // This calls a handler specified on the actual load item. Currently, the SoundJS plugin uses this. + if (item.completeHandler) { + item.completeHandler(event); + } + + this.hasEventListener("fileload") && this.dispatchEvent(event); +}; + +/** + * Dispatch a filestart {{#crossLink "Event"}}{{/crossLink}} immediately before a file starts to load. Please see + * the {{#crossLink "LoadQueue/filestart:event"}}{{/crossLink}} event for details on the event payload. + * @method _sendFileStart + * @param {LoadItem|Object} item The item that is being loaded. + * @protected + */ +p._sendFileStart = function (item) { + var event = new Event("filestart"); + event.item = item; + this.hasEventListener("filestart") && this.dispatchEvent(event); +}; + +p.toString = function () { + return "[PreloadJS LoadQueue]"; +}; + +var LoadQueue = promote(LoadQueue, "AbstractLoader"); + +module.exports = LoadQueue; \ No newline at end of file diff --git a/src/preloadjs/PreloadJS.js b/src/preloadjs/PreloadJS.js new file mode 100644 index 0000000..6767932 --- /dev/null +++ b/src/preloadjs/PreloadJS.js @@ -0,0 +1,16 @@ +// File for legacy window.createjs support. +(function (name, definition) { + if (typeof module != 'undefined') module.exports = definition(); + else if (typeof define == 'function' && typeof define.amd == 'object') define(definition); + else this[name] = definition(); +}('createjs', function () { + // TODO Merge in other libraries. + return { + LoadQueue: require("./LoadQueue"), + promote: require('../createjs/utils/promote'), + extend: require('../createjs/utils/extend'), + Event: require('../createjs/events/Event'), + ErrorEvent: require('../createjs/events/ErrorEvent'), + ProgressEvent: require('./events/ProgressEvent') + }; +})); diff --git a/src/preloadjs/data/LoadItem.js b/src/preloadjs/data/LoadItem.js index 8d7e9e0..66fe4fa 100644 --- a/src/preloadjs/data/LoadItem.js +++ b/src/preloadjs/data/LoadItem.js @@ -32,197 +32,194 @@ */ // namespace: -this.createjs = this.createjs || {}; -(function () { - "use strict"; +/** + * All loaders accept an item containing the properties defined in this class. If a raw object is passed instead, + * it will not be affected, but it must contain at least a {{#crossLink "src:property"}}{{/crossLink}} property. A + * string path or HTML tag is also acceptable, but it will be automatically converted to a LoadItem using the + * {{#crossLink "create"}}{{/crossLink}} method by {{#crossLink "AbstractLoader"}}{{/crossLink}} + * @class LoadItem + * @constructor + * @since 0.6.0 + */ +function LoadItem() { + /** + * The source of the file that is being loaded. This property is required. The source can either be a + * string (recommended), or an HTML tag. + * This can also be an object, but in that case it has to include a type and be handled by a plugin. + * @property src + * @type {String} + * @default null + */ + this.src = null; /** - * All loaders accept an item containing the properties defined in this class. If a raw object is passed instead, - * it will not be affected, but it must contain at least a {{#crossLink "src:property"}}{{/crossLink}} property. A - * string path or HTML tag is also acceptable, but it will be automatically converted to a LoadItem using the - * {{#crossLink "create"}}{{/crossLink}} method by {{#crossLink "AbstractLoader"}}{{/crossLink}} - * @class LoadItem - * @constructor - * @since 0.6.0 + * The type file that is being loaded. The type of the file is usually inferred by the extension, but can also + * be set manually. This is helpful in cases where a file does not have an extension. + * @property type + * @type {String} + * @default null */ - function LoadItem() { - /** - * The source of the file that is being loaded. This property is required. The source can either be a - * string (recommended), or an HTML tag. - * This can also be an object, but in that case it has to include a type and be handled by a plugin. - * @property src - * @type {String} - * @default null - */ - this.src = null; - - /** - * The type file that is being loaded. The type of the file is usually inferred by the extension, but can also - * be set manually. This is helpful in cases where a file does not have an extension. - * @property type - * @type {String} - * @default null - */ - this.type = null; - - /** - * A string identifier which can be used to reference the loaded object. If none is provided, this will be - * automatically set to the {{#crossLink "src:property"}}{{/crossLink}}. - * @property id - * @type {String} - * @default null - */ - this.id = null; - - /** - * Determines if a manifest will maintain the order of this item, in relation to other items in the manifest - * that have also set the `maintainOrder` property to `true`. This only applies when the max connections has - * been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}). Everything with this - * property set to `false` will finish as it is loaded. Ordered items are combined with script tags loading in - * order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} is set to `true`. - * @property maintainOrder - * @type {Boolean} - * @default false - */ - this.maintainOrder = false; - - /** - * A callback used by JSONP requests that defines what global method to call when the JSONP content is loaded. - * @property callback - * @type {String} - * @default null - */ - this.callback = null; - - /** - * An arbitrary data object, which is included with the loaded object. - * @property data - * @type {Object} - * @default null - */ - this.data = null; - - /** - * The request method used for HTTP calls. Both {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} or - * {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} request types are supported, and are defined as - * constants on {{#crossLink "AbstractLoader"}}{{/crossLink}}. - * @property method - * @type {String} - * @default get - */ - this.method = createjs.LoadItem.GET; - - /** - * An object hash of name/value pairs to send to the server. - * @property values - * @type {Object} - * @default null - */ - this.values = null; - - /** - * An object hash of headers to attach to an XHR request. PreloadJS will automatically attach some default - * headers when required, including "Origin", "Content-Type", and "X-Requested-With". You may override the - * default headers by including them in your headers object. - * @property headers - * @type {Object} - * @default null - */ - this.headers = null; - - /** - * Enable credentials for XHR requests. - * @property withCredentials - * @type {Boolean} - * @default false - */ - this.withCredentials = false; - - /** - * Set the mime type of XHR-based requests. This is automatically set to "text/plain; charset=utf-8" for text - * based files (json, xml, text, css, js). - * @property mimeType - * @type {String} - * @default null - */ - this.mimeType = null; - - /** - * Sets the crossOrigin attribute for CORS-enabled images loading cross-domain. - * @property crossOrigin - * @type {boolean} - * @default Anonymous - */ - this.crossOrigin = null; - - /** - * The duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR - * (level one) loading, as XHR (level 2) provides its own timeout event. - * @property loadTimeout - * @type {Number} - * @default 8000 (8 seconds) - */ - this.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; - }; - - var p = LoadItem.prototype = {}; - var s = LoadItem; + this.type = null; /** - * Default duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR - * (level one) loading, as XHR (level 2) provides its own timeout event. - * @property LOAD_TIMEOUT_DEFAULT - * @type {number} - * @static + * A string identifier which can be used to reference the loaded object. If none is provided, this will be + * automatically set to the {{#crossLink "src:property"}}{{/crossLink}}. + * @property id + * @type {String} + * @default null */ - s.LOAD_TIMEOUT_DEFAULT = 8000; + this.id = null; /** - * Create a LoadItem. - *
    - *
  • String-based items are converted to a LoadItem with a populated {{#crossLink "src:property"}}{{/crossLink}}.
  • - *
  • LoadItem instances are returned as-is
  • - *
  • Objects are returned with any needed properties added
  • - *
- * @method create - * @param {LoadItem|String|Object} value The load item value - * @returns {LoadItem|Object} - * @static + * Determines if a manifest will maintain the order of this item, in relation to other items in the manifest + * that have also set the `maintainOrder` property to `true`. This only applies when the max connections has + * been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}). Everything with this + * property set to `false` will finish as it is loaded. Ordered items are combined with script tags loading in + * order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} is set to `true`. + * @property maintainOrder + * @type {Boolean} + * @default false */ - s.create = function (value) { - if (typeof value == "string") { - var item = new LoadItem(); - item.src = value; - return item; - } else if (value instanceof s) { - return value; - } else if (value instanceof Object && value.src) { - if (value.loadTimeout == null) { - value.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; - } - return value; - } else { - throw new Error("Type not recognized."); - } - }; + this.maintainOrder = false; + + /** + * A callback used by JSONP requests that defines what global method to call when the JSONP content is loaded. + * @property callback + * @type {String} + * @default null + */ + this.callback = null; + + /** + * An arbitrary data object, which is included with the loaded object. + * @property data + * @type {Object} + * @default null + */ + this.data = null; + + /** + * The request method used for HTTP calls. Both {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} or + * {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} request types are supported, and are defined as + * constants on {{#crossLink "AbstractLoader"}}{{/crossLink}}. + * @property method + * @type {String} + * @default get + */ + this.method = LoadItem.GET; + + /** + * An object hash of name/value pairs to send to the server. + * @property values + * @type {Object} + * @default null + */ + this.values = null; + + /** + * An object hash of headers to attach to an XHR request. PreloadJS will automatically attach some default + * headers when required, including "Origin", "Content-Type", and "X-Requested-With". You may override the + * default headers by including them in your headers object. + * @property headers + * @type {Object} + * @default null + */ + this.headers = null; + + /** + * Enable credentials for XHR requests. + * @property withCredentials + * @type {Boolean} + * @default false + */ + this.withCredentials = false; + + /** + * Set the mime type of XHR-based requests. This is automatically set to "text/plain; charset=utf-8" for text + * based files (json, xml, text, css, js). + * @property mimeType + * @type {String} + * @default null + */ + this.mimeType = null; + + /** + * Sets the crossOrigin attribute for CORS-enabled images loading cross-domain. + * @property crossOrigin + * @type {boolean} + * @default Anonymous + */ + this.crossOrigin = null; /** - * Provides a chainable shortcut method for setting a number of properties on the instance. - * - *

Example

- * - * var loadItem = new createjs.LoadItem().set({src:"image.png", maintainOrder:true}); - * - * @method set - * @param {Object} props A generic object containing properties to copy to the LoadItem instance. - * @return {LoadItem} Returns the instance the method is called on (useful for chaining calls.) - */ - p.set = function(props) { - for (var n in props) { this[n] = props[n]; } - return this; - }; - - createjs.LoadItem = s; - -}()); + * The duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR + * (level one) loading, as XHR (level 2) provides its own timeout event. + * @property loadTimeout + * @type {Number} + * @default 8000 (8 seconds) + */ + this.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; +}; + +var p = LoadItem.prototype = {}; +var s = LoadItem; + +/** + * Default duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR + * (level one) loading, as XHR (level 2) provides its own timeout event. + * @property LOAD_TIMEOUT_DEFAULT + * @type {number} + * @static + */ +s.LOAD_TIMEOUT_DEFAULT = 8000; + +/** + * Create a LoadItem. + *
    + *
  • String-based items are converted to a LoadItem with a populated {{#crossLink "src:property"}}{{/crossLink}}.
  • + *
  • LoadItem instances are returned as-is
  • + *
  • Objects are returned with any needed properties added
  • + *
+ * @method create + * @param {LoadItem|String|Object} value The load item value + * @returns {LoadItem|Object} + * @static + */ +s.create = function (value) { + if (typeof value == "string") { + var item = new LoadItem(); + item.src = value; + return item; + } else if (value instanceof s) { + return value; + } else if (value instanceof Object && value.src) { + if (value.loadTimeout == null) { + value.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; + } + return value; + } else { + throw new Error("Type not recognized."); + } +}; + +/** + * Provides a chainable shortcut method for setting a number of properties on the instance. + * + *

Example

+ * + * var loadItem = new createjs.LoadItem().set({src:"image.png", maintainOrder:true}); + * + * @method set + * @param {Object} props A generic object containing properties to copy to the LoadItem instance. + * @return {LoadItem} Returns the instance the method is called on (useful for chaining calls.) + */ +p.set = function (props) { + for (var n in props) { + this[n] = props[n]; + } + return this; +}; + +var LoadItem = s; +module.exports = LoadItem; diff --git a/src/preloadjs/events/ProgressEvent.js b/src/preloadjs/events/ProgressEvent.js index 69f61f8..d05c68f 100644 --- a/src/preloadjs/events/ProgressEvent.js +++ b/src/preloadjs/events/ProgressEvent.js @@ -31,60 +31,57 @@ * @module PreloadJS */ -// namespace: -this.createjs = this.createjs || {}; +var promote = require('../../createjs/utils/promote'); +var extend = require('../../createjs/utils/extend'); +var Event = require('../../createjs/events/Event'); -(function (scope) { - "use strict"; +// constructor +/** + * A CreateJS {{#crossLink "Event"}}{{/crossLink}} that is dispatched when progress changes. + * @class ProgressEvent + * @param {Number} loaded The amount that has been loaded. This can be any number relative to the total. + * @param {Number} [total=1] The total amount that will load. This will default to 1, so if the `loaded` value is + * a percentage (between 0 and 1), it can be omitted. + * @todo Consider having this event be a "fileprogress" event as well + * @constructor + */ +function ProgressEvent(loaded, total) { + this.Event_constructor("progress"); - // constructor /** - * A CreateJS {{#crossLink "Event"}}{{/crossLink}} that is dispatched when progress changes. - * @class ProgressEvent - * @param {Number} loaded The amount that has been loaded. This can be any number relative to the total. - * @param {Number} [total=1] The total amount that will load. This will default to 1, so if the `loaded` value is - * a percentage (between 0 and 1), it can be omitted. - * @todo Consider having this event be a "fileprogress" event as well - * @constructor + * The amount that has been loaded (out of a total amount) + * @property loaded + * @type {Number} */ - function ProgressEvent(loaded, total) { - this.Event_constructor("progress"); - - /** - * The amount that has been loaded (out of a total amount) - * @property loaded - * @type {Number} - */ - this.loaded = loaded; - - /** - * The total "size" of the load. - * @property total - * @type {Number} - * @default 1 - */ - this.total = (total == null) ? 1 : total; - - /** - * The percentage (out of 1) that the load has been completed. This is calculated using `loaded/total`. - * @property progress - * @type {Number} - * @default 0 - */ - this.progress = (total == 0) ? 0 : this.loaded / this.total; - }; + this.loaded = loaded; - var p = createjs.extend(ProgressEvent, createjs.Event); + /** + * The total "size" of the load. + * @property total + * @type {Number} + * @default 1 + */ + this.total = (total == null) ? 1 : total; /** - * Returns a clone of the ProgressEvent instance. - * @method clone - * @return {ProgressEvent} a clone of the Event instance. - **/ - p.clone = function() { - return new createjs.ProgressEvent(this.loaded, this.total); - }; + * The percentage (out of 1) that the load has been completed. This is calculated using `loaded/total`. + * @property progress + * @type {Number} + * @default 0 + */ + this.progress = (total == 0) ? 0 : this.loaded / this.total; +}; - createjs.ProgressEvent = createjs.promote(ProgressEvent, "Event"); +var p = extend(ProgressEvent, Event); + +/** + * Returns a clone of the ProgressEvent instance. + * @method clone + * @return {ProgressEvent} a clone of the Event instance. + **/ +p.clone = function () { + return new ProgressEvent(this.loaded, this.total); +}; -}(window)); \ No newline at end of file +var ProgressEvent = promote(ProgressEvent, "Event"); +module.exports = ProgressEvent; diff --git a/src/preloadjs/loaders/AbstractLoader.js b/src/preloadjs/loaders/AbstractLoader.js index 8d43d19..1e1cbdb 100644 --- a/src/preloadjs/loaders/AbstractLoader.js +++ b/src/preloadjs/loaders/AbstractLoader.js @@ -31,729 +31,746 @@ * @module PreloadJS */ -// namespace: -this.createjs = this.createjs || {}; - -(function () { - "use strict"; +var EventDispatcher = require('../../createjs/events/EventDispatcher'); +var LoadItem = require('../data/LoadItem'); +var Event = require('../../createjs/events/Event'); +var ErrorEvent = require('../../createjs/events/ErrorEvent'); +var ProgressEvent = require('../events/ProgressEvent'); +var RequestUtils = require('../utils/RequestUtils'); +var TagRequest = require('../net/TagRequest'); +var XHRRequest = require('../net/XHRRequest'); +var proxy = require('../../createjs/utils/proxy'); +var promote = require('../../createjs/utils/promote'); +var extend = require('../../createjs/utils/extend'); +// namespace: // constructor - /** - * The base loader, which defines all the generic methods, properties, and events. All loaders extend this class, - * including the {{#crossLink "LoadQueue"}}{{/crossLink}}. - * @class AbstractLoader - * @param {LoadItem|object|string} loadItem The item to be loaded. - * @param {Boolean} [preferXHR] Determines if the LoadItem should try and load using XHR, or take a - * tag-based approach, which can be better in cross-domain situations. Not all loaders can load using one or the - * other, so this is a suggested directive. - * @param {String} [type] The type of loader. Loader types are defined as constants on the AbstractLoader class, - * such as {{#crossLink "IMAGE:property"}}{{/crossLink}}, {{#crossLink "CSS:property"}}{{/crossLink}}, etc. - * @extends EventDispatcher - */ - function AbstractLoader(loadItem, preferXHR, type) { - this.EventDispatcher_constructor(); - - // public properties - /** - * If the loader has completed loading. This provides a quick check, but also ensures that the different approaches - * used for loading do not pile up resulting in more than one `complete` {{#crossLink "Event"}}{{/crossLink}}. - * @property loaded - * @type {Boolean} - * @default false - */ - this.loaded = false; - - /** - * Determine if the loader was canceled. Canceled loads will not fire complete events. Note that this property - * is readonly, so {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "LoadQueue/close"}}{{/crossLink}} - * instead. - * @property canceled - * @type {Boolean} - * @default false - * @readonly - */ - this.canceled = false; - - /** - * The current load progress (percentage) for this item. This will be a number between 0 and 1. - * - *

Example

- * - * var queue = new createjs.LoadQueue(); - * queue.loadFile("largeImage.png"); - * queue.on("progress", function() { - * console.log("Progress:", queue.progress, event.progress); - * }); - * - * @property progress - * @type {Number} - * @default 0 - */ - this.progress = 0; - - /** - * The type of item this loader will load. See {{#crossLink "AbstractLoader"}}{{/crossLink}} for a full list of - * supported types. - * @property type - * @type {String} - */ - this.type = type; - - /** - * A formatter function that converts the loaded raw result into the final result. For example, the JSONLoader - * converts a string of text into a JavaScript object. Not all loaders have a resultFormatter, and this property - * can be overridden to provide custom formatting. - * - * Optionally, a resultFormatter can return a callback function in cases where the formatting needs to be - * asynchronous, such as creating a new image. The callback function is passed 2 parameters, which are callbacks - * to handle success and error conditions in the resultFormatter. Note that the resultFormatter method is - * called in the current scope, as well as the success and error callbacks. - * - *

Example asynchronous resultFormatter

- * - * function _formatResult(loader) { - * return function(success, error) { - * if (errorCondition) { error(errorDetailEvent); } - * success(result); - * } - * } - * @property resultFormatter - * @type {Function} - * @default null - */ - this.resultFormatter = null; - - // protected properties - /** - * The {{#crossLink "LoadItem"}}{{/crossLink}} this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}}, - * but will be available on loaders such as {{#crossLink "XMLLoader"}}{{/crossLink}} and {{#crossLink "ImageLoader"}}{{/crossLink}}. - * @property _item - * @type {LoadItem|Object} - * @private - */ - if (loadItem) { - this._item = createjs.LoadItem.create(loadItem); - } else { - this._item = null; - } - - /** - * Whether the loader will try and load content using XHR (true) or HTML tags (false). - * @property _preferXHR - * @type {Boolean} - * @private - */ - this._preferXHR = preferXHR; - - /** - * The loaded result after it is formatted by an optional {{#crossLink "resultFormatter"}}{{/crossLink}}. For - * items that are not formatted, this will be the same as the {{#crossLink "_rawResult:property"}}{{/crossLink}}. - * The result is accessed using the {{#crossLink "getResult"}}{{/crossLink}} method. - * @property _result - * @type {Object|String} - * @private - */ - this._result = null; - - /** - * The loaded result before it is formatted. The rawResult is accessed using the {{#crossLink "getResult"}}{{/crossLink}} - * method, and passing `true`. - * @property _rawResult - * @type {Object|String} - * @private - */ - this._rawResult = null; - - /** - * A list of items that loaders load behind the scenes. This does not include the main item the loader is - * responsible for loading. Examples of loaders that have sub-items include the {{#crossLink "SpriteSheetLoader"}}{{/crossLink}} and - * {{#crossLink "ManifestLoader"}}{{/crossLink}}. - * @property _loadItems - * @type {null} - * @protected - */ - this._loadedItems = null; - - /** - * The attribute the items loaded using tags use for the source. - * @type {string} - * @default null - * @private - */ - this._tagSrcAttribute = null; - - /** - * An HTML tag (or similar) that a loader may use to load HTML content, such as images, scripts, etc. - * @property _tag - * @type {Object} - * @private - */ - this._tag = null; - }; - - var p = createjs.extend(AbstractLoader, createjs.EventDispatcher); - var s = AbstractLoader; - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - - /** - * Defines a POST request, use for a method value when loading data. - * @property POST - * @type {string} - * @default post - * @static - */ - s.POST = "POST"; +/** + * The base loader, which defines all the generic methods, properties, and events. All loaders extend this class, + * including the {{#crossLink "LoadQueue"}}{{/crossLink}}. + * @class AbstractLoader + * @param {LoadItem|object|string} loadItem The item to be loaded. + * @param {Boolean} [preferXHR] Determines if the LoadItem should try and load using XHR, or take a + * tag-based approach, which can be better in cross-domain situations. Not all loaders can load using one or the + * other, so this is a suggested directive. + * @param {String} [type] The type of loader. Loader types are defined as constants on the AbstractLoader class, + * such as {{#crossLink "IMAGE:property"}}{{/crossLink}}, {{#crossLink "CSS:property"}}{{/crossLink}}, etc. + * @extends EventDispatcher + */ +function AbstractLoader(loadItem, preferXHR, type) { + this.EventDispatcher_constructor(); + // public properties /** - * Defines a GET request, use for a method value when loading data. - * @property GET - * @type {string} - * @default get - * @static + * If the loader has completed loading. This provides a quick check, but also ensures that the different approaches + * used for loading do not pile up resulting in more than one `complete` {{#crossLink "Event"}}{{/crossLink}}. + * @property loaded + * @type {Boolean} + * @default false */ - s.GET = "GET"; + this.loaded = false; /** - * The preload type for generic binary types. Note that images are loaded as binary files when using XHR. - * @property BINARY - * @type {String} - * @default binary - * @static - * @since 0.6.0 + * Determine if the loader was canceled. Canceled loads will not fire complete events. Note that this property + * is readonly, so {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "LoadQueue/close"}}{{/crossLink}} + * instead. + * @property canceled + * @type {Boolean} + * @default false + * @readonly */ - s.BINARY = "binary"; + this.canceled = false; /** - * The preload type for css files. CSS files are loaded using a <link> when loaded with XHR, or a - * <style> tag when loaded with tags. - * @property CSS - * @type {String} - * @default css - * @static - * @since 0.6.0 + * The current load progress (percentage) for this item. This will be a number between 0 and 1. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.loadFile("largeImage.png"); + * queue.on("progress", function() { + * console.log("Progress:", queue.progress, event.progress); + * }); + * + * @property progress + * @type {Number} + * @default 0 */ - s.CSS = "css"; + this.progress = 0; /** - * The preload type for image files, usually png, gif, or jpg/jpeg. Images are loaded into an <image> tag. - * @property IMAGE + * The type of item this loader will load. See {{#crossLink "AbstractLoader"}}{{/crossLink}} for a full list of + * supported types. + * @property type * @type {String} - * @default image - * @static - * @since 0.6.0 */ - s.IMAGE = "image"; + this.type = type; /** - * The preload type for javascript files, usually with the "js" file extension. JavaScript files are loaded into a - * <script> tag. + * A formatter function that converts the loaded raw result into the final result. For example, the JSONLoader + * converts a string of text into a JavaScript object. Not all loaders have a resultFormatter, and this property + * can be overridden to provide custom formatting. * - * Since version 0.4.1+, due to how tag-loaded scripts work, all JavaScript files are automatically injected into - * the body of the document to maintain parity between XHR and tag-loaded scripts. In version 0.4.0 and earlier, - * only tag-loaded scripts are injected. - * @property JAVASCRIPT - * @type {String} - * @default javascript - * @static - * @since 0.6.0 + * Optionally, a resultFormatter can return a callback function in cases where the formatting needs to be + * asynchronous, such as creating a new image. The callback function is passed 2 parameters, which are callbacks + * to handle success and error conditions in the resultFormatter. Note that the resultFormatter method is + * called in the current scope, as well as the success and error callbacks. + * + *

Example asynchronous resultFormatter

+ * + * function _formatResult(loader) { + * return function(success, error) { + * if (errorCondition) { error(errorDetailEvent); } + * success(result); + * } + * } + * @property resultFormatter + * @type {Function} + * @default null */ - s.JAVASCRIPT = "javascript"; + this.resultFormatter = null; + // protected properties /** - * The preload type for json files, usually with the "json" file extension. JSON data is loaded and parsed into a - * JavaScript object. Note that if a `callback` is present on the load item, the file will be loaded with JSONP, - * no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to, and the JSON - * must contain a matching wrapper function. - * @property JSON - * @type {String} - * @default json - * @static - * @since 0.6.0 + * The {{#crossLink "LoadItem"}}{{/crossLink}} this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}}, + * but will be available on loaders such as {{#crossLink "XMLLoader"}}{{/crossLink}} and {{#crossLink "ImageLoader"}}{{/crossLink}}. + * @property _item + * @type {LoadItem|Object} + * @private */ - s.JSON = "json"; + if (loadItem) { + this._item = LoadItem.create(loadItem); + } else { + this._item = null; + } /** - * The preload type for jsonp files, usually with the "json" file extension. JSON data is loaded and parsed into a - * JavaScript object. You are required to pass a callback parameter that matches the function wrapper in the JSON. - * Note that JSONP will always be used if there is a callback present, no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} - * property is set to. - * @property JSONP - * @type {String} - * @default jsonp - * @static - * @since 0.6.0 + * Whether the loader will try and load content using XHR (true) or HTML tags (false). + * @property _preferXHR + * @type {Boolean} + * @private */ - s.JSONP = "jsonp"; + this._preferXHR = preferXHR; /** - * The preload type for json-based manifest files, usually with the "json" file extension. The JSON data is loaded - * and parsed into a JavaScript object. PreloadJS will then look for a "manifest" property in the JSON, which is an - * Array of files to load, following the same format as the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} - * method. If a "callback" is specified on the manifest object, then it will be loaded using JSONP instead, - * regardless of what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to. - * @property MANIFEST - * @type {String} - * @default manifest - * @static - * @since 0.6.0 + * The loaded result after it is formatted by an optional {{#crossLink "resultFormatter"}}{{/crossLink}}. For + * items that are not formatted, this will be the same as the {{#crossLink "_rawResult:property"}}{{/crossLink}}. + * The result is accessed using the {{#crossLink "getResult"}}{{/crossLink}} method. + * @property _result + * @type {Object|String} + * @private */ - s.MANIFEST = "manifest"; + this._result = null; /** - * The preload type for sound files, usually mp3, ogg, or wav. When loading via tags, audio is loaded into an - * <audio> tag. - * @property SOUND - * @type {String} - * @default sound - * @static - * @since 0.6.0 + * The loaded result before it is formatted. The rawResult is accessed using the {{#crossLink "getResult"}}{{/crossLink}} + * method, and passing `true`. + * @property _rawResult + * @type {Object|String} + * @private */ - s.SOUND = "sound"; + this._rawResult = null; /** - * The preload type for video files, usually mp4, ts, or ogg. When loading via tags, video is loaded into an - * <video> tag. - * @property VIDEO - * @type {String} - * @default video - * @static - * @since 0.6.0 + * A list of items that loaders load behind the scenes. This does not include the main item the loader is + * responsible for loading. Examples of loaders that have sub-items include the {{#crossLink "SpriteSheetLoader"}}{{/crossLink}} and + * {{#crossLink "ManifestLoader"}}{{/crossLink}}. + * @property _loadItems + * @type {null} + * @protected */ - s.VIDEO = "video"; + this._loadedItems = null; /** - * The preload type for SpriteSheet files. SpriteSheet files are JSON files that contain string image paths. - * @property SPRITESHEET - * @type {String} - * @default spritesheet - * @static - * @since 0.6.0 + * The attribute the items loaded using tags use for the source. + * @type {string} + * @default null + * @private */ - s.SPRITESHEET = "spritesheet"; + this._tagSrcAttribute = null; /** - * The preload type for SVG files. - * @property SVG - * @type {String} - * @default svg - * @static - * @since 0.6.0 + * An HTML tag (or similar) that a loader may use to load HTML content, such as images, scripts, etc. + * @property _tag + * @type {Object} + * @private */ - s.SVG = "svg"; + this._tag = null; +}; - /** - * The preload type for text files, which is also the default file type if the type can not be determined. Text is - * loaded as raw text. - * @property TEXT - * @type {String} - * @default text - * @static - * @since 0.6.0 - */ - s.TEXT = "text"; +var p = extend(AbstractLoader, EventDispatcher); +var s = AbstractLoader; - /** - * The preload type for xml files. XML is loaded into an XML document. - * @property XML - * @type {String} - * @default xml - * @static - * @since 0.6.0 - */ - s.XML = "xml"; +// TODO: deprecated +// p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. -// Events - /** - * The {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when the overall progress changes. Prior to - * version 0.6.0, this was just a regular {{#crossLink "Event"}}{{/crossLink}}. - * @event progress - * @since 0.3.0 - */ - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a load starts. - * @event loadstart - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.3.1 - */ +/** + * Defines a POST request, use for a method value when loading data. + * @property POST + * @type {string} + * @default post + * @static + */ +s.POST = "POST"; - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the entire queue has been loaded. - * @event complete - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.3.0 - */ +/** + * Defines a GET request, use for a method value when loading data. + * @property GET + * @type {string} + * @default get + * @static + */ +s.GET = "GET"; - /** - * The {{#crossLink "ErrorEvent"}}{{/crossLink}} that is fired when the loader encounters an error. If the error was - * encountered by a file, the event will contain the item that caused the error. Prior to version 0.6.0, this was - * just a regular {{#crossLink "Event"}}{{/crossLink}}. - * @event error - * @since 0.3.0 - */ +/** + * The preload type for generic binary types. Note that images are loaded as binary files when using XHR. + * @property BINARY + * @type {String} + * @default binary + * @static + * @since 0.6.0 + */ +s.BINARY = "binary"; - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the loader encounters an internal file load error. - * This enables loaders to maintain internal queues, and surface file load errors. - * @event fileerror - * @param {Object} target The object that dispatched the event. - * @param {String} type The even type ("fileerror") - * @param {LoadItem|object} The item that encountered the error - * @since 0.6.0 - */ +/** + * The preload type for css files. CSS files are loaded using a <link> when loaded with XHR, or a + * <style> tag when loaded with tags. + * @property CSS + * @type {String} + * @default css + * @static + * @since 0.6.0 + */ +s.CSS = "css"; - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a loader internally loads a file. This enables - * loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} to maintain internal {{#crossLink "LoadQueue"}}{{/crossLink}}s - * and notify when they have loaded a file. The {{#crossLink "LoadQueue"}}{{/crossLink}} class dispatches a - * slightly different {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event. - * @event fileload - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type ("fileload") - * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the - * object will contain that value as a `src` property. - * @param {Object} result The HTML tag or parsed result of the loaded item. - * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted - * to a usable object. - * @since 0.6.0 - */ +/** + * The preload type for image files, usually png, gif, or jpg/jpeg. Images are loaded into an <image> tag. + * @property IMAGE + * @type {String} + * @default image + * @static + * @since 0.6.0 + */ +s.IMAGE = "image"; - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired after the internal request is created, but before a load. - * This allows updates to the loader for specific loading needs, such as binary or XHR image loading. - * @event initialize - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type ("initialize") - * @param {AbstractLoader} loader The loader that has been initialized. - */ +/** + * The preload type for javascript files, usually with the "js" file extension. JavaScript files are loaded into a + * <script> tag. + * + * Since version 0.4.1+, due to how tag-loaded scripts work, all JavaScript files are automatically injected into + * the body of the document to maintain parity between XHR and tag-loaded scripts. In version 0.4.0 and earlier, + * only tag-loaded scripts are injected. + * @property JAVASCRIPT + * @type {String} + * @default javascript + * @static + * @since 0.6.0 + */ +s.JAVASCRIPT = "javascript"; +/** + * The preload type for json files, usually with the "json" file extension. JSON data is loaded and parsed into a + * JavaScript object. Note that if a `callback` is present on the load item, the file will be loaded with JSONP, + * no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to, and the JSON + * must contain a matching wrapper function. + * @property JSON + * @type {String} + * @default json + * @static + * @since 0.6.0 + */ +s.JSON = "json"; - /** - * Get a reference to the manifest item that is loaded by this loader. In some cases this will be the value that was - * passed into {{#crossLink "LoadQueue"}}{{/crossLink}} using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or - * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. However if only a String path was passed in, then it will - * be a {{#crossLink "LoadItem"}}{{/crossLink}}. - * @method getItem - * @return {Object} The manifest item that this loader is responsible for loading. - * @since 0.6.0 - */ - p.getItem = function () { - return this._item; - }; +/** + * The preload type for jsonp files, usually with the "json" file extension. JSON data is loaded and parsed into a + * JavaScript object. You are required to pass a callback parameter that matches the function wrapper in the JSON. + * Note that JSONP will always be used if there is a callback present, no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} + * property is set to. + * @property JSONP + * @type {String} + * @default jsonp + * @static + * @since 0.6.0 + */ +s.JSONP = "jsonp"; - /** - * Get a reference to the content that was loaded by the loader (only available after the {{#crossLink "complete:event"}}{{/crossLink}} - * event is dispatched. - * @method getResult - * @param {Boolean} [raw=false] Determines if the returned result will be the formatted content, or the raw loaded - * data (if it exists). - * @return {Object} - * @since 0.6.0 - */ - p.getResult = function (raw) { - return raw ? this._rawResult : this._result; - }; +/** + * The preload type for json-based manifest files, usually with the "json" file extension. The JSON data is loaded + * and parsed into a JavaScript object. PreloadJS will then look for a "manifest" property in the JSON, which is an + * Array of files to load, following the same format as the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} + * method. If a "callback" is specified on the manifest object, then it will be loaded using JSONP instead, + * regardless of what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to. + * @property MANIFEST + * @type {String} + * @default manifest + * @static + * @since 0.6.0 + */ +s.MANIFEST = "manifest"; - /** - * Return the `tag` this object creates or uses for loading. - * @method getTag - * @return {Object} The tag instance - * @since 0.6.0 - */ - p.getTag = function () { - return this._tag; - }; +/** + * The preload type for sound files, usually mp3, ogg, or wav. When loading via tags, audio is loaded into an + * <audio> tag. + * @property SOUND + * @type {String} + * @default sound + * @static + * @since 0.6.0 + */ +s.SOUND = "sound"; - /** - * Set the `tag` this item uses for loading. - * @method setTag - * @param {Object} tag The tag instance - * @since 0.6.0 - */ - p.setTag = function(tag) { - this._tag = tag; - }; +/** + * The preload type for video files, usually mp4, ts, or ogg. When loading via tags, video is loaded into an + * <video> tag. + * @property VIDEO + * @type {String} + * @default video + * @static + * @since 0.6.0 + */ +s.VIDEO = "video"; - /** - * Begin loading the item. This method is required when using a loader by itself. - * - *

Example

- * - * var queue = new createjs.LoadQueue(); - * queue.on("complete", handleComplete); - * queue.loadManifest(fileArray, false); // Note the 2nd argument that tells the queue not to start loading yet - * queue.load(); - * - * @method load - */ - p.load = function () { - this._createRequest(); +/** + * The preload type for SpriteSheet files. SpriteSheet files are JSON files that contain string image paths. + * @property SPRITESHEET + * @type {String} + * @default spritesheet + * @static + * @since 0.6.0 + */ +s.SPRITESHEET = "spritesheet"; - this._request.on("complete", this, this); - this._request.on("progress", this, this); - this._request.on("loadStart", this, this); - this._request.on("abort", this, this); - this._request.on("timeout", this, this); - this._request.on("error", this, this); +/** + * The preload type for SVG files. + * @property SVG + * @type {String} + * @default svg + * @static + * @since 0.6.0 + */ +s.SVG = "svg"; - var evt = new createjs.Event("initialize"); - evt.loader = this._request; - this.dispatchEvent(evt); +/** + * The preload type for text files, which is also the default file type if the type can not be determined. Text is + * loaded as raw text. + * @property TEXT + * @type {String} + * @default text + * @static + * @since 0.6.0 + */ +s.TEXT = "text"; - this._request.load(); - }; +/** + * The preload type for xml files. XML is loaded into an XML document. + * @property XML + * @type {String} + * @default xml + * @static + * @since 0.6.0 + */ +s.XML = "xml"; - /** - * Close the the item. This will stop any open requests (although downloads using HTML tags may still continue in - * the background), but events will not longer be dispatched. - * @method cancel - */ - p.cancel = function () { - this.canceled = true; - this.destroy(); - }; +// Events +/** + * The {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when the overall progress changes. Prior to + * version 0.6.0, this was just a regular {{#crossLink "Event"}}{{/crossLink}}. + * @event progress + * @since 0.3.0 + */ - /** - * Clean up the loader. - * @method destroy - */ - p.destroy = function() { - if (this._request) { - this._request.removeAllEventListeners(); - this._request.destroy(); - } +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a load starts. + * @event loadstart + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @since 0.3.1 + */ - this._request = null; +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the entire queue has been loaded. + * @event complete + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type. + * @since 0.3.0 + */ - this._item = null; - this._rawResult = null; - this._result = null; +/** + * The {{#crossLink "ErrorEvent"}}{{/crossLink}} that is fired when the loader encounters an error. If the error was + * encountered by a file, the event will contain the item that caused the error. Prior to version 0.6.0, this was + * just a regular {{#crossLink "Event"}}{{/crossLink}}. + * @event error + * @since 0.3.0 + */ - this._loadItems = null; +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the loader encounters an internal file load error. + * This enables loaders to maintain internal queues, and surface file load errors. + * @event fileerror + * @param {Object} target The object that dispatched the event. + * @param {String} type The even type ("fileerror") + * @param {LoadItem|object} The item that encountered the error + * @since 0.6.0 + */ - this.removeAllEventListeners(); - }; +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a loader internally loads a file. This enables + * loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} to maintain internal {{#crossLink "LoadQueue"}}{{/crossLink}}s + * and notify when they have loaded a file. The {{#crossLink "LoadQueue"}}{{/crossLink}} class dispatches a + * slightly different {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event. + * @event fileload + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type ("fileload") + * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the + * object will contain that value as a `src` property. + * @param {Object} result The HTML tag or parsed result of the loaded item. + * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted + * to a usable object. + * @since 0.6.0 + */ - /** - * Get any items loaded internally by the loader. The enables loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} - * to expose items it loads internally. - * @method getLoadedItems - * @return {Array} A list of the items loaded by the loader. - * @since 0.6.0 - */ - p.getLoadedItems = function () { - return this._loadedItems; - }; +/** + * The {{#crossLink "Event"}}{{/crossLink}} that is fired after the internal request is created, but before a load. + * This allows updates to the loader for specific loading needs, such as binary or XHR image loading. + * @event initialize + * @param {Object} target The object that dispatched the event. + * @param {String} type The event type ("initialize") + * @param {AbstractLoader} loader The loader that has been initialized. + */ - // Private methods - /** - * Create an internal request used for loading. By default, an {{#crossLink "XHRRequest"}}{{/crossLink}} or - * {{#crossLink "TagRequest"}}{{/crossLink}} is created, depending on the value of {{#crossLink "preferXHR:property"}}{{/crossLink}}. - * Other loaders may override this to use different request types, such as {{#crossLink "ManifestLoader"}}{{/crossLink}}, - * which uses {{#crossLink "JSONLoader"}}{{/crossLink}} or {{#crossLink "JSONPLoader"}}{{/crossLink}} under the hood. - * @method _createRequest - * @protected - */ - p._createRequest = function() { - if (!this._preferXHR) { - this._request = new createjs.TagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); - } else { - this._request = new createjs.XHRRequest(this._item); - } - }; +/** + * Get a reference to the manifest item that is loaded by this loader. In some cases this will be the value that was + * passed into {{#crossLink "LoadQueue"}}{{/crossLink}} using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or + * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. However if only a String path was passed in, then it will + * be a {{#crossLink "LoadItem"}}{{/crossLink}}. + * @method getItem + * @return {Object} The manifest item that this loader is responsible for loading. + * @since 0.6.0 + */ +p.getItem = function () { + return this._item; +}; - /** - * Create the HTML tag used for loading. This method does nothing by default, and needs to be implemented - * by loaders that require tag loading. - * @method _createTag - * @param {String} src The tag source - * @return {HTMLElement} The tag that was created - * @protected - */ - p._createTag = function(src) { return null; }; +/** + * Get a reference to the content that was loaded by the loader (only available after the {{#crossLink "complete:event"}}{{/crossLink}} + * event is dispatched. + * @method getResult + * @param {Boolean} [raw=false] Determines if the returned result will be the formatted content, or the raw loaded + * data (if it exists). + * @return {Object} + * @since 0.6.0 + */ +p.getResult = function (raw) { + return raw ? this._rawResult : this._result; +}; - /** - * Dispatch a loadstart {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}} - * event for details on the event payload. - * @method _sendLoadStart - * @protected - */ - p._sendLoadStart = function () { - if (this._isCanceled()) { return; } - this.dispatchEvent("loadstart"); - }; +/** + * Return the `tag` this object creates or uses for loading. + * @method getTag + * @return {Object} The tag instance + * @since 0.6.0 + */ +p.getTag = function () { + return this._tag; +}; - /** - * Dispatch a {{#crossLink "ProgressEvent"}}{{/crossLink}}. - * @method _sendProgress - * @param {Number | Object} value The progress of the loaded item, or an object containing loaded - * and total properties. - * @protected - */ - p._sendProgress = function (value) { - if (this._isCanceled()) { return; } - var event = null; - if (typeof(value) == "number") { - this.progress = value; - event = new createjs.ProgressEvent(this.progress); - } else { - event = value; - this.progress = value.loaded / value.total; - event.progress = this.progress; - if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; } - } - this.hasEventListener("progress") && this.dispatchEvent(event); - }; +/** + * Set the `tag` this item uses for loading. + * @method setTag + * @param {Object} tag The tag instance + * @since 0.6.0 + */ +p.setTag = function (tag) { + this._tag = tag; +}; - /** - * Dispatch a complete {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event - * @method _sendComplete - * @protected - */ - p._sendComplete = function () { - if (this._isCanceled()) { return; } +/** + * Begin loading the item. This method is required when using a loader by itself. + * + *

Example

+ * + * var queue = new createjs.LoadQueue(); + * queue.on("complete", handleComplete); + * queue.loadManifest(fileArray, false); // Note the 2nd argument that tells the queue not to start loading yet + * queue.load(); + * + * @method load + */ +p.load = function () { + this._createRequest(); - this.loaded = true; + this._request.on("complete", this, this); + this._request.on("progress", this, this); + this._request.on("loadStart", this, this); + this._request.on("abort", this, this); + this._request.on("timeout", this, this); + this._request.on("error", this, this); - var event = new createjs.Event("complete"); - event.rawResult = this._rawResult; + var evt = new Event("initialize"); + evt.loader = this._request; + this.dispatchEvent(evt); - if (this._result != null) { - event.result = this._result; - } + this._request.load(); +}; - this.dispatchEvent(event); - }; +/** + * Close the the item. This will stop any open requests (although downloads using HTML tags may still continue in + * the background), but events will not longer be dispatched. + * @method cancel + */ +p.cancel = function () { + this.canceled = true; + this.destroy(); +}; - /** - * Dispatch an error {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} - * event for details on the event payload. - * @method _sendError - * @param {ErrorEvent} event The event object containing specific error properties. - * @protected - */ - p._sendError = function (event) { - if (this._isCanceled() || !this.hasEventListener("error")) { return; } - if (event == null) { - event = new createjs.ErrorEvent("PRELOAD_ERROR_EMPTY"); // TODO: Populate error - } - this.dispatchEvent(event); - }; +/** + * Clean up the loader. + * @method destroy + */ +p.destroy = function () { + if (this._request) { + this._request.removeAllEventListeners(); + this._request.destroy(); + } - /** - * Determine if the load has been canceled. This is important to ensure that method calls or asynchronous events - * do not cause issues after the queue has been cleaned up. - * @method _isCanceled - * @return {Boolean} If the loader has been canceled. - * @protected - */ - p._isCanceled = function () { - if (window.createjs == null || this.canceled) { - return true; - } - return false; - }; + this._request = null; - /** - * A custom result formatter function, which is called just before a request dispatches its complete event. Most - * loader types already have an internal formatter, but this can be user-overridden for custom formatting. The - * formatted result will be available on Loaders using {{#crossLink "getResult"}}{{/crossLink}}, and passing `true`. - * @property resultFormatter - * @type Function - * @return {Object} The formatted result - * @since 0.6.0 - */ - p.resultFormatter = null; + this._item = null; + this._rawResult = null; + this._result = null; - /** - * Handle events from internal requests. By default, loaders will handle, and redispatch the necessary events, but - * this method can be overridden for custom behaviours. - * @method handleEvent - * @param {Event} event The event that the internal request dispatches. - * @protected - * @since 0.6.0 - */ - p.handleEvent = function (event) { - switch (event.type) { - case "complete": - this._rawResult = event.target._response; - var result = this.resultFormatter && this.resultFormatter(this); - if (result instanceof Function) { - result.call(this, - createjs.proxy(this._resultFormatSuccess, this), - createjs.proxy(this._resultFormatFailed, this) - ); - } else { - this._result = result || this._rawResult; - this._sendComplete(); - } - break; - case "progress": - this._sendProgress(event); - break; - case "error": - this._sendError(event); - break; - case "loadstart": - this._sendLoadStart(); - break; - case "abort": - case "timeout": - if (!this._isCanceled()) { - this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_" + event.type.toUpperCase() + "_ERROR")); - } - break; + this._loadItems = null; + + this.removeAllEventListeners(); +}; + +/** + * Get any items loaded internally by the loader. The enables loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} + * to expose items it loads internally. + * @method getLoadedItems + * @return {Array} A list of the items loaded by the loader. + * @since 0.6.0 + */ +p.getLoadedItems = function () { + return this._loadedItems; +}; + + +// Private methods +/** + * Create an internal request used for loading. By default, an {{#crossLink "XHRRequest"}}{{/crossLink}} or + * {{#crossLink "TagRequest"}}{{/crossLink}} is created, depending on the value of {{#crossLink "preferXHR:property"}}{{/crossLink}}. + * Other loaders may override this to use different request types, such as {{#crossLink "ManifestLoader"}}{{/crossLink}}, + * which uses {{#crossLink "JSONLoader"}}{{/crossLink}} or {{#crossLink "JSONPLoader"}}{{/crossLink}} under the hood. + * @method _createRequest + * @protected + */ +p._createRequest = function () { + if (!this._preferXHR) { + this._request = new TagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); + } else { + this._request = new XHRRequest(this._item); + } +}; + +/** + * Create the HTML tag used for loading. This method does nothing by default, and needs to be implemented + * by loaders that require tag loading. + * @method _createTag + * @param {String} src The tag source + * @return {HTMLElement} The tag that was created + * @protected + */ +p._createTag = function (src) { + return null; +}; + +/** + * Dispatch a loadstart {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendLoadStart + * @protected + */ +p._sendLoadStart = function () { + if (this._isCanceled()) { + return; + } + this.dispatchEvent("loadstart"); +}; + +/** + * Dispatch a {{#crossLink "ProgressEvent"}}{{/crossLink}}. + * @method _sendProgress + * @param {Number | Object} value The progress of the loaded item, or an object containing loaded + * and total properties. + * @protected + */ +p._sendProgress = function (value) { + if (this._isCanceled()) { + return; + } + var event = null; + if (typeof(value) == "number") { + this.progress = value; + event = new ProgressEvent(this.progress); + } else { + event = value; + this.progress = value.loaded / value.total; + event.progress = this.progress; + if (isNaN(this.progress) || this.progress == Infinity) { + this.progress = 0; } - }; + } + this.hasEventListener("progress") && this.dispatchEvent(event); +}; - /** - * The "success" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous - * functions. - * @method _resultFormatSuccess - * @param {Object} result The formatted result - * @private - */ - p._resultFormatSuccess = function (result) { - this._result = result; - this._sendComplete(); - }; +/** + * Dispatch a complete {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event + * @method _sendComplete + * @protected + */ +p._sendComplete = function () { + if (this._isCanceled()) { + return; + } - /** - * The "error" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous - * functions. - * @method _resultFormatSuccess - * @param {Object} error The error event - * @private - */ - p._resultFormatFailed = function (event) { - this._sendError(event); - }; + this.loaded = true; - /** - * @method buildPath - * @protected - * @deprecated Use the {{#crossLink "RequestUtils"}}{{/crossLink}} method {{#crossLink "RequestUtils/buildPath"}}{{/crossLink}} - * instead. - */ - p.buildPath = function (src, data) { - return createjs.RequestUtils.buildPath(src, data); - }; + var event = new Event("complete"); + event.rawResult = this._rawResult; - /** - * @method toString - * @return {String} a string representation of the instance. - */ - p.toString = function () { - return "[PreloadJS AbstractLoader]"; - }; + if (this._result != null) { + event.result = this._result; + } + + this.dispatchEvent(event); +}; - createjs.AbstractLoader = createjs.promote(AbstractLoader, "EventDispatcher"); +/** + * Dispatch an error {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} + * event for details on the event payload. + * @method _sendError + * @param {ErrorEvent} event The event object containing specific error properties. + * @protected + */ +p._sendError = function (event) { + if (this._isCanceled() || !this.hasEventListener("error")) { + return; + } + if (event == null) { + event = new ErrorEvent("PRELOAD_ERROR_EMPTY"); // TODO: Populate error + } + this.dispatchEvent(event); +}; + +/** + * Determine if the load has been canceled. This is important to ensure that method calls or asynchronous events + * do not cause issues after the queue has been cleaned up. + * @method _isCanceled + * @return {Boolean} If the loader has been canceled. + * @protected + */ +p._isCanceled = function () { + if (window.createjs == null || this.canceled) { + return true; + } + return false; +}; + +/** + * A custom result formatter function, which is called just before a request dispatches its complete event. Most + * loader types already have an internal formatter, but this can be user-overridden for custom formatting. The + * formatted result will be available on Loaders using {{#crossLink "getResult"}}{{/crossLink}}, and passing `true`. + * @property resultFormatter + * @type Function + * @return {Object} The formatted result + * @since 0.6.0 + */ +p.resultFormatter = null; + +/** + * Handle events from internal requests. By default, loaders will handle, and redispatch the necessary events, but + * this method can be overridden for custom behaviours. + * @method handleEvent + * @param {Event} event The event that the internal request dispatches. + * @protected + * @since 0.6.0 + */ +p.handleEvent = function (event) { + switch (event.type) { + case "complete": + this._rawResult = event.target._response; + var result = this.resultFormatter && this.resultFormatter(this); + if (result instanceof Function) { + result.call(this, + proxy(this._resultFormatSuccess, this), + proxy(this._resultFormatFailed, this) + ); + } else { + this._result = result || this._rawResult; + this._sendComplete(); + } + break; + case "progress": + this._sendProgress(event); + break; + case "error": + this._sendError(event); + break; + case "loadstart": + this._sendLoadStart(); + break; + case "abort": + case "timeout": + if (!this._isCanceled()) { + this.dispatchEvent(new ErrorEvent("PRELOAD_" + event.type.toUpperCase() + "_ERROR")); + } + break; + } +}; + +/** + * The "success" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous + * functions. + * @method _resultFormatSuccess + * @param {Object} result The formatted result + * @private + */ +p._resultFormatSuccess = function (result) { + this._result = result; + this._sendComplete(); +}; + +/** + * The "error" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous + * functions. + * @method _resultFormatSuccess + * @param {Object} error The error event + * @private + */ +p._resultFormatFailed = function (event) { + this._sendError(event); +}; + +/** + * @method buildPath + * @protected + * @deprecated Use the {{#crossLink "RequestUtils"}}{{/crossLink}} method {{#crossLink "RequestUtils/buildPath"}}{{/crossLink}} + * instead. + */ +p.buildPath = function (src, data) { + return RequestUtils.buildPath(src, data); +}; + +/** + * @method toString + * @return {String} a string representation of the instance. + */ +p.toString = function () { + return "[PreloadJS AbstractLoader]"; +}; -}()); +module.exports = AbstractLoader = promote(AbstractLoader, "EventDispatcher"); diff --git a/src/preloadjs/loaders/AbstractMediaLoader.js b/src/preloadjs/loaders/AbstractMediaLoader.js index a3a0298..b089814 100644 --- a/src/preloadjs/loaders/AbstractMediaLoader.js +++ b/src/preloadjs/loaders/AbstractMediaLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -128,4 +129,4 @@ this.createjs = this.createjs || {}; createjs.AbstractMediaLoader = createjs.promote(AbstractMediaLoader, "AbstractLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/BinaryLoader.js b/src/preloadjs/loaders/BinaryLoader.js index 8195a66..3a07b8b 100644 --- a/src/preloadjs/loaders/BinaryLoader.js +++ b/src/preloadjs/loaders/BinaryLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -79,4 +80,4 @@ this.createjs = this.createjs || {}; createjs.BinaryLoader = createjs.promote(BinaryLoader, "AbstractLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/CSSLoader.js b/src/preloadjs/loaders/CSSLoader.js index 2eb7160..a9ba1cb 100644 --- a/src/preloadjs/loaders/CSSLoader.js +++ b/src/preloadjs/loaders/CSSLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -110,4 +111,4 @@ this.createjs = this.createjs || {}; createjs.CSSLoader = createjs.promote(CSSLoader, "AbstractLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/ImageLoader.js b/src/preloadjs/loaders/ImageLoader.js index 4768588..a494462 100644 --- a/src/preloadjs/loaders/ImageLoader.js +++ b/src/preloadjs/loaders/ImageLoader.js @@ -27,157 +27,159 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -// namespace: -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for image files. - * @class ImageLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractLoader - * @constructor - */ - function ImageLoader (loadItem, preferXHR) { - this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.IMAGE); - - // public properties - this.resultFormatter = this._formatResult; - - // protected properties - this._tagSrcAttribute = "src"; - - // Check if the preload item is already a tag. - if (createjs.RequestUtils.isImageTag(loadItem)) { - this._tag = loadItem; - } else if (createjs.RequestUtils.isImageTag(loadItem.src)) { - this._tag = loadItem.src; - } else if (createjs.RequestUtils.isImageTag(loadItem.tag)) { - this._tag = loadItem.tag; - } - - if (this._tag != null) { - this._preferXHR = false; - } else { - this._tag = document.createElement("img"); - } - - this.on("initialize", this._updateXHR, this); - }; - - var p = createjs.extend(ImageLoader, createjs.AbstractLoader); - var s = ImageLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.IMAGE; - }; - - // public methods - p.load = function () { - if (this._tag.src != "" && this._tag.complete) { - this._sendComplete(); - return; - } - - var crossOrigin = this._item.crossOrigin; - if (crossOrigin == true) { crossOrigin = "Anonymous"; } - if (crossOrigin != null && !createjs.RequestUtils.isLocal(this._item.src)) { - this._tag.crossOrigin = crossOrigin; - } - - this.AbstractLoader_load(); - }; - - // protected methods - /** - * Before the item loads, set its mimeType and responseType. - * @property _updateXHR - * @param {Event} event - * @private - */ - p._updateXHR = function (event) { - event.loader.mimeType = 'text/plain; charset=x-user-defined-binary'; - - // Only exists for XHR - if (event.loader.setResponseType) { - event.loader.setResponseType("blob"); - } - }; - - /** - * The result formatter for Image files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLImageElement} - * @private - */ - p._formatResult = function (loader) { - return this._formatImage; - }; - - /** - * The asynchronous image formatter function. This is required because images have - * a short delay before they are ready. - * @method _formatImage - * @param {Function} successCallback The method to call when the result has finished formatting - * @param {Function} errorCallback The method to call if an error occurs during formatting - * @private - */ - p._formatImage = function (successCallback, errorCallback) { - var tag = this._tag; - var URL = window.URL || window.webkitURL; - - if (!this._preferXHR) { - //document.body.removeChild(tag); - } else if (URL) { - var objURL = URL.createObjectURL(this.getResult(true)); - tag.src = objURL; - - tag.addEventListener("load", this._cleanUpURL, false); - tag.addEventListener("error", this._cleanUpURL, false); - } else { - tag.src = this._item.src; - } - - if (tag.complete) { - successCallback(tag); - } else { - tag.onload = createjs.proxy(function() { - successCallback(this._tag); - }, this); - - tag.onerror = createjs.proxy(function() { - errorCallback(_this._tag); - }, this); - } - }; - - /** - * Clean up the ObjectURL, the tag is done with it. Note that this function is run - * as an event listener without a proxy/closure, as it doesn't require it - so do not - * include any functionality that requires scope without changing it. - * @method _cleanUpURL - * @param event - * @private - */ - p._cleanUpURL = function (event) { - var URL = window.URL || window.webkitURL; - URL.revokeObjectURL(event.target.src); - }; - - createjs.ImageLoader = createjs.promote(ImageLoader, "AbstractLoader"); - -}()); +// constructor +/** + * A loader for image files. + * @class ImageLoader + * @param {LoadItem|Object} loadItem + * @param {Boolean} preferXHR + * @extends AbstractLoader + * @constructor + */ + +var AbstractLoader = require('./AbstractLoader'); +var RequestUtils = require('../utils/RequestUtils'); +var extend = require('../../createjs/utils/extend'); +var promote = require('../../createjs/utils/promote'); +var proxy = require('../../createjs/utils/proxy'); + +function ImageLoader(loadItem, preferXHR) { + this.AbstractLoader_constructor(loadItem, preferXHR, AbstractLoader.IMAGE); + + // public properties + this.resultFormatter = this._formatResult; + + // protected properties + this._tagSrcAttribute = "src"; + + // Check if the preload item is already a tag. + if (RequestUtils.isImageTag(loadItem)) { + this._tag = loadItem; + } else if (RequestUtils.isImageTag(loadItem.src)) { + this._tag = loadItem.src; + } else if (RequestUtils.isImageTag(loadItem.tag)) { + this._tag = loadItem.tag; + } + + if (this._tag != null) { + this._preferXHR = false; + } else { + this._tag = document.createElement("img"); + } + + this.on("initialize", this._updateXHR, this); +}; + +var p = extend(ImageLoader, AbstractLoader); +var s = ImageLoader; + +// static methods +/** + * Determines if the loader can load a specific item. This loader can only load items that are of type + * {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}. + * @method canLoadItem + * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. + * @returns {Boolean} Whether the loader can load the item. + * @static + */ +s.canLoadItem = function (item) { + return item.type == AbstractLoader.IMAGE; +}; + +// public methods +p.load = function () { + if (this._tag.src != "" && this._tag.complete) { + this._sendComplete(); + return; + } + + var crossOrigin = this._item.crossOrigin; + if (crossOrigin == true) { + crossOrigin = "Anonymous"; + } + if (crossOrigin != null && !RequestUtils.isLocal(this._item.src)) { + this._tag.crossOrigin = crossOrigin; + } + + this.AbstractLoader_load(); +}; + +// protected methods +/** + * Before the item loads, set its mimeType and responseType. + * @property _updateXHR + * @param {Event} event + * @private + */ +p._updateXHR = function (event) { + event.loader.mimeType = 'text/plain; charset=x-user-defined-binary'; + + // Only exists for XHR + if (event.loader.setResponseType) { + event.loader.setResponseType("blob"); + } +}; + +/** + * The result formatter for Image files. + * @method _formatResult + * @param {AbstractLoader} loader + * @returns {HTMLImageElement} + * @private + */ +p._formatResult = function (loader) { + return this._formatImage; +}; + +/** + * The asynchronous image formatter function. This is required because images have + * a short delay before they are ready. + * @method _formatImage + * @param {Function} successCallback The method to call when the result has finished formatting + * @param {Function} errorCallback The method to call if an error occurs during formatting + * @private + */ +p._formatImage = function (successCallback, errorCallback) { + var tag = this._tag; + var URL = window.URL || window.webkitURL; + + if (!this._preferXHR) { + //document.body.removeChild(tag); + } else if (URL) { + var objURL = URL.createObjectURL(this.getResult(true)); + tag.src = objURL; + + tag.addEventListener("load", this._cleanUpURL, false); + tag.addEventListener("error", this._cleanUpURL, false); + } else { + tag.src = this._item.src; + } + + if (tag.complete) { + successCallback(tag); + } else { + tag.onload = proxy(function () { + successCallback(this._tag); + }, this); + + tag.onerror = proxy(function () { + errorCallback(_this._tag); + }, this); + } +}; + +/** + * Clean up the ObjectURL, the tag is done with it. Note that this function is run + * as an event listener without a proxy/closure, as it doesn't require it - so do not + * include any functionality that requires scope without changing it. + * @method _cleanUpURL + * @param event + * @private + */ +p._cleanUpURL = function (event) { + var URL = window.URL || window.webkitURL; + URL.revokeObjectURL(event.target.src); +}; + +var ImageLoader = promote(ImageLoader, "AbstractLoader"); +module.exports = ImageLoader; diff --git a/src/preloadjs/loaders/JSONLoader.js b/src/preloadjs/loaders/JSONLoader.js index e088ae9..7628818 100644 --- a/src/preloadjs/loaders/JSONLoader.js +++ b/src/preloadjs/loaders/JSONLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -93,4 +94,4 @@ this.createjs = this.createjs || {}; createjs.JSONLoader = createjs.promote(JSONLoader, "AbstractLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/JSONPLoader.js b/src/preloadjs/loaders/JSONPLoader.js index bbb21e6..2ef8889 100644 --- a/src/preloadjs/loaders/JSONPLoader.js +++ b/src/preloadjs/loaders/JSONPLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -177,4 +178,4 @@ this.createjs = this.createjs || {}; createjs.JSONPLoader = createjs.promote(JSONPLoader, "AbstractLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/JavaScriptLoader.js b/src/preloadjs/loaders/JavaScriptLoader.js index 576c989..025e466 100644 --- a/src/preloadjs/loaders/JavaScriptLoader.js +++ b/src/preloadjs/loaders/JavaScriptLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -91,4 +92,4 @@ this.createjs = this.createjs || {}; createjs.JavaScriptLoader = createjs.promote(JavaScriptLoader, "AbstractLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/ManifestLoader.js b/src/preloadjs/loaders/ManifestLoader.js index 53d59e2..2bd79c9 100644 --- a/src/preloadjs/loaders/ManifestLoader.js +++ b/src/preloadjs/loaders/ManifestLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -226,4 +227,4 @@ this.createjs = this.createjs || {}; createjs.ManifestLoader = createjs.promote(ManifestLoader, "AbstractLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/SVGLoader.js b/src/preloadjs/loaders/SVGLoader.js index 2f12dff..4177b7b 100644 --- a/src/preloadjs/loaders/SVGLoader.js +++ b/src/preloadjs/loaders/SVGLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -107,4 +108,4 @@ this.createjs = this.createjs || {}; createjs.SVGLoader = createjs.promote(SVGLoader, "AbstractLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/SoundLoader.js b/src/preloadjs/loaders/SoundLoader.js index a3be741..6d80165 100644 --- a/src/preloadjs/loaders/SoundLoader.js +++ b/src/preloadjs/loaders/SoundLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -95,4 +96,4 @@ this.createjs = this.createjs || {}; createjs.SoundLoader = createjs.promote(SoundLoader, "AbstractMediaLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/SpriteSheetLoader.js b/src/preloadjs/loaders/SpriteSheetLoader.js index af8ee32..e6c3bd6 100644 --- a/src/preloadjs/loaders/SpriteSheetLoader.js +++ b/src/preloadjs/loaders/SpriteSheetLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -204,4 +205,4 @@ this.createjs = this.createjs || {}; createjs.SpriteSheetLoader = createjs.promote(SpriteSheetLoader, "AbstractLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/TextLoader.js b/src/preloadjs/loaders/TextLoader.js index 58f7d11..5e4be86 100644 --- a/src/preloadjs/loaders/TextLoader.js +++ b/src/preloadjs/loaders/TextLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -67,4 +68,4 @@ this.createjs = this.createjs || {}; createjs.TextLoader = createjs.promote(TextLoader, "AbstractLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/VideoLoader.js b/src/preloadjs/loaders/VideoLoader.js index da2f2b3..ccaa242 100644 --- a/src/preloadjs/loaders/VideoLoader.js +++ b/src/preloadjs/loaders/VideoLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -87,4 +88,4 @@ this.createjs = this.createjs || {}; createjs.VideoLoader = createjs.promote(VideoLoader, "AbstractMediaLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/loaders/XMLLoader.js b/src/preloadjs/loaders/XMLLoader.js index a2cb16a..1255ac9 100644 --- a/src/preloadjs/loaders/XMLLoader.js +++ b/src/preloadjs/loaders/XMLLoader.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -82,4 +83,4 @@ this.createjs = this.createjs || {}; createjs.XMLLoader = createjs.promote(XMLLoader, "AbstractLoader"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/net/AbstractRequest.js b/src/preloadjs/net/AbstractRequest.js index ccb10ae..0a0710e 100644 --- a/src/preloadjs/net/AbstractRequest.js +++ b/src/preloadjs/net/AbstractRequest.js @@ -31,45 +31,44 @@ * @module PreloadJS */ -// namespace: -this.createjs = this.createjs || {}; +var promote = require('../../createjs/utils/promote'); +var extend = require('../../createjs/utils/extend'); +var EventDispatcher = require('../../createjs/events/EventDispatcher'); -(function () { - "use strict"; - - /** - * A base class for actual data requests, such as {{#crossLink "XHRRequest"}}{{/crossLink}}, {{#crossLink "TagRequest"}}{{/crossLink}}, - * and {{#crossLink "MediaRequest"}}{{/crossLink}}. PreloadJS loaders will typically use a data loader under the - * hood to get data. - * @class AbstractRequest - * @param {LoadItem} item - * @constructor - */ - var AbstractRequest = function (item) { - this._item = item; - }; - - var p = createjs.extend(AbstractRequest, createjs.EventDispatcher); +/** + * A base class for actual data requests, such as {{#crossLink "XHRRequest"}}{{/crossLink}}, {{#crossLink "TagRequest"}}{{/crossLink}}, + * and {{#crossLink "MediaRequest"}}{{/crossLink}}. PreloadJS loaders will typically use a data loader under the + * hood to get data. + * @class AbstractRequest + * @param {LoadItem} item + * @constructor + */ +var AbstractRequest = function (item) { + this._item = item; +}; - // public methods - /** - * Begin a load. - * @method load - */ - p.load = function() {}; +var p = extend(AbstractRequest, EventDispatcher); - /** - * Clean up a request. - * @method destroy - */ - p.destroy = function() {}; +// public methods +/** + * Begin a load. + * @method load + */ +p.load = function () { +}; - /** - * Cancel an in-progress request. - * @method cancel - */ - p.cancel = function() {}; +/** + * Clean up a request. + * @method destroy + */ +p.destroy = function () { +}; - createjs.AbstractRequest = createjs.promote(AbstractRequest, "EventDispatcher"); +/** + * Cancel an in-progress request. + * @method cancel + */ +p.cancel = function () { +}; -}()); \ No newline at end of file +module.exports = AbstractRequest = promote(AbstractRequest, "EventDispatcher"); diff --git a/src/preloadjs/net/MediaTagRequest.js b/src/preloadjs/net/MediaTagRequest.js index 39c0fe0..88a21ff 100644 --- a/src/preloadjs/net/MediaTagRequest.js +++ b/src/preloadjs/net/MediaTagRequest.js @@ -32,9 +32,10 @@ */ // namespace: -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; // constructor @@ -118,4 +119,4 @@ this.createjs = this.createjs || {}; createjs.MediaTagRequest = createjs.promote(MediaTagRequest, "TagRequest"); -}()); +}(scope.createjs)); diff --git a/src/preloadjs/net/TagRequest.js b/src/preloadjs/net/TagRequest.js index 921c35c..ead17be 100644 --- a/src/preloadjs/net/TagRequest.js +++ b/src/preloadjs/net/TagRequest.js @@ -31,186 +31,184 @@ * @module PreloadJS */ -// namespace: -this.createjs = this.createjs || {}; +var proxy = require('../../createjs/utils/proxy'); +var extend = require('../../createjs/utils/extend'); +var AbstractRequest = require('./AbstractRequest'); +var Event = require('../../createjs/events/Event'); +var promote = require('../../createjs/utils/promote'); -(function () { - "use strict"; +// constructor +/** + * An {{#crossLink "AbstractRequest"}}{{/crossLink}} that loads HTML tags, such as images and scripts. + * @class TagRequest + * @param {LoadItem} loadItem + * @param {HTMLElement} tag + * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. + */ +function TagRequest(loadItem, tag, srcAttribute) { + this.AbstractRequest_constructor(loadItem); - // constructor - /** - * An {{#crossLink "AbstractRequest"}}{{/crossLink}} that loads HTML tags, such as images and scripts. - * @class TagRequest - * @param {LoadItem} loadItem - * @param {HTMLElement} tag - * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. - */ - function TagRequest(loadItem, tag, srcAttribute) { - this.AbstractRequest_constructor(loadItem); - - // protected properties - /** - * The HTML tag instance that is used to load. - * @property _tag - * @type {HTMLElement} - * @protected - */ - this._tag = tag; - - /** - * The tag attribute that specifies the source, such as "src", "href", etc. - * @property _tagSrcAttribute - * @type {String} - * @protected - */ - this._tagSrcAttribute = srcAttribute; - - /** - * A method closure used for handling the tag load event. - * @property _loadedHandler - * @type {Function} - * @private - */ - this._loadedHandler = createjs.proxy(this._handleTagComplete, this); - - /** - * Determines if the element was added to the DOM automatically by PreloadJS, so it can be cleaned up after. - * @property _addedToDOM - * @type {Boolean} - * @private - */ - this._addedToDOM = false; - - /** - * Determines what the tags initial style.visibility was, so we can set it correctly after a load. - * - * @type {null} - * @private - */ - this._startTagVisibility = null; - }; - - var p = createjs.extend(TagRequest, createjs.AbstractRequest); - - // public methods - p.load = function () { - this._tag.onload = createjs.proxy(this._handleTagComplete, this); - this._tag.onreadystatechange = createjs.proxy(this._handleReadyStateChange, this); - this._tag.onerror = createjs.proxy(this._handleError, this); - - var evt = new createjs.Event("initialize"); - evt.loader = this._tag; - - this.dispatchEvent(evt); - - this._hideTag(); - - this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); - - this._tag[this._tagSrcAttribute] = this._item.src; - - // wdg:: Append the tag AFTER setting the src, or SVG loading on iOS will fail. - if (this._tag.parentNode == null) { - window.document.body.appendChild(this._tag); - this._addedToDOM = true; - } - }; - - p.destroy = function() { - this._clean(); - this._tag = null; - - this.AbstractRequest_destroy(); - }; - - // private methods + // protected properties /** - * Handle the readyStateChange event from a tag. We need this in place of the `onload` callback (mainly SCRIPT - * and LINK tags), but other cases may exist. - * @method _handleReadyStateChange - * @private + * The HTML tag instance that is used to load. + * @property _tag + * @type {HTMLElement} + * @protected */ - p._handleReadyStateChange = function () { - clearTimeout(this._loadTimeout); - // This is strictly for tags in browsers that do not support onload. - var tag = this._tag; - - // Complete is for old IE support. - if (tag.readyState == "loaded" || tag.readyState == "complete") { - this._handleTagComplete(); - } - }; + this._tag = tag; /** - * Handle any error events from the tag. - * @method _handleError + * The tag attribute that specifies the source, such as "src", "href", etc. + * @property _tagSrcAttribute + * @type {String} * @protected */ - p._handleError = function() { - this._clean(); - this.dispatchEvent("error"); - }; + this._tagSrcAttribute = srcAttribute; /** - * Handle the tag's onload callback. - * @method _handleTagComplete + * A method closure used for handling the tag load event. + * @property _loadedHandler + * @type {Function} * @private */ - p._handleTagComplete = function () { - this._rawResult = this._tag; - this._result = this.resultFormatter && this.resultFormatter(this) || this._rawResult; - - this._clean(); - this._showTag(); - - this.dispatchEvent("complete"); - }; + this._loadedHandler = proxy(this._handleTagComplete, this); /** - * The tag request has not loaded within the time specified in loadTimeout. - * @method _handleError - * @param {Object} event The XHR error event. + * Determines if the element was added to the DOM automatically by PreloadJS, so it can be cleaned up after. + * @property _addedToDOM + * @type {Boolean} * @private */ - p._handleTimeout = function () { - this._clean(); - this.dispatchEvent(new createjs.Event("timeout")); - }; + this._addedToDOM = false; /** - * Remove event listeners, but don't destroy the request object - * @method _clean + * Determines what the tags initial style.visibility was, so we can set it correctly after a load. + * + * @type {null} * @private */ - p._clean = function() { - this._tag.onload = null; - this._tag.onreadystatechange = null; - this._tag.onerror = null; - if (this._addedToDOM && this._tag.parentNode != null) { - this._tag.parentNode.removeChild(this._tag); - } - clearTimeout(this._loadTimeout); - }; - - p._hideTag = function() { - this._startTagVisibility = this._tag.style.visibility; - this._tag.style.visibility = "hidden"; - }; - - p._showTag = function() { - this._tag.style.visibility = this._startTagVisibility; - }; + this._startTagVisibility = null; +}; - /** - * Handle a stalled audio event. The main place this happens is with HTMLAudio in Chrome when playing back audio - * that is already in a load, but not complete. - * @method _handleStalled - * @private - */ - p._handleStalled = function () { - //Ignore, let the timeout take care of it. Sometimes its not really stopped. - }; +var p = extend(TagRequest, AbstractRequest); + +// public methods +p.load = function () { + this._tag.onload = proxy(this._handleTagComplete, this); + this._tag.onreadystatechange = proxy(this._handleReadyStateChange, this); + this._tag.onerror = proxy(this._handleError, this); + + var evt = new Event("initialize"); + evt.loader = this._tag; + + this.dispatchEvent(evt); + + this._hideTag(); + + this._loadTimeout = setTimeout(proxy(this._handleTimeout, this), this._item.loadTimeout); + + this._tag[this._tagSrcAttribute] = this._item.src; + + // wdg:: Append the tag AFTER setting the src, or SVG loading on iOS will fail. + if (this._tag.parentNode == null) { + window.document.body.appendChild(this._tag); + this._addedToDOM = true; + } +}; + +p.destroy = function () { + this._clean(); + this._tag = null; + + this.AbstractRequest_destroy(); +}; - createjs.TagRequest = createjs.promote(TagRequest, "AbstractRequest"); +// private methods +/** + * Handle the readyStateChange event from a tag. We need this in place of the `onload` callback (mainly SCRIPT + * and LINK tags), but other cases may exist. + * @method _handleReadyStateChange + * @private + */ +p._handleReadyStateChange = function () { + clearTimeout(this._loadTimeout); + // This is strictly for tags in browsers that do not support onload. + var tag = this._tag; + + // Complete is for old IE support. + if (tag.readyState == "loaded" || tag.readyState == "complete") { + this._handleTagComplete(); + } +}; + +/** + * Handle any error events from the tag. + * @method _handleError + * @protected + */ +p._handleError = function () { + this._clean(); + this.dispatchEvent("error"); +}; + +/** + * Handle the tag's onload callback. + * @method _handleTagComplete + * @private + */ +p._handleTagComplete = function () { + this._rawResult = this._tag; + this._result = this.resultFormatter && this.resultFormatter(this) || this._rawResult; + + this._clean(); + this._showTag(); + + this.dispatchEvent("complete"); +}; + +/** + * The tag request has not loaded within the time specified in loadTimeout. + * @method _handleError + * @param {Object} event The XHR error event. + * @private + */ +p._handleTimeout = function () { + this._clean(); + this.dispatchEvent(new Event("timeout")); +}; + +/** + * Remove event listeners, but don't destroy the request object + * @method _clean + * @private + */ +p._clean = function () { + this._tag.onload = null; + this._tag.onreadystatechange = null; + this._tag.onerror = null; + if (this._addedToDOM && this._tag.parentNode != null) { + this._tag.parentNode.removeChild(this._tag); + } + clearTimeout(this._loadTimeout); +}; + +p._hideTag = function () { + this._startTagVisibility = this._tag.style.visibility; + this._tag.style.visibility = "hidden"; +}; + +p._showTag = function () { + this._tag.style.visibility = this._startTagVisibility; +}; + +/** + * Handle a stalled audio event. The main place this happens is with HTMLAudio in Chrome when playing back audio + * that is already in a load, but not complete. + * @method _handleStalled + * @private + */ +p._handleStalled = function () { + //Ignore, let the timeout take care of it. Sometimes its not really stopped. +}; -}()); +module.exports = promote(TagRequest, "AbstractRequest"); \ No newline at end of file diff --git a/src/preloadjs/net/XHRRequest.js b/src/preloadjs/net/XHRRequest.js index a5cfee6..8326dea 100644 --- a/src/preloadjs/net/XHRRequest.js +++ b/src/preloadjs/net/XHRRequest.js @@ -31,533 +31,533 @@ * @module PreloadJS */ -// namespace: -this.createjs = this.createjs || {}; +var proxy = require('../../createjs/utils/proxy'); +var extend = require('../../createjs/utils/extend'); +var promote = require('../../createjs/utils/promote'); +var AbstractRequest = require('./AbstractRequest'); +var AbstractLoader = require('../loaders/AbstractLoader'); +var RequestUtils = require('../utils/RequestUtils'); +var ErrorEvent = require('../../createjs/events/ErrorEvent'); +var ProgressEvent = require('../events/ProgressEvent'); -(function () { - "use strict"; +/** + * A preloader that loads items using XHR requests, usually XMLHttpRequest. However XDomainRequests will be used + * for cross-domain requests if possible, and older versions of IE fall back on to ActiveX objects when necessary. + * XHR requests load the content as text or binary data, provide progress and consistent completion events, and + * can be canceled during load. Note that XHR is not supported in IE 6 or earlier, and is not recommended for + * cross-domain loading. + * @class XHRRequest + * @constructor + * @param {Object} item The object that defines the file to load. Please see the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} + * for an overview of supported file properties. + * @extends AbstractLoader + */ +function XHRRequest(item) { + this.AbstractRequest_constructor(item); -// constructor + // protected properties /** - * A preloader that loads items using XHR requests, usually XMLHttpRequest. However XDomainRequests will be used - * for cross-domain requests if possible, and older versions of IE fall back on to ActiveX objects when necessary. - * XHR requests load the content as text or binary data, provide progress and consistent completion events, and - * can be canceled during load. Note that XHR is not supported in IE 6 or earlier, and is not recommended for - * cross-domain loading. - * @class XHRRequest - * @constructor - * @param {Object} item The object that defines the file to load. Please see the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * for an overview of supported file properties. - * @extends AbstractLoader + * A reference to the XHR request used to load the content. + * @property _request + * @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP} + * @private */ - function XHRRequest (item) { - this.AbstractRequest_constructor(item); - - // protected properties - /** - * A reference to the XHR request used to load the content. - * @property _request - * @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP} - * @private - */ - this._request = null; - - /** - * A manual load timeout that is used for browsers that do not support the onTimeout event on XHR (XHR level 1, - * typically IE9). - * @property _loadTimeout - * @type {Number} - * @private - */ - this._loadTimeout = null; - - /** - * The browser's XHR (XMLHTTPRequest) version. Supported versions are 1 and 2. There is no official way to detect - * the version, so we use capabilities to make a best guess. - * @property _xhrLevel - * @type {Number} - * @default 1 - * @private - */ - this._xhrLevel = 1; - - /** - * The response of a loaded file. This is set because it is expensive to look up constantly. This property will be - * null until the file is loaded. - * @property _response - * @type {mixed} - * @private - */ - this._response = null; - - /** - * The response of the loaded file before it is modified. In most cases, content is converted from raw text to - * an HTML tag or a formatted object which is set to the result property, but the developer may still - * want to access the raw content as it was loaded. - * @property _rawResponse - * @type {String|Object} - * @private - */ - this._rawResponse = null; - - this._canceled = false; - - // Setup our event handlers now. - this._handleLoadStartProxy = createjs.proxy(this._handleLoadStart, this); - this._handleProgressProxy = createjs.proxy(this._handleProgress, this); - this._handleAbortProxy = createjs.proxy(this._handleAbort, this); - this._handleErrorProxy = createjs.proxy(this._handleError, this); - this._handleTimeoutProxy = createjs.proxy(this._handleTimeout, this); - this._handleLoadProxy = createjs.proxy(this._handleLoad, this); - this._handleReadyStateChangeProxy = createjs.proxy(this._handleReadyStateChange, this); - - if (!this._createXHR(item)) { - //TODO: Throw error? - } - }; - - var p = createjs.extend(XHRRequest, createjs.AbstractRequest); + this._request = null; -// static properties /** - * A list of XMLHTTP object IDs to try when building an ActiveX object for XHR requests in earlier versions of IE. - * @property ACTIVEX_VERSIONS - * @type {Array} - * @since 0.4.2 + * A manual load timeout that is used for browsers that do not support the onTimeout event on XHR (XHR level 1, + * typically IE9). + * @property _loadTimeout + * @type {Number} * @private */ - XHRRequest.ACTIVEX_VERSIONS = [ - "Msxml2.XMLHTTP.6.0", - "Msxml2.XMLHTTP.5.0", - "Msxml2.XMLHTTP.4.0", - "MSXML2.XMLHTTP.3.0", - "MSXML2.XMLHTTP", - "Microsoft.XMLHTTP" - ]; + this._loadTimeout = null; -// Public methods /** - * Look up the loaded result. - * @method getResult - * @param {Boolean} [raw=false] Return a raw result instead of a formatted result. This applies to content - * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be - * returned instead. - * @return {Object} A result object containing the content that was loaded, such as: - *
    - *
  • An image tag (<image />) for images
  • - *
  • A script tag for JavaScript (<script />). Note that scripts loaded with tags may be added to the - * HTML head.
  • - *
  • A style tag for CSS (<style />)
  • - *
  • Raw text for TEXT
  • - *
  • A formatted JavaScript object defined by JSON
  • - *
  • An XML document
  • - *
  • An binary arraybuffer loaded by XHR
  • - *
- * Note that if a raw result is requested, but not found, the result will be returned instead. - */ - p.getResult = function (raw) { - if (raw && this._rawResponse) { - return this._rawResponse; - } - return this._response; - }; - - // Overrides abstract method in AbstractRequest - p.cancel = function () { - this.canceled = true; - this._clean(); - this._request.abort(); - }; - - // Overrides abstract method in AbstractLoader - p.load = function () { - if (this._request == null) { - this._handleError(); - return; - } - - //Events - if (this._request.addEventListener != null) { - this._request.addEventListener("loadstart", this._handleLoadStartProxy, false); - this._request.addEventListener("progress", this._handleProgressProxy, false); - this._request.addEventListener("abort", this._handleAbortProxy, false); - this._request.addEventListener("error", this._handleErrorProxy, false); - this._request.addEventListener("timeout", this._handleTimeoutProxy, false); - - // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. - this._request.addEventListener("load", this._handleLoadProxy, false); - this._request.addEventListener("readystatechange", this._handleReadyStateChangeProxy, false); - } else { - // IE9 support - this._request.onloadstart = this._handleLoadStartProxy; - this._request.onprogress = this._handleProgressProxy; - this._request.onabort = this._handleAbortProxy; - this._request.onerror = this._handleErrorProxy; - this._request.ontimeout = this._handleTimeoutProxy; - - // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. - this._request.onload = this._handleLoadProxy; - this._request.onreadystatechange = this._handleReadyStateChangeProxy; - } - - // Set up a timeout if we don't have XHR2 - if (this._xhrLevel == 1) { - this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); - } - - // Sometimes we get back 404s immediately, particularly when there is a cross origin request. // note this does not catch in Chrome - try { - if (!this._item.values || this._item.method == createjs.AbstractLoader.GET) { - this._request.send(); - } else if (this._item.method == createjs.AbstractLoader.POST) { - this._request.send(createjs.RequestUtils.formatQueryString(this._item.values)); - } - } catch (error) { - this.dispatchEvent(new createjs.ErrorEvent("XHR_SEND", null, error)); - } - }; - - p.setResponseType = function (type) { - // Some old browsers doesn't support blob, so we convert arraybuffer to blob after response is downloaded - if (type === 'blob') { - type = window.URL ? 'blob' : 'arraybuffer'; - this._responseType = type; - } - this._request.responseType = type; - }; - - /** - * Get all the response headers from the XmlHttpRequest. - * - * From the docs: Return all the HTTP headers, excluding headers that are a case-insensitive match - * for Set-Cookie or Set-Cookie2, as a single string, with each header line separated by a U+000D CR U+000A LF pair, - * excluding the status line, and with each header name and header value separated by a U+003A COLON U+0020 SPACE - * pair. - * @method getAllResponseHeaders - * @return {String} - * @since 0.4.1 + * The browser's XHR (XMLHTTPRequest) version. Supported versions are 1 and 2. There is no official way to detect + * the version, so we use capabilities to make a best guess. + * @property _xhrLevel + * @type {Number} + * @default 1 + * @private */ - p.getAllResponseHeaders = function () { - if (this._request.getAllResponseHeaders instanceof Function) { - return this._request.getAllResponseHeaders(); - } else { - return null; - } - }; + this._xhrLevel = 1; /** - * Get a specific response header from the XmlHttpRequest. - * - * From the docs: Returns the header field value from the response of which the field name matches - * header, unless the field name is Set-Cookie or Set-Cookie2. - * @method getResponseHeader - * @param {String} header The header name to retrieve. - * @return {String} - * @since 0.4.1 + * The response of a loaded file. This is set because it is expensive to look up constantly. This property will be + * null until the file is loaded. + * @property _response + * @type {mixed} + * @private */ - p.getResponseHeader = function (header) { - if (this._request.getResponseHeader instanceof Function) { - return this._request.getResponseHeader(header); - } else { - return null; - } - }; + this._response = null; -// protected methods /** - * The XHR request has reported progress. - * @method _handleProgress - * @param {Object} event The XHR progress event. + * The response of the loaded file before it is modified. In most cases, content is converted from raw text to + * an HTML tag or a formatted object which is set to the result property, but the developer may still + * want to access the raw content as it was loaded. + * @property _rawResponse + * @type {String|Object} * @private */ - p._handleProgress = function (event) { - if (!event || event.loaded > 0 && event.total == 0) { - return; // Sometimes we get no "total", so just ignore the progress event. - } + this._rawResponse = null; - var newEvent = new createjs.ProgressEvent(event.loaded, event.total); - this.dispatchEvent(newEvent); - }; + this._canceled = false; - /** - * The XHR request has reported a load start. - * @method _handleLoadStart - * @param {Object} event The XHR loadStart event. - * @private - */ - p._handleLoadStart = function (event) { - clearTimeout(this._loadTimeout); - this.dispatchEvent("loadstart"); - }; + // Setup our event handlers now. + this._handleLoadStartProxy = proxy(this._handleLoadStart, this); + this._handleProgressProxy = proxy(this._handleProgress, this); + this._handleAbortProxy = proxy(this._handleAbort, this); + this._handleErrorProxy = proxy(this._handleError, this); + this._handleTimeoutProxy = proxy(this._handleTimeout, this); + this._handleLoadProxy = proxy(this._handleLoad, this); + this._handleReadyStateChangeProxy = proxy(this._handleReadyStateChange, this); - /** - * The XHR request has reported an abort event. - * @method handleAbort - * @param {Object} event The XHR abort event. - * @private - */ - p._handleAbort = function (event) { - this._clean(); - this.dispatchEvent(new createjs.ErrorEvent("XHR_ABORTED", null, event)); - }; + if (!this._createXHR(item)) { + //TODO: Throw error? + } +}; - /** - * The XHR request has reported an error event. - * @method _handleError - * @param {Object} event The XHR error event. - * @private - */ - p._handleError = function (event) { - this._clean(); - this.dispatchEvent(new createjs.ErrorEvent(event.message)); - }; +var p = extend(XHRRequest, AbstractRequest); - /** - * The XHR request has reported a readyState change. Note that older browsers (IE 7 & 8) do not provide an onload - * event, so we must monitor the readyStateChange to determine if the file is loaded. - * @method _handleReadyStateChange - * @param {Object} event The XHR readyStateChange event. - * @private - */ - p._handleReadyStateChange = function (event) { - if (this._request.readyState == 4) { - this._handleLoad(); - } - }; +// static properties +/** + * A list of XMLHTTP object IDs to try when building an ActiveX object for XHR requests in earlier versions of IE. + * @property ACTIVEX_VERSIONS + * @type {Array} + * @since 0.4.2 + * @private + */ +XHRRequest.ACTIVEX_VERSIONS = [ + "Msxml2.XMLHTTP.6.0", + "Msxml2.XMLHTTP.5.0", + "Msxml2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", + "MSXML2.XMLHTTP", + "Microsoft.XMLHTTP" +]; - /** - * The XHR request has completed. This is called by the XHR request directly, or by a readyStateChange that has - * request.readyState == 4. Only the first call to this method will be processed. - * @method _handleLoad - * @param {Object} event The XHR load event. - * @private - */ - p._handleLoad = function (event) { - if (this.loaded) { - return; +// Public methods +/** + * Look up the loaded result. + * @method getResult + * @param {Boolean} [raw=false] Return a raw result instead of a formatted result. This applies to content + * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be + * returned instead. + * @return {Object} A result object containing the content that was loaded, such as: + *
    + *
  • An image tag (<image />) for images
  • + *
  • A script tag for JavaScript (<script />). Note that scripts loaded with tags may be added to the + * HTML head.
  • + *
  • A style tag for CSS (<style />)
  • + *
  • Raw text for TEXT
  • + *
  • A formatted JavaScript object defined by JSON
  • + *
  • An XML document
  • + *
  • An binary arraybuffer loaded by XHR
  • + *
+ * Note that if a raw result is requested, but not found, the result will be returned instead. + */ +p.getResult = function (raw) { + if (raw && this._rawResponse) { + return this._rawResponse; + } + return this._response; +}; + +// Overrides abstract method in AbstractRequest +p.cancel = function () { + this.canceled = true; + this._clean(); + this._request.abort(); +}; + +// Overrides abstract method in AbstractLoader +p.load = function () { + if (this._request == null) { + this._handleError(); + return; + } + + //Events + if (this._request.addEventListener != null) { + this._request.addEventListener("loadstart", this._handleLoadStartProxy, false); + this._request.addEventListener("progress", this._handleProgressProxy, false); + this._request.addEventListener("abort", this._handleAbortProxy, false); + this._request.addEventListener("error", this._handleErrorProxy, false); + this._request.addEventListener("timeout", this._handleTimeoutProxy, false); + + // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. + this._request.addEventListener("load", this._handleLoadProxy, false); + this._request.addEventListener("readystatechange", this._handleReadyStateChangeProxy, false); + } else { + // IE9 support + this._request.onloadstart = this._handleLoadStartProxy; + this._request.onprogress = this._handleProgressProxy; + this._request.onabort = this._handleAbortProxy; + this._request.onerror = this._handleErrorProxy; + this._request.ontimeout = this._handleTimeoutProxy; + + // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. + this._request.onload = this._handleLoadProxy; + this._request.onreadystatechange = this._handleReadyStateChangeProxy; + } + + // Set up a timeout if we don't have XHR2 + if (this._xhrLevel == 1) { + this._loadTimeout = setTimeout(proxy(this._handleTimeout, this), this._item.loadTimeout); + } + + // Sometimes we get back 404s immediately, particularly when there is a cross origin request. // note this does not catch in Chrome + try { + if (!this._item.values || this._item.method == AbstractLoader.GET) { + this._request.send(); + } else if (this._item.method == AbstractLoader.POST) { + this._request.send(RequestUtils.formatQueryString(this._item.values)); } - this.loaded = true; + } catch (error) { + this.dispatchEvent(new ErrorEvent("XHR_SEND", null, error)); + } +}; + +p.setResponseType = function (type) { + // Some old browsers doesn't support blob, so we convert arraybuffer to blob after response is downloaded + if (type === 'blob') { + type = window.URL ? 'blob' : 'arraybuffer'; + this._responseType = type; + } + this._request.responseType = type; +}; - var error = this._checkError(); - if (error) { - this._handleError(error); - return; - } +/** + * Get all the response headers from the XmlHttpRequest. + * + * From the docs: Return all the HTTP headers, excluding headers that are a case-insensitive match + * for Set-Cookie or Set-Cookie2, as a single string, with each header line separated by a U+000D CR U+000A LF pair, + * excluding the status line, and with each header name and header value separated by a U+003A COLON U+0020 SPACE + * pair. + * @method getAllResponseHeaders + * @return {String} + * @since 0.4.1 + */ +p.getAllResponseHeaders = function () { + if (this._request.getAllResponseHeaders instanceof Function) { + return this._request.getAllResponseHeaders(); + } else { + return null; + } +}; - this._response = this._getResponse(); - // Convert arraybuffer back to blob - if (this._responseType === 'arraybuffer') { - try { - this._response = new Blob([this._response]); - } catch (e) { - // Fallback to use BlobBuilder if Blob constructor is not supported - // Tested on Android 2.3 ~ 4.2 and iOS5 safari - window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; - if (e.name === 'TypeError' && window.BlobBuilder) { - var builder = new BlobBuilder(); - builder.append(this._response); - this._response = builder.getBlob(); - } - } - } - this._clean(); +/** + * Get a specific response header from the XmlHttpRequest. + * + * From the docs: Returns the header field value from the response of which the field name matches + * header, unless the field name is Set-Cookie or Set-Cookie2. + * @method getResponseHeader + * @param {String} header The header name to retrieve. + * @return {String} + * @since 0.4.1 + */ +p.getResponseHeader = function (header) { + if (this._request.getResponseHeader instanceof Function) { + return this._request.getResponseHeader(header); + } else { + return null; + } +}; - this.dispatchEvent(new createjs.Event("complete")); - }; +// protected methods +/** + * The XHR request has reported progress. + * @method _handleProgress + * @param {Object} event The XHR progress event. + * @private + */ +p._handleProgress = function (event) { + if (!event || event.loaded > 0 && event.total == 0) { + return; // Sometimes we get no "total", so just ignore the progress event. + } - /** - * The XHR request has timed out. This is called by the XHR request directly, or via a setTimeout - * callback. - * @method _handleTimeout - * @param {Object} [event] The XHR timeout event. This is occasionally null when called by the backup setTimeout. - * @private - */ - p._handleTimeout = function (event) { - this._clean(); + var newEvent = new ProgressEvent(event.loaded, event.total); + this.dispatchEvent(newEvent); +}; - this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_TIMEOUT", null, event)); - }; +/** + * The XHR request has reported a load start. + * @method _handleLoadStart + * @param {Object} event The XHR loadStart event. + * @private + */ +p._handleLoadStart = function (event) { + clearTimeout(this._loadTimeout); + this.dispatchEvent("loadstart"); +}; -// Protected - /** - * Determine if there is an error in the current load. This checks the status of the request for problem codes. Note - * that this does not check for an actual response. Currently, it only checks for 404 or 0 error code. - * @method _checkError - * @return {int} If the request status returns an error code. - * @private - */ - p._checkError = function () { - //LM: Probably need additional handlers here, maybe 501 - var status = parseInt(this._request.status); - - switch (status) { - case 404: // Not Found - case 0: // Not Loaded - return new Error(status); - } - return null; - }; +/** + * The XHR request has reported an abort event. + * @method handleAbort + * @param {Object} event The XHR abort event. + * @private + */ +p._handleAbort = function (event) { + this._clean(); + this.dispatchEvent(new ErrorEvent("XHR_ABORTED", null, event)); +}; - /** - * Validate the response. Different browsers have different approaches, some of which throw errors when accessed - * in other browsers. If there is no response, the _response property will remain null. - * @method _getResponse - * @private - */ - p._getResponse = function () { - if (this._response != null) { - return this._response; - } +/** + * The XHR request has reported an error event. + * @method _handleError + * @param {Object} event The XHR error event. + * @private + */ +p._handleError = function (event) { + this._clean(); + this.dispatchEvent(new ErrorEvent(event.message)); +}; - if (this._request.response != null) { - return this._request.response; - } +/** + * The XHR request has reported a readyState change. Note that older browsers (IE 7 & 8) do not provide an onload + * event, so we must monitor the readyStateChange to determine if the file is loaded. + * @method _handleReadyStateChange + * @param {Object} event The XHR readyStateChange event. + * @private + */ +p._handleReadyStateChange = function (event) { + if (this._request.readyState == 4) { + this._handleLoad(); + } +}; - // Android 2.2 uses .responseText +/** + * The XHR request has completed. This is called by the XHR request directly, or by a readyStateChange that has + * request.readyState == 4. Only the first call to this method will be processed. + * @method _handleLoad + * @param {Object} event The XHR load event. + * @private + */ +p._handleLoad = function (event) { + if (this.loaded) { + return; + } + this.loaded = true; + + var error = this._checkError(); + if (error) { + this._handleError(error); + return; + } + + this._response = this._getResponse(); + // Convert arraybuffer back to blob + if (this._responseType === 'arraybuffer') { try { - if (this._request.responseText != null) { - return this._request.responseText; - } + this._response = new Blob([this._response]); } catch (e) { - } - - // When loading XML, IE9 does not return .response, instead it returns responseXML.xml - try { - if (this._request.responseXML != null) { - return this._request.responseXML; + // Fallback to use BlobBuilder if Blob constructor is not supported + // Tested on Android 2.3 ~ 4.2 and iOS5 safari + window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; + if (e.name === 'TypeError' && window.BlobBuilder) { + var builder = new BlobBuilder(); + builder.append(this._response); + this._response = builder.getBlob(); } - } catch (e) { } + } + this._clean(); - return null; - }; + this.dispatchEvent(new Event("complete")); +}; - /** - * Create an XHR request. Depending on a number of factors, we get totally different results. - *
  1. Some browsers get an XDomainRequest when loading cross-domain.
  2. - *
  3. XMLHttpRequest are created when available.
  4. - *
  5. ActiveX.XMLHTTP objects are used in older IE browsers.
  6. - *
  7. Text requests override the mime type if possible
  8. - *
  9. Origin headers are sent for crossdomain requests in some browsers.
  10. - *
  11. Binary loads set the response type to "arraybuffer"
- * @method _createXHR - * @param {Object} item The requested item that is being loaded. - * @return {Boolean} If an XHR request or equivalent was successfully created. - * @private - */ - p._createXHR = function (item) { - // Check for cross-domain loads. We can't fully support them, but we can try. - var crossdomain = createjs.RequestUtils.isCrossDomain(item); - var headers = {}; - - // Create the request. Fallback to whatever support we have. - var req = null; - if (window.XMLHttpRequest) { - req = new XMLHttpRequest(); - // This is 8 or 9, so use XDomainRequest instead. - if (crossdomain && req.withCredentials === undefined && window.XDomainRequest) { - req = new XDomainRequest(); - } - } else { // Old IE versions use a different approach - for (var i = 0, l = s.ACTIVEX_VERSIONS.length; i < l; i++) { - var axVersion = s.ACTIVEX_VERSIONS[i]; - try { - req = new ActiveXObject(axVersion); - break; - } catch (e) { - } - } - if (req == null) { - return false; - } - } - - // Default to utf-8 for Text requests. - if (item.mimeType == null && createjs.RequestUtils.isText(item.type)) { - item.mimeType = "text/plain; charset=utf-8"; - } +/** + * The XHR request has timed out. This is called by the XHR request directly, or via a setTimeout + * callback. + * @method _handleTimeout + * @param {Object} [event] The XHR timeout event. This is occasionally null when called by the backup setTimeout. + * @private + */ +p._handleTimeout = function (event) { + this._clean(); - // IE9 doesn't support overrideMimeType(), so we need to check for it. - if (item.mimeType && req.overrideMimeType) { - req.overrideMimeType(item.mimeType); - } + this.dispatchEvent(new ErrorEvent("PRELOAD_TIMEOUT", null, event)); +}; - // Determine the XHR level - this._xhrLevel = (typeof req.responseType === "string") ? 2 : 1; +// Protected +/** + * Determine if there is an error in the current load. This checks the status of the request for problem codes. Note + * that this does not check for an actual response. Currently, it only checks for 404 or 0 error code. + * @method _checkError + * @return {int} If the request status returns an error code. + * @private + */ +p._checkError = function () { + //LM: Probably need additional handlers here, maybe 501 + var status = parseInt(this._request.status); + + switch (status) { + case 404: // Not Found + case 0: // Not Loaded + return new Error(status); + } + return null; +}; - var src = null; - if (item.method == createjs.AbstractLoader.GET) { - src = createjs.RequestUtils.buildPath(item.src, item.values); - } else { - src = item.src; - } +/** + * Validate the response. Different browsers have different approaches, some of which throw errors when accessed + * in other browsers. If there is no response, the _response property will remain null. + * @method _getResponse + * @private + */ +p._getResponse = function () { + if (this._response != null) { + return this._response; + } - // Open the request. Set cross-domain flags if it is supported (XHR level 1 only) - req.open(item.method || createjs.AbstractLoader.GET, src, true); + if (this._request.response != null) { + return this._request.response; + } - if (crossdomain && req instanceof XMLHttpRequest && this._xhrLevel == 1) { - headers["Origin"] = location.origin; + // Android 2.2 uses .responseText + try { + if (this._request.responseText != null) { + return this._request.responseText; } + } catch (e) { + } - // To send data we need to set the Content-type header) - if (item.values && item.method == createjs.AbstractLoader.POST) { - headers["Content-Type"] = "application/x-www-form-urlencoded"; + // When loading XML, IE9 does not return .response, instead it returns responseXML.xml + try { + if (this._request.responseXML != null) { + return this._request.responseXML; } + } catch (e) { + } - if (!crossdomain && !headers["X-Requested-With"]) { - headers["X-Requested-With"] = "XMLHttpRequest"; - } + return null; +}; - if (item.headers) { - for (var n in item.headers) { - headers[n] = item.headers[n]; +/** + * Create an XHR request. Depending on a number of factors, we get totally different results. + *
  1. Some browsers get an XDomainRequest when loading cross-domain.
  2. + *
  3. XMLHttpRequest are created when available.
  4. + *
  5. ActiveX.XMLHTTP objects are used in older IE browsers.
  6. + *
  7. Text requests override the mime type if possible
  8. + *
  9. Origin headers are sent for crossdomain requests in some browsers.
  10. + *
  11. Binary loads set the response type to "arraybuffer"
+ * @method _createXHR + * @param {Object} item The requested item that is being loaded. + * @return {Boolean} If an XHR request or equivalent was successfully created. + * @private + */ +p._createXHR = function (item) { + // Check for cross-domain loads. We can't fully support them, but we can try. + var crossdomain = RequestUtils.isCrossDomain(item); + var headers = {}; + + // Create the request. Fallback to whatever support we have. + var req = null; + if (window.XMLHttpRequest) { + req = new XMLHttpRequest(); + // This is 8 or 9, so use XDomainRequest instead. + if (crossdomain && req.withCredentials === undefined && window.XDomainRequest) { + req = new XDomainRequest(); + } + } else { // Old IE versions use a different approach + for (var i = 0, l = s.ACTIVEX_VERSIONS.length; i < l; i++) { + var axVersion = s.ACTIVEX_VERSIONS[i]; + try { + req = new ActiveXObject(axVersion); + break; + } catch (e) { } } - - for (n in headers) { - req.setRequestHeader(n, headers[n]) + if (req == null) { + return false; } - - if (req instanceof XMLHttpRequest && item.withCredentials !== undefined) { - req.withCredentials = item.withCredentials; + } + + // Default to utf-8 for Text requests. + if (item.mimeType == null && RequestUtils.isText(item.type)) { + item.mimeType = "text/plain; charset=utf-8"; + } + + // IE9 doesn't support overrideMimeType(), so we need to check for it. + if (item.mimeType && req.overrideMimeType) { + req.overrideMimeType(item.mimeType); + } + + // Determine the XHR level + this._xhrLevel = (typeof req.responseType === "string") ? 2 : 1; + + var src = null; + if (item.method == AbstractLoader.GET) { + src = RequestUtils.buildPath(item.src, item.values); + } else { + src = item.src; + } + + // Open the request. Set cross-domain flags if it is supported (XHR level 1 only) + req.open(item.method || AbstractLoader.GET, src, true); + + if (crossdomain && req instanceof XMLHttpRequest && this._xhrLevel == 1) { + headers["Origin"] = location.origin; + } + + // To send data we need to set the Content-type header) + if (item.values && item.method == AbstractLoader.POST) { + headers["Content-Type"] = "application/x-www-form-urlencoded"; + } + + if (!crossdomain && !headers["X-Requested-With"]) { + headers["X-Requested-With"] = "XMLHttpRequest"; + } + + if (item.headers) { + for (var n in item.headers) { + headers[n] = item.headers[n]; } + } - this._request = req; - - return true; - }; + for (n in headers) { + req.setRequestHeader(n, headers[n]) + } - /** - * A request has completed (or failed or canceled), and needs to be disposed. - * @method _clean - * @private - */ - p._clean = function () { - clearTimeout(this._loadTimeout); - - if (this._request.removeEventListener != null) { - this._request.removeEventListener("loadstart", this._handleLoadStartProxy); - this._request.removeEventListener("progress", this._handleProgressProxy); - this._request.removeEventListener("abort", this._handleAbortProxy); - this._request.removeEventListener("error", this._handleErrorProxy); - this._request.removeEventListener("timeout", this._handleTimeoutProxy); - this._request.removeEventListener("load", this._handleLoadProxy); - this._request.removeEventListener("readystatechange", this._handleReadyStateChangeProxy); - } else { - this._request.onloadstart = null; - this._request.onprogress = null; - this._request.onabort = null; - this._request.onerror = null; - this._request.ontimeout = null; - this._request.onload = null; - this._request.onreadystatechange = null; - } - }; + if (req instanceof XMLHttpRequest && item.withCredentials !== undefined) { + req.withCredentials = item.withCredentials; + } - p.toString = function () { - return "[PreloadJS XHRRequest]"; - }; + this._request = req; - createjs.XHRRequest = createjs.promote(XHRRequest, "AbstractRequest"); + return true; +}; -}()); +/** + * A request has completed (or failed or canceled), and needs to be disposed. + * @method _clean + * @private + */ +p._clean = function () { + clearTimeout(this._loadTimeout); + + if (this._request.removeEventListener != null) { + this._request.removeEventListener("loadstart", this._handleLoadStartProxy); + this._request.removeEventListener("progress", this._handleProgressProxy); + this._request.removeEventListener("abort", this._handleAbortProxy); + this._request.removeEventListener("error", this._handleErrorProxy); + this._request.removeEventListener("timeout", this._handleTimeoutProxy); + this._request.removeEventListener("load", this._handleLoadProxy); + this._request.removeEventListener("readystatechange", this._handleReadyStateChangeProxy); + } else { + this._request.onloadstart = null; + this._request.onprogress = null; + this._request.onabort = null; + this._request.onerror = null; + this._request.ontimeout = null; + this._request.onload = null; + this._request.onreadystatechange = null; + } +}; + +p.toString = function () { + return "[PreloadJS XHRRequest]"; +}; + +module.exports = XHRRequest = promote(XHRRequest, "AbstractRequest"); diff --git a/src/preloadjs/utils/DataUtils.js b/src/preloadjs/utils/DataUtils.js index b461098..9ff8dca 100644 --- a/src/preloadjs/utils/DataUtils.js +++ b/src/preloadjs/utils/DataUtils.js @@ -31,7 +31,11 @@ * @module PreloadJS */ -(function () { + +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { /** * A few data utilities for formatting different data types. @@ -97,4 +101,4 @@ createjs.DataUtils = s; -}()); +}(scope.createjs)); diff --git a/src/preloadjs/utils/DomUtils.js b/src/preloadjs/utils/DomUtils.js index 9480588..1915647 100644 --- a/src/preloadjs/utils/DomUtils.js +++ b/src/preloadjs/utils/DomUtils.js @@ -31,7 +31,10 @@ * @module PreloadJS */ -(function () { +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; + +(function (createjs) { /** * A few utilities for interacting with the dom. @@ -53,4 +56,4 @@ createjs.DomUtils = s; -}()); +}(scope.createjs)); diff --git a/src/preloadjs/utils/RequestUtils.js b/src/preloadjs/utils/RequestUtils.js index 072a26e..ca8f6bc 100644 --- a/src/preloadjs/utils/RequestUtils.js +++ b/src/preloadjs/utils/RequestUtils.js @@ -31,294 +31,296 @@ * @module PreloadJS */ -(function () { - /** - * Utilities that assist with parsing load items, and determining file types, etc. - * @class RequestUtils - */ - var s = {}; +var AbstractLoader = require('../loaders/AbstractLoader'); - /** - * The Regular Expression used to test file URLS for an absolute path. - * @property ABSOLUTE_PATH - * @type {RegExp} - * @static - */ - s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i; - - /** - * The Regular Expression used to test file URLS for a relative path. - * @property RELATIVE_PATH - * @type {RegExp} - * @static - */ - s.RELATIVE_PATT = (/^[./]*?\//i); +/** + * Utilities that assist with parsing load items, and determining file types, etc. + * @class RequestUtils + */ +var s = {}; - /** - * The Regular Expression used to test file URLS for an extension. Note that URIs must already have the query string - * removed. - * @property EXTENSION_PATT - * @type {RegExp} - * @static - */ - s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i; +/** + * The Regular Expression used to test file URLS for an absolute path. + * @property ABSOLUTE_PATH + * @type {RegExp} + * @static + */ +s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i; - /** - * Parse a file path to determine the information we need to work with it. Currently, PreloadJS needs to know: - *
    - *
  • If the path is absolute. Absolute paths start with a protocol (such as `http://`, `file://`, or - * `//networkPath`)
  • - *
  • If the path is relative. Relative paths start with `../` or `/path` (or similar)
  • - *
  • The file extension. This is determined by the filename with an extension. Query strings are dropped, and - * the file path is expected to follow the format `name.ext`.
  • - *
- * @method parseURI - * @param {String} path - * @returns {Object} An Object with an `absolute` and `relative` Boolean values, as well as an optional 'extension` - * property, which is the lowercase extension. - * @static - */ - s.parseURI = function (path) { - var info = {absolute: false, relative: false}; - if (path == null) { return info; } +/** + * The Regular Expression used to test file URLS for a relative path. + * @property RELATIVE_PATH + * @type {RegExp} + * @static + */ +s.RELATIVE_PATT = (/^[./]*?\//i); - // Drop the query string - var queryIndex = path.indexOf("?"); - if (queryIndex > -1) { - path = path.substr(0, queryIndex); - } +/** + * The Regular Expression used to test file URLS for an extension. Note that URIs must already have the query string + * removed. + * @property EXTENSION_PATT + * @type {RegExp} + * @static + */ +s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i; - // Absolute - var match; - if (s.ABSOLUTE_PATT.test(path)) { - info.absolute = true; +/** + * Parse a file path to determine the information we need to work with it. Currently, PreloadJS needs to know: + *
    + *
  • If the path is absolute. Absolute paths start with a protocol (such as `http://`, `file://`, or + * `//networkPath`)
  • + *
  • If the path is relative. Relative paths start with `../` or `/path` (or similar)
  • + *
  • The file extension. This is determined by the filename with an extension. Query strings are dropped, and + * the file path is expected to follow the format `name.ext`.
  • + *
+ * @method parseURI + * @param {String} path + * @returns {Object} An Object with an `absolute` and `relative` Boolean values, as well as an optional 'extension` + * property, which is the lowercase extension. + * @static + */ +s.parseURI = function (path) { + var info = {absolute: false, relative: false}; + if (path == null) { + return info; + } - // Relative - } else if (s.RELATIVE_PATT.test(path)) { - info.relative = true; - } + // Drop the query string + var queryIndex = path.indexOf("?"); + if (queryIndex > -1) { + path = path.substr(0, queryIndex); + } - // Extension - if (match = path.match(s.EXTENSION_PATT)) { - info.extension = match[1].toLowerCase(); - } - return info; - }; + // Absolute + var match; + if (s.ABSOLUTE_PATT.test(path)) { + info.absolute = true; - /** - * Formats an object into a query string for either a POST or GET request. - * @method formatQueryString - * @param {Object} data The data to convert to a query string. - * @param {Array} [query] Existing name/value pairs to append on to this query. - * @static - */ - s.formatQueryString = function (data, query) { - if (data == null) { - throw new Error('You must specify data.'); - } - var params = []; - for (var n in data) { - params.push(n + '=' + escape(data[n])); - } - if (query) { - params = params.concat(query); - } - return params.join('&'); - }; + // Relative + } else if (s.RELATIVE_PATT.test(path)) { + info.relative = true; + } - /** - * A utility method that builds a file path using a source and a data object, and formats it into a new path. - * @method buildPath - * @param {String} src The source path to add values to. - * @param {Object} [data] Object used to append values to this request as a query string. Existing parameters on the - * path will be preserved. - * @returns {string} A formatted string that contains the path and the supplied parameters. - * @static - */ - s.buildPath = function (src, data) { - if (data == null) { - return src; - } + // Extension + if (match = path.match(s.EXTENSION_PATT)) { + info.extension = match[1].toLowerCase(); + } + return info; +}; - var query = []; - var idx = src.indexOf('?'); +/** + * Formats an object into a query string for either a POST or GET request. + * @method formatQueryString + * @param {Object} data The data to convert to a query string. + * @param {Array} [query] Existing name/value pairs to append on to this query. + * @static + */ +s.formatQueryString = function (data, query) { + if (data == null) { + throw new Error('You must specify data.'); + } + var params = []; + for (var n in data) { + params.push(n + '=' + escape(data[n])); + } + if (query) { + params = params.concat(query); + } + return params.join('&'); +}; - if (idx != -1) { - var q = src.slice(idx + 1); - query = query.concat(q.split('&')); - } +/** + * A utility method that builds a file path using a source and a data object, and formats it into a new path. + * @method buildPath + * @param {String} src The source path to add values to. + * @param {Object} [data] Object used to append values to this request as a query string. Existing parameters on the + * path will be preserved. + * @returns {string} A formatted string that contains the path and the supplied parameters. + * @static + */ +s.buildPath = function (src, data) { + if (data == null) { + return src; + } - if (idx != -1) { - return src.slice(0, idx) + '?' + this._formatQueryString(data, query); - } else { - return src + '?' + this._formatQueryString(data, query); - } - }; + var query = []; + var idx = src.indexOf('?'); - /** - * @method isCrossDomain - * @param {LoadItem|Object} item A load item with a `src` property. - * @return {Boolean} If the load item is loading from a different domain than the current location. - * @static - */ - s.isCrossDomain = function (item) { - var target = document.createElement("a"); - target.href = item.src; + if (idx != -1) { + var q = src.slice(idx + 1); + query = query.concat(q.split('&')); + } - var host = document.createElement("a"); - host.href = location.href; + if (idx != -1) { + return src.slice(0, idx) + '?' + this._formatQueryString(data, query); + } else { + return src + '?' + this._formatQueryString(data, query); + } +}; - var crossdomain = (target.hostname != "") && - (target.port != host.port || - target.protocol != host.protocol || - target.hostname != host.hostname); - return crossdomain; - }; +/** + * @method isCrossDomain + * @param {LoadItem|Object} item A load item with a `src` property. + * @return {Boolean} If the load item is loading from a different domain than the current location. + * @static + */ +s.isCrossDomain = function (item) { + var target = document.createElement("a"); + target.href = item.src; - /** - * @method isLocal - * @param {LoadItem|Object} item A load item with a `src` property - * @return {Boolean} If the load item is loading from the "file:" protocol. Assume that the host must be local as - * well. - * @static - */ - s.isLocal = function (item) { - var target = document.createElement("a"); - target.href = item.src; - return target.hostname == "" && target.protocol == "file:"; - }; + var host = document.createElement("a"); + host.href = location.href; - /** - * Determine if a specific type should be loaded as a binary file. Currently, only images and items marked - * specifically as "binary" are loaded as binary. Note that audio is not a binary type, as we can not play - * back using an audio tag if it is loaded as binary. Plugins can change the item type to binary to ensure they get - * a binary result to work with. Binary files are loaded using XHR2. Types are defined as static constants on - * {{#crossLink "AbstractLoader"}}{{/crossLink}}. - * @method isBinary - * @param {String} type The item type. - * @return {Boolean} If the specified type is binary. - * @static - */ - s.isBinary = function (type) { - switch (type) { - case createjs.AbstractLoader.IMAGE: - case createjs.AbstractLoader.BINARY: - return true; - default: - return false; - } - }; + var crossdomain = (target.hostname != "") && + (target.port != host.port || + target.protocol != host.protocol || + target.hostname != host.hostname); + return crossdomain; +}; - /** - * Check if item is a valid HTMLImageElement - * @method isImageTag - * @param {Object} item - * @returns {Boolean} - * @static - */ - s.isImageTag = function(item) { - return item instanceof HTMLImageElement; - }; +/** + * @method isLocal + * @param {LoadItem|Object} item A load item with a `src` property + * @return {Boolean} If the load item is loading from the "file:" protocol. Assume that the host must be local as + * well. + * @static + */ +s.isLocal = function (item) { + var target = document.createElement("a"); + target.href = item.src; + return target.hostname == "" && target.protocol == "file:"; +}; - /** - * Check if item is a valid HTMLAudioElement - * @method isAudioTag - * @param {Object} item - * @returns {Boolean} - * @static - */ - s.isAudioTag = function(item) { - if (window.HTMLAudioElement) { - return item instanceof HTMLAudioElement; - } else { +/** + * Determine if a specific type should be loaded as a binary file. Currently, only images and items marked + * specifically as "binary" are loaded as binary. Note that audio is not a binary type, as we can not play + * back using an audio tag if it is loaded as binary. Plugins can change the item type to binary to ensure they get + * a binary result to work with. Binary files are loaded using XHR2. Types are defined as static constants on + * {{#crossLink "AbstractLoader"}}{{/crossLink}}. + * @method isBinary + * @param {String} type The item type. + * @return {Boolean} If the specified type is binary. + * @static + */ +s.isBinary = function (type) { + switch (type) { + case AbstractLoader.IMAGE: + case AbstractLoader.BINARY: + return true; + default: return false; - } - }; + } +}; - /** - * Check if item is a valid HTMLVideoElement - * @method isVideoTag - * @param {Object} item - * @returns {Boolean} - * @static - */ - s.isVideoTag = function(item) { - if (window.HTMLVideoElement) { - return item instanceof HTMLVideoElement; - } else { - return false; - } - }; +/** + * Check if item is a valid HTMLImageElement + * @method isImageTag + * @param {Object} item + * @returns {Boolean} + * @static + */ +s.isImageTag = function (item) { + return item instanceof HTMLImageElement; +}; + +/** + * Check if item is a valid HTMLAudioElement + * @method isAudioTag + * @param {Object} item + * @returns {Boolean} + * @static + */ +s.isAudioTag = function (item) { + if (window.HTMLAudioElement) { + return item instanceof HTMLAudioElement; + } else { + return false; + } +}; - /** - * Determine if a specific type is a text-based asset, and should be loaded as UTF-8. - * @method isText - * @param {String} type The item type. - * @return {Boolean} If the specified type is text. - * @static - */ - s.isText = function (type) { - switch (type) { - case createjs.AbstractLoader.TEXT: - case createjs.AbstractLoader.JSON: - case createjs.AbstractLoader.MANIFEST: - case createjs.AbstractLoader.XML: - case createjs.AbstractLoader.CSS: - case createjs.AbstractLoader.SVG: - case createjs.AbstractLoader.JAVASCRIPT: - case createjs.AbstractLoader.SPRITESHEET: - return true; - default: - return false; - } - }; +/** + * Check if item is a valid HTMLVideoElement + * @method isVideoTag + * @param {Object} item + * @returns {Boolean} + * @static + */ +s.isVideoTag = function (item) { + if (window.HTMLVideoElement) { + return item instanceof HTMLVideoElement; + } else { + return false; + } +}; - /** - * Determine the type of the object using common extensions. Note that the type can be passed in with the load item - * if it is an unusual extension. - * @method getTypeByExtension - * @param {String} extension The file extension to use to determine the load type. - * @return {String} The determined load type (for example, AbstractLoader.IMAGE). Will return `null` if - * the type can not be determined by the extension. - * @static - */ - s.getTypeByExtension = function (extension) { - if (extension == null) { - return createjs.AbstractLoader.TEXT; - } +/** + * Determine if a specific type is a text-based asset, and should be loaded as UTF-8. + * @method isText + * @param {String} type The item type. + * @return {Boolean} If the specified type is text. + * @static + */ +s.isText = function (type) { + switch (type) { + case AbstractLoader.TEXT: + case AbstractLoader.JSON: + case AbstractLoader.MANIFEST: + case AbstractLoader.XML: + case AbstractLoader.CSS: + case AbstractLoader.SVG: + case AbstractLoader.JAVASCRIPT: + case AbstractLoader.SPRITESHEET: + return true; + default: + return false; + } +}; - switch (extension.toLowerCase()) { - case "jpeg": - case "jpg": - case "gif": - case "png": - case "webp": - case "bmp": - return createjs.AbstractLoader.IMAGE; - case "ogg": - case "mp3": - case "webm": - return createjs.AbstractLoader.SOUND; - case "mp4": - case "webm": - case "ts": - return createjs.AbstractLoader.VIDEO; - case "json": - return createjs.AbstractLoader.JSON; - case "xml": - return createjs.AbstractLoader.XML; - case "css": - return createjs.AbstractLoader.CSS; - case "js": - return createjs.AbstractLoader.JAVASCRIPT; - case 'svg': - return createjs.AbstractLoader.SVG; - default: - return createjs.AbstractLoader.TEXT; - } - }; +/** + * Determine the type of the object using common extensions. Note that the type can be passed in with the load item + * if it is an unusual extension. + * @method getTypeByExtension + * @param {String} extension The file extension to use to determine the load type. + * @return {String} The determined load type (for example, AbstractLoader.IMAGE). Will return `null` if + * the type can not be determined by the extension. + * @static + */ +s.getTypeByExtension = function (extension) { + if (extension == null) { + return AbstractLoader.TEXT; + } - createjs.RequestUtils = s; + switch (extension.toLowerCase()) { + case "jpeg": + case "jpg": + case "gif": + case "png": + case "webp": + case "bmp": + return AbstractLoader.IMAGE; + case "ogg": + case "mp3": + case "webm": + return AbstractLoader.SOUND; + case "mp4": + case "webm": + case "ts": + return AbstractLoader.VIDEO; + case "json": + return AbstractLoader.JSON; + case "xml": + return AbstractLoader.XML; + case "css": + return AbstractLoader.CSS; + case "js": + return AbstractLoader.JAVASCRIPT; + case 'svg': + return AbstractLoader.SVG; + default: + return AbstractLoader.TEXT; + } +}; -}()); +var RequestUtils = s; +module.exports = RequestUtils; diff --git a/src/preloadjs/version.js b/src/preloadjs/version.js index 93bc877..2141e2e 100644 --- a/src/preloadjs/version.js +++ b/src/preloadjs/version.js @@ -1,6 +1,7 @@ -this.createjs = this.createjs || {}; +var scope = (typeof window == 'undefined')?this:window; +scope.createjs = scope.createjs || {}; -(function () { +(function (createjs) { "use strict"; /** @@ -25,4 +26,4 @@ this.createjs = this.createjs || {}; **/ s.buildDate = /*=date*/""; // injected by build process -})(); +})(scope.createjs);