Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 169 additions & 0 deletions src/fl/display/SafeLoader.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package fl.display {

import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.Sprite;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.utils.ByteArray;

/**
* This class is provided as sample code. Loading a SWF with the SafeLoader instead of
* flash.display.Loader allows you to load a SWF that uses TLF and the default RSL
* preloading options and be able to script the loaded content normally. When you use
* the SafeLoader, you will not get the Event.INIT or Event.COMPLETE events until the
* RSL preloading is completed and the real content is available and when you access
* the content property, you will be accessing the real content. This will allow you
* to write script that calls between the loaded SWF that uses TLF and the loading SWF
* as you normally would.
*
* <p>Note that SafeLoader is NOT a subclass of flash.display.Loader, so you will need
* to change all type references to be SafeLoader instead of Loader.</p>
*/

public class SafeLoader extends Sprite
{
private var _cli:SafeLoaderInfo;
private var _loader:Loader;
private var _content:DisplayObject;
private var _loading:Boolean;

public function SafeLoader()
{
_loading = false;
_content = null;
_loader = new Loader();
_loader.visible = false;
super.addChild(_loader);
_cli = new SafeLoaderInfo(this, loadDoneCallback);
}

// called by SafeLoaderInfo when the content is ready and before the events
// are dispatched. Returns false if load was cancelled
private function loadDoneCallback(d:DisplayObject):Boolean
{
if (!_loading) {
_loader.unload();
return false;
}
_loading = false;
_content = d;
if (d != null) {
super.addChild(d);
super.removeChild(_loader);
}
return true;
}

/**
* get access to the flash.display.Loader being used by the SafeLoader to do all the work.
*/
public function get realLoader():Loader { return _loader; }

/**
* mimic Loader API
*/
public function get content():DisplayObject {
return _content;
}

/**
* mimic Loader API. Important difference is contentLoaderInfo returns a SafeLoaderInfo,
* which is NOT a subclass of LoaderInfo.
*/
public function get contentLoaderInfo():SafeLoaderInfo {
return _cli;
}

/**
* mimic Loader API
*/
public function close():void {
if (_loading) {
_loading = false;
// we may be still acting as though the load is incomplete to allow RSL preloading
// to finish, so catch any errors
try { _loader.close(); } catch (e:Error) { }
} else {
_loader.close();
}
}

/**
* mimic Loader API
*/
public function load(request:URLRequest, context:LoaderContext=null):void {
_loading = true;
if (_content != null && _content.parent == this) super.removeChild(_content);
_content = null;
_loader.load(request, context);
}

/**
* mimic Loader API
*/
public function loadBytes(bytes:ByteArray, context:LoaderContext=null):void {
_loading = true;
if (_content != null && _content.parent == this) super.removeChild(_content);
_content = null;
_loader.loadBytes(bytes, context);
}

/**
* mimic Loader API
*/
public function unload():void {
if (_content != null && _content.parent == this) super.removeChild(_content);
_content = null;
_loader.unload();
}

/**
* mimic Loader API. This API only available player 10, AIR 1.5 or higher.
*/
public function unloadAndStop(gc:Boolean=true):void {
if (_content != null && _content.parent == this) super.removeChild(_content);
_content = null;
_loader["unloadAndStop"](gc);
}

/**
* mimic the way flash.display.Loader disallows children to be added, removed
* @private
*/
public override function addChild(c:DisplayObject):DisplayObject {
throw new Error("Error #2069: The SafeLoader class does not implement this method.");
}
/**
* mimic the way flash.display.Loader disallows children to be added, removed
* @private
*/
public override function addChildAt(c:DisplayObject, i:int):DisplayObject {
throw new Error("Error #2069: The SafeLoader class does not implement this method.");
}
/**
* mimic the way flash.display.Loader disallows children to be added, removed
* @private
*/
public override function removeChild(c:DisplayObject):DisplayObject {
throw new Error("Error #2069: The SafeLoader class does not implement this method.");
}
/**
* mimic the way flash.display.Loader disallows children to be added, removed
* @private
*/
public override function removeChildAt(i:int):DisplayObject {
throw new Error("Error #2069: The SafeLoader class does not implement this method.");
}
/**
* mimic the way flash.display.Loader disallows children to be added, removed
* @private
*/
public override function setChildIndex(c:DisplayObject, i:int):void {
throw new Error("Error #2069: The SafeLoader class does not implement this method.");
}

}
}

174 changes: 174 additions & 0 deletions src/fl/display/SafeLoaderInfo.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package fl.display {

import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.InteractiveObject;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.HTTPStatusEvent;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.system.ApplicationDomain;
import flash.utils.ByteArray;
import flash.utils.getQualifiedClassName;

/**
* This class is provided as example code. Used by SafeLoader to do the bulk of the
* heavy lifting of the safe loading of SWF files using TLF with default RSL preloading
* settings. This class has been developed to be compatible with Flash Player 10, but
* if you are using AIR and you need access to the childSandboxBridge or parentSandboxBridge
* properties, you can uncomment them in the code below.
*/

public class SafeLoaderInfo extends EventDispatcher{

private var _safeLoader:SafeLoader;
private var _loadDoneCallback:Function;
private var _realLI:LoaderInfo;

private var _rslPreloaderLoaded:Boolean;
private var _numAdded:int;

/**
* it is never useful to create a SafeLoaderInfo directly. It should always
* be created by the SafeLoader and accessed via the contentLoaderInfo property.
*/
public function SafeLoaderInfo(l:SafeLoader, c:Function)
{
_rslPreloaderLoaded = false;
_numAdded = 0;

_safeLoader = l;
_loadDoneCallback = c;
_realLI = l.realLoader.contentLoaderInfo;

_realLI.addEventListener(Event.COMPLETE, handleLoaderInfoEvent);
_realLI.addEventListener(HTTPStatusEvent.HTTP_STATUS, handleLoaderInfoEvent);
_realLI.addEventListener(Event.INIT, handleLoaderInfoEvent);
_realLI.addEventListener(IOErrorEvent.IO_ERROR, handleLoaderInfoEvent);
_realLI.addEventListener(Event.OPEN, handleLoaderInfoEvent);
_realLI.addEventListener(ProgressEvent.PROGRESS, handleProgressEvent);
_realLI.addEventListener(Event.UNLOAD, handleLoaderInfoEvent);
}

public function get actionScriptVersion():uint { return _realLI.actionScriptVersion; }
public function get applicationDomain():ApplicationDomain { return _realLI.applicationDomain; }
public function get bytes():ByteArray { return _realLI.bytes; }

/**
* prevent bytesLoaded from equalling bytesTotal until we are certain that everything
* is loaded completely correctly. Users should not rely on this to assume that everything
* is ready, they should be using the init and complete events, but just in case.
*/
public function get bytesLoaded():uint {
if (_realLI.bytesLoaded >= _realLI.bytesTotal && _safeLoader.content == null) {
return _realLI.bytesTotal - 1;
}
return _realLI.bytesLoaded;
}

public function get bytesTotal():uint { return _realLI.bytesTotal; }
public function get childAllowsParent():Boolean { return _realLI.childAllowsParent; }

// only for AIR apps.
public function get childSandboxBridge():Object { return _realLI["childSandboxBridge"]; }

public function get content():DisplayObject { return _safeLoader.content; }

public function get contentType():String { return _realLI.contentType; }
public function get frameRate():Number { return _realLI.frameRate; }
public function get height():int { return _realLI.height; }
public function get loader():SafeLoader { return _safeLoader; }
public function get loaderURL():String { return _realLI.loaderURL; }
public function get parameters():Object { return _realLI.parameters; }
public function get parentAllowsChild():Boolean { return _realLI.parentAllowsChild; }

// only for AIR apps.
public function get parentSandboxBridge():Object { return _realLI["parentSandboxBridge"]; }

public function get sameDomain():Boolean { return _realLI.sameDomain; }
public function get sharedEvents():EventDispatcher { return _realLI.sharedEvents; }
public function get swfVersion():uint { return _realLI.swfVersion; }
public function get url():String { return _realLI.url; }
public function get width():int { return _realLI.width; }

private function handleLoaderInfoEvent(e:Event):void
{
switch (e.type) {
case HTTPStatusEvent.HTTP_STATUS:
case IOErrorEvent.IO_ERROR:
case Event.OPEN:
case Event.UNLOAD:
// just forward these events
dispatchEvent(e);
break;
case Event.INIT:
// check if we have loaded an RSL preloader SWF
_rslPreloaderLoaded = false;
var theContent:DisplayObject = _realLI.content;
try {
var theName:String = getQualifiedClassName(theContent);
if (theName.substr(-13) == "__Preloader__") {
var rslPreloader:Object = theContent["__rslPreloader"];
if (rslPreloader != null) {
theName = getQualifiedClassName(rslPreloader);
if (theName == "fl.rsl::RSLPreloader") {
_rslPreloaderLoaded = true;
_numAdded = 0;
theContent.addEventListener(Event.ADDED, handleAddedEvent);
}
}
}
} catch (e:Error) {
_rslPreloaderLoaded = false;
}
if (!_rslPreloaderLoaded) {
_loadDoneCallback(theContent);
if (_realLI.bytesLoaded >= _realLI.bytesTotal) {
dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, _realLI.bytesLoaded, _realLI.bytesTotal));
}
dispatchEvent(e);
}
break;
case Event.COMPLETE:
if (!_rslPreloaderLoaded) dispatchEvent(e);
break;
}
}

private function handleProgressEvent(e:ProgressEvent):void
{
// don't dispatch event with progress at 100% completion until
// we have determined whether we need to stall for the RSL preload
// to complete
if (e.bytesLoaded < e.bytesTotal || _safeLoader.content != null) {
dispatchEvent(e);
}
}

private function handleAddedEvent(e:Event):void
{
// check to ensure this was actually something added to the Loader.content
var c:DisplayObject = e.target as DisplayObject;
var p:DisplayObjectContainer = e.currentTarget as DisplayObjectContainer;
if (c != null && p != null && c.parent == p) {
_numAdded++;
}
// the first thing added will be the loader animation swf, so ignore that
if (_numAdded > 1) {
e.currentTarget.removeEventListener(Event.ADDED, handleAddedEvent);
// if the load was cancelled, then _loadDoneCallback() will return false
if (_loadDoneCallback(c)) {
if (_realLI.bytesLoaded >= _realLI.bytesTotal) {
dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, _realLI.bytesLoaded, _realLI.bytesTotal));
}
dispatchEvent(new Event(Event.INIT, false, false));
dispatchEvent(new Event(Event.COMPLETE, false, false));
}
}
}

}
}
Loading