@jsenv/core 29.8.5 → 29.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/babel_helpers/iterableToArrayLimit/iterableToArrayLimit.js +21 -5
- package/dist/babel_helpers/iterableToArrayLimitLoose/iterableToArrayLimitLoose.js +8 -6
- package/dist/js/autoreload.js +1 -1
- package/dist/js/s.js +22 -5
- package/dist/js/s.js.map +9 -7
- package/dist/main.js +50 -2085
- package/package.json +8 -8
- package/src/build/build.js +33 -33
- package/src/plugins/plugins.js +1 -1
- package/src/plugins/ribbon/jsenv_plugin_ribbon.js +6 -1
- package/src/plugins/url_resolution/jsenv_plugin_url_resolution.js +6 -2
- package/src/plugins/url_resolution/node_esm_resolver.js +6 -1
- package/dist/js/html_src_set.js +0 -20
- package/src/plugins/toolbar/client/animation/toolbar_animation.js +0 -39
- package/src/plugins/toolbar/client/eventsource/eventsource.css +0 -83
- package/src/plugins/toolbar/client/eventsource/toolbar_eventsource.js +0 -57
- package/src/plugins/toolbar/client/execution/execution.css +0 -79
- package/src/plugins/toolbar/client/execution/toolbar_execution.js +0 -88
- package/src/plugins/toolbar/client/focus/focus.css +0 -61
- package/src/plugins/toolbar/client/focus/toolbar_focus.js +0 -19
- package/src/plugins/toolbar/client/jsenv_logo.svg +0 -140
- package/src/plugins/toolbar/client/notification/toolbar_notification.js +0 -181
- package/src/plugins/toolbar/client/responsive/overflow_menu.css +0 -61
- package/src/plugins/toolbar/client/responsive/toolbar_responsive.js +0 -103
- package/src/plugins/toolbar/client/settings/settings.css +0 -201
- package/src/plugins/toolbar/client/settings/toolbar_settings.js +0 -47
- package/src/plugins/toolbar/client/theme/jsenv_theme.css +0 -77
- package/src/plugins/toolbar/client/theme/light_theme.css +0 -106
- package/src/plugins/toolbar/client/theme/toolbar_theme.js +0 -34
- package/src/plugins/toolbar/client/toolbar.html +0 -457
- package/src/plugins/toolbar/client/toolbar_injector.js +0 -218
- package/src/plugins/toolbar/client/toolbar_main.css +0 -172
- package/src/plugins/toolbar/client/toolbar_main.js +0 -197
- package/src/plugins/toolbar/client/tooltip/tooltip.css +0 -61
- package/src/plugins/toolbar/client/tooltip/tooltip.js +0 -39
- package/src/plugins/toolbar/client/util/animation.js +0 -305
- package/src/plugins/toolbar/client/util/dom.js +0 -108
- package/src/plugins/toolbar/client/util/fetch_using_xhr.js +0 -400
- package/src/plugins/toolbar/client/util/fetching.js +0 -14
- package/src/plugins/toolbar/client/util/iframe_to_parent_href.js +0 -10
- package/src/plugins/toolbar/client/util/jsenv_logger.js +0 -28
- package/src/plugins/toolbar/client/util/preferences.js +0 -10
- package/src/plugins/toolbar/client/util/responsive.js +0 -112
- package/src/plugins/toolbar/client/util/util.js +0 -19
- package/src/plugins/toolbar/client/variant/variant.js +0 -74
- package/src/plugins/toolbar/jsenv_plugin_toolbar.js +0 -62
|
@@ -1,400 +0,0 @@
|
|
|
1
|
-
export const fetchUsingXHR = async (
|
|
2
|
-
url,
|
|
3
|
-
{
|
|
4
|
-
signal,
|
|
5
|
-
method = "GET",
|
|
6
|
-
credentials = "same-origin",
|
|
7
|
-
headers = {},
|
|
8
|
-
body = null,
|
|
9
|
-
} = {},
|
|
10
|
-
) => {
|
|
11
|
-
const headersPromise = createPromiseAndHooks()
|
|
12
|
-
const bodyPromise = createPromiseAndHooks()
|
|
13
|
-
|
|
14
|
-
const xhr = new XMLHttpRequest()
|
|
15
|
-
|
|
16
|
-
const failure = (error) => {
|
|
17
|
-
// if it was already resolved, we must reject the body promise
|
|
18
|
-
if (headersPromise.settled) {
|
|
19
|
-
bodyPromise.reject(error)
|
|
20
|
-
} else {
|
|
21
|
-
headersPromise.reject(error)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const cleanup = () => {
|
|
26
|
-
xhr.ontimeout = null
|
|
27
|
-
xhr.onerror = null
|
|
28
|
-
xhr.onload = null
|
|
29
|
-
xhr.onreadystatechange = null
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
xhr.ontimeout = () => {
|
|
33
|
-
cleanup()
|
|
34
|
-
failure(new Error(`xhr request timeout on ${url}.`))
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
xhr.onerror = (error) => {
|
|
38
|
-
cleanup()
|
|
39
|
-
// unfortunately with have no clue why it fails
|
|
40
|
-
// might be cors for instance
|
|
41
|
-
failure(createRequestError(error, { url }))
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
xhr.onload = () => {
|
|
45
|
-
cleanup()
|
|
46
|
-
bodyPromise.resolve()
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
signal.addEventListener("abort", () => {
|
|
50
|
-
xhr.abort()
|
|
51
|
-
const abortError = new Error("aborted")
|
|
52
|
-
abortError.name = "AbortError"
|
|
53
|
-
failure(abortError)
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
xhr.onreadystatechange = () => {
|
|
57
|
-
// https://developer.mozilla.org/fr/docs/Web/API/XMLHttpRequest/readyState
|
|
58
|
-
const { readyState } = xhr
|
|
59
|
-
|
|
60
|
-
if (readyState === 2) {
|
|
61
|
-
headersPromise.resolve()
|
|
62
|
-
} else if (readyState === 4) {
|
|
63
|
-
cleanup()
|
|
64
|
-
bodyPromise.resolve()
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
xhr.open(method, url, true)
|
|
69
|
-
Object.keys(headers).forEach((key) => {
|
|
70
|
-
xhr.setRequestHeader(key, headers[key])
|
|
71
|
-
})
|
|
72
|
-
xhr.withCredentials = computeWithCredentials({ credentials, url })
|
|
73
|
-
if ("responseType" in xhr && hasBlob) {
|
|
74
|
-
xhr.responseType = "blob"
|
|
75
|
-
}
|
|
76
|
-
xhr.send(body)
|
|
77
|
-
|
|
78
|
-
await headersPromise
|
|
79
|
-
|
|
80
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseURL
|
|
81
|
-
const responseUrl =
|
|
82
|
-
"responseURL" in xhr ? xhr.responseURL : headers["x-request-url"]
|
|
83
|
-
let responseStatus = xhr.status
|
|
84
|
-
const responseStatusText = xhr.statusText
|
|
85
|
-
const responseHeaders = getHeadersFromXHR(xhr)
|
|
86
|
-
|
|
87
|
-
const readBody = async () => {
|
|
88
|
-
await bodyPromise
|
|
89
|
-
|
|
90
|
-
const { status } = xhr
|
|
91
|
-
// in Chrome on file:/// URLs, status is 0
|
|
92
|
-
if (status === 0) {
|
|
93
|
-
responseStatus = 200
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const body = "response" in xhr ? xhr.response : xhr.responseText
|
|
97
|
-
|
|
98
|
-
return {
|
|
99
|
-
responseBody: body,
|
|
100
|
-
responseBodyType: detectBodyType(body),
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const text = async () => {
|
|
105
|
-
const { responseBody, responseBodyType } = await readBody()
|
|
106
|
-
|
|
107
|
-
if (responseBodyType === "blob") {
|
|
108
|
-
return blobToText(responseBody)
|
|
109
|
-
}
|
|
110
|
-
if (responseBodyType === "formData") {
|
|
111
|
-
throw new Error("could not read FormData body as text")
|
|
112
|
-
}
|
|
113
|
-
if (responseBodyType === "dataView") {
|
|
114
|
-
return arrayBufferToText(responseBody.buffer)
|
|
115
|
-
}
|
|
116
|
-
if (responseBodyType === "arrayBuffer") {
|
|
117
|
-
return arrayBufferToText(responseBody)
|
|
118
|
-
}
|
|
119
|
-
return String(responseBody)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const json = async () => {
|
|
123
|
-
const responseText = await text()
|
|
124
|
-
return JSON.parse(responseText)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const blob = async () => {
|
|
128
|
-
if (!hasBlob) {
|
|
129
|
-
throw new Error(`blob not supported`)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const { responseBody, responseBodyType } = await readBody()
|
|
133
|
-
|
|
134
|
-
if (responseBodyType === "blob") {
|
|
135
|
-
return responseBody
|
|
136
|
-
}
|
|
137
|
-
if (responseBodyType === "dataView") {
|
|
138
|
-
return new Blob([cloneBuffer(responseBody.buffer)])
|
|
139
|
-
}
|
|
140
|
-
if (responseBodyType === "arrayBuffer") {
|
|
141
|
-
return new Blob([cloneBuffer(responseBody)])
|
|
142
|
-
}
|
|
143
|
-
if (responseBodyType === "formData") {
|
|
144
|
-
throw new Error("could not read FormData body as blob")
|
|
145
|
-
}
|
|
146
|
-
return new Blob([String(responseBody)])
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const arrayBuffer = async () => {
|
|
150
|
-
const { responseBody, responseBodyType } = await readBody()
|
|
151
|
-
|
|
152
|
-
if (responseBodyType === "arrayBuffer") {
|
|
153
|
-
return cloneBuffer(responseBody)
|
|
154
|
-
}
|
|
155
|
-
const responseBlob = await blob()
|
|
156
|
-
return blobToArrayBuffer(responseBlob)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const formData = async () => {
|
|
160
|
-
if (!hasFormData) {
|
|
161
|
-
throw new Error(`formData not supported`)
|
|
162
|
-
}
|
|
163
|
-
const responseText = await text()
|
|
164
|
-
return textToFormData(responseText)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return {
|
|
168
|
-
url: responseUrl,
|
|
169
|
-
status: responseStatus,
|
|
170
|
-
statusText: responseStatusText,
|
|
171
|
-
headers: responseHeaders,
|
|
172
|
-
text,
|
|
173
|
-
json,
|
|
174
|
-
blob,
|
|
175
|
-
arrayBuffer,
|
|
176
|
-
formData,
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const canUseBlob = () => {
|
|
181
|
-
if (typeof window.FileReader !== "function") return false
|
|
182
|
-
|
|
183
|
-
if (typeof window.Blob !== "function") return false
|
|
184
|
-
|
|
185
|
-
try {
|
|
186
|
-
// eslint-disable-next-line no-new
|
|
187
|
-
new Blob()
|
|
188
|
-
return true
|
|
189
|
-
} catch (e) {
|
|
190
|
-
return false
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const hasBlob = canUseBlob()
|
|
195
|
-
|
|
196
|
-
const hasFormData = typeof window.FormData === "function"
|
|
197
|
-
|
|
198
|
-
const hasArrayBuffer = typeof window.ArrayBuffer === "function"
|
|
199
|
-
|
|
200
|
-
const hasSearchParams = typeof window.URLSearchParams === "function"
|
|
201
|
-
|
|
202
|
-
const createRequestError = (error, { url }) => {
|
|
203
|
-
return new Error(
|
|
204
|
-
`error during xhr request on ${url}.
|
|
205
|
-
--- error stack ---
|
|
206
|
-
${error.stack}`,
|
|
207
|
-
)
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const createPromiseAndHooks = () => {
|
|
211
|
-
let resolve
|
|
212
|
-
let reject
|
|
213
|
-
const promise = new Promise((res, rej) => {
|
|
214
|
-
resolve = (value) => {
|
|
215
|
-
promise.settled = true
|
|
216
|
-
res(value)
|
|
217
|
-
}
|
|
218
|
-
reject = (value) => {
|
|
219
|
-
promise.settled = true
|
|
220
|
-
rej(value)
|
|
221
|
-
}
|
|
222
|
-
})
|
|
223
|
-
promise.resolve = resolve
|
|
224
|
-
promise.reject = reject
|
|
225
|
-
return promise
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
|
|
229
|
-
const computeWithCredentials = ({ credentials, url }) => {
|
|
230
|
-
if (credentials === "same-origin") {
|
|
231
|
-
return originSameAsGlobalOrigin(url)
|
|
232
|
-
}
|
|
233
|
-
return credentials === "include"
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const originSameAsGlobalOrigin = (url) => {
|
|
237
|
-
// if we cannot read globalOrigin from window.location.origin, let's consider it's ok
|
|
238
|
-
if (typeof window !== "object") return true
|
|
239
|
-
if (typeof window.location !== "object") return true
|
|
240
|
-
const globalOrigin = window.location.origin
|
|
241
|
-
if (globalOrigin === "null") return true
|
|
242
|
-
return hrefToOrigin(url) === globalOrigin
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const detectBodyType = (body) => {
|
|
246
|
-
if (!body) {
|
|
247
|
-
return ""
|
|
248
|
-
}
|
|
249
|
-
if (typeof body === "string") {
|
|
250
|
-
return "text"
|
|
251
|
-
}
|
|
252
|
-
if (hasBlob && Blob.prototype.isPrototypeOf(body)) {
|
|
253
|
-
return "blob"
|
|
254
|
-
}
|
|
255
|
-
if (hasFormData && FormData.prototype.isPrototypeOf(body)) {
|
|
256
|
-
return "formData"
|
|
257
|
-
}
|
|
258
|
-
if (hasArrayBuffer) {
|
|
259
|
-
if (hasBlob && isDataView(body)) {
|
|
260
|
-
return `dataView`
|
|
261
|
-
}
|
|
262
|
-
if (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body)) {
|
|
263
|
-
return `arrayBuffer`
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
if (hasSearchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
|
|
267
|
-
return "searchParams"
|
|
268
|
-
}
|
|
269
|
-
return ""
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders#Example
|
|
273
|
-
const getHeadersFromXHR = (xhr) => {
|
|
274
|
-
const headerMap = {}
|
|
275
|
-
|
|
276
|
-
const headersString = xhr.getAllResponseHeaders()
|
|
277
|
-
if (headersString === "") return headerMap
|
|
278
|
-
|
|
279
|
-
const lines = headersString.trim().split(/[\r\n]+/)
|
|
280
|
-
lines.forEach((line) => {
|
|
281
|
-
const parts = line.split(": ")
|
|
282
|
-
const name = parts.shift()
|
|
283
|
-
const value = parts.join(": ")
|
|
284
|
-
headerMap[name.toLowerCase()] = value
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
return headerMap
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
const hrefToOrigin = (href) => {
|
|
291
|
-
const scheme = hrefToScheme(href)
|
|
292
|
-
|
|
293
|
-
if (scheme === "file") {
|
|
294
|
-
return "file://"
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (scheme === "http" || scheme === "https") {
|
|
298
|
-
const secondProtocolSlashIndex = scheme.length + "://".length
|
|
299
|
-
const pathnameSlashIndex = href.indexOf("/", secondProtocolSlashIndex)
|
|
300
|
-
|
|
301
|
-
if (pathnameSlashIndex === -1) return href
|
|
302
|
-
return href.slice(0, pathnameSlashIndex)
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return href.slice(0, scheme.length + 1)
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
const hrefToScheme = (href) => {
|
|
309
|
-
const colonIndex = href.indexOf(":")
|
|
310
|
-
if (colonIndex === -1) return ""
|
|
311
|
-
return href.slice(0, colonIndex)
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const isDataView = (obj) => {
|
|
315
|
-
return obj && DataView.prototype.isPrototypeOf(obj)
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const isArrayBufferView =
|
|
319
|
-
ArrayBuffer.isView ||
|
|
320
|
-
(() => {
|
|
321
|
-
const viewClasses = [
|
|
322
|
-
"[object Int8Array]",
|
|
323
|
-
"[object Uint8Array]",
|
|
324
|
-
"[object Uint8ClampedArray]",
|
|
325
|
-
"[object Int16Array]",
|
|
326
|
-
"[object Uint16Array]",
|
|
327
|
-
"[object Int32Array]",
|
|
328
|
-
"[object Uint32Array]",
|
|
329
|
-
"[object Float32Array]",
|
|
330
|
-
"[object Float64Array]",
|
|
331
|
-
]
|
|
332
|
-
|
|
333
|
-
return (value) => {
|
|
334
|
-
return (
|
|
335
|
-
value && viewClasses.includes(Object.prototype.toString.call(value))
|
|
336
|
-
)
|
|
337
|
-
}
|
|
338
|
-
})()
|
|
339
|
-
|
|
340
|
-
const textToFormData = (text) => {
|
|
341
|
-
const form = new FormData()
|
|
342
|
-
text
|
|
343
|
-
.trim()
|
|
344
|
-
.split("&")
|
|
345
|
-
.forEach(function (bytes) {
|
|
346
|
-
if (bytes) {
|
|
347
|
-
const split = bytes.split("=")
|
|
348
|
-
const name = split.shift().replace(/\+/g, " ")
|
|
349
|
-
const value = split.join("=").replace(/\+/g, " ")
|
|
350
|
-
form.append(decodeURIComponent(name), decodeURIComponent(value))
|
|
351
|
-
}
|
|
352
|
-
})
|
|
353
|
-
return form
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
const blobToArrayBuffer = async (blob) => {
|
|
357
|
-
const reader = new FileReader()
|
|
358
|
-
const promise = fileReaderReady(reader)
|
|
359
|
-
reader.readAsArrayBuffer(blob)
|
|
360
|
-
return promise
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
const blobToText = (blob) => {
|
|
364
|
-
const reader = new FileReader()
|
|
365
|
-
const promise = fileReaderReady(reader)
|
|
366
|
-
reader.readAsText(blob)
|
|
367
|
-
return promise
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
const arrayBufferToText = (arrayBuffer) => {
|
|
371
|
-
const view = new Uint8Array(arrayBuffer)
|
|
372
|
-
const chars = new Array(view.length)
|
|
373
|
-
let i = 0
|
|
374
|
-
while (i < view.length) {
|
|
375
|
-
chars[i] = String.fromCharCode(view[i])
|
|
376
|
-
|
|
377
|
-
i++
|
|
378
|
-
}
|
|
379
|
-
return chars.join("")
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
const fileReaderReady = (reader) => {
|
|
383
|
-
return new Promise(function (resolve, reject) {
|
|
384
|
-
reader.onload = function () {
|
|
385
|
-
resolve(reader.result)
|
|
386
|
-
}
|
|
387
|
-
reader.onerror = function () {
|
|
388
|
-
reject(reader.error)
|
|
389
|
-
}
|
|
390
|
-
})
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const cloneBuffer = (buffer) => {
|
|
394
|
-
if (buffer.slice) {
|
|
395
|
-
return buffer.slice(0)
|
|
396
|
-
}
|
|
397
|
-
const view = new Uint8Array(buffer.byteLength)
|
|
398
|
-
view.set(new Uint8Array(buffer))
|
|
399
|
-
return view.buffer
|
|
400
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { memoize } from "@jsenv/utils/src/memoize/memoize.js"
|
|
2
|
-
|
|
3
|
-
const fetchPolyfill = async (...args) => {
|
|
4
|
-
const { fetchUsingXHR } = await loadPolyfill()
|
|
5
|
-
return fetchUsingXHR(...args)
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const loadPolyfill = memoize(() => import("./fetch_using_xhr.js"))
|
|
9
|
-
|
|
10
|
-
export const fetchUrl =
|
|
11
|
-
typeof window.fetch === "function" &&
|
|
12
|
-
typeof window.AbortController === "function"
|
|
13
|
-
? window.fetch
|
|
14
|
-
: fetchPolyfill
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
const JSENV_LOG_ENABLED = false
|
|
2
|
-
|
|
3
|
-
export const jsenvLogger = {
|
|
4
|
-
log: (...args) => {
|
|
5
|
-
// prevent logs for now (do not mess with user logs)
|
|
6
|
-
if (JSENV_LOG_ENABLED) {
|
|
7
|
-
console.log(...prefixArgs(...args))
|
|
8
|
-
}
|
|
9
|
-
},
|
|
10
|
-
|
|
11
|
-
debug: (...args) => {
|
|
12
|
-
if (JSENV_LOG_ENABLED) {
|
|
13
|
-
console.log(...prefixArgs(...args))
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// a nice yellow:ffdc00
|
|
19
|
-
const backgroundColor = "#F7931E" // jsenv logo color
|
|
20
|
-
|
|
21
|
-
// eslint-disable-next-line no-unused-vars
|
|
22
|
-
const prefixArgs = (...args) => {
|
|
23
|
-
return [
|
|
24
|
-
`%cjsenv`,
|
|
25
|
-
`background: ${backgroundColor}; color: black; padding: 1px 3px; margin: 0 1px`,
|
|
26
|
-
...args,
|
|
27
|
-
]
|
|
28
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export const createPreference = (name) => {
|
|
2
|
-
return {
|
|
3
|
-
has: () => localStorage.hasOwnProperty(name),
|
|
4
|
-
get: () =>
|
|
5
|
-
localStorage.hasOwnProperty(name)
|
|
6
|
-
? JSON.parse(localStorage.getItem(name))
|
|
7
|
-
: undefined,
|
|
8
|
-
set: (value) => localStorage.setItem(name, JSON.stringify(value)),
|
|
9
|
-
}
|
|
10
|
-
}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
export const createHorizontalBreakpoint = (breakpointValue) => {
|
|
2
|
-
return createBreakpoint(windowWidthMeasure, breakpointValue)
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
const createMeasure = ({ compute, register }) => {
|
|
6
|
-
let currentValue = compute()
|
|
7
|
-
|
|
8
|
-
const get = () => compute()
|
|
9
|
-
|
|
10
|
-
const changed = createSignal()
|
|
11
|
-
|
|
12
|
-
let unregister = () => {}
|
|
13
|
-
if (register) {
|
|
14
|
-
unregister = register(() => {
|
|
15
|
-
const value = compute()
|
|
16
|
-
if (value !== currentValue) {
|
|
17
|
-
const previousValue = value
|
|
18
|
-
currentValue = value
|
|
19
|
-
changed.notify(value, previousValue)
|
|
20
|
-
}
|
|
21
|
-
})
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return { get, changed, unregister }
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const createSignal = () => {
|
|
28
|
-
const callbackArray = []
|
|
29
|
-
|
|
30
|
-
const listen = (callback) => {
|
|
31
|
-
callbackArray.push(callback)
|
|
32
|
-
return () => {
|
|
33
|
-
const index = callbackArray.indexOf(callback)
|
|
34
|
-
if (index > -1) {
|
|
35
|
-
callbackArray.splice(index, 1)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const notify = (...args) => {
|
|
41
|
-
callbackArray.slice().forEach((callback) => {
|
|
42
|
-
callback(...args)
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return { listen, notify }
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const windowWidthMeasure = createMeasure({
|
|
50
|
-
name: "window-width",
|
|
51
|
-
compute: () => window.innerWidth,
|
|
52
|
-
register: (onchange) => {
|
|
53
|
-
window.addEventListener("resize", onchange)
|
|
54
|
-
window.addEventListener("orientationchange", onchange)
|
|
55
|
-
return () => {
|
|
56
|
-
window.removeEventListener("resize", onchange)
|
|
57
|
-
window.removeEventListener("orientationchange", onchange)
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
const createBreakpoint = (measure, breakpointValue) => {
|
|
63
|
-
const getBreakpointState = () => {
|
|
64
|
-
const value = measure.get()
|
|
65
|
-
|
|
66
|
-
if (value < breakpointValue) {
|
|
67
|
-
return "below"
|
|
68
|
-
}
|
|
69
|
-
if (value > breakpointValue) {
|
|
70
|
-
return "above"
|
|
71
|
-
}
|
|
72
|
-
return "equals"
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
let currentBreakpointState = getBreakpointState()
|
|
76
|
-
|
|
77
|
-
const isAbove = () => {
|
|
78
|
-
return measure.get() > breakpointValue
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const isBelow = () => {
|
|
82
|
-
return measure.get() < breakpointValue
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const breakpointChanged = createSignal()
|
|
86
|
-
|
|
87
|
-
measure.changed.listen(() => {
|
|
88
|
-
const breakpointState = getBreakpointState()
|
|
89
|
-
if (breakpointState !== currentBreakpointState) {
|
|
90
|
-
const breakpointStatePrevious = currentBreakpointState
|
|
91
|
-
currentBreakpointState = breakpointState
|
|
92
|
-
breakpointChanged.notify(breakpointState, breakpointStatePrevious)
|
|
93
|
-
}
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
isAbove,
|
|
98
|
-
isBelow,
|
|
99
|
-
changed: breakpointChanged,
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// const windowScrollTop = createMeasure({
|
|
104
|
-
// name: "window-scroll-top",
|
|
105
|
-
// compute: () => window.scrollTop,
|
|
106
|
-
// register: (onchange) => {
|
|
107
|
-
// window.addEventListener("scroll", onchange)
|
|
108
|
-
// return () => {
|
|
109
|
-
// window.removeEventListener("scroll", onchange)
|
|
110
|
-
// }
|
|
111
|
-
// },
|
|
112
|
-
// })
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export const createPromiseAndHooks = () => {
|
|
2
|
-
let resolve
|
|
3
|
-
let reject
|
|
4
|
-
const promise = new Promise((res, rej) => {
|
|
5
|
-
resolve = res
|
|
6
|
-
reject = rej
|
|
7
|
-
})
|
|
8
|
-
promise.resolve = resolve
|
|
9
|
-
promise.reject = reject
|
|
10
|
-
return promise
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const moveElement = (element, from, to) => {
|
|
14
|
-
to.appendChild(element)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const replaceElement = (elementToReplace, otherElement) => {
|
|
18
|
-
elementToReplace.parentNode.replaceChild(otherElement, elementToReplace)
|
|
19
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
export const enableVariant = (rootNode, variables) => {
|
|
2
|
-
const nodesNotMatching = Array.from(
|
|
3
|
-
rootNode.querySelectorAll(`[${attributeIndicatingACondition}]`),
|
|
4
|
-
)
|
|
5
|
-
nodesNotMatching.forEach((nodeNotMatching) => {
|
|
6
|
-
const conditionAttributeValue = nodeNotMatching.getAttribute(
|
|
7
|
-
attributeIndicatingACondition,
|
|
8
|
-
)
|
|
9
|
-
const matches = testCondition(conditionAttributeValue, variables)
|
|
10
|
-
if (matches) {
|
|
11
|
-
renameAttribute(
|
|
12
|
-
nodeNotMatching,
|
|
13
|
-
attributeIndicatingACondition,
|
|
14
|
-
attributeIndicatingAMatch,
|
|
15
|
-
)
|
|
16
|
-
}
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
const nodesMatching = Array.from(
|
|
20
|
-
rootNode.querySelectorAll(`[${attributeIndicatingAMatch}]`),
|
|
21
|
-
)
|
|
22
|
-
nodesMatching.forEach((nodeMatching) => {
|
|
23
|
-
const conditionAttributeValue = nodeMatching.getAttribute(
|
|
24
|
-
attributeIndicatingAMatch,
|
|
25
|
-
)
|
|
26
|
-
const matches = testCondition(conditionAttributeValue, variables)
|
|
27
|
-
if (!matches) {
|
|
28
|
-
renameAttribute(
|
|
29
|
-
nodeMatching,
|
|
30
|
-
attributeIndicatingAMatch,
|
|
31
|
-
attributeIndicatingACondition,
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const testCondition = (conditionAttributeValue, variables) => {
|
|
38
|
-
const condition = parseCondition(conditionAttributeValue)
|
|
39
|
-
return Object.keys(variables).some((key) => {
|
|
40
|
-
if (condition.key !== key) {
|
|
41
|
-
return false
|
|
42
|
-
}
|
|
43
|
-
// the condition do not specify a value, any value is ok
|
|
44
|
-
if (condition.value === undefined) {
|
|
45
|
-
return true
|
|
46
|
-
}
|
|
47
|
-
if (condition.value === variables[key]) {
|
|
48
|
-
return true
|
|
49
|
-
}
|
|
50
|
-
return false
|
|
51
|
-
})
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const parseCondition = (conditionAttributeValue) => {
|
|
55
|
-
const colonIndex = conditionAttributeValue.indexOf(":")
|
|
56
|
-
if (colonIndex === -1) {
|
|
57
|
-
return {
|
|
58
|
-
key: conditionAttributeValue,
|
|
59
|
-
value: undefined,
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
key: conditionAttributeValue.slice(0, colonIndex),
|
|
64
|
-
value: conditionAttributeValue.slice(colonIndex + 1),
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const attributeIndicatingACondition = `data-when`
|
|
69
|
-
const attributeIndicatingAMatch = `data-when-active`
|
|
70
|
-
|
|
71
|
-
const renameAttribute = (node, name, newName) => {
|
|
72
|
-
node.setAttribute(newName, node.getAttribute(name))
|
|
73
|
-
node.removeAttribute(name)
|
|
74
|
-
}
|