@webqit/webflo 0.11.61 → 0.20.2-next.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 (235) hide show
  1. package/.github/FUNDING.yml +12 -0
  2. package/.github/workflows/publish.yml +48 -0
  3. package/.gitignore +2 -0
  4. package/LICENSE +2 -2
  5. package/README.md +71 -2050
  6. package/package.json +28 -13
  7. package/site/-/_.md +139 -0
  8. package/site/-/docs.old.md +2010 -0
  9. package/site/.vitepress/cache/deps/@braintree_sanitize-url 2.js +93 -0
  10. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
  11. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js 2.map +7 -0
  12. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
  13. package/site/.vitepress/cache/deps/_metadata 2.json +85 -0
  14. package/site/.vitepress/cache/deps/_metadata.json +85 -0
  15. package/site/.vitepress/cache/deps/chunk-BUSYA2B4 2.js +9 -0
  16. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
  17. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js 2.map +7 -0
  18. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
  19. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK 2.js +9719 -0
  20. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js +9719 -0
  21. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js 2.map +7 -0
  22. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js.map +7 -0
  23. package/site/.vitepress/cache/deps/chunk-QAXAIFA7 2.js +12705 -0
  24. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js +12705 -0
  25. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js 2.map +7 -0
  26. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js.map +7 -0
  27. package/site/.vitepress/cache/deps/cytoscape 2.js +30278 -0
  28. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent 2.js +4710 -0
  29. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
  30. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js 2.map +7 -0
  31. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
  32. package/site/.vitepress/cache/deps/cytoscape.js +30278 -0
  33. package/site/.vitepress/cache/deps/cytoscape.js 2.map +7 -0
  34. package/site/.vitepress/cache/deps/cytoscape.js.map +7 -0
  35. package/site/.vitepress/cache/deps/dayjs 2.js +285 -0
  36. package/site/.vitepress/cache/deps/dayjs.js +285 -0
  37. package/site/.vitepress/cache/deps/dayjs.js 2.map +7 -0
  38. package/site/.vitepress/cache/deps/dayjs.js.map +7 -0
  39. package/site/.vitepress/cache/deps/debug 2.js +453 -0
  40. package/site/.vitepress/cache/deps/debug.js +453 -0
  41. package/site/.vitepress/cache/deps/debug.js 2.map +7 -0
  42. package/site/.vitepress/cache/deps/debug.js.map +7 -0
  43. package/site/.vitepress/cache/deps/package 2.json +3 -0
  44. package/site/.vitepress/cache/deps/package.json +3 -0
  45. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api 2.js +4507 -0
  46. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
  47. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js 2.map +7 -0
  48. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  49. package/site/.vitepress/cache/deps/vitepress___@vueuse_core 2.js +584 -0
  50. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
  51. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js 2.map +7 -0
  52. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  53. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap 2.js +1166 -0
  54. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1166 -0
  55. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js 2.map +7 -0
  56. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  57. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js 2.js +1667 -0
  58. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
  59. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js 2.map +7 -0
  60. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  61. package/site/.vitepress/cache/deps/vitepress___minisearch 2.js +1815 -0
  62. package/site/.vitepress/cache/deps/vitepress___minisearch.js +1815 -0
  63. package/site/.vitepress/cache/deps/vitepress___minisearch.js 2.map +7 -0
  64. package/site/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  65. package/site/.vitepress/cache/deps/vue 2.js +344 -0
  66. package/site/.vitepress/cache/deps/vue.js +344 -0
  67. package/site/.vitepress/cache/deps/vue.js 2.map +7 -0
  68. package/site/.vitepress/cache/deps/vue.js.map +7 -0
  69. package/site/.vitepress/config.ts +147 -0
  70. package/site/.vitepress/theme/custom.css +50 -0
  71. package/site/.vitepress/theme/index.ts +6 -0
  72. package/site/api/webflo-fetch/FormData.md +0 -0
  73. package/site/api/webflo-fetch/Headers.md +0 -0
  74. package/site/api/webflo-fetch/LiveResponse.md +0 -0
  75. package/site/api/webflo-fetch/Request.md +0 -0
  76. package/site/api/webflo-fetch/Response.md +0 -0
  77. package/site/api/webflo-fetch/fetch.md +0 -0
  78. package/site/api/webflo-routing/HttpCookies.md +0 -0
  79. package/site/api/webflo-routing/HttpEvent/respondWith.md +1 -0
  80. package/site/api/webflo-routing/HttpEvent/waitUntil.md +1 -0
  81. package/site/api/webflo-routing/HttpEvent/waitUntilNavigate.md +1 -0
  82. package/site/api/webflo-routing/HttpEvent.md +30 -0
  83. package/site/api/webflo-routing/HttpSession.md +0 -0
  84. package/site/api/webflo-routing/HttpState.md +0 -0
  85. package/site/api/webflo-routing/HttpUser.md +0 -0
  86. package/site/api/webflo-routing/handler/fetch.md +42 -0
  87. package/site/api/webflo-routing/handler/next.md +54 -0
  88. package/site/api/webflo-routing/handler.md +119 -0
  89. package/site/api.md +26 -0
  90. package/site/contributing.md +16 -0
  91. package/site/docs/advanced/lifecycles.md +20 -0
  92. package/site/docs/advanced/redirects.md +0 -0
  93. package/site/docs/advanced/routing.md +1 -0
  94. package/site/docs/advanced.md +9 -0
  95. package/site/docs/concepts/realtime.md +637 -0
  96. package/site/docs/concepts/rendering.md +60 -0
  97. package/site/docs/concepts/request-response.md +47 -0
  98. package/site/docs/concepts/routing.md +656 -0
  99. package/site/docs/concepts/state.md +44 -0
  100. package/site/docs/concepts/templates.md +48 -0
  101. package/site/docs/concepts.md +97 -0
  102. package/site/docs/getting-started.md +378 -0
  103. package/site/docs/tech-stack.md +56 -0
  104. package/site/docs.md +100 -0
  105. package/site/examples/pwa.md +10 -0
  106. package/site/examples/web.md +11 -0
  107. package/site/examples.md +10 -0
  108. package/site/faq.md +13 -0
  109. package/site/guides/guide-auth.md +13 -0
  110. package/site/guides/guide-file-upload.md +11 -0
  111. package/site/guides/guide-service-worker.md +10 -0
  112. package/site/guides/tutorial-1-todo.md +24 -0
  113. package/site/guides.md +15 -0
  114. package/site/index.md +39 -0
  115. package/site/public/img/brand/logo-670x670.png +0 -0
  116. package/site/recipes/realtime.md +11 -0
  117. package/site/recipes/streaming.md +15 -0
  118. package/site/reference/cli.md +11 -0
  119. package/site/reference/config.md +13 -0
  120. package/site/reference/tools.md +9 -0
  121. package/src/Context.js +3 -11
  122. package/src/config-pi/deployment/Env.js +6 -19
  123. package/src/config-pi/deployment/Layout.js +11 -3
  124. package/src/config-pi/runtime/Client.js +40 -48
  125. package/src/config-pi/runtime/Server.js +52 -20
  126. package/src/config-pi/runtime/client/Worker.js +22 -20
  127. package/src/config-pi/static/Init.js +57 -0
  128. package/src/config-pi/static/index.js +2 -0
  129. package/src/deployment-pi/origins/index.js +1 -1
  130. package/src/deployment-pi/util.js +161 -0
  131. package/src/index.js +3 -9
  132. package/src/init-pi/index.js +117 -0
  133. package/src/init-pi/templates/pwa/app/handler.server.js +8 -0
  134. package/src/init-pi/templates/pwa/app/page.html +7 -0
  135. package/src/init-pi/templates/pwa/package.json +19 -0
  136. package/src/init-pi/templates/pwa/public/assets/app.css +16 -0
  137. package/src/init-pi/templates/pwa/public/index.html +39 -0
  138. package/src/init-pi/templates/pwa/public/manifest.json +29 -0
  139. package/src/init-pi/templates/web/app/handler.server.js +8 -0
  140. package/src/init-pi/templates/web/app/page.html +7 -0
  141. package/src/init-pi/templates/web/package.json +19 -0
  142. package/src/init-pi/templates/web/public/assets/app.css +16 -0
  143. package/src/init-pi/templates/web/public/index.html +39 -0
  144. package/src/runtime-pi/WebfloRuntime.js +350 -0
  145. package/src/runtime-pi/index.js +3 -10
  146. package/src/runtime-pi/webflo-client/ClientSideCookies.js +17 -0
  147. package/src/runtime-pi/webflo-client/ClientSideWorkport.js +63 -0
  148. package/src/runtime-pi/webflo-client/DeviceCapabilities.js +213 -0
  149. package/src/runtime-pi/webflo-client/WebfloClient.js +500 -0
  150. package/src/runtime-pi/webflo-client/WebfloRootClient1.js +206 -0
  151. package/src/runtime-pi/webflo-client/WebfloRootClient2.js +113 -0
  152. package/src/runtime-pi/webflo-client/WebfloSubClient.js +118 -0
  153. package/src/runtime-pi/webflo-client/index.js +17 -0
  154. package/src/runtime-pi/webflo-client/webflo-codegen.js +469 -0
  155. package/src/runtime-pi/webflo-client/webflo-devmode.js +243 -0
  156. package/src/runtime-pi/webflo-client/webflo-embedded.js +50 -0
  157. package/src/runtime-pi/webflo-fetch/LiveResponse.js +437 -0
  158. package/src/runtime-pi/webflo-fetch/cookies.js +10 -0
  159. package/src/runtime-pi/webflo-fetch/fetch.js +16 -0
  160. package/src/runtime-pi/webflo-fetch/formdata.js +54 -0
  161. package/src/runtime-pi/webflo-fetch/headers.js +151 -0
  162. package/src/runtime-pi/webflo-fetch/index.js +5 -0
  163. package/src/runtime-pi/webflo-fetch/message.js +49 -0
  164. package/src/runtime-pi/webflo-fetch/request.js +62 -0
  165. package/src/runtime-pi/webflo-fetch/response.js +110 -0
  166. package/src/runtime-pi/webflo-fetch/util.js +28 -0
  167. package/src/runtime-pi/webflo-messaging/WQBroadcastChannel.js +10 -0
  168. package/src/runtime-pi/webflo-messaging/WQMessageChannel.js +26 -0
  169. package/src/runtime-pi/webflo-messaging/WQMessageEvent.js +87 -0
  170. package/src/runtime-pi/webflo-messaging/WQMessagePort.js +38 -0
  171. package/src/runtime-pi/webflo-messaging/WQRelayPort.js +47 -0
  172. package/src/runtime-pi/webflo-messaging/WQSockPort.js +113 -0
  173. package/src/runtime-pi/webflo-messaging/WQStarPort.js +104 -0
  174. package/src/runtime-pi/webflo-messaging/wq-message-port.js +404 -0
  175. package/src/runtime-pi/webflo-routing/HttpCookies.js +42 -0
  176. package/src/runtime-pi/webflo-routing/HttpEvent.js +112 -0
  177. package/src/runtime-pi/webflo-routing/HttpSession.js +11 -0
  178. package/src/runtime-pi/webflo-routing/HttpState.js +153 -0
  179. package/src/runtime-pi/webflo-routing/HttpUser.js +54 -0
  180. package/src/runtime-pi/webflo-routing/WebfloRouter.js +245 -0
  181. package/src/runtime-pi/webflo-server/ServerSideCookies.js +19 -0
  182. package/src/runtime-pi/webflo-server/ServerSideSession.js +38 -0
  183. package/src/runtime-pi/webflo-server/WebfloServer.js +937 -0
  184. package/src/runtime-pi/webflo-server/index.js +11 -0
  185. package/src/runtime-pi/webflo-server/messaging/Client.js +27 -0
  186. package/src/runtime-pi/webflo-server/messaging/ClientRequestRealtime.js +50 -0
  187. package/src/runtime-pi/webflo-server/messaging/Clients.js +25 -0
  188. package/src/runtime-pi/webflo-server/webflo-devmode.js +326 -0
  189. package/src/runtime-pi/{client → webflo-url}/Url.js +27 -76
  190. package/src/runtime-pi/webflo-url/index.js +1 -0
  191. package/src/runtime-pi/webflo-url/urlpattern.js +38 -0
  192. package/src/runtime-pi/{util-url.js → webflo-url/util.js} +5 -43
  193. package/src/runtime-pi/webflo-url/xURL.js +94 -0
  194. package/src/runtime-pi/webflo-worker/WebfloWorker.js +234 -0
  195. package/src/runtime-pi/webflo-worker/WorkerSideCookies.js +19 -0
  196. package/src/runtime-pi/webflo-worker/WorkerSideWorkport.js +18 -0
  197. package/src/runtime-pi/webflo-worker/index.js +11 -0
  198. package/src/services-pi/index.js +2 -0
  199. package/src/services-pi/push/index.js +23 -0
  200. package/src/util.js +10 -0
  201. package/src/{webflo.js → webflo-cli.js} +4 -4
  202. package/src/runtime-pi/Application.js +0 -29
  203. package/src/runtime-pi/Cookies.js +0 -82
  204. package/src/runtime-pi/HttpEvent.js +0 -107
  205. package/src/runtime-pi/Router.js +0 -130
  206. package/src/runtime-pi/Runtime.js +0 -21
  207. package/src/runtime-pi/client/Application.js +0 -76
  208. package/src/runtime-pi/client/Context.js +0 -7
  209. package/src/runtime-pi/client/Router.js +0 -48
  210. package/src/runtime-pi/client/Runtime.js +0 -525
  211. package/src/runtime-pi/client/Workport.js +0 -190
  212. package/src/runtime-pi/client/createStorage.js +0 -58
  213. package/src/runtime-pi/client/generate.js +0 -481
  214. package/src/runtime-pi/client/index.js +0 -21
  215. package/src/runtime-pi/client/worker/Application.js +0 -44
  216. package/src/runtime-pi/client/worker/Context.js +0 -7
  217. package/src/runtime-pi/client/worker/Runtime.js +0 -275
  218. package/src/runtime-pi/client/worker/Workport.js +0 -78
  219. package/src/runtime-pi/client/worker/index.js +0 -21
  220. package/src/runtime-pi/server/Application.js +0 -101
  221. package/src/runtime-pi/server/Context.js +0 -16
  222. package/src/runtime-pi/server/Router.js +0 -159
  223. package/src/runtime-pi/server/Runtime.js +0 -558
  224. package/src/runtime-pi/server/index.js +0 -21
  225. package/src/runtime-pi/util-http.js +0 -86
  226. package/src/runtime-pi/xFormData.js +0 -24
  227. package/src/runtime-pi/xHeaders.js +0 -146
  228. package/src/runtime-pi/xRequest.js +0 -46
  229. package/src/runtime-pi/xRequestHeaders.js +0 -109
  230. package/src/runtime-pi/xResponse.js +0 -33
  231. package/src/runtime-pi/xResponseHeaders.js +0 -117
  232. package/src/runtime-pi/xURL.js +0 -105
  233. package/src/runtime-pi/xfetch.js +0 -23
  234. package/src/runtime-pi/xxHttpMessage.js +0 -102
  235. package/src/static-pi/index.js +0 -11
@@ -0,0 +1,206 @@
1
+ import { Observer } from '@webqit/quantum-js';
2
+ import { WebfloClient } from './WebfloClient.js';
3
+ import { ClientSideWorkport } from './ClientSideWorkport.js';
4
+ import { DeviceCapabilities } from './DeviceCapabilities.js';
5
+ import { WebfloHMR } from './webflo-devmode.js';
6
+
7
+ export class WebfloRootClient1 extends WebfloClient {
8
+
9
+ static get Workport() { return ClientSideWorkport; }
10
+
11
+ static get DeviceCapabilities() { return DeviceCapabilities; }
12
+
13
+ static create(cx, host) {
14
+ return new this(this.Context.create(cx), host);
15
+ }
16
+
17
+ #network;
18
+ get network() { return this.#network; }
19
+
20
+ #workport;
21
+ get workport() { return this.#workport; }
22
+
23
+ #deviceCapabilities;
24
+ get deviceCapabilities() { return this.#deviceCapabilities; }
25
+
26
+ #hmr;
27
+
28
+ get withViewTransitions() {
29
+ return document.querySelector('meta[name="webflo:viewtransitions"]')?.value;
30
+ }
31
+
32
+ constructor(cx, host) {
33
+ if (!(host instanceof Document)) {
34
+ throw new Error('Argument #1 must be a Document instance');
35
+ }
36
+ super(cx, host);
37
+ this.#network = { status: window.navigator.onLine };
38
+ }
39
+
40
+ async initialize() {
41
+ // INITIALIZATIONS
42
+ const instanceController = await super.initialize();
43
+ // Bind network status handlers
44
+ const onlineHandler = () => Observer.set(this.network, 'status', window.navigator.onLine);
45
+ window.addEventListener('online', onlineHandler, { signal: instanceController.signal });
46
+ window.addEventListener('offline', onlineHandler, { signal: instanceController.signal });
47
+ // Window opener pinging
48
+ if (window.opener) {
49
+ const beforeunloadHandler = () => window.opener.postMessage('close');
50
+ window.addEventListener('beforeunload', beforeunloadHandler, { signal: instanceController.signal });
51
+ }
52
+ // Bind top-level User-Agent requests
53
+ this.background.handleRequests('ua:query', async (e) => {
54
+ if (e.data?.query === 'push_registration') {
55
+ const pushManager = (await navigator.serviceWorker.getRegistration()).pushManager;
56
+ return await pushManager.getSubscription();
57
+ }
58
+ }, { signal: instanceController.signal });
59
+ // Bind top-level Storage requests
60
+ this.background.handleRequests('storage:query', (e) => {
61
+ const { source, namespace, query, key, value } = e.data;
62
+ const storage = source === 'session' ? sessionStorage : (source === 'local' ? localStorage : null);
63
+ if (!storage) return;
64
+ const data = JSON.parse(storage.getItem(namespace) || (query === 'set' ? '{}' : 'null'));
65
+ switch (query) {
66
+ case 'has': return !!data && Reflect.has(data, key);
67
+ case 'get': return data && Reflect.get(data, key);
68
+ case 'set':
69
+ Reflect.set(data, key, value);
70
+ return storage.setItem(namespace, JSON.stringify(data))
71
+ case 'delete':
72
+ if (!data) return;
73
+ Reflect.deleteProperty(data, key);
74
+ return storage.setItem(namespace, JSON.stringify(data));
75
+ case 'clear': return storage.removeItem(namespace);
76
+ case 'keys': return data && Reflect.ownKeys(data) || [];
77
+ case 'values': return data && Object.values(data) || [];
78
+ case 'entries': return data && Object.entries(data) || [];
79
+ case 'size': return data && Object.keys(data).length || 0;
80
+ }
81
+ }, { signal: instanceController.signal });
82
+ return instanceController;
83
+ }
84
+
85
+ async setupCapabilities() {
86
+ const instanceController = await super.setupCapabilities();
87
+ // Service Worker && Capabilities
88
+ const cleanups = [];
89
+ instanceController.signal.addEventListener('abort', () => cleanups.forEach((c) => c()), { once: true });
90
+ this.#deviceCapabilities = await this.constructor.DeviceCapabilities.initialize(this, this.config.CLIENT.capabilities);
91
+ cleanups.push(() => this.#deviceCapabilities.close());
92
+ if (this.config.CLIENT.capabilities?.service_worker?.filename) {
93
+ const { service_worker: { filename, ...restServiceWorkerParams } = {} } = this.config.CLIENT.capabilities;
94
+ this.#workport = await this.constructor.Workport.initialize(null, (this.config.CLIENT.public_base_url || '') + filename, restServiceWorkerParams);
95
+ cleanups.push(() => this.#workport.close());
96
+ }
97
+ return instanceController;
98
+ }
99
+
100
+ async hydrate() {
101
+ const instanceController = await super.hydrate();
102
+ const scopeObj = {};
103
+ scopeObj.data = this.host.querySelector(`script[rel="hydration"][type="application/json"]`)?.textContent?.trim() || null;
104
+ scopeObj.response = new Response.from(scopeObj.data, { headers: { 'Content-Type': 'application/json' } });
105
+ for (const name of ['X-Background-Messaging-Port', 'X-Live-Response-Message-ID', 'X-Webflo-Dev-Mode']) {
106
+ const metaElement = this.host.querySelector(`meta[name="${name}"]`);
107
+ if (!metaElement) continue;
108
+ scopeObj.response.headers.set(name, metaElement.content?.trim() || '');
109
+ }
110
+ if (scopeObj.response.isLive()) {
111
+ this.background.addPort(scopeObj.response.wqRealtime);
112
+ }
113
+ if (scopeObj.response.body || scopeObj.response.isLive()) {
114
+ const httpEvent = this.createHttpEvent({ request: this.createRequest(this.location.href) }, true);
115
+ await this.render(httpEvent, scopeObj.response);
116
+ } else {
117
+ await this.navigate(this.location.href);
118
+ }
119
+ if (scopeObj.response.headers.get('X-Webflo-Dev-Mode') === 'true') {
120
+ this.enterDevMode();
121
+ }
122
+ return instanceController;
123
+ }
124
+
125
+ async enterDevMode() {
126
+ this.#hmr = WebfloHMR.manage(this);
127
+ }
128
+
129
+ control() {
130
+ // ON LOCATION CHANGE
131
+ const locationCallback = (newHref) => {
132
+ try {
133
+ const scrollPosition = this.host === window.document
134
+ ? [window.scrollX, window.scrollY]
135
+ : [this.host.scrollLeft, this.host.scrollTop,];
136
+ const state = { ...(this.currentEntry()?.getState?.() || {}), scrollPosition };
137
+ window.history.replaceState(state, '', this.location.href);
138
+ } catch (e) { }
139
+ try { window.history.pushState({}, '', newHref); } catch (e) { }
140
+ };
141
+ const instanceController = super.controlClassic/*IMPORTANT*/(locationCallback);
142
+ // ONPOPSTATE
143
+ const popstateHandler = (e) => {
144
+ if (this.isHashChange(location)) {
145
+ Observer.set(this.location, 'href', location.href);
146
+ return;
147
+ }
148
+ // Navigation details
149
+ const detail = {
150
+ navigationType: 'traverse',
151
+ navigationOrigins: [],
152
+ destination: this._asEntry(e.state),
153
+ source: this.currentEntry(),
154
+ userInitiated: true,
155
+ };
156
+ // Traversal?
157
+ // Push
158
+ this.navigate(location.href, {}, detail);
159
+ };
160
+ window.addEventListener('popstate', popstateHandler, { signal: instanceController.signal });
161
+ return instanceController;
162
+ }
163
+
164
+ reload() {
165
+ return window.history.reload();
166
+ }
167
+
168
+ back() {
169
+ return window.history.back();
170
+ }
171
+
172
+ forward() {
173
+ return window.history.forward();
174
+ }
175
+
176
+ traverseTo(...args) {
177
+ return window.history.go(...args);
178
+ }
179
+
180
+ async push(url, state = {}) {
181
+ if (typeof url === 'string' && url.startsWith('&')) { url = this.location.href.split('#')[0] + (this.location.href.includes('?') ? url : url.replace('&', '?')); }
182
+ url = new URL(url, this.location.href);
183
+ window.history.pushState(state, '', url.href);
184
+ Observer.set(this.location, 'href', url.href);
185
+ }
186
+
187
+ entries() {
188
+ return window.history;
189
+ }
190
+
191
+ currentEntry() {
192
+ return this._asEntry(history.state);
193
+ }
194
+
195
+ async updateCurrentEntry(params, url = null) {
196
+ window.history.replaceState(params.state, '', url);
197
+ }
198
+
199
+ async applyPostRenderState(httpEvent) {
200
+ const destinationState = httpEvent.detail.destination?.getState() || {};
201
+ if (destinationState.scrollPosition?.length) {
202
+ window.scroll(...destinationState.scrollPosition);
203
+ (document.querySelector('[autofocus]') || document.body).focus();
204
+ } else await super.applyPostRenderState(httpEvent);
205
+ }
206
+ }
@@ -0,0 +1,113 @@
1
+ import { Observer } from '@webqit/quantum-js';
2
+ import { WebfloRootClient1 } from './WebfloRootClient1.js';
3
+
4
+ export class WebfloRootClient2 extends WebfloRootClient1 {
5
+
6
+ control() {
7
+ const instanceController = super.controlSuper/*IMPORTANT*/();
8
+ // Detect source elements
9
+ let navigationOrigins = [];
10
+ // Capture all link-clicks
11
+ const clickHandler = (e) => {
12
+ if (!this._canIntercept(e) || e.defaultPrevented) return;
13
+ let anchorEl = e.target.closest('a');
14
+ if (!anchorEl || !anchorEl.href || anchorEl.target) return;
15
+ navigationOrigins = [anchorEl, null, anchorEl.closest('[navigationcontext]')];
16
+ };
17
+ // Capture all form-submits
18
+ const submitHandler = (e) => {
19
+ if (!this._canIntercept(e) || e.defaultPrevented) return;
20
+ navigationOrigins = [e.submitter, e.target.closest('form'), e.target.closest('[navigationcontext]')];
21
+ };
22
+ // Handle navigation event which happens after the above
23
+ const navigateHandler = (e) => {
24
+ if (!e.canIntercept
25
+ || e.downloadRequest !== null
26
+ || !this.isSpaRoute(e.destination.url)
27
+ || e.navigationType === 'reload') return;
28
+ if (e.hashChange) {
29
+ Observer.set(this.location, 'href', e.destination.url);
30
+ return;
31
+ }
32
+ const { navigationType, destination, signal, formData, info, userInitiated } = e;
33
+ if (formData && navigationOrigins[1]?.hasAttribute('webflo-no-intercept')) return;
34
+ if (formData && (navigationOrigins[0] || {}).name) { formData.set(navigationOrigins[0].name, navigationOrigins[0].value); }
35
+ // Navigation details
36
+ const detail = {
37
+ navigationType,
38
+ navigationOrigins,
39
+ destination,
40
+ source: this.currentEntry(),
41
+ userInitiated,
42
+ info
43
+ };
44
+ navigationOrigins = [];
45
+ // Traversal?
46
+ // Push
47
+ const url = new URL(destination.url, this.location.href);
48
+ const init = {
49
+ method: formData && 'POST' || 'GET',
50
+ body: formData,
51
+ signal
52
+ };
53
+ this.updateCurrentEntry({
54
+ state: {
55
+ ...(this.currentEntry().getState() || {}),
56
+ scrollPosition: [window.scrollX, window.scrollY],
57
+ }
58
+ });
59
+ const runtime = this;
60
+ e.intercept({
61
+ scroll: 'after-transition',
62
+ focusReset: 'after-transition',
63
+ async handler() {
64
+ if (navigationType === 'replace') return;
65
+ await runtime.navigate(url, init, detail);
66
+ },
67
+ });
68
+ };
69
+ window.addEventListener('click', clickHandler, { signal: instanceController.signal });
70
+ window.addEventListener('submit', submitHandler, { signal: instanceController.signal });
71
+ window.navigation.addEventListener('navigate', navigateHandler, { signal: instanceController.signal });
72
+ return instanceController;
73
+ }
74
+
75
+ reload(params) {
76
+ return window.navigation.reload(params);
77
+ }
78
+
79
+ back() {
80
+ return window.navigation.canGoBack && window.navigation.back();
81
+ }
82
+
83
+ forward() {
84
+ return window.navigation.canGoForward && window.navigation.forward();
85
+ }
86
+
87
+ traverseTo(...args) {
88
+ return window.navigation.traverseTo(...args);
89
+ }
90
+
91
+ async push(url, state = {}) {
92
+ if (typeof url === 'string' && url.startsWith('&')) { url = this.location.href.split('#')[0] + (this.location.href.includes('?') ? url : url.replace('&', '?')); }
93
+ url = new URL(url, this.location.href);
94
+ await window.navigation.navigate(url.href, state).committed;
95
+ Observer.set(this.location, 'href', url.href);
96
+ }
97
+
98
+ entries() {
99
+ return window.navigation.entries();
100
+ }
101
+
102
+ currentEntry() {
103
+ return window.navigation.currentEntry;
104
+ }
105
+
106
+ async updateCurrentEntry(params, url = null) {
107
+ if (!url || url === window.navigation.currentEntry.url) {
108
+ window.navigation.updateCurrentEntry(params);
109
+ } else {
110
+ await window.navigation.navigate(url, { ...params, history: 'replace' }).committed;
111
+ }
112
+ }
113
+ }
@@ -0,0 +1,118 @@
1
+ import { Observer } from '@webqit/quantum-js';
2
+ import { WebfloClient } from './WebfloClient.js';
3
+ import { defineElement } from './webflo-embedded.js';
4
+ import { Url } from '../webflo-url/Url.js';
5
+ import { _wq } from '../../util.js';
6
+
7
+ export class WebfloSubClient extends WebfloClient {
8
+
9
+ static defineElement() {
10
+ defineElement(this);
11
+ }
12
+
13
+ static create(superRuntime, host) {
14
+ return new this(superRuntime, host);
15
+ }
16
+
17
+ #superRuntime;
18
+ get superRuntime() { return this.#superRuntime; }
19
+
20
+ get network() { return this.#superRuntime.network; }
21
+
22
+ get workport() { return this.#superRuntime.workport; }
23
+
24
+ get deviceCapabilities() { return this.#superRuntime.deviceCapabilities; }
25
+
26
+ get withViewTransitions() { return this.host.hasAttribute('viewtransitions'); }
27
+
28
+ constructor(superRuntime, host) {
29
+ if (!(superRuntime instanceof WebfloClient)) {
30
+ throw new Error('Argument #2 must be a Webflo Client instance');
31
+ }
32
+ if (!(host instanceof HTMLElement)) {
33
+ throw new Error('Argument #1 must be a HTMLElement instance');
34
+ }
35
+ super(superRuntime.cx, host);
36
+ this.#superRuntime = superRuntime;
37
+ }
38
+
39
+ async initialize() {
40
+ if (this.host.location.origin !== window.location.origin) {
41
+ throw new Error(`Webflo embeddable origin violation in "${window.location}"`);
42
+ }
43
+ const instanceController = await super.initialize();
44
+ _wq(this.background, 'meta').set('parentNode', this.#superRuntime.background);
45
+ instanceController.signal.addEventListener('abort', () => {
46
+ if (_wq(this.background, 'meta').get('parentNode') === this.#superRuntime.background) {
47
+ _wq(this.background, 'meta').set('parentNode', null);
48
+ }
49
+ }, { once: true });
50
+ return instanceController;
51
+ }
52
+
53
+ async hydrate() {
54
+ const instanceController = await super.hydrate();
55
+ if (this.host.hasAttribute('location')) {
56
+ await this.navigate(this.location.href);
57
+ }
58
+ return instanceController;
59
+ }
60
+
61
+ control() {
62
+ const locationCallback = (newHref) => {
63
+ this.host.reflectLocation(newHref);
64
+ };
65
+ return super.controlClassic/*IMPORTANT*/(locationCallback);
66
+ }
67
+
68
+ reload(params) {}
69
+
70
+ back() {}
71
+
72
+ forward() {}
73
+
74
+ traverseTo(...args) {}
75
+
76
+ async push(url, state = {}) {}
77
+
78
+ entries() {}
79
+
80
+ currentEntry() {}
81
+
82
+ async updateCurrentEntry(params, url = null) {
83
+ this.host.reflectLocation(url);
84
+ }
85
+
86
+ async applyPostRenderState(httpEvent) {
87
+ if (httpEvent.url.hash) {
88
+ this.host.querySelector(httpEvent.url.hash)?.scrollIntoView();
89
+ } else await super.applyPostRenderState(httpEvent);
90
+ (this.host.querySelector('[autofocus]') || this.host).focus();
91
+ }
92
+
93
+ redirect(location, responseRealtime = null) {
94
+ location = typeof location === 'string' ? new URL(location, this.location.origin) : location;
95
+ const width = Math.min(800, window.innerWidth);
96
+ const height = Math.min(600, window.innerHeight);
97
+ const left = (window.outerWidth - width) / 2;
98
+ const top = (window.outerHeight - height) / 2;
99
+ const popup = window.open(location, '_blank', `popup=true,width=${width},height=${height},left=${left},top=${top}`);
100
+ if (responseRealtime) {
101
+ Observer.set(this.navigator, 'redirecting', new Url/*NOT URL*/(location), { diff: true });
102
+ responseRealtime.addEventListener('close', (e) => {
103
+ window.removeEventListener('message', windowMessageHandler);
104
+ Observer.set(this.navigator, 'redirecting', null);
105
+ popup.postMessage('timeout:5');
106
+ setTimeout(() => {
107
+ popup.close();
108
+ }, 5000);
109
+ }, { once: true });
110
+ const windowMessageHandler = (e) => {
111
+ if (e.source === popup && e.data === 'close') {
112
+ responseRealtime.close();
113
+ }
114
+ };
115
+ window.addEventListener('message', windowMessageHandler);
116
+ }
117
+ }
118
+ }
@@ -0,0 +1,17 @@
1
+ import { WebfloRootClient1 } from './WebfloRootClient1.js';
2
+ import { WebfloRootClient2 } from './WebfloRootClient2.js';
3
+ import { WebfloSubClient } from './WebfloSubClient.js';
4
+
5
+ export async function start() {
6
+ const WebfloRootClient = window.navigation ? WebfloRootClient2 : WebfloRootClient1;
7
+ const instance = WebfloRootClient.create(this || {}, document);
8
+ await instance.initialize();
9
+ WebfloSubClient.defineElement();
10
+ return instance;
11
+ }
12
+
13
+ export {
14
+ WebfloRootClient1,
15
+ WebfloRootClient2,
16
+ WebfloSubClient
17
+ }