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 import { init_logging as main_init_logging
} from '../core/util/logging.js';
12 // init log level reading the logging HTTP param
13 export function init_logging (level
) {
15 if (typeof level
!== "undefined") {
16 main_init_logging(level
);
18 var param
= document
.location
.href
.match(/logging=([A-Za-z0-9._-]*)/);
19 main_init_logging(param
|| undefined);
23 // Read a query string variable
24 export function getQueryVar (name
, defVal
) {
26 var re
= new RegExp('.*[?&]' + name
+ '=([^&#]*)'),
27 match
= document
.location
.href
.match(re
);
28 if (typeof defVal
=== 'undefined') { defVal
= null; }
30 return decodeURIComponent(match
[1]);
36 // Read a hash fragment variable
37 export function getHashVar (name
, defVal
) {
39 var re
= new RegExp('.*[&#]' + name
+ '=([^&]*)'),
40 match
= document
.location
.hash
.match(re
);
41 if (typeof defVal
=== 'undefined') { defVal
= null; }
43 return decodeURIComponent(match
[1]);
49 // Read a variable from the fragment or the query string
50 // Fragment takes precedence
51 export function getConfigVar (name
, defVal
) {
53 var val
= getHashVar(name
);
55 val
= getQueryVar(name
, defVal
);
61 * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
64 // No days means only for this browser session
65 export function createCookie (name
, value
, days
) {
70 date
.setTime(date
.getTime() + (days
* 24 * 60 * 60 * 1000));
71 expires
= "; expires=" + date
.toGMTString();
77 if (document
.location
.protocol
=== "https:") {
82 document
.cookie
= name
+ "=" + value
+ expires
+ "; path=/" + secure
;
85 export function readCookie (name
, defaultValue
) {
87 var nameEQ
= name
+ "=",
88 ca
= document
.cookie
.split(';');
90 for (var i
= 0; i
< ca
.length
; i
+= 1) {
92 while (c
.charAt(0) === ' ') { c
= c
.substring(1, c
.length
); }
93 if (c
.indexOf(nameEQ
) === 0) { return c
.substring(nameEQ
.length
, c
.length
); }
95 return (typeof defaultValue
!== 'undefined') ? defaultValue
: null;
98 export function eraseCookie (name
) {
100 createCookie(name
, "", -1);
109 export function initSettings (callback
/*, ...callbackArgs */) {
111 var callbackArgs
= Array
.prototype.slice
.call(arguments
, 1);
112 if (window
.chrome
&& window
.chrome
.storage
) {
113 window
.chrome
.storage
.sync
.get(function (cfg
) {
116 callback
.apply(this, callbackArgs
);
122 callback
.apply(this, callbackArgs
);
127 // Update the settings cache, but do not write to permanent storage
128 export function setSetting (name
, value
) {
129 settings
[name
] = value
;
132 // No days means only for this browser session
133 export function writeSetting (name
, value
) {
135 if (settings
[name
] === value
) return;
136 settings
[name
] = value
;
137 if (window
.chrome
&& window
.chrome
.storage
) {
138 window
.chrome
.storage
.sync
.set(settings
);
140 localStorage
.setItem(name
, value
);
144 export function readSetting (name
, defaultValue
) {
147 if ((name
in settings
) || (window
.chrome
&& window
.chrome
.storage
)) {
148 value
= settings
[name
];
150 value
= localStorage
.getItem(name
);
151 settings
[name
] = value
;
153 if (typeof value
=== "undefined") {
156 if (value
=== null && typeof defaultValue
!== "undefined") {
163 export function eraseSetting (name
) {
165 // Deleting here means that next time the setting is read when using local
166 // storage, it will be pulled from local storage again.
167 // If the setting in local storage is changed (e.g. in another tab)
168 // between this delete and the next read, it could lead to an unexpected
170 delete settings
[name
];
171 if (window
.chrome
&& window
.chrome
.storage
) {
172 window
.chrome
.storage
.sync
.remove(name
);
174 localStorage
.removeItem(name
);
178 export function injectParamIfMissing (path
, param
, value
) {
179 // force pretend that we're dealing with a relative path
180 // (assume that we wanted an extra if we pass one in)
183 var elem
= document
.createElement('a');
186 var param_eq
= encodeURIComponent(param
) + "=";
189 query
= elem
.search
.slice(1).split('&');
194 if (!query
.some(function (v
) { return v
.startsWith(param_eq
); })) {
195 query
.push(param_eq
+ encodeURIComponent(value
));
196 elem
.search
= "?" + query
.join("&");
199 // some browsers (e.g. IE11) may occasionally omit the leading slash
200 // in the elem.pathname string. Handle that case gracefully.
201 if (elem
.pathname
.charAt(0) == "/") {
202 return elem
.pathname
.slice(1) + elem
.search
+ elem
.hash
;
204 return elem
.pathname
+ elem
.search
+ elem
.hash
;
208 // sadly, we can't use the Fetch API until we decide to drop
209 // IE11 support or polyfill promises and fetch in IE11.
210 // resolve will receive an object on success, while reject
211 // will receive either an event or an error on failure.
212 export function fetchJSON(path
, resolve
, reject
) {
213 // NB: IE11 doesn't support JSON as a responseType
214 var req
= new XMLHttpRequest();
215 req
.open('GET', path
);
217 req
.onload = function () {
218 if (req
.status
=== 200) {
220 var resObj
= JSON
.parse(req
.responseText
);
227 reject(new Error("XHR got non-200 status while trying to load '" + path
+ "': " + req
.status
));
231 req
.onerror = function (evt
) {
232 reject(new Error("XHR encountered an error while trying to load '" + path
+ "': " + evt
.message
));
235 req
.ontimeout = function (evt
) {
236 reject(new Error("XHR timed out while trying to load '" + path
+ "'"));