blob: 700e0088ab174c67e8228290f0754d63714c8b57 [file] [log] [blame]
/**
An implementation of Flash 8's ExternalInterface that works with Flash 6
and which is source-compatible with Flash 8.
@author Brad Neuberg, bkn3@columbia.edu
*/
class DojoExternalInterface{
public static var available:Boolean;
private static var callbacks = new Object();
public static function initialize(){
// FIXME: Set available variable
// FIXME: do a test run to see if we can communicate from Flash to JavaScript
// and back again to make sure we can actually communicate (set 'available'
// variable)
initializeFlashRunner();
}
public static function addCallback(methodName:String, instance:Object,
method:Function) : Boolean{
// A variable that indicates whether the call below succeeded
_root._succeeded = null;
// Callbacks are registered with the JavaScript side as follows.
// On the Flash side, we maintain a lookup table that associates
// the methodName with the actual instance and method that are
// associated with this method.
// Using fscommand, we send over the action "addCallback", with the
// argument being the methodName to add, such as "foobar".
// The JavaScript takes these values and registers the existence of
// this callback point.
// precede the method name with a _ character in case it starts
// with a number
callbacks["_" + methodName] = {_instance: instance, _method: method};
fscommand("addCallback", methodName);
// The API for ExternalInterface says we have to make sure the call
// succeeded; check to see if there is a value
// for _succeeded, which is set by the JavaScript side
if(_root._succeeded == null){
return false;
}else{
return true;
}
}
public static function call(methodName:String) : Object{
// FIXME: support full JSON serialization
// First, we pack up all of the arguments to this call and set them
// as Flash variables, which the JavaScript side will unpack using
// plugin.GetVariable(). We set the number of arguments as "_numArgs",
// and add each argument as a variable, such as "_1", "_2", etc., starting
// from 0.
// We then execute an fscommand with the action "call" and the
// argument being the method name. JavaScript takes the method name,
// retrieves the arguments using GetVariable, executes the method,
// and then places the return result in a Flash variable
// named "_returnResult".
_root._numArgs = arguments.length - 1;
for(var i = 1; i < arguments.length; i++){
var argIndex = i - 1;
_root["_" + argIndex] = arguments[i];
}
_root._returnResult = undefined;
fscommand("call", methodName);
return _root.returnResult;
}
/**
Called by Flash to indicate to JavaScript that we are ready to have
our Flash functions called. Calling loaded()
will fire the dojo.flash.loaded() event, so that JavaScript can know that
Flash has finished loading and adding its callbacks, and can begin to
interact with the Flash file.
*/
public static function loaded(){
call("dojo.flash.loaded");
}
/**
When JavaScript wants to communicate with Flash it simply sets
the Flash variable "_execute" to true; this method creates the
internal Movie Clip, called the Flash Runner, that makes this
magic happen.
*/
private static function initializeFlashRunner(){
// create our Flash runner movie clip and instance, and attach it to
// the root stage
_root.createEmptyMovieClip("_flashRunner_mc");
_root.attachMovie("_flashRunner_mc", "_flashRunner");
// get the actual object instance of the Flash runner movie clip and
// make it invisible
var _flashRunner:MovieClip = _root._flashRunner;
_flashRunner._visible = false;
// ActionScript 2 has no way to dynamically add new script to a
// dynamic Movie Clip's keyframes or labels. Instead, we use the
// onEnterFrame handler, which is called invoked continually at the frame
// rate of the SWF file. When the JavaScript wants to tell the
// Flash Runner to execute, it simply sets the Flash variable
// "_execute" to true, and our onEnterFrame handler knows to execute
// a Flash method
_root._execute = "false";
_flashRunner.onEnterFrame = function(){
// SetVariable on the JavaScript side turns all values into strings,
// so this comes over as "true" not a Boolean true
if(_root._execute == "true"){
// reset the execution request
_root._execute = "false";
// handle and execute it
DojoExternalInterface._handleJSCall();
}
}
}
/**
Handles and executes a JavaScript to Flash method call. Used by
initializeFlashRunner.
*/
public static function _handleJSCall(){
// get our parameters
var numArgs = parseInt(_root._numArgs);
var jsArgs = new Array();
for(var i = 0; i < numArgs; i++){
var currentValue = _root["_" + i];
jsArgs.push(currentValue);
}
// get our function name
var functionName = _root._functionName;
// now get the actual instance and method object to execute on,
// using our lookup table that was constructed by calls to
// addCallback on initialization
var instance = callbacks["_" + functionName]._instance;
var method = callbacks["_" + functionName]._method;
// execute it
var results = method.apply(instance, jsArgs);
getURL("javascript:dojo.debug('FLASH: result="+results+"')");
// return the results
_root._returnResult = results;
}
}
// vim:ts=4:noet:tw=0: