crelte 0.4.8 → 0.5.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Crelte.d.ts +7 -6
- package/dist/Crelte.d.ts.map +1 -1
- package/dist/Crelte.js +5 -13
- package/dist/CrelteRequest.d.ts +9 -0
- package/dist/CrelteRequest.d.ts.map +1 -1
- package/dist/CrelteRequest.js +16 -2
- package/dist/blocks/Blocks.svelte +2 -2
- package/dist/blocks/Blocks.svelte.d.ts +3 -19
- package/dist/blocks/Blocks.svelte.d.ts.map +1 -1
- package/dist/cookies/ClientCookies.d.ts +0 -1
- package/dist/cookies/ClientCookies.d.ts.map +1 -1
- package/dist/cookies/ClientCookies.js +0 -1
- package/dist/cookies/ServerCookies.d.ts +1 -2
- package/dist/cookies/ServerCookies.d.ts.map +1 -1
- package/dist/cookies/ServerCookies.js +2 -6
- package/dist/cookies/index.d.ts +0 -2
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/graphql/GraphQl.d.ts +2 -2
- package/dist/graphql/GraphQl.d.ts.map +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -6
- package/dist/init/InternalApp.d.ts +30 -0
- package/dist/init/InternalApp.d.ts.map +1 -0
- package/dist/init/InternalApp.js +71 -0
- package/dist/init/client.d.ts +0 -5
- package/dist/init/client.d.ts.map +1 -1
- package/dist/init/client.js +88 -75
- package/dist/init/crelte-vite-plugin.d.ts +5 -0
- package/dist/init/server.d.ts +0 -5
- package/dist/init/server.d.ts.map +1 -1
- package/dist/init/server.js +49 -20
- package/dist/init/shared.d.ts +7 -18
- package/dist/init/shared.d.ts.map +1 -1
- package/dist/init/shared.js +97 -154
- package/dist/init/svelteComponents.d.ts +3 -0
- package/dist/init/svelteComponents.d.ts.map +1 -0
- package/dist/init/svelteComponents.js +7 -0
- package/dist/loadData/Globals.d.ts +40 -33
- package/dist/loadData/Globals.d.ts.map +1 -1
- package/dist/loadData/Globals.js +99 -88
- package/dist/loadData/index.d.ts +3 -2
- package/dist/loadData/index.d.ts.map +1 -1
- package/dist/loadData/index.js +2 -0
- package/dist/plugins/Events.d.ts +11 -13
- package/dist/plugins/Events.d.ts.map +1 -1
- package/dist/plugins/Events.js +10 -3
- package/dist/routing/BaseRoute.d.ts +255 -0
- package/dist/routing/BaseRoute.d.ts.map +1 -0
- package/dist/routing/BaseRoute.js +349 -0
- package/dist/routing/BaseRouter.d.ts +210 -0
- package/dist/routing/BaseRouter.d.ts.map +1 -0
- package/dist/routing/BaseRouter.js +444 -0
- package/dist/routing/ClientRouter.d.ts +32 -0
- package/dist/routing/ClientRouter.d.ts.map +1 -0
- package/dist/routing/ClientRouter.js +259 -0
- package/dist/routing/LoadRunner.d.ts +39 -0
- package/dist/routing/LoadRunner.d.ts.map +1 -0
- package/dist/routing/{PageLoader.js → LoadRunner.js} +32 -20
- package/dist/routing/Request.d.ts +35 -3
- package/dist/routing/Request.d.ts.map +1 -1
- package/dist/routing/Request.js +64 -5
- package/dist/routing/Route.d.ts +24 -223
- package/dist/routing/Route.d.ts.map +1 -1
- package/dist/routing/Route.js +26 -315
- package/dist/routing/Router.d.ts +49 -73
- package/dist/routing/Router.d.ts.map +1 -1
- package/dist/routing/Router.js +85 -251
- package/dist/routing/ServerRouter.d.ts +23 -0
- package/dist/routing/ServerRouter.d.ts.map +1 -0
- package/dist/routing/ServerRouter.js +57 -0
- package/dist/routing/utils.d.ts +5 -0
- package/dist/routing/utils.d.ts.map +1 -1
- package/dist/routing/utils.js +39 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +3 -0
- package/package.json +7 -6
- package/src/Crelte.ts +12 -18
- package/src/CrelteRequest.ts +21 -2
- package/src/cookies/ClientCookies.ts +0 -2
- package/src/cookies/ServerCookies.ts +2 -7
- package/src/cookies/index.ts +0 -3
- package/src/graphql/GraphQl.ts +2 -1
- package/src/index.ts +17 -9
- package/src/init/InternalApp.ts +134 -0
- package/src/init/client.ts +104 -93
- package/src/init/crelte-vite-plugin.d.ts +5 -0
- package/src/init/server.ts +67 -35
- package/src/init/shared.ts +107 -227
- package/src/init/svelteComponents.ts +12 -0
- package/src/loadData/Globals.ts +121 -102
- package/src/loadData/index.ts +3 -2
- package/src/plugins/Events.ts +40 -42
- package/src/routing/BaseRoute.ts +422 -0
- package/src/routing/BaseRouter.ts +528 -0
- package/src/routing/ClientRouter.ts +329 -0
- package/src/routing/{PageLoader.ts → LoadRunner.ts} +43 -30
- package/src/routing/Request.ts +97 -12
- package/src/routing/Route.ts +56 -376
- package/src/routing/Router.ts +100 -359
- package/src/routing/ServerRouter.ts +78 -0
- package/src/routing/utils.ts +53 -0
- package/src/utils.ts +4 -0
- package/dist/routing/InnerRouter.d.ts +0 -113
- package/dist/routing/InnerRouter.d.ts.map +0 -1
- package/dist/routing/InnerRouter.js +0 -417
- package/dist/routing/PageLoader.d.ts +0 -36
- package/dist/routing/PageLoader.d.ts.map +0 -1
- package/src/routing/InnerRouter.ts +0 -498
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is the Router which we internally extend from
|
|
3
|
+
* it does not directly get exposed
|
|
4
|
+
*/
|
|
5
|
+
import { Writable } from 'crelte-std/stores';
|
|
6
|
+
import Request, { isRequest } from './Request.js';
|
|
7
|
+
import Site, { siteFromUrl } from './Site.js';
|
|
8
|
+
import { matchAcceptLang } from './utils.js';
|
|
9
|
+
import LoadRunner from './LoadRunner.js';
|
|
10
|
+
import { Listeners } from 'crelte-std/sync';
|
|
11
|
+
import { isPromise, objClone } from '../utils.js';
|
|
12
|
+
const INF_LOOP_CHECK = '__REQ_FROM_REQ_START__';
|
|
13
|
+
export default class BaseRouter {
|
|
14
|
+
sites;
|
|
15
|
+
sitesByLanguage;
|
|
16
|
+
/**
|
|
17
|
+
* The current route
|
|
18
|
+
*
|
|
19
|
+
* ## Note
|
|
20
|
+
* Will always contain a route except in the first loadData call
|
|
21
|
+
*/
|
|
22
|
+
route;
|
|
23
|
+
// todo should probably be a derived
|
|
24
|
+
/**
|
|
25
|
+
* The current site
|
|
26
|
+
*
|
|
27
|
+
* ## Note
|
|
28
|
+
* Will always contain a site except in the first loadData call
|
|
29
|
+
*/
|
|
30
|
+
site;
|
|
31
|
+
// todo should probably be a derived
|
|
32
|
+
/**
|
|
33
|
+
* The current entry
|
|
34
|
+
*
|
|
35
|
+
* ## Note
|
|
36
|
+
* Will always contain an entry except in the first loadData call
|
|
37
|
+
*/
|
|
38
|
+
entry;
|
|
39
|
+
// the next request if it is not only a preload request
|
|
40
|
+
request;
|
|
41
|
+
/**
|
|
42
|
+
* The loading flag, specifies if a page is currently
|
|
43
|
+
* getting loaded
|
|
44
|
+
*/
|
|
45
|
+
loading;
|
|
46
|
+
/**
|
|
47
|
+
* The loading progress, the value is between 0 and 1
|
|
48
|
+
*/
|
|
49
|
+
loadingProgress;
|
|
50
|
+
onNewCrelteRequest;
|
|
51
|
+
/**
|
|
52
|
+
* Not sure the naming here is great but
|
|
53
|
+
*/
|
|
54
|
+
onBeforeRequest;
|
|
55
|
+
onRequestListeners;
|
|
56
|
+
loadRunner;
|
|
57
|
+
onRouteListeners;
|
|
58
|
+
/// should return once the render is done
|
|
59
|
+
onRender;
|
|
60
|
+
constructor(sites, opts) {
|
|
61
|
+
this.sites = sites.map(s => new Site(s));
|
|
62
|
+
this.sitesByLanguage = new Map(this.sites.map(s => [s.language, s]));
|
|
63
|
+
this.route = new Writable(null);
|
|
64
|
+
this.site = new Writable(null);
|
|
65
|
+
this.entry = new Writable(null);
|
|
66
|
+
this.request = null;
|
|
67
|
+
this.loading = new Writable(false);
|
|
68
|
+
this.loadingProgress = new Writable(0);
|
|
69
|
+
this.onNewCrelteRequest = () => null;
|
|
70
|
+
this.onBeforeRequest = () => { };
|
|
71
|
+
this.onRequestListeners = new Listeners();
|
|
72
|
+
this.loadRunner = new LoadRunner(opts);
|
|
73
|
+
this.onRouteListeners = new Listeners();
|
|
74
|
+
this.onRender = async () => null;
|
|
75
|
+
// todo move this to the client?
|
|
76
|
+
this.loadRunner.onProgress = (loading, progress) => {
|
|
77
|
+
if (this.loading.get() !== loading)
|
|
78
|
+
this.loading.set(loading);
|
|
79
|
+
if (typeof progress === 'number')
|
|
80
|
+
this.loadingProgress.set(progress);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get the default site
|
|
85
|
+
*/
|
|
86
|
+
primarySite() {
|
|
87
|
+
return this.sites.find(s => s.primary) ?? this.sites[0];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Should be override by environment specific router
|
|
91
|
+
*
|
|
92
|
+
* This should be based on the language
|
|
93
|
+
*
|
|
94
|
+
* todo check that the router uses the correct sites for each function
|
|
95
|
+
*/
|
|
96
|
+
defaultSite() {
|
|
97
|
+
return this.primarySite();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get a site and if possible use the accept lang header.
|
|
101
|
+
*
|
|
102
|
+
* @param acceptLang Accept Language header.
|
|
103
|
+
*/
|
|
104
|
+
siteByAcceptLang(acceptLang = null) {
|
|
105
|
+
if (!acceptLang)
|
|
106
|
+
return this.primarySite();
|
|
107
|
+
const lang = matchAcceptLang(acceptLang, Array.from(this.sitesByLanguage.keys()));
|
|
108
|
+
return lang ? this.sitesByLanguage.get(lang) : this.primarySite();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Tries to get a site by it's id
|
|
112
|
+
*/
|
|
113
|
+
siteById(id) {
|
|
114
|
+
return this.sites.find(s => s.id === id) ?? null;
|
|
115
|
+
}
|
|
116
|
+
// keep this doc in sync with Router.targetToRequest
|
|
117
|
+
/**
|
|
118
|
+
* Resolve a url or Route and convert it to a Request
|
|
119
|
+
*
|
|
120
|
+
* @param target
|
|
121
|
+
* @param opts, any option present will override the value in target
|
|
122
|
+
* @return Returns null if the url does not match our host (the protocol get's ignored)
|
|
123
|
+
*/
|
|
124
|
+
targetToRequest(target, opts = {}) {
|
|
125
|
+
if (typeof target === 'string') {
|
|
126
|
+
if (target.startsWith('/')) {
|
|
127
|
+
// todo should we use the language matching or throw if the route does not
|
|
128
|
+
// exists
|
|
129
|
+
const site = this.route.get()?.site ?? this.primarySite();
|
|
130
|
+
target = new URL(site.uri + target, site.url);
|
|
131
|
+
}
|
|
132
|
+
else if (!target) {
|
|
133
|
+
throw new Error('the url is not allowed to be empty');
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
target = new URL(target);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (target instanceof URL) {
|
|
140
|
+
target = this.requestFromUrl(target);
|
|
141
|
+
}
|
|
142
|
+
if (!isRequest(target)) {
|
|
143
|
+
return Request.fromRoute(target, opts);
|
|
144
|
+
}
|
|
145
|
+
target._updateOpts(opts);
|
|
146
|
+
return target;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Resolve a url and convert it to a Request
|
|
150
|
+
*
|
|
151
|
+
* @param url
|
|
152
|
+
* @return Returns null if the url does not match our host (the protocol get's ignored)
|
|
153
|
+
*/
|
|
154
|
+
requestFromUrl(fullUrl) {
|
|
155
|
+
// strip stuff we dont need from url
|
|
156
|
+
const req = new Request(fullUrl, null);
|
|
157
|
+
const site = siteFromUrl(req.url, this.sites);
|
|
158
|
+
// todo should we throw if we can't find a site
|
|
159
|
+
// or use the site which matches the language
|
|
160
|
+
req.site = site ?? this.primarySite();
|
|
161
|
+
return req;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Open a new route
|
|
165
|
+
*
|
|
166
|
+
* @param target the target to open can be an url, a route or a request
|
|
167
|
+
* the url needs to start with http or with a / which will be considered as
|
|
168
|
+
* the site baseUrl
|
|
169
|
+
*
|
|
170
|
+
* ## Note
|
|
171
|
+
* The origin will always be set to 'manual'
|
|
172
|
+
*
|
|
173
|
+
* ## Example
|
|
174
|
+
* ```
|
|
175
|
+
* import { getRouter } from 'crelte';
|
|
176
|
+
*
|
|
177
|
+
* const router = getRouter();
|
|
178
|
+
* console.log(router.site.get().url.href); // 'https://example.com/de';
|
|
179
|
+
*
|
|
180
|
+
* router.open('/foo/bar');
|
|
181
|
+
* // the following page will be opened https://example.com/de/foo/bar
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
async open(target, opts = {}) {
|
|
185
|
+
const req = this.targetToRequest(target, {
|
|
186
|
+
...opts,
|
|
187
|
+
origin: 'manual',
|
|
188
|
+
});
|
|
189
|
+
if (!req)
|
|
190
|
+
return;
|
|
191
|
+
if (req === this.request) {
|
|
192
|
+
throw new Error('Cannot open the same request object twice. Either clone the request ' +
|
|
193
|
+
'or just pass in the url.');
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
return await this.openRequest(req);
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
console.warn('opening route failed', e);
|
|
200
|
+
throw e;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async openRequest(_req) {
|
|
204
|
+
throw new Error('environment specific');
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* This pushes the new route without triggering a new pageload
|
|
208
|
+
*
|
|
209
|
+
* You can use this when using pagination for example change the route object
|
|
210
|
+
* (search argument) and then call push
|
|
211
|
+
*
|
|
212
|
+
* ## Note
|
|
213
|
+
* This will always set the origin to 'push'
|
|
214
|
+
* And will clear the scrollY value if you not provide a new one via the `opts`
|
|
215
|
+
* This will disableLoadData by default if you not provide an override via the `opts`
|
|
216
|
+
*
|
|
217
|
+
* ## Example using the update function
|
|
218
|
+
* ```
|
|
219
|
+
* import { getRouter } from 'crelte';
|
|
220
|
+
*
|
|
221
|
+
* const router = getRouter();
|
|
222
|
+
*
|
|
223
|
+
* const page = 1;
|
|
224
|
+
* router.push(req => req.setSearchParam('page', page || null));
|
|
225
|
+
* ```
|
|
226
|
+
*
|
|
227
|
+
* ## Example using the route object
|
|
228
|
+
* ```
|
|
229
|
+
* import { getRouter } from 'crelte';
|
|
230
|
+
*
|
|
231
|
+
* const router = getRouter();
|
|
232
|
+
*
|
|
233
|
+
* const page = 1;
|
|
234
|
+
* const route = router.route.get();
|
|
235
|
+
* route.setSearchParam('page', page > 0 ? page : null);
|
|
236
|
+
* router.push(route);
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
async push(route, opts = {}) {
|
|
240
|
+
// theoretically string and URL also work but we might
|
|
241
|
+
// change that in the future
|
|
242
|
+
const req = this.targetToRequest(route, {
|
|
243
|
+
...opts,
|
|
244
|
+
origin: 'push',
|
|
245
|
+
scrollY: opts.scrollY ?? undefined,
|
|
246
|
+
disableLoadData: opts.disableLoadData ?? true,
|
|
247
|
+
});
|
|
248
|
+
if (!req)
|
|
249
|
+
return;
|
|
250
|
+
try {
|
|
251
|
+
return await this.pushRequest(req, opts);
|
|
252
|
+
}
|
|
253
|
+
catch (e) {
|
|
254
|
+
console.warn('pushing route failed', e);
|
|
255
|
+
throw e;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
pushRequest(_req, _opts = {}) {
|
|
259
|
+
throw new Error('environment specific');
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* This replaces the state of the route without triggering a new pageload
|
|
263
|
+
*
|
|
264
|
+
* You can use this when using some filters for example a search filter
|
|
265
|
+
*
|
|
266
|
+
* ## Note
|
|
267
|
+
* This will always set the origin to 'replace'
|
|
268
|
+
* And will clear the scrollY value if you don't provide a new one via the `opts`
|
|
269
|
+
* This will disableLoadData by default if you don't provide an override via the `opts`
|
|
270
|
+
*
|
|
271
|
+
* ## Example using the update function
|
|
272
|
+
* ```
|
|
273
|
+
* import { getRouter } from 'crelte';
|
|
274
|
+
*
|
|
275
|
+
* const router = getRouter();
|
|
276
|
+
*
|
|
277
|
+
* const search = 'foo';
|
|
278
|
+
* router.replace(req => req.setSearchParam('search', search));
|
|
279
|
+
* ```
|
|
280
|
+
*
|
|
281
|
+
* ## Example using the route object
|
|
282
|
+
* ```
|
|
283
|
+
* import { getRouter } from 'crelte';
|
|
284
|
+
*
|
|
285
|
+
* const router = getRouter();
|
|
286
|
+
*
|
|
287
|
+
* const search = 'foo';
|
|
288
|
+
* const route = router.route.get();
|
|
289
|
+
* route.setSearchParam('search', search);
|
|
290
|
+
* router.replace(route);
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
async replace(route, opts = {}) {
|
|
294
|
+
// theoretically string and URL also work but we might
|
|
295
|
+
// change that in the future
|
|
296
|
+
const req = this.targetToRequest(route, {
|
|
297
|
+
...opts,
|
|
298
|
+
origin: 'replace',
|
|
299
|
+
scrollY: opts.scrollY ?? undefined,
|
|
300
|
+
disableLoadData: opts.disableLoadData ?? true,
|
|
301
|
+
});
|
|
302
|
+
if (!req)
|
|
303
|
+
return;
|
|
304
|
+
try {
|
|
305
|
+
return await this.replaceRequest(req, opts);
|
|
306
|
+
}
|
|
307
|
+
catch (e) {
|
|
308
|
+
console.warn('replacing route failed', e);
|
|
309
|
+
throw e;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
async replaceRequest(_req, _opts = {}) {
|
|
313
|
+
throw new Error('environment specific');
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Checks if there are previous routes which would allow it to go back
|
|
317
|
+
*/
|
|
318
|
+
canGoBack() {
|
|
319
|
+
throw new Error('environment specific');
|
|
320
|
+
// return this.route.get()?.canGoBack() ?? false;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Go back in the history
|
|
324
|
+
*/
|
|
325
|
+
back() {
|
|
326
|
+
throw new Error('environment specific');
|
|
327
|
+
// this.inner.history.back();
|
|
328
|
+
}
|
|
329
|
+
async preload(target) {
|
|
330
|
+
const req = this.targetToRequest(target);
|
|
331
|
+
const current = this.route.get();
|
|
332
|
+
// if the origin matches, the route will be able to be load
|
|
333
|
+
// so let's preload it
|
|
334
|
+
if (current && current.url.origin === req.url.origin) {
|
|
335
|
+
// todo i don't wan't to send a CrelteRequest?
|
|
336
|
+
this.loadRunner.preload(this.onNewCrelteRequest(req));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
cancelRequest() {
|
|
340
|
+
// destroy the old request
|
|
341
|
+
if (this.request) {
|
|
342
|
+
this.request._cancel();
|
|
343
|
+
this.request = null;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* ## Throws
|
|
348
|
+
* If the request completed but had an error
|
|
349
|
+
*/
|
|
350
|
+
async handleRequest(req, updateHistory) {
|
|
351
|
+
// this isCancelled check is not if a user cancelled the request
|
|
352
|
+
// but if the router cancelled the request, because for example
|
|
353
|
+
// the user clicked on a new link or an event decided to call open
|
|
354
|
+
const isCancelled = () => req.cancelled;
|
|
355
|
+
// cancel the previous request
|
|
356
|
+
this.cancelRequest();
|
|
357
|
+
const barrier = req._renderBarrier;
|
|
358
|
+
if (barrier.isOpen())
|
|
359
|
+
throw new Error('the request was already used');
|
|
360
|
+
// not sure this really helps
|
|
361
|
+
// it should be in open maybe?
|
|
362
|
+
if (req.getContext(INF_LOOP_CHECK))
|
|
363
|
+
throw new Error('infinite loop detected');
|
|
364
|
+
this.request = req;
|
|
365
|
+
const cr = this.onNewCrelteRequest(req);
|
|
366
|
+
// trigger event onRequestStart
|
|
367
|
+
const onBeforeReqProm = this.onBeforeRequest(cr);
|
|
368
|
+
if (isPromise(onBeforeReqProm))
|
|
369
|
+
await onBeforeReqProm;
|
|
370
|
+
if (isCancelled())
|
|
371
|
+
return;
|
|
372
|
+
// if the request does not have a matching site, redirect
|
|
373
|
+
if (!req.siteMatches()) {
|
|
374
|
+
const site = this.defaultSite();
|
|
375
|
+
const req = new Request(site.url, site);
|
|
376
|
+
req.setContext(INF_LOOP_CHECK, true);
|
|
377
|
+
return await this.openRequest(req);
|
|
378
|
+
}
|
|
379
|
+
// trigger onRequest listeners (this is not an event and more intended
|
|
380
|
+
// to be used by the actual site and not a plugin)
|
|
381
|
+
this.onRequestListeners.trigger(cr);
|
|
382
|
+
if (isCancelled())
|
|
383
|
+
return;
|
|
384
|
+
//!! this block might throw if something did not work as expected
|
|
385
|
+
// todo do we wan't this?
|
|
386
|
+
if (!req.disableLoadData) {
|
|
387
|
+
const completed = await this.loadRunner.load(cr);
|
|
388
|
+
// the request was succeeded by some other request
|
|
389
|
+
if (!completed)
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
// just discard the old one since nobody will wan't it
|
|
394
|
+
this.loadRunner.discard();
|
|
395
|
+
this.copyEntryToRequest(req);
|
|
396
|
+
}
|
|
397
|
+
// check if the render was cancelled
|
|
398
|
+
// else wait until the renderBarrier gets opened
|
|
399
|
+
const readyProm = req._renderBarrier.ready();
|
|
400
|
+
const wasCancelled = isPromise(readyProm) ? await readyProm : readyProm;
|
|
401
|
+
if (wasCancelled || isCancelled())
|
|
402
|
+
return;
|
|
403
|
+
// the onRender should decide by itself if it wants to render or not
|
|
404
|
+
// for example in most cases if !entryChanged it does not make sense to render
|
|
405
|
+
return await this.onRender(cr,
|
|
406
|
+
// readyForRoute
|
|
407
|
+
() => {
|
|
408
|
+
// throws if the route is missing entry, template or loadedData
|
|
409
|
+
// or the request was cancelled
|
|
410
|
+
const route = req.toRoute();
|
|
411
|
+
updateHistory(route);
|
|
412
|
+
// update route, site and onRoute
|
|
413
|
+
this.triggerRoute(route);
|
|
414
|
+
return route;
|
|
415
|
+
},
|
|
416
|
+
// domUpdated
|
|
417
|
+
// we use a callback to maybe decrease latency?
|
|
418
|
+
(cr, route) => {
|
|
419
|
+
this.updateScroll(cr, route);
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
copyEntryToRequest(req) {
|
|
423
|
+
const route = this.route.get();
|
|
424
|
+
if (!route)
|
|
425
|
+
throw new Error('the first request is not allowed to disableLoadData');
|
|
426
|
+
req.entry = objClone(route.entry);
|
|
427
|
+
req.template = route.template;
|
|
428
|
+
req.loadedData = objClone(route.loadedData);
|
|
429
|
+
}
|
|
430
|
+
triggerRoute(route) {
|
|
431
|
+
this.route.setSilent(route);
|
|
432
|
+
const siteChanged = this.site.get()?.id !== route.site.id;
|
|
433
|
+
this.site.setSilent(route.site);
|
|
434
|
+
this.entry.setSilent(route.entry);
|
|
435
|
+
// trigger an update
|
|
436
|
+
this.route.notify();
|
|
437
|
+
if (siteChanged)
|
|
438
|
+
this.site.notify();
|
|
439
|
+
if (route.entryChanged)
|
|
440
|
+
this.entry.notify();
|
|
441
|
+
this.onRouteListeners.trigger(route);
|
|
442
|
+
}
|
|
443
|
+
updateScroll(_cr, _route) { }
|
|
444
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import CrelteRequest from '../CrelteRequest.js';
|
|
2
|
+
import BaseRouter, { BaseRouterOptions } from './BaseRouter.js';
|
|
3
|
+
import { Request, RequestOptions } from './index.js';
|
|
4
|
+
import Route from './Route.js';
|
|
5
|
+
import { SiteFromGraphQl } from './Site.js';
|
|
6
|
+
export type ClientRouterOptions = {
|
|
7
|
+
preloadOnMouseOver: boolean;
|
|
8
|
+
} & BaseRouterOptions;
|
|
9
|
+
export default class ClientRouter extends BaseRouter {
|
|
10
|
+
private scrollDebounceTimeout;
|
|
11
|
+
private preloadOnMouseOver;
|
|
12
|
+
onError: (e: any) => void;
|
|
13
|
+
constructor(sites: SiteFromGraphQl[], opts: ClientRouterOptions);
|
|
14
|
+
/**
|
|
15
|
+
* ## Throws
|
|
16
|
+
*/
|
|
17
|
+
init(): Promise<void | Route>;
|
|
18
|
+
/**
|
|
19
|
+
* Do not call this with origin push or replace
|
|
20
|
+
*/
|
|
21
|
+
openRequest(req: Request): Promise<Route | void>;
|
|
22
|
+
pushRequest(req: Request, _opts?: RequestOptions): Promise<void | Route>;
|
|
23
|
+
replaceRequest(req: Request, _opts?: RequestOptions): Promise<void | Route>;
|
|
24
|
+
/**
|
|
25
|
+
* This returns a route if it was handled else if an error occured
|
|
26
|
+
* or the request was cancelled returns void
|
|
27
|
+
*/
|
|
28
|
+
handleRequestAndError(req: Request, updateHistory: (route: Route) => void): Promise<Route | void>;
|
|
29
|
+
listen(): void;
|
|
30
|
+
updateScroll(cr: CrelteRequest, _route: Route): void;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=ClientRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClientRouter.d.ts","sourceRoot":"","sources":["../../src/routing/ClientRouter.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,UAAU,EAAE,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,MAAM,mBAAmB,GAAG;IACjC,kBAAkB,EAAE,OAAO,CAAC;CAC5B,GAAG,iBAAiB,CAAC;AAEtB,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,UAAU;IACnD,OAAO,CAAC,qBAAqB,CAAa;IAC1C,OAAO,CAAC,kBAAkB,CAAU;IAEpC,OAAO,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;gBAEd,KAAK,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,mBAAmB;IAQ/D;;OAEG;IACG,IAAI;IAaV;;OAEG;IACG,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IA6ChD,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,GAAE,cAAmB;IAyBpD,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,GAAE,cAAmB;IA8B7D;;;OAGG;IACG,qBAAqB,CAC1B,GAAG,EAAE,OAAO,EACZ,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GACnC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IASxB,MAAM;IAiGN,YAAY,CAAC,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,GAAG,IAAI;CAwEpD"}
|