package org.externalassets { import flash.display.LoaderInfo; import flash.events.Event; import flash.events.EventDispatcher; import flash.events.ProgressEvent; import flash.net.URLRequest; import flash.system.ApplicationDomain; import flash.system.LoaderContext; import flash.system.SecurityDomain; /** * Class used to load one or more SWFs. Automatically registers the SWFs * to the current application domain. * * - If you are trying to load swfs for the express purpose of accessing symbols * within those swfs, wait for the Event.INIT, do not wait for Event.COMPLETE, * the swfs will not be accessible. * * - You can add ProgressEvent.PROGRESS, Event.INIT and Event.COMPLETE * listeners to this class. Whether you have one swf or a hundred swfs, * the class will abstract that from you and give you status events as * if there was only one swf being loaded. For example, the currentBytes * values of ProgressEvent will be filled with the sum of all of the current * swfs being loaded, the same goes for the totalBytes. COMPLETE will be * dispatched when everything has been loaded, INIT will be dispatched when * everything has been loaded and is accessible. * * - Once the objects are loaded, the loaders are accessible in the loaderArray. * Just make sure you wait until Event.Complete is dispatched at a minimum. * * @author crebstock * */ public class AssetLoader extends EventDispatcher { /** * True if all loaders have finished loading * * @default null */ public var allLoaded : Boolean; /** * True if the methods and properties of all * loaded objects are accessible * * @default null */ public var allReady : Boolean; /** * True if the Event.Complete notification * has already been dispatched, notifying * listeners that all loading has completed * * @default null */ public var alreadyNotifiedComplete : Boolean; /** * True if the Event.Init notification * has already been dispatched, notifying * listeners that all loaded objects are * accessible * * @default null */ public var alreadyNotifiedInit : Boolean; /** * The sum of all the currentBytes properties of * the Loaders in the loadArray * * @default null */ public var bytesLoaded : Number; /** * The sum of all the totalBytes properties of * the Loaders in the loadArray * * @default null */ public var bytesTotal : Number; /** * Array of loaders * * @default null */ protected var __loaderArray : Array; /** * Security domain for the loaders * * @default null */ private var __secDom:SecurityDomain = null; public function AssetLoader() { bytesLoaded = 0; bytesTotal = 0; } public function get loaderArray() : Array { return __loaderArray; } /** * Initializes loaders, adds listeners and starts loading on * all files, loaders or url's passed in. * * @param loadObjs an array of strings, urlrequests or loaders * */ public function load( ...loadObjs ) : void { //Initialize Loader array __loaderArray = createLoaderArray( loadObjs ); //Create and add listeners to the load array addLoadArrayListeners(); //liftoff! beginLoading(); } /** * Adds listeners to the load array * */ protected function addLoadArrayListeners() : void { for( var i : Number = 0; i < __loaderArray.length; i++ ) { __loaderArray[i].contentLoaderInfo.addEventListener( ProgressEvent.PROGRESS, onLoaderProgress ); __loaderArray[i].contentLoaderInfo.addEventListener( Event.COMPLETE, onLoaderComplete ); __loaderArray[i].contentLoaderInfo.addEventListener( Event.INIT, onLoaderInit ); } } /** * Called when every load is complete, removes complete and progress event listeners and * sets the alreadyNotified boolean to true to prevent duplicate notifications * */ protected function allLoadsComplete() : void { alreadyNotifiedComplete = true; for( var i : Number = 0; i < __loaderArray.length; i++ ) { __loaderArray[i].contentLoaderInfo.removeEventListener( ProgressEvent.PROGRESS, onLoaderProgress ); __loaderArray[i].contentLoaderInfo.removeEventListener( Event.COMPLETE, onLoaderComplete ); } } /** * Called when every load has passed back an init event indicating its properties and * methods are accessible, removes init event listener and sets the alreadyNotified * boolean to true to prevent duplicate notifications * */ protected function allLoadsReady() : void { alreadyNotifiedInit = true; for( var i : Number = 0; i < __loaderArray.length; i++ ) { __loaderArray[i].contentLoaderInfo.removeEventListener( Event.INIT, onLoaderInit ); } } /** * Iterates through the loader array to start each individual loader * */ protected function beginLoading() : void { for( var i : Number = 0; i < __loaderArray.length; i++ ) { __loaderArray[i].load( __loaderArray[i].loaderURL, new LoaderContext( false, ApplicationDomain.currentDomain, __secDom ) ); } } /** * Creates an array of loaders equal in length to the loaderURLArray * * @return Array */ protected function createLoaderArray( unParsedObjs : Array ) : Array { var tmpArray : Array = new Array(); var tmpLoaderObj : AssetLoaderObject; for( var i : Number = 0; i < unParsedObjs.length; i++ ) { tmpLoaderObj = new AssetLoaderObject(); //If current object is a string, create a loader from the string if( unParsedObjs[i] is String ) { tmpLoaderObj.loaderURL = new URLRequest( unParsedObjs[i] ); tmpLoaderObj.loaderInit = false; tmpLoaderObj.loaderStatus = false; tmpArray.push( tmpLoaderObj ); } } return tmpArray; } /** * Iterates through the loaderArray to see if all loaders * have finished loading, sets allLoaded to true if this * is the case */ protected function checkForAllLoaded() : void { var tmpLoaded : Boolean = true; for( var i : Number = 0; i < __loaderArray.length; i++ ) { if( __loaderArray[i].loaderStatus != true ) tmpLoaded = false; } allLoaded = tmpLoaded; } /** * Iterates through the loaderArray to see if the methods * and properties of all loaders are accessible, sets * allLoaded to true if this is the case */ protected function checkForAllReady() : void { var tmpReady : Boolean = true; for( var i : Number = 0; i < __loaderArray.length; i++ ) { if( __loaderArray[i].loaderReady != true ) tmpReady = false; } allReady = tmpReady; } /** * Iterates through the loaderArray and returns the location of the loader * * @return Number */ protected function locateLoader( ldr : LoaderInfo ) : Number { //Iterate through the loaders to find out which one issued //the event (probably a faster than 0(n) way to do this) for( var i : Number = 0; i < __loaderArray.length; i++ ) { if( ldr == __loaderArray[i].contentLoaderInfo ) { //Once you find it, return its location return i; } } //You should never get here, but if you do then 0 is as good an answer as any return 0; } protected function onLoaderProgress( evt : ProgressEvent ) : void { updateLoadedPercentage( locateLoader( evt.target as LoaderInfo ) ); } protected function onLoaderComplete( evt : Event ) : void { updateLoadedPercentage( locateLoader( evt.target as LoaderInfo ) ); } protected function onLoaderInit( evt : Event ) : void { updateLoadedInit( locateLoader( evt.target as LoaderInfo ) ); } protected function updateBytesLoaded() : void { bytesLoaded = 0; for( var i : Number = 0; i < __loaderArray.length; i++ ) { bytesLoaded += __loaderArray[i].contentLoaderInfo.bytesLoaded; } } /** * Calculates the new curLoaded variable and updates the curLoaderArray * element that was changed. Also dispatches a load complete event * if all loaders have finished. * * @param updateLoc location in the arrays that got updated * */ protected function updateLoadedPercentage( updateLoc : Number ) : void { //if this is the first bit of load information we've gotten //from this particular loader, add its total to the //bytesTotal property if( !__loaderArray[updateLoc].loaderInit ) { bytesTotal += __loaderArray[updateLoc].contentLoaderInfo.bytesTotal; __loaderArray[updateLoc].loaderInit = true; } //if this loader has finished loading, set its loaderStatus property to true if( __loaderArray[updateLoc].contentLoaderInfo.bytesLoaded == __loaderArray[updateLoc].contentLoaderInfo.bytesTotal ) { //loading has finished for this loader object __loaderArray[updateLoc].loaderStatus = true; } updateBytesLoaded(); checkForAllLoaded(); if( !allLoaded ) { dispatchEvent( new ProgressEvent( ProgressEvent.PROGRESS, false, false, bytesLoaded, bytesTotal ) ); } else { allLoadsComplete(); dispatchEvent( new Event( Event.COMPLETE, false, false ) ); } } protected function updateLoadedInit( updateLoc : Number ) : void { __loaderArray[updateLoc].loaderReady = true; checkForAllReady(); if( allReady ) { allLoadsReady(); dispatchEvent( new Event( Event.INIT, false, false ) ); } } } }