| /* |
| Copyright (c) 2004-2006, The Dojo Foundation |
| All Rights Reserved. |
| |
| Licensed under the Academic Free License version 2.1 or above OR the |
| modified BSD license. For more information on Dojo licensing, see: |
| |
| http://dojotoolkit.org/community/licensing.shtml |
| */ |
| |
| /** |
| 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; |
| public static var dojoPath = ""; |
| |
| public static var _fscommandReady = false; |
| public static var _callbacks = new Array(); |
| |
| public static function initialize(){ |
| //getURL("javascript:dojo.debug('FLASH:DojoExternalInterface initialize')"); |
| // FIXME: Set available variable by testing for capabilities |
| DojoExternalInterface.available = true; |
| |
| // extract the dojo base path |
| DojoExternalInterface.dojoPath = DojoExternalInterface.getDojoPath(); |
| //getURL("javascript:dojo.debug('FLASH:dojoPath="+DojoExternalInterface.dojoPath+"')"); |
| |
| // Sometimes, on IE, the fscommand infrastructure can take a few hundred |
| // milliseconds the first time a page loads. Set a timer to keep checking |
| // to make sure we can issue fscommands; otherwise, our calls to fscommand |
| // for setCallback() and loaded() will just "disappear" |
| _root.fscommandReady = false; |
| var fsChecker = function(){ |
| // issue a test fscommand |
| fscommand("fscommandReady"); |
| |
| // JavaScript should set _root.fscommandReady if it got the call |
| if(_root.fscommandReady == "true"){ |
| DojoExternalInterface._fscommandReady = true; |
| clearInterval(_root.fsTimer); |
| } |
| }; |
| _root.fsTimer = setInterval(fsChecker, 100); |
| } |
| |
| 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}; |
| _callbacks[_callbacks.length] = 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, |
| resultsCallback:Function) : Void{ |
| // 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 - 2; |
| for(var i = 2; i < arguments.length; i++){ |
| var argIndex = i - 2; |
| _root["_" + argIndex] = arguments[i]; |
| } |
| |
| _root._returnResult = undefined; |
| fscommand("call", methodName); |
| |
| // immediately return if the caller is not waiting for return results |
| if(resultsCallback == undefined || resultsCallback == null){ |
| return; |
| } |
| |
| // check at regular intervals for return results |
| var resultsChecker = function(){ |
| if((typeof _root._returnResult != "undefined")&& |
| (_root._returnResult != "undefined")){ |
| clearInterval(_root._callbackID); |
| resultsCallback.call(null, _root._returnResult); |
| } |
| }; |
| _root._callbackID = setInterval(resultsChecker, 100); |
| } |
| |
| /** |
| 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(){ |
| //getURL("javascript:dojo.debug('FLASH:loaded')"); |
| |
| // one more step: see if fscommands are ready to be executed; if not, |
| // set an interval that will keep running until fscommands are ready; |
| // make sure the gateway is loaded as well |
| var execLoaded = function(){ |
| if(DojoExternalInterface._fscommandReady == true){ |
| clearInterval(_root.loadedInterval); |
| |
| // initialize the small Flash file that helps gateway JS to Flash |
| // calls |
| DojoExternalInterface._initializeFlashRunner(); |
| } |
| }; |
| |
| if(_fscommandReady == true){ |
| execLoaded(); |
| }else{ |
| _root.loadedInterval = setInterval(execLoaded, 50); |
| } |
| } |
| |
| /** |
| 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); |
| |
| // return the results |
| _root._returnResult = results; |
| } |
| |
| /** Called by the flash6_gateway.swf to indicate that it is loaded. */ |
| public static function _gatewayReady(){ |
| for(var i = 0; i < _callbacks.length; i++){ |
| fscommand("addCallback", _callbacks[i]); |
| } |
| 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. |
| */ |
| public static function _initializeFlashRunner(){ |
| // figure out where our Flash movie is |
| var swfLoc = DojoExternalInterface.dojoPath + "flash6_gateway.swf"; |
| |
| // load our gateway helper file |
| _root.createEmptyMovieClip("_flashRunner", 5000); |
| _root._flashRunner._lockroot = true; |
| _root._flashRunner.loadMovie(swfLoc); |
| } |
| |
| private static function getDojoPath(){ |
| var url = _root._url; |
| var start = url.indexOf("baseRelativePath=") + "baseRelativePath=".length; |
| var path = url.substring(start); |
| var end = path.indexOf("&"); |
| if(end != -1){ |
| path = path.substring(0, end); |
| } |
| return path; |
| } |
| } |
| |
| // vim:ts=4:noet:tw=0: |