JSAS
/**
* Copyright wh0 ( http://wonderfl.net/user/wh0 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/3lRD
*/
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.UncaughtErrorEvent;
import flash.external.ExternalInterface;
import flash.system.ApplicationDomain;
import flash.system.Security;
import flash.utils.describeType;
import flash.utils.Dictionary;
// import com.actionscriptbible.Example;
// public class JSAS extends Example {
public class JSAS extends Sprite {
private var index:int = 0;
private var heap:Array = [];
private var reverseHeap:Dictionary = new Dictionary();
public function JSAS() {
// loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, function(e:UncaughtErrorEvent):void { trace(e.error); });
Security.allowDomain('*');
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
ExternalInterface.addCallback('_get', _get);
ExternalInterface.addCallback('_set', _set);
ExternalInterface.addCallback('_call', _call);
ExternalInterface.addCallback('_getStatic', _getStatic);
ExternalInterface.addCallback('_callStatic', _callStatic);
ExternalInterface.addCallback('_construct', _construct);
ExternalInterface.call('JSAS._onready', ExternalInterface.objectID, encode(this));
}
private function _get(v:*, k:String):* {
v = decode(v);
// trace('getting ' + v + '.' + k);
return encode(v[k]);
}
private function _set(v:*, k:String, u:*):void {
v = decode(v);
u = decode(u);
// trace('setting ' + v + '.' + k + ' = ' + u);
v[k] = u;
}
private function _call(v:*, k:String, a:Array=null):* {
v = decode(v);
a = a ? a.map(decode) : [];
// trace('calling ' + v + '.' + k + '(' + a + ')');
return encode(v[k].apply(v, a));
}
private function _getStatic(k:String):* {
// trace('getting ' + k);
return encode(ApplicationDomain.currentDomain.getDefinition(k));
}
private function _callStatic(k:*, a:Array=null):* {
a = a ? a.map(decode) : [];
// trace('calling ' + k + '(' + a + ')');
k = ApplicationDomain.currentDomain.getDefinition(k);
return encode(k.apply(null, a));
}
private function _construct(v:*, a:Array=null):* {
var r:* = null;
v = decode(v);
a = a ? a.map(decode) : [];
// trace('constructing ' + v + '(' + a + ')');
// lol can't invoke constructors with argument array
switch (a.length) {
case 0: r = new v(); break;
case 1: r = new v(a[0]); break;
case 2: r = new v(a[0], a[1]); break;
case 3: r = new v(a[0], a[1], a[2]); break;
case 4: r = new v(a[0], a[1], a[2], a[3]); break;
case 5: r = new v(a[0], a[1], a[2], a[3], a[4]); break;
case 6: r = new v(a[0], a[1], a[2], a[3], a[4], a[5]); break;
case 7: r = new v(a[0], a[1], a[2], a[3], a[4], a[5], a[6]); break;
case 8: r = new v(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]); break;
case 9: r = new v(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); break;
case 10: r = new v(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]); break;
case 11: r = new v(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10]); break;
case 12: r = new v(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]); break;
case 13: r = new v(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12]); break;
case 14: r = new v(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13]); break;
// 14 max. c.f. http://code.google.com/p/haxe/source/browse/trunk/std/flash9/_std/Type.hx#129
}
return encode(r);
}
private function encode(v:*, i:int=0, a:Array=null):* {
if (!v) {
return v;
} else if (typeof(v) == 'object') {
if (v in reverseHeap) return {_jsas: true, _index: reverseHeap[v]};
var d:XML = describeType(v);
if (d.@name == 'Object') {
var o:Object = {};
for (var k:String in v) {
o[k] = encode(v[k]);
}
return o;
} else if (d.@name == 'Array') {
return v.map(encode);
} else {
return makeSpec(v, d);
}
} else if (typeof(v) == 'function') {
return {_jsas: true, _function: true};
} else {
return v;
}
}
private function decode(v:*, i:int=0, a:Array=null):* {
if (!v) {
return v;
} else if (typeof(v) == 'object') {
if (v._jsas) {
if (v._index < index) return heap[v._index];
else return makeWrapper(v);
} else if (v is Array) {
return v.map(decode);
} else {
var o:Object = {};
for (var k:String in v) {
o[k] = decode(v[k]);
}
return o;
}
} else {
return v;
}
}
private function makeSpec(v:*, d:XML):* {
reverseHeap[v] = index;
heap[index] = v;
// trace('heap[' + index + '] = ' + v);
var r:Object = {_jsas: true, _index: index, _getters: [], _setters: [], _methods: []};
index += 1;
var f:XML;
for each (f in d.constant) {
r._getters.push(f.@name.toString());
}
for each (f in d.variable) {
r._getters.push(f.@name.toString());
r._setters.push(f.@name.toString());
}
for each (f in d.accessor) {
if (f.@access != 'writeonly') r._getters.push(f.@name.toString());
if (f.@access != 'readonly') r._setters.push(f.@name.toString());
}
for each (f in d.method) {
r._methods.push(f.@name.toString());
}
if (d.@base == 'Class') r._class = true;
return r;
}
private function makeWrapper(v:*):* {
var r:* = function():* {
var s:Object = {_jsas: true, _index: v._index};
var a:Array = arguments.map(encode);
// trace('calling callback ' + v._index + '(' + a + ')');
return decode(ExternalInterface.call('JSAS._callback', ExternalInterface.objectID, s, a));
};
reverseHeap[r] = v._index;
heap[v._index] = r;
// trace('heap[' + v._index + '] = ' + r);
index = v._index + 1;
return r;
}
}
}