]> git.proxmox.com Git - mirror_novnc.git/blame - app/webutil.js
Use fat arrow functions `const foo = () => { ... };` for callbacks
[mirror_novnc.git] / app / webutil.js
CommitLineData
8d5d2c82
AM
1/*
2 * noVNC: HTML5 VNC client
d58f8b51 3 * Copyright (C) 2012 Joel Martin
ad941fad 4 * Copyright (C) 2013 NTT corp.
1d728ace 5 * Licensed under MPL 2.0 (see LICENSE.txt)
8d5d2c82
AM
6 *
7 * See README.md for usage and integration instructions.
8 */
9
c464f47e 10import { init_logging as main_init_logging } from '../core/util/logging.js';
8d5d2c82
AM
11
12// init log level reading the logging HTTP param
6d6f0db0 13export function init_logging (level) {
ee7d4c61 14 "use strict";
2cde6e43 15 if (typeof level !== "undefined") {
6d6f0db0 16 main_init_logging(level);
2cde6e43 17 } else {
2b5f94fa 18 const param = document.location.href.match(/logging=([A-Za-z0-9._-]*)/);
6d6f0db0 19 main_init_logging(param || undefined);
2cde6e43 20 }
8727f598 21}
8d5d2c82 22
8d5d2c82 23// Read a query string variable
6d6f0db0 24export function getQueryVar (name, defVal) {
ee7d4c61 25 "use strict";
2b5f94fa 26 const re = new RegExp('.*[?&]' + name + '=([^&#]*)'),
fa5b334d 27 match = document.location.href.match(re);
8d5d2c82 28 if (typeof defVal === 'undefined') { defVal = null; }
2b5f94fa 29
fa5b334d
JM
30 if (match) {
31 return decodeURIComponent(match[1]);
fa5b334d 32 }
2b5f94fa
JD
33
34 return defVal;
8727f598 35}
8d5d2c82 36
494b407a 37// Read a hash fragment variable
6d6f0db0 38export function getHashVar (name, defVal) {
494b407a 39 "use strict";
2b5f94fa 40 const re = new RegExp('.*[&#]' + name + '=([^&]*)'),
494b407a
GV
41 match = document.location.hash.match(re);
42 if (typeof defVal === 'undefined') { defVal = null; }
2b5f94fa 43
494b407a
GV
44 if (match) {
45 return decodeURIComponent(match[1]);
494b407a 46 }
2b5f94fa
JD
47
48 return defVal;
8727f598 49}
494b407a
GV
50
51// Read a variable from the fragment or the query string
52// Fragment takes precedence
6d6f0db0 53export function getConfigVar (name, defVal) {
494b407a 54 "use strict";
2b5f94fa
JD
55 const val = getHashVar(name);
56
494b407a 57 if (val === null) {
2b5f94fa 58 return getQueryVar(name, defVal);
494b407a 59 }
2b5f94fa 60
494b407a 61 return val;
8727f598 62}
8d5d2c82
AM
63
64/*
65 * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
66 */
67
68// No days means only for this browser session
6d6f0db0 69export function createCookie (name, value, days) {
ee7d4c61 70 "use strict";
2b5f94fa 71 let date, expires;
8d5d2c82
AM
72 if (days) {
73 date = new Date();
ee7d4c61
SR
74 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
75 expires = "; expires=" + date.toGMTString();
ad941fad 76 } else {
8d5d2c82
AM
77 expires = "";
78 }
ee7d4c61 79
2b5f94fa 80 let secure;
ad941fad
TN
81 if (document.location.protocol === "https:") {
82 secure = "; secure";
83 } else {
84 secure = "";
85 }
ee7d4c61 86 document.cookie = name + "=" + value + expires + "; path=/" + secure;
8727f598 87}
8d5d2c82 88
6d6f0db0 89export function readCookie (name, defaultValue) {
ee7d4c61 90 "use strict";
2b5f94fa
JD
91 const nameEQ = name + "=";
92 const ca = document.cookie.split(';');
ee7d4c61 93
2b5f94fa
JD
94 for (let i = 0; i < ca.length; i += 1) {
95 let c = ca[i];
96 while (c.charAt(0) === ' ') {
97 c = c.substring(1, c.length);
98 }
99 if (c.indexOf(nameEQ) === 0) {
100 return c.substring(nameEQ.length, c.length);
101 }
8d5d2c82 102 }
2b5f94fa 103
8d5d2c82 104 return (typeof defaultValue !== 'undefined') ? defaultValue : null;
8727f598 105}
8d5d2c82 106
6d6f0db0 107export function eraseCookie (name) {
ee7d4c61 108 "use strict";
6d6f0db0 109 createCookie(name, "", -1);
8727f598 110}
8d5d2c82 111
3af1c275
JM
112/*
113 * Setting handling.
114 */
115
2b5f94fa 116let settings = {};
6d6f0db0
SR
117
118export function initSettings (callback /*, ...callbackArgs */) {
ee7d4c61 119 "use strict";
2b5f94fa 120 const callbackArgs = Array.prototype.slice.call(arguments, 1);
d5fe1509 121 if (window.chrome && window.chrome.storage) {
651c23ec 122 window.chrome.storage.sync.get((cfg) => {
6d6f0db0 123 settings = cfg;
3af1c275
JM
124 if (callback) {
125 callback.apply(this, callbackArgs);
126 }
127 });
128 } else {
e0750f9b 129 settings = {};
3af1c275
JM
130 if (callback) {
131 callback.apply(this, callbackArgs);
132 }
133 }
8727f598 134}
3af1c275 135
e0750f9b
AW
136// Update the settings cache, but do not write to permanent storage
137export function setSetting (name, value) {
138 settings[name] = value;
8727f598 139}
e0750f9b 140
3af1c275 141// No days means only for this browser session
6d6f0db0 142export function writeSetting (name, value) {
ee7d4c61 143 "use strict";
e0750f9b
AW
144 if (settings[name] === value) return;
145 settings[name] = value;
d5fe1509 146 if (window.chrome && window.chrome.storage) {
e0750f9b 147 window.chrome.storage.sync.set(settings);
3af1c275
JM
148 } else {
149 localStorage.setItem(name, value);
150 }
8727f598 151}
3af1c275 152
6d6f0db0 153export function readSetting (name, defaultValue) {
ee7d4c61 154 "use strict";
2b5f94fa 155 let value;
e0750f9b 156 if ((name in settings) || (window.chrome && window.chrome.storage)) {
6d6f0db0 157 value = settings[name];
3af1c275
JM
158 } else {
159 value = localStorage.getItem(name);
e0750f9b 160 settings[name] = value;
3af1c275
JM
161 }
162 if (typeof value === "undefined") {
163 value = null;
164 }
2b5f94fa 165
eb533b2b 166 if (value === null && typeof defaultValue !== "undefined") {
3af1c275 167 return defaultValue;
3af1c275 168 }
2b5f94fa
JD
169
170 return value;
8727f598 171}
3af1c275 172
6d6f0db0 173export function eraseSetting (name) {
ee7d4c61 174 "use strict";
e0750f9b
AW
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
179 // value change.
180 delete settings[name];
d5fe1509
JM
181 if (window.chrome && window.chrome.storage) {
182 window.chrome.storage.sync.remove(name);
3af1c275
JM
183 } else {
184 localStorage.removeItem(name);
185 }
8727f598 186}
3af1c275 187
6d6f0db0 188export function injectParamIfMissing (path, param, value) {
c55f05f6
MXPN
189 // force pretend that we're dealing with a relative path
190 // (assume that we wanted an extra if we pass one in)
191 path = "/" + path;
192
2b5f94fa 193 const elem = document.createElement('a');
c55f05f6
MXPN
194 elem.href = path;
195
2b5f94fa
JD
196 const param_eq = encodeURIComponent(param) + "=";
197 let query;
c55f05f6
MXPN
198 if (elem.search) {
199 query = elem.search.slice(1).split('&');
200 } else {
201 query = [];
202 }
203
651c23ec 204 if (!query.some(v => v.startsWith(param_eq))) {
c55f05f6
MXPN
205 query.push(param_eq + encodeURIComponent(value));
206 elem.search = "?" + query.join("&");
207 }
208
c8294760
JB
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;
3c955844 213 }
2b5f94fa
JD
214
215 return elem.pathname + elem.search + elem.hash;
8727f598 216}
ae510306 217
2a7c6d20
SR
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.
6d6f0db0 222export function fetchJSON(path, resolve, reject) {
2a7c6d20 223 // NB: IE11 doesn't support JSON as a responseType
2b5f94fa 224 const req = new XMLHttpRequest();
2a7c6d20
SR
225 req.open('GET', path);
226
651c23ec 227 req.onload = () => {
2a7c6d20 228 if (req.status === 200) {
2b5f94fa 229 let resObj;
2a7c6d20 230 try {
2b5f94fa 231 resObj = JSON.parse(req.responseText);
2a7c6d20
SR
232 } catch (err) {
233 reject(err);
2a7c6d20
SR
234 }
235 resolve(resObj);
236 } else {
237 reject(new Error("XHR got non-200 status while trying to load '" + path + "': " + req.status));
238 }
239 };
240
651c23ec 241 req.onerror = evt => reject(new Error("XHR encountered an error while trying to load '" + path + "': " + evt.message));
2a7c6d20 242
651c23ec 243 req.ontimeout = evt => reject(new Error("XHR timed out while trying to load '" + path + "'"));
2a7c6d20
SR
244
245 req.send();
6d6f0db0 246}