crelte 0.1.1 → 0.1.3
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 +89 -25
- package/dist/Crelte.d.ts.map +1 -1
- package/dist/Crelte.js +79 -38
- package/dist/CrelteRequest.d.ts +63 -0
- package/dist/CrelteRequest.d.ts.map +1 -0
- package/dist/CrelteRequest.js +94 -0
- package/dist/blocks/Blocks.d.ts +27 -3
- package/dist/blocks/Blocks.d.ts.map +1 -1
- package/dist/blocks/Blocks.js +8 -0
- package/dist/blocks/Blocks.svelte +1 -1
- package/dist/blocks/Blocks.svelte.d.ts +36 -4
- package/dist/blocks/Blocks.svelte.d.ts.map +1 -1
- package/dist/blocks/index.d.ts +6 -3
- package/dist/blocks/index.d.ts.map +1 -1
- package/dist/blocks/index.js +3 -2
- package/dist/cookies/ServerCookies.d.ts +1 -1
- package/dist/cookies/ServerCookies.d.ts.map +1 -1
- package/dist/cookies/index.d.ts +7 -0
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/graphql/GraphQl.d.ts +53 -14
- package/dist/graphql/GraphQl.d.ts.map +1 -1
- package/dist/graphql/GraphQl.js +44 -23
- package/dist/graphql/index.d.ts +1 -1
- package/dist/graphql/index.d.ts.map +1 -1
- package/dist/graphql/index.js +2 -2
- package/dist/index.d.ts +55 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +50 -23
- package/dist/init/client.d.ts +43 -2
- package/dist/init/client.d.ts.map +1 -1
- package/dist/init/client.js +26 -6
- package/dist/init/server.d.ts +49 -2
- package/dist/init/server.d.ts.map +1 -1
- package/dist/init/server.js +56 -6
- package/dist/init/shared.d.ts +5 -4
- package/dist/init/shared.d.ts.map +1 -1
- package/dist/init/shared.js +3 -3
- package/dist/loadData/Globals.d.ts +41 -2
- package/dist/loadData/Globals.d.ts.map +1 -1
- package/dist/loadData/Globals.js +33 -5
- package/dist/loadData/index.d.ts +74 -11
- package/dist/loadData/index.d.ts.map +1 -1
- package/dist/loadData/index.js +5 -8
- package/dist/plugins/Events.d.ts +18 -5
- package/dist/plugins/Events.d.ts.map +1 -1
- package/dist/plugins/Events.js +3 -0
- package/dist/plugins/Plugins.d.ts +28 -2
- package/dist/plugins/Plugins.d.ts.map +1 -1
- package/dist/plugins/Plugins.js +8 -0
- package/dist/routing/History.d.ts +3 -0
- package/dist/routing/History.d.ts.map +1 -1
- package/dist/routing/History.js +6 -0
- package/dist/routing/InnerRouter.d.ts +10 -9
- package/dist/routing/InnerRouter.d.ts.map +1 -1
- package/dist/routing/InnerRouter.js +41 -33
- package/dist/routing/PageLoader.d.ts +5 -5
- package/dist/routing/PageLoader.d.ts.map +1 -1
- package/dist/routing/PageLoader.js +7 -7
- package/dist/routing/Request.d.ts +102 -0
- package/dist/routing/Request.d.ts.map +1 -0
- package/dist/routing/Request.js +128 -0
- package/dist/routing/Route.d.ts +73 -5
- package/dist/routing/Route.d.ts.map +1 -1
- package/dist/routing/Route.js +72 -7
- package/dist/routing/Router.d.ts +59 -53
- package/dist/routing/Router.d.ts.map +1 -1
- package/dist/routing/Router.js +92 -117
- package/dist/routing/Site.d.ts +1 -1
- package/dist/routing/Site.js +2 -2
- package/dist/routing/index.d.ts +4 -3
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +2 -1
- package/dist/routing/utils.d.ts +2 -0
- package/dist/routing/utils.d.ts.map +1 -0
- package/dist/routing/utils.js +3 -0
- package/dist/ssr/SsrCache.d.ts +17 -0
- package/dist/ssr/SsrCache.d.ts.map +1 -1
- package/dist/ssr/SsrCache.js +17 -4
- package/dist/ssr/SsrComponents.d.ts +1 -0
- package/dist/ssr/SsrComponents.d.ts.map +1 -1
- package/dist/ssr/SsrComponents.js +1 -0
- package/package.json +6 -6
- package/src/Crelte.ts +124 -52
- package/src/CrelteRequest.ts +124 -0
- package/src/blocks/Blocks.svelte +35 -18
- package/src/blocks/Blocks.ts +38 -6
- package/src/blocks/index.ts +19 -10
- package/src/cookies/ServerCookies.ts +1 -1
- package/src/cookies/index.ts +7 -1
- package/src/graphql/GraphQl.ts +79 -27
- package/src/graphql/index.ts +7 -1
- package/src/index.ts +65 -29
- package/src/init/client.ts +55 -10
- package/src/init/server.ts +70 -10
- package/src/init/shared.ts +8 -7
- package/src/loadData/Globals.ts +43 -7
- package/src/loadData/index.ts +76 -13
- package/src/plugins/Events.ts +16 -5
- package/src/plugins/Plugins.ts +28 -2
- package/src/routing/History.ts +9 -0
- package/src/routing/InnerRouter.ts +47 -37
- package/src/routing/PageLoader.ts +10 -10
- package/src/routing/Request.ts +175 -0
- package/src/routing/Route.ts +74 -9
- package/src/routing/Router.ts +103 -163
- package/src/routing/Site.ts +2 -2
- package/src/routing/index.ts +12 -3
- package/src/routing/utils.ts +3 -0
- package/src/ssr/SsrCache.ts +17 -4
- package/src/ssr/SsrComponents.ts +1 -0
- package/dist/CrelteBase.d.ts +0 -16
- package/dist/CrelteBase.d.ts.map +0 -1
- package/dist/CrelteBase.js +0 -1
- package/dist/CrelteRouted.d.ts +0 -50
- package/dist/CrelteRouted.d.ts.map +0 -1
- package/dist/CrelteRouted.js +0 -88
- package/src/CrelteBase.ts +0 -24
- package/src/CrelteRouted.ts +0 -128
package/src/loadData/Globals.ts
CHANGED
|
@@ -25,13 +25,28 @@ export default class Globals {
|
|
|
25
25
|
this.prevSiteId = null;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* returns a store which contains a globalSet
|
|
30
|
+
*
|
|
31
|
+
* ## Note
|
|
32
|
+
* This only works in loadData, in loadGlobalData this will
|
|
33
|
+
* always return null. In that context you should use
|
|
34
|
+
* `.getGlobalAsync`
|
|
35
|
+
*/
|
|
36
|
+
get<T extends GlobalData>(name: string): Global<T> | null {
|
|
29
37
|
return this.entries.get(name) ?? null;
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Get a store which contains a globalSet and wait until it is loaded
|
|
42
|
+
*
|
|
43
|
+
* ## Note
|
|
44
|
+
* This is only useful in loadGlobalData in all other cases
|
|
45
|
+
* you can use `.getGlobal` which does return a Promise
|
|
46
|
+
*/
|
|
47
|
+
getAsync<T extends GlobalData>(
|
|
48
|
+
name: string,
|
|
49
|
+
): Promise<Global<T> | null> | Global<T> | null {
|
|
35
50
|
if (this.loaded) return this.get(name);
|
|
36
51
|
|
|
37
52
|
let waiter = this.waiters.get(name);
|
|
@@ -45,15 +60,15 @@ export default class Globals {
|
|
|
45
60
|
});
|
|
46
61
|
}
|
|
47
62
|
|
|
48
|
-
|
|
63
|
+
/** @hidden */
|
|
49
64
|
_wasLoaded(): boolean {
|
|
50
65
|
return this.loaded;
|
|
51
66
|
}
|
|
52
67
|
|
|
53
|
-
// hidden
|
|
54
68
|
// data is the data from the global graphql
|
|
55
69
|
// so it contains some keys and data which should be parsed
|
|
56
70
|
// and created a store for each key
|
|
71
|
+
/** @hidden */
|
|
57
72
|
_setData(siteId: number, data: any) {
|
|
58
73
|
const wasLoaded = this.loaded;
|
|
59
74
|
this.loaded = true;
|
|
@@ -70,6 +85,7 @@ export default class Globals {
|
|
|
70
85
|
}
|
|
71
86
|
}
|
|
72
87
|
|
|
88
|
+
/** @hidden */
|
|
73
89
|
_globalsBySite(siteId: number): Map<string, any> {
|
|
74
90
|
const map = new Map();
|
|
75
91
|
|
|
@@ -80,6 +96,7 @@ export default class Globals {
|
|
|
80
96
|
return map;
|
|
81
97
|
}
|
|
82
98
|
|
|
99
|
+
/** @hidden */
|
|
83
100
|
_updateSiteId(siteId: number) {
|
|
84
101
|
// todo we should only trigger
|
|
85
102
|
if (this.prevSiteId === siteId) return;
|
|
@@ -88,10 +105,19 @@ export default class Globals {
|
|
|
88
105
|
}
|
|
89
106
|
}
|
|
90
107
|
|
|
108
|
+
/**
|
|
109
|
+
* A globalSet Data
|
|
110
|
+
*
|
|
111
|
+
* Each global query should contain the siteId
|
|
112
|
+
*/
|
|
91
113
|
export interface GlobalData {
|
|
92
114
|
siteId?: number;
|
|
115
|
+
[key: string]: any;
|
|
93
116
|
}
|
|
94
117
|
|
|
118
|
+
/**
|
|
119
|
+
* A globalSet store
|
|
120
|
+
*/
|
|
95
121
|
export class Global<T extends GlobalData> {
|
|
96
122
|
private inner: Writable<T>;
|
|
97
123
|
/// if languages is null this means we always have the same data
|
|
@@ -129,11 +155,20 @@ export class Global<T extends GlobalData> {
|
|
|
129
155
|
return this.inner.subscribe(fn);
|
|
130
156
|
}
|
|
131
157
|
|
|
158
|
+
/**
|
|
159
|
+
* The current value
|
|
160
|
+
*/
|
|
132
161
|
get(): T {
|
|
133
162
|
return this.inner.get();
|
|
134
163
|
}
|
|
135
164
|
|
|
136
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Get the value based on the siteId
|
|
167
|
+
*
|
|
168
|
+
* ## Note
|
|
169
|
+
* If you pass a siteId which comes from craft
|
|
170
|
+
* you will never receive null
|
|
171
|
+
*/
|
|
137
172
|
bySiteId(siteId: number): T | null {
|
|
138
173
|
if (this.languages)
|
|
139
174
|
return this.languages.find(d => d.siteId === siteId) ?? null;
|
|
@@ -141,6 +176,7 @@ export class Global<T extends GlobalData> {
|
|
|
141
176
|
return this.inner.get();
|
|
142
177
|
}
|
|
143
178
|
|
|
179
|
+
/** @hidden */
|
|
144
180
|
_updateSiteId(siteId: number) {
|
|
145
181
|
if (!this.languages) return;
|
|
146
182
|
|
package/src/loadData/index.ts
CHANGED
|
@@ -1,22 +1,85 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type CrelteRouted from '../CrelteRouted.js';
|
|
1
|
+
import CrelteRequest from '../CrelteRequest.js';
|
|
6
2
|
import { isGraphQlQuery, type GraphQlQuery } from '../graphql/GraphQl.js';
|
|
7
3
|
import type Globals from './Globals.js';
|
|
8
4
|
import type { Global } from './Globals.js';
|
|
9
5
|
|
|
10
6
|
export type { Globals, Global };
|
|
11
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Load data function
|
|
10
|
+
*
|
|
11
|
+
* There are three main ways `loadData` can be defined:
|
|
12
|
+
*
|
|
13
|
+
* ## Object
|
|
14
|
+
* This is the most common way loadData will be used.
|
|
15
|
+
* Each property should be a loadData type, each one is called in parallel.
|
|
16
|
+
* And will be available to your component with the same name.
|
|
17
|
+
* ```
|
|
18
|
+
* export const loadData = {
|
|
19
|
+
*
|
|
20
|
+
* import entriesQuery from '@/queries/entries.graphql';
|
|
21
|
+
* import { loadData as headerLoadData } from '@/layout/header.svelte';
|
|
22
|
+
*
|
|
23
|
+
* export const loadData = {
|
|
24
|
+
* entries: entriesQuery,
|
|
25
|
+
* header: headerLoadData
|
|
26
|
+
* };
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* ## GraphQl
|
|
30
|
+
* You can just export a graphql query as a loadData type.
|
|
31
|
+
* This will export all queries from the graphql file as properties.
|
|
32
|
+
* ```
|
|
33
|
+
* import blogsQuery from '@/queries/blogs.graphql';
|
|
34
|
+
*
|
|
35
|
+
* export const loadData = blogsQuery;
|
|
36
|
+
*
|
|
37
|
+
* // or another option
|
|
38
|
+
* import { gql } from '@craft-svelte/core/graphql';
|
|
39
|
+
*
|
|
40
|
+
* export const loadData = gql`query {
|
|
41
|
+
* blogs: entries(section: "blogs") {
|
|
42
|
+
* title
|
|
43
|
+
* url
|
|
44
|
+
* }
|
|
45
|
+
* }`;
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* ## Function
|
|
49
|
+
* Using a function gives you the most flexibility but also is the
|
|
50
|
+
* most cumbersome.
|
|
51
|
+
*
|
|
52
|
+
* ```
|
|
53
|
+
* import articlesQuery from '@/queries/articles.graphql';
|
|
54
|
+
*
|
|
55
|
+
* export async function loadData(cr, entry) {
|
|
56
|
+
* return await cr.query(articlesQuery, {
|
|
57
|
+
* category: entry.category
|
|
58
|
+
* });
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* // or
|
|
62
|
+
* export const loadData = (cr, entry) => cr.query(articlesQuery, {
|
|
63
|
+
* category: entry.category
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* // or if you're in the context of an object
|
|
67
|
+
* export const loadData = {
|
|
68
|
+
* articles: (cr, entry) => cr.query(articlesQuery, {
|
|
69
|
+
* category: entry.category
|
|
70
|
+
* })
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
|
|
12
75
|
export type LoadData<T> =
|
|
13
|
-
| ((cr:
|
|
76
|
+
| ((cr: CrelteRequest, ...args: any[]) => Promise<T>)
|
|
14
77
|
| GraphQlQuery
|
|
15
78
|
| T;
|
|
16
79
|
|
|
17
80
|
export async function callLoadData(
|
|
18
81
|
ld: LoadData<unknown>,
|
|
19
|
-
cr:
|
|
82
|
+
cr: CrelteRequest,
|
|
20
83
|
...args: any[]
|
|
21
84
|
): Promise<unknown> {
|
|
22
85
|
// either we have a function
|
|
@@ -49,15 +112,15 @@ export async function callLoadData(
|
|
|
49
112
|
* ## Example
|
|
50
113
|
* ```
|
|
51
114
|
* export const loadData = mergeLoadData(
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* )
|
|
115
|
+
* {
|
|
116
|
+
* filter: (cr) => cr.route.search.get('filter'),
|
|
117
|
+
* },
|
|
118
|
+
* (cr) => cr.query(myQuery, { siteId: cr.site.id })
|
|
119
|
+
* );
|
|
57
120
|
* ```
|
|
58
121
|
*/
|
|
59
122
|
export function mergeLoadData(...lds: LoadData<object>[]): LoadData<object> {
|
|
60
|
-
return async (cr:
|
|
123
|
+
return async (cr: CrelteRequest, ...args: any[]) => {
|
|
61
124
|
const datas = await Promise.all(
|
|
62
125
|
lds.map(ld => callLoadData(ld, cr, ...args) as Promise<object>),
|
|
63
126
|
);
|
package/src/plugins/Events.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CrelteRequest } from '../index.js';
|
|
2
2
|
|
|
3
3
|
export default class Events {
|
|
4
4
|
inner: Map<string, Set<any>>;
|
|
@@ -7,19 +7,21 @@ export default class Events {
|
|
|
7
7
|
this.inner = new Map();
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
11
|
* Listens for an event.
|
|
12
|
+
*
|
|
13
|
+
* @returns a function to remove the listener
|
|
12
14
|
*/
|
|
13
15
|
// override this function to add your own function signatures
|
|
14
16
|
on(
|
|
15
17
|
ev: 'loadGlobalData',
|
|
16
|
-
fn: (cr:
|
|
18
|
+
fn: (cr: CrelteRequest) => Promise<any>,
|
|
17
19
|
): () => void;
|
|
18
20
|
on(
|
|
19
21
|
ev: 'loadData',
|
|
20
|
-
fn: (cr:
|
|
22
|
+
fn: (cr: CrelteRequest, entry: any) => Promise<any>,
|
|
21
23
|
): () => void;
|
|
22
|
-
on(ev: 'beforeRender', fn: (cr:
|
|
24
|
+
on(ev: 'beforeRender', fn: (cr: CrelteRequest) => void): () => void;
|
|
23
25
|
on(ev: string, fn: (...args: any[]) => any): () => void {
|
|
24
26
|
let set = this.inner.get(ev);
|
|
25
27
|
if (!set) {
|
|
@@ -34,6 +36,9 @@ export default class Events {
|
|
|
34
36
|
};
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Remove a listener
|
|
41
|
+
*/
|
|
37
42
|
remove(ev: string, fn: any) {
|
|
38
43
|
const set = this.inner.get(ev);
|
|
39
44
|
if (!set) return;
|
|
@@ -41,6 +46,12 @@ export default class Events {
|
|
|
41
46
|
set.delete(fn);
|
|
42
47
|
}
|
|
43
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Trigger an event
|
|
51
|
+
*/
|
|
52
|
+
trigger(ev: 'loadGlobalData', cr: CrelteRequest): Promise<any>[];
|
|
53
|
+
trigger(ev: 'loadData', cr: CrelteRequest, entry: any): Promise<any>[];
|
|
54
|
+
trigger(ev: 'beforeRender', cr: CrelteRequest): void[];
|
|
44
55
|
trigger(ev: string, ...args: any[]): any[] {
|
|
45
56
|
const set = this.inner.get(ev);
|
|
46
57
|
if (!set) return [];
|
package/src/plugins/Plugins.ts
CHANGED
|
@@ -1,11 +1,32 @@
|
|
|
1
|
-
import
|
|
1
|
+
import CrelteCore from '../Crelte.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* A plugin
|
|
5
|
+
*/
|
|
3
6
|
export interface Plugin {
|
|
4
7
|
name: string;
|
|
5
8
|
}
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
/**
|
|
11
|
+
* A plugin create function
|
|
12
|
+
*
|
|
13
|
+
* Each plugin needs to export a createPluginname function which will be called
|
|
14
|
+
* by crelte to create the plugin. If youre plugin has options you can create
|
|
15
|
+
* a configurePluginname function which will be called by youre user and should
|
|
16
|
+
* return a createPlugin function.
|
|
17
|
+
*
|
|
18
|
+
* ## Example App.svelte in module="context"
|
|
19
|
+
* ```
|
|
20
|
+
* import { createPlugin, configurePlugin } from 'some-plugin';
|
|
21
|
+
*
|
|
22
|
+
* export plugins = [createPlugin, configurePlugin({ enableFeature: true })];
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export type PluginCreator = (crelte: CrelteCore) => Plugin;
|
|
8
26
|
|
|
27
|
+
/**
|
|
28
|
+
* A plugin manager
|
|
29
|
+
*/
|
|
9
30
|
export default class Plugins {
|
|
10
31
|
plugins: Map<string, Plugin>;
|
|
11
32
|
|
|
@@ -13,6 +34,11 @@ export default class Plugins {
|
|
|
13
34
|
this.plugins = new Map();
|
|
14
35
|
}
|
|
15
36
|
|
|
37
|
+
/**
|
|
38
|
+
* @hidden
|
|
39
|
+
*
|
|
40
|
+
* Plugins should be added via App.svelte plugins export
|
|
41
|
+
*/
|
|
16
42
|
add(plugin: Plugin) {
|
|
17
43
|
this.plugins.set(plugin.name, plugin);
|
|
18
44
|
}
|
package/src/routing/History.ts
CHANGED
|
@@ -3,6 +3,7 @@ export default interface History {
|
|
|
3
3
|
replaceState(data: any, url?: string): void;
|
|
4
4
|
pushState(data: any, url: string): void;
|
|
5
5
|
open(url: string): void;
|
|
6
|
+
back(): void;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
export class ClientHistory implements History {
|
|
@@ -21,6 +22,10 @@ export class ClientHistory implements History {
|
|
|
21
22
|
open(url: string): void {
|
|
22
23
|
window.location.href = url;
|
|
23
24
|
}
|
|
25
|
+
|
|
26
|
+
back(): void {
|
|
27
|
+
window.history.back();
|
|
28
|
+
}
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
export class ServerHistory implements History {
|
|
@@ -49,4 +54,8 @@ export class ServerHistory implements History {
|
|
|
49
54
|
open(url: string): void {
|
|
50
55
|
this.url = url;
|
|
51
56
|
}
|
|
57
|
+
|
|
58
|
+
back(): void {
|
|
59
|
+
throw new Error('Cannot go back on the server');
|
|
60
|
+
}
|
|
52
61
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import Route from './Route.js';
|
|
2
1
|
import Site, { SiteFromGraphQl } from './Site.js';
|
|
3
|
-
import History
|
|
2
|
+
import History from './History.js';
|
|
3
|
+
import { ClientHistory, ServerHistory } from './History.js';
|
|
4
|
+
import Request, { isRequest } from './Request.js';
|
|
5
|
+
import Route from './Route.js';
|
|
4
6
|
|
|
5
7
|
export type InnerRouterOpts = {
|
|
6
8
|
preloadOnMouseOver: boolean;
|
|
@@ -19,8 +21,8 @@ export default class InnerRouter {
|
|
|
19
21
|
* @param changeHistory returns a function you need to call when you are ready to
|
|
20
22
|
update the window history (note do not call this after another onRoute call was made)
|
|
21
23
|
*/
|
|
22
|
-
onRoute: (route:
|
|
23
|
-
onPreload: (route:
|
|
24
|
+
onRoute: (route: Request, site: Site, changeHistory: () => void) => void;
|
|
25
|
+
onPreload: (route: Request, site: Site) => void;
|
|
24
26
|
|
|
25
27
|
private scrollDebounceTimeout: any | null;
|
|
26
28
|
|
|
@@ -56,7 +58,7 @@ export default class InnerRouter {
|
|
|
56
58
|
this.listen();
|
|
57
59
|
|
|
58
60
|
// let's first try to load from the state
|
|
59
|
-
const route = this.
|
|
61
|
+
const route = this.targetToRequest(window.location.href);
|
|
60
62
|
route._fillFromState(window.history.state);
|
|
61
63
|
|
|
62
64
|
route.origin = 'init';
|
|
@@ -139,7 +141,7 @@ export default class InnerRouter {
|
|
|
139
141
|
* @param target
|
|
140
142
|
* @return Returns null if the url does not match our host (the protocol get's ignored)
|
|
141
143
|
*/
|
|
142
|
-
|
|
144
|
+
targetToRequest(target: string | URL | Route | Request): Request {
|
|
143
145
|
if (typeof target === 'string') {
|
|
144
146
|
if (target.startsWith('/')) {
|
|
145
147
|
const site = this.site;
|
|
@@ -150,7 +152,11 @@ export default class InnerRouter {
|
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
if (target instanceof URL) {
|
|
153
|
-
|
|
155
|
+
target = this.routeFromUrl(target);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!isRequest(target)) {
|
|
159
|
+
return Request.fromRoute(target);
|
|
154
160
|
}
|
|
155
161
|
|
|
156
162
|
return target;
|
|
@@ -269,7 +275,7 @@ export default class InnerRouter {
|
|
|
269
275
|
window.addEventListener('popstate', async e => {
|
|
270
276
|
if (!('route' in e.state)) return;
|
|
271
277
|
|
|
272
|
-
const route = this.
|
|
278
|
+
const route = this.targetToRequest(window.location.href);
|
|
273
279
|
route._fillFromState(e.state);
|
|
274
280
|
route.origin = 'pop';
|
|
275
281
|
|
|
@@ -288,12 +294,12 @@ export default class InnerRouter {
|
|
|
288
294
|
* @param route a route object or an url or uri, never input the same route object again
|
|
289
295
|
* @param pushState if true pushed the state to the window.history
|
|
290
296
|
*/
|
|
291
|
-
open(target: string | URL | Route, pushState: boolean = true) {
|
|
292
|
-
const
|
|
297
|
+
open(target: string | URL | Route | Request, pushState: boolean = true) {
|
|
298
|
+
const req = this.targetToRequest(target);
|
|
293
299
|
|
|
294
300
|
const current = this.route;
|
|
295
301
|
if (current) {
|
|
296
|
-
// if the scrollY
|
|
302
|
+
// if the scrollY would still be updated we clear the timeout
|
|
297
303
|
// since we should have the latest scrollY
|
|
298
304
|
if (this.scrollDebounceTimeout) {
|
|
299
305
|
clearTimeout(this.scrollDebounceTimeout);
|
|
@@ -311,20 +317,21 @@ export default class InnerRouter {
|
|
|
311
317
|
// if the domain of the current site is different than the domain of the
|
|
312
318
|
// new site we need to do a window.location.href call
|
|
313
319
|
if (
|
|
314
|
-
(current && current.url.origin !==
|
|
320
|
+
(current && current.url.origin !== req.url.origin) ||
|
|
321
|
+
// @ts-ignore
|
|
315
322
|
import.meta.env.SSR
|
|
316
323
|
) {
|
|
317
|
-
this.history.open(
|
|
324
|
+
this.history.open(req.url.href);
|
|
318
325
|
return;
|
|
319
326
|
}
|
|
320
327
|
|
|
321
328
|
if (pushState) {
|
|
322
|
-
|
|
323
|
-
this.onRoute(
|
|
324
|
-
this.pushState(
|
|
329
|
+
req.index = (current?.index ?? 0) + 1;
|
|
330
|
+
this.onRoute(req, req.site ?? this.site, () => {
|
|
331
|
+
this.pushState(req.toRoute());
|
|
325
332
|
});
|
|
326
333
|
} else {
|
|
327
|
-
this.setRoute(
|
|
334
|
+
this.setRoute(req);
|
|
328
335
|
}
|
|
329
336
|
}
|
|
330
337
|
|
|
@@ -334,13 +341,13 @@ export default class InnerRouter {
|
|
|
334
341
|
* Will trigger an onRoute event but will not store any scroll progress
|
|
335
342
|
* or modify the history
|
|
336
343
|
*
|
|
337
|
-
* @param
|
|
344
|
+
* @param req
|
|
338
345
|
*/
|
|
339
|
-
setRoute(
|
|
340
|
-
this.route =
|
|
341
|
-
if (
|
|
346
|
+
setRoute(req: Request) {
|
|
347
|
+
this.route = req.toRoute();
|
|
348
|
+
if (req.site) this.site = req.site;
|
|
342
349
|
|
|
343
|
-
this.onRoute(
|
|
350
|
+
this.onRoute(req, this.site, () => {});
|
|
344
351
|
}
|
|
345
352
|
|
|
346
353
|
/**
|
|
@@ -389,26 +396,29 @@ export default class InnerRouter {
|
|
|
389
396
|
*
|
|
390
397
|
* @param url
|
|
391
398
|
*/
|
|
392
|
-
preload(target: string | URL | Route) {
|
|
393
|
-
const
|
|
399
|
+
preload(target: string | URL | Route | Request) {
|
|
400
|
+
const req = this.targetToRequest(target);
|
|
394
401
|
|
|
402
|
+
// todo, don't think this makes any sense
|
|
395
403
|
// if the domain of the current site is different than the domain of the
|
|
396
404
|
// new site id does not make sense to preload
|
|
397
|
-
if (this.site.url.origin !==
|
|
405
|
+
if (this.site.url.origin !== req.url.origin) {
|
|
398
406
|
return;
|
|
399
407
|
}
|
|
400
408
|
|
|
401
409
|
const current = this.route;
|
|
402
|
-
const site =
|
|
410
|
+
const site = req.site ?? this.site;
|
|
403
411
|
|
|
404
412
|
// if the origin matches, the route will be able to be load
|
|
405
413
|
// so let's preload it
|
|
406
|
-
if (current && current.url.origin ===
|
|
407
|
-
this.onPreload(
|
|
414
|
+
if (current && current.url.origin === req.url.origin) {
|
|
415
|
+
this.onPreload(req, site);
|
|
408
416
|
}
|
|
409
417
|
}
|
|
410
418
|
|
|
411
|
-
domReady(
|
|
419
|
+
domReady(req: Request) {
|
|
420
|
+
if (req.disableScroll) return;
|
|
421
|
+
|
|
412
422
|
// scroll to target
|
|
413
423
|
let scrollTo:
|
|
414
424
|
| { top: number; behavior: ScrollBehavior }
|
|
@@ -417,7 +427,7 @@ export default class InnerRouter {
|
|
|
417
427
|
|
|
418
428
|
// if the route is a live preview init and we have a scrollY stored
|
|
419
429
|
// scroll to that
|
|
420
|
-
if (
|
|
430
|
+
if (req.origin === 'live-preview-init') {
|
|
421
431
|
const scrollY = sessionStorage.getItem('live-preview-scroll');
|
|
422
432
|
if (scrollY) {
|
|
423
433
|
scrollTo = {
|
|
@@ -427,11 +437,11 @@ export default class InnerRouter {
|
|
|
427
437
|
}
|
|
428
438
|
// if we have a hash and the route was not visited
|
|
429
439
|
} else if (
|
|
430
|
-
|
|
431
|
-
((
|
|
432
|
-
|
|
440
|
+
req.hash &&
|
|
441
|
+
((req.origin === 'init' && typeof req.scrollY !== 'number') ||
|
|
442
|
+
req.origin === 'click')
|
|
433
443
|
) {
|
|
434
|
-
const el = document.getElementById(
|
|
444
|
+
const el = document.getElementById(req.hash.substring(1));
|
|
435
445
|
if (el) {
|
|
436
446
|
scrollTo = {
|
|
437
447
|
intoView: el,
|
|
@@ -443,11 +453,11 @@ export default class InnerRouter {
|
|
|
443
453
|
// restore scroll position
|
|
444
454
|
if (
|
|
445
455
|
!scrollTo &&
|
|
446
|
-
|
|
447
|
-
typeof
|
|
456
|
+
req.origin !== 'click' &&
|
|
457
|
+
typeof req.scrollY === 'number'
|
|
448
458
|
) {
|
|
449
459
|
scrollTo = {
|
|
450
|
-
top:
|
|
460
|
+
top: req.scrollY,
|
|
451
461
|
behavior: 'instant',
|
|
452
462
|
};
|
|
453
463
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Request from './Request.js';
|
|
2
2
|
import Site from './Site.js';
|
|
3
3
|
|
|
4
4
|
export type PageLoaderOptions = {
|
|
@@ -11,7 +11,7 @@ export type LoadResponse = {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
export type LoadFn = (
|
|
14
|
-
|
|
14
|
+
req: Request,
|
|
15
15
|
site: Site,
|
|
16
16
|
opts: LoadOptions,
|
|
17
17
|
) => Promise<any> | any;
|
|
@@ -31,7 +31,7 @@ export default class PageLoader<More> {
|
|
|
31
31
|
|
|
32
32
|
onLoaded: (
|
|
33
33
|
resp: LoadResponse,
|
|
34
|
-
|
|
34
|
+
req: Request,
|
|
35
35
|
site: Site,
|
|
36
36
|
more: More,
|
|
37
37
|
) => void;
|
|
@@ -62,7 +62,7 @@ export default class PageLoader<More> {
|
|
|
62
62
|
this.onProgress(false);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
async load(
|
|
65
|
+
async load(req: Request, site: Site, more: More) {
|
|
66
66
|
this.onProgress(true);
|
|
67
67
|
|
|
68
68
|
const version = ++this.loadingVersion;
|
|
@@ -76,7 +76,7 @@ export default class PageLoader<More> {
|
|
|
76
76
|
|
|
77
77
|
const resp: LoadResponse = { success: false, data: null };
|
|
78
78
|
try {
|
|
79
|
-
resp.data = await this.loadFn(
|
|
79
|
+
resp.data = await this.loadFn(req, site, { setProgress });
|
|
80
80
|
resp.success = true;
|
|
81
81
|
} catch (e) {
|
|
82
82
|
resp.success = false;
|
|
@@ -91,19 +91,19 @@ export default class PageLoader<More> {
|
|
|
91
91
|
return console.log('route changed quickly, ignoring response');
|
|
92
92
|
|
|
93
93
|
this.onProgress(false);
|
|
94
|
-
this.onLoaded(resp,
|
|
94
|
+
this.onLoaded(resp, req, site, more);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
// you don't need to wait on this call
|
|
98
|
-
async preload(
|
|
99
|
-
const url =
|
|
98
|
+
async preload(req: Request, site: Site) {
|
|
99
|
+
const url = req.url.origin + req.url.pathname;
|
|
100
100
|
if (this.preloadedUrls.has(url)) return;
|
|
101
101
|
|
|
102
102
|
this.preloadedUrls.add(url);
|
|
103
103
|
|
|
104
104
|
try {
|
|
105
|
-
await this.loadFn(
|
|
106
|
-
} catch (
|
|
105
|
+
await this.loadFn(req, site, { setProgress: () => null });
|
|
106
|
+
} catch (_e) {
|
|
107
107
|
console.log('preload failed');
|
|
108
108
|
// retry at another time
|
|
109
109
|
this.preloadedUrls.delete(url);
|