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