]>
Commit | Line | Data |
---|---|---|
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 | 10 | import { init_logging as main_init_logging } from '../core/util/logging.js'; |
8d5d2c82 AM |
11 | |
12 | // init log level reading the logging HTTP param | |
6d6f0db0 | 13 | export 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 | 24 | export 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 | 38 | export 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 | 53 | export 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 | 69 | export 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 | 89 | export 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 | 107 | export 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 | 116 | let settings = {}; |
6d6f0db0 SR |
117 | |
118 | export function initSettings (callback /*, ...callbackArgs */) { | |
ee7d4c61 | 119 | "use strict"; |
2b5f94fa | 120 | const callbackArgs = Array.prototype.slice.call(arguments, 1); |
d5fe1509 JM |
121 | if (window.chrome && window.chrome.storage) { |
122 | window.chrome.storage.sync.get(function (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 |
137 | export function setSetting (name, value) { | |
138 | settings[name] = value; | |
8727f598 | 139 | } |
e0750f9b | 140 | |
3af1c275 | 141 | // No days means only for this browser session |
6d6f0db0 | 142 | export 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 | 153 | export 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 | 173 | export 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 | 188 | export 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 | ||
204 | if (!query.some(function (v) { return v.startsWith(param_eq); })) { | |
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 | 222 | export 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 | ||
227 | req.onload = function () { | |
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 | ||
241 | req.onerror = function (evt) { | |
242 | reject(new Error("XHR encountered an error while trying to load '" + path + "': " + evt.message)); | |
243 | }; | |
244 | ||
245 | req.ontimeout = function (evt) { | |
246 | reject(new Error("XHR timed out while trying to load '" + path + "'")); | |
247 | }; | |
248 | ||
249 | req.send(); | |
6d6f0db0 | 250 | } |