this.createjs = this.createjs||{};
(function() {
"use strict";
/**
* Static class holding library specific information such as the version and buildDate of
* the library.
*
* The old PreloadJS class has been renamed to LoadQueue. Please see the {{#crossLink "LoadQueue"}}{{/crossLink}}
* class for information on loading files.
* @class PreloadJS
**/
var s = createjs.PreloadJS = createjs.PreloadJS || {};
/**
* The version string for this release.
* @property version
* @type String
* @static
**/
s.version = /*version*/"NEXT"; // injected by build process
/**
* The build date for this release in UTC format.
* @property buildDate
* @type String
* @static
**/
s.buildDate = /*date*/"Wed, 22 Oct 2014 16:11:35 GMT"; // injected by build process
})();
/*
* 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
* files of each library and are available on the createsjs namespace directly.
*
*
Example
* myObject.addEventListener("change", createjs.proxy(myMethod, scope));
*
* @module CreateJS
* @main CreateJS
*/
// namespace:
this.createjs = this.createjs||{};
(function() {
"use strict";
/**
* 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
**/
var Event = function(type, bubbles, cancelable) {
this.initialize(type, bubbles, cancelable);
};
var p = Event.prototype;
Event.prototype.constructor = Event;
// events:
// public properties:
/**
* The type of event.
* @property type
* @type String
**/
p.type = null;
/**
* The object that generated an event.
* @property target
* @type Object
* @default null
* @readonly
*/
p.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
*/
p.currentTarget = null;
/**
* For bubbling events, this indicates the current event phase:
* - capture phase: starting from the top parent to the target
* - at target phase: currently being dispatched from the target
* - bubbling phase: from the target to the top parent
*
* @property eventPhase
* @type Number
* @default 0
* @readonly
*/
p.eventPhase = 0;
/**
* Indicates whether the event will bubble through the display list.
* @property bubbles
* @type Boolean
* @default false
* @readonly
*/
p.bubbles = false;
/**
* 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
*/
p.cancelable = false;
/**
* The epoch time at which this event was created.
* @property timeStamp
* @type Number
* @default 0
* @readonly
*/
p.timeStamp = 0;
/**
* Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called
* on this event.
* @property defaultPrevented
* @type Boolean
* @default false
* @readonly
*/
p.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
*/
p.propagationStopped = false;
/**
* Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called
* on this event.
* @property immediatePropagationStopped
* @type Boolean
* @default false
* @readonly
*/
p.immediatePropagationStopped = false;
/**
* Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event.
* @property removed
* @type Boolean
* @default false
* @readonly
*/
p.removed = false;
// constructor:
/**
* Initialization method.
* @method initialize
* @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.
* @protected
**/
p.initialize = function(type, bubbles, cancelable) {
this.type = type;
this.bubbles = bubbles;
this.cancelable = cancelable;
this.timeStamp = (new Date()).getTime();
};
// public methods:
/**
* Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true.
* Mirrors the DOM event standard.
* @method preventDefault
**/
p.preventDefault = function() {
this.defaultPrevented = 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);
};
/**
* 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;
}());
/*
* 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";
/**
* 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
**/
var EventDispatcher = function() {
/* this.initialize(); */ // not needed.
};
var p = EventDispatcher.prototype;
EventDispatcher.prototype.constructor = EventDispatcher;
/**
* 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;
};
// constructor:
// private properties:
/**
* @protected
* @property _listeners
* @type Object
**/
p._listeners = null;
/**
* @protected
* @property _captureListeners
* @type Object
**/
p._captureListeners = null;
// constructor:
/**
* Initialization method.
* @method initialize
* @protected
**/
p.initialize = function() {};
// 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; iExample
*
* // 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();
}
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; iExample
* myObject.addEventListener("change", createjs.proxy(myMethod, scope));
*
* @class Utility Methods
* @main Utility Methods
*/
(function() {
"use strict";
/**
* 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));
};
}
}());/*
* 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
*/
// namespace:
this.createjs = this.createjs||{};
(function() {
"use strict";
/**
* The base loader, which defines all the generic callbacks and events. All loaders extend this class, including the
* {{#crossLink "LoadQueue"}}{{/crossLink}}.
* @class AbstractLoader
* @extends EventDispatcher
*/
var AbstractLoader = function () {
this.init();
};
var p = AbstractLoader.prototype = new createjs.EventDispatcher();
AbstractLoader.prototype.constructor = AbstractLoader;
var s = AbstractLoader;
/**
* The Regular Expression used to test file URLS for an absolute path.
* @property ABSOLUTE_PATH
* @static
* @type {RegExp}
* @since 0.4.2
*/
s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i;
/**
* The Regular Expression used to test file URLS for an absolute path.
* @property RELATIVE_PATH
* @static
* @type {RegExp}
* @since 0.4.2
*/
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
* @static
* @type {RegExp}
* @since 0.4.2
*/
s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i;
/**
* 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
event.
* @property loaded
* @type {Boolean}
* @default false
*/
p.loaded = false;
/**
* Determine if the loader was canceled. Canceled loads will not fire complete events. Note that
* {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "AbstractLoader/close"}}{{/crossLink}}
* instead of setting this property.
* @property canceled
* @type {Boolean}
* @default false
*/
p.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
*/
p.progress = 0;
/**
* The item this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}}, but will
* be available on loaders such as {{#crossLink "XHRLoader"}}{{/crossLink}} and {{#crossLink "TagLoader"}}{{/crossLink}}.
* @property _item
* @type {Object}
* @private
*/
p._item = null;
// Events
/**
* The event that is fired when the overall progress changes.
* @event progress
* @param {Object} target The object that dispatched the event.
* @param {String} type The event type.
* @param {Number} loaded The amount that has been loaded so far. Note that this is may just be a percentage of 1,
* since file sizes can not be determined before a load is kicked off, if at all.
* @param {Number} total The total number of bytes. Note that this may just be 1.
* @param {Number} progress The ratio that has been loaded between 0 and 1.
* @since 0.3.0
*/
/**
* The event 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 event 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 event 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. There may be additional properties such as the error reason on event
* objects.
* @event error
* @param {Object} target The object that dispatched the event.
* @param {String} type The event type.
* @param {Object} [item] The item that was being loaded that caused the error. The item 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 {String} [error] The error object or text.
* @since 0.3.0
*/
//TODO: Deprecated
/**
* REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "AbstractLoader/progress:event"}}{{/crossLink}}
* event.
* @property onProgress
* @type {Function}
* @deprecated Use addEventListener and the "progress" event.
*/
/**
* REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}}
* event.
* @property onLoadStart
* @type {Function}
* @deprecated Use addEventListener and the "loadstart" event.
*/
/**
* REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}}
* event.
* @property onComplete
* @type {Function}
* @deprecated Use addEventListener and the "complete" event.
*/
/**
* REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}
* event.
* @property onError
* @type {Function}
* @deprecated Use addEventListener and the "error" event.
*/
/**
* Get a reference to the manifest item that is loaded by this loader. In most 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 an Object created by the LoadQueue.
* @return {Object} The manifest item that this loader is responsible for loading.
*/
p.getItem = function() {
return this._item;
};
/**
* Initialize the loader. This is called by the constructor.
* @method init
* @private
*/
p.init = function () {};
/**
* Begin loading the queued items. This method can be called when a {{#crossLink "LoadQueue"}}{{/crossLink}} is set
* up but not started immediately.
* @example
* var queue = new createjs.LoadQueue();
* queue.addEventListener("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() {};
/**
* 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() {};
//Callback proxies
/**
* Dispatch a loadstart event. 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 progress event. Please see the {{#crossLink "AbstractLoader/progress:event"}}{{/crossLink}} event for
* details on the event payload.
* @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.Event("progress");
event.loaded = this.progress;
event.total = 1;
} else {
event = value;
this.progress = value.loaded / value.total;
if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; }
}
event.progress = this.progress;
this.hasEventListener("progress") && this.dispatchEvent(event);
};
/**
* Dispatch a complete event. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event
* for details on the event payload.
* @method _sendComplete
* @protected
*/
p._sendComplete = function() {
if (this._isCanceled()) { return; }
this.dispatchEvent("complete");
};
/**
* Dispatch an error event. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} event for
* details on the event payload.
* @method _sendError
* @param {Object} 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.Event("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;
};
/**
* @method _parseURI
* 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`.
*
*
* Note: This has changed from earlier versions, which used a single, complicated Regular Expression, which
* was difficult to maintain, and over-aggressive in determining all file properties. It has been simplified to
* only pull out what it needs.
* @param path
* @returns {Object} An Object with an `absolute` and `relative` Boolean, as well as an optional 'extension` String
* property, which is the lowercase extension.
* @private
*/
p._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.
* @private
*/
p._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. All
* of the loaders in PreloadJS use this method to compile paths when loading.
* @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.
* @since 0.3.1
*/
p.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 {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.
* @private
*/
p._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 {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.
* @private
*/
p._isLocal = function(item) {
var target = document.createElement("a");
target.href = item.src;
return target.hostname == "" && target.protocol == "file:";
};
/**
* @method toString
* @return {String} a string representation of the instance.
*/
p.toString = function() {
return "[PreloadJS AbstractLoader]";
};
createjs.AbstractLoader = AbstractLoader;
}());
/*
* 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, SVG, and JSONP). 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:
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";
/**
* 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 useXHR
* 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"}]);
*
* 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.LoadQueue.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.LoadQueue.IMAGE});
*
* Supported types are defined on the LoadQueue class, and include:
*
* - {{#crossLink "LoadQueue/BINARY:property"}}{{/crossLink}}: Raw binary data via XHR
* - {{#crossLink "LoadQueue/CSS:property"}}{{/crossLink}}: CSS files
* - {{#crossLink "LoadQueue/IMAGE:property"}}{{/crossLink}}: Common image formats
* - {{#crossLink "LoadQueue/JAVASCRIPT:property"}}{{/crossLink}}: JavaScript files
* - {{#crossLink "LoadQueue/JSON:property"}}{{/crossLink}}: JSON data
* - {{#crossLink "LoadQueue/JSONP:property"}}{{/crossLink}}: JSON files cross-domain
* - {{#crossLink "LoadQueue/MANIFEST:property"}}{{/crossLink}}: A list of files to load in JSON format, see
* {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}
* - {{#crossLink "LoadQueue/SOUND:property"}}{{/crossLink}}: Audio file formats
* - {{#crossLink "LoadQueue/SVG:property"}}{{/crossLink}}: SVG files
* - {{#crossLink "LoadQueue/TEXT:property"}}{{/crossLink}}: Text files - XHR only
* - {{#crossLink "LoadQueue/XML:property"}}{{/crossLink}}: XML data
*
*
* 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
* resolved object that can be used immediately, including:
*
* - Image: An <img /> tag
* - Audio: An <audio /> tag
*
- JavaScript: A <script /> tag
* - CSS: A <link /> tag
* - XML: An XML DOM node
* - SVG: An <object /> tag
* - JSON: A formatted JavaScript Object
* - Text: Raw text
* - Binary: The binary loaded result
*
*
* 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.
*
* 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} [useXHR=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.
* @constructor
* @extends AbstractLoader
*/
var LoadQueue = function(useXHR, basePath, crossOrigin) {
this.init(useXHR, basePath, crossOrigin);
};
var p = LoadQueue.prototype = new createjs.AbstractLoader();
LoadQueue.prototype.constructor = LoadQueue;
var s = LoadQueue;
/**
* 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
*/
s.loadTimeout = 8000;
/**
* Time in milliseconds to assume a load has failed.
* @type {Number}
* @deprecated in favor of the {{#crossLink "LoadQueue/loadTimeout:property"}}{{/crossLink}} property.
*/
s.LOAD_TIMEOUT = 0;
// Preload Types
/**
* 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
*/
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
*/
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
*/
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
*/
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/useXHR:property"}}{{/crossLink}} property is set to, and the JSON
* must contain a matching wrapper function.
* @property JSON
* @type {String}
* @default json
* @static
*/
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/useXHR:property"}}{{/crossLink}}
* property is set to.
* @property JSONP
* @type {String}
* @default jsonp
* @static
*/
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/useXHR:property"}}{{/crossLink}} property is set to.
* @property MANIFEST
* @type {String}
* @default manifest
* @static
* @since 0.4.1
*/
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
*/
s.SOUND = "sound";
/**
* The preload type for SVG files.
* @property SVG
* @type {String}
* @default svg
* @static
*/
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
*/
s.TEXT = "text";
/**
* The preload type for xml files. XML is loaded into an XML document.
* @property XML
* @type {String}
* @default xml
* @static
*/
s.XML = "xml";
/**
* Defines a POST request, use for a method value when loading data.
*
* @type {string}
*/
s.POST = 'POST';
/**
* Defines a GET request, use for a method value when loading data.
*
* @type {string}
*/
s.GET = 'GET';
// Prototype
/**
* A path that will be prepended on to the item's `src`. 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
*/
p._basePath = null;
/**
* 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}
* @defaultValue ""
* @private
* @since 0.4.1
*/
p._crossOrigin = "";
/**
* 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 WebAudio can not be
* loaded with tags, so it will default the the correct type instead of using the user-defined type.
*
* Note: This property is read-only. To change it, please use the {{#crossLink "LoadQueue/setUseXHR"}}{{/crossLink}}
* method, or specify the `useXHR` argument in the LoadQueue constructor.
*
* @property useXHR
* @type {Boolean}
* @readOnly
* @default true
*/
p.useXHR = true;
/**
* Determines if the LoadQueue will stop processing the current queue when an error is encountered.
* @property stopOnError
* @type {Boolean}
* @default false
*/
p.stopOnError = false;
/**
* 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 `maintainOrder` 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
*/
p.maintainScriptOrder = true;
/**
* 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
*/
p.next = null;
// 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 event is fired when an an individual file progress changes.
* @event fileprogress
* @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 `src` property.
* @param {Number} loaded The number of bytes that have been loaded. Note that this may just be a percentage of 1.
* @param {Number} total The total number of bytes. If it is unknown, the value is 1.
* @param {Number} progress The amount that has been loaded between 0 and 1.
* @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.
*/
//TODO: Deprecated
/**
* REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}}
* event.
* @property onFileLoad
* @type {Function}
* @deprecated Use addEventListener and the "fileload" event.
*/
/**
* REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}}
* event.
* @property onFileProgress
* @type {Function}
* @deprecated Use addEventListener and the "fileprogress" event.
*/
// Protected
/**
* 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._typeCallbacks = null;
/**
* 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
*/
p._extensionCallbacks = null;
/**
* 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
*/
p._loadStartWasDispatched = 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
*/
p._maxConnections = 1;
/**
* 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
*/
p._currentlyLoadingScript = null;
/**
* An array containing the currently downloading files.
* @property _currentLoads
* @type {Array}
* @private
*/
p._currentLoads = null;
/**
* An array containing the queued items that have not yet started downloading.
* @property _loadQueue
* @type {Array}
* @private
*/
p._loadQueue = null;
/**
* An array containing downloads that have not completed, so that the LoadQueue can be properly reset.
* @property _loadQueueBackup
* @type {Array}
* @private
*/
p._loadQueueBackup = null;
/**
* An object hash of items that have finished downloading, indexed by item IDs.
* @property _loadItemsById
* @type {Object}
* @private
*/
p._loadItemsById = null;
/**
* An object hash of items that have finished downloading, indexed by item source.
* @property _loadItemsBySrc
* @type {Object}
* @private
*/
p._loadItemsBySrc = null;
/**
* An object hash of loaded items, indexed by the ID of the load item.
* @property _loadedResults
* @type {Object}
* @private
*/
p._loadedResults = null;
/**
* An object hash of un-parsed loaded items, indexed by the ID of the load item.
* @property _loadedRawResults
* @type {Object}
* @private
*/
p._loadedRawResults = null;
/**
* 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.
* @property _numItems
* @type {Number}
* @default 0
* @private
*/
p._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
*/
p._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
*/
p._scriptOrder = null;
/**
* 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._loadedScripts = null;
// Overrides abstract method in AbstractLoader
p.init = function(useXHR, basePath, crossOrigin) {
this._numItems = this._numItemsLoaded = 0;
this._paused = false;
this._loadStartWasDispatched = false;
this._currentLoads = [];
this._loadQueue = [];
this._loadQueueBackup = [];
this._scriptOrder = [];
this._loadedScripts = [];
this._loadItemsById = {};
this._loadItemsBySrc = {};
this._loadedResults = {};
this._loadedRawResults = {};
// Callbacks for plugins
this._typeCallbacks = {};
this._extensionCallbacks = {};
this._basePath = basePath;
this.setUseXHR(useXHR);
this._crossOrigin = (crossOrigin === true)
? "Anonymous" : (crossOrigin === false || crossOrigin == null)
? "" : crossOrigin;
};
/**
* Change the usXHR value. Note that if this is set to true, it may fail depending on the browser's capabilities.
* Additionally, some files require XHR in order to load, such as JSON (without JSONP), Text, and XML, so XHR will
* be used regardless of what is passed to this method.
* @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
*/
p.setUseXHR = 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.useXHR = (value != false && window.XMLHttpRequest != null);
return this.useXHR;
};
/**
* 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 && !(idsOrUrls instanceof Array)) {
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.useXHR, this._basePath, this._crossOrigin);
// 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) {
delete this._loadItemsById[r.id];
delete this._loadItemsBySrc[r.src];
this._disposeItem(r);
} 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; inot 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.
* @method isBinary
* @param {String} type The item type.
* @return {Boolean} If the specified type is binary.
* @private
*/
s.isBinary = function(type) {
switch (type) {
case createjs.LoadQueue.IMAGE:
case createjs.LoadQueue.BINARY:
return true;
default:
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.
* @private
*/
s.isText = function(type) {
switch (type) {
case createjs.LoadQueue.TEXT:
case createjs.LoadQueue.JSON:
case createjs.LoadQueue.MANIFEST:
case createjs.LoadQueue.XML:
case createjs.LoadQueue.HTML:
case createjs.LoadQueue.CSS:
case createjs.LoadQueue.SVG:
case createjs.LoadQueue.JAVASCRIPT:
return true;
default:
return 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 || plugin.getPreloadHandlers == null) { return; }
var map = plugin.getPreloadHandlers();
map.scope = plugin;
if (map.types != null) {
for (var i=0, l=map.types.length; iExample
*
* 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 {Object | String} file The file object or path to load. A file can be either
*
* - A string path to a resource. Note that this kind of load item will be converted to an object (see below)
* in the background.
* - OR an object that contains:
* - src: 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.
* - type: The type of file that will be loaded (image, sound, json, etc). PreloadJS does auto-detection
* of types using the extension. Supported types are defined on LoadQueue, such as
LoadQueue.IMAGE
.
* It is recommended that a type is specified when a non-standard file URI (such as a php script) us used.
* - id: A string identifier which can be used to reference the loaded object.
* - maintainOrder: Set to `true` to ensure this asset loads in the order defined in the manifest. This
* will happen when the max connections has been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}),
* and will only affect other assets also defined as `maintainOrder`. Everything else 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`.
* - callback: Optional, used for JSONP requests, to define what method to call when the JSONP is loaded.
* - data: An arbitrary data object, which is included with the loaded object
* - method: used to define if this request uses GET or POST when sending data to the server. The default
* value is "GET"
* - values: Optional object of name/value pairs to send to the server.
* - headers: Optional 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 if needed.
*
*
* @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 "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.loadFile = function(file, loadNow, basePath) {
if (file == null) {
var event = new createjs.Event("error");
event.text = "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:
*
* - 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.
* - 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.
* - 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.
* - An Array of files to load.
*
*
* Each "file" in a manifest can be either:
*
* - A string path to a resource (string). Note that this kind of load item will be converted to an object
* (see below) in the background.
* - OR an object that contains:
* - src: 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.
* - type: The type of file that will be loaded (image, sound, json, etc). PreloadJS does auto-detection
* of types using the extension. Supported types are defined on LoadQueue, such as {{#crossLink "LoadQueue/IMAGE:property"}}{{/crossLink}}.
* It is recommended that a type is specified when a non-standard file URI (such as a php script) us used.
* - id: A string identifier which can be used to reference the loaded object.
* - maintainOrder: Set to `true` to ensure this asset loads in the order defined in the manifest. This
* will happen when the max connections has been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}),
* and will only affect other assets also defined as `maintainOrder`. Everything else 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`.
* - callback: Optional, used for JSONP requests, to define what method to call when the JSONP is loaded.
* - data: An arbitrary data object, which is included with the loaded object
* - method: used to define if this request uses GET or POST when sending data to the server. The default
* value is "GET"
* - values: Optional object of name/value pairs to send to the server.
* - headers: Optional 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 if needed.
*
*
* @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 (manifest instanceof Array) {
if (manifest.length == 0) {
var event = new createjs.Event("error");
event.text = "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.Event("error");
event.text = "PRELOAD_MANIFEST_ERROR";
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.Event("error");
event.text = "PRELOAD_MANIFEST_NULL";
this._sendError(event);
return;
}
for (var i=0, l=fileList.length; iid
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];
};
/**
* 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();
}
};
// Overrides abstract method in AbstractLoader
p.close = function() {
while (this._currentLoads.length) {
this._currentLoads.pop().cancel();
}
this._scriptOrder.length = 0;
this._loadedScripts.length = 0;
this.loadStartWasDispatched = false;
};
//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) {
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 load item, which contains all the required properties (src, type, extension, tag). 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 = null;
// Create/modify a load item
switch(typeof(value)) {
case "string":
item = {
src: value
}; break;
case "object":
if (window.HTMLAudioElement && value instanceof window.HTMLAudioElement) {
item = {
tag: value,
src: item.tag.src,
type: createjs.LoadQueue.SOUND
};
} else {
item = value;
}
break;
default:
return null;
}
// Determine Extension, etc.
var match = this._parseURI(item.src);
if (match.extension) { item.ext = match.extension; }
if (item.type == null) {
item.type = this._getTypeByExtension(item.ext);
}
// Inject path & basePath
var bp = ""; // Store the generated basePath
var useBasePath = basePath || this._basePath;
var autoId = item.src;
if (!match.absolute && !match.relative) {
if (path) {
bp = path;
var pathMatch = this._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 (item.type == createjs.LoadQueue.JSON || item.type == createjs.LoadQueue.MANIFEST) {
item._loadAsJSONP = (item.callback != null);
}
if (item.type == createjs.LoadQueue.JSONP && item.callback == null) {
throw new Error('callback is required for loading JSONP requests.');
}
// Create a tag for the item. This ensures there is something to either load with or populate when finished.
if (item.tag === undefined || item.tag === null) {
item.tag = this._createTag(item);
}
// 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.src, item.type, item.id, item.data,
bp, this);
// NOTE: BasePath argument is deprecated. We pass it to plugins.allow SoundJS to modify the file. to sanymore. The full path is sent to the plugin
// 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.src != null) { item.src = result.src; }
if (result.id != null) { item.id = result.id; } // TODO: Evaluate this. An overridden ID could be problematic
if (result.tag != null) { // Assumes that the returned tag either has a load method or a src setter.
item.tag = result.tag;
}
if (result.completeHandler != null) { item.completeHandler = result.completeHandler; }
// Allow type overriding:
if (result.type) { item.type = result.type; }
// Update the extension in case the type changed:
match = this._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;
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) {
// Initially, try and use the provided/supported XHR mode:
var useXHR = this.useXHR;
// Determine the XHR usage overrides:
switch (item.type) {
case createjs.LoadQueue.JSON:
case createjs.LoadQueue.MANIFEST:
useXHR = !item._loadAsJSONP;
break;
case createjs.LoadQueue.XML:
case createjs.LoadQueue.TEXT:
useXHR = true; // Always use XHR2 with text/XML
break;
case createjs.LoadQueue.SOUND:
case createjs.LoadQueue.JSONP:
useXHR = false; // Never load audio using XHR. WebAudio will provide its own loader.
break;
case null:
return null;
// Note: IMAGE, CSS, SCRIPT, SVG can all use TAGS or XHR.
}
if (useXHR) {
return new createjs.XHRLoader(item, this._crossOrigin);
} else {
return new createjs.TagLoader(item);
}
};
/**
* 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._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. Events 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("progress", this._handleProgress, this);
loader.on("complete", this._handleFileComplete, this);
loader.on("error", this._handleFileError, this);
this._currentLoads.push(loader);
this._sendFileStart(loader.getItem());
loader.load();
};
/**
* 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 _handleFileError
* @param {Object} event The error event, containing relevant error information.
* @private
*/
p._handleFileError = function(event) {
var loader = event.target;
this._numItemsLoaded++;
this._finishOrderedItem(loader, true);
this._updateProgress();
var newEvent = new createjs.Event("error");
newEvent.text = "FILE_LOAD_ERROR";
newEvent.item = loader.getItem();
// TODO: Propagate actual error message.
this._sendError(newEvent);
if (!this.stopOnError) {
this._removeLoadItem(loader);
this._loadNext();
}
};
/**
* 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" event, and can also be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}.
* @method _handleFileComplete
* @param {Object} event The event object from the loader.
* @private
*/
p._handleFileComplete = function(event) {
var loader = event.target;
var item = loader.getItem();
this._loadedResults[item.id] = loader.getResult();
if (loader instanceof createjs.XHRLoader) {
this._loadedRawResults[item.id] = loader.getResult(true);
}
// Clean up the load item
this._removeLoadItem(loader);
if (!this._finishOrderedItem(loader)) {
// The item was NOT managed, so process it now
this._processFinishedLoad(item, loader);
}
};
/**
* Flag an item as finished. If the item's order is being managed, then set it up to finish
* @method _finishOrderedItem
* @param {AbstractLoader} loader
* @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.TagLoader && item.type == createjs.LoadQueue.JAVASCRIPT) {
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;ibefore
* the script can even be started, since it exist in the DOM while loading.
* @method _canStartLoad
* @param {XHRLoader|TagLoader} 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 instanceof createjs.XHRLoader) { 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 item = loader.getItem();
delete item._loader;
delete item._loadAsJSONP;
var l = this._currentLoads.length;
for (var i=0;i
* 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; iLoadQueue.IMAGE or null if it can not be
* determined by the extension.
* @private
*/
p._getTypeByExtension = function(extension) {
if (extension == null) {
return createjs.LoadQueue.TEXT;
}
switch (extension.toLowerCase()) {
case "jpeg":
case "jpg":
case "gif":
case "png":
case "webp":
case "bmp":
return createjs.LoadQueue.IMAGE;
case "ogg":
case "mp3":
case "wav":
return createjs.LoadQueue.SOUND;
case "json":
return createjs.LoadQueue.JSON;
case "xml":
return createjs.LoadQueue.XML;
case "css":
return createjs.LoadQueue.CSS;
case "js":
return createjs.LoadQueue.JAVASCRIPT;
case 'svg':
return createjs.LoadQueue.SVG;
default:
return createjs.LoadQueue.TEXT;
}
};
/**
* Dispatch a fileprogress event (and onFileProgress callback). Please see the LoadQueue.fileprogress
* event for details on the event payload.
* @method _sendFileProgress
* @param {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._cleanUp();
return;
}
if (!this.hasEventListener("fileprogress")) { return; }
var event = new createjs.Event("fileprogress");
event.progress = progress;
event.loaded = progress;
event.total = 1;
event.item = item;
this.dispatchEvent(event);
};
/**
* Dispatch a fileload event. Please see the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event for
* details on the event payload.
* @method _sendFileComplete
* @param {Object} item The item that is being loaded.
* @param {TagLoader | XHRLoader} loader
* @protected
*/
p._sendFileComplete = function(item, loader) {
if (this._isCanceled()) { 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 event 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 {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);
};
/**
* REMOVED. Use createjs.proxy instead
* @method proxy
* @param {Function} method The function to call
* @param {Object} scope The scope to call the method name on
* @static
* @private
* @deprecated In favour of the createjs.proxy method (see LoadQueue source).
*/
p.toString = function() {
return "[PreloadJS LoadQueue]";
};
createjs.LoadQueue = LoadQueue;
// Helper methods
// An additional module to determine the current browser, version, operating system, and other environmental variables.
var BrowserDetect = function() {}
BrowserDetect.init = function() {
var agent = navigator.userAgent;
BrowserDetect.isFirefox = (agent.indexOf("Firefox") > -1);
BrowserDetect.isOpera = (window.opera != null);
BrowserDetect.isChrome = (agent.indexOf("Chrome") > -1);
BrowserDetect.isIOS = agent.indexOf("iPod") > -1 || agent.indexOf("iPhone") > -1 || agent.indexOf("iPad") > -1;
};
BrowserDetect.init();
createjs.LoadQueue.BrowserDetect = BrowserDetect;
}());
/*
* TagLoader
* 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:
this.createjs = this.createjs||{};
(function() {
"use strict";
/**
* A preloader that loads items using a tag-based approach. HTML audio and images can use this loader to load
* content cross-domain without security errors, whereas anything loaded with XHR has potential issues with cross-
* domain requests.
*
* Note for audio tags, TagLoader relies on the canPlayThrough
event, which fires when the buffer
* is full enough to play the audio all the way through at the current download speed. This completely preloads most
* sound effects, however longer tracks like background audio will only load a portion before the event is fired.
* Most browsers (all excluding Chrome) will continue to preload once this is fired, so this is considered good
* enough for most cases.
* @class TagLoader
* @constructor
* @extends AbstractLoader
* @param {Object} item The item to load. Please see {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} for
* information on load items.
*/
var TagLoader = function (item) {
this.init(item);
};
var p = TagLoader.prototype = new createjs.AbstractLoader();
TagLoader.prototype.constructor = TagLoader;
// Protected
/**
* The timeout that is fired if nothing is loaded after a certain delay. See the LoadQueue.LOAD_TIMEOUT
* for the timeout duration.
* @property _loadTimeout
* @type {Number}
* @private
*/
p._loadTimeout = null;
/**
* A reference to a bound function, which we need in order to properly remove the event handler when the load
* completes.
* @property _tagCompleteProxy
* @type {Function}
* @private
*/
p._tagCompleteProxy = null;
/**
* Determines if the load item is an audio tag, since we take some specific approaches to properly load audio.
* @property _isAudio
* @type {Boolean}
* @default false
* @protected
*/
p._isAudio = false;
/**
* The HTML tag or JavaScript object this loader uses to preload content. Note that a tag may be a custom object
* that matches the API of an HTML tag (load method, onload callback). For example, flash audio from SoundJS passes
* in a custom object to handle preloading for Flash audio and WebAudio.
* @property _tag
* @type {HTMLAudioElement | Object}
* @private
*/
p._tag = null;
/**
* When loading a JSONP request this will be the parsed JSON result.
*
* @type {Object}
* @private
*/
p._jsonResult = null;
// Overrides abstract method in AbstractLoader
p.init = function (item) {
this._item = item;
this._tag = item.tag;
this._isAudio = (window.HTMLAudioElement && item.tag instanceof window.HTMLAudioElement);
this._tagCompleteProxy = createjs.proxy(this._handleLoad, this);
};
/**
* Get the loaded content. This is usually an HTML tag or other tag-style object that has been fully loaded. If the
* loader is not complete, this will be null.
* @method getResult
* @return {HTMLImageElement | HTMLAudioElement | Object} The loaded and parsed content.
*/
p.getResult = function() {
if (this._item.type == createjs.LoadQueue.JSONP || this._item.type == createjs.LoadQueue.MANIFEST) {
return this._jsonResult;
} else {
return this._tag;
}
};
// Overrides abstract method in AbstractLoader
p.cancel = function() {
this.canceled = true;
this._clean();
};
// Overrides abstract method in AbstractLoader
p.load = function() {
var item = this._item;
var tag = this._tag;
clearTimeout(this._loadTimeout); // Clear out any existing timeout
var duration = createjs.LoadQueue.LOAD_TIMEOUT;
if (duration == 0) { duration = createjs.LoadQueue.loadTimeout; }
this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), duration);
if (this._isAudio) {
tag.src = null; // Unset the source so we can set the preload type to "auto" without kicking off a load. This is only necessary for audio tags passed in by the developer.
tag.preload = "auto";
}
// Handlers for all tags
tag.onerror = createjs.proxy(this._handleError, this);
// Note: We only get progress events in Chrome, but do not fully load tags in Chrome due to its behaviour, so we ignore progress.
if (this._isAudio) {
tag.onstalled = createjs.proxy(this._handleStalled, this);
// 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.
tag.addEventListener("canplaythrough", this._tagCompleteProxy, false); // canplaythrough callback doesn't work in Chrome, so we use an event.
} else {
tag.onload = createjs.proxy(this._handleLoad, this);
tag.onreadystatechange = createjs.proxy(this._handleReadyStateChange, this);
}
var src = this.buildPath(item.src, item.values);
// Set the src after the events are all added.
switch(item.type) {
case createjs.LoadQueue.CSS:
tag.href = src;
break;
case createjs.LoadQueue.SVG:
tag.data = src;
break;
default:
tag.src = src;
}
// If we're loading JSONP, we need to add our callback now.
if (item.type == createjs.LoadQueue.JSONP
|| item.type == createjs.LoadQueue.JSON
|| item.type == createjs.LoadQueue.MANIFEST) {
if (item.callback == null) {
throw new Error('callback is required for loading JSONP requests.');
}
if (window[item.callback] != null) {
throw new Error('JSONP callback "' + item.callback + '" already exists on window. You need to specify a different callback. Or re-name the current one.');
}
window[item.callback] = createjs.proxy(this._handleJSONPLoad, this);
}
// If its SVG, it needs to be on the DOM to load (we remove it before sending complete).
// It is important that this happens AFTER setting the src/data.
if (item.type == createjs.LoadQueue.SVG ||
item.type == createjs.LoadQueue.JSONP ||
item.type == createjs.LoadQueue.JSON ||
item.type == createjs.LoadQueue.MANIFEST ||
item.type == createjs.LoadQueue.JAVASCRIPT ||
item.type == createjs.LoadQueue.CSS) {
this._startTagVisibility = tag.style.visibility;
tag.style.visibility = "hidden";
var node = document.body || document.getElementsByTagName("body")[0];
if (node == null) {
if (item.type == createjs.LoadQueue.SVG) {
this._handleSVGError();
return;
} else {
node = document.head || document.getElementsByTagName("head");
}
}
node.appendChild(tag);
}
// Note: Previous versions didn't seem to work when we called load() for OGG tags in Firefox. Seems fixed in 15.0.1
if (tag.load != null) {
tag.load();
}
};
p._handleSVGError = function() {
this._clean();
var event = new createjs.Event("error");
event.text = "SVG_NO_BODY";
this._sendError(event);
};
p._handleJSONPLoad = function(data) {
this._jsonResult = data;
};
/**
* Handle an audio timeout. Newer browsers get a callback from the tags, but older ones may require a setTimeout
* to handle it. The setTimeout is always running until a response is handled by the browser.
* @method _handleTimeout
* @private
*/
p._handleTimeout = function() {
this._clean();
var event = new createjs.Event("error");
event.text = "PRELOAD_TIMEOUT";
this._sendError(event);
};
/**
* Handle a stalled audio event. The main place we seem to get these is with HTMLAudio in Chrome when we try and
* playback 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.
};
/**
* Handle an error event generated by the tag.
* @method _handleError
* @private
*/
p._handleError = function(event) {
this._clean();
var newEvent = new createjs.Event("error");
//TODO: Propagate actual event error?
this._sendError(newEvent);
};
/**
* Handle the readyStateChange event from a tag. We sometimes need this in place of the onload event (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.getItem().tag;
// Complete is for old IE support.
if (tag.readyState == "loaded" || tag.readyState == "complete") {
this._handleLoad();
}
};
/**
* Handle a load (complete) event. This is called by tag callbacks, but also by readyStateChange and canPlayThrough
* events. Once loaded, the item is dispatched to the {{#crossLink "LoadQueue"}}{{/crossLink}}.
* @method _handleLoad
* @param {Object} [event] A load event from a tag. This is sometimes called from other handlers without an event.
* @private
*/
p._handleLoad = function(event) {
if (this._isCanceled()) { return; }
var item = this.getItem();
var tag = item.tag;
if (this.loaded || this._isAudio && tag.readyState !== 4) { return; } //LM: Not sure if we still need the audio check.
this.loaded = true;
// Remove from the DOM
switch (item.type) {
case createjs.LoadQueue.SVG:
case createjs.LoadQueue.JSON:
case createjs.LoadQueue.JSONP: // Note: Removing script tags is a fool's errand.
case createjs.LoadQueue.MANIFEST:
case createjs.LoadQueue.CSS:
// case createjs.LoadQueue.CSS:
//LM: We may need to remove CSS tags loaded using a LINK
tag.style.visibility = this._startTagVisibility;
tag.parentNode && tag.parentNode.contains(tag) && tag.parentNode.removeChild(tag);
break;
default:
}
this._clean();
this._sendComplete();
};
/**
* Clean up the loader.
* This stops any timers and removes references to prevent errant callbacks and clean up memory.
* @method _clean
* @private
*/
p._clean = function() {
clearTimeout(this._loadTimeout);
// Delete handlers.
var item = this.getItem();
var tag = item.tag;
if (tag != null) {
tag.onload = null;
tag.removeEventListener && tag.removeEventListener("canplaythrough", this._tagCompleteProxy, false);
tag.onstalled = null;
tag.onprogress = null;
tag.onerror = null;
//TODO: Test this
if (tag.parentNode != null
&& item.type == createjs.LoadQueue.SVG
&& item.type == createjs.LoadQueue.JSON
&& item.type == createjs.LoadQueue.MANIFEST
&& item.type == createjs.LoadQueue.CSS
&& item.type == createjs.LoadQueue.JSONP) {
// Note: Removing script tags is a fool's errand.
tag.parentNode.removeChild(tag);
}
}
var item = this.getItem();
if (item.type == createjs.LoadQueue.JSONP
|| item.type == createjs.LoadQueue.MANIFEST) {
window[item.callback] = null;
}
};
p.toString = function() {
return "[PreloadJS TagLoader]";
};
createjs.TagLoader = TagLoader;
}());
/*
* XHRLoader
* 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:
this.createjs = this.createjs || {};
(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 XHRLoader
* @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.
* @param {String} [crossOrigin] An optional flag to support images loaded from a CORS-enabled server. Please see
* {{#crossLink "LoadQueue/_crossOrigin:property"}}{{/crossLink}} for more info.
* @extends AbstractLoader
*/
var XHRLoader = function (item, crossOrigin) {
this.init(item, crossOrigin);
};
var s = XHRLoader;
/**
* 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.ACTIVEX_VERSIONS = [
"Msxml2.XMLHTTP.6.0",
"Msxml2.XMLHTTP.5.0",
"Msxml2.XMLHTTP.4.0",
"MSXML2.XMLHTTP.3.0",
"MSXML2.XMLHTTP",
"Microsoft.XMLHTTP"
];
var p = XHRLoader.prototype = new createjs.AbstractLoader();
XHRLoader.prototype.constructor = XHRLoader;
//Protected
/**
* A reference to the XHR request used to load the content.
* @property _request
* @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP}
* @private
*/
p._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
*/
p._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
*/
p._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
*/
p._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
*/
p._rawResponse = null;
/**
* See {{#crossLink "LoadQueue/_crossOrigin:property"}}{{/crossLink}}
* @property _crossOrigin
* @type {String}
* @defaultValue ""
* @private
*/
p._crossOrigin = "";
// Overrides abstract method in AbstractLoader
p.init = function (item, crossOrigin) {
this._item = item;
this._crossOrigin = crossOrigin;
if (!this._createXHR(item)) {
//TODO: Throw error?
}
};
/**
* Look up the loaded result.
* @method getResult
* @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 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 (rawResult) {
if (rawResult && this._rawResponse) {
return this._rawResponse;
}
return this._response;
};
// Overrides abstract method in AbstractLoader
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
this._request.onloadstart = createjs.proxy(this._handleLoadStart, this);
this._request.onprogress = createjs.proxy(this._handleProgress, this);
this._request.onabort = createjs.proxy(this._handleAbort, this);
this._request.onerror = createjs.proxy(this._handleError, this);
this._request.ontimeout = createjs.proxy(this._handleTimeout, this);
// Set up a timeout if we don't have XHR2
if (this._xhrLevel == 1) {
var duration = createjs.LoadQueue.LOAD_TIMEOUT;
if (duration == 0) {
duration = createjs.LoadQueue.loadTimeout;
} else {
try { console.warn("LoadQueue.LOAD_TIMEOUT has been deprecated in favor of LoadQueue.loadTimeout");} catch(e) {}
}
this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), duration);
}
// Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these.
this._request.onload = createjs.proxy(this._handleLoad, this);
this._request.onreadystatechange = createjs.proxy(this._handleReadyStateChange, this);
// 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.LoadQueue.GET) {
this._request.send();
} else if (this._item.method == createjs.LoadQueue.POST) {
this._request.send(this._formatQueryString(this._item.values));
}
} catch (error) {
var event = new createjs.Event("error");
event.error = error;
this._sendError(event);
}
};
/**
* 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;
}
};
/**
* 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.Event("progress");
newEvent.loaded = event.loaded;
newEvent.total = event.total;
this._sendProgress(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._sendLoadStart();
};
/**
* The XHR request has reported an abort event.
* @method handleAbort
* @param {Object} event The XHR abort event.
* @private
*/
p._handleAbort = function (event) {
this._clean();
var newEvent = new createjs.Event("error");
newEvent.text = "XHR_ABORTED";
this._sendError(newEvent);
};
/**
* The XHR request has reported an error event.
* @method _handleError
* @param {Object} event The XHR error event.
* @private
*/
p._handleError = function (event) {
this._clean();
var newEvent = new createjs.Event("error");
//TODO: Propagate event error
this._sendError(newEvent);
};
/**
* 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;
if (!this._checkError()) {
this._handleError();
return;
}
this._response = this._getResponse();
this._clean();
var isComplete = this._generateTag();
if (isComplete) {
this._sendComplete();
}
};
/**
* 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 createjs.Event("error");
newEvent.text = "PRELOAD_TIMEOUT";
//TODO: Propagate actual event error
this._sendError(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 {Boolean} 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 false;
}
return true;
};
/**
* 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
//TODO: TEST
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.
* - Some browsers get an
XDomainRequest
when loading cross-domain.
* - XMLHttpRequest are created when available.
* - ActiveX.XMLHTTP objects are used in older IE browsers.
* - Text requests override the mime type if possible
* - Origin headers are sent for crossdomain requests in some browsers.
* - 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 = this._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