Friday, September 19, 2008

Code Review Vol. 7 - Automated JS Loading, Reformatting and Injecting with ActionScript 3.0

Based on my previous post I then abstracted a bit further. Instead of having the JavaScript embedded directly in the ActionScript I read it in, reformat it to fit my needs and then inject it into the page. I use the same instance for all file loadings so I don't store any of the values in class properties and I make my own asynchronous token pattern since it's pure AS3 and not Flex. I'll do a full walk through at a later date.


public class JSInjector extends EventDispatcher
{
public function JSInjector()
{}


public function loadExternalJS(url:String):void
{
readFile(url);
}


public function readFile(url:String):void
{
var ldr:ASyncTokenURLLoader = new ASyncTokenURLLoader()
ldr.ASyncToken = url
ldr.addEventListener(Event.COMPLETE , loadComplete,false,0,true);
ldr.addEventListener(IOErrorEvent.IO_ERROR, jsloadError,false,0,true);

var urlReq:URLRequest = new URLRequest(url);
ldr.load(urlReq)
}

private function loadComplete(event:Event):void
{
var e:AsynTokenEvent = new AsynTokenEvent(AsynTokenEvent.ASYNC_LOADED)
e.token = event.target.ASyncToken
dispatchEvent(e);
formatJS(event.target.data)
}

private function jsloadError(e:IOErrorEvent):void
{

}

private function formatJS(js:String):void
{
js = formatFunctionDefinitions(js);
js = formatGlobalVarDefinition(js)
js = js.split("var ").join(" ")
injectJS(js)
}

private function formatGlobalVarDefinition(js:String):String
{
var gvarSCPattern:RegExp =/var\s\w+\s?[^=](?=;\r|\n)/gixm
js = js.replace(gvarSCPattern, '$& = ""')
return js
}

private function formatFunctionDefinitions(js:String):String
{

var functionPattern:RegExp =/function[\s?](\w+)/gim
var newFunctionSource:String = js.replace(functionPattern, "$1 = function")
return newFunctionSource
}

private function injectJS(js:String):void
{
var externalJS:String = "function(){ "+js+" }";

try{
ExternalInterface.call(externalJS);
}catch(e:Error){

}
}

Monday, September 8, 2008

Code Review Vol. 6 - Injecting JavaScript from ActionScript

A project that I have been working on at my new company - which I will post about soon, I've just been waiting to take pictures so I can document how incredible the facilities are - is an ActionScript video player that allows us to play videos from multiple sources, including videos from vendors who require us to load in their player for the actual video playback. The external players, of course, require JavaScript to interact with them. In order to make my player self contained I needed a way to source the JavaScript directly from the ActionScript - this player is to used in a multitude of applications and projects company-wide and I couldn't guarantee that each project would have these necessary .js files.

I found this excellent article by Peter McBride - JavaScript and VBScript Injection in ActionScript 3

I based my solution off of the methodology in the article and it worked beautifully.

I created several AS classes, each with static public functions that could be invoked to load their respective JS into memory. Like the article describes, anonymous functions assigned to variables.


import flash.external.ExternalInterface;

public class JSONInjector
{
public function JSONInjector()
{
}

static public function registerPlayer():void
{
var js:XML = <script>
<![CDATA[
function()
{
JSPLAYER = new Object()
JSPLAYER.obs = {}; // Observers
JSPLAYER.addListener = function( eventType, callbackObj, callbackFunc){ .. }


Rsize = function(divID, height, width)
{
var element = document.getElementById(divID);
element.style.height = height + "px";
element.style.width = width + "px";
}

OpenNewWindow = function(URLtoOpen, windowName, windowFeatures)
{
var newWindow=window.open(URLtoOpen, windowName, windowFeatures);
}

...
}
]]>
</script>
try{
ExternalInterface.call(js);
}catch(e:Error){}

}



Then within the init of the main application I simply called the functions:


JSONInjector.registerContainer()
JSONInjector.registerPlayer()


And within my external interface files, I simply called the JS objects through external interface:


ExternalInterface.call("JSPLAYER.pause",true)


It's as simple as that, and now the need for any peripheral .js files has been negated and we have a self-contained solution for all video playback.

Wednesday, September 3, 2008

New lesson plans

Over the long weekend, in between visiting my grandparents and hitting the shore, I wrote a few new lesson plans. One of the classes I'm teaching this semester is the Scripting Languages class that I re-worked. Previously the class was a VBA class, but I determined that VBA was out of place with the rest of the curriculum. I re-wrote it to cover PHP and .Net. But lately I'd been feeling unsatisfied by the class. It seemed that there really wasn't enough time in one semester to really get as far into each topic as I would like; including both only really allowed a brief primer of each, but I wanted more. So last year I changed it up and concentrated on PHP and it's interaction with MySQL. The results of that were good - except it became almost indistinguishable from my Database Management and Scripting class - which is in PHP and MySQL.

So this year I was determined to give the class an identity of its own while continuing to focus on PHP. This past weekend I got around to it. I wrote up one lesson plan purely as a primer to web services, what they are, how they are used, with examples to several real world ones - specifically last.fm and amazon's. I then concentrate one week going over SOAP and PHP and then finally another week on REST and PHP. I need to create some labs around those topics, and then a multi-week assignment and that will take up the last quarter of the semester.

I'm pretty happy with the results. The next thing I want to do is add some more JavaScript lessons to my HTML/JavaScript class. The class was originally written assuming no prior experience with either technology, but the past few years I've seen the students are all at least comfortable with HTML, so I feel that I can de-emphasize that part and maybe write some more advance topics in JavaScript. I'd love to cover some JSON or Dojo. Hopefully I can work that in this semester as well.