]> git.proxmox.com Git - mirror_novnc.git/blob - include/web-socket-js/web_socket.js
69053a114a1fd5e0ece2c1f3f822a41da9549872
[mirror_novnc.git] / include / web-socket-js / web_socket.js
1 // Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
2 // Lincense: New BSD Lincense
3 // Reference: http://dev.w3.org/html5/websockets/
4 // Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
5
6 (function() {
7
8 if (window.WebSocket) return;
9
10 var console = window.console;
11 if (!console) console = {log: function(){ }, error: function(){ }};
12
13 function hasFlash() {
14 if ('navigator' in window && 'plugins' in navigator && navigator.plugins['Shockwave Flash']) {
15 return !!navigator.plugins['Shockwave Flash'].description;
16 }
17 if ('ActiveXObject' in window) {
18 try {
19 return !!new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
20 } catch (e) {}
21 }
22 return false;
23 }
24
25 if (!hasFlash()) {
26 console.error("Flash Player is not installed.");
27 return;
28 }
29
30 WebSocket = function(url, protocol, proxyHost, proxyPort, headers) {
31 var self = this;
32 self.readyState = WebSocket.CONNECTING;
33 self.bufferedAmount = 0;
34 WebSocket.__addTask(function() {
35 self.__flash =
36 WebSocket.__flash.create(url, protocol, proxyHost || null, proxyPort || 0, headers || null);
37
38 self.__flash.addEventListener("open", function(fe) {
39 try {
40 if (self.onopen) self.onopen();
41 } catch (e) {
42 console.error(e.toString());
43 }
44 });
45
46 self.__flash.addEventListener("close", function(fe) {
47 try {
48 if (self.onclose) self.onclose();
49 } catch (e) {
50 console.error(e.toString());
51 }
52 });
53
54 self.__flash.addEventListener("message", function(fe) {
55 var data = decodeURIComponent(fe.getData());
56 try {
57 if (self.onmessage) {
58 var e;
59 if (window.MessageEvent) {
60 e = document.createEvent("MessageEvent");
61 e.initMessageEvent("message", false, false, data, null, null, window);
62 } else { // IE
63 e = {data: data};
64 }
65 self.onmessage(e);
66 }
67 } catch (e) {
68 console.error(e.toString());
69 }
70 });
71
72 self.__flash.addEventListener("stateChange", function(fe) {
73 try {
74 self.readyState = fe.getReadyState();
75 self.bufferedAmount = fe.getBufferedAmount();
76 } catch (e) {
77 console.error(e.toString());
78 }
79 });
80
81 //console.log("[WebSocket] Flash object is ready");
82 });
83 }
84
85 WebSocket.prototype.send = function(data) {
86 if (!this.__flash || this.readyState == WebSocket.CONNECTING) {
87 throw "INVALID_STATE_ERR: Web Socket connection has not been established";
88 }
89 var result = this.__flash.send(data);
90 if (result < 0) { // success
91 return true;
92 } else {
93 this.bufferedAmount = result;
94 return false;
95 }
96 };
97
98 WebSocket.prototype.close = function() {
99 if (!this.__flash) return;
100 if (this.readyState != WebSocket.OPEN) return;
101 this.__flash.close();
102 // Sets/calls them manually here because Flash WebSocketConnection.close cannot fire events
103 // which causes weird error:
104 // > You are trying to call recursively into the Flash Player which is not allowed.
105 this.readyState = WebSocket.CLOSED;
106 if (this.onclose) this.onclose();
107 };
108
109 /**
110 * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
111 *
112 * @param {string} type
113 * @param {function} listener
114 * @param {boolean} useCapture !NB Not implemented yet
115 * @return void
116 */
117 WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
118 if (!('__events' in this)) {
119 this.__events = {};
120 }
121 if (!(type in this.__events)) {
122 this.__events[type] = [];
123 if ('function' == typeof this['on' + type]) {
124 this.__events[type].defaultHandler = this['on' + type];
125 this['on' + type] = WebSocket_FireEvent(this, type);
126 }
127 }
128 this.__events[type].push(listener);
129 };
130
131 /**
132 * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
133 *
134 * @param {string} type
135 * @param {function} listener
136 * @param {boolean} useCapture NB! Not implemented yet
137 * @return void
138 */
139 WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
140 if (!('__events' in this)) {
141 this.__events = {};
142 }
143 if (!(type in this.__events)) return;
144 for (var i = this.__events.length; i > -1; --i) {
145 if (listener === this.__events[type][i]) {
146 this.__events[type].splice(i, 1);
147 break;
148 }
149 }
150 };
151
152 /**
153 * Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
154 *
155 * @param {WebSocketEvent} event
156 * @return void
157 */
158 WebSocket.prototype.dispatchEvent = function(event) {
159 if (!('__events' in this)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';
160 if (!(event.type in this.__events)) throw 'UNSPECIFIED_EVENT_TYPE_ERR';
161
162 for (var i = 0, l = this.__events[event.type].length; i < l; ++ i) {
163 this.__events[event.type][i](event);
164 if (event.cancelBubble) break;
165 }
166
167 if (false !== event.returnValue &&
168 'function' == typeof this.__events[event.type].defaultHandler)
169 {
170 this.__events[event.type].defaultHandler(event);
171 }
172 };
173
174 /**
175 *
176 * @param {object} object
177 * @param {string} type
178 */
179 function WebSocket_FireEvent(object, type) {
180 return function(data) {
181 var event = new WebSocketEvent();
182 event.initEvent(type, true, true);
183 event.target = event.currentTarget = object;
184 for (var key in data) {
185 event[key] = data[key];
186 }
187 object.dispatchEvent(event, arguments);
188 };
189 }
190
191 /**
192 * Basic implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface">DOM 2 EventInterface</a>}
193 *
194 * @class
195 * @constructor
196 */
197 function WebSocketEvent(){}
198
199 /**
200 *
201 * @type boolean
202 */
203 WebSocketEvent.prototype.cancelable = true;
204
205 /**
206 *
207 * @type boolean
208 */
209 WebSocketEvent.prototype.cancelBubble = false;
210
211 /**
212 *
213 * @return void
214 */
215 WebSocketEvent.prototype.preventDefault = function() {
216 if (this.cancelable) {
217 this.returnValue = false;
218 }
219 };
220
221 /**
222 *
223 * @return void
224 */
225 WebSocketEvent.prototype.stopPropagation = function() {
226 this.cancelBubble = true;
227 };
228
229 /**
230 *
231 * @param {string} eventTypeArg
232 * @param {boolean} canBubbleArg
233 * @param {boolean} cancelableArg
234 * @return void
235 */
236 WebSocketEvent.prototype.initEvent = function(eventTypeArg, canBubbleArg, cancelableArg) {
237 this.type = eventTypeArg;
238 this.cancelable = cancelableArg;
239 this.timeStamp = new Date();
240 };
241
242
243 WebSocket.CONNECTING = 0;
244 WebSocket.OPEN = 1;
245 WebSocket.CLOSED = 2;
246
247 WebSocket.__tasks = [];
248
249 WebSocket.__initialize = function() {
250 if (!WebSocket.__swfLocation) {
251 console.error("[WebSocket] set WebSocket.__swfLocation to location of WebSocketMain.swf");
252 return;
253 }
254 var container = document.createElement("div");
255 container.id = "webSocketContainer";
256 // Puts the Flash out of the window. Note that we cannot use display: none or visibility: hidden
257 // here because it prevents Flash from loading at least in IE.
258 container.style.position = "absolute";
259 container.style.left = "-100px";
260 container.style.top = "-100px";
261 var holder = document.createElement("div");
262 holder.id = "webSocketFlash";
263 container.appendChild(holder);
264 document.body.appendChild(container);
265 swfobject.embedSWF(
266 WebSocket.__swfLocation, "webSocketFlash", "8", "8", "9.0.0",
267 null, {bridgeName: "webSocket"}, null, null,
268 function(e) {
269 if (!e.success) console.error("[WebSocket] swfobject.embedSWF failed");
270 }
271 );
272 FABridge.addInitializationCallback("webSocket", function() {
273 try {
274 //console.log("[WebSocket] FABridge initializad");
275 WebSocket.__flash = FABridge.webSocket.root();
276 WebSocket.__flash.setCallerUrl(location.href);
277 for (var i = 0; i < WebSocket.__tasks.length; ++i) {
278 WebSocket.__tasks[i]();
279 }
280 WebSocket.__tasks = [];
281 } catch (e) {
282 console.error("[WebSocket] " + e.toString());
283 }
284 });
285 };
286
287 WebSocket.__addTask = function(task) {
288 if (WebSocket.__flash) {
289 task();
290 } else {
291 WebSocket.__tasks.push(task);
292 }
293 }
294
295 // called from Flash
296 function webSocketLog(message) {
297 console.log(decodeURIComponent(message));
298 }
299
300 // called from Flash
301 function webSocketError(message) {
302 console.error(decodeURIComponent(message));
303 }
304
305 /*
306 if (window.addEventListener) {
307 window.addEventListener("load", WebSocket.__initialize, false);
308 } else {
309 window.attachEvent("onload", WebSocket.__initialize);
310 }
311 */
312
313 })();