Skip to content

Instantly share code, notes, and snippets.

@bastman
Created April 7, 2012 13:03
Show Gist options
  • Save bastman/2328725 to your computer and use it in GitHub Desktop.
Save bastman/2328725 to your computer and use it in GitHub Desktop.
JsEvalProxy for as3: pimp flash.external.ExternalInterface
package de.basilicom.utils
{
/**
* @requires: JSON on javascript-side, e.g: JSON2.js
* @description pimp flash.external.ExternalInterface
* @author seb
*/
import com.adobe.serialization.json.JSON;
import flash.external.ExternalInterface;
public class JsEvalProxy
{
private static var _instance:JsEvalProxy;
protected var _proxyName:String;
protected var _jsAvailable:Boolean;
protected var _isCreated:Boolean;
protected var _isDebugLogEnabled:Boolean = true;
protected var _debugConsoleName:String = "console";
protected var _autoCreateEnabled:Boolean = true;
// debugging
protected var _proxyCreateResult: *;
protected var _proxyScript:String;
protected var _proxyCreateResultType:String;
// ++++++++++++++++++++++++++++++++++++++++++++++++++
public function JsEvalProxy()
{
_instance = this;
if(_autoCreateEnabled) {
autoCreate();
}
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++
public static function getInstance():JsEvalProxy
{
if (!JsEvalProxy._instance) {
JsEvalProxy._instance = new JsEvalProxy();
}
return JsEvalProxy._instance;
}
// ++++++++++++++++++++ samples ++++++++++++
public function jsInvokeFunction(method:String, params:Array, mashallExceptions:Boolean):*
{
if (!method) {
throw new Error("Invalid method");
}
var result:* = _jsInvokeFunction(method, params, mashallExceptions);
return result;
}
public function jsAlert(...args):*
{
var mashallExceptions:Boolean = false;
var script:String = "alert.apply(null, arguments)"
var params:Array = args;
var result:* = run(script, params, mashallExceptions);
return result;
}
public function jsConsoleLog(...args):*
{
var mashallExceptions:Boolean = false;
var script:String = 'if ((typeof(console)==="object") && (typeof(console.log)==="function")) {console.log.apply(null, arguments);}';
var params:Array = args;
var result:* = run(script, params, mashallExceptions);
return result;
}
public function jsTypeOf(variableName:String):*
{
if (!variableName) {
return "null";
}
var script:String = "return typeof("+variableName+");";
return run(script, [], false);
}
public function jsCreateEchoTestFunction():*
{
var methodName:String = "window.JSEvalEchoTest";
var script:String = ""+methodName+"=function(arg) {return arg;};";
return run(script, [], false);
}
public function jsEchoTest(value:*):*
{
var methodName:String = "window.JSEvalEchoTest";
if (jsTypeOf(methodName) !== "function") {
jsCreateEchoTestFunction();
}
var result:* = jsInvokeFunction(methodName, [value], false);
return result;
}
protected function _jsInvokeFunction(method:String, params:Array, mashallExceptions:Boolean):*
{
if (!method) {
throw new Error("Invalid method");
}
var script:String = "return " + method + ".apply(null, arguments);";
if (!params) {
params = [];
}
var result:* = run(script, params, mashallExceptions);
return result;
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++
public function autoCreate():Boolean
{
var name:String = "flashjsevalproxy";
var uid:String = new Date().valueOf()
+ "_" + Math.round(Math.random() * 100000)
+ "_" + Math.round(Math.random() * 100000)
+ "_" + Math.round(Math.random() * 100000)
var proxyName:String = "window." + name + "_" + uid;
_proxyName = proxyName;
var isCreated:Boolean = createByName(proxyName);
if (isCreated) {
_isCreated = true;
}
return isCreated;
}
public function isDebugLogEnabled():Boolean
{
return _isDebugLogEnabled;
}
public function setDebugLogEnabled(enabled:Boolean):void
{
_isDebugLogEnabled = enabled;
}
public function getProxyCreateResult():*
{
return _proxyCreateResult;
}
public function getProxyCreateResultType():*
{
return _proxyCreateResultType;
}
public function getProxyScript():*
{
return _proxyScript;
}
public function getProxyName():String
{
return _proxyName;
}
public function isCreated():Boolean
{
return _isCreated;
}
public function isLocal():Boolean
{
return (!isJavascriptAvailable());
}
public function isJavascriptAvailable():Boolean
{
if (_jsAvailable === true) {
return true;
}
var result:Boolean = false;
if (!ExternalInterface.available) {
return result;
}
var r = _invoke("eval", [true], false);
var jsAvailable:Boolean = (r === true);
if (jsAvailable) {
_jsAvailable = true;
}
return (jsAvailable);
}
public function run(script: String, params:Array, marshallExceptions:Boolean):*
{
var result:* = null;
var proxyMethod:String = getProxyName();
if (!proxyMethod) {
throw new Error("Invalid proxy method");
}
result = runByName(proxyMethod, script, params, marshallExceptions);
return result;
}
public function runByName(name:String, script: String, params:Array, marshallExceptions:Boolean):*
{
var result:* = null;
var proxyMethod:String = name;
if (!proxyMethod) {
throw new Error("Inalid proxy method");
}
try {
var scriptEncoded:String = "" + script;
scriptEncoded = JSON.encode(scriptEncoded);
scriptEncoded = encodeURIComponent(scriptEncoded);
}catch (e:Error) {
throw new Error("Encode script failed! " +e.message);
}
var finalParams:Array = [
"" + scriptEncoded
];
if (!params) {
params = [];
}
var i:int;
for (i = 0; i < params.length; i++) {
var param:* = params[i];
try {
param = JSON.encode(param);
param = encodeURIComponent(param);
}catch (e:Error) {
throw new Error("Encode script param at "+i+" failed! " +e.message);
}
finalParams.push(param);
}
if (!isJavascriptAvailable()) {
return result;
}
result = _invoke(proxyMethod, finalParams, marshallExceptions);
if (result === "undefined") {
result = undefined;
}
if ( typeof(result) === "string" ) {
try {
result = decodeURIComponent(result);
result = JSON.decode(result);
}catch (e:Error) {
throw new Error("Decode result failed! " +e.message);
}
}
return result;
}
public function createByName(name:String)
{
var result:Boolean = false;
if (!name) {
throw new Error("Invalid parameter 'name'");
}
var consoleName = (_debugConsoleName || "console");
var script:String =''+
'' + name + ' = function () {' +
'var logEnabled =' + JSON.encode(isDebugLogEnabled()) + ';' +
'var debugConsole ='+consoleName + ';' +
'var doLog = ( (logEnabled) && (typeof(debugConsole)==="object") && (debugConsole) );' +
'if (doLog) {debugConsole.log("--------------------- JsEvalProxy ----------------------------"); };' +
'if (doLog) {debugConsole.log("JsEvalProxy: args=",arguments); };' +
'var source=null;'+
'var params=[];' +
'for (var i=0; i<arguments.length; i++) {' +
' if (i===0) {' +
' var source = arguments[i];' +
' } else {' +
' params.push(arguments[i]);' +
' };' +
'};' +
'if (doLog) {debugConsole.log("JsEvalProxy: source=",source); };'+
'if (doLog) {debugConsole.log("JsEvalProxy: params=",params); };'+
'var $source;'+
'var $params;'+
'if(typeof(source==="string")) {'+
' try {' +
' var $source = source;' +
' if (doLog) {debugConsole.log("JsEvalProxy: source=",$source);};' +
' $source = decodeURIComponent($source);' +
' if (doLog) {debugConsole.log("JsEvalProxy: source=",$source);};' +
' $source = JSON.parse($source);' +
' if (doLog) {debugConsole.log("JsEvalProxy: source=",$source);};' +
' }catch (e) {' +
' if (doLog) {debugConsole.log("JsEvalProxy: source=",source);};' +
' throw new Error("JsEvalProxy: failed to decode source. reason:"+e.message);'+
' };'+
'} else {'+
' $source = source;'+
'};'+
'if(!params) {'+
' var params = [];'+
'};'+
'$params = [];'+
'for(var i=0; i<params.length; i++) {'+
' var p = params[i];' +
' if (doLog) {debugConsole.log("JsEvalProxy: prepare param at "+i+" of type="+typeof(p)+" value=",p); };' +
' if(typeof(p)==="string") {'+
' try {'+
' var $p = p;'+
' $p = decodeURIComponent($p);'+
' if (doLog) {debugConsole.log("JsEvalProxy: --> decoded param at "+i+" of type="+typeof($p)+" value=",$p); };' +
' $p = JSON.parse($p);'+
' if (doLog) {debugConsole.log("JsEvalProxy: --> decoded param at "+i+" of type="+typeof($p)+" value=",$p); };' +
' }catch (e) {' +
' if (doLog) {debugConsole.log("JsEvalProxy: invalid param=",p); };' +
' throw new Error("JsEvalProxy:failed to decode param at "+i+". reason:"+e.message+" param="+p);'+
' };'+
' } else {'+
' var $p = p;'+
' };' +
' if (doLog) {debugConsole.log("JsEvalProxy: add param of at "+i+" of type="+typeof($p)+" value=",$p); };' +
' $params.push($p);'+
'};'+
'var fnText = "(function() " +'+
' "{" +'+
' ""+$source+";" +'+
' "}" +'+
' ");";' +
'if (doLog) {debugConsole.log("JsEvalProxy: eval funcText=",fnText);};' +
'if (doLog) {debugConsole.log("JsEvalProxy: $params=",$params);};' +
'var func = eval(fnText);'+
'if (doLog) {debugConsole.log("JsEvalProxy: func=",func);};' +
'var result = func.apply(null, $params);' +
'if (doLog) {debugConsole.log("JsEvalProxy: func result=",result);};' +
'if (typeof(result)==="undefined") { result=null; };'+
'if (typeof(result)==="function") { result=null; };' +
'try {'+
' var result = JSON.stringify(result);'+
' var result = encodeURIComponent(result);' +
'} catch(e) { '+
' throw new Error("JsEvalProxy: Encode result failed! " + e);' +
'};' +
'return result;'+
'};'+
'';
var s:String;
s = script;
_proxyScript = s;
if (!isJavascriptAvailable()) {
return result;
}
_proxyCreateResult = _invoke("eval", [s], false); // supposed to be null, since "fucntion" can't be serialized
_proxyCreateResultType = _invoke("eval", ["typeof("+name+")"], false);
var isCreated:Boolean = (_proxyCreateResultType === "function");
return (isCreated===true)
}
// ++++++++++++++++++++++++++++++++++++++++++++++++++
protected function _invoke(method:String, params:Array, marshallExceptions:Boolean):*
{
var result:* = null;
var error:* = null;
var args:Array=[
method
];
for(var i:int=0;i<params.length;i++) {
args.push(params[i]);
}
var marshallExceptionsOld:Boolean = (flash.external.ExternalInterface.marshallExceptions === true);
flash.external.ExternalInterface.marshallExceptions = (marshallExceptions === true);
try {
result = flash.external.ExternalInterface.call.apply(null, args);
}catch (e:Error) {
error = e;
}
flash.external.ExternalInterface.marshallExceptions = marshallExceptionsOld;
if (error is Error) {
if (marshallExceptions) {
throw error;
}
}
return result;
}
}
}
// +++++++++ NOTE: JSON required on javascript side, e.g. JSON2.js ++++++++++++++++++++++
import com.adobe.serialization.json.JSON;
import de.basilicom.utils.JsEvalProxy;
var r;
// ++++++++++ simple examples +++++++++++++++++++++
JsEvalProxy.getInstance().jsAlert("Hello World from Flash!");
JsEvalProxy.getInstance().jsConsoleLog("Hello World from Flash!", "foo", "bar", "baz");
JsEvalProxy.getInstance().run("console.log('args=',arguments)", ["foo", "bar"], false);
r=JsEvalProxy.getInstance().jsInvokeFunction('Math.round', [4.345], false)
JsEvalProxy.getInstance().jsConsoleLog(
"the result of last function... : ",
r
);
// ++++++++++ complex examples +++++++++++++++++++++
//JsEvalProxy.getInstance().jsCreateEchoTestFunction();
r=JsEvalProxy.getInstance().jsTypeOf("window.JSEvalEchoTest");
r=JsEvalProxy.getInstance().jsEchoTest("foo");
JsEvalProxy.getInstance().jsConsoleLog(
"the result of last function... : ",
r
);
var o= {
"foo":"bar",
"x":1,
"r":1.234,
"b":true,
"a":["foo","bar","baz"],
"text":"Hello World. Watch this: äöüÄÖÜ߀$!",
"baz": JSON.encode(
{
"foo":"bar",
"x":1,
"r":1.234,
"b":true,
"a":["foo","bar","baz"],
"text":"Hello World. Watch this: äöüÄÖÜ߀$!",
"baz": JSON.encode( {
"foo":"bar",
"x":1,
"r":1.234,
"b":true,
"a":["foo","bar","baz"],
"text":"Hello World. Watch this: äöüÄÖÜ߀$!"
}
)
})
};
r = JsEvalProxy.getInstance().jsInvokeFunction('JSON.stringify', [o], false);
JsEvalProxy.getInstance().jsConsoleLog(
"the result of last function... : ",
r
);
r = JsEvalProxy.getInstance().jsEchoTest(o);
JsEvalProxy.getInstance().jsConsoleLog(
"the result of last function... : ",
r
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment