add ajaxchat library - needs a lot of integration work to handle decentralisation (e.g. chatroom@website) and zotid w/permissions (e.g. ACL controlled chatrooms); we can also rip out a lot of stuff we don't need.
This commit is contained in:
591
library/ajaxchat/chat/js/FABridge.js
Normal file
591
library/ajaxchat/chat/js/FABridge.js
Normal file
@@ -0,0 +1,591 @@
|
||||
/*
|
||||
/*
|
||||
Copyright 2006 Adobe Systems Incorporated
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* The Bridge class, responsible for navigating AS instances
|
||||
*/
|
||||
function FABridge(target,bridgeName)
|
||||
{
|
||||
this.target = target;
|
||||
this.remoteTypeCache = {};
|
||||
this.remoteInstanceCache = {};
|
||||
this.remoteFunctionCache = {};
|
||||
this.localFunctionCache = {};
|
||||
this.bridgeID = FABridge.nextBridgeID++;
|
||||
this.name = bridgeName;
|
||||
this.nextLocalFuncID = 0;
|
||||
FABridge.instances[this.name] = this;
|
||||
FABridge.idMap[this.bridgeID] = this;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// type codes for packed values
|
||||
FABridge.TYPE_ASINSTANCE = 1;
|
||||
FABridge.TYPE_ASFUNCTION = 2;
|
||||
|
||||
FABridge.TYPE_JSFUNCTION = 3;
|
||||
FABridge.TYPE_ANONYMOUS = 4;
|
||||
|
||||
FABridge.initCallbacks = {}
|
||||
|
||||
FABridge.argsToArray = function(args)
|
||||
{
|
||||
var result = [];
|
||||
for (var i = 0; i < args.length; i++)
|
||||
{
|
||||
result[i] = args[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function instanceFactory(objID)
|
||||
{
|
||||
this.fb_instance_id = objID;
|
||||
return this;
|
||||
}
|
||||
|
||||
function FABridge__invokeJSFunction(args)
|
||||
{
|
||||
var funcID = args[0];
|
||||
var throughArgs = args.concat();//FABridge.argsToArray(arguments);
|
||||
throughArgs.shift();
|
||||
|
||||
var bridge = FABridge.extractBridgeFromID(funcID);
|
||||
return bridge.invokeLocalFunction(funcID, throughArgs);
|
||||
}
|
||||
|
||||
FABridge.addInitializationCallback = function(bridgeName, callback)
|
||||
{
|
||||
var inst = FABridge.instances[bridgeName];
|
||||
if (inst != undefined)
|
||||
{
|
||||
callback.call(inst);
|
||||
return;
|
||||
}
|
||||
|
||||
var callbackList = FABridge.initCallbacks[bridgeName];
|
||||
if(callbackList == null)
|
||||
{
|
||||
FABridge.initCallbacks[bridgeName] = callbackList = [];
|
||||
}
|
||||
|
||||
callbackList.push(callback);
|
||||
}
|
||||
|
||||
function FABridge__bridgeInitialized(bridgeName) {
|
||||
var objects = document.getElementsByTagName("object");
|
||||
var ol = objects.length;
|
||||
var activeObjects = [];
|
||||
if (ol > 0) {
|
||||
for (var i = 0; i < ol; i++) {
|
||||
if (typeof objects[i].SetVariable != "undefined") {
|
||||
activeObjects[activeObjects.length] = objects[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
var embeds = document.getElementsByTagName("embed");
|
||||
var el = embeds.length;
|
||||
var activeEmbeds = [];
|
||||
if (el > 0) {
|
||||
for (var j = 0; j < el; j++) {
|
||||
if (typeof embeds[j].SetVariable != "undefined") {
|
||||
activeEmbeds[activeEmbeds.length] = embeds[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
var aol = activeObjects.length;
|
||||
var ael = activeEmbeds.length;
|
||||
var searchStr = "bridgeName="+ bridgeName;
|
||||
if ((aol == 1 && !ael) || (aol == 1 && ael == 1)) {
|
||||
FABridge.attachBridge(activeObjects[0], bridgeName);
|
||||
}
|
||||
else if (ael == 1 && !aol) {
|
||||
FABridge.attachBridge(activeEmbeds[0], bridgeName);
|
||||
}
|
||||
else {
|
||||
var flash_found = false;
|
||||
if (aol > 1) {
|
||||
for (var k = 0; k < aol; k++) {
|
||||
var params = activeObjects[k].childNodes;
|
||||
for (var l = 0; l < params.length; l++) {
|
||||
var param = params[l];
|
||||
if (param.nodeType == 1 && param.tagName.toLowerCase() == "param" && param["name"].toLowerCase() == "flashvars" && param["value"].indexOf(searchStr) >= 0) {
|
||||
FABridge.attachBridge(activeObjects[k], bridgeName);
|
||||
flash_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flash_found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!flash_found && ael > 1) {
|
||||
for (var m = 0; m < ael; m++) {
|
||||
var flashVars = activeEmbeds[m].attributes.getNamedItem("flashVars").nodeValue;
|
||||
if (flashVars.indexOf(searchStr) >= 0) {
|
||||
FABridge.attachBridge(activeEmbeds[m], bridgeName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// used to track multiple bridge instances, since callbacks from AS are global across the page.
|
||||
|
||||
FABridge.nextBridgeID = 0;
|
||||
FABridge.instances = {};
|
||||
FABridge.idMap = {};
|
||||
FABridge.refCount = 0;
|
||||
|
||||
FABridge.extractBridgeFromID = function(id)
|
||||
{
|
||||
var bridgeID = (id >> 16);
|
||||
return FABridge.idMap[bridgeID];
|
||||
}
|
||||
|
||||
FABridge.attachBridge = function(instance, bridgeName)
|
||||
{
|
||||
var newBridgeInstance = new FABridge(instance, bridgeName);
|
||||
|
||||
FABridge[bridgeName] = newBridgeInstance;
|
||||
|
||||
/* FABridge[bridgeName] = function() {
|
||||
return newBridgeInstance.root();
|
||||
}
|
||||
*/
|
||||
var callbacks = FABridge.initCallbacks[bridgeName];
|
||||
if (callbacks == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < callbacks.length; i++)
|
||||
{
|
||||
callbacks[i].call(newBridgeInstance);
|
||||
}
|
||||
delete FABridge.initCallbacks[bridgeName]
|
||||
}
|
||||
|
||||
// some methods can't be proxied. You can use the explicit get,set, and call methods if necessary.
|
||||
|
||||
FABridge.blockedMethods =
|
||||
{
|
||||
toString: true,
|
||||
get: true,
|
||||
set: true,
|
||||
call: true
|
||||
};
|
||||
|
||||
FABridge.prototype =
|
||||
{
|
||||
|
||||
|
||||
// bootstrapping
|
||||
|
||||
root: function()
|
||||
{
|
||||
return this.deserialize(this.target.getRoot());
|
||||
},
|
||||
//clears all of the AS objects in the cache maps
|
||||
releaseASObjects: function()
|
||||
{
|
||||
return this.target.releaseASObjects();
|
||||
},
|
||||
//clears a specific object in AS from the type maps
|
||||
releaseNamedASObject: function(value)
|
||||
{
|
||||
if(typeof(value) != "object")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ret = this.target.releaseNamedASObject(value.fb_instance_id);
|
||||
return ret;
|
||||
}
|
||||
},
|
||||
//create a new AS Object
|
||||
create: function(className)
|
||||
{
|
||||
return this.deserialize(this.target.create(className));
|
||||
},
|
||||
|
||||
|
||||
// utilities
|
||||
|
||||
makeID: function(token)
|
||||
{
|
||||
return (this.bridgeID << 16) + token;
|
||||
},
|
||||
|
||||
|
||||
// low level access to the flash object
|
||||
|
||||
//get a named property from an AS object
|
||||
getPropertyFromAS: function(objRef, propName)
|
||||
{
|
||||
if (FABridge.refCount > 0)
|
||||
{
|
||||
throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
|
||||
}
|
||||
else
|
||||
{
|
||||
FABridge.refCount++;
|
||||
retVal = this.target.getPropFromAS(objRef, propName);
|
||||
retVal = this.handleError(retVal);
|
||||
FABridge.refCount--;
|
||||
return retVal;
|
||||
}
|
||||
},
|
||||
//set a named property on an AS object
|
||||
setPropertyInAS: function(objRef,propName, value)
|
||||
{
|
||||
if (FABridge.refCount > 0)
|
||||
{
|
||||
throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
|
||||
}
|
||||
else
|
||||
{
|
||||
FABridge.refCount++;
|
||||
retVal = this.target.setPropInAS(objRef,propName, this.serialize(value));
|
||||
retVal = this.handleError(retVal);
|
||||
FABridge.refCount--;
|
||||
return retVal;
|
||||
}
|
||||
},
|
||||
|
||||
//call an AS function
|
||||
callASFunction: function(funcID, args)
|
||||
{
|
||||
if (FABridge.refCount > 0)
|
||||
{
|
||||
throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
|
||||
}
|
||||
else
|
||||
{
|
||||
FABridge.refCount++;
|
||||
retVal = this.target.invokeASFunction(funcID, this.serialize(args));
|
||||
retVal = this.handleError(retVal);
|
||||
FABridge.refCount--;
|
||||
return retVal;
|
||||
}
|
||||
},
|
||||
//call a method on an AS object
|
||||
callASMethod: function(objID, funcName, args)
|
||||
{
|
||||
if (FABridge.refCount > 0)
|
||||
{
|
||||
throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
|
||||
}
|
||||
else
|
||||
{
|
||||
FABridge.refCount++;
|
||||
args = this.serialize(args);
|
||||
retVal = this.target.invokeASMethod(objID, funcName, args);
|
||||
retVal = this.handleError(retVal);
|
||||
FABridge.refCount--;
|
||||
return retVal;
|
||||
}
|
||||
},
|
||||
|
||||
// responders to remote calls from flash
|
||||
|
||||
//callback from flash that executes a local JS function
|
||||
//used mostly when setting js functions as callbacks on events
|
||||
invokeLocalFunction: function(funcID, args)
|
||||
{
|
||||
var result;
|
||||
var func = this.localFunctionCache[funcID];
|
||||
|
||||
if(func != undefined)
|
||||
{
|
||||
result = this.serialize(func.apply(null, this.deserialize(args)));
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
// Object Types and Proxies
|
||||
|
||||
// accepts an object reference, returns a type object matching the obj reference.
|
||||
getTypeFromName: function(objTypeName)
|
||||
{
|
||||
return this.remoteTypeCache[objTypeName];
|
||||
},
|
||||
//create an AS proxy for the given object ID and type
|
||||
createProxy: function(objID, typeName)
|
||||
{
|
||||
var objType = this.getTypeFromName(typeName);
|
||||
instanceFactory.prototype = objType;
|
||||
var instance = new instanceFactory(objID);
|
||||
this.remoteInstanceCache[objID] = instance;
|
||||
return instance;
|
||||
},
|
||||
//return the proxy associated with the given object ID
|
||||
getProxy: function(objID)
|
||||
{
|
||||
return this.remoteInstanceCache[objID];
|
||||
},
|
||||
|
||||
// accepts a type structure, returns a constructed type
|
||||
addTypeDataToCache: function(typeData)
|
||||
{
|
||||
newType = new ASProxy(this, typeData.name);
|
||||
var accessors = typeData.accessors;
|
||||
for (var i = 0; i < accessors.length; i++)
|
||||
{
|
||||
this.addPropertyToType(newType, accessors[i]);
|
||||
}
|
||||
|
||||
var methods = typeData.methods;
|
||||
for (var i = 0; i < methods.length; i++)
|
||||
{
|
||||
if (FABridge.blockedMethods[methods[i]] == undefined)
|
||||
{
|
||||
this.addMethodToType(newType, methods[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.remoteTypeCache[newType.typeName] = newType;
|
||||
return newType;
|
||||
},
|
||||
|
||||
//add a property to a typename; used to define the properties that can be called on an AS proxied object
|
||||
addPropertyToType: function(ty, propName)
|
||||
{
|
||||
var c = propName.charAt(0);
|
||||
var setterName;
|
||||
var getterName;
|
||||
if(c >= "a" && c <= "z")
|
||||
{
|
||||
getterName = "get" + c.toUpperCase() + propName.substr(1);
|
||||
setterName = "set" + c.toUpperCase() + propName.substr(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
getterName = "get" + propName;
|
||||
setterName = "set" + propName;
|
||||
}
|
||||
ty[setterName] = function(val)
|
||||
{
|
||||
this.bridge.setPropertyInAS(this.fb_instance_id, propName, val);
|
||||
}
|
||||
ty[getterName] = function()
|
||||
{
|
||||
return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName));
|
||||
}
|
||||
},
|
||||
|
||||
//add a method to a typename; used to define the methods that can be callefd on an AS proxied object
|
||||
addMethodToType: function(ty, methodName)
|
||||
{
|
||||
ty[methodName] = function()
|
||||
{
|
||||
return this.bridge.deserialize(this.bridge.callASMethod(this.fb_instance_id, methodName, FABridge.argsToArray(arguments)));
|
||||
}
|
||||
},
|
||||
|
||||
// Function Proxies
|
||||
|
||||
//returns the AS proxy for the specified function ID
|
||||
getFunctionProxy: function(funcID)
|
||||
{
|
||||
var bridge = this;
|
||||
if (this.remoteFunctionCache[funcID] == null)
|
||||
{
|
||||
this.remoteFunctionCache[funcID] = function()
|
||||
{
|
||||
bridge.callASFunction(funcID, FABridge.argsToArray(arguments));
|
||||
}
|
||||
}
|
||||
return this.remoteFunctionCache[funcID];
|
||||
},
|
||||
|
||||
//reutrns the ID of the given function; if it doesnt exist it is created and added to the local cache
|
||||
getFunctionID: function(func)
|
||||
{
|
||||
if (func.__bridge_id__ == undefined)
|
||||
{
|
||||
func.__bridge_id__ = this.makeID(this.nextLocalFuncID++);
|
||||
this.localFunctionCache[func.__bridge_id__] = func;
|
||||
}
|
||||
return func.__bridge_id__;
|
||||
},
|
||||
|
||||
// serialization / deserialization
|
||||
|
||||
serialize: function(value)
|
||||
{
|
||||
var result = {};
|
||||
|
||||
var t = typeof(value);
|
||||
//primitives are kept as such
|
||||
if (t == "number" || t == "string" || t == "boolean" || t == null || t == undefined)
|
||||
{
|
||||
result = value;
|
||||
}
|
||||
else if (value instanceof Array)
|
||||
{
|
||||
//arrays are serializesd recursively
|
||||
result = [];
|
||||
for (var i = 0; i < value.length; i++)
|
||||
{
|
||||
result[i] = this.serialize(value[i]);
|
||||
}
|
||||
}
|
||||
else if (t == "function")
|
||||
{
|
||||
//js functions are assigned an ID and stored in the local cache
|
||||
result.type = FABridge.TYPE_JSFUNCTION;
|
||||
result.value = this.getFunctionID(value);
|
||||
}
|
||||
else if (value instanceof ASProxy)
|
||||
{
|
||||
result.type = FABridge.TYPE_ASINSTANCE;
|
||||
result.value = value.fb_instance_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.type = FABridge.TYPE_ANONYMOUS;
|
||||
result.value = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
//on deserialization we always check the return for the specific error code that is used to marshall NPE's into JS errors
|
||||
// the unpacking is done by returning the value on each pachet for objects/arrays
|
||||
deserialize: function(packedValue)
|
||||
{
|
||||
|
||||
var result;
|
||||
|
||||
var t = typeof(packedValue);
|
||||
if (t == "number" || t == "string" || t == "boolean" || packedValue == null || packedValue == undefined)
|
||||
{
|
||||
result = this.handleError(packedValue);
|
||||
}
|
||||
else if (packedValue instanceof Array)
|
||||
{
|
||||
result = [];
|
||||
for (var i = 0; i < packedValue.length; i++)
|
||||
{
|
||||
result[i] = this.deserialize(packedValue[i]);
|
||||
}
|
||||
}
|
||||
else if (t == "object")
|
||||
{
|
||||
for(var i = 0; i < packedValue.newTypes.length; i++)
|
||||
{
|
||||
this.addTypeDataToCache(packedValue.newTypes[i]);
|
||||
}
|
||||
for (var aRefID in packedValue.newRefs)
|
||||
{
|
||||
this.createProxy(aRefID, packedValue.newRefs[aRefID]);
|
||||
}
|
||||
if (packedValue.type == FABridge.TYPE_PRIMITIVE)
|
||||
{
|
||||
result = packedValue.value;
|
||||
}
|
||||
else if (packedValue.type == FABridge.TYPE_ASFUNCTION)
|
||||
{
|
||||
result = this.getFunctionProxy(packedValue.value);
|
||||
}
|
||||
else if (packedValue.type == FABridge.TYPE_ASINSTANCE)
|
||||
{
|
||||
result = this.getProxy(packedValue.value);
|
||||
}
|
||||
else if (packedValue.type == FABridge.TYPE_ANONYMOUS)
|
||||
{
|
||||
result = packedValue.value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
//increases the reference count for the given object
|
||||
addRef: function(obj)
|
||||
{
|
||||
this.target.incRef(obj.fb_instance_id);
|
||||
},
|
||||
//decrease the reference count for the given object and release it if needed
|
||||
release:function(obj)
|
||||
{
|
||||
this.target.releaseRef(obj.fb_instance_id);
|
||||
},
|
||||
|
||||
// check the given value for the components of the hard-coded error code : __FLASHERROR
|
||||
// used to marshall NPE's into flash
|
||||
|
||||
handleError: function(value)
|
||||
{
|
||||
if (typeof(value)=="string" && value.indexOf("__FLASHERROR")==0)
|
||||
{
|
||||
var myErrorMessage = value.split("||");
|
||||
if(FABridge.refCount > 0 )
|
||||
{
|
||||
FABridge.refCount--;
|
||||
}
|
||||
throw new Error(myErrorMessage[1]);
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// The root ASProxy class that facades a flash object
|
||||
|
||||
ASProxy = function(bridge, typeName)
|
||||
{
|
||||
this.bridge = bridge;
|
||||
this.typeName = typeName;
|
||||
return this;
|
||||
};
|
||||
//methods available on each ASProxy object
|
||||
ASProxy.prototype =
|
||||
{
|
||||
get: function(propName)
|
||||
{
|
||||
return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName));
|
||||
},
|
||||
|
||||
set: function(propName, value)
|
||||
{
|
||||
this.bridge.setPropertyInAS(this.fb_instance_id, propName, value);
|
||||
},
|
||||
|
||||
call: function(funcName, args)
|
||||
{
|
||||
this.bridge.callASMethod(this.fb_instance_id, funcName, args);
|
||||
},
|
||||
|
||||
addRef: function() {
|
||||
this.bridge.addRef(this);
|
||||
},
|
||||
|
||||
release: function() {
|
||||
this.bridge.release(this);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user