2014-01-03 13:32:13 -05:00
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" } } { { / c r o s s L i n k } }
* 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
* * /
2014-02-02 19:31:06 -05:00
s . buildDate = /*date*/ "Wed, 18 Dec 2013 23:28:57 GMT" ; // injected by build process
2014-01-03 13:32:13 -05:00
} ) ( ) ;
/ *
* 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 .
*
* < h4 > Example < / h 4 >
* 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" } } { { / c r o s s L i n k } } .
*
* 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 ;
// 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 : < OL >
* < LI > capture phase : starting from the top parent to the target < / L I >
* < LI > at target phase : currently being dispatched from the target < / L I >
* < LI > bubbling phase : from the target to the top parent < / L I >
* < / O L >
* @ 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" } } { { / c r o s s L i n k } } . T h i s i s s e t v i a t h e E v e n t c o n s t r u c t o r .
* @ 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" } } { { / c r o s s L i n k } } h a s b e e n c a l l e d
* on this event .
* @ property defaultPrevented
* @ type Boolean
* @ default false
* @ readonly
* /
p . defaultPrevented = false ;
/ * *
* Indicates if { { # crossLink "Event/stopPropagation" } } { { / c r o s s L i n k } } o r
* { { # crossLink "Event/stopImmediatePropagation" } } { { / c r o s s L i n k } } h a s b e e n c a l l e d o n t h i s e v e n t .
* @ property propagationStopped
* @ type Boolean
* @ default false
* @ readonly
* /
p . propagationStopped = false ;
/ * *
* Indicates if { { # crossLink "Event/stopImmediatePropagation" } } { { / c r o s s L i n k } } h a s b e e n c a l l e d
* on this event .
* @ property immediatePropagationStopped
* @ type Boolean
* @ default false
* @ readonly
* /
p . immediatePropagationStopped = false ;
/ * *
* Indicates if { { # crossLink "Event/remove" } } { { / c r o s s L i n k } } h a s b e e n c a l l e d o n t h i s e v e n t .
* @ 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" } } { { / c r o s s L i n k } } t o t r u e .
* Mirrors the DOM event standard .
* @ method preventDefault
* * /
p . preventDefault = function ( ) {
this . defaultPrevented = true ;
} ;
/ * *
* Sets { { # crossLink "Event/propagationStopped" } } { { / c r o s s L i n k } } t o t r u e .
* Mirrors the DOM event standard .
* @ method stopPropagation
* * /
p . stopPropagation = function ( ) {
this . propagationStopped = true ;
} ;
/ * *
* Sets { { # crossLink "Event/propagationStopped" } } { { / c r o s s L i n k } } a n d
* { { # crossLink "Event/immediatePropagationStopped" } } { { / c r o s s L i n k } } t o t r u e .
* 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" } } { { / c r o s s L i n k } } m e t h o d .
*
* 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" } } { { / c r o s s L i n k } } m e t h o d , w h i c h m a k e s i t e a s i e r
* to create scoped listeners , listeners that only run once , and listeners with associated arbitrary data . The
* { { # crossLink "EventDispatcher/off" } } { { / c r o s s L i n k } } m e t h o d i s m e r e l y a n a l i a s t o
* { { # crossLink "EventDispatcher/removeEventListener" } } { { / c r o s s L i n k } } .
*
* Another addition to the DOM Level 2 model is the { { # crossLink "EventDispatcher/removeAllEventListeners" } } { { / c r o s s L i n k } }
* 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" } } { { / c r o s s L i n k } } m e t h o d w h i c h r e m o v e s t h e a c t i v e l i s t e n e r .
*
* < h4 > Example < / h 4 >
* Add EventDispatcher capabilities to the "MyClass" class .
*
* EventDispatcher . initialize ( MyClass . prototype ) ;
*
* Add an event ( see { { # crossLink "EventDispatcher/addEventListener" } } { { / c r o s s L i n k } } ) .
*
* instance . addEventListener ( "eventName" , handlerMethod ) ;
* function handlerMethod ( event ) {
* console . log ( event . target + " Was Clicked" ) ;
* }
*
* < b > Maintaining proper scope < /b><br / >
* Scope ( ie . "this" ) can be be a challenge with events . Using the { { # crossLink "EventDispatcher/on" } } { { / c r o s s L i n k } }
* 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 ;
/ * *
* 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 ;
2014-02-02 19:31:06 -05:00
target . willTrigger = p . willTrigger ;
2014-01-03 13:32:13 -05:00
} ;
// 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 .
*
* < h4 > Example < / h 4 >
*
* 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 ) .
*
* < h4 > Example < / h 4 >
*
* 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 .
*
* < b > Important Note : < / b > t h a t y o u m u s t p a s s t h e e x a c t f u n c t i o n r e f e r e n c e u s e d w h e n t h e e v e n t w a s a d d e d . I f a p r o x y
* function , or function closure is used as the callback , the proxy / closure reference must be used - a new proxy or
* closure will not work .
*
* < h4 > Example < / h 4 >
*
* displayObject . removeEventListener ( "click" , handleClick ) ;
*
* @ method removeEventListener
* @ param { String } type The string type of the event .
* @ param { Function | Object } listener The listener function or object .
* @ param { Boolean } [ useCapture ] For events that bubble , indicates whether to listen for the event in the capture or bubbling / target phase .
* * /
p . removeEventListener = function ( type , listener , useCapture ) {
var listeners = useCapture ? this . _captureListeners : this . _listeners ;
if ( ! listeners ) { return ; }
var arr = listeners [ type ] ;
if ( ! arr ) { return ; }
for ( var i = 0 , l = arr . length ; i < l ; i ++ ) {
if ( arr [ i ] == listener ) {
if ( l == 1 ) { delete ( listeners [ type ] ) ; } // allows for faster checks.
else { arr . splice ( i , 1 ) ; }
break ;
}
}
} ;
/ * *
* A shortcut to the removeEventListener method , with the same parameters and return value . This is a companion to the
* . on method .
*
* @ method off
* @ param { String } type The string type of the event .
* @ param { Function | Object } listener The listener function or object .
* @ param { Boolean } [ useCapture ] For events that bubble , indicates whether to listen for the event in the capture or bubbling / target phase .
* * /
p . off = p . removeEventListener ;
/ * *
* Removes all listeners for the specified type , or all listeners of all types .
*
* < h4 > Example < / h 4 >
*
* // 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 .
*
* < h4 > Example < / h 4 >
*
* // 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 .
* @ param { Object } [ target ] The object to use as the target property of the event object . This will default to the
* dispatching object . < b > This parameter is deprecated and will be removed . < / b >
* @ return { Boolean } Returns the value of eventObj . defaultPrevented .
* * /
p . dispatchEvent = function ( eventObj , target ) {
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 ) ;
}
// TODO: deprecated. Target param is deprecated, only use case is MouseEvent/mousemove, remove.
eventObj . target = target || this ;
if ( ! eventObj . bubbles || ! this . parent ) {
this . _dispatchEvent ( eventObj , 2 ) ;
} else {
var top = this , list = [ top ] ;
while ( top . parent ) { list . push ( top = top . parent ) ; }
var i , l = list . length ;
// capture & atTarget
for ( i = l - 1 ; i >= 0 && ! eventObj . propagationStopped ; i -- ) {
list [ i ] . _dispatchEvent ( eventObj , 1 + ( i == 0 ) ) ;
}
// bubbling
for ( i = 1 ; i < l && ! eventObj . propagationStopped ; i ++ ) {
list [ i ] . _dispatchEvent ( eventObj , 3 ) ;
}
}
return eventObj . defaultPrevented ;
} ;
/ * *
2014-02-02 19:31:06 -05:00
* Indicates whether there is at least one listener for the specified event type .
2014-01-03 13:32:13 -05:00
* @ method hasEventListener
* @ param { String } type The string type of the event .
* @ return { Boolean } Returns true if there is at least one listener for the specified event .
* * /
p . hasEventListener = function ( type ) {
var listeners = this . _listeners , captureListeners = this . _captureListeners ;
return ! ! ( ( listeners && listeners [ type ] ) || ( captureListeners && captureListeners [ type ] ) ) ;
} ;
2014-02-02 19:31:06 -05:00
/ * *
* Indicates whether there is at least one listener for the specified event type on this object or any of its
* ancestors ( parent , parent ' s parent , etc ) . A return value of true indicates that if a bubbling event of the
* specified type is dispatched from this object , it will trigger at least one listener .
*
* This is similar to { { # crossLink "EventDispatcher/hasEventListener" } } { { / c r o s s L i n k } } , b u t i t s e a r c h e s t h e e n t i r e
* event flow for a listener , not just this object .
* @ method willTrigger
* @ param { String } type The string type of the event .
* @ return { Boolean } Returns ` true ` if there is at least one listener for the specified event .
* * /
p . willTrigger = function ( type ) {
var o = this ;
while ( o ) {
if ( o . hasEventListener ( type ) ) { return true ; }
o = o . parent ;
}
return false ;
} ;
2014-01-03 13:32:13 -05:00
/ * *
* @ method toString
* @ return { String } a string representation of the instance .
* * /
p . toString = function ( ) {
return "[EventDispatcher]" ;
} ;
// private methods:
/ * *
* @ method _dispatchEvent
* @ param { Object | String | Event } eventObj
* @ param { Object } eventPhase
* @ protected
* * /
p . _dispatchEvent = function ( eventObj , eventPhase ) {
var l , listeners = ( eventPhase == 1 ) ? this . _captureListeners : this . _listeners ;
if ( eventObj && listeners ) {
var arr = listeners [ eventObj . type ] ;
if ( ! arr || ! ( l = arr . length ) ) { return ; }
eventObj . currentTarget = this ;
eventObj . eventPhase = eventPhase ;
eventObj . removed = false ;
arr = arr . slice ( ) ; // to avoid issues with items being removed or added during the dispatch
for ( var i = 0 ; i < l && ! eventObj . immediatePropagationStopped ; i ++ ) {
var o = arr [ i ] ;
if ( o . handleEvent ) { o . handleEvent ( eventObj ) ; }
else { o ( eventObj ) ; }
if ( eventObj . removed ) {
this . off ( eventObj . type , o , eventPhase == 1 ) ;
eventObj . removed = false ;
}
}
}
} ;
createjs . EventDispatcher = EventDispatcher ;
} ( ) ) ;
/ *
* IndexOf
* 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 || { } ;
/ * *
* @ class Utility Methods
* /
( function ( ) {
"use strict" ;
/ *
* Employs Duff ' s Device to make a more performant implementation of indexOf .
* see http : //jsperf.com/duffs-indexof/2
* # method indexOf
* @ param { Array } array Array to search for searchElement
* @ param searchElement Element to search array for .
* @ return { Number } The position of the first occurrence of a specified value searchElement in the passed in array ar .
* @ constructor
* /
/ * r e p l a c e d w i t h s i m p l e f o r l o o p f o r n o w , p e r h a p s w i l l b e r e s e a r c h e d f u r t h e r
createjs . indexOf = function ( ar , searchElement ) {
var l = ar . length ;
var n = ( l * 0.125 ) ^ 0 ; // 0.125 == 1/8, using multiplication because it's faster in some browsers // ^0 floors result
for ( var i = 0 ; i < n ; i ++ ) {
if ( searchElement === ar [ i * 8 ] ) { return ( i * 8 ) ; }
if ( searchElement === ar [ i * 8 + 1 ] ) { return ( i * 8 + 1 ) ; }
if ( searchElement === ar [ i * 8 + 2 ] ) { return ( i * 8 + 2 ) ; }
if ( searchElement === ar [ i * 8 + 3 ] ) { return ( i * 8 + 3 ) ; }
if ( searchElement === ar [ i * 8 + 4 ] ) { return ( i * 8 + 4 ) ; }
if ( searchElement === ar [ i * 8 + 5 ] ) { return ( i * 8 + 5 ) ; }
if ( searchElement === ar [ i * 8 + 6 ] ) { return ( i * 8 + 6 ) ; }
if ( searchElement === ar [ i * 8 + 7 ] ) { return ( i * 8 + 7 ) ; }
}
var n = l % 8 ;
for ( var i = 0 ; i < n ; i ++ ) {
if ( searchElement === ar [ l - n + i ] ) {
return l - n + i ;
}
}
return - 1 ;
}
* /
/ * *
* Finds the first occurrence of a specified value searchElement in the passed in array , and returns the index of
* that value . Returns - 1 if value is not found .
*
* var i = createjs . indexOf ( myArray , myElementToFind ) ;
*
* @ method indexOf
* @ param { Array } array Array to search for searchElement
* @ param searchElement Element to find in array .
* @ return { Number } The first index of searchElement in array .
* /
createjs . indexOf = function ( array , searchElement ) {
for ( var i = 0 , l = array . length ; i < l ; i ++ ) {
if ( searchElement === array [ i ] ) {
return i ;
}
}
return - 1 ;
}
} ( ) ) ; / *
* Proxy
* Visit http : //createjs.com/ for documentation, updates and examples.
*
* Copyright ( c ) 2010 gskinner . com , inc .
*
* Permission is hereby granted , free of charge , to any person
* obtaining a copy of this software and associated documentation
* files ( the "Software" ) , to deal in the Software without
* restriction , including without limitation the rights to use ,
* copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following
* conditions :
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY ,
* WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
* FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE .
* /
/ * *
* @ module CreateJS
* /
// namespace:
this . createjs = this . createjs || { } ;
/ * *
* Various utilities that the CreateJS Suite uses . Utilities are created as separate files , and will be available on the
* createjs namespace directly :
*
* < h4 > Example < / h 4 >
* 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 .
*
* < h4 > Example < / h 4 >
* 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" } } { { / c r o s s L i n k } } .
* @ class AbstractLoader
2014-02-02 19:31:06 -05:00
* @ extends EventDispatcher
2014-01-03 13:32:13 -05:00
* /
var AbstractLoader = function ( ) {
this . init ( ) ;
} ;
2014-02-02 19:31:06 -05:00
AbstractLoader . prototype = new createjs . EventDispatcher ( ) ; //TODO: TEST!
2014-01-03 13:32:13 -05:00
var p = AbstractLoader . prototype ;
var s = AbstractLoader ;
/ * *
* The RegExp pattern to use to parse file URIs . This supports simple file names , as well as full domain URIs with
2014-02-02 19:31:06 -05:00
* query strings . The resulting match is : protocol : $1 domain : $2 relativePath : $3 path : $4 file : $5 extension : $6 query : $7 .
2014-01-03 13:32:13 -05:00
* @ property FILE _PATTERN
* @ type { RegExp }
* @ static
* @ protected
* /
2014-02-02 19:31:06 -05:00
s . FILE _PATTERN = /^(?:(\w+:)\/{2}(\w+(?:\.\w+)*\/?)|(.{0,2}\/{1}))?([/.]*?(?:[^?]+)?\/)?((?:[^/?]+)\.(\w+))(?:\?(\S+)?)?$/ ;
/ * *
* The RegExp pattern to use to parse path URIs . This supports protocols , relative files , and paths . The resulting
* match is : protocol : $1 relativePath : $2 path$3 .
* @ property PATH _PATTERN
* @ type { RegExp }
* @ static
* @ protected
* /
s . PATH _PATTERN = /^(?:(\w+:)\/{2})|(.{0,2}\/{1})?([/.]*?(?:[^?]+)?\/?)?$/ ;
2014-01-03 13:32:13 -05:00
/ * *
* 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 < code > complete < / c o d e > e v e n t .
* @ 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" } } { { / c r o s s L i n k } } q u e u e s s h o u l d b e c l o s e d u s i n g { { # c r o s s L i n k " A b s t r a c t L o a d e r / c l o s e " } } { { / c r o s s L i n k } }
2014-02-02 19:31:06 -05:00
* instead of setting this property .
2014-01-03 13:32:13 -05:00
* @ 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.
2014-02-02 19:31:06 -05:00
*
* < h4 > Example < / h 4 >
*
* var queue = new createjs . LoadQueue ( ) ;
* queue . loadFile ( "largeImage.png" ) ;
* queue . on ( "progress" , function ( ) {
* console . log ( "Progress:" , queue . progress , event . progress ) ;
* } ) ;
*
2014-01-03 13:32:13 -05:00
* @ property progress
* @ type { Number }
* @ default 0
* /
p . progress = 0 ;
/ * *
* The item this loader represents . Note that this is null in a { { # crossLink "LoadQueue" } } { { / c r o s s L i n k } } , b u t w i l l
* be available on loaders such as { { # crossLink "XHRLoader" } } { { / c r o s s L i n k } } a n d { { # c r o s s L i n k " T a g L o a d e r " } } { { / c r o s s L i n k } } .
* @ 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" } } { { / c r o s s L i n k } } o r { { # c r o s s L i n k " L o a d Q u e u e / l o a d M a n i f e s t " } } { { / c r o s s L i n k } }
2014-02-02 19:31:06 -05:00
* call . If only a string path or tag was specified , the object will contain that value as a ` src ` property .
2014-01-03 13:32:13 -05:00
* @ param { String } [ error ] The error object or text .
* @ since 0.3 . 0
* /
//TODO: Deprecated
/ * *
* REMOVED . Use { { # crossLink "EventDispatcher/addEventListener" } } { { / c r o s s L i n k } } a n d t h e { { # c r o s s L i n k " A b s t r a c t L o a d e r / p r o g r e s s : e v e n t " } } { { / c r o s s L i n k } }
* event .
* @ property onProgress
* @ type { Function }
* @ deprecated Use addEventListener and the "progress" event .
* /
/ * *
* REMOVED . Use { { # crossLink "EventDispatcher/addEventListener" } } { { / c r o s s L i n k } } a n d t h e { { # c r o s s L i n k " A b s t r a c t L o a d e r / l o a d s t a r t : e v e n t " } } { { / c r o s s L i n k } }
* event .
* @ property onLoadStart
* @ type { Function }
* @ deprecated Use addEventListener and the "loadstart" event .
* /
/ * *
* REMOVED . Use { { # crossLink "EventDispatcher/addEventListener" } } { { / c r o s s L i n k } } a n d t h e { { # c r o s s L i n k " A b s t r a c t L o a d e r / c o m p l e t e : e v e n t " } } { { / c r o s s L i n k } }
* event .
* @ property onComplete
* @ type { Function }
* @ deprecated Use addEventListener and the "complete" event .
* /
/ * *
* REMOVED . Use { { # crossLink "EventDispatcher/addEventListener" } } { { / c r o s s L i n k } } a n d t h e { { # c r o s s L i n k " A b s t r a c t L o a d e r / e r r o r : e v e n t " } } { { / c r o s s L i n k } }
* 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" } } { { / c r o s s L i n k } } u s i n g { { # c r o s s L i n k " L o a d Q u e u e / l o a d F i l e " } } { { / c r o s s L i n k } } o r
* { { # crossLink "LoadQueue/loadManifest" } } { { / c r o s s L i n k } } . H o w e v e r i f o n l y a S t r i n g p a t h w a s p a s s e d i n , t h e n i t w i l l
* 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" } } { { / c r o s s L i n k } } i s s e t
* 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" } } { { / c r o s s L i n k } } m e t h o d i n s t e a d .
* @ method close
* /
p . close = function ( ) { } ;
//Callback proxies
/ * *
* Dispatch a loadstart event . Please see the { { # crossLink "AbstractLoader/loadstart:event" } } { { / c r o s s L i n k } } e v e n t
* 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" } } { { / c r o s s L i n k } } e v e n t f o r
* details on the event payload .
* @ method _sendProgress
* @ param { Number | Object } value The progress of the loaded item , or an object containing < code > loaded < / c o d e >
* and < code > total < / c o d e > p r o p e r t i e s .
* @ 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" } } { { / c r o s s L i n k } } e v e n t
* 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" } } { { / c r o s s L i n k } } e v e n t f o r
* 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 ;
} ;
/ * *
2014-02-02 19:31:06 -05:00
* Parse a file URI using the { { # crossLink "AbstractLoader/FILE_PATTERN:property" } } { { / c r o s s L i n k } } R e g E x p p a t t e r n .
2014-01-03 13:32:13 -05:00
* @ method _parseURI
* @ param { String } path The file path to parse .
2014-02-02 19:31:06 -05:00
* @ return { Array } The matched file contents . Please see the FILE _PATTERN property for details on the return value .
* This will return null if it does not match .
2014-01-03 13:32:13 -05:00
* @ protected
* /
p . _parseURI = function ( path ) {
if ( ! path ) { return null ; }
return path . match ( s . FILE _PATTERN ) ;
} ;
2014-02-02 19:31:06 -05:00
/ * *
* Parse a file URI using the { { # crossLink "AbstractLoader/PATH_PATTERN" } } { { / c r o s s L i n k } } R e g E x p p a t t e r n .
* @ method _parsePath
* @ param { String } path The file path to parse .
* @ return { Array } The matched path contents . Please see the PATH _PATTERN property for details on the return value .
* This will return null if it does not match .
* @ protected
* /
p . _parsePath = function ( path ) {
if ( ! path ) { return null ; }
return path . match ( s . PATH _PATTERN ) ;
} ;
2014-01-03 13:32:13 -05:00
/ * *
* 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 ( '&' ) ;
} ;
/ * *
2014-02-02 19:31:06 -05:00
* 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 .
2014-01-03 13:32:13 -05:00
* @ 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
* /
2014-02-02 19:31:06 -05:00
p . buildPath = function ( src , data ) {
2014-01-03 13:32:13 -05:00
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 ) ;
}
} ;
2014-02-02 19:31:06 -05:00
/ * *
* @ 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:" ;
} ;
2014-01-03 13:32:13 -05:00
/ * *
* @ 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 , < b > however due to cross - domain issues , it may still be preferable to use tag - based loading
* instead < / b > . N o t e t h a t s o m e c o n t e n t r e q u i r e s X H R t o w o r k ( p l a i n t e x t , w e b a u d i o ) , a n d s o m e r e q u i r e s t a g s ( H T M L a u d i o ) .
* 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 .
*
* < h4 > Getting Started < / h 4 >
* To get started , check out the { { # crossLink "LoadQueue" } } { { / c r o s s L i n k } } c l a s s , w h i c h i n c l u d e s a q u i c k o v e r v i e w o f h o w
* to load files and process results .
*
* < h4 > Example < / h 4 >
2014-02-02 19:31:06 -05:00
*
2014-01-03 13:32:13 -05:00
* 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 ) ;
* }
*
* < b > Important note on plugins : < /b> Plugins must be installed <i>before</i > 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 .
*
* < h4 > Browser Support < / h 4 >
* PreloadJS is partially supported in all browsers , and fully supported in all modern browsers . Known exceptions :
2014-02-02 19:31:06 -05:00
* < ul > < li > XHR loading of any content will not work in many older browsers ( See a matrix here : < a href = "http://caniuse.com/xhr2" target = "_blank" > http : //caniuse.com/xhr2</a>).
2014-01-03 13:32:13 -05:00
* 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 . < / l i >
* < li > Some formats have poor support for complete events in IE 6 , 7 , and 8 ( SVG , tag loading of scripts , XML / JSON ) < / l i >
* < li > Opera has poor support for SVG loading with XHR < / l i >
* < li > CSS loading in Android and Safari will not work with tags ( currently , a workaround is in progress ) < / l i >
2014-02-02 19:31:06 -05:00
* < li > 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" } } { { / c r o s s L i n k } }
* for more information . < / l i >
* < / u l >
*
* < h4 > Cross - domain Loading < / h 4 >
* 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" } } { { / c r o s s L i n k } }
* 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.
2014-01-03 13:32:13 -05:00
*
* @ 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" ;
/ * *
2014-02-02 19:31:06 -05:00
* 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 .
2014-01-03 13:32:13 -05:00
*
* < b > Creating a Queue < /b><br / >
* 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 ) ;
*
* < b > Listening for Events < /b><br / >
* Add any listeners you want to the queue . Since PreloadJS 0.3 . 0 , the { { # crossLink "EventDispatcher" } } { { / c r o s s L i n k } }
2014-02-02 19:31:06 -05:00
* lets you add as many listeners as you want for events . You can subscribe to the following events : < ul >
* < li > { { # crossLink "AbstractLoader/complete:event" } } { { / c r o s s L i n k } } : f i r e d w h e n a q u e u e c o m p l e t e s l o a d i n g a l l
* files < / l i >
* < li > { { # crossLink "AbstractLoader/error:event" } } { { / c r o s s L i n k } } : f i r e d w h e n t h e q u e u e e n c o u n t e r s a n e r r o r w i t h
* any file . < / l i >
* < li > { { # crossLink "AbstractLoader/progress:event" } } { { / c r o s s L i n k } } : P r o g r e s s f o r t h e e n t i r e q u e u e h a s
* changed . < / l i >
* < li > { { # crossLink "LoadQueue/fileload:event" } } { { / c r o s s L i n k } } : A s i n g l e f i l e h a s c o m p l e t e d l o a d i n g . < / l i >
* < li > { { # crossLink "LoadQueue/fileprogress:event" } } { { / c r o s s L i n k } } : P r o g r e s s f o r a s i n g l e f i l e h a s c h a n g e s . N o t e
* that only files loaded with XHR ( or possibly by plugins ) will fire progress events other than 0 or 100 % . < / l i >
* < / u l >
2014-01-03 13:32:13 -05:00
*
* queue . on ( "fileload" , handleFileLoad , this ) ;
* queue . on ( "complete" , handleComplete , this ) ;
*
* < b > Adding files and manifests < /b><br / >
* Add files you want to load using { { # crossLink "LoadQueue/loadFile" } } { { / c r o s s L i n k } } o r a d d m u l t i p l e f i l e s a t a
2014-02-02 19:31:06 -05:00
* time using a list or a manifest definition using { { # crossLink "LoadQueue/loadManifest" } } { { / c r o s s L i n k } } . F i l e s a r e
* appended to the end of the active queue , so you can use these methods as many times as you like , whenever you
* like .
2014-01-03 13:32:13 -05:00
*
* queue . loadFile ( "filePath/file.jpg" ) ;
* queue . loadFile ( { id : "image" , src : "filePath/file.jpg" } ) ;
2014-02-02 19:31:06 -05:00
* queue . loadManifest ( [ "filePath/file.jpg" , { id : "image" , src : "filePath/file.jpg" } ] ) ;
2014-01-03 13:32:13 -05:00
*
2014-02-02 19:31:06 -05:00
* 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" } } { { / c r o s s L i n k } } m e t h o d t o b e g i n
* a paused queue . Note that a paused queue will automatically resume when new files are added to it with a
* ` loadNow ` argument of ` true ` .
2014-01-03 13:32:13 -05:00
*
* queue . load ( ) ;
*
* < b > File Types < /b><br / >
* 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
* < code > type < / c o d e > p r o p e r t y w i t h a n y m a n i f e s t i t e m .
*
* queue . loadFile ( { src : "path/to/myFile.mp3x" , type : createjs . LoadQueue . SOUND } ) ;
*
* // Note that PreloadJS will not read a file extension from the query string
2014-02-02 19:31:06 -05:00
* queue . loadFile ( { src : "http://server.com/proxy?file=image.jpg" , type : createjs . LoadQueue . IMAGE } ) ;
2014-01-03 13:32:13 -05:00
*
2014-02-02 19:31:06 -05:00
* Supported types are defined on the LoadQueue class , and include :
2014-01-03 13:32:13 -05:00
* < ul >
2014-02-02 19:31:06 -05:00
* < li > { { # crossLink "LoadQueue/BINARY:property" } } { { / c r o s s L i n k } } : R a w b i n a r y d a t a v i a X H R < / l i >
* < li > { { # crossLink "LoadQueue/CSS:property" } } { { / c r o s s L i n k } } : C S S f i l e s < / l i >
* < li > { { # crossLink "LoadQueue/IMAGE:property" } } { { / c r o s s L i n k } } : C o m m o n i m a g e f o r m a t s < / l i >
* < li > { { # crossLink "LoadQueue/JAVASCRIPT:property" } } { { / c r o s s L i n k } } : J a v a S c r i p t f i l e s < / l i >
* < li > { { # crossLink "LoadQueue/JSON:property" } } { { / c r o s s L i n k } } : J S O N d a t a < / l i >
* < li > { { # crossLink "LoadQueue/JSONP:property" } } { { / c r o s s L i n k } } : J S O N f i l e s c r o s s - d o m a i n < / l i >
* < li > { { # crossLink "LoadQueue/MANIFEST:property" } } { { / c r o s s L i n k } } : A l i s t o f f i l e s t o l o a d i n J S O N f o r m a t , s e e
* { { # crossLink "LoadQueue/loadManifest" } } { { / c r o s s L i n k } } < / l i >
* < li > { { # crossLink "LoadQueue/SOUND:property" } } { { / c r o s s L i n k } } : A u d i o f i l e f o r m a t s < / l i >
* < li > { { # crossLink "LoadQueue/SVG:property" } } { { / c r o s s L i n k } } : S V G f i l e s < / l i >
* < li > { { # crossLink "LoadQueue/TEXT:property" } } { { / c r o s s L i n k } } : T e x t f i l e s - X H R o n l y < / l i >
* < li > { { # crossLink "LoadQueue/XML:property" } } { { / c r o s s L i n k } } : X M L d a t a < / l i >
2014-01-03 13:32:13 -05:00
* < / u l >
*
* < b > Handling Results < /b><br / >
2014-02-02 19:31:06 -05:00
* When a file is finished downloading , a { { # crossLink "LoadQueue/fileload:event" } } { { / c r o s s L i n k } } e v e n t i s
* 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 :
2014-01-03 13:32:13 -05:00
* < ul >
2014-02-02 19:31:06 -05:00
* < li > Image : An & lt ; img / & gt ; tag < / l i >
* < li > Audio : An & lt ; audio / & gt ; tag < / a >
* < li > JavaScript : A & lt ; script / & gt ; tag < / l i >
* < li > CSS : A & lt ; link / & gt ; tag < / l i >
* < li > XML : An XML DOM node < / l i >
* < li > SVG : An & lt ; object / & gt ; tag < / l i >
* < li > JSON : A formatted JavaScript Object < / l i >
* < li > Text : Raw text < / l i >
* < li > Binary : The binary loaded result < / l i >
* < / u l >
2014-01-03 13:32:13 -05:00
*
* function handleFileLoad ( event ) {
2014-02-02 19:31:06 -05:00
* var item = event . item ; // A reference to the item that was passed in to the LoadQueue
2014-01-03 13:32:13 -05:00
* 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" } } { { / c r o s s L i n k } } . I f n o i d w a s p r o v i d e d , t h e n t h e " s r c " o r
2014-02-02 19:31:06 -05:00
* file path can be used instead , including the ` path ` defined by a manifest , but < strong > not including < / s t r o n g > a
* base path defined on the LoadQueue . It is recommended to always pass an id .
2014-01-03 13:32:13 -05:00
*
* var image = queue . getResult ( "image" ) ;
* document . body . appendChild ( image ) ;
*
2014-02-02 19:31:06 -05:00
* Raw loaded content can be accessed using the < code > rawResult < / c o d e > p r o p e r t y o f t h e { { # c r o s s L i n k " L o a d Q u e u e / f i l e l o a d : e v e n t " } } { { / c r o s s L i n k } }
* event , or can be looked up using { { # crossLink "LoadQueue/getResult" } } { { / c r o s s L i n k } } , p a s s i n g ` t r u e ` a s t h e 2 n d
* 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 .
2014-01-03 13:32:13 -05:00
*
2014-02-02 19:31:06 -05:00
* var image = queue . getResult ( "image" , true ) ; // load the binary image data loaded with XHR.
2014-01-03 13:32:13 -05:00
*
* < b > Plugins < /b><br / >
* LoadQueue has a simple plugin architecture to help process and preload content . For example , to preload audio ,
2014-02-02 19:31:06 -05:00
* make sure to install the < a href = "http://soundjs.com" > SoundJS < / a > S o u n d c l a s s , w h i c h w i l l h e l p l o a d H T M L a u d i o ,
* Flash audio , and WebAudio files . This should be installed < strong > before < / s t r o n g > l o a d i n g a n y a u d i o f i l e s .
2014-01-03 13:32:13 -05:00
*
* queue . installPlugin ( createjs . Sound ) ;
*
* < h4 > Known Browser Issues < / h 4 >
* < ul >
* < li > Browsers without audio support can not load audio files . < / l i >
* < li > Safari on Mac OS X can only play HTML audio if QuickTime is installed < / l i >
* < li > HTML Audio tags will only download until their < code > canPlayThrough < / c o d e > e v e n t i s f i r e d . B r o w s e r s o t h e r
* than Chrome will continue to download in the background . < / l i >
* < li > When loading scripts using tags , they are automatically added to the document . < / l i >
* < li > Scripts loaded via XHR may not be properly inspectable with browser tools . < / l i >
* < li > IE6 and IE7 ( and some other browsers ) may not be able to load XML , Text , or JSON , since they require
* XHR to work . < / l i >
* < li > Content loaded via tags will not show progress , and will continue to download in the background when
* canceled , although no events will be dispatched . < / l i >
* < / u l >
*
* @ class LoadQueue
2014-02-02 19:31:06 -05:00
* @ 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
2014-01-03 13:32:13 -05:00
* when necessary .
2014-02-02 19:31:06 -05:00
* @ 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 .
2014-01-03 13:32:13 -05:00
* @ constructor
* @ extends AbstractLoader
* /
2014-02-02 19:31:06 -05:00
var LoadQueue = function ( useXHR , basePath , crossOrigin ) {
this . init ( useXHR , basePath , crossOrigin ) ;
2014-01-03 13:32:13 -05:00
} ;
var p = LoadQueue . prototype = new createjs . AbstractLoader ( ) ;
var s = LoadQueue ;
/ * *
2014-02-02 19:31:06 -05:00
* Time in milliseconds to assume a load has failed . An { { # crossLink "AbstractLoader/error:event" } } { { / c r o s s L i n k } }
* event is dispatched if the timeout is reached before any data is received .
* @ property loadTimeout
2014-01-03 13:32:13 -05:00
* @ type { Number }
* @ default 8000
* @ static
2014-02-02 19:31:06 -05:00
* @ since 0.4 . 1
2014-01-03 13:32:13 -05:00
* /
2014-02-02 19:31:06 -05:00
s . loadTimeout = 8000 ;
/ * *
* Time in milliseconds to assume a load has failed .
* @ type { Number }
* @ deprecated in favor of the { { # crossLink "LoadQueue/loadTimeout:property" } } { { / c r o s s L i n k } } p r o p e r t y .
* /
s . LOAD _TIMEOUT = 0 ;
2014-01-03 13:32:13 -05:00
// Preload Types
/ * *
2014-02-02 19:31:06 -05:00
* The preload type for generic binary types . Note that images are loaded as binary files when using XHR .
2014-01-03 13:32:13 -05:00
* @ property BINARY
* @ type { String }
* @ default binary
* @ static
* /
s . BINARY = "binary" ;
/ * *
2014-02-02 19:31:06 -05:00
* The preload type for css files . CSS files are loaded using a & lt ; link & gt ; when loaded with XHR , or a
* & lt ; style & gt ; tag when loaded with tags .
2014-01-03 13:32:13 -05:00
* @ property CSS
* @ type { String }
* @ default css
* @ static
* /
s . CSS = "css" ;
/ * *
2014-02-02 19:31:06 -05:00
* The preload type for image files , usually png , gif , or jpg / jpeg . Images are loaded into an & lt ; image & gt ; tag .
2014-01-03 13:32:13 -05:00
* @ 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
2014-02-02 19:31:06 -05:00
* & lt ; script & gt ; tag .
2014-01-03 13:32:13 -05:00
*
* Since version 0.4 . 1 + , due to how tag - loaded scripts work , all JavaScript files are automatically injected into
2014-02-02 19:31:06 -05:00
* 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 .
2014-01-03 13:32:13 -05:00
* @ 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 ,
2014-02-02 19:31:06 -05:00
* no matter what the { { # crossLink "LoadQueue/useXHR:property" } } { { / c r o s s L i n k } } p r o p e r t y i s s e t t o , a n d t h e J S O N
* must contain a matching wrapper function .
2014-01-03 13:32:13 -05:00
* @ 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" } } { { / c r o s s L i n k } }
* 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
2014-02-02 19:31:06 -05:00
* 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" } } { { / c r o s s L i n k } }
2014-01-03 13:32:13 -05:00
* 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" } } { { / c r o s s L i n k } } p r o p e r t y i s s e t t o .
* @ property MANIFEST
* @ type { String }
* @ default manifest
* @ static
* @ since 0.4 . 1
* /
s . MANIFEST = "manifest" ;
/ * *
2014-02-02 19:31:06 -05:00
* The preload type for sound files , usually mp3 , ogg , or wav . When loading via tags , audio is loaded into an
* & lt ; audio & gt ; tag .
2014-01-03 13:32:13 -05:00
* @ 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
2014-02-02 19:31:06 -05:00
/ * *
* 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 = "" ;
2014-01-03 13:32:13 -05:00
/ * *
* 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 .
*
* < b > Note : This property is read - only . < / b > T o c h a n g e i t , p l e a s e u s e t h e { { # c r o s s L i n k " L o a d Q u e u e / s e t U s e X H R " } } { { / c r o s s L i n k } }
* 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 ;
/ * *
2014-02-02 19:31:06 -05:00
* Ensure loaded scripts "complete" in the order they are specified . Loaded scripts are added to the document head
* once they are loaded . Note that scripts loaded via tags will load one - at - a - time when this property is ` true ` .
* load one at a time
2014-01-03 13:32:13 -05:00
* @ 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" } } { { / c r o s s L i n k } } i s ` t r u e ` , t h e n e x t q u e u e w i l l n o t b e p r o c e s s e d .
* @ 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" } } { { / c r o s s L i n k } }
* or { { # crossLink "LoadQueue/loadManifest" } } { { / c r o s s L i n k } } c a l l . I f o n l y a s t r i n g p a t h o r t a g w a s s p e c i f i e d , t h e
2014-02-02 19:31:06 -05:00
* object will contain that value as a ` src ` property .
2014-01-03 13:32:13 -05:00
* @ 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" } } { { / c r o s s L i n k } }
* or { { # crossLink "LoadQueue/loadManifest" } } { { / c r o s s L i n k } } c a l l . I f o n l y a s t r i n g p a t h o r t a g w a s s p e c i f i e d , t h e
2014-02-02 19:31:06 -05:00
* object will contain that value as a ` src ` property .
2014-01-03 13:32:13 -05:00
* @ 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" } } { { / c r o s s L i n k } }
* or { { # crossLink "LoadQueue/loadManifest" } } { { / c r o s s L i n k } } c a l l . I f o n l y a s t r i n g p a t h o r t a g w a s s p e c i f i e d , t h e
* object will contain that value as a property .
* /
//TODO: Deprecated
/ * *
* REMOVED . Use { { # crossLink "EventDispatcher/addEventListener" } } { { / c r o s s L i n k } } a n d t h e { { # c r o s s L i n k " L o a d Q u e u e / f i l e l o a d : e v e n t " } } { { / c r o s s L i n k } }
* event .
* @ property onFileLoad
* @ type { Function }
* @ deprecated Use addEventListener and the "fileload" event .
* /
/ * *
* REMOVED . Use { { # crossLink "EventDispatcher/addEventListener" } } { { / c r o s s L i n k } } a n d t h e { { # c r o s s L i n k " L o a d Q u e u e / f i l e p r o g r e s s : e v e n t " } } { { / c r o s s L i n k } }
* 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" } } { { / c r o s s L i n k } }
* 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" } } { { / c r o s s L i n k } }
* 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" } } { { / c r o s s L i n k } } f o r m o r e i n f o r m a t i o n .
* @ 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 < code > null < / c o d e > w h e n t h e y a r e
* requested , contain the loaded item if it has completed , but not been dispatched to the user , and < code > true < / t r u e >
* once they are complete and have been dispatched .
* @ property _loadedScripts
* @ type { Array }
* @ private
* /
p . _loadedScripts = null ;
// Overrides abstract method in AbstractLoader
2014-02-02 19:31:06 -05:00
p . init = function ( useXHR , basePath , crossOrigin ) {
2014-01-03 13:32:13 -05:00
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 ) ;
2014-02-02 19:31:06 -05:00
this . _crossOrigin = ( crossOrigin === true )
? "Anonymous" : ( crossOrigin === false || crossOrigin == null )
? "" : crossOrigin ;
2014-01-03 13:32:13 -05:00
} ;
/ * *
* Change the usXHR value . Note that if this is set to true , it may fail depending on the browser ' s capabilities .
2014-02-02 19:31:06 -05:00
* 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 .
2014-01-03 13:32:13 -05:00
* @ 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
2014-02-02 19:31:06 -05:00
* content , and allows the queue to be used again .
2014-01-03 13:32:13 -05:00
* @ 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 ) .
2014-02-02 19:31:06 -05:00
*
* < h4 > Example < / h 4 >
*
* 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.
*
2014-01-03 13:32:13 -05:00
* @ method remove
2014-02-02 19:31:06 -05:00
* @ param { String | Array } idsOrUrls * The id or ids to remove from this queue . You can pass an item , an array of
2014-01-03 13:32:13 -05:00
* 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 ) ;
// 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" } } { { / c r o s s L i n k } } . I t e m s a r e n o t r e m o v e d f r o m t h e
* queue . To remove items use the { { # crossLink "LoadQueue/remove" } } { { / c r o s s L i n k } } o r
* { { # crossLink "LoadQueue/removeAll" } } { { / c r o s s L i n k } } m e t h o d .
* @ method reset
* @ since 0.3 . 0
* /
p . reset = function ( ) {
this . close ( ) ;
for ( var n in this . _loadItemsById ) {
this . _disposeItem ( this . _loadItemsById [ n ] ) ;
}
//Reset the queue to its start state
var a = [ ] ;
for ( var i = 0 , l = this . _loadQueueBackup . length ; i < l ; i ++ ) {
a . push ( this . _loadQueueBackup [ i ] . getItem ( ) ) ;
}
this . loadManifest ( a , false ) ;
} ;
/ * *
* Determine if a specific type should be loaded as a binary file . Currently , only images and items marked
* specifically as "binary" are loaded as binary . Note that audio is < b > not < / b > a b i n a r y t y p e , a s w e c a n n o t p l a y
* 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 .
2014-02-02 19:31:06 -05:00
* @ return { Boolean } If the specified type is binary .
2014-01-03 13:32:13 -05:00
* @ private
* /
s . isBinary = function ( type ) {
switch ( type ) {
case createjs . LoadQueue . IMAGE :
case createjs . LoadQueue . BINARY :
return true ;
default :
return false ;
}
} ;
2014-02-02 19:31:06 -05:00
/ * *
* 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 ;
}
} ;
2014-01-03 13:32:13 -05:00
/ * *
* 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 < code > getPreloadHandlers ( ) < / c o d e > m e t h o d w i l l b e c a l l e d o n i t . F o r m o r e i n f o r m a t i o n
* on this method , check out the { { # crossLink "SamplePlugin/getPreloadHandlers" } } { { / c r o s s L i n k } } m e t h o d i n t h e
* { { # crossLink "SamplePlugin" } } { { / c r o s s L i n k } } c l a s s .
*
* 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" } } { { / c r o s s L i n k } } m e t h o d , i t w i l l b e i n v o k e d f i r s t , a n d i t s
* 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" } } { { / c r o s s L i n k } } a n d { { # c r o s s L i n k " S a m p l e P l u g i n / f i l e L o a d H a n d l e r " } } { { / c r o s s L i n k } }
* methods on the { { # crossLink "SamplePlugin" } } { { / c r o s s L i n k } } .
*
* @ 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 ; i < l ; i ++ ) {
this . _typeCallbacks [ map . types [ i ] ] = map ;
}
}
if ( map . extensions != null ) {
for ( i = 0 , l = map . extensions . length ; i < l ; i ++ ) {
this . _extensionCallbacks [ map . extensions [ i ] ] = map ;
}
}
} ;
/ * *
* Set the maximum number of concurrent connections . Note that browsers and servers may have a built - in maximum
* number of open connections , so any additional connections may remain in a pending state until the browser
2014-02-02 19:31:06 -05:00
* opens the connection . When loading scripts using tags , and when { { # crossLink "LoadQueue/maintainScriptOrder:property" } } { { / c r o s s L i n k } }
2014-01-03 13:32:13 -05:00
* is ` true ` , only one script is loaded at a time due to browser limitations .
2014-02-02 19:31:06 -05:00
*
* < h4 > Example < / h 4 >
*
* var queue = new createjs . LoadQueue ( ) ;
* queue . setMaxConnections ( 10 ) ; // Allow 10 concurrent loads
*
2014-01-03 13:32:13 -05:00
* @ 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 ( ) ;
}
2014-02-02 19:31:06 -05:00
} ;
2014-01-03 13:32:13 -05:00
/ * *
* Load a single file . To add multiple files at once , use the { { # crossLink "LoadQueue/loadManifest" } } { { / c r o s s L i n k } }
* method .
*
2014-02-02 19:31:06 -05:00
* Files are always appended to the current queue , so this method can be used multiple times to add files .
2014-01-03 13:32:13 -05:00
* To clear the queue first , use the { { # crossLink "AbstractLoader/close" } } { { / c r o s s L i n k } } m e t h o d .
* @ method loadFile
* @ param { Object | String } file The file object or path to load . A file can be either
2014-02-02 19:31:06 -05:00
* < ul >
* < li > A string path to a resource . Note that this kind of load item will be converted to an object ( see below )
* in the background . < / l i >
2014-01-03 13:32:13 -05:00
* < li > OR an object that contains : < ul >
* < li > src : The source of the file that is being loaded . This property is < b > required < / b > . T h e s o u r c e c a n
* either be a string ( recommended ) , or an HTML tag . < / l i >
* < li > 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 < code > LoadQueue . IMAGE < / c o d e > .
* It is recommended that a type is specified when a non - standard file URI ( such as a php script ) us used . < / l i >
* < li > id : A string identifier which can be used to reference the loaded object . < / l i >
* < li > callback : Optional , used for JSONP requests , to define what method to call when the JSONP is loaded . < / l i >
* < li > data : An arbitrary data object , which is included with the loaded object < / l i >
2014-02-02 19:31:06 -05:00
* < li > method : used to define if this request uses GET or POST when sending data to the server . The default
* value is "GET" < / l i >
2014-01-03 13:32:13 -05:00
* < li > values : Optional object of name / value pairs to send to the server . < / l i >
2014-02-02 19:31:06 -05:00
* < li > 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 . < / l i >
* < / u l >
* < / u l >
2014-01-03 13:32:13 -05:00
* @ 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" } } { { / c r o s s L i n k } } , a n d t h e v a l u e i s
2014-02-02 19:31:06 -05:00
* ` 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" } } { { / c r o s s L i n k } } ,
* its files will < strong > NOT < / s t r o n g > u s e t h e b a s e P a t h p a r a m e t e r . < s t r o n g > T h e b a s e P a t h p a r a m e t e r i s d e p r e c a t e d . < / s t r o n g >
* 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 .
2014-01-03 13:32:13 -05:00
* /
p . loadFile = function ( file , loadNow , basePath ) {
if ( file == null ) {
var event = new createjs . Event ( "error" ) ;
event . text = "PRELOAD_NO_FILE" ;
this . _sendError ( event ) ;
return ;
}
2014-02-02 19:31:06 -05:00
this . _addItem ( file , null , basePath ) ;
2014-01-03 13:32:13 -05:00
if ( loadNow !== false ) {
this . setPaused ( false ) ;
} else {
this . setPaused ( true ) ;
}
2014-02-02 19:31:06 -05:00
} ;
2014-01-03 13:32:13 -05:00
/ * *
2014-02-02 19:31:06 -05:00
* Load an array of files . To load a single file , use the { { # crossLink "LoadQueue/loadFile" } } { { / c r o s s L i n k } } m e t h o d .
2014-01-03 13:32:13 -05:00
* 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" } } { { / c r o s s L i n k } } . S c r i p t s w i l l l o a d
* in the right order as long as { { # crossLink "LoadQueue/maintainScriptOrder" } } { { / c r o s s L i n k } } i s t r u e ( w h i c h i s
* default ) .
*
2014-02-02 19:31:06 -05:00
* Files are always appended to the current queue , so this method can be used multiple times to add files .
2014-01-03 13:32:13 -05:00
* To clear the queue first , use the { { # crossLink "AbstractLoader/close" } } { { / c r o s s L i n k } } m e t h o d .
* @ method loadManifest
2014-02-02 19:31:06 -05:00
* @ param { Array | String | Object } manifest An list of files to load . The loadManifest call supports four types of
* manifests :
2014-01-03 13:32:13 -05:00
* < ol >
2014-02-02 19:31:06 -05:00
* < li > 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 . < / l i >
* < li > 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 . < / l i >
* < li > 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 . < / l i >
* < li > An Array of files to load . < / l i >
* < / o l >
*
* Each "file" in a manifest can be either :
* < ul >
* < li > 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 . < / l i >
* < li > OR an object that contains : < ul >
* < li > src : The source of the file that is being loaded . This property is < b > required < / b > . T h e s o u r c e c a n
* either be a string ( recommended ) , or an HTML tag . < / l i >
2014-01-03 13:32:13 -05:00
* < li > 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 < code > LoadQueue . IMAGE < / c o d e > .
* It is recommended that a type is specified when a non - standard file URI ( such as a php script ) us used . < / l i >
* < li > id : A string identifier which can be used to reference the loaded object . < / l i >
2014-02-02 19:31:06 -05:00
* < li > callback : Optional , used for JSONP requests , to define what method to call when the JSONP is loaded . < / l i >
* < li > data : An arbitrary data object , which is included with the loaded object < / l i >
* < li > method : used to define if this request uses GET or POST when sending data to the server . The default
* value is "GET" < / l i >
* < li > values : Optional object of name / value pairs to send to the server . < / l i >
* < li > 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 . < / l i >
2014-01-03 13:32:13 -05:00
* < / u l >
2014-02-02 19:31:06 -05:00
* < / u l >
2014-01-03 13:32:13 -05:00
* @ 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" } } { { / c r o s s L i n k } } a n d t h i s v a l u e i s
2014-02-02 19:31:06 -05:00
* ` 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" } } { { / c r o s s L i n k } } ,
* its files will < strong > NOT < / s t r o n g > u s e t h e b a s e P a t h p a r a m e t e r . < s t r o n g > T h e b a s e P a t h p a r a m e t e r i s d e p r e c a t e d . < / s t r o n g >
* 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 .
2014-01-03 13:32:13 -05:00
* /
p . loadManifest = function ( manifest , loadNow , basePath ) {
2014-02-02 19:31:06 -05:00
var fileList = null ;
var path = null ;
2014-01-03 13:32:13 -05:00
2014-02-02 19:31:06 -05:00
// Array-based list of items
2014-01-03 13:32:13 -05:00
if ( manifest instanceof Array ) {
if ( manifest . length == 0 ) {
var event = new createjs . Event ( "error" ) ;
event . text = "PRELOAD_MANIFEST_EMPTY" ;
this . _sendError ( event ) ;
return ;
}
2014-02-02 19:31:06 -05:00
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 ] ;
2014-01-03 13:32:13 -05:00
2014-02-02 19:31:06 -05:00
// An object that defines a manifest
} else if ( manifest . manifest !== undefined ) {
fileList = manifest . manifest ;
path = manifest . path ;
2014-01-03 13:32:13 -05:00
}
2014-02-02 19:31:06 -05:00
// Unsupported. This will throw an error.
} else {
var event = new createjs . Event ( "error" ) ;
event . text = "PRELOAD_MANIFEST_NULL" ;
this . _sendError ( event ) ;
return ;
2014-01-03 13:32:13 -05:00
}
2014-02-02 19:31:06 -05:00
for ( var i = 0 , l = fileList . length ; i < l ; i ++ ) {
this . _addItem ( fileList [ i ] , path , basePath ) ;
2014-01-03 13:32:13 -05:00
}
if ( loadNow !== false ) {
this . setPaused ( false ) ;
} else {
this . setPaused ( true ) ;
}
} ;
// Overrides abstract method in AbstractLoader
p . load = function ( ) {
this . setPaused ( false ) ;
} ;
/ * *
2014-02-02 19:31:06 -05:00
* Look up a load item 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 .
2014-01-03 13:32:13 -05:00
* @ method getItem
* @ param { String } value The < code > id < / c o d e > o r < c o d e > s r c < / c o d e > o f t h e l o a d i t e m .
* @ return { Object } The load item that was initially requested using { { # crossLink "LoadQueue/loadFile" } } { { / c r o s s L i n k } }
2014-02-02 19:31:06 -05:00
* or { { # crossLink "LoadQueue/loadManifest" } } { { / c r o s s L i n k } } . T h i s o b j e c t i s a l s o r e t u r n e d v i a t h e { { # c r o s s L i n k " L o a d Q u e u e / f i l e l o a d : e v e n t " } } { { / c r o s s L i n k } }
* event as the ` item ` parameter .
2014-01-03 13:32:13 -05:00
* /
p . getItem = function ( value ) {
return this . _loadItemsById [ value ] || this . _loadItemsBySrc [ value ] ;
} ;
/ * *
2014-02-02 19:31:06 -05:00
* 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 .
2014-01-03 13:32:13 -05:00
* @ method getResult
* @ param { String } value The < code > id < / c o d e > o r < c o d e > s r c < / c o d e > o f t h e l o a d i t e m .
* @ 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 :
* < ul >
* < li > An image tag ( & lt ; image / & gt ; ) for images < / l i >
2014-02-02 19:31:06 -05:00
* < li > A script tag for JavaScript ( & lt ; script / & gt ; ) . Note that scripts are automatically added to the HTML
* DOM . < / l i >
* < li > A style tag for CSS ( & lt ; style / & gt ; or & lt ; link & gt ; ) < / l i >
2014-01-03 13:32:13 -05:00
* < li > Raw text for TEXT < / l i >
* < li > A formatted JavaScript object defined by JSON < / l i >
* < li > An XML document < / l i >
2014-02-02 19:31:06 -05:00
* < li > A binary arraybuffer loaded by XHR < / l i >
2014-01-03 13:32:13 -05:00
* < li > An audio tag ( & lt ; audio & gt ; ) 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 . < / l i >
* < / u l >
2014-02-02 19:31:06 -05:00
* This object is also returned via the { { # crossLink "LoadQueue/fileload:event" } } { { / c r o s s L i n k } } e v e n t a s t h e ' i t e m `
* parameter . Note that if a raw result is requested , but not found , the result will be returned instead .
2014-01-03 13:32:13 -05:00
* /
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 .
2014-02-02 19:31:06 -05:00
*
* Note that if new items are added to the queue using { { # crossLink "LoadQueue/loadFile" } } { { / c r o s s L i n k } } o r { { # c r o s s L i n k " L o a d Q u e u e / l o a d M a n i f e s t " } } { { / c r o s s L i n k } } ,
* a paused queue will be resumed , unless the ` loadNow ` argument is ` false ` .
2014-01-03 13:32:13 -05:00
* @ 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" } } { { / c r o s s L i n k } }
* method .
* @ method _addItem
* @ param { String | Object } value The item to add to the queue .
2014-02-02 19:31:06 -05:00
* @ 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" } } { { / c r o s s L i n k } } , t h e n i t w i l l o p t i o n a l l y b e p r e p e n d e d a f t e r .
* @ param { String } [ basePath ] < strong > Deprecated < / s t r o n g > A n o p t i o n a l b a s e P a t h p a s s e d i n t o a { { # c r o s s L i n k " L o a d Q u e u e / l o a d M a n i f e s t " } } { { / c r o s s L i n k } }
* or { { # crossLink "LoadQueue/loadFile" } } { { / c r o s s L i n k } } c a l l . T h i s p a r a m e t e r w i l l b e r e m o v e d i n a f u t u r e t a g g e d
* version .
2014-01-03 13:32:13 -05:00
* @ private
* /
2014-02-02 19:31:06 -05:00
p . _addItem = function ( value , path , basePath ) {
var item = this . _createLoadItem ( value , path , basePath ) ; // basePath and manifest path are added to the src.
2014-01-03 13:32:13 -05:00
if ( item == null ) { return ; } // Sometimes plugins or types should be skipped.
2014-02-02 19:31:06 -05:00
var loader = this . _createLoader ( item ) ;
2014-01-03 13:32:13 -05:00
if ( loader != null ) {
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 ) {
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 .
2014-02-02 19:31:06 -05:00
* @ 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" } } { { / c r o s s L i n k } }
* when it is added .
* @ param { String } [ basePath ] < strong > Deprectated < / s t r o n g > A b a s e p a t h t o p r e p e n d t o t h e i t e m s s o u r c e i n a d d i t i o n t o
* the path argument .
2014-01-03 13:32:13 -05:00
* @ return { Object } The loader instance that will be used .
* @ private
* /
2014-02-02 19:31:06 -05:00
p . _createLoadItem = function ( value , path , basePath ) {
2014-01-03 13:32:13 -05:00
var item = null ;
// Create/modify a load item
switch ( typeof ( value ) ) {
case "string" :
item = {
src : value
} ; break ;
case "object" :
2014-02-02 19:31:06 -05:00
if ( window . HTMLAudioElement && value instanceof window . HTMLAudioElement ) {
2014-01-03 13:32:13 -05:00
item = {
tag : value ,
src : item . tag . src ,
type : createjs . LoadQueue . SOUND
} ;
} else {
item = value ;
}
break ;
default :
return null ;
}
2014-02-02 19:31:06 -05:00
// Determine Extension, etc.
2014-01-03 13:32:13 -05:00
var match = this . _parseURI ( item . src ) ;
2014-02-02 19:31:06 -05:00
if ( match != null ) { item . ext = match [ 6 ] ; }
2014-01-03 13:32:13 -05:00
if ( item . type == null ) {
item . type = this . _getTypeByExtension ( item . ext ) ;
}
2014-02-02 19:31:06 -05:00
// Inject path & basePath
var bp = "" ; // Store the generated basePath
var useBasePath = basePath || this . _basePath ;
var autoId = item . src ;
if ( match && match [ 1 ] == null && match [ 3 ] == null ) {
if ( path ) {
bp = path ;
var pathMatch = this . _parsePath ( path ) ;
autoId = path + autoId ;
// Also append basePath
if ( useBasePath != null && pathMatch && pathMatch [ 1 ] == null && pathMatch [ 2 ] == null ) {
bp = useBasePath + bp ;
}
} else if ( useBasePath != null ) {
bp = useBasePath ;
}
}
item . src = bp + item . src ;
item . path = bp ;
2014-01-03 13:32:13 -05:00
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.
2014-02-02 19:31:06 -05:00
if ( item . tag === undefined || item . tag === null ) {
item . tag = this . _createTag ( item ) ;
2014-01-03 13:32:13 -05:00
}
// If there's no id, set one now.
2014-02-02 19:31:06 -05:00
if ( item . id === undefined || item . id === null || item . id === "" ) {
item . id = autoId ;
2014-01-03 13:32:13 -05:00
}
// Give plugins a chance to modify the loadItem:
var customHandler = this . _typeCallbacks [ item . type ] || this . _extensionCallbacks [ item . ext ] ;
if ( customHandler ) {
2014-02-02 19:31:06 -05:00
// 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.
2014-01-03 13:32:13 -05:00
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 ; }
2014-02-02 19:31:06 -05:00
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.
2014-01-03 13:32:13 -05:00
item . tag = result . tag ;
}
2014-02-02 19:31:06 -05:00
if ( result . completeHandler != null ) { item . completeHandler = result . completeHandler ; }
2014-01-03 13:32:13 -05:00
2014-02-02 19:31:06 -05:00
// Allow type overriding:
if ( result . type ) { item . type = result . type ; }
2014-01-03 13:32:13 -05:00
2014-02-02 19:31:06 -05:00
// Update the extension in case the type changed:
match = this . _parseURI ( item . src ) ;
if ( match != null && match [ 6 ] != null ) {
item . ext = match [ 6 ] . toLowerCase ( ) ;
}
}
2014-01-03 13:32:13 -05:00
}
// 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
* /
2014-02-02 19:31:06 -05:00
p . _createLoader = function ( item ) {
2014-01-03 13:32:13 -05:00
// 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 ) {
2014-02-02 19:31:06 -05:00
return new createjs . XHRLoader ( item , this . _crossOrigin ) ;
2014-01-03 13:32:13 -05:00
} else {
2014-02-02 19:31:06 -05:00
return new createjs . TagLoader ( item ) ;
2014-01-03 13:32:13 -05:00
}
} ;
/ * *
* 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" } } { { / c r o s s L i n k } } m e t h o d . T h e o n l y e x c e p t i o n i s s c r i p t s t h a t a r e l o a d e d
* using tags , which have to be loaded one at a time to maintain load order .
* @ method _loadNext
* @ private
* /
p . _loadNext = function ( ) {
if ( this . _paused ) { return ; }
// Only dispatch loadstart event when the first file is loaded.
if ( ! this . _loadStartWasDispatched ) {
this . _sendLoadStart ( ) ;
this . _loadStartWasDispatched = true ;
}
// The queue has completed.
if ( this . _numItems == this . _numItemsLoaded ) {
this . loaded = true ;
this . _sendComplete ( ) ;
// Load the next queue, if it has been defined.
if ( this . next && this . next . load ) {
this . next . load ( ) ;
}
} else {
this . loaded = false ;
}
// Must iterate forwards to load in the right order.
for ( var i = 0 ; i < this . _loadQueue . length ; i ++ ) {
if ( this . _currentLoads . length >= this . _maxConnections ) { break ; }
var loader = this . _loadQueue [ i ] ;
// Determine if we should be only loading one at a time:
if ( this . maintainScriptOrder
&& loader instanceof createjs . TagLoader
&& loader . getItem ( ) . type == createjs . LoadQueue . JAVASCRIPT ) {
if ( this . _currentlyLoadingScript ) { continue ; } // Later items in the queue might not be scripts.
this . _currentlyLoadingScript = true ;
}
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" } } { { / c r o s s L i n k } }
* 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 . _updateProgress ( ) ;
2014-02-02 19:31:06 -05:00
var newEvent = new createjs . Event ( "error" ) ;
newEvent . text = "FILE_LOAD_ERROR" ;
newEvent . item = loader . getItem ( ) ;
2014-01-03 13:32:13 -05:00
// TODO: Propagate actual error message.
2014-02-02 19:31:06 -05:00
this . _sendError ( newEvent ) ;
2014-01-03 13:32:13 -05:00
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" } } { { / c r o s s L i n k } } .
* @ 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 ) ;
}
this . _removeLoadItem ( loader ) ;
// Ensure that script loading happens in the right order.
if ( this . maintainScriptOrder && item . type == createjs . LoadQueue . JAVASCRIPT ) {
if ( loader instanceof createjs . TagLoader ) {
this . _currentlyLoadingScript = false ;
} else {
this . _loadedScripts [ createjs . indexOf ( this . _scriptOrder , item ) ] = item ;
this . _checkScriptLoadOrder ( loader ) ;
return ;
}
}
2014-02-02 19:31:06 -05:00
// Clean up the load item
2014-01-03 13:32:13 -05:00
delete item . _loadAsJSONP ;
2014-02-02 19:31:06 -05:00
// If the item was a manifest, then
2014-01-03 13:32:13 -05:00
if ( item . type == createjs . LoadQueue . MANIFEST ) {
2014-02-02 19:31:06 -05:00
var result = loader . getResult ( ) ;
if ( result != null && result . manifest !== undefined ) {
this . loadManifest ( result , true ) ;
2014-01-03 13:32:13 -05:00
}
}
this . _processFinishedLoad ( item , loader ) ;
2014-02-02 19:31:06 -05:00
} ;
2014-01-03 13:32:13 -05:00
2014-02-02 19:31:06 -05:00
/ * *
* @ method _processFinishedLoad
* @ param { Object } item
* @ param { AbstractLoader } loader
* @ protected
* /
2014-01-03 13:32:13 -05:00
p . _processFinishedLoad = function ( item , loader ) {
// Old handleFileTagComplete follows here.
this . _numItemsLoaded ++ ;
this . _updateProgress ( ) ;
this . _sendFileComplete ( item , loader ) ;
this . _loadNext ( ) ;
} ;
/ * *
* 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 < code > true < / c o d e > . T h i s m e t h o d s i m p l y
* iterates the array , and ensures that any loaded items that are not preceded by a < code > null < / c o d e > v a l u e a r e
* dispatched .
* @ method _checkScriptLoadOrder
* @ private
* /
p . _checkScriptLoadOrder = function ( ) {
var l = this . _loadedScripts . length ;
for ( var i = 0 ; i < l ; i ++ ) {
var item = this . _loadedScripts [ i ] ;
if ( item === null ) { break ; } // This is still loading. Do not process further.
if ( item === true ) { continue ; } // This has completed, and been processed. Move on.
2014-02-02 19:31:06 -05:00
// Append script tags to the head automatically. Tags do this in the loader, but XHR scripts have to maintain order.
var loadItem = this . _loadedResults [ item . id ] ;
( document . body || document . getElementsByTagName ( "body" ) [ 0 ] ) . appendChild ( loadItem ) ;
2014-01-03 13:32:13 -05:00
this . _processFinishedLoad ( item ) ;
this . _loadedScripts [ i ] = true ;
}
} ;
/ * *
* A load item is completed or was canceled , and needs to be removed from the LoadQueue .
* @ method _removeLoadItem
* @ param { AbstractLoader } loader A loader instance to remove .
* @ private
* /
p . _removeLoadItem = function ( loader ) {
var l = this . _currentLoads . length ;
for ( var i = 0 ; i < l ; i ++ ) {
if ( this . _currentLoads [ i ] == loader ) {
this . _currentLoads . splice ( i , 1 ) ; break ;
}
}
} ;
/ * *
* An item has dispatched progress . Propagate that progress , and update the LoadQueue overall progress .
* @ method _handleProgress
* @ param { Object } event The progress event from the item .
* @ private
* /
p . _handleProgress = function ( event ) {
var loader = event . target ;
this . _sendFileProgress ( loader . getItem ( ) , loader . progress ) ;
this . _updateProgress ( ) ;
} ;
/ * *
* Overall progress has changed , so determine the new progress amount and dispatch it . This changes any time an
* item dispatches progress or completes . Note that since we don ' t know the actual filesize of items before they are
* loaded , and even then we can only get the size of items loaded with XHR . In this case , we define a "slot" for
* each item ( 1 item in 10 would get 10 % ) , and then append loaded progress on top of the already - loaded items .
*
* For example , if 5 / 10 items have loaded , and item 6 is 20 % loaded , the total progress would be : < ul >
* < li > 5 / 10 of the items in the queue ( 50 % ) < / l i >
* < li > plus 20 % of item 6 ' s slot ( 2 % ) < / l i >
* < li > equals 52 % < / l i > < / u l >
* @ method _updateProgress
* @ private
* /
p . _updateProgress = function ( ) {
var loaded = this . _numItemsLoaded / this . _numItems ; // Fully Loaded Progress
var remaining = this . _numItems - this . _numItemsLoaded ;
if ( remaining > 0 ) {
var chunk = 0 ;
for ( var i = 0 , l = this . _currentLoads . length ; i < l ; i ++ ) {
chunk += this . _currentLoads [ i ] . progress ;
}
loaded += ( chunk / remaining ) * ( remaining / this . _numItems ) ;
}
this . _sendProgress ( loaded ) ;
2014-02-02 19:31:06 -05:00
} ;
2014-01-03 13:32:13 -05:00
/ * *
* Clean out item results , to free them from memory . Mainly , the loaded item and results are cleared from internal
* hashes .
* @ method _disposeItem
* @ param { Object } item The item that was passed in for preloading .
* @ private
* /
p . _disposeItem = function ( item ) {
delete this . _loadedResults [ item . id ] ;
delete this . _loadedRawResults [ item . id ] ;
delete this . _loadItemsById [ item . id ] ;
delete this . _loadItemsBySrc [ item . src ] ;
} ;
/ * *
* Create an HTML tag . This is in LoadQueue instead of { { # crossLink "TagLoader" } } { { / c r o s s L i n k } } b e c a u s e n o m a t t e r
* how we load the data , we may need to return it in a tag .
* @ method _createTag
* @ param { String } type The item type . Items are passed in by the developer , or deteremined by the extension .
* @ return { HTMLImageElement | HTMLAudioElement | HTMLScriptElement | HTMLLinkElement | Object } The tag that is created .
* Note that tags are not appended to the HTML body .
* @ private
* /
2014-02-02 19:31:06 -05:00
p . _createTag = function ( item ) {
2014-01-03 13:32:13 -05:00
var tag = null ;
2014-02-02 19:31:06 -05:00
switch ( item . type ) {
2014-01-03 13:32:13 -05:00
case createjs . LoadQueue . IMAGE :
2014-02-02 19:31:06 -05:00
tag = document . createElement ( "img" ) ;
if ( this . _crossOrigin != "" && ! this . _isLocal ( item ) ) { tag . crossOrigin = this . _crossOrigin ; }
return tag ;
2014-01-03 13:32:13 -05:00
case createjs . LoadQueue . SOUND :
tag = document . createElement ( "audio" ) ;
tag . autoplay = false ;
// Note: The type property doesn't seem necessary.
return tag ;
case createjs . LoadQueue . JSON :
case createjs . LoadQueue . JSONP :
case createjs . LoadQueue . JAVASCRIPT :
case createjs . LoadQueue . MANIFEST :
tag = document . createElement ( "script" ) ;
tag . type = "text/javascript" ;
return tag ;
case createjs . LoadQueue . CSS :
if ( this . useXHR ) {
tag = document . createElement ( "style" ) ;
} else {
tag = document . createElement ( "link" ) ;
}
tag . rel = "stylesheet" ;
tag . type = "text/css" ;
return tag ;
case createjs . LoadQueue . SVG :
if ( this . useXHR ) {
tag = document . createElement ( "svg" ) ;
} else {
tag = document . createElement ( "object" ) ;
tag . type = "image/svg+xml" ;
}
return tag ;
}
return null ;
} ;
/ * *
* Determine the type of the object using common extensions . Note that the type can be passed in with the load item
* if it is an unusual extension .
* @ param { String } extension The file extension to use to determine the load type .
* @ return { String } The determined load type ( for example , < code > LoadQueue . IMAGE < / c o d e > o r n u l l i f i t c a n n o t b e
* 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 < code > LoadQueue . fileprogress < / c o d e >
* 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" } } { { / c r o s s L i n k } } e v e n t f o r
* 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" } } { { / c r o s s L i n k } }
* event for details on the event payload .
* @ method _sendFileStart
2014-02-02 19:31:06 -05:00
* @ param { Object } item The item that is being loaded .
2014-01-03 13:32:13 -05:00
* @ 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 ;
2014-02-02 19:31:06 -05:00
} ;
2014-01-03 13:32:13 -05:00
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 < code > canPlayThrough < / c o d e > e v e n t , w h i c h f i r e s w h e n t h e b u f f e r
* 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" } } { { / c r o s s L i n k } } f o r
* information on load items .
* /
2014-02-02 19:31:06 -05:00
var TagLoader = function ( item ) {
this . init ( item ) ;
2014-01-03 13:32:13 -05:00
} ;
var p = TagLoader . prototype = new createjs . AbstractLoader ( ) ;
// Protected
/ * *
* The timeout that is fired if nothing is loaded after a certain delay . See the < code > LoadQueue . LOAD _TIMEOUT < / c o d e >
* 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
2014-02-02 19:31:06 -05:00
* @ protected
2014-01-03 13:32:13 -05:00
* /
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
2014-02-02 19:31:06 -05:00
p . init = function ( item ) {
2014-01-03 13:32:13 -05:00
this . _item = item ;
this . _tag = item . tag ;
2014-02-02 19:31:06 -05:00
this . _isAudio = ( window . HTMLAudioElement && item . tag instanceof window . HTMLAudioElement ) ;
2014-01-03 13:32:13 -05:00
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
2014-02-02 19:31:06 -05:00
var duration = createjs . LoadQueue . LOAD _TIMEOUT ;
if ( duration == 0 ) { duration = createjs . LoadQueue . loadTimeout ; }
this . _loadTimeout = setTimeout ( createjs . proxy ( this . _handleTimeout , this ) , duration ) ;
2014-01-03 13:32:13 -05:00
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 ) ;
}
2014-02-02 19:31:06 -05:00
var src = this . buildPath ( item . src , item . values ) ;
2014-01-03 13:32:13 -05:00
// 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" ;
( document . body || document . getElementsByTagName ( "body" ) [ 0 ] ) . 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 . _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" } } { { / c r o s s L i n k } } .
* @ 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 ;
2014-02-02 19:31:06 -05:00
if ( this . loaded || this . _isAudio && tag . readyState !== 4 ) { return ; } //LM: Not sure if we still need the audio check.
2014-01-03 13:32:13 -05:00
this . loaded = true ;
// Remove from the DOM
switch ( item . type ) {
case createjs . LoadQueue . SVG :
2014-02-02 19:31:06 -05:00
case createjs . LoadQueue . JSON :
2014-01-03 13:32:13 -05:00
case createjs . LoadQueue . JSONP : // Note: Removing script tags is a fool's errand.
case createjs . LoadQueue . MANIFEST :
2014-02-02 19:31:06 -05:00
case createjs . LoadQueue . CSS :
2014-01-03 13:32:13 -05:00
// case createjs.LoadQueue.CSS:
//LM: We may need to remove CSS tags loaded using a LINK
tag . style . visibility = this . _startTagVisibility ;
( document . body || document . getElementsByTagName ( "body" ) [ 0 ] ) . 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.
2014-02-02 19:31:06 -05:00
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 ) ;
}
2014-01-03 13:32:13 -05:00
}
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]" ;
2014-02-02 19:31:06 -05:00
} ;
2014-01-03 13:32:13 -05:00
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" } } { { / c r o s s L i n k } }
* for an overview of supported file properties .
2014-02-02 19:31:06 -05:00
* @ param { String } [ crossOrigin ] An optional flag to support images loaded from a CORS - enabled server . Please see
* { { # crossLink "LoadQueue/_crossOrigin:property" } } { { / c r o s s L i n k } } f o r m o r e i n f o .
2014-01-03 13:32:13 -05:00
* @ extends AbstractLoader
* /
2014-02-02 19:31:06 -05:00
var XHRLoader = function ( item , crossOrigin ) {
this . init ( item , crossOrigin ) ;
2014-01-03 13:32:13 -05:00
} ;
2014-02-02 19:31:06 -05:00
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"
] ;
2014-01-03 13:32:13 -05:00
var p = XHRLoader . prototype = new createjs . AbstractLoader ( ) ;
//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 < code > result < / c o d e > p r o p e r t y , b u t t h e d e v e l o p e r m a y s t i l l
* want to access the raw content as it was loaded .
* @ property _rawResponse
* @ type { String | Object }
* @ private
* /
p . _rawResponse = null ;
2014-02-02 19:31:06 -05:00
/ * *
* See { { # crossLink "LoadQueue/_crossOrigin:property" } } { { / c r o s s L i n k } }
* @ property _crossOrigin
* @ type { String }
* @ defaultValue ""
* @ private
* /
p . _crossOrigin = "" ;
2014-01-03 13:32:13 -05:00
// Overrides abstract method in AbstractLoader
2014-02-02 19:31:06 -05:00
p . init = function ( item , crossOrigin ) {
2014-01-03 13:32:13 -05:00
this . _item = item ;
2014-02-02 19:31:06 -05:00
this . _crossOrigin = crossOrigin ;
2014-01-03 13:32:13 -05:00
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 :
* < ul >
* < li > An image tag ( & lt ; image / & gt ; ) for images < / l i >
* < li > A script tag for JavaScript ( & lt ; script / & gt ; ) . Note that scripts loaded with tags may be added to the
* HTML head . < / l i >
* < li > A style tag for CSS ( & lt ; style / & gt ; ) < / l i >
* < li > Raw text for TEXT < / l i >
* < li > A formatted JavaScript object defined by JSON < / l i >
* < li > An XML document < / l i >
* < li > An binary arraybuffer loaded by XHR < / l i >
* < / u l >
* 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 ) {
2014-02-02 19:31:06 -05:00
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 ) ;
2014-01-03 13:32:13 -05:00
}
// 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 .
*
* < strong > From the docs : < / s t r o n g > R e t u r n a l l t h e H T T P h e a d e r s , e x c l u d i n g h e a d e r s t h a t a r e a c a s e - i n s e n s i t i v e m a t c h
* for Set - Cookie or Set - Cookie2 , as a single string , with each header line separated by a U + 000 D CR U + 000 A LF pair ,
* excluding the status line , and with each header name and header value separated by a U + 003 A 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 .
*
* < strong > From the docs : < / s t r o n g > R e t u r n s t h e h e a d e r f i e l d v a l u e f r o m t h e r e s p o n s e o f w h i c h t h e f i e l d n a m e m a t c h e s
* 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 ( ) ;
2014-02-02 19:31:06 -05:00
var newEvent = new createjs . Event ( "error" ) ;
newEvent . text = "XHR_ABORTED" ;
this . _sendError ( newEvent ) ;
2014-01-03 13:32:13 -05:00
} ;
/ * *
* 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
* < code > request . readyState == 4 < / c o d e > . O n l y t h e f i r s t c a l l t o t h i s m e t h o d w i l l b e p r o c e s s e d .
* @ 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 < code > setTimeout < / c o d e >
* 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 < code > _response < / c o d e > p r o p e r t y w i l l r e m a i n n u l l .
* @ 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 .
* < ol > < li > Some browsers get an < code > XDomainRequest < / c o d e > w h e n l o a d i n g c r o s s - d o m a i n . < / l i >
* < li > XMLHttpRequest are created when available . < / l i >
* < li > ActiveX . XMLHTTP objects are used in older IE browsers . < / l i >
* < li > Text requests override the mime type if possible < / l i >
* < li > Origin headers are sent for crossdomain requests in some browsers . < / l i >
* < li > Binary loads set the response type to "arraybuffer" < / l i > < / o l >
* @ 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.
2014-02-02 19:31:06 -05:00
var crossdomain = this . _isCrossDomain ( item ) ;
var headers = { } ;
2014-01-03 13:32:13 -05:00
2014-02-02 19:31:06 -05:00
// Create the request. Fallback to whatever support we have.
2014-01-03 13:32:13 -05:00
var req = null ;
2014-02-02 19:31:06 -05:00
if ( window . XMLHttpRequest ) {
2014-01-03 13:32:13 -05:00
req = new XMLHttpRequest ( ) ;
2014-02-02 19:31:06 -05:00
// This is 8 or 9, so use XDomainRequest instead.
if ( crossdomain && req . withCredentials === undefined && window . XDomainRequest ) {
req = new XDomainRequest ( ) ;
2014-01-03 13:32:13 -05:00
}
2014-02-02 19:31:06 -05:00
} else { // Old IE versions use a different approach
for ( var i = 0 , l = s . ACTIVEX _VERSIONS . length ; i < l ; i ++ ) {
var axVersion = s . ACTIVEX _VERSIONS [ i ] ;
try {
req = new ActiveXObject ( axVersions ) ;
break ;
} catch ( e ) { }
}
if ( req == null ) { return false ; }
2014-01-03 13:32:13 -05:00
}
// IE9 doesn't support overrideMimeType(), so we need to check for it.
2014-02-02 19:31:06 -05:00
if ( createjs . LoadQueue . isText ( item . type ) && req . overrideMimeType ) {
req . overrideMimeType ( "text/plain; charset=utf-8" ) ;
2014-01-03 13:32:13 -05:00
}
// Determine the XHR level
this . _xhrLevel = ( typeof req . responseType === "string" ) ? 2 : 1 ;
var src = null ;
if ( item . method == createjs . LoadQueue . GET ) {
2014-02-02 19:31:06 -05:00
src = this . buildPath ( item . src , item . values ) ;
2014-01-03 13:32:13 -05:00
} else {
2014-02-02 19:31:06 -05:00
src = item . src ;
2014-01-03 13:32:13 -05:00
}
// Open the request. Set cross-domain flags if it is supported (XHR level 1 only)
req . open ( item . method || createjs . LoadQueue . GET , src , true ) ;
if ( crossdomain && req instanceof XMLHttpRequest && this . _xhrLevel == 1 ) {
2014-02-02 19:31:06 -05:00
headers [ "Origin" ] = location . origin ;
2014-01-03 13:32:13 -05:00
}
// To send data we need to set the Content-type header)
2014-02-02 19:31:06 -05:00
if ( item . values && item . method == createjs . LoadQueue . POST ) {
headers [ "Content-Type" ] = "application/x-www-form-urlencoded" ;
}
if ( ! crossdomain && ! headers [ "X-Requested-With" ] ) {
headers [ "X-Requested-With" ] = "XMLHttpRequest" ;
}
if ( item . headers ) {
for ( var n in item . headers ) {
headers [ n ] = item . headers [ n ] ;
}
}
2014-01-03 13:32:13 -05:00
// Binary files are loaded differently.
if ( createjs . LoadQueue . isBinary ( item . type ) ) {
req . responseType = "arraybuffer" ;
}
2014-02-02 19:31:06 -05:00
for ( n in headers ) {
req . setRequestHeader ( n , headers [ n ] )
}
2014-01-03 13:32:13 -05:00
this . _request = req ;
2014-02-02 19:31:06 -05:00
2014-01-03 13:32:13 -05:00
return true ;
} ;
/ * *
* A request has completed ( or failed or canceled ) , and needs to be disposed .
* @ method _clean
* @ private
* /
p . _clean = function ( ) {
clearTimeout ( this . _loadTimeout ) ;
var req = this . _request ;
req . onloadstart = null ;
req . onprogress = null ;
req . onabort = null ;
req . onerror = null ;
req . onload = null ;
req . ontimeout = null ;
req . onloadend = null ;
req . onreadystatechange = null ;
} ;
/ * *
* Generate a tag for items that can be represented as tags . For example , IMAGE , SCRIPT , and LINK . This also handles
* XML and SVG objects .
* @ method _generateTag
* @ return { Boolean } If a tag was generated and is ready for instantiation . If it still needs processing , this
* method returns false .
* @ private
* /
p . _generateTag = function ( ) {
var type = this . _item . type ;
var tag = this . _item . tag ;
switch ( type ) {
// Note: Images need to wait for onload, but do use the cache.
case createjs . LoadQueue . IMAGE :
tag . onload = createjs . proxy ( this . _handleTagReady , this ) ;
2014-02-02 19:31:06 -05:00
if ( this . _crossOrigin != "" ) { tag . crossOrigin = "Anonymous" ; } // We can assume this, since XHR images are always loaded on a server.
tag . src = this . buildPath ( this . _item . src , this . _item . values ) ;
2014-01-03 13:32:13 -05:00
this . _rawResponse = this . _response ;
this . _response = tag ;
return false ; // Images need to get an onload event first
case createjs . LoadQueue . JAVASCRIPT :
tag = document . createElement ( "script" ) ;
tag . text = this . _response ;
this . _rawResponse = this . _response ;
this . _response = tag ;
return true ;
case createjs . LoadQueue . CSS :
// Maybe do this conditionally?
var head = document . getElementsByTagName ( "head" ) [ 0 ] ; //Note: This is unavoidable in IE678
head . appendChild ( tag ) ;
if ( tag . styleSheet ) { // IE
tag . styleSheet . cssText = this . _response ;
} else {
var textNode = document . createTextNode ( this . _response ) ;
tag . appendChild ( textNode ) ;
}
this . _rawResponse = this . _response ;
this . _response = tag ;
return true ;
case createjs . LoadQueue . XML :
var xml = this . _parseXML ( this . _response , "text/xml" ) ;
this . _rawResponse = this . _response ;
this . _response = xml ;
return true ;
case createjs . LoadQueue . SVG :
var xml = this . _parseXML ( this . _response , "image/svg+xml" ) ;
this . _rawResponse = this . _response ;
if ( xml . documentElement != null ) {
tag . appendChild ( xml . documentElement ) ;
this . _response = tag ;
} else { // For browsers that don't support SVG, just give them the XML. (IE 9-8)
this . _response = xml ;
}
return true ;
case createjs . LoadQueue . JSON :
case createjs . LoadQueue . MANIFEST :
var json = { } ;
try {
json = JSON . parse ( this . _response ) ;
} catch ( error ) {
json = error ;
}
this . _rawResponse = this . _response ;
this . _response = json ;
return true ;
}
return true ;
} ;
/ * *
* Parse XML using the DOM . This is required when preloading XML or SVG .
* @ method _parseXML
* @ param { String } text The raw text or XML that is loaded by XHR .
* @ param { String } type The mime type of the XML .
* @ return { XML } An XML document .
* @ private
* /
p . _parseXML = function ( text , type ) {
var xml = null ;
2014-02-02 19:31:06 -05:00
try {
// CocoonJS does not support XML parsing with either method.
// Windows (?) Opera DOMParser throws DOMException: NOT_SUPPORTED_ERR // potential solution https://gist.github.com/1129031
if ( window . DOMParser ) {
var parser = new DOMParser ( ) ;
xml = parser . parseFromString ( text , type ) ;
} else { // IE
xml = new ActiveXObject ( "Microsoft.XMLDOM" ) ;
xml . async = false ;
xml . loadXML ( text ) ;
}
} catch ( e ) { }
2014-01-03 13:32:13 -05:00
return xml ;
} ;
/ * *
* A generated tag is now ready for use .
* @ method _handleTagReady
* @ private
* /
p . _handleTagReady = function ( ) {
2014-02-02 19:31:06 -05:00
var tag = this . _item . tag ;
tag && ( tag . onload = null ) ;
2014-01-03 13:32:13 -05:00
this . _sendComplete ( ) ;
2014-02-02 19:31:06 -05:00
} ;
2014-01-03 13:32:13 -05:00
p . toString = function ( ) {
return "[PreloadJS XHRLoader]" ;
2014-02-02 19:31:06 -05:00
} ;
2014-01-03 13:32:13 -05:00
createjs . XHRLoader = XHRLoader ;
} ( ) ) ;
/ * *
* Include json2 here , to correctly parse json .
* Used on browsers that don ' t have a native JSON object .
*
* /
/ *
json2 . js
2012 - 10 - 08
Public Domain .
NO WARRANTY EXPRESSED OR IMPLIED . USE AT YOUR OWN RISK .
See http : //www.JSON.org/js.html
This code should be minified before deployment .
See http : //javascript.crockford.com/jsmin.html
USE YOUR OWN COPY . IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL .
* /
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
if ( typeof JSON !== 'object' ) {
JSON = { } ;
}
( function ( ) {
'use strict' ;
function f ( n ) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n ;
}
if ( typeof Date . prototype . toJSON !== 'function' ) {
Date . prototype . toJSON = function ( key ) {
return isFinite ( this . valueOf ( ) )
? this . getUTCFullYear ( ) + '-' +
f ( this . getUTCMonth ( ) + 1 ) + '-' +
f ( this . getUTCDate ( ) ) + 'T' +
f ( this . getUTCHours ( ) ) + ':' +
f ( this . getUTCMinutes ( ) ) + ':' +
f ( this . getUTCSeconds ( ) ) + 'Z'
: null ;
} ;
String . prototype . toJSON =
Number . prototype . toJSON =
Boolean . prototype . toJSON = function ( key ) {
return this . valueOf ( ) ;
} ;
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g ,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g ,
gap ,
indent ,
meta = { // table of character substitutions
'\b' : '\\b' ,
'\t' : '\\t' ,
'\n' : '\\n' ,
'\f' : '\\f' ,
'\r' : '\\r' ,
'"' : '\\"' ,
'\\' : '\\\\'
} ,
rep ;
function quote ( string ) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable . lastIndex = 0 ;
return escapable . test ( string ) ? '"' + string . replace ( escapable , function ( a ) {
var c = meta [ a ] ;
return typeof c === 'string'
? c
: '\\u' + ( '0000' + a . charCodeAt ( 0 ) . toString ( 16 ) ) . slice ( - 4 ) ;
} ) + '"' : '"' + string + '"' ;
}
function str ( key , holder ) {
// Produce a string from holder[key].
var i , // The loop counter.
k , // The member key.
v , // The member value.
length ,
mind = gap ,
partial ,
value = holder [ key ] ;
// If the value has a toJSON method, call it to obtain a replacement value.
if ( value && typeof value === 'object' &&
typeof value . toJSON === 'function' ) {
value = value . toJSON ( key ) ;
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if ( typeof rep === 'function' ) {
value = rep . call ( holder , key , value ) ;
}
// What happens next depends on the value's type.
switch ( typeof value ) {
case 'string' :
return quote ( value ) ;
case 'number' :
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite ( value ) ? String ( value ) : 'null' ;
case 'boolean' :
case 'null' :
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String ( value ) ;
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object' :
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if ( ! value ) {
return 'null' ;
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent ;
partial = [ ] ;
// Is the value an array?
if ( Object . prototype . toString . apply ( value ) === '[object Array]' ) {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value . length ;
for ( i = 0 ; i < length ; i += 1 ) {
partial [ i ] = str ( i , value ) || 'null' ;
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial . length === 0
? '[]'
: gap
? '[\n' + gap + partial . join ( ',\n' + gap ) + '\n' + mind + ']'
: '[' + partial . join ( ',' ) + ']' ;
gap = mind ;
return v ;
}
// If the replacer is an array, use it to select the members to be stringified.
if ( rep && typeof rep === 'object' ) {
length = rep . length ;
for ( i = 0 ; i < length ; i += 1 ) {
if ( typeof rep [ i ] === 'string' ) {
k = rep [ i ] ;
v = str ( k , value ) ;
if ( v ) {
partial . push ( quote ( k ) + ( gap ? ': ' : ':' ) + v ) ;
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for ( k in value ) {
if ( Object . prototype . hasOwnProperty . call ( value , k ) ) {
v = str ( k , value ) ;
if ( v ) {
partial . push ( quote ( k ) + ( gap ? ': ' : ':' ) + v ) ;
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial . length === 0
? '{}'
: gap
? '{\n' + gap + partial . join ( ',\n' + gap ) + '\n' + mind + '}'
: '{' + partial . join ( ',' ) + '}' ;
gap = mind ;
return v ;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if ( typeof JSON . stringify !== 'function' ) {
JSON . stringify = function ( value , replacer , space ) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i ;
gap = '' ;
indent = '' ;
// If the space parameter is a number, make an indent string containing that
// many spaces.
if ( typeof space === 'number' ) {
for ( i = 0 ; i < space ; i += 1 ) {
indent += ' ' ;
}
// If the space parameter is a string, it will be used as the indent string.
} else if ( typeof space === 'string' ) {
indent = space ;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer ;
if ( replacer && typeof replacer !== 'function' &&
( typeof replacer !== 'object' ||
typeof replacer . length !== 'number' ) ) {
throw new Error ( 'JSON.stringify' ) ;
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str ( '' , { '' : value } ) ;
} ;
}
// If the JSON object does not yet have a parse method, give it one.
if ( typeof JSON . parse !== 'function' ) {
JSON . parse = function ( text , reviver ) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j ;
function walk ( holder , key ) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k , v , value = holder [ key ] ;
if ( value && typeof value === 'object' ) {
for ( k in value ) {
if ( Object . prototype . hasOwnProperty . call ( value , k ) ) {
v = walk ( value , k ) ;
if ( v !== undefined ) {
value [ k ] = v ;
} else {
delete value [ k ] ;
}
}
}
}
return reviver . call ( holder , key , value ) ;
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String ( text ) ;
cx . lastIndex = 0 ;
if ( cx . test ( text ) ) {
text = text . replace ( cx , function ( a ) {
return '\\u' +
( '0000' + a . charCodeAt ( 0 ) . toString ( 16 ) ) . slice ( - 4 ) ;
} ) ;
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if ( /^[\],:{}\s]*$/
. test ( text . replace ( /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g , '@' )
. replace ( /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g , ']' )
. replace ( /(?:^|:|,)(?:\s*\[)+/g , '' ) ) ) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval ( '(' + text + ')' ) ;
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function'
? walk ( { '' : j } , '' )
: j ;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError ( 'JSON.parse' ) ;
} ;
}
} ( ) ) ;