Adobe: Why no AS3/HTML5 solution for Flash?

Every time Adobe does an article about the Flash IDE’s ability to do HTML5, I am very interested and I check it out. I am always disappointed when they get back to the fact that you have to use JavaScript.

I really cannot understand why Adobe has not endorsed or offered a method to compile Actionscript (or a better language) to JavaScript from within the Flash IDE. Actionscript 3 is clearly superior to JavaScript. Why should we have to re-write everything when we’re in the same IDE? Why are they taking a step backwards?

I would consider Haxe to be the ultimate solution, but Adobe could even use Jangaroo or similar technology to target HTML5—maybe even bundle Google Swiffy. If they did, I’m sure developers would be happy to be able to create both Adobe AIR apps and HTML5 apps from the same code base without needing to install other tools. Those of us using Haxe are already basking in the glory of that.

Perhaps Adobe thinks such a move would eat away at their AIR platform’s popularity. I just don’t know why they bother with JavaScript tools within Flash, when better tools exist. As it stands, I expect that more developers will be doing like I did and begin switching to Haxe with OpenFL, which is a more advanced language than AS3 and can compile to SWF/AIR, HTML5, and a host of other desktop, console and mobile platforms.

Solved: Using ExternalInterface With Swiffy and AS2

I’ve been thankful for Swiffy as a tool for migrating Flash content to HTML5/SVG. It really does an amazing job and its drawbacks are few, but recently I discovered that it does not support using ExternalInterface with ActionScript 2 projects. In layman’s terms this means that the converted application cannot communicate with JavaScript on the page it resides on.

The problem:

Our application needed to support keyboard input on touch-screen devices, and the keyboard is only summoned when a real text input box receives focus. Swiffy uses SVG, which has no form text fields. Therefore we needed to use a JavaScript prompt for entering text, which then returned its data back to the Swiffy application. Remember, we can’t use ExternalInterface.

The solution: NOT using ExternalInterface

Fortunately LoadVars is supported with Swiffy’s AS2, so I came up with the idea of tricking the application into thinking it was communicating with a server. Fortunately I found EWSJS, which is a JavaScript for doing just that. It intercepts AJAX calls and returns whatever data you like.

I have posted my code in case anybody wants it, but seriously—if you don’t need this problem solved save yourself and stop reading now.

The Actionscript needed to have these functions:


grabTextLabelFromJavascript();
var result_thing:LoadVars = new LoadVars();
var t:Number;
result_thing.onLoad = function(success:Boolean) {
if (success) {
trace ("got it:"+result_thing.newTextValue);
if(result_thing.newTextValue==""){
//keep going
trace("keep going");
} else {
if( result_thing.newTextValue=="CANCEL"){
trace("cancel");
} else {
trace("making a new label:"+result_thing.newTextValue);
makeTextLabel(result_thing.newTextValue);
}
clearInterval(t);
getURL("javascript:enableServer(false);"); //disables the fake server
}
} else {
trace("nothing");
}
};
function grabTextLabelFromJavascript(){
t=setInterval(this,"loadIt",500);
getURL("javascript:summonPrompt();");
}
function loadIt():Void{
var send_lv:LoadVars = new LoadVars();
send_lv.sendAndLoad("/labelValue", result_thing, "GET");
}


The Swiffy resides in an iframe on another page so there is code on both HTML documents. First the iframe code:
// remember you will need to embed ewsjs.js and JQuery on this page
<script type="text/javascript">// <!&#91;CDATA&#91; var newLabel=""; var theResponse=""; (function($&;) { var route, router; router = { "/labelValue": { "GET": function(config) { // return the new text label if (newLabel!="") { console.log("newLabel ok:"+newLabel); theResponse="newTextValue="+newLabel; newLabel=""; }else{ console.log("nope"); theResponse="newTextValue="; } return({status: 200, response: theResponse, headers: {"Content-Type":"text/plain"}}); } } }; // simple to wrap around the actual handler, makes it easier to handle GET/PUT/POST/DELETE var handlerFn = function(r) { return function(config){ if (r&#91;config.method&#93;) { return(r&#91;config.method&#93;(config)); } }; }; for (route in router) { if (router.hasOwnProperty(route)) { EWS.registerHandler(route,handlerFn(router&#91;route&#93;)); } } }(jQuery)); function saveLabel(l){ console.log("saving label:"+l); newLabel=l; } // &#93;&#93;></script>

Now the iframe’s containing page:

<script type="text/javascript">// <!&#91;CDATA&#91; var newText=""; function summonPrompt(){ enableServer(true); //newText=""; var lt = prompt("Please enter text for the label:","Label text"); if (lt!=null) { document.getElementById("swiffyFrame").contentWindow.saveLabel(lt); //newText=lt; } else { document.getElementById("swiffyFrame").contentWindow.saveLabel("CANCEL"); } } function enableServer(bool){ console.log("enabling server:"+bool); document.getElementById('swiffyFrame').contentWindow.EWS.enable(bool); } // &#93;&#93;></script>

I hope this helps someone out there in cyberspace.