socky-client-rails 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/assets/socky.js ADDED
@@ -0,0 +1,1122 @@
1
+ /**
2
+ * Socky push-server JavaScript client
3
+ *
4
+ * @version 0.4.0
5
+ * @author Bernard Potocki <bernard.potocki@imanel.org>
6
+ * @license The MIT license.
7
+ * @source http://github.com/socky/socky-js
8
+ *
9
+ */
10
+
11
+ // Set URL of your WebSocketMain.swf here:
12
+ WEB_SOCKET_SWF_LOCATION = "/javascripts/socky/WebSocketMain.swf";
13
+ // Set this to dump debug message from Flash to console.log:
14
+ WEB_SOCKET_DEBUG = false;
15
+
16
+ Socky = function(host, port, params) {
17
+ this.host = host;
18
+ this.port = port;
19
+ this.params = params;
20
+ this.connect();
21
+ };
22
+
23
+ // Socky states
24
+ Socky.CONNECTING = 0;
25
+ Socky.AUTHENTICATING = 1;
26
+ Socky.OPEN = 2;
27
+ Socky.CLOSED = 3;
28
+ Socky.UNAUTHENTICATED = 4;
29
+
30
+ Socky.prototype.connect = function() {
31
+ var instance = this;
32
+ instance.state = Socky.CONNECTING;
33
+
34
+ var ws = new WebSocket(this.host + ':' + this.port + '/?' + this.params);
35
+ ws.onopen = function() { instance.onopen(); };
36
+ ws.onmessage = function(evt) { instance.onmessage(evt); };
37
+ ws.onclose = function() { instance.onclose(); };
38
+ ws.onerror = function() { instance.onerror(); };
39
+ };
40
+
41
+
42
+
43
+ // ***** Private methods *****
44
+ // Try to avoid any modification of these methods
45
+ // Modification of these methods may cause script to work invalid
46
+ // Please see 'public methods' below
47
+ // ***************************
48
+
49
+ // Called when connection is opened
50
+ Socky.prototype.onopen = function() {
51
+ this.state = Socky.AUTHENTICATING;
52
+ this.respond_to_connect();
53
+ };
54
+
55
+ // Called when socket message is received
56
+ Socky.prototype.onmessage = function(evt) {
57
+ try {
58
+ var request = JSON.parse(evt.data);
59
+ switch (request.type) {
60
+ case "message":
61
+ this.respond_to_message(request.body);
62
+ break;
63
+ case "authentication":
64
+ if(request.body == "success") {
65
+ this.state = Socky.OPEN;
66
+ this.respond_to_authentication_success();
67
+ } else {
68
+ this.state = Socky.UNAUTHENTICATED;
69
+ this.respond_to_authentication_failure();
70
+ }
71
+ break;
72
+ }
73
+ } catch (e) {
74
+ console.error(e.toString());
75
+ }
76
+ };
77
+
78
+ // Called when socket connection is closed
79
+ Socky.prototype.onclose = function() {
80
+ if(this.state != Socky.CLOSED && this.state != Socky.UNAUTHENTICATED) {
81
+ this.respond_to_disconnect();
82
+ }
83
+ };
84
+
85
+ // Called when error occurs
86
+ // Currently unused
87
+ Socky.prototype.onerror = function() {};
88
+
89
+
90
+
91
+ // ***** Public methods *****
92
+ // These methods can be freely modified.
93
+ // The change should not affect the normal operation of the script.
94
+ // **************************
95
+
96
+ // Called after connection but before authentication confirmation is received
97
+ // At this point user is still not allowed to receive messages
98
+ Socky.prototype.respond_to_connect = function() {
99
+ };
100
+
101
+ // Called when authentication confirmation is received.
102
+ // At this point user will be able to receive messages
103
+ Socky.prototype.respond_to_authentication_success = function() {
104
+ };
105
+
106
+ // Called when authentication is rejected by server
107
+ // This usually means that secret is invalid or that authentication server is unavailable
108
+ // This method will NOT be called if connection with Socky server will be broken - see respond_to_disconnect
109
+ Socky.prototype.respond_to_authentication_failure = function() {
110
+ };
111
+
112
+ // Called when new message is received
113
+ // Note that msg is not sanitized - it can be any script received.
114
+ Socky.prototype.respond_to_message = function(msg) {
115
+ eval(msg);
116
+ };
117
+
118
+ // Called when connection is broken between client and server
119
+ // This usually happens when user lost his connection or when Socky server is down.
120
+ // At default it will try to reconnect after 1 second.
121
+ Socky.prototype.respond_to_disconnect = function() {
122
+ var instance = this;
123
+ setTimeout(function() { instance.connect(); }, 1000);
124
+ }
125
+ /* SWFObject v2.2 <http://code.google.com/p/swfobject/>
126
+ is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
127
+ */
128
+ var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener("load",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener("load",Y,false)}else{if(typeof O.attachEvent!=D){i(O,"onload",Y)}else{if(typeof O.onload=="function"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName("body")[0];var aa=C(r);aa.setAttribute("type",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable("$version");if(ab){ab=ab.split(" ")[1].split(",");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute("name").toLowerCase()!="movie"){ah[X[ad].getAttribute("name")]=X[ad].getAttribute("value")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName=="OBJECT"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F("6.0.65")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName=="OBJECT"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width="310"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height="137"}j.title=j.title.slice(0,47)+" - Flash Player Installation";var ad=M.ie&&M.win?"ActiveX":"PlugIn",ac="MMredirectURL="+O.location.toString().replace(/&/g,"%26")+"&MMplayerType="+ad+"&MMdoctitle="+j.title;if(typeof ab.flashvars!=D){ab.flashvars+="&"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C("div");X+="SWFObjectNew";Y.setAttribute("id",X);ae.parentNode.insertBefore(Y,ae);ae.style.display="none";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C("div");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display="none";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C("div");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName=="PARAM")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah="";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()=="data"){ag.movie=ai[ae]}else{if(ae.toLowerCase()=="styleclass"){ah+=' class="'+ai[ae]+'"'}else{if(ae.toLowerCase()!="classid"){ah+=" "+ae+'="'+ai[ae]+'"'}}}}}var af="";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name="'+ad+'" value="'+ag[ad]+'" />'}}aa.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+ah+">"+af+"</object>";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+="";ag+="";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+="&"+ai+"="+Z[ai]}else{am.flashvars=ai+"="+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\?/.test(Z)){Z=Z.split("?")[1]}if(aa==null){return L(Z)}var Y=Z.split("&");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf("="))==aa){return L(Y[X].substring((Y[X].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display="block"}}if(E){E(B)}}a=false}}}}();
129
+ /*
130
+ /*
131
+ Copyright 2006 Adobe Systems Incorporated
132
+
133
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
134
+ to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
135
+ 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:
136
+
137
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
138
+
139
+
140
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
141
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
142
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
143
+ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
144
+
145
+ */
146
+
147
+
148
+ /*
149
+ * The Bridge class, responsible for navigating AS instances
150
+ */
151
+ function FABridge(target,bridgeName)
152
+ {
153
+ this.target = target;
154
+ this.remoteTypeCache = {};
155
+ this.remoteInstanceCache = {};
156
+ this.remoteFunctionCache = {};
157
+ this.localFunctionCache = {};
158
+ this.bridgeID = FABridge.nextBridgeID++;
159
+ this.name = bridgeName;
160
+ this.nextLocalFuncID = 0;
161
+ FABridge.instances[this.name] = this;
162
+ FABridge.idMap[this.bridgeID] = this;
163
+
164
+ return this;
165
+ }
166
+
167
+ // type codes for packed values
168
+ FABridge.TYPE_ASINSTANCE = 1;
169
+ FABridge.TYPE_ASFUNCTION = 2;
170
+
171
+ FABridge.TYPE_JSFUNCTION = 3;
172
+ FABridge.TYPE_ANONYMOUS = 4;
173
+
174
+ FABridge.initCallbacks = {};
175
+ FABridge.userTypes = {};
176
+
177
+ FABridge.addToUserTypes = function()
178
+ {
179
+ for (var i = 0; i < arguments.length; i++)
180
+ {
181
+ FABridge.userTypes[arguments[i]] = {
182
+ 'typeName': arguments[i],
183
+ 'enriched': false
184
+ };
185
+ }
186
+ }
187
+
188
+ FABridge.argsToArray = function(args)
189
+ {
190
+ var result = [];
191
+ for (var i = 0; i < args.length; i++)
192
+ {
193
+ result[i] = args[i];
194
+ }
195
+ return result;
196
+ }
197
+
198
+ function instanceFactory(objID)
199
+ {
200
+ this.fb_instance_id = objID;
201
+ return this;
202
+ }
203
+
204
+ function FABridge__invokeJSFunction(args)
205
+ {
206
+ var funcID = args[0];
207
+ var throughArgs = args.concat();//FABridge.argsToArray(arguments);
208
+ throughArgs.shift();
209
+
210
+ var bridge = FABridge.extractBridgeFromID(funcID);
211
+ return bridge.invokeLocalFunction(funcID, throughArgs);
212
+ }
213
+
214
+ FABridge.addInitializationCallback = function(bridgeName, callback)
215
+ {
216
+ var inst = FABridge.instances[bridgeName];
217
+ if (inst != undefined)
218
+ {
219
+ callback.call(inst);
220
+ return;
221
+ }
222
+
223
+ var callbackList = FABridge.initCallbacks[bridgeName];
224
+ if(callbackList == null)
225
+ {
226
+ FABridge.initCallbacks[bridgeName] = callbackList = [];
227
+ }
228
+
229
+ callbackList.push(callback);
230
+ }
231
+
232
+ // updated for changes to SWFObject2
233
+ function FABridge__bridgeInitialized(bridgeName) {
234
+ var objects = document.getElementsByTagName("object");
235
+ var ol = objects.length;
236
+ var activeObjects = [];
237
+ if (ol > 0) {
238
+ for (var i = 0; i < ol; i++) {
239
+ if (typeof objects[i].SetVariable != "undefined") {
240
+ activeObjects[activeObjects.length] = objects[i];
241
+ }
242
+ }
243
+ }
244
+ var embeds = document.getElementsByTagName("embed");
245
+ var el = embeds.length;
246
+ var activeEmbeds = [];
247
+ if (el > 0) {
248
+ for (var j = 0; j < el; j++) {
249
+ if (typeof embeds[j].SetVariable != "undefined") {
250
+ activeEmbeds[activeEmbeds.length] = embeds[j];
251
+ }
252
+ }
253
+ }
254
+ var aol = activeObjects.length;
255
+ var ael = activeEmbeds.length;
256
+ var searchStr = "bridgeName="+ bridgeName;
257
+ if ((aol == 1 && !ael) || (aol == 1 && ael == 1)) {
258
+ FABridge.attachBridge(activeObjects[0], bridgeName);
259
+ }
260
+ else if (ael == 1 && !aol) {
261
+ FABridge.attachBridge(activeEmbeds[0], bridgeName);
262
+ }
263
+ else {
264
+ var flash_found = false;
265
+ if (aol > 1) {
266
+ for (var k = 0; k < aol; k++) {
267
+ var params = activeObjects[k].childNodes;
268
+ for (var l = 0; l < params.length; l++) {
269
+ var param = params[l];
270
+ if (param.nodeType == 1 && param.tagName.toLowerCase() == "param" && param["name"].toLowerCase() == "flashvars" && param["value"].indexOf(searchStr) >= 0) {
271
+ FABridge.attachBridge(activeObjects[k], bridgeName);
272
+ flash_found = true;
273
+ break;
274
+ }
275
+ }
276
+ if (flash_found) {
277
+ break;
278
+ }
279
+ }
280
+ }
281
+ if (!flash_found && ael > 1) {
282
+ for (var m = 0; m < ael; m++) {
283
+ var flashVars = activeEmbeds[m].attributes.getNamedItem("flashVars").nodeValue;
284
+ if (flashVars.indexOf(searchStr) >= 0) {
285
+ FABridge.attachBridge(activeEmbeds[m], bridgeName);
286
+ break;
287
+ }
288
+ }
289
+ }
290
+ }
291
+ return true;
292
+ }
293
+
294
+ // used to track multiple bridge instances, since callbacks from AS are global across the page.
295
+
296
+ FABridge.nextBridgeID = 0;
297
+ FABridge.instances = {};
298
+ FABridge.idMap = {};
299
+ FABridge.refCount = 0;
300
+
301
+ FABridge.extractBridgeFromID = function(id)
302
+ {
303
+ var bridgeID = (id >> 16);
304
+ return FABridge.idMap[bridgeID];
305
+ }
306
+
307
+ FABridge.attachBridge = function(instance, bridgeName)
308
+ {
309
+ var newBridgeInstance = new FABridge(instance, bridgeName);
310
+
311
+ FABridge[bridgeName] = newBridgeInstance;
312
+
313
+ /* FABridge[bridgeName] = function() {
314
+ return newBridgeInstance.root();
315
+ }
316
+ */
317
+ var callbacks = FABridge.initCallbacks[bridgeName];
318
+ if (callbacks == null)
319
+ {
320
+ return;
321
+ }
322
+ for (var i = 0; i < callbacks.length; i++)
323
+ {
324
+ callbacks[i].call(newBridgeInstance);
325
+ }
326
+ delete FABridge.initCallbacks[bridgeName]
327
+ }
328
+
329
+ // some methods can't be proxied. You can use the explicit get,set, and call methods if necessary.
330
+
331
+ FABridge.blockedMethods =
332
+ {
333
+ toString: true,
334
+ get: true,
335
+ set: true,
336
+ call: true
337
+ };
338
+
339
+ FABridge.prototype =
340
+ {
341
+
342
+
343
+ // bootstrapping
344
+
345
+ root: function()
346
+ {
347
+ return this.deserialize(this.target.getRoot());
348
+ },
349
+ //clears all of the AS objects in the cache maps
350
+ releaseASObjects: function()
351
+ {
352
+ return this.target.releaseASObjects();
353
+ },
354
+ //clears a specific object in AS from the type maps
355
+ releaseNamedASObject: function(value)
356
+ {
357
+ if(typeof(value) != "object")
358
+ {
359
+ return false;
360
+ }
361
+ else
362
+ {
363
+ var ret = this.target.releaseNamedASObject(value.fb_instance_id);
364
+ return ret;
365
+ }
366
+ },
367
+ //create a new AS Object
368
+ create: function(className)
369
+ {
370
+ return this.deserialize(this.target.create(className));
371
+ },
372
+
373
+
374
+ // utilities
375
+
376
+ makeID: function(token)
377
+ {
378
+ return (this.bridgeID << 16) + token;
379
+ },
380
+
381
+
382
+ // low level access to the flash object
383
+
384
+ //get a named property from an AS object
385
+ getPropertyFromAS: function(objRef, propName)
386
+ {
387
+ if (FABridge.refCount > 0)
388
+ {
389
+ 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.");
390
+ }
391
+ else
392
+ {
393
+ FABridge.refCount++;
394
+ retVal = this.target.getPropFromAS(objRef, propName);
395
+ retVal = this.handleError(retVal);
396
+ FABridge.refCount--;
397
+ return retVal;
398
+ }
399
+ },
400
+ //set a named property on an AS object
401
+ setPropertyInAS: function(objRef,propName, value)
402
+ {
403
+ if (FABridge.refCount > 0)
404
+ {
405
+ 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.");
406
+ }
407
+ else
408
+ {
409
+ FABridge.refCount++;
410
+ retVal = this.target.setPropInAS(objRef,propName, this.serialize(value));
411
+ retVal = this.handleError(retVal);
412
+ FABridge.refCount--;
413
+ return retVal;
414
+ }
415
+ },
416
+
417
+ //call an AS function
418
+ callASFunction: function(funcID, args)
419
+ {
420
+ if (FABridge.refCount > 0)
421
+ {
422
+ 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.");
423
+ }
424
+ else
425
+ {
426
+ FABridge.refCount++;
427
+ retVal = this.target.invokeASFunction(funcID, this.serialize(args));
428
+ retVal = this.handleError(retVal);
429
+ FABridge.refCount--;
430
+ return retVal;
431
+ }
432
+ },
433
+ //call a method on an AS object
434
+ callASMethod: function(objID, funcName, args)
435
+ {
436
+ if (FABridge.refCount > 0)
437
+ {
438
+ 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.");
439
+ }
440
+ else
441
+ {
442
+ FABridge.refCount++;
443
+ args = this.serialize(args);
444
+ retVal = this.target.invokeASMethod(objID, funcName, args);
445
+ retVal = this.handleError(retVal);
446
+ FABridge.refCount--;
447
+ return retVal;
448
+ }
449
+ },
450
+
451
+ // responders to remote calls from flash
452
+
453
+ //callback from flash that executes a local JS function
454
+ //used mostly when setting js functions as callbacks on events
455
+ invokeLocalFunction: function(funcID, args)
456
+ {
457
+ var result;
458
+ var func = this.localFunctionCache[funcID];
459
+
460
+ if(func != undefined)
461
+ {
462
+ result = this.serialize(func.apply(null, this.deserialize(args)));
463
+ }
464
+
465
+ return result;
466
+ },
467
+
468
+ // Object Types and Proxies
469
+
470
+ // accepts an object reference, returns a type object matching the obj reference.
471
+ getTypeFromName: function(objTypeName)
472
+ {
473
+ return this.remoteTypeCache[objTypeName];
474
+ },
475
+ //create an AS proxy for the given object ID and type
476
+ createProxy: function(objID, typeName)
477
+ {
478
+ var objType = this.getTypeFromName(typeName);
479
+ instanceFactory.prototype = objType;
480
+ var instance = new instanceFactory(objID);
481
+ this.remoteInstanceCache[objID] = instance;
482
+ return instance;
483
+ },
484
+ //return the proxy associated with the given object ID
485
+ getProxy: function(objID)
486
+ {
487
+ return this.remoteInstanceCache[objID];
488
+ },
489
+
490
+ // accepts a type structure, returns a constructed type
491
+ addTypeDataToCache: function(typeData)
492
+ {
493
+ var newType = new ASProxy(this, typeData.name);
494
+ var accessors = typeData.accessors;
495
+ for (var i = 0; i < accessors.length; i++)
496
+ {
497
+ this.addPropertyToType(newType, accessors[i]);
498
+ }
499
+
500
+ var methods = typeData.methods;
501
+ for (var i = 0; i < methods.length; i++)
502
+ {
503
+ if (FABridge.blockedMethods[methods[i]] == undefined)
504
+ {
505
+ this.addMethodToType(newType, methods[i]);
506
+ }
507
+ }
508
+
509
+
510
+ this.remoteTypeCache[newType.typeName] = newType;
511
+ return newType;
512
+ },
513
+
514
+ //add a property to a typename; used to define the properties that can be called on an AS proxied object
515
+ addPropertyToType: function(ty, propName)
516
+ {
517
+ var c = propName.charAt(0);
518
+ var setterName;
519
+ var getterName;
520
+ if(c >= "a" && c <= "z")
521
+ {
522
+ getterName = "get" + c.toUpperCase() + propName.substr(1);
523
+ setterName = "set" + c.toUpperCase() + propName.substr(1);
524
+ }
525
+ else
526
+ {
527
+ getterName = "get" + propName;
528
+ setterName = "set" + propName;
529
+ }
530
+ ty[setterName] = function(val)
531
+ {
532
+ this.bridge.setPropertyInAS(this.fb_instance_id, propName, val);
533
+ }
534
+ ty[getterName] = function()
535
+ {
536
+ return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName));
537
+ }
538
+ },
539
+
540
+ //add a method to a typename; used to define the methods that can be callefd on an AS proxied object
541
+ addMethodToType: function(ty, methodName)
542
+ {
543
+ ty[methodName] = function()
544
+ {
545
+ return this.bridge.deserialize(this.bridge.callASMethod(this.fb_instance_id, methodName, FABridge.argsToArray(arguments)));
546
+ }
547
+ },
548
+
549
+ // Function Proxies
550
+
551
+ //returns the AS proxy for the specified function ID
552
+ getFunctionProxy: function(funcID)
553
+ {
554
+ var bridge = this;
555
+ if (this.remoteFunctionCache[funcID] == null)
556
+ {
557
+ this.remoteFunctionCache[funcID] = function()
558
+ {
559
+ bridge.callASFunction(funcID, FABridge.argsToArray(arguments));
560
+ }
561
+ }
562
+ return this.remoteFunctionCache[funcID];
563
+ },
564
+
565
+ //reutrns the ID of the given function; if it doesnt exist it is created and added to the local cache
566
+ getFunctionID: function(func)
567
+ {
568
+ if (func.__bridge_id__ == undefined)
569
+ {
570
+ func.__bridge_id__ = this.makeID(this.nextLocalFuncID++);
571
+ this.localFunctionCache[func.__bridge_id__] = func;
572
+ }
573
+ return func.__bridge_id__;
574
+ },
575
+
576
+ // serialization / deserialization
577
+
578
+ serialize: function(value)
579
+ {
580
+ var result = {};
581
+
582
+ var t = typeof(value);
583
+ //primitives are kept as such
584
+ if (t == "number" || t == "string" || t == "boolean" || t == null || t == undefined)
585
+ {
586
+ result = value;
587
+ }
588
+ else if (value instanceof Array)
589
+ {
590
+ //arrays are serializesd recursively
591
+ result = [];
592
+ for (var i = 0; i < value.length; i++)
593
+ {
594
+ result[i] = this.serialize(value[i]);
595
+ }
596
+ }
597
+ else if (t == "function")
598
+ {
599
+ //js functions are assigned an ID and stored in the local cache
600
+ result.type = FABridge.TYPE_JSFUNCTION;
601
+ result.value = this.getFunctionID(value);
602
+ }
603
+ else if (value instanceof ASProxy)
604
+ {
605
+ result.type = FABridge.TYPE_ASINSTANCE;
606
+ result.value = value.fb_instance_id;
607
+ }
608
+ else
609
+ {
610
+ result.type = FABridge.TYPE_ANONYMOUS;
611
+ result.value = value;
612
+ }
613
+
614
+ return result;
615
+ },
616
+
617
+ //on deserialization we always check the return for the specific error code that is used to marshall NPE's into JS errors
618
+ // the unpacking is done by returning the value on each pachet for objects/arrays
619
+ deserialize: function(packedValue)
620
+ {
621
+
622
+ var result;
623
+
624
+ var t = typeof(packedValue);
625
+ if (t == "number" || t == "string" || t == "boolean" || packedValue == null || packedValue == undefined)
626
+ {
627
+ result = this.handleError(packedValue);
628
+ }
629
+ else if (packedValue instanceof Array)
630
+ {
631
+ result = [];
632
+ for (var i = 0; i < packedValue.length; i++)
633
+ {
634
+ result[i] = this.deserialize(packedValue[i]);
635
+ }
636
+ }
637
+ else if (t == "object")
638
+ {
639
+ for(var i = 0; i < packedValue.newTypes.length; i++)
640
+ {
641
+ this.addTypeDataToCache(packedValue.newTypes[i]);
642
+ }
643
+ for (var aRefID in packedValue.newRefs)
644
+ {
645
+ this.createProxy(aRefID, packedValue.newRefs[aRefID]);
646
+ }
647
+ if (packedValue.type == FABridge.TYPE_PRIMITIVE)
648
+ {
649
+ result = packedValue.value;
650
+ }
651
+ else if (packedValue.type == FABridge.TYPE_ASFUNCTION)
652
+ {
653
+ result = this.getFunctionProxy(packedValue.value);
654
+ }
655
+ else if (packedValue.type == FABridge.TYPE_ASINSTANCE)
656
+ {
657
+ result = this.getProxy(packedValue.value);
658
+ }
659
+ else if (packedValue.type == FABridge.TYPE_ANONYMOUS)
660
+ {
661
+ result = packedValue.value;
662
+ }
663
+ }
664
+ return result;
665
+ },
666
+ //increases the reference count for the given object
667
+ addRef: function(obj)
668
+ {
669
+ this.target.incRef(obj.fb_instance_id);
670
+ },
671
+ //decrease the reference count for the given object and release it if needed
672
+ release:function(obj)
673
+ {
674
+ this.target.releaseRef(obj.fb_instance_id);
675
+ },
676
+
677
+ // check the given value for the components of the hard-coded error code : __FLASHERROR
678
+ // used to marshall NPE's into flash
679
+
680
+ handleError: function(value)
681
+ {
682
+ if (typeof(value)=="string" && value.indexOf("__FLASHERROR")==0)
683
+ {
684
+ var myErrorMessage = value.split("||");
685
+ if(FABridge.refCount > 0 )
686
+ {
687
+ FABridge.refCount--;
688
+ }
689
+ throw new Error(myErrorMessage[1]);
690
+ return value;
691
+ }
692
+ else
693
+ {
694
+ return value;
695
+ }
696
+ }
697
+ };
698
+
699
+ // The root ASProxy class that facades a flash object
700
+
701
+ ASProxy = function(bridge, typeName)
702
+ {
703
+ this.bridge = bridge;
704
+ this.typeName = typeName;
705
+ return this;
706
+ };
707
+ //methods available on each ASProxy object
708
+ ASProxy.prototype =
709
+ {
710
+ get: function(propName)
711
+ {
712
+ return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName));
713
+ },
714
+
715
+ set: function(propName, value)
716
+ {
717
+ this.bridge.setPropertyInAS(this.fb_instance_id, propName, value);
718
+ },
719
+
720
+ call: function(funcName, args)
721
+ {
722
+ this.bridge.callASMethod(this.fb_instance_id, funcName, args);
723
+ },
724
+
725
+ addRef: function() {
726
+ this.bridge.addRef(this);
727
+ },
728
+
729
+ release: function() {
730
+ this.bridge.release(this);
731
+ }
732
+ };
733
+
734
+ // Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
735
+ // License: New BSD License
736
+ // Reference: http://dev.w3.org/html5/websockets/
737
+ // Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
738
+
739
+ (function() {
740
+
741
+ if (window.WebSocket) return;
742
+
743
+ var console = window.console;
744
+ if (!console) console = {log: function(){ }, error: function(){ }};
745
+
746
+ if (!swfobject.hasFlashPlayerVersion("9.0.0")) {
747
+ console.error("Flash Player is not installed.");
748
+ return;
749
+ }
750
+ if (location.protocol == "file:") {
751
+ console.error(
752
+ "WARNING: web-socket-js doesn't work in file:///... URL " +
753
+ "unless you set Flash Security Settings properly. " +
754
+ "Open the page via Web server i.e. http://...");
755
+ }
756
+
757
+ WebSocket = function(url, protocol, proxyHost, proxyPort, headers) {
758
+ var self = this;
759
+ self.readyState = WebSocket.CONNECTING;
760
+ self.bufferedAmount = 0;
761
+ // Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
762
+ // Otherwise, when onopen fires immediately, onopen is called before it is set.
763
+ setTimeout(function() {
764
+ WebSocket.__addTask(function() {
765
+ self.__createFlash(url, protocol, proxyHost, proxyPort, headers);
766
+ });
767
+ }, 1);
768
+ }
769
+
770
+ WebSocket.prototype.__createFlash = function(url, protocol, proxyHost, proxyPort, headers) {
771
+ var self = this;
772
+ self.__flash =
773
+ WebSocket.__flash.create(url, protocol, proxyHost || null, proxyPort || 0, headers || null);
774
+
775
+ self.__flash.addEventListener("open", function(fe) {
776
+ try {
777
+ self.readyState = self.__flash.getReadyState();
778
+ if (self.__timer) clearInterval(self.__timer);
779
+ if (window.opera) {
780
+ // Workaround for weird behavior of Opera which sometimes drops events.
781
+ self.__timer = setInterval(function () {
782
+ self.__handleMessages();
783
+ }, 500);
784
+ }
785
+ if (self.onopen) self.onopen();
786
+ } catch (e) {
787
+ console.error(e.toString());
788
+ }
789
+ });
790
+
791
+ self.__flash.addEventListener("close", function(fe) {
792
+ try {
793
+ self.readyState = self.__flash.getReadyState();
794
+ if (self.__timer) clearInterval(self.__timer);
795
+ if (self.onclose) self.onclose();
796
+ } catch (e) {
797
+ console.error(e.toString());
798
+ }
799
+ });
800
+
801
+ self.__flash.addEventListener("message", function() {
802
+ try {
803
+ self.__handleMessages();
804
+ } catch (e) {
805
+ console.error(e.toString());
806
+ }
807
+ });
808
+
809
+ self.__flash.addEventListener("error", function(fe) {
810
+ try {
811
+ if (self.__timer) clearInterval(self.__timer);
812
+ if (self.onerror) self.onerror();
813
+ } catch (e) {
814
+ console.error(e.toString());
815
+ }
816
+ });
817
+
818
+ self.__flash.addEventListener("stateChange", function(fe) {
819
+ try {
820
+ self.readyState = self.__flash.getReadyState();
821
+ self.bufferedAmount = fe.getBufferedAmount();
822
+ } catch (e) {
823
+ console.error(e.toString());
824
+ }
825
+ });
826
+
827
+ //console.log("[WebSocket] Flash object is ready");
828
+ };
829
+
830
+ WebSocket.prototype.send = function(data) {
831
+ if (this.__flash) {
832
+ this.readyState = this.__flash.getReadyState();
833
+ }
834
+ if (!this.__flash || this.readyState == WebSocket.CONNECTING) {
835
+ throw "INVALID_STATE_ERR: Web Socket connection has not been established";
836
+ }
837
+ // We use encodeURIComponent() here, because FABridge doesn't work if
838
+ // the argument includes some characters. We don't use escape() here
839
+ // because of this:
840
+ // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
841
+ // But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
842
+ // preserve all Unicode characters either e.g. "\uffff" in Firefox.
843
+ var result = this.__flash.send(encodeURIComponent(data));
844
+ if (result < 0) { // success
845
+ return true;
846
+ } else {
847
+ this.bufferedAmount = result;
848
+ return false;
849
+ }
850
+ };
851
+
852
+ WebSocket.prototype.close = function() {
853
+ var self = this;
854
+ if (!self.__flash) return;
855
+ self.readyState = self.__flash.getReadyState();
856
+ if (self.readyState == WebSocket.CLOSED || self.readyState == WebSocket.CLOSING) return;
857
+ self.__flash.close();
858
+ // Sets/calls them manually here because Flash WebSocketConnection.close cannot fire events
859
+ // which causes weird error:
860
+ // > You are trying to call recursively into the Flash Player which is not allowed.
861
+ self.readyState = WebSocket.CLOSED;
862
+ if (self.__timer) clearInterval(self.__timer);
863
+ if (self.onclose) {
864
+ // Make it asynchronous so that it looks more like an actual
865
+ // close event
866
+ setTimeout(self.onclose, 1);
867
+ }
868
+ };
869
+
870
+ /**
871
+ * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
872
+ *
873
+ * @param {string} type
874
+ * @param {function} listener
875
+ * @param {boolean} useCapture !NB Not implemented yet
876
+ * @return void
877
+ */
878
+ WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
879
+ if (!('__events' in this)) {
880
+ this.__events = {};
881
+ }
882
+ if (!(type in this.__events)) {
883
+ this.__events[type] = [];
884
+ if ('function' == typeof this['on' + type]) {
885
+ this.__events[type].defaultHandler = this['on' + type];
886
+ this['on' + type] = this.__createEventHandler(this, type);
887
+ }
888
+ }
889
+ this.__events[type].push(listener);
890
+ };
891
+
892
+ /**
893
+ * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
894
+ *
895
+ * @param {string} type
896
+ * @param {function} listener
897
+ * @param {boolean} useCapture NB! Not implemented yet
898
+ * @return void
899
+ */
900
+ WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
901
+ if (!('__events' in this)) {
902
+ this.__events = {};
903
+ }
904
+ if (!(type in this.__events)) return;
905
+ for (var i = this.__events.length; i > -1; --i) {
906
+ if (listener === this.__events[type][i]) {
907
+ this.__events[type].splice(i, 1);
908
+ break;
909
+ }
910
+ }
911
+ };
912
+
913
+ /**
914
+ * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
915
+ *
916
+ * @param {WebSocketEvent} event
917
+ * @return void
918
+ */
919
+ WebSocket.prototype.dispatchEvent = function(event) {
920
+ if (!('__events' in this)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';
921
+ if (!(event.type in this.__events)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';
922
+
923
+ for (var i = 0, l = this.__events[event.type].length; i < l; ++ i) {
924
+ this.__events[event.type][i](event);
925
+ if (event.cancelBubble) break;
926
+ }
927
+
928
+ if (false !== event.returnValue &&
929
+ 'function' == typeof this.__events[event.type].defaultHandler)
930
+ {
931
+ this.__events[event.type].defaultHandler(event);
932
+ }
933
+ };
934
+
935
+ WebSocket.prototype.__handleMessages = function() {
936
+ // Gets data using readSocketData() instead of getting it from event object
937
+ // of Flash event. This is to make sure to keep message order.
938
+ // It seems sometimes Flash events don't arrive in the same order as they are sent.
939
+ var arr = this.__flash.readSocketData();
940
+ for (var i = 0; i < arr.length; i++) {
941
+ var data = decodeURIComponent(arr[i]);
942
+ try {
943
+ if (this.onmessage) {
944
+ var e;
945
+ if (window.MessageEvent && !window.opera) {
946
+ e = document.createEvent("MessageEvent");
947
+ e.initMessageEvent("message", false, false, data, null, null, window, null);
948
+ } else { // IE and Opera, the latter one truncates the data parameter after any 0x00 bytes
949
+ e = {data: data};
950
+ }
951
+ this.onmessage(e);
952
+ }
953
+ } catch (e) {
954
+ console.error(e.toString());
955
+ }
956
+ }
957
+ };
958
+
959
+ /**
960
+ * @param {object} object
961
+ * @param {string} type
962
+ */
963
+ WebSocket.prototype.__createEventHandler = function(object, type) {
964
+ return function(data) {
965
+ var event = new WebSocketEvent();
966
+ event.initEvent(type, true, true);
967
+ event.target = event.currentTarget = object;
968
+ for (var key in data) {
969
+ event[key] = data[key];
970
+ }
971
+ object.dispatchEvent(event, arguments);
972
+ };
973
+ }
974
+
975
+ /**
976
+ * Basic implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface">DOM 2 EventInterface</a>}
977
+ *
978
+ * @class
979
+ * @constructor
980
+ */
981
+ function WebSocketEvent(){}
982
+
983
+ /**
984
+ *
985
+ * @type boolean
986
+ */
987
+ WebSocketEvent.prototype.cancelable = true;
988
+
989
+ /**
990
+ *
991
+ * @type boolean
992
+ */
993
+ WebSocketEvent.prototype.cancelBubble = false;
994
+
995
+ /**
996
+ *
997
+ * @return void
998
+ */
999
+ WebSocketEvent.prototype.preventDefault = function() {
1000
+ if (this.cancelable) {
1001
+ this.returnValue = false;
1002
+ }
1003
+ };
1004
+
1005
+ /**
1006
+ *
1007
+ * @return void
1008
+ */
1009
+ WebSocketEvent.prototype.stopPropagation = function() {
1010
+ this.cancelBubble = true;
1011
+ };
1012
+
1013
+ /**
1014
+ *
1015
+ * @param {string} eventTypeArg
1016
+ * @param {boolean} canBubbleArg
1017
+ * @param {boolean} cancelableArg
1018
+ * @return void
1019
+ */
1020
+ WebSocketEvent.prototype.initEvent = function(eventTypeArg, canBubbleArg, cancelableArg) {
1021
+ this.type = eventTypeArg;
1022
+ this.cancelable = cancelableArg;
1023
+ this.timeStamp = new Date();
1024
+ };
1025
+
1026
+
1027
+ WebSocket.CONNECTING = 0;
1028
+ WebSocket.OPEN = 1;
1029
+ WebSocket.CLOSING = 2;
1030
+ WebSocket.CLOSED = 3;
1031
+
1032
+ WebSocket.__tasks = [];
1033
+
1034
+ WebSocket.__initialize = function() {
1035
+ if (WebSocket.__swfLocation) {
1036
+ // For backword compatibility.
1037
+ window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
1038
+ }
1039
+ if (!window.WEB_SOCKET_SWF_LOCATION) {
1040
+ console.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
1041
+ return;
1042
+ }
1043
+ var container = document.createElement("div");
1044
+ container.id = "webSocketContainer";
1045
+ // Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
1046
+ // Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
1047
+ // But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
1048
+ // Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
1049
+ // the best we can do as far as we know now.
1050
+ container.style.position = "absolute";
1051
+ if (WebSocket.__isFlashLite()) {
1052
+ container.style.left = "0px";
1053
+ container.style.top = "0px";
1054
+ } else {
1055
+ container.style.left = "-100px";
1056
+ container.style.top = "-100px";
1057
+ }
1058
+ var holder = document.createElement("div");
1059
+ holder.id = "webSocketFlash";
1060
+ container.appendChild(holder);
1061
+ document.body.appendChild(container);
1062
+ // See this article for hasPriority:
1063
+ // http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
1064
+ swfobject.embedSWF(
1065
+ WEB_SOCKET_SWF_LOCATION, "webSocketFlash",
1066
+ "1" /* width */, "1" /* height */, "9.0.0" /* SWF version */,
1067
+ null, {bridgeName: "webSocket"}, {hasPriority: true, allowScriptAccess: "always"}, null,
1068
+ function(e) {
1069
+ if (!e.success) console.error("[WebSocket] swfobject.embedSWF failed");
1070
+ }
1071
+ );
1072
+ FABridge.addInitializationCallback("webSocket", function() {
1073
+ try {
1074
+ //console.log("[WebSocket] FABridge initializad");
1075
+ WebSocket.__flash = FABridge.webSocket.root();
1076
+ WebSocket.__flash.setCallerUrl(location.href);
1077
+ WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
1078
+ for (var i = 0; i < WebSocket.__tasks.length; ++i) {
1079
+ WebSocket.__tasks[i]();
1080
+ }
1081
+ WebSocket.__tasks = [];
1082
+ } catch (e) {
1083
+ console.error("[WebSocket] " + e.toString());
1084
+ }
1085
+ });
1086
+ };
1087
+
1088
+ WebSocket.__addTask = function(task) {
1089
+ if (WebSocket.__flash) {
1090
+ task();
1091
+ } else {
1092
+ WebSocket.__tasks.push(task);
1093
+ }
1094
+ };
1095
+
1096
+ WebSocket.__isFlashLite = function() {
1097
+ if (!window.navigator || !window.navigator.mimeTypes) return false;
1098
+ var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
1099
+ if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) return false;
1100
+ return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
1101
+ };
1102
+
1103
+ // called from Flash
1104
+ window.webSocketLog = function(message) {
1105
+ console.log(decodeURIComponent(message));
1106
+ };
1107
+
1108
+ // called from Flash
1109
+ window.webSocketError = function(message) {
1110
+ console.error(decodeURIComponent(message));
1111
+ };
1112
+
1113
+ if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
1114
+ if (window.addEventListener) {
1115
+ window.addEventListener("load", WebSocket.__initialize, false);
1116
+ } else {
1117
+ window.attachEvent("onload", WebSocket.__initialize);
1118
+ }
1119
+ }
1120
+
1121
+ })();
1122
+