crelte 0.1.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.
- package/LICENSE.md +41 -0
- package/dist/Crelte.d.ts +55 -0
- package/dist/Crelte.d.ts.map +1 -0
- package/dist/Crelte.js +106 -0
- package/dist/CrelteBase.d.ts +16 -0
- package/dist/CrelteBase.d.ts.map +1 -0
- package/dist/CrelteBase.js +1 -0
- package/dist/CrelteRouted.d.ts +50 -0
- package/dist/CrelteRouted.d.ts.map +1 -0
- package/dist/CrelteRouted.js +88 -0
- package/dist/blocks/Blocks.d.ts +35 -0
- package/dist/blocks/Blocks.d.ts.map +1 -0
- package/dist/blocks/Blocks.js +100 -0
- package/dist/blocks/Blocks.svelte +21 -0
- package/dist/blocks/Blocks.svelte.d.ts +24 -0
- package/dist/blocks/Blocks.svelte.d.ts.map +1 -0
- package/dist/blocks/index.d.ts +5 -0
- package/dist/blocks/index.d.ts.map +1 -0
- package/dist/blocks/index.js +3 -0
- package/dist/cookies/ClientCookies.d.ts +9 -0
- package/dist/cookies/ClientCookies.d.ts.map +1 -0
- package/dist/cookies/ClientCookies.js +22 -0
- package/dist/cookies/ServerCookies.d.ts +13 -0
- package/dist/cookies/ServerCookies.d.ts.map +1 -0
- package/dist/cookies/ServerCookies.js +31 -0
- package/dist/cookies/index.d.ts +20 -0
- package/dist/cookies/index.d.ts.map +1 -0
- package/dist/cookies/index.js +1 -0
- package/dist/cookies/utils.d.ts +12 -0
- package/dist/cookies/utils.d.ts.map +1 -0
- package/dist/cookies/utils.js +32 -0
- package/dist/graphql/GraphQl.d.ts +60 -0
- package/dist/graphql/GraphQl.d.ts.map +1 -0
- package/dist/graphql/GraphQl.js +197 -0
- package/dist/graphql/gql.test.d.ts +2 -0
- package/dist/graphql/gql.test.d.ts.map +1 -0
- package/dist/graphql/gql.test.js +80 -0
- package/dist/graphql/index.d.ts +3 -0
- package/dist/graphql/index.d.ts.map +1 -0
- package/dist/graphql/index.js +2 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +83 -0
- package/dist/init/client.d.ts +13 -0
- package/dist/init/client.d.ts.map +1 -0
- package/dist/init/client.js +129 -0
- package/dist/init/server.d.ts +38 -0
- package/dist/init/server.d.ts.map +1 -0
- package/dist/init/server.js +95 -0
- package/dist/init/shared.d.ts +29 -0
- package/dist/init/shared.d.ts.map +1 -0
- package/dist/init/shared.js +154 -0
- package/dist/loadData/Globals.d.ts +33 -0
- package/dist/loadData/Globals.d.ts.map +1 -0
- package/dist/loadData/Globals.js +119 -0
- package/dist/loadData/index.d.ts +25 -0
- package/dist/loadData/index.d.ts.map +1 -0
- package/dist/loadData/index.js +39 -0
- package/dist/plugins/Events.d.ts +11 -0
- package/dist/plugins/Events.d.ts.map +1 -0
- package/dist/plugins/Events.js +29 -0
- package/dist/plugins/Plugins.d.ts +12 -0
- package/dist/plugins/Plugins.d.ts.map +1 -0
- package/dist/plugins/Plugins.js +12 -0
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +2 -0
- package/dist/routing/History.d.ts +22 -0
- package/dist/routing/History.d.ts.map +1 -0
- package/dist/routing/History.js +36 -0
- package/dist/routing/InnerRouter.d.ts +111 -0
- package/dist/routing/InnerRouter.d.ts.map +1 -0
- package/dist/routing/InnerRouter.js +397 -0
- package/dist/routing/PageLoader.d.ts +37 -0
- package/dist/routing/PageLoader.d.ts.map +1 -0
- package/dist/routing/PageLoader.js +72 -0
- package/dist/routing/Route.d.ts +82 -0
- package/dist/routing/Route.d.ts.map +1 -0
- package/dist/routing/Route.js +134 -0
- package/dist/routing/Router.d.ts +162 -0
- package/dist/routing/Router.d.ts.map +1 -0
- package/dist/routing/Router.js +333 -0
- package/dist/routing/Site.d.ts +47 -0
- package/dist/routing/Site.d.ts.map +1 -0
- package/dist/routing/Site.js +48 -0
- package/dist/routing/index.d.ts +5 -0
- package/dist/routing/index.d.ts.map +1 -0
- package/dist/routing/index.js +4 -0
- package/dist/ssr/SsrCache.d.ts +12 -0
- package/dist/ssr/SsrCache.d.ts.map +1 -0
- package/dist/ssr/SsrCache.js +50 -0
- package/dist/ssr/SsrComponents.d.ts +7 -0
- package/dist/ssr/SsrComponents.d.ts.map +1 -0
- package/dist/ssr/SsrComponents.js +30 -0
- package/dist/ssr/index.d.ts +4 -0
- package/dist/ssr/index.d.ts.map +1 -0
- package/dist/ssr/index.js +3 -0
- package/package.json +79 -0
- package/src/Crelte.ts +135 -0
- package/src/CrelteBase.ts +24 -0
- package/src/CrelteRouted.ts +128 -0
- package/src/blocks/Blocks.svelte +68 -0
- package/src/blocks/Blocks.ts +155 -0
- package/src/blocks/index.ts +14 -0
- package/src/cookies/ClientCookies.ts +30 -0
- package/src/cookies/ServerCookies.ts +42 -0
- package/src/cookies/index.ts +24 -0
- package/src/cookies/utils.ts +53 -0
- package/src/graphql/GraphQl.ts +281 -0
- package/src/graphql/gql.test.ts +123 -0
- package/src/graphql/index.ts +8 -0
- package/src/index.ts +109 -0
- package/src/init/client.ts +190 -0
- package/src/init/server.ts +177 -0
- package/src/init/shared.ts +221 -0
- package/src/loadData/Globals.ts +150 -0
- package/src/loadData/index.ts +67 -0
- package/src/plugins/Events.ts +50 -0
- package/src/plugins/Plugins.ts +23 -0
- package/src/plugins/index.ts +5 -0
- package/src/routing/History.ts +52 -0
- package/src/routing/InnerRouter.ts +469 -0
- package/src/routing/PageLoader.ts +112 -0
- package/src/routing/Route.ts +184 -0
- package/src/routing/Router.ts +476 -0
- package/src/routing/Site.ts +65 -0
- package/src/routing/index.ts +5 -0
- package/src/ssr/SsrCache.ts +61 -0
- package/src/ssr/SsrComponents.ts +34 -0
- package/src/ssr/index.ts +4 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CrelteRouted } from '../index.js';
|
|
2
|
+
export default class Events {
|
|
3
|
+
inner: Map<string, Set<any>>;
|
|
4
|
+
constructor();
|
|
5
|
+
on(ev: 'loadGlobalData', fn: (cr: CrelteRouted) => Promise<any>): () => void;
|
|
6
|
+
on(ev: 'loadData', fn: (cr: CrelteRouted, entry: any, data: any) => Promise<any>): () => void;
|
|
7
|
+
on(ev: 'beforeRender', fn: (cr: CrelteRouted) => void): () => void;
|
|
8
|
+
remove(ev: string, fn: any): void;
|
|
9
|
+
trigger(ev: string, ...args: any[]): any[];
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=Events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Events.d.ts","sourceRoot":"","sources":["../../../../src/plugins/Events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,CAAC,OAAO,OAAO,MAAM;IAC1B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;;IAU7B,EAAE,CACD,EAAE,EAAE,gBAAgB,EACpB,EAAE,EAAE,CAAC,EAAE,EAAE,YAAY,KAAK,OAAO,CAAC,GAAG,CAAC,GACpC,MAAM,IAAI;IACb,EAAE,CACD,EAAE,EAAE,UAAU,EACd,EAAE,EAAE,CAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAC3D,MAAM,IAAI;IACb,EAAE,CAAC,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI;IAelE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG;IAO1B,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE;CAM1C"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export default class Events {
|
|
2
|
+
inner;
|
|
3
|
+
constructor() {
|
|
4
|
+
this.inner = new Map();
|
|
5
|
+
}
|
|
6
|
+
on(ev, fn) {
|
|
7
|
+
let set = this.inner.get(ev);
|
|
8
|
+
if (!set) {
|
|
9
|
+
set = new Set();
|
|
10
|
+
this.inner.set(ev, set);
|
|
11
|
+
}
|
|
12
|
+
set.add(fn);
|
|
13
|
+
return () => {
|
|
14
|
+
set.delete(fn);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
remove(ev, fn) {
|
|
18
|
+
const set = this.inner.get(ev);
|
|
19
|
+
if (!set)
|
|
20
|
+
return;
|
|
21
|
+
set.delete(fn);
|
|
22
|
+
}
|
|
23
|
+
trigger(ev, ...args) {
|
|
24
|
+
const set = this.inner.get(ev);
|
|
25
|
+
if (!set)
|
|
26
|
+
return [];
|
|
27
|
+
return Array.from(set).map(fn => fn(...args));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import Crelte from '../Crelte.js';
|
|
2
|
+
export interface Plugin {
|
|
3
|
+
name: string;
|
|
4
|
+
}
|
|
5
|
+
export type PluginCreator = (crelte: Crelte) => Plugin;
|
|
6
|
+
export default class Plugins {
|
|
7
|
+
plugins: Map<string, Plugin>;
|
|
8
|
+
constructor();
|
|
9
|
+
add(plugin: Plugin): void;
|
|
10
|
+
get(name: string): Plugin | null;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=Plugins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Plugins.d.ts","sourceRoot":"","sources":["../../../../src/plugins/Plugins.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC,MAAM,WAAW,MAAM;IACtB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;AAEvD,MAAM,CAAC,OAAO,OAAO,OAAO;IAC3B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;;IAM7B,GAAG,CAAC,MAAM,EAAE,MAAM;IAIlB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAGhC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/plugins/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAErD,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export default interface History {
|
|
2
|
+
scrollY(): number;
|
|
3
|
+
replaceState(data: any, url?: string): void;
|
|
4
|
+
pushState(data: any, url: string): void;
|
|
5
|
+
open(url: string): void;
|
|
6
|
+
}
|
|
7
|
+
export declare class ClientHistory implements History {
|
|
8
|
+
scrollY(): number;
|
|
9
|
+
replaceState(data: any, url?: string): void;
|
|
10
|
+
pushState(data: any, url: string): void;
|
|
11
|
+
open(url: string): void;
|
|
12
|
+
}
|
|
13
|
+
export declare class ServerHistory implements History {
|
|
14
|
+
state: any | null;
|
|
15
|
+
url: string | null;
|
|
16
|
+
constructor();
|
|
17
|
+
scrollY(): number;
|
|
18
|
+
replaceState(data: any, url?: string): void;
|
|
19
|
+
pushState(data: any, url: string): void;
|
|
20
|
+
open(url: string): void;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=History.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"History.d.ts","sourceRoot":"","sources":["../../../../src/routing/History.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,WAAW,OAAO;IAC/B,OAAO,IAAI,MAAM,CAAC;IAClB,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,qBAAa,aAAc,YAAW,OAAO;IAC5C,OAAO,IAAI,MAAM;IAIjB,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAI3C,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAIvC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAGvB;AAED,qBAAa,aAAc,YAAW,OAAO;IAC5C,KAAK,EAAE,GAAG,GAAG,IAAI,CAAC;IAClB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;;IAOnB,OAAO,IAAI,MAAM;IAIjB,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAK3C,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAKvC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAGvB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export class ClientHistory {
|
|
2
|
+
scrollY() {
|
|
3
|
+
return window.scrollY;
|
|
4
|
+
}
|
|
5
|
+
replaceState(data, url) {
|
|
6
|
+
history.replaceState(data, '', url);
|
|
7
|
+
}
|
|
8
|
+
pushState(data, url) {
|
|
9
|
+
history.pushState(data, '', url);
|
|
10
|
+
}
|
|
11
|
+
open(url) {
|
|
12
|
+
window.location.href = url;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class ServerHistory {
|
|
16
|
+
state;
|
|
17
|
+
url;
|
|
18
|
+
constructor() {
|
|
19
|
+
this.state = null;
|
|
20
|
+
this.url = null;
|
|
21
|
+
}
|
|
22
|
+
scrollY() {
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
replaceState(data, url) {
|
|
26
|
+
this.state = data;
|
|
27
|
+
this.url = url ?? null;
|
|
28
|
+
}
|
|
29
|
+
pushState(data, url) {
|
|
30
|
+
this.state = data;
|
|
31
|
+
this.url = url;
|
|
32
|
+
}
|
|
33
|
+
open(url) {
|
|
34
|
+
this.url = url;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import Route from './Route.js';
|
|
2
|
+
import Site, { SiteFromGraphQl } from './Site.js';
|
|
3
|
+
import History from './History.js';
|
|
4
|
+
export type InnerRouterOpts = {
|
|
5
|
+
preloadOnMouseOver: boolean;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Manages event listeners or functions.
|
|
9
|
+
*/
|
|
10
|
+
export default class InnerRouter {
|
|
11
|
+
sites: Site[];
|
|
12
|
+
route: Route | null;
|
|
13
|
+
site: Site;
|
|
14
|
+
history: History;
|
|
15
|
+
preloadOnMouseOver: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* @param changeHistory returns a function you need to call when you are ready to
|
|
18
|
+
update the window history (note do not call this after another onRoute call was made)
|
|
19
|
+
*/
|
|
20
|
+
onRoute: (route: Route, site: Site, changeHistory: () => void) => void;
|
|
21
|
+
onPreload: (route: Route, site: Site) => void;
|
|
22
|
+
private scrollDebounceTimeout;
|
|
23
|
+
/**
|
|
24
|
+
* Creates a new Router
|
|
25
|
+
*
|
|
26
|
+
* @param sites - sites needs to be from craft-graphql-sites plugin
|
|
27
|
+
* @param opts - Options for the router
|
|
28
|
+
*/
|
|
29
|
+
constructor(sites: SiteFromGraphQl[], opts: InnerRouterOpts);
|
|
30
|
+
/**
|
|
31
|
+
* Initializes the router when running on the client.
|
|
32
|
+
*/
|
|
33
|
+
initClient(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Initializes the router when running on the server.
|
|
36
|
+
*/
|
|
37
|
+
initServer(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Get a site and if possible use the accept lang header.
|
|
40
|
+
*
|
|
41
|
+
* @param {(string|null)} [acceptLang=null] Accept Language header.
|
|
42
|
+
* @return {Site}
|
|
43
|
+
*/
|
|
44
|
+
siteByAcceptLang(acceptLang?: string | null): Site;
|
|
45
|
+
/**
|
|
46
|
+
* Get the default site
|
|
47
|
+
*/
|
|
48
|
+
defaultSite(): Site;
|
|
49
|
+
/**
|
|
50
|
+
* Tries to get a site by it's id
|
|
51
|
+
*/
|
|
52
|
+
siteById(id: number): Site | null;
|
|
53
|
+
/**
|
|
54
|
+
* Resolve a url or Route and convert it to a Route
|
|
55
|
+
*
|
|
56
|
+
* @param target
|
|
57
|
+
* @return Returns null if the url does not match our host (the protocol get's ignored)
|
|
58
|
+
*/
|
|
59
|
+
targetToRoute(target: string | URL | Route): Route;
|
|
60
|
+
/**
|
|
61
|
+
* Resolve a url and convert it to a Route
|
|
62
|
+
*
|
|
63
|
+
* @param url
|
|
64
|
+
* @return Returns null if the url does not match our host (the protocol get's ignored)
|
|
65
|
+
*/
|
|
66
|
+
routeFromUrl(fullUrl: URL): Route;
|
|
67
|
+
listen(): void;
|
|
68
|
+
/**
|
|
69
|
+
* Open's a route
|
|
70
|
+
*
|
|
71
|
+
* @param route a route object or an url or uri, never input the same route object again
|
|
72
|
+
* @param pushState if true pushed the state to the window.history
|
|
73
|
+
*/
|
|
74
|
+
open(target: string | URL | Route, pushState?: boolean): void;
|
|
75
|
+
/**
|
|
76
|
+
* Sets a route
|
|
77
|
+
*
|
|
78
|
+
* Will trigger an onRoute event but will not store any scroll progress
|
|
79
|
+
* or modify the history
|
|
80
|
+
*
|
|
81
|
+
* @param route
|
|
82
|
+
*/
|
|
83
|
+
setRoute(route: Route): void;
|
|
84
|
+
/**
|
|
85
|
+
* This pushes the state of the route without triggering a currentRoute
|
|
86
|
+
* or currentSiteId change
|
|
87
|
+
*
|
|
88
|
+
* You can use when using pagination for example change the route object
|
|
89
|
+
* (search argument) and then call pushState
|
|
90
|
+
*
|
|
91
|
+
* @param route, never input the same route object again
|
|
92
|
+
*/
|
|
93
|
+
pushState(route: Route): void;
|
|
94
|
+
/**
|
|
95
|
+
* This replaces the state of the route without triggering a currentRoute
|
|
96
|
+
* or currentSiteId change
|
|
97
|
+
*
|
|
98
|
+
* @param route, never input the same route object again
|
|
99
|
+
*/
|
|
100
|
+
replaceState(route: Route): void;
|
|
101
|
+
/**
|
|
102
|
+
* Preload a url
|
|
103
|
+
*
|
|
104
|
+
* This will only work if the origin of the url matches the current site
|
|
105
|
+
*
|
|
106
|
+
* @param url
|
|
107
|
+
*/
|
|
108
|
+
preload(target: string | URL | Route): void;
|
|
109
|
+
domReady(route: Route): void;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=InnerRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InnerRouter.d.ts","sourceRoot":"","sources":["../../../../src/routing/InnerRouter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,IAAI,EAAE,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,OAAyC,MAAM,cAAc,CAAC;AAErE,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,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACvE,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAE9C,OAAO,CAAC,qBAAqB,CAAa;IAE1C;;;;;OAKG;gBACS,KAAK,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,eAAe;IAmB3D;;OAEG;IACH,UAAU;IAkBV;;OAEG;IACH,UAAU;IAEV;;;;;OAKG;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;IAIjC;;;;;OAKG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK,GAAG,KAAK;IAiBlD;;;;;OAKG;IACH,YAAY,CAAC,OAAO,EAAE,GAAG,GAAG,KAAK;IA8BjC,MAAM;IA0FN;;;;;OAKG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK,EAAE,SAAS,GAAE,OAAc;IAkC5D;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,EAAE,KAAK;IAOrB;;;;;;;;OAQG;IACH,SAAS,CAAC,KAAK,EAAE,KAAK;IAYtB;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK;IAYzB;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK;IAmBpC,QAAQ,CAAC,KAAK,EAAE,KAAK;CAgErB"}
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import Route from './Route.js';
|
|
2
|
+
import Site from './Site.js';
|
|
3
|
+
import { ClientHistory, ServerHistory } from './History.js';
|
|
4
|
+
/**
|
|
5
|
+
* Manages event listeners or functions.
|
|
6
|
+
*/
|
|
7
|
+
export default class InnerRouter {
|
|
8
|
+
sites;
|
|
9
|
+
route;
|
|
10
|
+
site;
|
|
11
|
+
history;
|
|
12
|
+
preloadOnMouseOver;
|
|
13
|
+
/**
|
|
14
|
+
* @param changeHistory returns a function you need to call when you are ready to
|
|
15
|
+
update the window history (note do not call this after another onRoute call was made)
|
|
16
|
+
*/
|
|
17
|
+
onRoute;
|
|
18
|
+
onPreload;
|
|
19
|
+
scrollDebounceTimeout;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new Router
|
|
22
|
+
*
|
|
23
|
+
* @param sites - sites needs to be from craft-graphql-sites plugin
|
|
24
|
+
* @param opts - Options for the router
|
|
25
|
+
*/
|
|
26
|
+
constructor(sites, opts) {
|
|
27
|
+
this.sites = sites.map(s => new Site(s));
|
|
28
|
+
this.route = null;
|
|
29
|
+
this.site = this.defaultSite();
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
this.history = import.meta.env.SSR
|
|
32
|
+
? new ServerHistory()
|
|
33
|
+
: new ClientHistory();
|
|
34
|
+
this.preloadOnMouseOver = opts.preloadOnMouseOver;
|
|
35
|
+
// this.preloadListeners = new Listeners();
|
|
36
|
+
this.onRoute = () => { };
|
|
37
|
+
this.onPreload = () => { };
|
|
38
|
+
this.scrollDebounceTimeout = null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Initializes the router when running on the client.
|
|
42
|
+
*/
|
|
43
|
+
initClient() {
|
|
44
|
+
this.listen();
|
|
45
|
+
// let's first try to load from the state
|
|
46
|
+
const route = this.targetToRoute(window.location.href);
|
|
47
|
+
route._fillFromState(window.history.state);
|
|
48
|
+
route.origin = 'init';
|
|
49
|
+
if (route.search.get('x-craft-live-preview')) {
|
|
50
|
+
route.origin = 'live-preview-init';
|
|
51
|
+
}
|
|
52
|
+
window.history.scrollRestoration = 'manual';
|
|
53
|
+
this.open(route, false);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Initializes the router when running on the server.
|
|
57
|
+
*/
|
|
58
|
+
initServer() { }
|
|
59
|
+
/**
|
|
60
|
+
* Get a site and if possible use the accept lang header.
|
|
61
|
+
*
|
|
62
|
+
* @param {(string|null)} [acceptLang=null] Accept Language header.
|
|
63
|
+
* @return {Site}
|
|
64
|
+
*/
|
|
65
|
+
siteByAcceptLang(acceptLang = null) {
|
|
66
|
+
if (!acceptLang)
|
|
67
|
+
return this.defaultSite();
|
|
68
|
+
const directives = acceptLang
|
|
69
|
+
.split(',')
|
|
70
|
+
.map(d => d.trim())
|
|
71
|
+
.filter(d => !!d);
|
|
72
|
+
// let's expect that weights are correctly ordered
|
|
73
|
+
const languages = directives
|
|
74
|
+
.map(d => {
|
|
75
|
+
const lang = d.split(';');
|
|
76
|
+
return lang[0].trim();
|
|
77
|
+
})
|
|
78
|
+
.filter(d => !!d);
|
|
79
|
+
// find a site which matches the language
|
|
80
|
+
// first try to match the full language
|
|
81
|
+
for (const lang of languages) {
|
|
82
|
+
const site = this.sites.find(s => s.language === lang);
|
|
83
|
+
if (site)
|
|
84
|
+
return site;
|
|
85
|
+
}
|
|
86
|
+
// if we don't find any language which matches
|
|
87
|
+
// try to match languages without the -
|
|
88
|
+
for (let lang of languages) {
|
|
89
|
+
lang = lang.split('-')[0];
|
|
90
|
+
const site = this.sites.find(s => {
|
|
91
|
+
const sLang = s.language.split('-')[0];
|
|
92
|
+
return sLang === lang;
|
|
93
|
+
});
|
|
94
|
+
if (site)
|
|
95
|
+
return site;
|
|
96
|
+
}
|
|
97
|
+
// we did not find a match then just return the first site
|
|
98
|
+
return this.defaultSite();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get the default site
|
|
102
|
+
*/
|
|
103
|
+
defaultSite() {
|
|
104
|
+
return this.sites[0];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Tries to get a site by it's id
|
|
108
|
+
*/
|
|
109
|
+
siteById(id) {
|
|
110
|
+
return this.sites.find(s => s.id === id) ?? null;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Resolve a url or Route and convert it to a Route
|
|
114
|
+
*
|
|
115
|
+
* @param target
|
|
116
|
+
* @return Returns null if the url does not match our host (the protocol get's ignored)
|
|
117
|
+
*/
|
|
118
|
+
targetToRoute(target) {
|
|
119
|
+
if (typeof target === 'string') {
|
|
120
|
+
if (target.startsWith('/')) {
|
|
121
|
+
const site = this.site;
|
|
122
|
+
target = new URL(site.uri + target, site.url);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
target = new URL(target);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (target instanceof URL) {
|
|
129
|
+
return this.routeFromUrl(target);
|
|
130
|
+
}
|
|
131
|
+
return target;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Resolve a url and convert it to a Route
|
|
135
|
+
*
|
|
136
|
+
* @param url
|
|
137
|
+
* @return Returns null if the url does not match our host (the protocol get's ignored)
|
|
138
|
+
*/
|
|
139
|
+
routeFromUrl(fullUrl) {
|
|
140
|
+
// strip stuff we dont need from url
|
|
141
|
+
const route = new Route(fullUrl, null);
|
|
142
|
+
const url = route.url;
|
|
143
|
+
let site = null;
|
|
144
|
+
// get the site which matches the url the most
|
|
145
|
+
for (const s of this.sites) {
|
|
146
|
+
const siteUri = s.uri;
|
|
147
|
+
// make sure the start of the url matches
|
|
148
|
+
if (url.host !== s.url.host || !url.pathname.startsWith(siteUri)) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
// make sure that after the base url a slash follows or nothing
|
|
152
|
+
const uri = url.pathname.substring(siteUri.length);
|
|
153
|
+
if (uri.length > 0 && !uri.startsWith('/'))
|
|
154
|
+
continue;
|
|
155
|
+
/// make sure we get the most matched site
|
|
156
|
+
if (site && site.uri.length > siteUri.length)
|
|
157
|
+
continue;
|
|
158
|
+
site = s;
|
|
159
|
+
}
|
|
160
|
+
route.site = site;
|
|
161
|
+
return route;
|
|
162
|
+
}
|
|
163
|
+
listen() {
|
|
164
|
+
window.addEventListener('click', async (e) => {
|
|
165
|
+
// @ts-ignore
|
|
166
|
+
const link = e.target.closest('a');
|
|
167
|
+
const openInNewTab = e.metaKey || e.ctrlKey || e.shiftKey;
|
|
168
|
+
const saveLink = e.altKey;
|
|
169
|
+
if (!link || !link.href || openInNewTab || saveLink)
|
|
170
|
+
return;
|
|
171
|
+
if (link.target.toLowerCase() === '_blank')
|
|
172
|
+
return;
|
|
173
|
+
if (!link.href.startsWith('http'))
|
|
174
|
+
return;
|
|
175
|
+
e.preventDefault();
|
|
176
|
+
const route = this.routeFromUrl(link.href);
|
|
177
|
+
if (this.route?.eq(route))
|
|
178
|
+
return;
|
|
179
|
+
route.origin = 'click';
|
|
180
|
+
this.open(route);
|
|
181
|
+
});
|
|
182
|
+
if (this.preloadOnMouseOver) {
|
|
183
|
+
let currentMouseOver = null;
|
|
184
|
+
window.addEventListener('mouseover', e => {
|
|
185
|
+
// @ts-ignore
|
|
186
|
+
const link = e.target.closest('a');
|
|
187
|
+
if (currentMouseOver && link === currentMouseOver)
|
|
188
|
+
return;
|
|
189
|
+
if (link && link.target.toLowerCase() === '_blank')
|
|
190
|
+
return;
|
|
191
|
+
if (link && !link.hasAttribute('data-no-preload')) {
|
|
192
|
+
this.preload(link.href);
|
|
193
|
+
}
|
|
194
|
+
currentMouseOver = link;
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
// store the scrollY position every 200ms
|
|
198
|
+
// we can't do this at the time of the open call since the pop event
|
|
199
|
+
// has already changed to a new history state so we can't update our
|
|
200
|
+
// current/previous state
|
|
201
|
+
// eslint-disable-next-line no-constant-condition
|
|
202
|
+
if (true) {
|
|
203
|
+
window.addEventListener('scroll', () => {
|
|
204
|
+
const current = this.route;
|
|
205
|
+
if (!current)
|
|
206
|
+
return;
|
|
207
|
+
// store the scroll position
|
|
208
|
+
current.scrollY = window.scrollY;
|
|
209
|
+
if (this.scrollDebounceTimeout)
|
|
210
|
+
return;
|
|
211
|
+
// this might cause `Attempt to use history.replaceState() more than
|
|
212
|
+
// 100 times per 30 seconds` in safari
|
|
213
|
+
// since we wait a moment we should almost ever be fine
|
|
214
|
+
this.scrollDebounceTimeout = setTimeout(() => {
|
|
215
|
+
if (!this.route || !current.eq(this.route))
|
|
216
|
+
return;
|
|
217
|
+
// use the latest state
|
|
218
|
+
this.history.replaceState(this.route._toState());
|
|
219
|
+
if (current.origin === 'live-preview-init') {
|
|
220
|
+
sessionStorage.setItem('live-preview-scroll',
|
|
221
|
+
// use the latest scrollY
|
|
222
|
+
this.route.scrollY + '');
|
|
223
|
+
}
|
|
224
|
+
this.scrollDebounceTimeout = null;
|
|
225
|
+
}, 280);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
window.addEventListener('popstate', async (e) => {
|
|
229
|
+
if (!('route' in e.state))
|
|
230
|
+
return;
|
|
231
|
+
const route = this.targetToRoute(window.location.href);
|
|
232
|
+
route._fillFromState(e.state);
|
|
233
|
+
route.origin = 'pop';
|
|
234
|
+
// since the pop event replaced our state we can't replace the state
|
|
235
|
+
// for the scrollY in our open call so we just clear the current
|
|
236
|
+
// route since it is now already the new route
|
|
237
|
+
this.route = null;
|
|
238
|
+
this.open(route, false);
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Open's a route
|
|
243
|
+
*
|
|
244
|
+
* @param route a route object or an url or uri, never input the same route object again
|
|
245
|
+
* @param pushState if true pushed the state to the window.history
|
|
246
|
+
*/
|
|
247
|
+
open(target, pushState = true) {
|
|
248
|
+
const route = this.targetToRoute(target);
|
|
249
|
+
const current = this.route;
|
|
250
|
+
if (current) {
|
|
251
|
+
// if the scrollY will still be updated we clear the timeout
|
|
252
|
+
// since we should have the latest scrollY
|
|
253
|
+
if (this.scrollDebounceTimeout) {
|
|
254
|
+
clearTimeout(this.scrollDebounceTimeout);
|
|
255
|
+
this.scrollDebounceTimeout = null;
|
|
256
|
+
}
|
|
257
|
+
// store the scroll position
|
|
258
|
+
current.scrollY = this.history.scrollY();
|
|
259
|
+
this.history.replaceState(current._toState());
|
|
260
|
+
}
|
|
261
|
+
// if the domain of the current site is different than the domain of the
|
|
262
|
+
// new site we need to do a window.location.href call
|
|
263
|
+
if (current && current.url.origin !== route.url.origin) {
|
|
264
|
+
this.history.open(route.url.href);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (pushState) {
|
|
268
|
+
route.index = (current?.index ?? 0) + 1;
|
|
269
|
+
this.onRoute(route, route.site ?? this.site, () => {
|
|
270
|
+
this.pushState(route);
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
this.setRoute(route);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Sets a route
|
|
279
|
+
*
|
|
280
|
+
* Will trigger an onRoute event but will not store any scroll progress
|
|
281
|
+
* or modify the history
|
|
282
|
+
*
|
|
283
|
+
* @param route
|
|
284
|
+
*/
|
|
285
|
+
setRoute(route) {
|
|
286
|
+
this.route = route;
|
|
287
|
+
if (route.site)
|
|
288
|
+
this.site = route.site;
|
|
289
|
+
this.onRoute(route, this.site, () => { });
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* This pushes the state of the route without triggering a currentRoute
|
|
293
|
+
* or currentSiteId change
|
|
294
|
+
*
|
|
295
|
+
* You can use when using pagination for example change the route object
|
|
296
|
+
* (search argument) and then call pushState
|
|
297
|
+
*
|
|
298
|
+
* @param route, never input the same route object again
|
|
299
|
+
*/
|
|
300
|
+
pushState(route) {
|
|
301
|
+
const url = route.url;
|
|
302
|
+
this.history.pushState(route._toState(), url.pathname + url.search + url.hash);
|
|
303
|
+
this.route = route;
|
|
304
|
+
if (route.site)
|
|
305
|
+
this.site = route.site;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* This replaces the state of the route without triggering a currentRoute
|
|
309
|
+
* or currentSiteId change
|
|
310
|
+
*
|
|
311
|
+
* @param route, never input the same route object again
|
|
312
|
+
*/
|
|
313
|
+
replaceState(route) {
|
|
314
|
+
const url = route.url;
|
|
315
|
+
this.history.replaceState(route._toState(), url.pathname + url.search + url.hash);
|
|
316
|
+
this.route = route;
|
|
317
|
+
if (route.site)
|
|
318
|
+
this.site = route.site;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Preload a url
|
|
322
|
+
*
|
|
323
|
+
* This will only work if the origin of the url matches the current site
|
|
324
|
+
*
|
|
325
|
+
* @param url
|
|
326
|
+
*/
|
|
327
|
+
preload(target) {
|
|
328
|
+
const route = this.targetToRoute(target);
|
|
329
|
+
// if the domain of the current site is different than the domain of the
|
|
330
|
+
// new site id does not make sense to preload
|
|
331
|
+
if (this.site.url.origin !== route.url.origin) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const current = this.route;
|
|
335
|
+
const site = route.site ?? this.site;
|
|
336
|
+
// if the origin matches, the route will be able to be load
|
|
337
|
+
// so let's preload it
|
|
338
|
+
if (current && current.url.origin === route.url.origin) {
|
|
339
|
+
this.onPreload(route, site);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
domReady(route) {
|
|
343
|
+
// scroll to target
|
|
344
|
+
let scrollTo = null;
|
|
345
|
+
// if the route is a live preview init and we have a scrollY stored
|
|
346
|
+
// scroll to that
|
|
347
|
+
if (route.origin === 'live-preview-init') {
|
|
348
|
+
const scrollY = sessionStorage.getItem('live-preview-scroll');
|
|
349
|
+
if (scrollY) {
|
|
350
|
+
scrollTo = {
|
|
351
|
+
top: parseInt(scrollY),
|
|
352
|
+
behavior: 'instant',
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
// if we have a hash and the route was not visited
|
|
356
|
+
}
|
|
357
|
+
else if (route.hash &&
|
|
358
|
+
((route.origin === 'init' && typeof route.scrollY !== 'number') ||
|
|
359
|
+
route.origin === 'click')) {
|
|
360
|
+
const el = document.getElementById(route.hash.substring(1));
|
|
361
|
+
if (el) {
|
|
362
|
+
scrollTo = {
|
|
363
|
+
intoView: el,
|
|
364
|
+
behavior: 'smooth',
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// restore scroll position
|
|
369
|
+
if (!scrollTo &&
|
|
370
|
+
route.origin !== 'click' &&
|
|
371
|
+
typeof route.scrollY === 'number') {
|
|
372
|
+
scrollTo = {
|
|
373
|
+
top: route.scrollY,
|
|
374
|
+
behavior: 'instant',
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
// scroll to the top if nothing else matches
|
|
378
|
+
if (!scrollTo) {
|
|
379
|
+
scrollTo = {
|
|
380
|
+
top: 0,
|
|
381
|
+
behavior: 'instant',
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
if ('top' in scrollTo) {
|
|
385
|
+
window.scrollTo({
|
|
386
|
+
top: scrollTo.top,
|
|
387
|
+
behavior: scrollTo.behavior,
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
scrollTo.intoView.scrollIntoView({
|
|
392
|
+
behavior: scrollTo.behavior,
|
|
393
|
+
block: 'start',
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|