]> git.proxmox.com Git - mirror_novnc.git/blame - include/util.js
New API. Refactor Canvas and RFB objects.
[mirror_novnc.git] / include / util.js
CommitLineData
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
14var Util = {}, $;
15
81e5adaf 16
da6dd893
JM
17/*
18 * Simple DOM selector by ID
19 */
15046f00
JM
20if (!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
37Array.prototype.shift8 = function () {
38 return this.shift();
39};
40Array.prototype.push8 = function (num) {
41 this.push(num & 0xFF);
42};
43
44Array.prototype.shift16 = function () {
45 return (this.shift() << 8) +
46 (this.shift() );
47};
48Array.prototype.push16 = function (num) {
49 this.push((num >> 8) & 0xFF,
50 (num ) & 0xFF );
51};
2c2b492c
JM
52Array.prototype.push16le = function (num) {
53 this.push((num ) & 0xFF,
54 (num >> 8) & 0xFF );
55};
56ec48be
JM
56
57
58Array.prototype.shift32 = function () {
59 return (this.shift() << 24) +
60 (this.shift() << 16) +
61 (this.shift() << 8) +
62 (this.shift() );
63};
64Array.prototype.get32 = function (off) {
65 return (this[off ] << 24) +
66 (this[off + 1] << 16) +
67 (this[off + 2] << 8) +
68 (this[off + 3] );
69};
70Array.prototype.push32 = function (num) {
71 this.push((num >> 24) & 0xFF,
72 (num >> 16) & 0xFF,
73 (num >> 8) & 0xFF,
74 (num ) & 0xFF );
75};
2c2b492c
JM
76Array.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
84Array.prototype.shiftStr = function (len) {
85 var arr = this.splice(0, len);
86 return arr.map(function (num) {
87 return String.fromCharCode(num); } ).join('');
88};
89Array.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
96Array.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
110Util.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
138Util.init_logging( (document.location.href.match(
139 /logging=([A-Za-z0-9\._\-]*)/) ||
140 ['', 'warn'])[1] );
141
15046f00
JM
142Util.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
165Util.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 172Util.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
204Util.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 217Util.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
239Util.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
251Util.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
263Util.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.
273Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)};
274
275Util.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
288Util.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
308Util.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
321Util.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
331Util.eraseCookie = function(name) {
a7a89626 332 Util.createCookie(name,"",-1);
da6dd893
JM
333};
334
335/*
336 * Alternate stylesheet selection
337 */
338Util.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.
351Util.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};