| /* |
| 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 |
| */ |
| |
| /**
|
| A wrapper around Flash 8's ExternalInterface; DojoExternalInterface is needed so that we
|
| can do a Flash 6 implementation of ExternalInterface, and be able
|
| to support having a single codebase that uses DojoExternalInterface
|
| across Flash versions rather than having two seperate source bases,
|
| where one uses ExternalInterface and the other uses DojoExternalInterface.
|
|
|
| DojoExternalInterface class does a variety of optimizations to bypass ExternalInterface's
|
| unbelievably bad performance so that we can have good performance
|
| on Safari; see the blog post
|
| http://codinginparadise.org/weblog/2006/02/how-to-speed-up-flash-8s.html
|
| for details.
|
|
|
| @author Brad Neuberg, bkn3@columbia.edu
|
| */
|
| import flash.external.ExternalInterface;
|
|
|
| class DojoExternalInterface{
|
| public static var available:Boolean;
|
| public static var dojoPath = "";
|
|
|
| private static var flashMethods:Array = new Array();
|
| private static var numArgs:Number;
|
| private static var argData:Array;
|
| private static var resultData = null;
|
|
|
| public static function initialize(){
|
| // extract the dojo base path
|
| DojoExternalInterface.dojoPath = DojoExternalInterface.getDojoPath();
|
|
|
| // see if we need to do an express install
|
| var install:ExpressInstall = new ExpressInstall();
|
| if(install.needsUpdate){
|
| install.init();
|
| }
|
|
|
| // register our callback functions
|
| ExternalInterface.addCallback("startExec", DojoExternalInterface, startExec);
|
| ExternalInterface.addCallback("setNumberArguments", DojoExternalInterface,
|
| setNumberArguments);
|
| ExternalInterface.addCallback("chunkArgumentData", DojoExternalInterface,
|
| chunkArgumentData);
|
| ExternalInterface.addCallback("exec", DojoExternalInterface, exec);
|
| ExternalInterface.addCallback("getReturnLength", DojoExternalInterface,
|
| getReturnLength);
|
| ExternalInterface.addCallback("chunkReturnData", DojoExternalInterface,
|
| chunkReturnData);
|
| ExternalInterface.addCallback("endExec", DojoExternalInterface, endExec);
|
|
|
| // set whether communication is available
|
| DojoExternalInterface.available = ExternalInterface.available;
|
| DojoExternalInterface.call("loaded");
|
| }
|
|
|
| public static function addCallback(methodName:String, instance:Object,
|
| method:Function) : Boolean{
|
| // register DojoExternalInterface methodName with it's instance
|
| DojoExternalInterface.flashMethods[methodName] = instance;
|
|
|
| // tell JavaScript about DojoExternalInterface new method so we can create a proxy
|
| ExternalInterface.call("dojo.flash.comm._addExternalInterfaceCallback",
|
| methodName);
|
|
|
| return true;
|
| }
|
|
|
| public static function call(methodName:String,
|
| resultsCallback:Function) : Void{
|
| // we might have any number of optional arguments, so we have to
|
| // pass them in dynamically; strip out the results callback
|
| var parameters = new Array();
|
| for(var i = 0; i < arguments.length; i++){
|
| if(i != 1){ // skip the callback
|
| parameters.push(arguments[i]);
|
| }
|
| }
|
|
|
| var results = ExternalInterface.call.apply(ExternalInterface, parameters);
|
|
|
| // immediately give the results back, since ExternalInterface is
|
| // synchronous
|
| if(resultsCallback != null && typeof resultsCallback != "undefined"){
|
| resultsCallback.call(null, results);
|
| }
|
| }
|
|
|
| /**
|
| 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(){
|
| DojoExternalInterface.call("dojo.flash.loaded");
|
| }
|
|
|
| public static function startExec():Void{
|
| DojoExternalInterface.numArgs = null;
|
| DojoExternalInterface.argData = null;
|
| DojoExternalInterface.resultData = null;
|
| }
|
|
|
| public static function setNumberArguments(numArgs):Void{
|
| DojoExternalInterface.numArgs = numArgs;
|
| DojoExternalInterface.argData = new Array(DojoExternalInterface.numArgs);
|
| }
|
|
|
| public static function chunkArgumentData(value, argIndex:Number):Void{
|
| //getURL("javascript:dojo.debug('FLASH: chunkArgumentData, value="+value+", argIndex="+argIndex+"')");
|
| var currentValue = DojoExternalInterface.argData[argIndex];
|
| if(currentValue == null || typeof currentValue == "undefined"){
|
| DojoExternalInterface.argData[argIndex] = value;
|
| }else{
|
| DojoExternalInterface.argData[argIndex] += value;
|
| }
|
| }
|
|
|
| public static function exec(methodName):Void{
|
| // decode all of the arguments that were passed in
|
| for(var i = 0; i < DojoExternalInterface.argData.length; i++){
|
| DojoExternalInterface.argData[i] =
|
| DojoExternalInterface.decodeData(DojoExternalInterface.argData[i]);
|
| }
|
|
|
| var instance = DojoExternalInterface.flashMethods[methodName];
|
| DojoExternalInterface.resultData = instance[methodName].apply(
|
| instance, DojoExternalInterface.argData);
|
| // encode the result data
|
| DojoExternalInterface.resultData =
|
| DojoExternalInterface.encodeData(DojoExternalInterface.resultData);
|
|
|
| //getURL("javascript:dojo.debug('FLASH: encoded result data="+DojoExternalInterface.resultData+"')");
|
| }
|
|
|
| public static function getReturnLength():Number{
|
| if(DojoExternalInterface.resultData == null ||
|
| typeof DojoExternalInterface.resultData == "undefined"){
|
| return 0;
|
| }
|
| var segments = Math.ceil(DojoExternalInterface.resultData.length / 1024);
|
| return segments;
|
| }
|
|
|
| public static function chunkReturnData(segment:Number):String{
|
| var numSegments = DojoExternalInterface.getReturnLength();
|
| var startCut = segment * 1024;
|
| var endCut = segment * 1024 + 1024;
|
| if(segment == (numSegments - 1)){
|
| endCut = segment * 1024 + DojoExternalInterface.resultData.length;
|
| }
|
|
|
| var piece = DojoExternalInterface.resultData.substring(startCut, endCut);
|
|
|
| //getURL("javascript:dojo.debug('FLASH: chunking return piece="+piece+"')");
|
|
|
| return piece;
|
| }
|
|
|
| public static function endExec():Void{
|
| }
|
|
|
| private static function decodeData(data):String{
|
| // we have to use custom encodings for certain characters when passing
|
| // them over; for example, passing a backslash over as //// from JavaScript
|
| // to Flash doesn't work
|
| data = DojoExternalInterface.replaceStr(data, "&custom_backslash;", "\\");
|
|
|
| data = DojoExternalInterface.replaceStr(data, "\\\'", "\'");
|
| data = DojoExternalInterface.replaceStr(data, "\\\"", "\"");
|
|
|
| return data;
|
| }
|
|
|
| private static function encodeData(data){
|
| //getURL("javascript:dojo.debug('inside flash, data before="+data+"')");
|
|
|
| // double encode all entity values, or they will be mis-decoded
|
| // by Flash when returned
|
| data = DojoExternalInterface.replaceStr(data, "&", "&");
|
|
|
| // certain XMLish characters break Flash's wire serialization for
|
| // ExternalInterface; encode these into a custom encoding, rather than
|
| // the standard entity encoding, because otherwise we won't be able to
|
| // differentiate between our own encoding and any entity characters
|
| // that are being used in the string itself
|
| data = DojoExternalInterface.replaceStr(data, '<', '&custom_lt;');
|
| data = DojoExternalInterface.replaceStr(data, '>', '&custom_gt;');
|
|
|
| // encode control characters and JavaScript delimiters
|
| data = DojoExternalInterface.replaceStr(data, "\n", "\\n");
|
| data = DojoExternalInterface.replaceStr(data, "\r", "\\r");
|
| data = DojoExternalInterface.replaceStr(data, "\f", "\\f");
|
| data = DojoExternalInterface.replaceStr(data, "'", "\\'");
|
| data = DojoExternalInterface.replaceStr(data, '"', '\"');
|
|
|
| //getURL("javascript:dojo.debug('inside flash, data after="+data+"')");
|
| return data;
|
| }
|
|
|
| /**
|
| Flash ActionScript has no String.replace method or support for
|
| Regular Expressions! We roll our own very simple one.
|
| */
|
| private static function replaceStr(inputStr:String, replaceThis:String,
|
| withThis:String):String {
|
| var splitStr = inputStr.split(replaceThis)
|
| inputStr = splitStr.join(withThis)
|
| return inputStr;
|
| }
|
|
|
| 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:
|