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
package/src/routing/utils.ts
CHANGED
|
@@ -1,3 +1,56 @@
|
|
|
1
1
|
export function trimSlashEnd(str: string) {
|
|
2
2
|
return str.endsWith('/') ? str.substring(0, str.length - 1) : str;
|
|
3
3
|
}
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `parseAcceptLang('fr-CH, en;q=0.7, fr;q=0.8')` will return `[['fr-CH', 1], ['fr', 0.8], ['en', 0.7]]`
|
|
7
|
+
*/
|
|
8
|
+
function parseAcceptLang(acceptLang: string): [string, number][] {
|
|
9
|
+
return acceptLang
|
|
10
|
+
.split(',')
|
|
11
|
+
.map(d => {
|
|
12
|
+
// eslint-disable-next-line prefer-const
|
|
13
|
+
let [lang, pq] = d.split(';');
|
|
14
|
+
lang = lang.trim();
|
|
15
|
+
if (!lang) return null;
|
|
16
|
+
|
|
17
|
+
let quality = 1;
|
|
18
|
+
if (pq?.startsWith('q=')) {
|
|
19
|
+
const q = parseFloat(pq.substring(2));
|
|
20
|
+
if (!isNaN(q)) quality = q;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return [lang, quality] as [string, number];
|
|
24
|
+
})
|
|
25
|
+
.filter(d => !!d)
|
|
26
|
+
.sort((a, b) => b[1] - a[1]);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* if no match was found null is returned
|
|
31
|
+
* `matchAcceptLang('fr-CH, en;q=0.7, fr;q=0.8', ['en-GB'])` will return `en-GB`
|
|
32
|
+
*/
|
|
33
|
+
export function matchAcceptLang(
|
|
34
|
+
acceptLang: string,
|
|
35
|
+
langs: string[],
|
|
36
|
+
): string | null {
|
|
37
|
+
const qualities = new Map(
|
|
38
|
+
parseAcceptLang(acceptLang).map(([l, q]) => [l.toLowerCase(), q]),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return langs.reduce<{ lang: string | null; q: number }>(
|
|
42
|
+
(best, lang) => {
|
|
43
|
+
const lowerLang = lang.toLowerCase();
|
|
44
|
+
// this might splitting to much
|
|
45
|
+
const [p1, p2] = lowerLang.split('-');
|
|
46
|
+
|
|
47
|
+
const q1 = qualities.get(lowerLang) ?? 0;
|
|
48
|
+
const q2 = p2 ? (qualities.get(p1) ?? 0) : 0;
|
|
49
|
+
|
|
50
|
+
const q = Math.max(q1, q2);
|
|
51
|
+
|
|
52
|
+
return best.q < q ? { lang, q } : best;
|
|
53
|
+
},
|
|
54
|
+
{ lang: null, q: 0 },
|
|
55
|
+
).lang;
|
|
56
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -9,5 +9,9 @@ export function objClone(obj: any): any {
|
|
|
9
9
|
return JSON.parse(JSON.stringify(obj));
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
export function isPromise<T>(p: Promise<T> | T): p is Promise<T> {
|
|
13
|
+
return typeof (p as any)?.then === 'function';
|
|
14
|
+
}
|
|
15
|
+
|
|
12
16
|
// this allows us to fix cyclic dependencies
|
|
13
17
|
export const circles: Record<string, any> = {};
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import Site, { SiteFromGraphQl } from './Site.js';
|
|
2
|
-
import History from './History.js';
|
|
3
|
-
import Request, { RequestOptions } from './Request.js';
|
|
4
|
-
import Route from './Route.js';
|
|
5
|
-
export type InnerRouterOpts = {
|
|
6
|
-
preloadOnMouseOver: boolean;
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Manages event listeners or functions.
|
|
10
|
-
*/
|
|
11
|
-
export default class InnerRouter {
|
|
12
|
-
sites: Site[];
|
|
13
|
-
/**
|
|
14
|
-
* The current route
|
|
15
|
-
*
|
|
16
|
-
* ## Null
|
|
17
|
-
* It might be null on the first targetToRequest, open, and routeFromUrl call
|
|
18
|
-
*/
|
|
19
|
-
route: Route | null;
|
|
20
|
-
history: History;
|
|
21
|
-
preloadOnMouseOver: boolean;
|
|
22
|
-
/**
|
|
23
|
-
* @param changeHistory returns a function you need to call when you are ready to
|
|
24
|
-
update the window history (note do not call this after another onRoute call was made)
|
|
25
|
-
*/
|
|
26
|
-
onRoute: (route: Request, changeHistory: () => void) => void;
|
|
27
|
-
onPreload: (route: Request) => void;
|
|
28
|
-
private scrollDebounceTimeout;
|
|
29
|
-
/**
|
|
30
|
-
* Creates a new Router
|
|
31
|
-
*
|
|
32
|
-
* @param sites - sites needs to be from craft-graphql-sites plugin
|
|
33
|
-
* @param opts - Options for the router
|
|
34
|
-
*/
|
|
35
|
-
constructor(sites: SiteFromGraphQl[], opts: InnerRouterOpts);
|
|
36
|
-
/**
|
|
37
|
-
* Initializes the router when running on the client.
|
|
38
|
-
*/
|
|
39
|
-
initClient(): void;
|
|
40
|
-
/**
|
|
41
|
-
* Initializes the router when running on the server.
|
|
42
|
-
*/
|
|
43
|
-
initServer(): void;
|
|
44
|
-
/**
|
|
45
|
-
* Get a site and if possible use the accept lang header.
|
|
46
|
-
*
|
|
47
|
-
* @param acceptLang Accept Language header.
|
|
48
|
-
*/
|
|
49
|
-
siteByAcceptLang(acceptLang?: string | null): Site;
|
|
50
|
-
/**
|
|
51
|
-
* Get the default site
|
|
52
|
-
*/
|
|
53
|
-
defaultSite(): Site;
|
|
54
|
-
/**
|
|
55
|
-
* Tries to get a site by it's id
|
|
56
|
-
*/
|
|
57
|
-
siteById(id: number): Site | null;
|
|
58
|
-
/**
|
|
59
|
-
* Resolve a url or Route and convert it to a Request
|
|
60
|
-
*
|
|
61
|
-
* @param target
|
|
62
|
-
* @param opts, any option present will override the value in target
|
|
63
|
-
* @return Returns null if the url does not match our host (the protocol get's ignored)
|
|
64
|
-
*/
|
|
65
|
-
targetToRequest(target: string | URL | Route | Request, opts?: RequestOptions): Request;
|
|
66
|
-
/**
|
|
67
|
-
* Resolve a url and convert it to a Route
|
|
68
|
-
*
|
|
69
|
-
* @param url
|
|
70
|
-
* @return Returns null if the url does not match our host (the protocol get's ignored)
|
|
71
|
-
*/
|
|
72
|
-
routeFromUrl(fullUrl: URL): Route;
|
|
73
|
-
listen(): void;
|
|
74
|
-
/**
|
|
75
|
-
* Open a new route
|
|
76
|
-
*
|
|
77
|
-
* @param route a route object or an url or uri, never input the same route object again
|
|
78
|
-
* @param pushState if true pushed the state to the window.history
|
|
79
|
-
*
|
|
80
|
-
* ## Important
|
|
81
|
-
* Make sure a req always has the correct origin,
|
|
82
|
-
* `push` and `replace` will cause this function to throw an error
|
|
83
|
-
*/
|
|
84
|
-
open(req: Request): void;
|
|
85
|
-
/**
|
|
86
|
-
* This pushes a new route to the history
|
|
87
|
-
*
|
|
88
|
-
* @param req, never input the same route object again
|
|
89
|
-
*
|
|
90
|
-
* ## Important
|
|
91
|
-
* Make sure the route has the correct origin
|
|
92
|
-
*/
|
|
93
|
-
push(req: Request): void;
|
|
94
|
-
/**
|
|
95
|
-
* This replaces the current route
|
|
96
|
-
*
|
|
97
|
-
* @param req, never input the same route object again
|
|
98
|
-
*
|
|
99
|
-
* ## Important
|
|
100
|
-
* Make sure the route has the correct origin
|
|
101
|
-
*/
|
|
102
|
-
replace(req: Request): void;
|
|
103
|
-
/**
|
|
104
|
-
* Preload a url
|
|
105
|
-
*
|
|
106
|
-
* This will only work if the origin of the url matches the current site
|
|
107
|
-
*
|
|
108
|
-
* @param url
|
|
109
|
-
*/
|
|
110
|
-
preload(target: string | URL | Route | Request): void;
|
|
111
|
-
domReady(req: Request): void;
|
|
112
|
-
}
|
|
113
|
-
//# sourceMappingURL=InnerRouter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"InnerRouter.d.ts","sourceRoot":"","sources":["../../src/routing/InnerRouter.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,EAAE,EAAE,eAAe,EAAe,MAAM,WAAW,CAAC;AAC/D,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,OAAO,EAAE,EAAa,cAAc,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,MAAM,MAAM,eAAe,GAAG;IAC7B,kBAAkB,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,WAAW;IAC/B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd;;;;;OAKG;IACH,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAC7D,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAEpC,OAAO,CAAC,qBAAqB,CAAa;IAE1C;;;;;OAKG;gBACS,KAAK,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,eAAe;IAkB3D;;OAEG;IACH,UAAU;IAgBV;;OAEG;IACH,UAAU;IAEV;;;;OAIG;IACH,gBAAgB,CAAC,UAAU,GAAE,MAAM,GAAG,IAAW,GAAG,IAAI;IAsCxD;;OAEG;IACH,WAAW,IAAI,IAAI;IAInB;;OAEG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAKjC;;;;;;OAMG;IACH,eAAe,CACd,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK,GAAG,OAAO,EACtC,IAAI,GAAE,cAAmB,GACvB,OAAO;IA0BV;;;;;OAKG;IACH,YAAY,CAAC,OAAO,EAAE,GAAG,GAAG,KAAK;IAcjC,MAAM;IAiGN;;;;;;;;;OASG;IACH,IAAI,CAAC,GAAG,EAAE,OAAO;IA6CjB;;;;;;;OAOG;IACH,IAAI,CAAC,GAAG,EAAE,OAAO;IAuBjB;;;;;;;OAOG;IACH,OAAO,CAAC,GAAG,EAAE,OAAO;IAuBpB;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK,GAAG,OAAO;IAW9C,QAAQ,CAAC,GAAG,EAAE,OAAO;CAsErB"}
|
|
@@ -1,417 +0,0 @@
|
|
|
1
|
-
import Site, { siteFromUrl } from './Site.js';
|
|
2
|
-
import { ClientHistory, ServerHistory } from './History.js';
|
|
3
|
-
import Request, { isRequest } from './Request.js';
|
|
4
|
-
import Route from './Route.js';
|
|
5
|
-
/**
|
|
6
|
-
* Manages event listeners or functions.
|
|
7
|
-
*/
|
|
8
|
-
export default class InnerRouter {
|
|
9
|
-
sites;
|
|
10
|
-
/**
|
|
11
|
-
* The current route
|
|
12
|
-
*
|
|
13
|
-
* ## Null
|
|
14
|
-
* It might be null on the first targetToRequest, open, and routeFromUrl call
|
|
15
|
-
*/
|
|
16
|
-
route;
|
|
17
|
-
history;
|
|
18
|
-
preloadOnMouseOver;
|
|
19
|
-
/**
|
|
20
|
-
* @param changeHistory returns a function you need to call when you are ready to
|
|
21
|
-
update the window history (note do not call this after another onRoute call was made)
|
|
22
|
-
*/
|
|
23
|
-
onRoute;
|
|
24
|
-
onPreload;
|
|
25
|
-
scrollDebounceTimeout;
|
|
26
|
-
/**
|
|
27
|
-
* Creates a new Router
|
|
28
|
-
*
|
|
29
|
-
* @param sites - sites needs to be from craft-graphql-sites plugin
|
|
30
|
-
* @param opts - Options for the router
|
|
31
|
-
*/
|
|
32
|
-
constructor(sites, opts) {
|
|
33
|
-
this.sites = sites.map(s => new Site(s));
|
|
34
|
-
this.route = null;
|
|
35
|
-
// @ts-ignore
|
|
36
|
-
this.history = import.meta.env.SSR
|
|
37
|
-
? new ServerHistory()
|
|
38
|
-
: new ClientHistory();
|
|
39
|
-
this.preloadOnMouseOver = opts.preloadOnMouseOver;
|
|
40
|
-
// this.preloadListeners = new Listeners();
|
|
41
|
-
this.onRoute = () => { };
|
|
42
|
-
this.onPreload = () => { };
|
|
43
|
-
this.scrollDebounceTimeout = null;
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Initializes the router when running on the client.
|
|
47
|
-
*/
|
|
48
|
-
initClient() {
|
|
49
|
-
this.listen();
|
|
50
|
-
// let's first try to load from the state
|
|
51
|
-
const req = this.targetToRequest(window.location.href);
|
|
52
|
-
req._fillFromState(window.history.state);
|
|
53
|
-
req.origin = 'init';
|
|
54
|
-
window.history.scrollRestoration = 'manual';
|
|
55
|
-
// we set it now instead of waiting for the onRoute call
|
|
56
|
-
// because the window.history is already set
|
|
57
|
-
this.route = req.toRoute();
|
|
58
|
-
this.onRoute(req, () => { });
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Initializes the router when running on the server.
|
|
62
|
-
*/
|
|
63
|
-
initServer() { }
|
|
64
|
-
/**
|
|
65
|
-
* Get a site and if possible use the accept lang header.
|
|
66
|
-
*
|
|
67
|
-
* @param acceptLang Accept Language header.
|
|
68
|
-
*/
|
|
69
|
-
siteByAcceptLang(acceptLang = null) {
|
|
70
|
-
if (!acceptLang)
|
|
71
|
-
return this.defaultSite();
|
|
72
|
-
const directives = acceptLang
|
|
73
|
-
.split(',')
|
|
74
|
-
.map(d => d.trim())
|
|
75
|
-
.filter(d => !!d);
|
|
76
|
-
// let's expect that weights are correctly ordered
|
|
77
|
-
const languages = directives
|
|
78
|
-
.map(d => {
|
|
79
|
-
const lang = d.split(';');
|
|
80
|
-
return lang[0].trim();
|
|
81
|
-
})
|
|
82
|
-
.filter(d => !!d);
|
|
83
|
-
// find a site which matches the language
|
|
84
|
-
// first try to match the full language
|
|
85
|
-
for (const lang of languages) {
|
|
86
|
-
const site = this.sites.find(s => s.language === lang);
|
|
87
|
-
if (site)
|
|
88
|
-
return site;
|
|
89
|
-
}
|
|
90
|
-
// if we don't find any language which matches
|
|
91
|
-
// try to match languages without the -
|
|
92
|
-
for (let lang of languages) {
|
|
93
|
-
lang = lang.split('-')[0];
|
|
94
|
-
const site = this.sites.find(s => {
|
|
95
|
-
const sLang = s.language.split('-')[0];
|
|
96
|
-
return sLang === lang;
|
|
97
|
-
});
|
|
98
|
-
if (site)
|
|
99
|
-
return site;
|
|
100
|
-
}
|
|
101
|
-
// we did not find a match then just return the first site
|
|
102
|
-
return this.defaultSite();
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Get the default site
|
|
106
|
-
*/
|
|
107
|
-
defaultSite() {
|
|
108
|
-
return this.sites.find(s => s.primary) ?? this.sites[0];
|
|
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?.site ?? this.defaultSite();
|
|
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.routeFromUrl(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 Route
|
|
150
|
-
*
|
|
151
|
-
* @param url
|
|
152
|
-
* @return Returns null if the url does not match our host (the protocol get's ignored)
|
|
153
|
-
*/
|
|
154
|
-
routeFromUrl(fullUrl) {
|
|
155
|
-
// strip stuff we dont need from url
|
|
156
|
-
const route = new Route(fullUrl, null);
|
|
157
|
-
const url = route.url;
|
|
158
|
-
const site = siteFromUrl(url, this.sites);
|
|
159
|
-
// todo should we throw if we can't find a site
|
|
160
|
-
// or use the site which matches the language
|
|
161
|
-
route.site = site ?? this.defaultSite();
|
|
162
|
-
return route;
|
|
163
|
-
}
|
|
164
|
-
listen() {
|
|
165
|
-
window.addEventListener('click', async (e) => {
|
|
166
|
-
// @ts-ignore
|
|
167
|
-
const link = e.target.closest('a');
|
|
168
|
-
const openInNewTab = e.metaKey || e.ctrlKey || e.shiftKey;
|
|
169
|
-
const saveLink = e.altKey;
|
|
170
|
-
if (!link || !link.href || openInNewTab || saveLink)
|
|
171
|
-
return;
|
|
172
|
-
if (link.target.toLowerCase() === '_blank')
|
|
173
|
-
return;
|
|
174
|
-
if (!link.href.startsWith('http'))
|
|
175
|
-
return;
|
|
176
|
-
e.preventDefault();
|
|
177
|
-
const req = this.targetToRequest(link.href, { origin: 'click' });
|
|
178
|
-
const routeEq = this.route && this.route.eqUrl(req) && this.route.eqSearch(req);
|
|
179
|
-
// this means the route is the same maybe with a different hash
|
|
180
|
-
// so it is not necessary to load the data again
|
|
181
|
-
if (routeEq) {
|
|
182
|
-
req.disableLoadData = true;
|
|
183
|
-
}
|
|
184
|
-
this.open(req);
|
|
185
|
-
});
|
|
186
|
-
if (this.preloadOnMouseOver) {
|
|
187
|
-
let currentMouseOver = null;
|
|
188
|
-
window.addEventListener('mouseover', e => {
|
|
189
|
-
// @ts-ignore
|
|
190
|
-
const link = e.target.closest('a');
|
|
191
|
-
if (currentMouseOver && link === currentMouseOver)
|
|
192
|
-
return;
|
|
193
|
-
if (link && link.target.toLowerCase() === '_blank')
|
|
194
|
-
return;
|
|
195
|
-
if (link &&
|
|
196
|
-
!link.hasAttribute('data-no-preload') &&
|
|
197
|
-
link.href) {
|
|
198
|
-
this.preload(link.href);
|
|
199
|
-
}
|
|
200
|
-
currentMouseOver = link;
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
// store the scrollY position every 200ms
|
|
204
|
-
// we can't do this at the time of the open call since the pop event
|
|
205
|
-
// has already changed to a new history state so we can't update our
|
|
206
|
-
// current/previous state
|
|
207
|
-
// eslint-disable-next-line no-constant-condition
|
|
208
|
-
if (true) {
|
|
209
|
-
window.addEventListener('scroll', () => {
|
|
210
|
-
const current = this.route;
|
|
211
|
-
if (!current)
|
|
212
|
-
return;
|
|
213
|
-
// store the scroll position
|
|
214
|
-
current.scrollY = window.scrollY;
|
|
215
|
-
if (this.scrollDebounceTimeout)
|
|
216
|
-
return;
|
|
217
|
-
// this might cause `Attempt to use history.replaceState() more than
|
|
218
|
-
// 100 times per 30 seconds` in safari
|
|
219
|
-
// since we wait a moment we should almost ever be fine
|
|
220
|
-
this.scrollDebounceTimeout = setTimeout(() => {
|
|
221
|
-
if (!this.route || !current.eq(this.route))
|
|
222
|
-
return;
|
|
223
|
-
// use the latest state
|
|
224
|
-
this.history.replaceState(this.route._toState());
|
|
225
|
-
if (current.inLivePreview()) {
|
|
226
|
-
sessionStorage.setItem('live-preview-scroll',
|
|
227
|
-
// use the latest scrollY
|
|
228
|
-
this.route.scrollY + '');
|
|
229
|
-
}
|
|
230
|
-
this.scrollDebounceTimeout = null;
|
|
231
|
-
}, 280);
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
window.addEventListener('popstate', async (e) => {
|
|
235
|
-
if (!e.state?.route)
|
|
236
|
-
return;
|
|
237
|
-
const req = this.targetToRequest(window.location.href);
|
|
238
|
-
req._fillFromState(e.state);
|
|
239
|
-
req.origin = 'pop';
|
|
240
|
-
// we set it now instead of waiting for the onRoute call
|
|
241
|
-
// because the window.history was already modified
|
|
242
|
-
this.route = req.toRoute();
|
|
243
|
-
this.onRoute(req, () => { });
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Open a new route
|
|
248
|
-
*
|
|
249
|
-
* @param route a route object or an url or uri, never input the same route object again
|
|
250
|
-
* @param pushState if true pushed the state to the window.history
|
|
251
|
-
*
|
|
252
|
-
* ## Important
|
|
253
|
-
* Make sure a req always has the correct origin,
|
|
254
|
-
* `push` and `replace` will cause this function to throw an error
|
|
255
|
-
*/
|
|
256
|
-
open(req) {
|
|
257
|
-
if (['push', 'replace'].includes(req.origin)) {
|
|
258
|
-
throw new Error('Do not use open with push or replace');
|
|
259
|
-
}
|
|
260
|
-
const current = this.route;
|
|
261
|
-
// store scrollY
|
|
262
|
-
if (current) {
|
|
263
|
-
// if the scrollY would still be updated we clear the timeout
|
|
264
|
-
// since we should have the latest scrollY
|
|
265
|
-
if (this.scrollDebounceTimeout) {
|
|
266
|
-
clearTimeout(this.scrollDebounceTimeout);
|
|
267
|
-
this.scrollDebounceTimeout = null;
|
|
268
|
-
}
|
|
269
|
-
// store the scroll position
|
|
270
|
-
const scrollY = this.history.scrollY();
|
|
271
|
-
if (typeof scrollY === 'number') {
|
|
272
|
-
current.scrollY = scrollY;
|
|
273
|
-
this.history.replaceState(current._toState());
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
// if the domain of the current site is different than the domain of the
|
|
277
|
-
// new site we need to do a window.location.href call
|
|
278
|
-
if ((current && current.url.origin !== req.url.origin) ||
|
|
279
|
-
// @ts-ignore
|
|
280
|
-
import.meta.env.SSR) {
|
|
281
|
-
this.history.open(req);
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
req.index = (current?.index ?? 0) + 1;
|
|
285
|
-
this.onRoute(req, () => {
|
|
286
|
-
const url = req.url;
|
|
287
|
-
this.history.pushState(req._toState(), url.pathname + url.search + url.hash);
|
|
288
|
-
this.route = req.toRoute();
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* This pushes a new route to the history
|
|
293
|
-
*
|
|
294
|
-
* @param req, never input the same route object again
|
|
295
|
-
*
|
|
296
|
-
* ## Important
|
|
297
|
-
* Make sure the route has the correct origin
|
|
298
|
-
*/
|
|
299
|
-
push(req) {
|
|
300
|
-
const url = req.url;
|
|
301
|
-
// todo a push should also store the previous scrollY
|
|
302
|
-
let nReq = req;
|
|
303
|
-
if (req.scrollY === null) {
|
|
304
|
-
// if there is no scrollY stored we store the current scrollY
|
|
305
|
-
// since a push does not cause a scroll top
|
|
306
|
-
// todo: probably should refactor something probably
|
|
307
|
-
// should not be here
|
|
308
|
-
nReq = req.clone();
|
|
309
|
-
nReq.scrollY = this.history.scrollY();
|
|
310
|
-
}
|
|
311
|
-
this.onRoute(req, () => {
|
|
312
|
-
this.history.pushState(req._toState(), url.pathname + url.search + url.hash);
|
|
313
|
-
this.route = req.toRoute();
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* This replaces the current route
|
|
318
|
-
*
|
|
319
|
-
* @param req, never input the same route object again
|
|
320
|
-
*
|
|
321
|
-
* ## Important
|
|
322
|
-
* Make sure the route has the correct origin
|
|
323
|
-
*/
|
|
324
|
-
replace(req) {
|
|
325
|
-
const url = req.url;
|
|
326
|
-
let nReq = req;
|
|
327
|
-
if (req.scrollY === null) {
|
|
328
|
-
// if there is no scrollY stored we store the current scrollY
|
|
329
|
-
// since a replace does not cause a scrollTo and we wan't
|
|
330
|
-
// history back to work as intended
|
|
331
|
-
// todo: probably should refactor something probably
|
|
332
|
-
// should not be here
|
|
333
|
-
nReq = req.clone();
|
|
334
|
-
nReq.scrollY = this.history.scrollY();
|
|
335
|
-
}
|
|
336
|
-
this.onRoute(req, () => {
|
|
337
|
-
this.history.replaceState(req._toState(), url.pathname + url.search + url.hash);
|
|
338
|
-
this.route = req.toRoute();
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
/**
|
|
342
|
-
* Preload a url
|
|
343
|
-
*
|
|
344
|
-
* This will only work if the origin of the url matches the current site
|
|
345
|
-
*
|
|
346
|
-
* @param url
|
|
347
|
-
*/
|
|
348
|
-
preload(target) {
|
|
349
|
-
const req = this.targetToRequest(target);
|
|
350
|
-
const current = this.route;
|
|
351
|
-
// if the origin matches, the route will be able to be load
|
|
352
|
-
// so let's preload it
|
|
353
|
-
if (current && current.url.origin === req.url.origin) {
|
|
354
|
-
this.onPreload(req);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
domReady(req) {
|
|
358
|
-
if (req.disableScroll)
|
|
359
|
-
return;
|
|
360
|
-
// scroll to target
|
|
361
|
-
let scrollTo = null;
|
|
362
|
-
// if the route is a live preview init and we have a scrollY stored
|
|
363
|
-
// scroll to that
|
|
364
|
-
if (req.inLivePreview()) {
|
|
365
|
-
const scrollY = sessionStorage.getItem('live-preview-scroll');
|
|
366
|
-
if (scrollY) {
|
|
367
|
-
scrollTo = {
|
|
368
|
-
top: parseInt(scrollY),
|
|
369
|
-
behavior: 'instant',
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
// if we have a hash and the route was not visited
|
|
373
|
-
}
|
|
374
|
-
else if (req.hash &&
|
|
375
|
-
((req.origin === 'init' && typeof req.scrollY !== 'number') ||
|
|
376
|
-
req.origin === 'click')) {
|
|
377
|
-
const el = document.getElementById(req.hash.substring(1));
|
|
378
|
-
if (el) {
|
|
379
|
-
scrollTo = {
|
|
380
|
-
intoView: el,
|
|
381
|
-
behavior: 'smooth',
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
// restore scroll position
|
|
386
|
-
if (!scrollTo &&
|
|
387
|
-
req.origin !== 'click' &&
|
|
388
|
-
typeof req.scrollY === 'number') {
|
|
389
|
-
scrollTo = {
|
|
390
|
-
top: req.scrollY,
|
|
391
|
-
behavior: 'instant',
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
// make sure push and replace don't cause a scroll if it is not intended
|
|
395
|
-
if (!scrollTo && (req.origin === 'push' || req.origin === 'replace'))
|
|
396
|
-
return;
|
|
397
|
-
// scroll to the top if nothing else matches
|
|
398
|
-
if (!scrollTo) {
|
|
399
|
-
scrollTo = {
|
|
400
|
-
top: 0,
|
|
401
|
-
behavior: 'instant',
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
if ('top' in scrollTo) {
|
|
405
|
-
window.scrollTo({
|
|
406
|
-
top: scrollTo.top,
|
|
407
|
-
behavior: scrollTo.behavior,
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
else {
|
|
411
|
-
scrollTo.intoView.scrollIntoView({
|
|
412
|
-
behavior: scrollTo.behavior,
|
|
413
|
-
block: 'start',
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import Request from './Request.js';
|
|
2
|
-
export type PageLoaderOptions = {
|
|
3
|
-
debugTiming: boolean;
|
|
4
|
-
};
|
|
5
|
-
export type LoadResponse = {
|
|
6
|
-
success: boolean;
|
|
7
|
-
data: any;
|
|
8
|
-
};
|
|
9
|
-
export type LoadFn = (req: Request, opts: LoadOptions) => Promise<any> | any;
|
|
10
|
-
export type LoadOptions = {
|
|
11
|
-
setProgress: (num: number) => void;
|
|
12
|
-
};
|
|
13
|
-
/**
|
|
14
|
-
* The PageLoader which is responsible for loading page Data
|
|
15
|
-
*/
|
|
16
|
-
export default class PageLoader<More> {
|
|
17
|
-
private debugTiming;
|
|
18
|
-
private preloadedUrls;
|
|
19
|
-
private loadingVersion;
|
|
20
|
-
onLoaded: (resp: LoadResponse, req: Request, more: More) => void;
|
|
21
|
-
onProgress: (loading: boolean, progress?: number) => void;
|
|
22
|
-
loadFn: LoadFn;
|
|
23
|
-
/**
|
|
24
|
-
* Creates a new PageLoader
|
|
25
|
-
*
|
|
26
|
-
* @param {Object} options `{debugTiming}`
|
|
27
|
-
*/
|
|
28
|
-
constructor(options: PageLoaderOptions);
|
|
29
|
-
/**
|
|
30
|
-
* Discard the current page load if one is happening
|
|
31
|
-
*/
|
|
32
|
-
discard(): void;
|
|
33
|
-
load(req: Request, more: More): Promise<void>;
|
|
34
|
-
preload(req: Request): Promise<void>;
|
|
35
|
-
}
|
|
36
|
-
//# sourceMappingURL=PageLoader.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PageLoader.d.ts","sourceRoot":"","sources":["../../src/routing/PageLoader.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,MAAM,MAAM,iBAAiB,GAAG;IAC/B,WAAW,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,GAAG,CAAC;CACV,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;AAE7E,MAAM,MAAM,WAAW,GAAG;IACzB,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,UAAU,CAAC,IAAI;IACnC,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,aAAa,CAAc;IAEnC,OAAO,CAAC,cAAc,CAAS;IAE/B,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACjE,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,MAAM,EAAE,MAAM,CAAC;IAEf;;;;OAIG;gBACS,OAAO,EAAE,iBAAiB;IAWtC;;OAEG;IACH,OAAO;IAKD,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI;IAiC7B,OAAO,CAAC,GAAG,EAAE,OAAO;CAc1B"}
|