@webqit/webflo 0.11.61 → 1.0.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.
Files changed (66) hide show
  1. package/package.json +1 -1
  2. package/src/{Context.js → AbstractContext.js} +1 -9
  3. package/src/deployment-pi/origins/index.js +1 -1
  4. package/src/index.js +1 -9
  5. package/src/runtime-pi/HttpEvent.js +101 -81
  6. package/src/runtime-pi/HttpUser.js +126 -0
  7. package/src/runtime-pi/MessagingOverBroadcast.js +9 -0
  8. package/src/runtime-pi/MessagingOverChannel.js +85 -0
  9. package/src/runtime-pi/MessagingOverSocket.js +106 -0
  10. package/src/runtime-pi/MultiportMessagingAPI.js +81 -0
  11. package/src/runtime-pi/WebfloCookieStorage.js +27 -0
  12. package/src/runtime-pi/WebfloEventTarget.js +39 -0
  13. package/src/runtime-pi/WebfloMessageEvent.js +58 -0
  14. package/src/runtime-pi/WebfloMessagingAPI.js +69 -0
  15. package/src/runtime-pi/{Router.js → WebfloRouter.js} +3 -34
  16. package/src/runtime-pi/WebfloRuntime.js +52 -0
  17. package/src/runtime-pi/WebfloStorage.js +109 -0
  18. package/src/runtime-pi/client/ClientMessaging.js +5 -0
  19. package/src/runtime-pi/client/Context.js +2 -6
  20. package/src/runtime-pi/client/CookieStorage.js +17 -0
  21. package/src/runtime-pi/client/Router.js +3 -13
  22. package/src/runtime-pi/client/SessionStorage.js +33 -0
  23. package/src/runtime-pi/client/Url.js +24 -72
  24. package/src/runtime-pi/client/WebfloClient.js +544 -0
  25. package/src/runtime-pi/client/WebfloRootClient1.js +179 -0
  26. package/src/runtime-pi/client/WebfloRootClient2.js +109 -0
  27. package/src/runtime-pi/client/WebfloSubClient.js +165 -0
  28. package/src/runtime-pi/client/Workport.js +89 -161
  29. package/src/runtime-pi/client/generate.js +1 -1
  30. package/src/runtime-pi/client/index.js +13 -18
  31. package/src/runtime-pi/client/worker/ClientMessaging.js +5 -0
  32. package/src/runtime-pi/client/worker/Context.js +2 -6
  33. package/src/runtime-pi/client/worker/CookieStorage.js +17 -0
  34. package/src/runtime-pi/client/worker/SessionStorage.js +13 -0
  35. package/src/runtime-pi/client/worker/WebfloWorker.js +294 -0
  36. package/src/runtime-pi/client/worker/Workport.js +13 -73
  37. package/src/runtime-pi/client/worker/index.js +7 -18
  38. package/src/runtime-pi/index.js +1 -8
  39. package/src/runtime-pi/server/ClientMessaging.js +18 -0
  40. package/src/runtime-pi/server/ClientMessagingRegistry.js +57 -0
  41. package/src/runtime-pi/server/Context.js +2 -6
  42. package/src/runtime-pi/server/CookieStorage.js +17 -0
  43. package/src/runtime-pi/server/Router.js +2 -68
  44. package/src/runtime-pi/server/SessionStorage.js +53 -0
  45. package/src/runtime-pi/server/WebfloServer.js +755 -0
  46. package/src/runtime-pi/server/index.js +7 -18
  47. package/src/runtime-pi/util-http.js +268 -32
  48. package/src/runtime-pi/xURL.js +25 -22
  49. package/src/runtime-pi/xfetch.js +2 -2
  50. package/src/runtime-pi/Application.js +0 -29
  51. package/src/runtime-pi/Cookies.js +0 -82
  52. package/src/runtime-pi/Runtime.js +0 -21
  53. package/src/runtime-pi/client/Application.js +0 -76
  54. package/src/runtime-pi/client/Runtime.js +0 -525
  55. package/src/runtime-pi/client/createStorage.js +0 -58
  56. package/src/runtime-pi/client/worker/Application.js +0 -44
  57. package/src/runtime-pi/client/worker/Runtime.js +0 -275
  58. package/src/runtime-pi/server/Application.js +0 -101
  59. package/src/runtime-pi/server/Runtime.js +0 -558
  60. package/src/runtime-pi/xFormData.js +0 -24
  61. package/src/runtime-pi/xHeaders.js +0 -146
  62. package/src/runtime-pi/xRequest.js +0 -46
  63. package/src/runtime-pi/xRequestHeaders.js +0 -109
  64. package/src/runtime-pi/xResponse.js +0 -33
  65. package/src/runtime-pi/xResponseHeaders.js +0 -117
  66. package/src/runtime-pi/xxHttpMessage.js +0 -102
@@ -1,525 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import { _before, _toTitle } from '@webqit/util/str/index.js';
6
- import createStorage from './createStorage.js';
7
- import Url from './Url.js';
8
- import Workport from './Workport.js';
9
- import xRequest from "../xRequest.js";
10
- import xResponse from "../xResponse.js";
11
- import xfetch from '../xfetch.js';
12
- import HttpEvent from '../HttpEvent.js';
13
- import _Runtime from '../Runtime.js';
14
- import { params } from '../util-url.js';
15
-
16
- const { Observer } = webqit;
17
-
18
- export {
19
- HttpEvent,
20
- Observer,
21
- }
22
-
23
- export default class Runtime extends _Runtime {
24
-
25
- /**
26
- * Runtime
27
- *
28
- * @param Object cx
29
- * @param Function applicationInstance
30
- *
31
- * @return void
32
- */
33
- constructor(cx, applicationInstance) {
34
- super(cx, applicationInstance);
35
- // -----------------------
36
- // Initialize location
37
- Observer.set(this, 'location', new Url(window.document.location));
38
- Observer.set(this, 'network', {});
39
- window.addEventListener('online', () => Observer.set(this.network, 'connectivity', 'online'));
40
- window.addEventListener('offline', () => Observer.set(this.network, 'connectivity', 'offline'));
41
- this.useNavigationAPI = window.navigation;
42
- // -----------------------
43
- // Initialise API
44
- if (this.useNavigationAPI) {
45
- this.home = window.navigation.currentEntry;
46
- this._initNavigationAPI();
47
- } else { this._initLegacyAPI(); }
48
- // -----------------------
49
- // Service Worker && COMM
50
- if (this.cx.params.service_worker?.filename) {
51
- const { public_base_url: base, service_worker: { filename, ...serviceWorkerParams }, env } = this.cx.params;
52
- const workport = new Workport(base + filename, { ...serviceWorkerParams, startMessages: true }, env);
53
- Observer.set(this, 'workport', workport);
54
- }
55
- // -----------------------
56
- // Initialize and Hydration
57
- (async () => {
58
- let shouldHydrate;
59
- if (this.app.init) {
60
- const request = this.generateRequest(this.location);
61
- const httpEvent = new HttpEvent(request, { navigationType: 'init' }, (id = null, persistent = false) => this.getSession(httpEvent, id, persistent));
62
- shouldHydrate = await this.app.init(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
63
- }
64
- if (shouldHydrate !== false) {
65
- this.go(this.location, {}, { navigationType: 'startup', navigationOrigins: [], });
66
- }
67
- })();
68
- }
69
-
70
- _initLegacyAPI() {
71
- const updateLocation = (navigationOrigins, newHref) => {
72
- const scrollContainer = this._getScrollContainer();
73
- try { window.history.replaceState({
74
- ...(this.currentEntry().getState() || {}),
75
- navigationOrigins: this._serializeOrigins(navigationOrigins),
76
- scrollPosition: scrollContainer === window ? [] : [ scrollContainer.scrollLeft, scrollContainer.scrollTop, ],
77
- }, '', window.location.href); } catch(e) {}
78
- try { window.history.pushState({}, '', newHref); } catch(e) {}
79
- };
80
- // -----------------------
81
- // Capture all link-clicks
82
- // and fire to this router.
83
- window.addEventListener('click', e => {
84
- if (!this._canIntercept(e)) return;
85
- var anchorEl = e.target.closest('a');
86
- if (!anchorEl || !anchorEl.href || anchorEl.target || anchorEl.download || !this.isSpaRoute(anchorEl)) return;
87
- if (this.isHashChange(anchorEl)) {
88
- Observer.set(this.location, 'href', anchorEl.href);
89
- return;
90
- }
91
- // ---------------
92
- // Handle now
93
- e.preventDefault();
94
- this._abortController?.abort();
95
- this._abortController = new AbortController();
96
- // Note the order of calls below
97
- const detail = {
98
- navigationType: 'push',
99
- navigationOrigins: [ anchorEl ],
100
- destination: this._asEntry(null),
101
- source: this.currentEntry(), // this
102
- userInitiated: true,
103
- };
104
- updateLocation([ anchorEl ], anchorEl.href); // this
105
- this.go(
106
- Url.copy(anchorEl),
107
- { signal: this._abortController.signal, },
108
- detail,
109
- ); // this
110
- });
111
- // -----------------------
112
- // Capture all form-submit
113
- // and fire to this router.
114
- window.addEventListener('submit', e => {
115
- if (!this._canIntercept(e)) return;
116
- // ---------------
117
- // Declare form submission modifyers
118
- const form = e.target.closest('form'), submitter = e.submitter;
119
- const submitParams = [ 'action', 'enctype', 'method', 'noValidate', 'target' ].reduce((params, prop) => {
120
- params[prop] = submitter && submitter.hasAttribute(`form${prop.toLowerCase()}`) ? submitter[`form${_toTitle(prop)}`] : form[prop];
121
- return params;
122
- }, {});
123
- submitParams.method = (submitter && submitter.dataset.formmethod) || form.dataset.method || submitParams.method;
124
- if (submitParams.target || !this.isSpaRoute(submitParams.action)) return;
125
- var actionEl = window.document.createElement('a');
126
- actionEl.href = submitParams.action;
127
- if (this.isHashChange(anchorEl)) {
128
- Observer.set(this.location, 'href', anchorEl.href);
129
- return;
130
- }
131
- // ---------------
132
- // Handle now
133
- var formData = new FormData(form);
134
- if ((submitter || {}).name) { formData.set(submitter.name, submitter.value); }
135
- if (submitParams.method.toUpperCase() === 'GET') {
136
- var query = {};
137
- Array.from(formData.entries()).forEach(_entry => {
138
- params.set(query, _entry[0], _entry[1]);
139
- });
140
- actionEl.search = params.stringify(query);
141
- formData = null;
142
- }
143
- e.preventDefault();
144
- this._abortController?.abort();
145
- this._abortController = new AbortController();
146
- // Note the order of calls below
147
- const detail = {
148
- navigationType: 'push',
149
- navigationOrigins: [ submitter, form ],
150
- destination: this._asEntry(null),
151
- source: this.currentEntry(), // this
152
- userInitiated: true,
153
- };
154
- updateLocation([ submitter, form ], actionEl.href); // this
155
- this.go(
156
- Url.copy(actionEl),
157
- {
158
- method: submitParams.method,
159
- body: formData,
160
- signal: this._abortController.signal,
161
- },
162
- detail,
163
- ); // this
164
- });
165
- // -----------------------
166
- // This event is triggered by
167
- // either the browser back button,
168
- // the window.history.back(),
169
- // the window.history.forward(),
170
- // or the window.history.go() action.
171
- window.addEventListener('popstate', e => {
172
- if (this.isHashChange(location)) {
173
- Observer.set(this.location, 'href', location.href);
174
- return;
175
- }
176
- // Navigation details
177
- const detail = {
178
- navigationType: 'traverse',
179
- navigationOrigins: [],
180
- destination: this._asEntry(e.state),
181
- source: this.currentEntry(),
182
- userInitiated: true,
183
- };
184
- // Traversal?
185
- // Push
186
- const url = location.href;
187
- this.go(url, {}, detail);
188
- });
189
- }
190
-
191
- _initNavigationAPI() {
192
- // -----------------------
193
- // Detect source elements
194
- let navigationOrigins = [];
195
- window.addEventListener('click', e => {
196
- if (!this._canIntercept(e)) return;
197
- let anchorEl = e.target.closest('a');
198
- if (!anchorEl || !anchorEl.href || anchorEl.target) return;
199
- navigationOrigins = [ anchorEl ];
200
- });
201
- window.addEventListener('submit', e => {
202
- if (!this._canIntercept(e)) return;
203
- navigationOrigins = [ e.submitter, e.target.closest('form') ];
204
- });
205
- // -----------------------
206
- // Handle navigation event which happens after the above
207
- window.navigation.addEventListener('navigate', e => {
208
- if (!e.canIntercept || e.downloadRequest !== null) return;
209
- if (e.hashChange) {
210
- Observer.set(this.location, 'href', e.destination.url);
211
- return;
212
- }
213
- const { navigationType, destination, signal, formData, info, userInitiated } = e;
214
- if (formData && navigationOrigins[1]?.hasAttribute('webflo-no-intercept')) return;
215
- // Navigation details
216
- const detail = {
217
- navigationType,
218
- navigationOrigins,
219
- destination,
220
- source: this.currentEntry(),
221
- userInitiated,
222
- info,
223
- };
224
- const scrollContainer = this._getScrollContainer();
225
- this.updateCurrentEntry({ state: {
226
- ...(this.currentEntry().getState() || {}),
227
- navigationOrigins: this._serializeOrigins(navigationOrigins),
228
- scrollPosition: scrollContainer === window ? [] : [ scrollContainer.scrollLeft, scrollContainer.scrollTop, ],
229
- } });
230
- navigationOrigins = [];
231
- // Traversal?
232
- // Push
233
- const url = destination.url;
234
- const init = {
235
- method: formData && 'POST' || 'GET',
236
- body: formData,
237
- signal,
238
- };
239
- const nav = this;
240
- e.intercept({
241
- scroll: (scrollContainer !== window) && 'manual' || 'after-transition',
242
- focusReset: (scrollContainer !== window) && 'manual' || 'after-transition',
243
- async handler() { await nav.go(url, init, detail); },
244
- });
245
- });
246
- }
247
-
248
- _asEntry(state) { return { getState() { return state; } }; }
249
- _canIntercept(e) { return !(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey); }
250
- _uniqueId() { return ( 0 | Math.random() * 9e6 ).toString( 36 ); }
251
-
252
- _serializeOrigins(origins) {
253
- return origins.map(node => {
254
- let originId = node.getAttribute(this._webfloOriginIdAttr);
255
- if (!originId) {
256
- originId = this._uniqueId() + ':auto';
257
- node.setAttribute(this._webfloOriginIdAttr, originId);
258
- }
259
- return originId;
260
- });
261
- }
262
-
263
- _deserializeOrigins(origins) {
264
- return origins.map(originId => {
265
- const node = document.querySelector(`[${ this._webfloOriginIdAttr }="${ originId }"]`);
266
- if (node && originId.endsWith(':auto')) { node.toggleAttribute(this._webfloOriginIdAttr, false); }
267
- return node;
268
- });
269
- }
270
-
271
- _transitOrigins(origins, state, autoRevert = 0) {
272
- if (!window.webqit?.oohtml?.configs) return;
273
- const { BINDINGS_API: { api: bindingsConfig } = {}, } = window.webqit.oohtml.configs;
274
- origins.forEach(node => { node && (node[bindingsConfig.bindings].active = state); });
275
- if (!autoRevert) return;
276
- setTimeout(() => {
277
- origins.forEach(node => { node && (node[bindingsConfig.bindings].active = !state); });
278
- }, autoRevert);
279
- }
280
-
281
- _getScrollContainer() {
282
- if (!window.webqit?.oohtml?.configs) return;
283
- const { CONTEXT_API: { attr: contextConfig } = {}, } = window.webqit.oohtml.configs;
284
- return window.document.body.querySelector(`[${ window.CSS.escape( contextConfig.contextname ) }="app"]`) || window;
285
- }
286
-
287
- _webfloOriginIdAttr = 'webflo-navigation-origin-id';
288
- _xRedirectCode = 200;
289
-
290
- // Check is-hash-action
291
- isHashChange(urlObj) { return _before(this.location.href, '#') === _before(urlObj.href, '#') && (this.location.href.includes('#') || urlObj.href.includes('#')); }
292
-
293
- // Check is-spa-route
294
- isSpaRoute(url) {
295
- url = typeof url === 'string' ? new URL(url, this.location.origin) : url;
296
- if (url.origin && url.origin !== this.location.origin) return false;
297
- if (!this.cx.params.routing) return true;
298
- if (this.cx.params.routing.targets === false/** explicit false means disabled */) return false;
299
- let b = url.pathname.split('/').filter(s => s);
300
- const match = a => {
301
- a = a.split('/').filter(s => s);
302
- return a.reduce((prev, s, i) => prev && (s === b[i] || [s, b[i]].includes('-')), true);
303
- };
304
- return match(this.cx.params.routing.root) && this.cx.params.routing.subroots.reduce((prev, subroot) => {
305
- return prev && !match(subroot);
306
- }, true);
307
- }
308
-
309
- // Initiates remote fetch and sets the status
310
- async remoteFetch(request, ...args) {
311
- let href = request;
312
- if (request instanceof Request) {
313
- href = request.url;
314
- } else if (request instanceof URL) {
315
- href = request.href;
316
- }
317
- Observer.set(this.network, 'remote', href, { diff: true });
318
- let _response = xfetch(request, ...args);
319
- // Return xResponse
320
- return _response.then(async response => {
321
- // Stop loading status
322
- Observer.set(this.network, 'remote', null, { diff: true });
323
- return xResponse.compat(response);
324
- });
325
- }
326
-
327
- // Generates request object
328
- generateRequest(href, init = {}) {
329
- return new xRequest(href, {
330
- ...init,
331
- headers: {
332
- 'Accept': 'application/json',
333
- 'X-Redirect-Policy': 'manual-when-cross-spa',
334
- 'X-Redirect-Code': this._xRedirectCode,
335
- 'X-Powered-By': '@webqit/webflo',
336
- ...(init.headers || {}),
337
- },
338
- });
339
- }
340
-
341
- // Generates session object
342
- createStorage(e, id = null, persistent = false) {
343
- return createStorage(id, persistent);
344
- }
345
-
346
- // -----------------------------------------------
347
-
348
- /**
349
- * reload()
350
- */
351
- reload(params) {
352
- if (this.useNavigationAPI) { return window.navigation.reload(params); }
353
- return window.history.reload();
354
- }
355
-
356
- /**
357
- * back()
358
- */
359
- back() {
360
- if (this.useNavigationAPI) { return window.navigation.canGoBack && window.navigation.back(); }
361
- return window.history.back();
362
- }
363
-
364
- /**
365
- * forward()
366
- */
367
- forward() {
368
- if (this.useNavigationAPI) { return window.navigation.canGoForward && window.navigation.forward(); }
369
- return window.history.forward();
370
- }
371
-
372
- /**
373
- * go()
374
- */
375
- traverseTo(...args) {
376
- if (this.useNavigationAPI) { return window.navigation.traverseTo(...args); }
377
- return window.history.go(...args);
378
- }
379
-
380
- /**
381
- * entries()
382
- */
383
- entries() {
384
- if (this.useNavigationAPI) { return window.navigation.entries(); }
385
- return history;
386
- }
387
-
388
- /**
389
- * currentEntry()
390
- */
391
- currentEntry() {
392
- if (window.navigation) return window.navigation.currentEntry;
393
- return this._asEntry(history.state);
394
- }
395
-
396
- /**
397
- * updateCurrentEntry()
398
- */
399
- async updateCurrentEntry(params, url = null) {
400
- if (this.useNavigationAPI) {
401
- if (!url || url === window.navigation.currentEntry.url) {
402
- window.navigation.updateCurrentEntry(params);
403
- } else { await window.navigation.navigate(url, { ...params, history: 'replace' }).committed; }
404
- return;
405
- }
406
- window.history.replaceState(params.state, '', url);
407
- }
408
-
409
- /**
410
- * push()
411
- */
412
- async push(url, state = {}) {
413
- if (typeof url === 'string' && url.startsWith('&')) { url = this.location.href.split('#')[0] + (this.location.href.includes('?') ? url : url.replace('&', '?')); }
414
- url = new URL(url, this.location.href);
415
- if (this.useNavigationAPI) {
416
- await window.navigation.navigate(url.href, state).committed;
417
- } else { window.history.pushState(state, '', url.href); }
418
- Observer.set(this.location, 'href', url.href);
419
- }
420
-
421
- /**
422
- * Performs a request.
423
- *
424
- * @param object|string href
425
- * @param object|Request init
426
- * @param object src
427
- *
428
- * @return Response
429
- */
430
- async go(url, init = {}, detail = {}) {
431
- // ------------
432
- // Resolve inputs
433
- // ------------
434
- url = typeof url === 'string' ? new URL(url, this.location.origin) : url;
435
- if (!(init instanceof Request) && !init.referrer) { init = { referrer: this.location.href, ...init }; }
436
- if (![ 'startup', 'rdr' ].includes(detail.navigationType) && (_before(url.href, '#') === _before(init.referrer, '#') && (init.method || 'GET').toUpperCase() === 'GET')) return;
437
-
438
- // ------------
439
- // Pre-request states
440
- // ------------
441
- Observer.set(this.network, 'error', null, { diff: true });
442
- Observer.set(this.network, 'requesting', { init, detail });
443
- if (detail.navigationType !== 'traverse') { this._transitOrigins(detail.navigationOrigins, true); }
444
-
445
- // ------------
446
- // Request
447
- // ------------
448
- const request = this.generateRequest(url.href, init);
449
- const httpEvent = new HttpEvent(request, detail, (id = null, persistent = false) => this.createStorage(httpEvent, id, persistent));
450
- let response;
451
- try {
452
- // Fire request and obtain response
453
- response = await this.app.handle(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
454
- if (typeof response === 'undefined') { response = new xResponse(null, { status: 404 }); }
455
- else if (!(response instanceof xResponse)) { response = xResponse.compat(response); }
456
- } catch(e) {
457
- console.error(e);
458
- Observer.set(this.network, 'error', { ...e, retry: () => this.go(url, init, detail) });
459
- response = new xResponse(e.message, { status: 500 });
460
- }
461
- // Handle redirection
462
- const location = response.headers.get('Location');
463
- if (location) {
464
- const xActualRedirectCode = parseInt(response.headers.get('X-Redirect-Code'));
465
- if (xActualRedirectCode && response.status === this._xRedirectCode) {
466
- response.attrs.status = xActualRedirectCode; // @NOTE 1
467
- }
468
- if ([ 302,301 ].includes(response.status)) {
469
- Observer.set(this.network, 'redirecting', location, { diff: true });
470
- if (this.isSpaRoute(location)) {
471
- this.go(location, {}, { navigationType: 'rdr', navigationOrigins: [] });
472
- } else { window.location = location; }
473
- return;
474
- }
475
- }
476
-
477
- // ------------
478
- // // Post-request states
479
- // ------------
480
- const update = async () => {
481
- //Observer.set(this.location, newLocation);
482
- // Reset states
483
- Observer.set(this.network, 'requesting', null, { diff: true });
484
- Observer.set(this.network, 'redirecting', null, { diff: true });
485
- if ([ 404, 500 ].includes(response.status)) {
486
- Observer.set(this.network, 'error', new Error(response.statusText, { code: response.status }));
487
- }
488
- // Update location and render
489
- const finalUrl = response.url || request.url;
490
- Observer.set(this.location, 'href', finalUrl);
491
- const extraDetail = (await this.app.render?.(httpEvent, response), {});
492
- // Transit origins
493
- const scrollContainer = this._getScrollContainer();
494
- if (detail.navigationType === 'traverse') {
495
- const destinationState = detail.destination?.getState() || {};
496
- this._transitOrigins(this._deserializeOrigins(destinationState.navigationOrigins || []), true, 110);
497
- // Manual scrolling?
498
- if (scrollContainer !== window && destinationState.scrollPosition?.length) {
499
- scrollContainer.scroll(...destinationState.scrollPosition);
500
- (document.querySelector('[autofocus]') || document.body).focus();
501
- }
502
- } else {
503
- this._transitOrigins(detail.navigationOrigins, false);
504
- const stateData = { ...(this.currentEntry().getState() || {}), ...extraDetail, redirected: response.redirected, };
505
- await this.updateCurrentEntry({ state: stateData }, finalUrl);
506
- // Manual scrolling?
507
- if (scrollContainer !== window && httpEvent.url.hash) {
508
- document.querySelector(httpEvent.url.hash)?.scrollIntoView({ behavior: 'smooth' });
509
- (document.querySelector('[autofocus]') || document.body).focus();
510
- }
511
- }
512
- await new Promise(res => setTimeout(res, 100));
513
- };
514
- if (document.startViewTransition && detail.navigationType !== 'startup') {
515
- const synthesizeWhile = window.webqit?.realdom?.synthesizeWhile || ( callback => callback() );
516
- return synthesizeWhile(async () => {
517
- document.documentElement.classList.toggle('transiting', true);
518
- try { await document.startViewTransition( update ).ready; } catch(e) { console.log(e); }
519
- document.documentElement.classList.toggle('transiting', false);
520
- });
521
- }
522
- return await update();
523
- }
524
-
525
- }
@@ -1,58 +0,0 @@
1
-
2
-
3
- /**
4
- * @imports
5
- */
6
- import { _isString, _isUndefined } from '@webqit/util/js/index.js';
7
- import { Observer } from './Runtime.js';
8
-
9
- export default function(namespace = null, persistent = false) {
10
- const storeType = persistent ? 'localStorage' : 'sessionStorage';
11
- if (!window[storeType]) {
12
- throw new Error(`The specified Web Storage API ${storeType} is invalid or not supported`);
13
- }
14
- const _storage = {}, key = e => namespace ? `${namespace}.${e.key}` : e.key;
15
- Observer.intercept(_storage, {
16
- get: (event, received, next) => {
17
- if (!_isString(event.key)) return;
18
- const value = window[storeType].getItem(key(event));
19
- return next(!_isUndefined(value) ? JSON.parse(value) : value);
20
- },
21
- set: (event, received, next) => {
22
- if (!_isString(event.key)) return;
23
- window[storeType].setItem(key(event), !_isUndefined(event.value) ? JSON.stringify(event.value) : event.value);
24
- return next(true);
25
- },
26
- deleteProperty: (event, received, next) => {
27
- if (!_isString(event.key)) return;
28
- window[storeType].removeItem(key(event));
29
- return next(true);
30
- },
31
- has: (event, received, next) => {
32
- if (!_isString(event.key)) return;
33
- const _key = key(event);
34
- for(let i = 0; i < window[storeType].length; i ++){
35
- if (window[storeType].key(i) === _key) {
36
- return next(true);
37
- }
38
- };
39
- return next(false);
40
- },
41
- ownKeys: (event, received, next) => {
42
- const keys = [];
43
- for(let i = 0; i < window[storeType].length; i ++){
44
- keys.push(window[storeType].key(i));
45
- };
46
- return next(keys);
47
- },
48
- getOwnPropertyDescriptor: (event, received, next) => {
49
- return next({ enumerable: true, configurable: true });
50
- },
51
- });
52
-
53
- return Observer.proxy(_storage);
54
- }
55
-
56
- export {
57
- Observer,
58
- }
@@ -1,44 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import Router from '../Router.js';
6
- import _Application from '../../Application.js';
7
-
8
- export default class Application extends _Application {
9
-
10
- // Returns router class
11
- get Router() {
12
- return Router;
13
- }
14
-
15
- /**
16
- * Handles HTTP events.
17
- *
18
- * @param HttpEvent httpEvent
19
- * @param Function remoteFetch
20
- *
21
- * @return Response
22
- */
23
- async handle(httpEvent, remoteFetch) {
24
- // The app router
25
- const router = new this.Router(this.cx, httpEvent.url.pathname);
26
- const handle = async () => {
27
- // --------
28
- // ROUTE FOR DATA
29
- // --------
30
- return router.route([httpEvent.request.method, 'default'], httpEvent, {}, async event => {
31
- if (event !== httpEvent) {
32
- // This was nexted()
33
- if (!event.request.headers.has('Accept')) {
34
- event.request.headers.set('Accept', 'application/json');
35
- }
36
- }
37
- return remoteFetch(event.request);
38
- }, remoteFetch);
39
- };
40
- return handle();
41
- }
42
-
43
- }
44
-