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