Update web-socket-js to bb5797cad.
Primary change is removal of FABridge interface. Seems to improve overall latency by perhaps 10%. Also, the slowdown over time in Opera is about half as bad (but still there).
This commit is contained in:
parent
10decacf64
commit
aa868173ea
@ -1,604 +0,0 @@
|
|||||||
/*
|
|
||||||
/*
|
|
||||||
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.userTypes = {};
|
|
||||||
|
|
||||||
FABridge.addToUserTypes = function()
|
|
||||||
{
|
|
||||||
for (var i = 0; i < arguments.length; i++)
|
|
||||||
{
|
|
||||||
FABridge.userTypes[arguments[i]] = {
|
|
||||||
'typeName': arguments[i],
|
|
||||||
'enriched': false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// updated for changes to SWFObject2
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
var 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);
|
|
||||||
}
|
|
||||||
};
|
|
Binary file not shown.
@ -12,8 +12,8 @@
|
|||||||
console = {log: function(){ }, error: function(){ }};
|
console = {log: function(){ }, error: function(){ }};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!swfobject.hasFlashPlayerVersion("9.0.0")) {
|
if (!swfobject.hasFlashPlayerVersion("10.0.0")) {
|
||||||
console.error("Flash Player is not installed.");
|
console.error("Flash Player >= 10.0.0 is required.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (location.protocol == "file:") {
|
if (location.protocol == "file:") {
|
||||||
@ -23,33 +23,38 @@
|
|||||||
"Open the page via Web server i.e. http://...");
|
"Open the page via Web server i.e. http://...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents a faux web socket.
|
||||||
|
* @param {string} url
|
||||||
|
* @param {string} protocol
|
||||||
|
* @param {string} proxyHost
|
||||||
|
* @param {int} proxyPort
|
||||||
|
* @param {string} headers
|
||||||
|
*/
|
||||||
WebSocket = function(url, protocol, proxyHost, proxyPort, headers) {
|
WebSocket = function(url, protocol, proxyHost, proxyPort, headers) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
self.__id = WebSocket.__nextId++;
|
||||||
|
WebSocket.__instances[self.__id] = self;
|
||||||
self.readyState = WebSocket.CONNECTING;
|
self.readyState = WebSocket.CONNECTING;
|
||||||
self.bufferedAmount = 0;
|
self.bufferedAmount = 0;
|
||||||
|
self.__events = {};
|
||||||
// Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
|
// Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
|
||||||
// Otherwise, when onopen fires immediately, onopen is called before it is set.
|
// Otherwise, when onopen fires immediately, onopen is called before it is set.
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
WebSocket.__addTask(function() {
|
WebSocket.__addTask(function() {
|
||||||
self.__createFlash(url, protocol, proxyHost, proxyPort, headers);
|
WebSocket.__flash.create(
|
||||||
|
self.__id, url, protocol, proxyHost || null, proxyPort || 0, headers || null);
|
||||||
});
|
});
|
||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
WebSocket.prototype.__createFlash = function(url, protocol, proxyHost, proxyPort, headers) {
|
|
||||||
var self = this;
|
|
||||||
self.__flash =
|
|
||||||
WebSocket.__flash.create(url, protocol, proxyHost || null, proxyPort || 0, headers || null);
|
|
||||||
self.__flash.addEventListener("event", function(fe) {
|
|
||||||
// Uses setTimeout() to workaround the error:
|
|
||||||
// > You are trying to call recursively into the Flash Player which is not allowed.
|
|
||||||
setTimeout(function() { self.__handleEvents(); }, 0);
|
|
||||||
});
|
|
||||||
//console.log("[WebSocket] Flash object is ready");
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send data to the web socket.
|
||||||
|
* @param {string} data The data to send to the socket.
|
||||||
|
* @return {boolean} True for success, false for failure.
|
||||||
|
*/
|
||||||
WebSocket.prototype.send = function(data) {
|
WebSocket.prototype.send = function(data) {
|
||||||
if (!this.__flash || this.readyState == WebSocket.CONNECTING) {
|
if (this.readyState == WebSocket.CONNECTING) {
|
||||||
throw "INVALID_STATE_ERR: Web Socket connection has not been established";
|
throw "INVALID_STATE_ERR: Web Socket connection has not been established";
|
||||||
}
|
}
|
||||||
// We use encodeURIComponent() here, because FABridge doesn't work if
|
// We use encodeURIComponent() here, because FABridge doesn't work if
|
||||||
@ -58,7 +63,9 @@
|
|||||||
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
|
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
|
||||||
// But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
|
// But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
|
||||||
// preserve all Unicode characters either e.g. "\uffff" in Firefox.
|
// preserve all Unicode characters either e.g. "\uffff" in Firefox.
|
||||||
var result = this.__flash.send(encodeURIComponent(data));
|
// Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require
|
||||||
|
// additional testing.
|
||||||
|
var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
|
||||||
if (result < 0) { // success
|
if (result < 0) { // success
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -67,21 +74,15 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close this web socket gracefully.
|
||||||
|
*/
|
||||||
WebSocket.prototype.close = function() {
|
WebSocket.prototype.close = function() {
|
||||||
var self = this;
|
if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
|
||||||
if (!self.__flash) return;
|
return;
|
||||||
if (self.readyState == WebSocket.CLOSED || self.readyState == WebSocket.CLOSING) return;
|
}
|
||||||
self.__flash.close();
|
this.readyState = WebSocket.CLOSING;
|
||||||
// Sets/calls them manually here because Flash WebSocketConnection.close cannot fire events
|
WebSocket.__flash.close(this.__id);
|
||||||
// which causes weird error:
|
|
||||||
// > You are trying to call recursively into the Flash Player which is not allowed.
|
|
||||||
self.readyState = WebSocket.CLOSED;
|
|
||||||
if (self.__timer) clearInterval(self.__timer);
|
|
||||||
if (self.onclose) {
|
|
||||||
// Make it asynchronous so that it looks more like an actual
|
|
||||||
// close event
|
|
||||||
setTimeout(self.onclose, 0);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,19 +90,12 @@
|
|||||||
*
|
*
|
||||||
* @param {string} type
|
* @param {string} type
|
||||||
* @param {function} listener
|
* @param {function} listener
|
||||||
* @param {boolean} useCapture !NB Not implemented yet
|
* @param {boolean} useCapture
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
|
WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
|
||||||
if (!('__events' in this)) {
|
|
||||||
this.__events = {};
|
|
||||||
}
|
|
||||||
if (!(type in this.__events)) {
|
if (!(type in this.__events)) {
|
||||||
this.__events[type] = [];
|
this.__events[type] = [];
|
||||||
if ('function' == typeof this['on' + type]) {
|
|
||||||
this.__events[type].defaultHandler = this['on' + type];
|
|
||||||
this['on' + type] = this.__createEventHandler(this, type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.__events[type].push(listener);
|
this.__events[type].push(listener);
|
||||||
};
|
};
|
||||||
@ -111,17 +105,15 @@
|
|||||||
*
|
*
|
||||||
* @param {string} type
|
* @param {string} type
|
||||||
* @param {function} listener
|
* @param {function} listener
|
||||||
* @param {boolean} useCapture NB! Not implemented yet
|
* @param {boolean} useCapture
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
|
WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
|
||||||
if (!('__events' in this)) {
|
|
||||||
this.__events = {};
|
|
||||||
}
|
|
||||||
if (!(type in this.__events)) return;
|
if (!(type in this.__events)) return;
|
||||||
for (var i = this.__events.length; i > -1; --i) {
|
var events = this.__events[type];
|
||||||
if (listener === this.__events[type][i]) {
|
for (var i = events.length - 1; i >= 0; --i) {
|
||||||
this.__events[type].splice(i, 1);
|
if (events[i] === listener) {
|
||||||
|
events.splice(i, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,164 +122,93 @@
|
|||||||
/**
|
/**
|
||||||
* Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
|
* Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
|
||||||
*
|
*
|
||||||
* @param {WebSocketEvent} event
|
* @param {Event} event
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
WebSocket.prototype.dispatchEvent = function(event) {
|
WebSocket.prototype.dispatchEvent = function(event) {
|
||||||
if (!('__events' in this)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';
|
var events = this.__events[event.type] || [];
|
||||||
if (!(event.type in this.__events)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';
|
for (var i = 0; i < events.length; ++i) {
|
||||||
|
events[i](event);
|
||||||
for (var i = 0, l = this.__events[event.type].length; i < l; ++ i) {
|
|
||||||
this.__events[event.type][i](event);
|
|
||||||
if (event.cancelBubble) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false !== event.returnValue &&
|
|
||||||
'function' == typeof this.__events[event.type].defaultHandler)
|
|
||||||
{
|
|
||||||
this.__events[event.type].defaultHandler(event);
|
|
||||||
}
|
}
|
||||||
|
var handler = this["on" + event.type];
|
||||||
|
if (handler) handler(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
WebSocket.prototype.__handleEvents = function() {
|
/**
|
||||||
// Gets events using receiveEvents() instead of getting it from event object
|
* Handles an event from Flash.
|
||||||
// of Flash event. This is to make sure to keep message order.
|
* @param {Object} flashEvent
|
||||||
// It seems sometimes Flash events don't arrive in the same order as they are sent.
|
*/
|
||||||
var events = this.__flash.receiveEvents();
|
WebSocket.prototype.__handleEvent = function(flashEvent) {
|
||||||
for (var i = 0; i < events.length; i++) {
|
if ("readyState" in flashEvent) {
|
||||||
try {
|
this.readyState = flashEvent.readyState;
|
||||||
var event = events[i];
|
}
|
||||||
if ("readyState" in event) {
|
|
||||||
this.readyState = event.readyState;
|
var jsEvent;
|
||||||
}
|
if (flashEvent.type == "open" || flashEvent.type == "error") {
|
||||||
if (event.type == "open") {
|
jsEvent = this.__createSimpleEvent(flashEvent.type);
|
||||||
|
} else if (flashEvent.type == "close") {
|
||||||
if (this.__timer) clearInterval(this.__timer);
|
// TODO implement jsEvent.wasClean
|
||||||
if (window.opera) {
|
jsEvent = this.__createSimpleEvent("close");
|
||||||
// Workaround for weird behavior of Opera which sometimes drops events.
|
} else if (flashEvent.type == "message") {
|
||||||
var that = this;
|
var data = decodeURIComponent(flashEvent.message);
|
||||||
this.__timer = setInterval(function () {
|
jsEvent = this.__createMessageEvent("message", data);
|
||||||
that.__handleEvents();
|
} else {
|
||||||
}, 500);
|
throw "unknown event type: " + flashEvent.type;
|
||||||
}
|
}
|
||||||
if (this.onopen) this.onopen();
|
|
||||||
|
this.dispatchEvent(jsEvent);
|
||||||
} else if (event.type == "close") {
|
};
|
||||||
|
|
||||||
if (this.__timer) clearInterval(this.__timer);
|
WebSocket.prototype.__createSimpleEvent = function(type) {
|
||||||
if (this.onclose) this.onclose();
|
if (document.createEvent && window.Event) {
|
||||||
|
var event = document.createEvent("Event");
|
||||||
} else if (event.type == "message") {
|
event.initEvent(type, false, false);
|
||||||
|
return event;
|
||||||
if (this.onmessage) {
|
} else {
|
||||||
var data = decodeURIComponent(event.data);
|
return {type: type, bubbles: false, cancelable: false};
|
||||||
var e;
|
}
|
||||||
if (window.MessageEvent && !window.opera) {
|
};
|
||||||
e = document.createEvent("MessageEvent");
|
|
||||||
e.initMessageEvent("message", false, false, data, null, null, window, null);
|
WebSocket.prototype.__createMessageEvent = function(type, data) {
|
||||||
} else {
|
if (document.createEvent && window.MessageEvent && !window.opera) {
|
||||||
// IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
|
var event = document.createEvent("MessageEvent");
|
||||||
e = {data: data};
|
event.initMessageEvent("message", false, false, data, null, null, window, null);
|
||||||
}
|
return event;
|
||||||
this.onmessage(e);
|
} else {
|
||||||
}
|
// IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
|
||||||
|
return {type: type, data: data, bubbles: false, cancelable: false};
|
||||||
} else if (event.type == "error") {
|
|
||||||
|
|
||||||
if (this.__timer) clearInterval(this.__timer);
|
|
||||||
if (this.onerror) this.onerror();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw "unknown event type: " + event.type;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object} object
|
* Define the WebSocket readyState enumeration.
|
||||||
* @param {string} type
|
|
||||||
*/
|
*/
|
||||||
WebSocket.prototype.__createEventHandler = function(object, type) {
|
|
||||||
return function(data) {
|
|
||||||
var event = new WebSocketEvent();
|
|
||||||
event.initEvent(type, true, true);
|
|
||||||
event.target = event.currentTarget = object;
|
|
||||||
for (var key in data) {
|
|
||||||
event[key] = data[key];
|
|
||||||
}
|
|
||||||
object.dispatchEvent(event, arguments);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface">DOM 2 EventInterface</a>}
|
|
||||||
*
|
|
||||||
* @class
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function WebSocketEvent(){}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type boolean
|
|
||||||
*/
|
|
||||||
WebSocketEvent.prototype.cancelable = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type boolean
|
|
||||||
*/
|
|
||||||
WebSocketEvent.prototype.cancelBubble = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
WebSocketEvent.prototype.preventDefault = function() {
|
|
||||||
if (this.cancelable) {
|
|
||||||
this.returnValue = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
WebSocketEvent.prototype.stopPropagation = function() {
|
|
||||||
this.cancelBubble = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {string} eventTypeArg
|
|
||||||
* @param {boolean} canBubbleArg
|
|
||||||
* @param {boolean} cancelableArg
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
WebSocketEvent.prototype.initEvent = function(eventTypeArg, canBubbleArg, cancelableArg) {
|
|
||||||
this.type = eventTypeArg;
|
|
||||||
this.cancelable = cancelableArg;
|
|
||||||
this.timeStamp = new Date();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
WebSocket.CONNECTING = 0;
|
WebSocket.CONNECTING = 0;
|
||||||
WebSocket.OPEN = 1;
|
WebSocket.OPEN = 1;
|
||||||
WebSocket.CLOSING = 2;
|
WebSocket.CLOSING = 2;
|
||||||
WebSocket.CLOSED = 3;
|
WebSocket.CLOSED = 3;
|
||||||
|
|
||||||
|
WebSocket.__flash = null;
|
||||||
|
WebSocket.__instances = {};
|
||||||
WebSocket.__tasks = [];
|
WebSocket.__tasks = [];
|
||||||
|
WebSocket.__nextId = 0;
|
||||||
WebSocket.loadFlashPolicyFile = function(url) {
|
|
||||||
|
/**
|
||||||
|
* Load a new flash security policy file.
|
||||||
|
* @param {string} url
|
||||||
|
*/
|
||||||
|
WebSocket.loadFlashPolicyFile = function(url){
|
||||||
WebSocket.__addTask(function() {
|
WebSocket.__addTask(function() {
|
||||||
WebSocket.__flash.loadManualPolicyFile(url);
|
WebSocket.__flash.loadManualPolicyFile(url);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
|
||||||
|
*/
|
||||||
WebSocket.__initialize = function() {
|
WebSocket.__initialize = function() {
|
||||||
|
if (WebSocket.__flash) return;
|
||||||
|
|
||||||
if (WebSocket.__swfLocation) {
|
if (WebSocket.__swfLocation) {
|
||||||
// For backword compatibility.
|
// For backword compatibility.
|
||||||
window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
|
window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
|
||||||
@ -318,29 +239,70 @@
|
|||||||
// See this article for hasPriority:
|
// See this article for hasPriority:
|
||||||
// http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
|
// http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
|
||||||
swfobject.embedSWF(
|
swfobject.embedSWF(
|
||||||
WEB_SOCKET_SWF_LOCATION, "webSocketFlash",
|
WEB_SOCKET_SWF_LOCATION,
|
||||||
"1" /* width */, "1" /* height */, "9.0.0" /* SWF version */,
|
"webSocketFlash",
|
||||||
null, {bridgeName: "webSocket"}, {hasPriority: true, allowScriptAccess: "always"}, null,
|
"1" /* width */,
|
||||||
|
"1" /* height */,
|
||||||
|
"10.0.0" /* SWF version */,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
{hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
|
||||||
|
null,
|
||||||
function(e) {
|
function(e) {
|
||||||
if (!e.success) console.error("[WebSocket] swfobject.embedSWF failed");
|
if (!e.success) {
|
||||||
}
|
console.error("[WebSocket] swfobject.embedSWF failed");
|
||||||
);
|
|
||||||
FABridge.addInitializationCallback("webSocket", function() {
|
|
||||||
try {
|
|
||||||
//console.log("[WebSocket] FABridge initializad");
|
|
||||||
WebSocket.__flash = FABridge.webSocket.root();
|
|
||||||
WebSocket.__flash.setCallerUrl(location.href);
|
|
||||||
WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
|
|
||||||
for (var i = 0; i < WebSocket.__tasks.length; ++i) {
|
|
||||||
WebSocket.__tasks[i]();
|
|
||||||
}
|
}
|
||||||
WebSocket.__tasks = [];
|
});
|
||||||
} catch (e) {
|
|
||||||
console.error("[WebSocket] " + e.toString());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by Flash to notify JS that it's fully loaded and ready
|
||||||
|
* for communication.
|
||||||
|
*/
|
||||||
|
WebSocket.__onFlashInitialized = function() {
|
||||||
|
// We need to set a timeout here to avoid round-trip calls
|
||||||
|
// to flash during the initialization process.
|
||||||
|
setTimeout(function() {
|
||||||
|
WebSocket.__flash = document.getElementById("webSocketFlash");
|
||||||
|
WebSocket.__flash.setCallerUrl(location.href);
|
||||||
|
WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
|
||||||
|
for (var i = 0; i < WebSocket.__tasks.length; ++i) {
|
||||||
|
WebSocket.__tasks[i]();
|
||||||
|
}
|
||||||
|
WebSocket.__tasks = [];
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by Flash to notify WebSockets events are fired.
|
||||||
|
*/
|
||||||
|
WebSocket.__onFlashEvent = function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
try {
|
||||||
|
// Gets events using receiveEvents() instead of getting it from event object
|
||||||
|
// of Flash event. This is to make sure to keep message order.
|
||||||
|
// It seems sometimes Flash events don't arrive in the same order as they are sent.
|
||||||
|
var events = WebSocket.__flash.receiveEvents();
|
||||||
|
for (var i = 0; i < events.length; ++i) {
|
||||||
|
WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Called by Flash.
|
||||||
|
WebSocket.__log = function(message) {
|
||||||
|
console.log(decodeURIComponent(message));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Called by Flash.
|
||||||
|
WebSocket.__error = function(message) {
|
||||||
|
console.error(decodeURIComponent(message));
|
||||||
|
};
|
||||||
|
|
||||||
WebSocket.__addTask = function(task) {
|
WebSocket.__addTask = function(task) {
|
||||||
if (WebSocket.__flash) {
|
if (WebSocket.__flash) {
|
||||||
task();
|
task();
|
||||||
@ -349,28 +311,30 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if the browser is running flash lite.
|
||||||
|
* @return {boolean} True if flash lite is running, false otherwise.
|
||||||
|
*/
|
||||||
WebSocket.__isFlashLite = function() {
|
WebSocket.__isFlashLite = function() {
|
||||||
if (!window.navigator || !window.navigator.mimeTypes) return false;
|
if (!window.navigator || !window.navigator.mimeTypes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
|
var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
|
||||||
if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) return false;
|
if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
|
return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// called from Flash
|
|
||||||
window.webSocketLog = function(message) {
|
|
||||||
console.log(decodeURIComponent(message));
|
|
||||||
};
|
|
||||||
|
|
||||||
// called from Flash
|
|
||||||
window.webSocketError = function(message) {
|
|
||||||
console.error(decodeURIComponent(message));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
|
if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
|
||||||
if (window.addEventListener) {
|
if (window.addEventListener) {
|
||||||
window.addEventListener("load", WebSocket.__initialize, false);
|
window.addEventListener("load", function(){
|
||||||
|
WebSocket.__initialize();
|
||||||
|
}, false);
|
||||||
} else {
|
} else {
|
||||||
window.attachEvent("onload", WebSocket.__initialize);
|
window.attachEvent("onload", function(){
|
||||||
|
WebSocket.__initialize();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@ if (window.WebSocket) {
|
|||||||
WEB_SOCKET_SWF_LOCATION += "?" + Math.random();
|
WEB_SOCKET_SWF_LOCATION += "?" + Math.random();
|
||||||
}
|
}
|
||||||
extra += start + "web-socket-js/swfobject.js" + end;
|
extra += start + "web-socket-js/swfobject.js" + end;
|
||||||
extra += start + "web-socket-js/FABridge.js" + end;
|
|
||||||
extra += start + "web-socket-js/web_socket.js" + end;
|
extra += start + "web-socket-js/web_socket.js" + end;
|
||||||
document.write(extra);
|
document.write(extra);
|
||||||
}());
|
}());
|
||||||
|
Loading…
Reference in New Issue
Block a user