Two-Way Communicating between JavaScript and Frontal Scripts
From Frontal Wiki
Contents |
Introduction
Oftentimes there is functionality built into JavaScript that you would like to access from Frontal. And at other times, it is useful to be able to do something in JavaScript that affects the Frontal document. With Frontal, this is possible using the Flash ExternalInterface mechanism. With this mechanism, it is possible to call from Frontal in to JavaScript and to call from JavaScript in to Frontal. And because Frontal has an interpreted scripting language and so can support code on demand, there's no limit to the possibilities of the integration.
Towards the end of this section we'll discuss the details of enabling these interfaces but as they are already enabled for the workspace and the Frontal deployment packages, let's look at some examples first.
Calling JavaScript from Frontal
This is very easily done with the Flash ExternalInterface class. Here we show how we can issue a JavaScript alert from Frontal.
<style><![CDATA #test { @onClick { flash.external.ExternalInterface.call ( "alert", "Hello, world." ); } } ]]></script> <text id="test">click me!</text>
If you are using Firefox and have Firebug installed then open up the network tab after you submit this example from the workspace. When you click the Google link you'll be able to see that a tracking event is being sent to Google Analytics.
As an aside, this technique of using a separate namespace to track clicks in your Frontal document just for analytics is very handy. It's described in the section Adding Interactions#Adding Multiple Interactions for a Single Event.
Calling Frontal Script from JavaScript
We can also call a Frontal script from JavaScript. This can be extremely useful in integrating your HTML/JS page and its interactions and events with the Frontal environment. This means that as you process AJAX calls, say, in JavaScript, it is straightforward to alter or completely create a Frontal document in response.
For our example, we will use Frontal script to call JavaScript and have it create a red square on the HTML page. We will then assign an onclick interaction to that HTML object such that it will make a call in Frontal to add a green square to it. This green square when clicked will show a JavaScript alert.
<style><![CDATA[ div { width: 100px; height: 100px; background-color: green; glow-strength: 2; float: left; margin: 10px; @onClick { flash.external.ExternalInterface.call ( "alert", "Frontal-to-JavaScript-to-Frontal-toJavaScript... Whew!" ); } } ]]></style> <script><![CDATA[ com.frontalcode.ExternalInterfaceManager.gI().addFrontalEvalCallback ( ); var jsCode = 'var div = document.createElement ( "div" );'; jsCode += 'div.style.width = "100px";'; jsCode += 'div.style.height = "100px";'; jsCode += 'div.style.backgroundColor = "red";'; jsCode += 'div.onclick = function ( ) { callExternalInterface ( "gD ( 1 ).write ( \'<div />\' );" ); };'; jsCode += 'var body = document.getElementsByTagName ( "body" ) [ 0 ];'; jsCode += 'body.insertBefore ( div, body.firstChild );'; flash.external.ExternalInterface.call ( 'eval', jsCode ); ]]></script>
It's a bit hard to tell that the red square is indeed HTML and not part of Frontal but one way you can tell is to right-click it (or command click it on the Mac) and see that the context menu is HTML's.
So at the heart of the JavaScript-to-Frontal communication in this example is this call:
callExternalInterface ( "gD ( 1 ).write ( \'<div />\' );" );
callExternalInterface is a JavaScript function that is in all the Frontal pages. It is described more below, but is a shortcut to calling the one method that Frontal exports to JavaScript: frontalEval. Because Frontal has an interpreted scripting language, that is all that needs to be exported; any Frontal script may be passed into this call to do whatever it likes in the Frontal document.
Of course, this interface is only opened if it is requested as we did in the previous example with this line:
com.frontalcode.ExternalInterfaceManager.gI().addFrontalEvalCallback ( );
We'll discuss the enabling of this interface more below.
Then back to our example, the call to callExternalInterface is finding our document object and writing a 'div' tag to it. This along with our style sheet is what is creating the green square.
You may ask, "why do we have access to the "gD" (also known as "getDocument") method in the call?" The reason is that any Frontal script run this way will run in the context of the DocumentManager instance. And it is this class that implements the gD method.
Enabling the Frontal-to-JavaScript Calls
By default, this is enabled on the Frontal site and in the Frontal deployment packages. But basically, you need to be sure the "allowscriptaccess" parameter in the Flash embedding code in the HTML page is set to "always" or "sameDomain." See the Flash documentation for details.
Enabling the JavaScript-to-Frontal Calls
By default, this too is enabled on the Frontal site and in the Frontal deployment packages. To use this, you need to either set "enableExternalEval" to true in the "flashvars" parameter in the Flash embedding code in the HTML page or you need to add code like the following to your Frontal document:
<script><![CDATA[ com.frontalcode.ExternalInterfaceManager.gI().addFrontalEvalCallback ( ); </script>
Also in the HTML page, you will need to be sure to set an id on the object tag used for embedding the Flash movie and a name on the embed tag. The value you use for these should be the same and, to use the following JavaScript functions, should be "movie". When using SWFObject, this means passing an id and a name in the attributes object.
Then, add the following JavaScript to your HTML page:
function callExternalInterface ( cmd ) { var result=thisMovie("movie").frontalEval(cmd); } function thisMovie ( movieName ) { if (navigator.appName.indexOf("Microsoft") != -1) { return window[movieName] } else { return document[movieName] } }
Caveats for Multiple, Separate Frontal Documents in an HTML Page
You will notice in the JavaScript function "callExternalInterface" we defined above that we have hard-coded a movie name ("movie") into it. This is because we are catering to the case that there is a single Frontal document in the HTML page. If there are more, that is, if there are multiple calls to SWFObject to embed several Frontal documents, say, then each movie must have a unique id and then the callExternalInterface function must be changed to allow the caller to specify which movie to target.