An ActionScript JavaScript communication library that doesn't sucks.
See the original blog post for extended informations and background on this.
Source code is available under a GPL license, in the public hg repository here: http://open.zoomorama.com/hg/as3.jsas/.
The current official release is 20091220-0.1.
This is meant to be usable with Flex SDK 3.4 or greater.
The library does provide a handful of methods:
public function RegisterForIFace( iFace: Class, myObj: Object, jsNameSpace: String = null ): void
public function callSandbox( func: String ): void
public function resetSandbox(): void
public static function get UUID(): Number
You should call resetSandbox() to set-up a fresh execution context for your javascript injections (as often as you deem it necessary, probably at least once if you plan on calling code inside the sandbox).
Getting the UUID back is useful if you plan to execute code from *outside* the sandbox, as to let you get access to your swf node.
The callSandbox( func: String ) method will let you execute any javascript code inside the sandboxed window object.
Finally, the most interesting method obviously is RegisterForIFace that lets you expose methods and accessors of an ActionScript object described by an Interface as a javascript object inside the sandbox.
Assuming you have the following interface:
public interface IExposeTest
{
function get sString(): String;
function gsIFaceOther(): IExposeTest2;
function complexCall( complexArg: IExposeTest2 ): void
}
… implemented by the class of a given object named mySuperObject.
Calling this:
JSAS.instance.RegisterForIFace( IExposeTest, mySuperObject, "contentWindow.exposeHere" );
Will attach onto the javascript object corresponding to your <object> node, additional “contentWindow” and “contentWindow.exposeHere” objects that will have as members the following functions:
Javascript code invoked through the callSandbox method will see in their scope the “exposeHere” object (being bound to the contentWindow object as a global scope).
The RegisterForIFace method does:
The following are important features and limitations that you may be aware of:
Pretty much, one of the painful parts of working in (injected) js with an AS <object> that exposes methods is that you need to first get back to that object.
To do so, JSAS exposes you the UUID and an access method:
if(ExternalInterfaceNG.available){
ExternalInterfaceNG.call(
<script><![CDATA[
function( uuid ){
var mySwfNode = zm.__internalv1.getBrowserByUUID(uuid);
// Do something and call methods on your mySwfNode now
}
]]>
</script>,
m_UUID
);
}
This is still a somewhat convoluted way to work, so, JSAS also exposes you the callSandbox method that let you pass javascript directly that will get executed “as” if the mySwfNode.contentWindow object was the global window scope.
This technically is done by rebinding the fake window to the global scope before execution:
In rather blunt terms, that means:
var funcCore: XML = new XML('<script><![CDATA[\
function(){\
return new (function(window){\
with(window){' + func + '\
}\
})(zm.__internalv1.getBrowserByUUID(' + m_UUID + ').contentWindow);\
}\
]]></script>');
ExternalInterface.call.apply(ExternalInterface, [funcCore]);
You need to beware though, that browsers don't act the same with function declarations, depending on the scope…
Experts possibly want to read this blog post.
Others can simply stick to the idea that function declarations should be avoided, and use function literals or assignments instead.
AS complex type objects may cross the JSAS boundary back and forth, as explained, by being stored in an internal (AS) cache holder, and by using a (JS) identifier.
On the other hand, if you want to feed-in complex type JS objects, you need to code a serialization mechanism and declare it in javascript so that such objects can be serialized before being fed.
Here is a simple example, that declares that JS object of type “Element” will be serialized using a method getting the value of their cacheid attribute:
window.zm.__internalv1.js2asConverter.register(
Element,
function(node) {
return node.getAttributeNS('http://www.zoomorama.com/ns/DOM/1.0', 'cacheid');
}
);
JSAS has the same switches as rebase.