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 const 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 const re
= new RegExp('.*[?&]' + name
+ '=([^&#]*)'),
27 match
= document
.location
.href
.match(re
);
28 if (typeof defVal
=== 'undefined') { defVal
= null; }
31 return decodeURIComponent(match
[1]);
37 // Read a hash fragment variable
38 export function getHashVar (name
, defVal
) {
40 const re
= new RegExp('.*[&#]' + name
+ '=([^&]*)'),
41 match
= document
.location
.hash
.match(re
);
42 if (typeof defVal
=== 'undefined') { defVal
= null; }
45 return decodeURIComponent(match
[1]);
51 // Read a variable from the fragment or the query string
52 // Fragment takes precedence
53 export function getConfigVar (name
, defVal
) {
55 const val
= getHashVar(name
);
58 return getQueryVar(name
, defVal
);
65 * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
68 // No days means only for this browser session
69 export function createCookie (name
, value
, days
) {
74 date
.setTime(date
.getTime() + (days
* 24 * 60 * 60 * 1000));
75 expires
= "; expires=" + date
.toGMTString();
81 if (document
.location
.protocol
=== "https:") {
86 document
.cookie
= name
+ "=" + value
+ expires
+ "; path=/" + secure
;
89 export function readCookie (name
, defaultValue
) {
91 const nameEQ
= name
+ "=";
92 const ca
= document
.cookie
.split(';');
94 for (let i
= 0; i
< ca
.length
; i
+= 1) {
96 while (c
.charAt(0) === ' ') {
97 c
= c
.substring(1, c
.length
);
99 if (c
.indexOf(nameEQ
) === 0) {
100 return c
.substring(nameEQ
.length
, c
.length
);
104 return (typeof defaultValue
!== 'undefined') ? defaultValue
: null;
107 export function eraseCookie (name
) {
109 createCookie(name
, "", -1);
118 export function initSettings (callback
/*, ...callbackArgs */) {
120 const callbackArgs
= Array
.prototype.slice
.call(arguments
, 1);
121 if (window
.chrome
&& window
.chrome
.storage
) {
122 window
.chrome
.storage
.sync
.get(function (cfg
) {
125 callback
.apply(this, callbackArgs
);
131 callback
.apply(this, callbackArgs
);
136 // Update the settings cache, but do not write to permanent storage
137 export function setSetting (name
, value
) {
138 settings
[name
] = value
;
141 // No days means only for this browser session
142 export function writeSetting (name
, value
) {
144 if (settings
[name
] === value
) return;
145 settings
[name
] = value
;
146 if (window
.chrome
&& window
.chrome
.storage
) {
147 window
.chrome
.storage
.sync
.set(settings
);
149 localStorage
.setItem(name
, value
);
153 export function readSetting (name
, defaultValue
) {
156 if ((name
in settings
) || (window
.chrome
&& window
.chrome
.storage
)) {
157 value
= settings
[name
];
159 value
= localStorage
.getItem(name
);
160 settings
[name
] = value
;
162 if (typeof value
=== "undefined") {
166 if (value
=== null && typeof defaultValue
!== "undefined") {
173 export function eraseSetting (name
) {
175 // Deleting here means that next time the setting is read when using local
176 // storage, it will be pulled from local storage again.
177 // If the setting in local storage is changed (e.g. in another tab)
178 // between this delete and the next read, it could lead to an unexpected
180 delete settings
[name
];
181 if (window
.chrome
&& window
.chrome
.storage
) {
182 window
.chrome
.storage
.sync
.remove(name
);
184 localStorage
.removeItem(name
);
188 export function injectParamIfMissing (path
, param
, value
) {
189 // force pretend that we're dealing with a relative path
190 // (assume that we wanted an extra if we pass one in)
193 const elem
= document
.createElement('a');
196 const param_eq
= encodeURIComponent(param
) + "=";
199 query
= elem
.search
.slice(1).split('&');
204 if (!query
.some(function (v
) { return v
.startsWith(param_eq
); })) {
205 query
.push(param_eq
+ encodeURIComponent(value
));
206 elem
.search
= "?" + query
.join("&");
209 // some browsers (e.g. IE11) may occasionally omit the leading slash
210 // in the elem.pathname string. Handle that case gracefully.
211 if (elem
.pathname
.charAt(0) == "/") {
212 return elem
.pathname
.slice(1) + elem
.search
+ elem
.hash
;
215 return elem
.pathname
+ elem
.search
+ elem
.hash
;
218 // sadly, we can't use the Fetch API until we decide to drop
219 // IE11 support or polyfill promises and fetch in IE11.
220 // resolve will receive an object on success, while reject
221 // will receive either an event or an error on failure.
222 export function fetchJSON(path
, resolve
, reject
) {
223 // NB: IE11 doesn't support JSON as a responseType
224 const req
= new XMLHttpRequest();
225 req
.open('GET', path
);
227 req
.onload = function () {
228 if (req
.status
=== 200) {
231 resObj
= JSON
.parse(req
.responseText
);
237 reject(new Error("XHR got non-200 status while trying to load '" + path
+ "': " + req
.status
));
241 req
.onerror = function (evt
) {
242 reject(new Error("XHR encountered an error while trying to load '" + path
+ "': " + evt
.message
));
245 req
.ontimeout = function (evt
) {
246 reject(new Error("XHR timed out while trying to load '" + path
+ "'"));