Full JavaScript Access From ActionScript (update)

Have you ever tought about accessing DOM from ActionScript? In fact, you can do it and even far more. You can create and call JavaScript methods and objects, access cookies, change styles… All you need is correct AllowScriptAccess parameter within your flash object. No framework needed here, no hacks, ExternalInterface takes care.
Following application runs JavaScript from textarea:
Application. Line 16 does all the fun
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
applicationComplete="init()">
<mx:Script>
<![CDATA[
[Bindable]
private var lastResult:String = "";
private function init():void
{
ExternalInterface.addCallback("universalCallback", universalCallback);
}
private function runScript():void
{
ExternalInterface.call("eval", script.text);
}
private function universalCallback(... rest):void
{
lastResult = String(rest[0]);
}
]]>
</mx:Script>
<mx:HBox width="100%" height="100%">
<mx:TextArea id="script" width="100%" height="100%">
<mx:text>
<![CDATA[
function myFunction(){
var flash = document.getElementById("flash");
var data = document.childNodes[1].innerHTML;
flash.universalCallback(data);
}
myFunction();
alert(document.getElementsByTagName('title')[0].innerHTML);
]]>
</mx:text>
</mx:TextArea>
<mx:TextArea width="100%" height="100%" text="{lastResult}" />
</mx:HBox>
<mx:Button click="runScript()" label="Run"/>
</mx:Application>
HTML template
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
<head>
<title>Full Javascript Access</title>
<meta http-equiv="Content-Type" content="application/xml; charset=utf-8" />
<meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="expires" content="1" />
<meta http-equiv="pragma" content="no-cache" />
<meta name="author" content="http://studio.yoz.sk" />
<meta name="description" content="Full Javascript Access" />
<meta name="robots" content="all" />
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript">
<!--
var flashvars = {}
var params = {
allowscriptaccess: "always"
};
var attributes = {
id: "flash",
name: "flash"
};
swfobject.embedSWF("Tests.swf", "alternative", "100%", "100%", "10.0.0",
"flash/expressInstall.swf", flashvars, params, attributes);
//-->
</script>
<style type='text/css'>
<!--
body {margin:0px;overflow:hidden;}
html, body, object, embed {width:100%;height:100%;outline:none;}
-->
</style>
</head>
<body>
<div id="alternative">
<a href="http://www.adobe.com/go/getflashplayer">
<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" />
</a>
</div>
</body>
</html>
No additional nothing here just:
- line 20: allowscriptaccess: “always” (“sameDomain” may also be used)
- line 24: tip – add name attribute with swfobject so ExternalInterface.objectID will get correct value
- Improper use of eval opens up your code for injection attacks
- Debugging can be more challenging (no line numbers, etc.)
- eval’d code executes more slowly (no opportunity to compile/cache eval’d code)
Update (Feb 11, 2010): You can use either eval call:
ExternalInterface.call("eval", script.text);
or wrap your script into anonymous function:
ExternalInterface.call("function(){" + script.text + "}");
Personally, I do not see any difference in execution, it seems to be the same, maybe some performance testing would clarify it. What do you think?
Where to go from here:
You can also use the mxml String tag to place your script in it:
Comment eaten. Round 2:
Comment eaten again. Round 3:
< fx:String id=”script”>< ![CDATA[
function myFunction(){
var flash = document.getElementById("APICheck");
var data = document.childNodes[1].innerHTML;
flash.universalCallback(data);
}
]] >< /fx:String>
FYI – if you have a linebreak character then it will break your script. IE this code, “\n” needs to be changed to “\\n”