@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
@@ -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
- }