]>
Commit | Line | Data |
---|---|---|
8d5d2c82 AM |
1 | /* |
2 | * noVNC: HTML5 VNC client | |
412d9306 | 3 | * Copyright (C) 2019 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 | ||
a7fe079f | 9 | import { initLogging as mainInitLogging } from '../core/util/logging.js'; |
8d5d2c82 AM |
10 | |
11 | // init log level reading the logging HTTP param | |
a7fe079f | 12 | export function initLogging(level) { |
ee7d4c61 | 13 | "use strict"; |
2cde6e43 | 14 | if (typeof level !== "undefined") { |
a7fe079f | 15 | mainInitLogging(level); |
2cde6e43 | 16 | } else { |
2b5f94fa | 17 | const param = document.location.href.match(/logging=([A-Za-z0-9._-]*)/); |
a7fe079f | 18 | mainInitLogging(param || undefined); |
2cde6e43 | 19 | } |
8727f598 | 20 | } |
8d5d2c82 | 21 | |
8d5d2c82 | 22 | // Read a query string variable |
2c5491e1 | 23 | export 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 | 37 | export 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 | 52 | export 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 | 68 | export 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 | 88 | export 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 | 106 | export 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 | 115 | let settings = {}; |
6d6f0db0 | 116 | |
1c9b904d JD |
117 | export 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 | 128 | export function setSetting(name, value) { |
e0750f9b | 129 | settings[name] = value; |
8727f598 | 130 | } |
e0750f9b | 131 | |
3af1c275 | 132 | // No days means only for this browser session |
2c5491e1 | 133 | export 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 | 144 | export 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 | 164 | export 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 | 179 | export 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 |
213 | export 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 | } |