]>
git.proxmox.com Git - mirror_novnc.git/blob - app/webutil.js
2 * noVNC: HTML5 VNC client
3 * Copyright (C) 2012 Joel Martin
4 * Copyright (C) 2013 NTT corp.
5 * Licensed under MPL 2.0 (see LICENSE.txt)
7 * See README.md for usage and integration instructions.
10 /*jslint bitwise: false, white: false, browser: true, devel: true */
11 /*global Util, window, document */
14 * import Util from "../core/util";
17 // Globals defined here
21 * ------------------------------------------------------
22 * Namespaced in WebUtil
23 * ------------------------------------------------------
26 // init log level reading the logging HTTP param
27 WebUtil
.init_logging = function (level
) {
29 if (typeof level
!== "undefined") {
30 Util
._log_level
= level
;
32 var param
= document
.location
.href
.match(/logging=([A-Za-z0-9\._\-]*)/);
33 Util
._log_level
= (param
|| ['', Util
._log_level
])[1];
39 WebUtil
.dirObj = function (obj
, depth
, parent
) {
41 if (! depth
) { depth
= 2; }
42 if (! parent
) { parent
= ""; }
44 // Print the properties of the passed-in object
47 if ((depth
> 1) && (typeof obj
[i
] === "object")) {
48 // Recurse attributes that are objects
49 msg
+= WebUtil
.dirObj(obj
[i
], depth
- 1, parent
+ "." + i
);
51 //val = new String(obj[i]).replace("\n", " ");
53 if (typeof(obj
[i
]) === "undefined") {
56 val
= obj
[i
].toString().replace("\n", " ");
58 if (val
.length
> 30) {
59 val
= val
.substr(0, 30) + "...";
61 msg
+= parent
+ "." + i
+ ": " + val
+ "\n";
67 // Read a query string variable
68 WebUtil
.getQueryVar = function (name
, defVal
) {
70 var re
= new RegExp('.*[?&]' + name
+ '=([^&#]*)'),
71 match
= document
.location
.href
.match(re
);
72 if (typeof defVal
=== 'undefined') { defVal
= null; }
74 return decodeURIComponent(match
[1]);
80 // Read a hash fragment variable
81 WebUtil
.getHashVar = function (name
, defVal
) {
83 var re
= new RegExp('.*[&#]' + name
+ '=([^&]*)'),
84 match
= document
.location
.hash
.match(re
);
85 if (typeof defVal
=== 'undefined') { defVal
= null; }
87 return decodeURIComponent(match
[1]);
93 // Read a variable from the fragment or the query string
94 // Fragment takes precedence
95 WebUtil
.getConfigVar = function (name
, defVal
) {
97 var val
= WebUtil
.getHashVar(name
);
99 val
= WebUtil
.getQueryVar(name
, defVal
);
105 * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
108 // No days means only for this browser session
109 WebUtil
.createCookie = function (name
, value
, days
) {
114 date
.setTime(date
.getTime() + (days
* 24 * 60 * 60 * 1000));
115 expires
= "; expires=" + date
.toGMTString();
121 if (document
.location
.protocol
=== "https:") {
126 document
.cookie
= name
+ "=" + value
+ expires
+ "; path=/" + secure
;
129 WebUtil
.readCookie = function (name
, defaultValue
) {
131 var nameEQ
= name
+ "=",
132 ca
= document
.cookie
.split(';');
134 for (var i
= 0; i
< ca
.length
; i
+= 1) {
136 while (c
.charAt(0) === ' ') { c
= c
.substring(1, c
.length
); }
137 if (c
.indexOf(nameEQ
) === 0) { return c
.substring(nameEQ
.length
, c
.length
); }
139 return (typeof defaultValue
!== 'undefined') ? defaultValue
: null;
142 WebUtil
.eraseCookie = function (name
) {
144 WebUtil
.createCookie(name
, "", -1);
151 WebUtil
.initSettings = function (callback
/*, ...callbackArgs */) {
153 var callbackArgs
= Array
.prototype.slice
.call(arguments
, 1);
154 if (window
.chrome
&& window
.chrome
.storage
) {
155 window
.chrome
.storage
.sync
.get(function (cfg
) {
156 WebUtil
.settings
= cfg
;
157 console
.log(WebUtil
.settings
);
159 callback
.apply(this, callbackArgs
);
165 callback
.apply(this, callbackArgs
);
170 // No days means only for this browser session
171 WebUtil
.writeSetting = function (name
, value
) {
173 if (window
.chrome
&& window
.chrome
.storage
) {
174 //console.log("writeSetting:", name, value);
175 if (WebUtil
.settings
[name
] !== value
) {
176 WebUtil
.settings
[name
] = value
;
177 window
.chrome
.storage
.sync
.set(WebUtil
.settings
);
180 localStorage
.setItem(name
, value
);
184 WebUtil
.readSetting = function (name
, defaultValue
) {
187 if (window
.chrome
&& window
.chrome
.storage
) {
188 value
= WebUtil
.settings
[name
];
190 value
= localStorage
.getItem(name
);
192 if (typeof value
=== "undefined") {
195 if (value
=== null && typeof defaultValue
!== undefined) {
202 WebUtil
.eraseSetting = function (name
) {
204 if (window
.chrome
&& window
.chrome
.storage
) {
205 window
.chrome
.storage
.sync
.remove(name
);
206 delete WebUtil
.settings
[name
];
208 localStorage
.removeItem(name
);
213 * Alternate stylesheet selection
215 WebUtil
.getStylesheets = function () {
217 var links
= document
.getElementsByTagName("link");
220 for (var i
= 0; i
< links
.length
; i
+= 1) {
221 if (links
[i
].title
&&
222 links
[i
].rel
.toUpperCase().indexOf("STYLESHEET") > -1) {
223 sheets
.push(links
[i
]);
229 // No sheet means try and use value from cookie, null sheet used to
230 // clear all alternates.
231 WebUtil
.selectStylesheet = function (sheet
) {
233 if (typeof sheet
=== 'undefined') {
237 var sheets
= WebUtil
.getStylesheets();
238 for (var i
= 0; i
< sheets
.length
; i
+= 1) {
239 var link
= sheets
[i
];
240 if (link
.title
=== sheet
) {
241 Util
.Debug("Using stylesheet " + sheet
);
242 link
.disabled
= false;
244 //Util.Debug("Skipping stylesheet " + link.title);
245 link
.disabled
= true;
251 WebUtil
.injectParamIfMissing = function (path
, param
, value
) {
252 // force pretend that we're dealing with a relative path
253 // (assume that we wanted an extra if we pass one in)
256 var elem
= document
.createElement('a');
259 var param_eq
= encodeURIComponent(param
) + "=";
262 query
= elem
.search
.slice(1).split('&');
267 if (!query
.some(function (v
) { return v
.startsWith(param_eq
); })) {
268 query
.push(param_eq
+ encodeURIComponent(value
));
269 elem
.search
= "?" + query
.join("&");
272 // some browsers (e.g. IE11) may occasionally omit the leading slash
273 // in the elem.pathname string. Handle that case gracefully.
274 if (elem
.pathname
.charAt(0) == "/") {
275 return elem
.pathname
.slice(1) + elem
.search
+ elem
.hash
;
277 return elem
.pathname
+ elem
.search
+ elem
.hash
;
281 // Emulate Element.setCapture() when not supported
283 WebUtil
._captureRecursion
= false;
284 WebUtil
._captureProxy = function (e
) {
285 // Recursion protection as we'll see our own event
286 if (WebUtil
._captureRecursion
) return;
288 // Clone the event as we cannot dispatch an already dispatched event
289 var newEv
= new e
.constructor(e
.type
, e
);
291 WebUtil
._captureRecursion
= true;
292 WebUtil
._captureElem
.dispatchEvent(newEv
);
293 WebUtil
._captureRecursion
= false;
295 // Implicitly release the capture on button release
296 if ((e
.type
=== "mouseup") || (e
.type
=== "touchend")) {
297 WebUtil
.releaseCapture();
301 WebUtil
.setCapture = function (elem
) {
302 if (elem
.setCapture
) {
306 // IE releases capture on 'click' events which might not trigger
307 elem
.addEventListener('mouseup', WebUtil
.releaseCapture
);
308 elem
.addEventListener('touchend', WebUtil
.releaseCapture
);
311 // Safari on iOS 9 has a broken constructor for TouchEvent.
312 // We are fine in this case however, since Safari seems to
313 // have some sort of implicit setCapture magic anyway.
314 if (window
.TouchEvent
!== undefined) {
316 new TouchEvent("touchstart");
317 } catch (TypeError
) {
322 var captureElem
= document
.getElementById("noVNC_mouse_capture_elem");
324 if (captureElem
=== null) {
325 captureElem
= document
.createElement("div");
326 captureElem
.id
= "noVNC_mouse_capture_elem";
327 captureElem
.style
.position
= "fixed";
328 captureElem
.style
.top
= "0px";
329 captureElem
.style
.left
= "0px";
330 captureElem
.style
.width
= "100%";
331 captureElem
.style
.height
= "100%";
332 captureElem
.style
.zIndex
= 10000;
333 captureElem
.style
.display
= "none";
334 document
.body
.appendChild(captureElem
);
336 captureElem
.addEventListener('mousemove', WebUtil
._captureProxy
);
337 captureElem
.addEventListener('mouseup', WebUtil
._captureProxy
);
339 captureElem
.addEventListener('touchmove', WebUtil
._captureProxy
);
340 captureElem
.addEventListener('touchend', WebUtil
._captureProxy
);
343 WebUtil
._captureElem
= elem
;
344 captureElem
.style
.display
= null;
346 // We listen to events on window in order to keep tracking if it
347 // happens to leave the viewport
348 window
.addEventListener('mousemove', WebUtil
._captureProxy
);
349 window
.addEventListener('mouseup', WebUtil
._captureProxy
);
351 window
.addEventListener('touchmove', WebUtil
._captureProxy
);
352 window
.addEventListener('touchend', WebUtil
._captureProxy
);
356 WebUtil
.releaseCapture = function () {
357 if (document
.releaseCapture
) {
359 document
.releaseCapture();
362 var captureElem
= document
.getElementById("noVNC_mouse_capture_elem");
363 WebUtil
._captureElem
= null;
364 captureElem
.style
.display
= "none";
366 window
.removeEventListener('mousemove', WebUtil
._captureProxy
);
367 window
.removeEventListener('mouseup', WebUtil
._captureProxy
);
369 window
.removeEventListener('touchmove', WebUtil
._captureProxy
);
370 window
.removeEventListener('touchend', WebUtil
._captureProxy
);
375 // Get language file location
376 WebUtil
.getLanguageFileLocation = function () {
377 return '../app/locale/locale-'+Util
.Localisation
.getLanguageCode()+'.js';
380 // Dynamically load scripts without using document.write()
381 // Reference: http://unixpapa.com/js/dyna.html
383 // Handles the case where load_scripts is invoked from a script that
384 // itself is loaded via load_scripts. Once all scripts are loaded the
385 // window.onscriptsloaded handler is called (if set).
386 WebUtil
.get_include_uri = function (root_dir
) {
387 return (typeof INCLUDE_URI
!== "undefined") ? INCLUDE_URI
+ root_dir
+ '/' : root_dir
+ '/';
389 WebUtil
._loading_scripts
= [];
390 WebUtil
._pending_scripts
= [];
391 WebUtil
.load_scripts = function (files_by_dir
) {
393 var head
= document
.getElementsByTagName('head')[0], script
,
394 ls
= WebUtil
._loading_scripts
, ps
= WebUtil
._pending_scripts
;
396 var loadFunc = function (e
) {
397 while (ls
.length
> 0 && (ls
[0].readyState
=== 'loaded' ||
398 ls
[0].readyState
=== 'complete')) {
399 // For IE, append the script to trigger execution
401 //console.log("loaded script: " + s.src);
404 if (!this.readyState
||
405 (Util
.Engine
.presto
&& this.readyState
=== 'loaded') ||
406 this.readyState
=== 'complete') {
407 if (ps
.indexOf(this) >= 0) {
408 this.onload
= this.onreadystatechange
= null;
409 //console.log("completed script: " + this.src);
410 ps
.splice(ps
.indexOf(this), 1);
412 // Call window.onscriptsload after last script loads
413 if (ps
.length
=== 0 && window
.onscriptsload
) {
414 window
.onscriptsload();
420 var root_dirs
= Object
.keys(files_by_dir
);
422 for (var d
= 0; d
< root_dirs
.length
; d
++) {
423 var root_dir
= root_dirs
[d
];
424 var files
= files_by_dir
[root_dir
];
426 for (var f
= 0; f
< files
.length
; f
++) {
427 script
= document
.createElement('script');
428 script
.type
= 'text/javascript';
429 script
.src
= WebUtil
.get_include_uri(root_dir
) + files
[f
];
430 //console.log("loading script: " + script.src);
431 script
.onload
= script
.onreadystatechange
= loadFunc
;
432 // In-order script execution tricks
433 if (Util
.Engine
.trident
) {
434 // For IE wait until readyState is 'loaded' before
435 // appending it which will trigger execution
436 // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
439 // For webkit and firefox set async=false and append now
440 // https://developer.mozilla.org/en-US/docs/HTML/Element/script
441 script
.async
= false;
442 head
.appendChild(script
);
449 /* [module] export default WebUtil; */