]>
Commit | Line | Data |
---|---|---|
61dd52c9 | 1 | /* |
15046f00 JM |
2 | * noVNC: HTML5 VNC client |
3 | * Copyright (C) 2010 Joel Martin | |
4 | * Licensed under LGPL-3 (see LICENSE.LGPL-3) | |
5 | * | |
6 | * See README.md for usage and integration instructions. | |
61dd52c9 JM |
7 | */ |
8 | ||
15046f00 JM |
9 | "use strict"; |
10 | /*jslint bitwise: false, white: false */ | |
a7a89626 | 11 | /*global window, console, document, navigator, ActiveXObject*/ |
61dd52c9 | 12 | |
15046f00 JM |
13 | // Globals defined here |
14 | var Util = {}, $; | |
15 | ||
81e5adaf | 16 | |
da6dd893 JM |
17 | /* |
18 | * Simple DOM selector by ID | |
19 | */ | |
15046f00 JM |
20 | if (!window.$) { |
21 | $ = function (id) { | |
22 | if (document.getElementById) { | |
23 | return document.getElementById(id); | |
24 | } else if (document.all) { | |
25 | return document.all[id]; | |
26 | } else if (document.layers) { | |
27 | return document.layers[id]; | |
28 | } | |
29 | return undefined; | |
30 | }; | |
31 | } | |
56ec48be JM |
32 | |
33 | /* | |
34 | * Make arrays quack | |
35 | */ | |
36 | ||
37 | Array.prototype.shift8 = function () { | |
38 | return this.shift(); | |
39 | }; | |
40 | Array.prototype.push8 = function (num) { | |
41 | this.push(num & 0xFF); | |
42 | }; | |
43 | ||
44 | Array.prototype.shift16 = function () { | |
45 | return (this.shift() << 8) + | |
46 | (this.shift() ); | |
47 | }; | |
48 | Array.prototype.push16 = function (num) { | |
49 | this.push((num >> 8) & 0xFF, | |
50 | (num ) & 0xFF ); | |
51 | }; | |
2c2b492c JM |
52 | Array.prototype.push16le = function (num) { |
53 | this.push((num ) & 0xFF, | |
54 | (num >> 8) & 0xFF ); | |
55 | }; | |
56ec48be JM |
56 | |
57 | ||
58 | Array.prototype.shift32 = function () { | |
59 | return (this.shift() << 24) + | |
60 | (this.shift() << 16) + | |
61 | (this.shift() << 8) + | |
62 | (this.shift() ); | |
63 | }; | |
64 | Array.prototype.get32 = function (off) { | |
65 | return (this[off ] << 24) + | |
66 | (this[off + 1] << 16) + | |
67 | (this[off + 2] << 8) + | |
68 | (this[off + 3] ); | |
69 | }; | |
70 | Array.prototype.push32 = function (num) { | |
71 | this.push((num >> 24) & 0xFF, | |
72 | (num >> 16) & 0xFF, | |
73 | (num >> 8) & 0xFF, | |
74 | (num ) & 0xFF ); | |
75 | }; | |
2c2b492c JM |
76 | Array.prototype.push32le = function (num) { |
77 | this.push((num ) & 0xFF, | |
78 | (num >> 8) & 0xFF, | |
79 | (num >> 16) & 0xFF, | |
80 | (num >> 24) & 0xFF ); | |
81 | }; | |
82 | ||
56ec48be JM |
83 | |
84 | Array.prototype.shiftStr = function (len) { | |
85 | var arr = this.splice(0, len); | |
86 | return arr.map(function (num) { | |
87 | return String.fromCharCode(num); } ).join(''); | |
88 | }; | |
89 | Array.prototype.pushStr = function (str) { | |
90 | var i, n = str.length; | |
15046f00 | 91 | for (i=0; i < n; i+=1) { |
56ec48be JM |
92 | this.push(str.charCodeAt(i)); |
93 | } | |
94 | }; | |
95 | ||
96 | Array.prototype.shiftBytes = function (len) { | |
97 | return this.splice(0, len); | |
98 | }; | |
99 | ||
15046f00 JM |
100 | /* |
101 | * ------------------------------------------------------ | |
102 | * Namespaced in Util | |
103 | * ------------------------------------------------------ | |
104 | */ | |
105 | ||
8db09746 JM |
106 | /* |
107 | * Logging/debug routines | |
108 | */ | |
109 | ||
110 | Util.init_logging = function (level) { | |
111 | if (typeof window.console === "undefined") { | |
112 | if (typeof window.opera !== "undefined") { | |
113 | window.console = { | |
114 | 'log' : window.opera.postError, | |
115 | 'warn' : window.opera.postError, | |
116 | 'error': window.opera.postError }; | |
117 | } else { | |
118 | window.console = { | |
119 | 'log' : function(m) {}, | |
120 | 'warn' : function(m) {}, | |
121 | 'error': function(m) {}}; | |
122 | } | |
123 | } | |
124 | ||
125 | Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {}; | |
126 | switch (level) { | |
127 | case 'debug': Util.Debug = function (msg) { console.log(msg); }; | |
128 | case 'info': Util.Info = function (msg) { console.log(msg); }; | |
129 | case 'warn': Util.Warn = function (msg) { console.warn(msg); }; | |
130 | case 'error': Util.Error = function (msg) { console.error(msg); }; | |
131 | case 'none': | |
132 | break; | |
133 | default: | |
134 | throw("invalid logging type '" + level + "'"); | |
135 | } | |
136 | }; | |
137 | // Initialize logging level | |
138 | Util.init_logging( (document.location.href.match( | |
139 | /logging=([A-Za-z0-9\._\-]*)/) || | |
140 | ['', 'warn'])[1] ); | |
141 | ||
15046f00 JM |
142 | Util.dirObj = function (obj, depth, parent) { |
143 | var i, msg = "", val = ""; | |
144 | if (! depth) { depth=2; } | |
145 | if (! parent) { parent= ""; } | |
146 | ||
147 | // Print the properties of the passed-in object | |
148 | for (i in obj) { | |
149 | if ((depth > 1) && (typeof obj[i] === "object")) { | |
150 | // Recurse attributes that are objects | |
151 | msg += Util.dirObj(obj[i], depth-1, parent + "." + i); | |
152 | } else { | |
153 | //val = new String(obj[i]).replace("\n", " "); | |
154 | val = obj[i].toString().replace("\n", " "); | |
155 | if (val.length > 30) { | |
156 | val = val.substr(0,30) + "..."; | |
157 | } | |
158 | msg += parent + "." + i + ": " + val + "\n"; | |
159 | } | |
160 | } | |
161 | return msg; | |
162 | }; | |
163 | ||
a8edf9d8 JM |
164 | // Read a query string variable |
165 | Util.getQueryVar = function(name, defVal) { | |
166 | var re = new RegExp('[?][^#]*' + name + '=([^&#]*)'); | |
167 | if (typeof defVal === 'undefined') { defVal = null; } | |
168 | return (document.location.href.match(re) || ['',defVal])[1]; | |
169 | }; | |
170 | ||
125d8bbb | 171 | // Set defaults for Crockford style function namespaces |
8db09746 | 172 | Util.conf_default = function(cfg, api, v, val, force_bool) { |
125d8bbb JM |
173 | if (typeof cfg[v] === 'undefined') { |
174 | cfg[v] = val; | |
175 | } | |
176 | // Default getter | |
177 | if (typeof api['get_' + v] === 'undefined') { | |
178 | api['get_' + v] = function () { | |
179 | return cfg[v]; | |
180 | }; | |
181 | } | |
182 | // Default setter | |
183 | if (typeof api['set_' + v] === 'undefined') { | |
184 | api['set_' + v] = function (val) { | |
8db09746 JM |
185 | if (force_bool) { |
186 | if ((!val) || (val in {'0':1, 'no':1, 'false':1})) { | |
187 | val = false; | |
188 | } else { | |
189 | val = true; | |
190 | } | |
191 | } | |
125d8bbb JM |
192 | cfg[v] = val; |
193 | }; | |
194 | } | |
195 | }; | |
196 | ||
197 | ||
a8edf9d8 | 198 | |
15046f00 JM |
199 | /* |
200 | * Cross-browser routines | |
201 | */ | |
202 | ||
203 | // Get DOM element position on page | |
204 | Util.getPosition = function (obj) { | |
205 | var x = 0, y = 0; | |
206 | if (obj.offsetParent) { | |
207 | do { | |
208 | x += obj.offsetLeft; | |
209 | y += obj.offsetTop; | |
210 | obj = obj.offsetParent; | |
211 | } while (obj); | |
212 | } | |
213 | return {'x': x, 'y': y}; | |
214 | }; | |
215 | ||
216 | // Get mouse event position in DOM element | |
125d8bbb | 217 | Util.getEventPosition = function (e, obj, scale) { |
15046f00 JM |
218 | var evt, docX, docY, pos; |
219 | //if (!e) evt = window.event; | |
220 | evt = (e ? e : window.event); | |
221 | if (evt.pageX || evt.pageY) { | |
222 | docX = evt.pageX; | |
223 | docY = evt.pageY; | |
224 | } else if (evt.clientX || evt.clientY) { | |
225 | docX = evt.clientX + document.body.scrollLeft + | |
226 | document.documentElement.scrollLeft; | |
227 | docY = evt.clientY + document.body.scrollTop + | |
228 | document.documentElement.scrollTop; | |
229 | } | |
230 | pos = Util.getPosition(obj); | |
125d8bbb JM |
231 | if (typeof scale === "undefined") { |
232 | scale = 1; | |
233 | } | |
234 | return {'x': (docX - pos.x) / scale, 'y': (docY - pos.y) / scale}; | |
15046f00 JM |
235 | }; |
236 | ||
237 | ||
238 | // Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events | |
239 | Util.addEvent = function (obj, evType, fn){ | |
d93d3e09 | 240 | if (obj.attachEvent){ |
15046f00 JM |
241 | var r = obj.attachEvent("on"+evType, fn); |
242 | return r; | |
d93d3e09 JM |
243 | } else if (obj.addEventListener){ |
244 | obj.addEventListener(evType, fn, false); | |
245 | return true; | |
15046f00 JM |
246 | } else { |
247 | throw("Handler could not be attached"); | |
248 | } | |
249 | }; | |
250 | ||
251 | Util.removeEvent = function(obj, evType, fn){ | |
d93d3e09 | 252 | if (obj.detachEvent){ |
15046f00 JM |
253 | var r = obj.detachEvent("on"+evType, fn); |
254 | return r; | |
d93d3e09 JM |
255 | } else if (obj.removeEventListener){ |
256 | obj.removeEventListener(evType, fn, false); | |
257 | return true; | |
15046f00 JM |
258 | } else { |
259 | throw("Handler could not be removed"); | |
260 | } | |
261 | }; | |
262 | ||
263 | Util.stopEvent = function(e) { | |
264 | if (e.stopPropagation) { e.stopPropagation(); } | |
265 | else { e.cancelBubble = true; } | |
266 | ||
267 | if (e.preventDefault) { e.preventDefault(); } | |
268 | else { e.returnValue = false; } | |
269 | }; | |
270 | ||
271 | ||
272 | // Set browser engine versions. Based on mootools. | |
273 | Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}; | |
274 | ||
275 | Util.Engine = { | |
276 | 'presto': (function() { | |
277 | return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()), | |
278 | 'trident': (function() { | |
279 | return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); }()), | |
280 | 'webkit': (function() { | |
11bb7a4a JM |
281 | try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()), |
282 | //'webkit': (function() { | |
283 | // return ((typeof navigator.taintEnabled !== "unknown") && navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); }()), | |
15046f00 JM |
284 | 'gecko': (function() { |
285 | return (!document.getBoxObjectFor && !window.mozInnerScreenX) ? false : ((document.getElementsByClassName) ? 19 : 18); }()) | |
286 | }; | |
287 | ||
288 | Util.Flash = (function(){ | |
289 | var v, version; | |
290 | try { | |
291 | v = navigator.plugins['Shockwave Flash'].description; | |
292 | } catch(err1) { | |
293 | try { | |
294 | v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); | |
295 | } catch(err2) { | |
296 | v = '0 r0'; | |
297 | } | |
298 | } | |
299 | version = v.match(/\d+/g); | |
300 | return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; | |
301 | }()); | |
302 | ||
da6dd893 JM |
303 | /* |
304 | * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html | |
305 | */ | |
a8edf9d8 | 306 | |
da6dd893 JM |
307 | // No days means only for this browser session |
308 | Util.createCookie = function(name,value,days) { | |
a7a89626 | 309 | var date, expires; |
da6dd893 | 310 | if (days) { |
a7a89626 | 311 | date = new Date(); |
da6dd893 | 312 | date.setTime(date.getTime()+(days*24*60*60*1000)); |
a7a89626 JM |
313 | expires = "; expires="+date.toGMTString(); |
314 | } | |
315 | else { | |
316 | expires = ""; | |
da6dd893 | 317 | } |
da6dd893 JM |
318 | document.cookie = name+"="+value+expires+"; path=/"; |
319 | }; | |
320 | ||
321 | Util.readCookie = function(name, defaultValue) { | |
8db09746 JM |
322 | var i, c, nameEQ = name + "=", ca = document.cookie.split(';'); |
323 | for(i=0; i < ca.length; i += 1) { | |
324 | c = ca[i]; | |
a7a89626 JM |
325 | while (c.charAt(0) === ' ') { c = c.substring(1,c.length); } |
326 | if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length,c.length); } | |
da6dd893 JM |
327 | } |
328 | return (typeof defaultValue !== 'undefined') ? defaultValue : null; | |
329 | }; | |
330 | ||
331 | Util.eraseCookie = function(name) { | |
a7a89626 | 332 | Util.createCookie(name,"",-1); |
da6dd893 JM |
333 | }; |
334 | ||
335 | /* | |
336 | * Alternate stylesheet selection | |
337 | */ | |
338 | Util.getStylesheets = function() { var i, links, sheets = []; | |
a7a89626 | 339 | links = document.getElementsByTagName("link"); |
8db09746 | 340 | for (i = 0; i < links.length; i += 1) { |
da6dd893 JM |
341 | if (links[i].title && |
342 | links[i].rel.toUpperCase().indexOf("STYLESHEET") > -1) { | |
343 | sheets.push(links[i]); | |
344 | } | |
345 | } | |
346 | return sheets; | |
347 | }; | |
348 | ||
349 | // No sheet means try and use value from cookie, null sheet used to | |
350 | // clear all alternates. | |
351 | Util.selectStylesheet = function(sheet) { | |
352 | var i, link, sheets = Util.getStylesheets(); | |
353 | if (typeof sheet === 'undefined') { | |
354 | sheet = 'default'; | |
355 | } | |
8db09746 | 356 | for (i=0; i < sheets.length; i += 1) { |
da6dd893 JM |
357 | link = sheets[i]; |
358 | if (link.title === sheet) { | |
359 | Util.Debug("Using stylesheet " + sheet); | |
360 | link.disabled = false; | |
361 | } else { | |
8db09746 | 362 | //Util.Debug("Skipping stylesheet " + link.title); |
da6dd893 JM |
363 | link.disabled = true; |
364 | } | |
365 | } | |
366 | return sheet; | |
367 | }; |