elegance-js 2.1.18 → 2.1.20
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/client/client.mjs +522 -390
- package/dist/compilation/compilation.mjs +6 -2
- package/package.json +2 -2
package/dist/client/client.mjs
CHANGED
|
@@ -1,442 +1,574 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
(() => {
|
|
3
|
+
// src/shared/serverElements.ts
|
|
4
|
+
var createBuildableElement = (tag) => {
|
|
5
|
+
return (options, ...children) => ({
|
|
6
|
+
tag,
|
|
7
|
+
options: options || {},
|
|
8
|
+
children
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var createChildrenlessBuildableElement = (tag) => {
|
|
12
|
+
return (options) => ({
|
|
13
|
+
tag,
|
|
14
|
+
options: options || {},
|
|
15
|
+
children: null
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
var childrenlessElementTags = [
|
|
19
|
+
"area",
|
|
20
|
+
"base",
|
|
21
|
+
"br",
|
|
22
|
+
"col",
|
|
23
|
+
"embed",
|
|
24
|
+
"hr",
|
|
25
|
+
"img",
|
|
26
|
+
"input",
|
|
27
|
+
"link",
|
|
28
|
+
"meta",
|
|
29
|
+
"source",
|
|
30
|
+
"track",
|
|
31
|
+
"path",
|
|
32
|
+
"rect"
|
|
33
|
+
];
|
|
34
|
+
var elementTags = [
|
|
35
|
+
"a",
|
|
36
|
+
"address",
|
|
37
|
+
"article",
|
|
38
|
+
"aside",
|
|
39
|
+
"audio",
|
|
40
|
+
"blockquote",
|
|
41
|
+
"body",
|
|
42
|
+
"button",
|
|
43
|
+
"canvas",
|
|
44
|
+
"caption",
|
|
45
|
+
"colgroup",
|
|
46
|
+
"data",
|
|
47
|
+
"datalist",
|
|
48
|
+
"dd",
|
|
49
|
+
"del",
|
|
50
|
+
"details",
|
|
51
|
+
"dialog",
|
|
52
|
+
"div",
|
|
53
|
+
"dl",
|
|
54
|
+
"dt",
|
|
55
|
+
"fieldset",
|
|
56
|
+
"figcaption",
|
|
57
|
+
"figure",
|
|
58
|
+
"footer",
|
|
59
|
+
"form",
|
|
60
|
+
"h1",
|
|
61
|
+
"h2",
|
|
62
|
+
"h3",
|
|
63
|
+
"h4",
|
|
64
|
+
"h5",
|
|
65
|
+
"h6",
|
|
66
|
+
"head",
|
|
67
|
+
"header",
|
|
68
|
+
"hgroup",
|
|
69
|
+
"html",
|
|
70
|
+
"iframe",
|
|
71
|
+
"ins",
|
|
72
|
+
"label",
|
|
73
|
+
"legend",
|
|
74
|
+
"li",
|
|
75
|
+
"main",
|
|
76
|
+
"map",
|
|
77
|
+
"meter",
|
|
78
|
+
"nav",
|
|
79
|
+
"noscript",
|
|
80
|
+
"object",
|
|
81
|
+
"ol",
|
|
82
|
+
"optgroup",
|
|
83
|
+
"option",
|
|
84
|
+
"output",
|
|
85
|
+
"p",
|
|
86
|
+
"picture",
|
|
87
|
+
"pre",
|
|
88
|
+
"progress",
|
|
89
|
+
"q",
|
|
90
|
+
"section",
|
|
91
|
+
"select",
|
|
92
|
+
"summary",
|
|
93
|
+
"table",
|
|
94
|
+
"tbody",
|
|
95
|
+
"td",
|
|
96
|
+
"template",
|
|
97
|
+
"textarea",
|
|
98
|
+
"tfoot",
|
|
99
|
+
"th",
|
|
100
|
+
"thead",
|
|
101
|
+
"time",
|
|
102
|
+
"tr",
|
|
103
|
+
"ul",
|
|
104
|
+
"video",
|
|
105
|
+
"span",
|
|
106
|
+
"script",
|
|
107
|
+
"abbr",
|
|
108
|
+
"b",
|
|
109
|
+
"bdi",
|
|
110
|
+
"bdo",
|
|
111
|
+
"cite",
|
|
112
|
+
"code",
|
|
113
|
+
"dfn",
|
|
114
|
+
"em",
|
|
115
|
+
"i",
|
|
116
|
+
"kbd",
|
|
117
|
+
"mark",
|
|
118
|
+
"rp",
|
|
119
|
+
"rt",
|
|
120
|
+
"ruby",
|
|
121
|
+
"s",
|
|
122
|
+
"samp",
|
|
123
|
+
"small",
|
|
124
|
+
"strong",
|
|
125
|
+
"sub",
|
|
126
|
+
"sup",
|
|
127
|
+
"u",
|
|
128
|
+
"wbr",
|
|
129
|
+
"title",
|
|
130
|
+
"svg"
|
|
47
131
|
];
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
132
|
+
var elements = {};
|
|
133
|
+
var childrenlessElements = {};
|
|
134
|
+
for (const element of elementTags) {
|
|
135
|
+
elements[element] = createBuildableElement(element);
|
|
136
|
+
}
|
|
137
|
+
for (const element of childrenlessElementTags) {
|
|
138
|
+
childrenlessElements[element] = createChildrenlessBuildableElement(element);
|
|
139
|
+
}
|
|
140
|
+
var allElements = {
|
|
141
|
+
...elements,
|
|
142
|
+
...childrenlessElements
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// src/shared/bindServerElements.ts
|
|
146
|
+
Object.assign(globalThis, elements);
|
|
147
|
+
Object.assign(globalThis, childrenlessElements);
|
|
148
|
+
|
|
149
|
+
// src/client/client.ts
|
|
150
|
+
console.log("Elegance.JS is loading..");
|
|
151
|
+
var pd = {};
|
|
152
|
+
var ld = {};
|
|
153
|
+
Object.assign(window, {
|
|
154
|
+
observe: (subjects, updateCallback) => {
|
|
155
|
+
return {
|
|
156
|
+
subjects,
|
|
157
|
+
updateCallback,
|
|
158
|
+
isAttribute: true,
|
|
159
|
+
type: 2 /* OBSERVER */
|
|
160
|
+
};
|
|
161
|
+
},
|
|
162
|
+
eventListener: (subjects, eventListener) => {
|
|
163
|
+
return {
|
|
164
|
+
subjects,
|
|
165
|
+
eventListener,
|
|
166
|
+
isAttribute: true,
|
|
167
|
+
type: 1 /* STATE */
|
|
57
168
|
};
|
|
58
|
-
|
|
59
|
-
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
var domParser = new DOMParser();
|
|
172
|
+
var xmlSerializer = new XMLSerializer();
|
|
173
|
+
var pageStringCache = /* @__PURE__ */ new Map();
|
|
174
|
+
var loc = window.location;
|
|
175
|
+
var doc = document;
|
|
176
|
+
var cleanupProcedures = [];
|
|
177
|
+
var sanitizePathname = (pn) => {
|
|
178
|
+
if (!pn.endsWith("/") || pn === "/") return pn;
|
|
179
|
+
return pn.slice(0, -1);
|
|
180
|
+
};
|
|
181
|
+
var currentPage = sanitizePathname(loc.pathname);
|
|
182
|
+
var createStateManager = (subjects, bindLevel) => {
|
|
183
|
+
const state = {
|
|
184
|
+
subjects: subjects.map((subject) => {
|
|
185
|
+
const s = {
|
|
186
|
+
...subject,
|
|
187
|
+
observers: /* @__PURE__ */ new Map()
|
|
188
|
+
};
|
|
189
|
+
s.signal = () => {
|
|
190
|
+
for (const observer of s.observers.values()) {
|
|
191
|
+
try {
|
|
192
|
+
observer(s.value);
|
|
193
|
+
} catch (e) {
|
|
194
|
+
console.error(e);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
return s;
|
|
200
|
+
}),
|
|
201
|
+
destroy: (s) => {
|
|
202
|
+
state.subjects.splice(state.subjects.indexOf(s), 1);
|
|
203
|
+
},
|
|
204
|
+
get: (id) => {
|
|
205
|
+
const subject = state.subjects.find((s) => s.id === id);
|
|
206
|
+
if (subject) return subject;
|
|
207
|
+
if (bindLevel === 2 /* SCOPED */) return void 0;
|
|
208
|
+
const parts = window.location.pathname.split("/").filter(Boolean);
|
|
209
|
+
const paths = [
|
|
210
|
+
...parts.map((_, i) => "/" + parts.slice(0, i + 1).join("/")),
|
|
211
|
+
"/"
|
|
212
|
+
].reverse();
|
|
213
|
+
for (const item of paths) {
|
|
214
|
+
const sanitized = sanitizePathname(item);
|
|
215
|
+
const data = ld[sanitized];
|
|
216
|
+
if (!data) continue;
|
|
217
|
+
const entry = data.stateManager.get(id);
|
|
218
|
+
if (entry) return entry;
|
|
219
|
+
}
|
|
220
|
+
return void 0;
|
|
221
|
+
},
|
|
222
|
+
/**
|
|
223
|
+
Bind is deprecated, but kept as a paramater to not upset legacy code.
|
|
224
|
+
*/
|
|
225
|
+
getAll: (refs) => refs?.map((ref) => {
|
|
226
|
+
return state.get(ref.id);
|
|
227
|
+
}),
|
|
228
|
+
observe: (subject, observer, key) => {
|
|
229
|
+
subject.observers.delete(key);
|
|
230
|
+
subject.observers.set(key, observer);
|
|
231
|
+
},
|
|
232
|
+
unobserve: (subject, key) => {
|
|
233
|
+
subject.observers.delete(key);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
return state;
|
|
237
|
+
};
|
|
238
|
+
var initPageData = (data, currentPage2, previousPage, bindLevel) => {
|
|
239
|
+
if (!data) {
|
|
240
|
+
console.error("Data for page " + currentPage2 + " is null.");
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
let state = data?.stateManager;
|
|
244
|
+
if (!state) {
|
|
245
|
+
state = createStateManager(data.state || [], bindLevel);
|
|
246
|
+
data.stateManager = state;
|
|
247
|
+
}
|
|
248
|
+
for (const subject of state.subjects) {
|
|
249
|
+
if (!subject.observers) subject.observers = /* @__PURE__ */ new Map();
|
|
250
|
+
}
|
|
251
|
+
for (const ooa of data.ooa || []) {
|
|
252
|
+
const els = doc.querySelectorAll(`[key="${ooa.key}"]`);
|
|
253
|
+
let values = {};
|
|
254
|
+
for (const { id } of ooa.refs) {
|
|
255
|
+
const subject = state.get(id);
|
|
256
|
+
values[subject.id] = subject.value;
|
|
257
|
+
const updateFunction = (value) => {
|
|
258
|
+
values[id] = value;
|
|
60
259
|
try {
|
|
61
|
-
|
|
260
|
+
const newValue = ooa.update(...Object.values(values));
|
|
261
|
+
let attribute = ooa.attribute === "class" ? "className" : ooa.attribute;
|
|
262
|
+
for (const el of Array.from(els)) {
|
|
263
|
+
el[attribute] = newValue;
|
|
264
|
+
}
|
|
62
265
|
} catch (e) {
|
|
63
266
|
console.error(e);
|
|
64
|
-
|
|
267
|
+
return;
|
|
65
268
|
}
|
|
269
|
+
};
|
|
270
|
+
updateFunction(subject.value);
|
|
271
|
+
try {
|
|
272
|
+
state.observe(subject, updateFunction, ooa.key);
|
|
273
|
+
} catch (e) {
|
|
274
|
+
console.error(e);
|
|
275
|
+
return;
|
|
66
276
|
}
|
|
67
|
-
};
|
|
68
|
-
return s;
|
|
69
|
-
}),
|
|
70
|
-
destroy: (s) => {
|
|
71
|
-
state.subjects.splice(state.subjects.indexOf(s), 1);
|
|
72
|
-
},
|
|
73
|
-
get: (id) => {
|
|
74
|
-
const subject = state.subjects.find((s) => s.id === id);
|
|
75
|
-
if (subject) return subject;
|
|
76
|
-
if (bindLevel === 2 /* SCOPED */) return void 0;
|
|
77
|
-
const parts = window.location.pathname.split("/").filter(Boolean);
|
|
78
|
-
const paths = [
|
|
79
|
-
...parts.map((_, i) => "/" + parts.slice(0, i + 1).join("/")),
|
|
80
|
-
"/"
|
|
81
|
-
].reverse();
|
|
82
|
-
for (const item of paths) {
|
|
83
|
-
const sanitized = sanitizePathname(item);
|
|
84
|
-
const data = ld[sanitized];
|
|
85
|
-
if (!data) continue;
|
|
86
|
-
const entry = data.stateManager.get(id);
|
|
87
|
-
if (entry) return entry;
|
|
88
277
|
}
|
|
89
|
-
return void 0;
|
|
90
|
-
},
|
|
91
|
-
/**
|
|
92
|
-
Bind is deprecated, but kept as a paramater to not upset legacy code.
|
|
93
|
-
*/
|
|
94
|
-
getAll: (refs) => refs?.map((ref) => {
|
|
95
|
-
return state.get(ref.id);
|
|
96
|
-
}),
|
|
97
|
-
observe: (subject, observer, key) => {
|
|
98
|
-
subject.observers.delete(key);
|
|
99
|
-
subject.observers.set(key, observer);
|
|
100
|
-
},
|
|
101
|
-
unobserve: (subject, key) => {
|
|
102
|
-
subject.observers.delete(key);
|
|
103
278
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
let state = data?.stateManager;
|
|
113
|
-
if (!state) {
|
|
114
|
-
state = createStateManager(data.state || [], bindLevel);
|
|
115
|
-
data.stateManager = state;
|
|
116
|
-
}
|
|
117
|
-
for (const subject of state.subjects) {
|
|
118
|
-
if (!subject.observers) subject.observers = /* @__PURE__ */ new Map();
|
|
119
|
-
}
|
|
120
|
-
for (const ooa of data.ooa || []) {
|
|
121
|
-
const els = doc.querySelectorAll(`[key="${ooa.key}"]`);
|
|
122
|
-
let values = {};
|
|
123
|
-
for (const { id } of ooa.refs) {
|
|
124
|
-
const subject = state.get(id);
|
|
125
|
-
values[subject.id] = subject.value;
|
|
126
|
-
const updateFunction = (value) => {
|
|
127
|
-
values[id] = value;
|
|
279
|
+
for (const soa of data.soa || []) {
|
|
280
|
+
const el = doc.querySelector(`[key="${soa.key}"]`);
|
|
281
|
+
if (!el) {
|
|
282
|
+
console.error("Could not find SOA element for SOA:", soa);
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
const subject = state.get(soa.id);
|
|
286
|
+
if (typeof subject.value === "function") {
|
|
128
287
|
try {
|
|
129
|
-
|
|
130
|
-
let attribute = ooa.attribute === "class" ? "className" : ooa.attribute;
|
|
131
|
-
for (const el of Array.from(els)) {
|
|
132
|
-
el[attribute] = newValue;
|
|
133
|
-
}
|
|
288
|
+
el[soa.attribute] = (event) => subject.value(state, event);
|
|
134
289
|
} catch (e) {
|
|
135
290
|
console.error(e);
|
|
136
291
|
return;
|
|
137
292
|
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
state.observe(subject, updateFunction, ooa.key);
|
|
142
|
-
} catch (e) {
|
|
143
|
-
console.error(e);
|
|
144
|
-
return;
|
|
293
|
+
} else {
|
|
294
|
+
el[soa.attribute] = subject.value;
|
|
145
295
|
}
|
|
146
296
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
const subject = state.get(soa.id);
|
|
155
|
-
if (typeof subject.value === "function") {
|
|
156
|
-
try {
|
|
157
|
-
el[soa.attribute] = (event) => subject.value(state, event);
|
|
158
|
-
} catch (e) {
|
|
159
|
-
console.error(e);
|
|
160
|
-
return;
|
|
297
|
+
const loadHooks = data.lh;
|
|
298
|
+
for (const loadHook of loadHooks || []) {
|
|
299
|
+
const wasInScope = previousPage ? previousPage.startsWith(currentPage2) : false;
|
|
300
|
+
if (wasInScope && bindLevel !== 1 /* STRICT */) {
|
|
301
|
+
continue;
|
|
161
302
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
303
|
+
const fn = loadHook.fn;
|
|
304
|
+
try {
|
|
305
|
+
let cleanupFunction;
|
|
306
|
+
if (fn.constructor.name === "AsyncFunction") {
|
|
307
|
+
const res = fn(state);
|
|
308
|
+
res.then((cleanupFunction2) => {
|
|
309
|
+
if (cleanupFunction2) {
|
|
310
|
+
cleanupProcedures.push({
|
|
311
|
+
cleanupFunction: cleanupFunction2,
|
|
312
|
+
page: `${currentPage2}`,
|
|
313
|
+
loadHook,
|
|
314
|
+
bindLevel
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
} else {
|
|
319
|
+
cleanupFunction = fn(state);
|
|
320
|
+
if (cleanupFunction) {
|
|
179
321
|
cleanupProcedures.push({
|
|
180
|
-
cleanupFunction
|
|
322
|
+
cleanupFunction,
|
|
181
323
|
page: `${currentPage2}`,
|
|
182
324
|
loadHook,
|
|
183
325
|
bindLevel
|
|
184
326
|
});
|
|
185
327
|
}
|
|
186
|
-
});
|
|
187
|
-
} else {
|
|
188
|
-
cleanupFunction = fn(state);
|
|
189
|
-
if (cleanupFunction) {
|
|
190
|
-
cleanupProcedures.push({
|
|
191
|
-
cleanupFunction,
|
|
192
|
-
page: `${currentPage2}`,
|
|
193
|
-
loadHook,
|
|
194
|
-
bindLevel
|
|
195
|
-
});
|
|
196
328
|
}
|
|
329
|
+
} catch (e) {
|
|
330
|
+
console.error(e);
|
|
331
|
+
return;
|
|
197
332
|
}
|
|
198
|
-
} catch (e) {
|
|
199
|
-
console.error(e);
|
|
200
|
-
return;
|
|
201
333
|
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
334
|
+
};
|
|
335
|
+
var loadPage = async (previousPage = null) => {
|
|
336
|
+
const fixedUrl = new URL(loc.href);
|
|
337
|
+
fixedUrl.pathname = sanitizePathname(fixedUrl.pathname);
|
|
338
|
+
const pathname = fixedUrl.pathname;
|
|
339
|
+
currentPage = pathname;
|
|
340
|
+
pageStringCache.set(
|
|
341
|
+
currentPage,
|
|
342
|
+
xmlSerializer.serializeToString(doc)
|
|
343
|
+
);
|
|
344
|
+
history.replaceState(null, "", fixedUrl.href);
|
|
345
|
+
{
|
|
346
|
+
const parts = window.location.pathname.split("/").filter(Boolean);
|
|
347
|
+
const paths = [
|
|
348
|
+
...parts.map((_, i) => "/" + parts.slice(0, i + 1).join("/")),
|
|
349
|
+
"/"
|
|
350
|
+
];
|
|
351
|
+
for (const path of paths) {
|
|
352
|
+
const layoutDataScript = document.querySelector(`script[data-layout="true"][data-pathname="${path}"]`);
|
|
353
|
+
if (!layoutDataScript) {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
const { data } = await import(layoutDataScript.src);
|
|
357
|
+
if (!ld[pathname]) ld[pathname] = data;
|
|
358
|
+
{
|
|
359
|
+
const dataScript = document.querySelector(`script[data-hook="true"][data-pathname="${sanitizePathname(pathname)}"]`);
|
|
360
|
+
if (dataScript) dataScript.remove();
|
|
361
|
+
}
|
|
362
|
+
initPageData(ld[pathname], path, previousPage, 2 /* SCOPED */);
|
|
224
363
|
}
|
|
225
|
-
|
|
226
|
-
|
|
364
|
+
}
|
|
365
|
+
{
|
|
366
|
+
const pageDataScript = document.head.querySelector(`script[data-page="true"][data-pathname="${sanitizePathname(pathname)}"]`);
|
|
367
|
+
const { data } = await import(pageDataScript.src);
|
|
368
|
+
if (!pd[pathname]) pd[pathname] = data;
|
|
227
369
|
{
|
|
228
370
|
const dataScript = document.querySelector(`script[data-hook="true"][data-pathname="${sanitizePathname(pathname)}"]`);
|
|
229
371
|
if (dataScript) dataScript.remove();
|
|
230
372
|
}
|
|
231
|
-
initPageData(
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
{
|
|
235
|
-
const pageDataScript = document.head.querySelector(`script[data-page="true"][data-pathname="${sanitizePathname(pathname)}"]`);
|
|
236
|
-
const { data } = await import(pageDataScript.src);
|
|
237
|
-
if (!pd[pathname]) pd[pathname] = data;
|
|
238
|
-
{
|
|
239
|
-
const dataScript = document.querySelector(`script[data-hook="true"][data-pathname="${sanitizePathname(pathname)}"]`);
|
|
240
|
-
if (dataScript) dataScript.remove();
|
|
241
|
-
}
|
|
242
|
-
initPageData(pd[pathname], currentPage, previousPage, 1 /* STRICT */);
|
|
243
|
-
}
|
|
244
|
-
console.info(
|
|
245
|
-
`Loading finished, cleanupProcedures are currently:`,
|
|
246
|
-
cleanupProcedures
|
|
247
|
-
);
|
|
248
|
-
};
|
|
249
|
-
const fetchPage = async (targetURL) => {
|
|
250
|
-
const pathname = sanitizePathname(targetURL.pathname);
|
|
251
|
-
if (pageStringCache.has(pathname)) {
|
|
252
|
-
return domParser.parseFromString(pageStringCache.get(pathname), "text/html");
|
|
253
|
-
}
|
|
254
|
-
const res = await fetch(targetURL);
|
|
255
|
-
const newDOM = domParser.parseFromString(await res.text(), "text/html");
|
|
256
|
-
{
|
|
257
|
-
const dataScripts = Array.from(newDOM.querySelectorAll('script[data-module="true"]'));
|
|
258
|
-
const currentScripts = Array.from(document.head.querySelectorAll('script[data-module="true"]'));
|
|
259
|
-
for (const dataScript of dataScripts) {
|
|
260
|
-
const existing = currentScripts.find((s) => s.src === dataScript.src);
|
|
261
|
-
if (existing) {
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
document.head.appendChild(dataScript);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
{
|
|
268
|
-
const pageDataScript = newDOM.querySelector('script[data-page="true"]');
|
|
269
|
-
if (!pageDataScript) {
|
|
270
|
-
return;
|
|
373
|
+
initPageData(pd[pathname], currentPage, previousPage, 1 /* STRICT */);
|
|
271
374
|
}
|
|
272
|
-
|
|
273
|
-
|
|
375
|
+
console.info(
|
|
376
|
+
`Loading finished, cleanupProcedures are currently:`,
|
|
377
|
+
cleanupProcedures
|
|
378
|
+
);
|
|
379
|
+
};
|
|
380
|
+
var fetchPage = async (targetURL) => {
|
|
381
|
+
const pathname = sanitizePathname(targetURL.pathname);
|
|
382
|
+
if (pageStringCache.has(pathname)) {
|
|
383
|
+
return domParser.parseFromString(pageStringCache.get(pathname), "text/html");
|
|
274
384
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
385
|
+
const res = await fetch(targetURL);
|
|
386
|
+
const newDOM = domParser.parseFromString(await res.text(), "text/html");
|
|
387
|
+
{
|
|
388
|
+
const dataScripts = Array.from(newDOM.querySelectorAll('script[data-module="true"]'));
|
|
389
|
+
const currentScripts = Array.from(document.head.querySelectorAll('script[data-module="true"]'));
|
|
390
|
+
for (const dataScript of dataScripts) {
|
|
391
|
+
const existing = currentScripts.find((s) => s.src === dataScript.src);
|
|
392
|
+
if (existing) {
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
document.head.appendChild(dataScript);
|
|
284
396
|
}
|
|
285
397
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
};
|
|
290
|
-
const navigateLocally = async (target, pushState = true) => {
|
|
291
|
-
const targetURL = new URL(target);
|
|
292
|
-
const pathname = sanitizePathname(targetURL.pathname);
|
|
293
|
-
console.log(
|
|
294
|
-
`%c${currentPage} -> ${targetURL.pathname}`,
|
|
295
|
-
"font-size: 18px; font-weight: 600; color: lightgreen;"
|
|
296
|
-
);
|
|
297
|
-
let newPage = await fetchPage(targetURL);
|
|
298
|
-
if (!newPage) return;
|
|
299
|
-
if (pathname === currentPage) return;
|
|
300
|
-
for (const cleanupProcedure of [...cleanupProcedures]) {
|
|
301
|
-
const isInScope = pathname.startsWith(cleanupProcedure.page);
|
|
302
|
-
if (!isInScope || cleanupProcedure.bindLevel === 1 /* STRICT */) {
|
|
303
|
-
try {
|
|
304
|
-
cleanupProcedure.cleanupFunction();
|
|
305
|
-
} catch (e) {
|
|
306
|
-
console.error(e);
|
|
398
|
+
{
|
|
399
|
+
const pageDataScript = newDOM.querySelector('script[data-page="true"]');
|
|
400
|
+
if (!pageDataScript) {
|
|
307
401
|
return;
|
|
308
402
|
}
|
|
309
|
-
|
|
403
|
+
if (!pd[pathname]) {
|
|
404
|
+
await import(pageDataScript.src);
|
|
405
|
+
}
|
|
310
406
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const oldPageLayout = oldPageLayouts[i];
|
|
321
|
-
const newLayoutId = newPageLayout.getAttribute("layout-id");
|
|
322
|
-
const oldLayoutId = oldPageLayout.getAttribute("layout-id");
|
|
323
|
-
if (newLayoutId !== oldLayoutId) {
|
|
324
|
-
break;
|
|
407
|
+
{
|
|
408
|
+
const layoutDataScripts = Array.from(newDOM.querySelectorAll('script[data-layout="true"]'));
|
|
409
|
+
for (const script of layoutDataScripts) {
|
|
410
|
+
const url = new URL(script.src, window.location.origin);
|
|
411
|
+
const dir = url.pathname.substring(0, url.pathname.lastIndexOf("/")) || "/";
|
|
412
|
+
const pathname2 = sanitizePathname(dir);
|
|
413
|
+
if (!ld[pathname2]) {
|
|
414
|
+
await import(script.src);
|
|
415
|
+
}
|
|
325
416
|
}
|
|
326
|
-
oldPageLatest = oldPageLayout.nextElementSibling;
|
|
327
|
-
newPageLatest = newPageLayout.nextElementSibling;
|
|
328
417
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
418
|
+
pageStringCache.set(pathname, xmlSerializer.serializeToString(newDOM));
|
|
419
|
+
return newDOM;
|
|
420
|
+
};
|
|
421
|
+
var navigateLocally = async (target, pushState = true) => {
|
|
422
|
+
const targetURL = new URL(target);
|
|
423
|
+
const pathname = sanitizePathname(targetURL.pathname);
|
|
424
|
+
console.log(
|
|
425
|
+
`%c${currentPage} -> ${targetURL.pathname}`,
|
|
426
|
+
"font-size: 18px; font-weight: 600; color: lightgreen;"
|
|
334
427
|
);
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
428
|
+
let newPage = await fetchPage(targetURL);
|
|
429
|
+
if (!newPage) return;
|
|
430
|
+
if (pathname === currentPage) return;
|
|
431
|
+
for (const cleanupProcedure of [...cleanupProcedures]) {
|
|
432
|
+
const isInScope = pathname.startsWith(cleanupProcedure.page);
|
|
433
|
+
if (!isInScope || cleanupProcedure.bindLevel === 1 /* STRICT */) {
|
|
434
|
+
try {
|
|
435
|
+
cleanupProcedure.cleanupFunction();
|
|
436
|
+
} catch (e) {
|
|
437
|
+
console.error(e);
|
|
438
|
+
return;
|
|
340
439
|
}
|
|
341
|
-
|
|
440
|
+
cleanupProcedures.splice(cleanupProcedures.indexOf(cleanupProcedure), 1);
|
|
342
441
|
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
442
|
+
}
|
|
443
|
+
let oldPageLatest = doc.body;
|
|
444
|
+
let newPageLatest = newPage.body;
|
|
445
|
+
{
|
|
446
|
+
const newPageLayouts = Array.from(newPage.querySelectorAll("template[layout-id]"));
|
|
447
|
+
const oldPageLayouts = Array.from(doc.querySelectorAll("template[layout-id]"));
|
|
448
|
+
const size = Math.min(newPageLayouts.length, oldPageLayouts.length);
|
|
449
|
+
for (let i = 0; i < size; i++) {
|
|
450
|
+
const newPageLayout = newPageLayouts[i];
|
|
451
|
+
const oldPageLayout = oldPageLayouts[i];
|
|
452
|
+
const newLayoutId = newPageLayout.getAttribute("layout-id");
|
|
453
|
+
const oldLayoutId = oldPageLayout.getAttribute("layout-id");
|
|
454
|
+
if (newLayoutId !== oldLayoutId) {
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
oldPageLatest = oldPageLayout.nextElementSibling;
|
|
458
|
+
newPageLatest = newPageLayout.nextElementSibling;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
oldPageLatest.replaceWith(newPageLatest);
|
|
462
|
+
{
|
|
463
|
+
doc.head.querySelector("title")?.replaceWith(
|
|
464
|
+
newPage.head.querySelector("title") ?? ""
|
|
465
|
+
);
|
|
466
|
+
const update = (targetList, matchAgainst, action) => {
|
|
467
|
+
for (const target2 of targetList) {
|
|
468
|
+
const matching = matchAgainst.find((n) => n.isEqualNode(target2));
|
|
469
|
+
if (matching) {
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
action(target2);
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
const oldTags = Array.from([
|
|
476
|
+
...Array.from(document.head.querySelectorAll("link")),
|
|
477
|
+
...Array.from(document.head.querySelectorAll("meta")),
|
|
478
|
+
...Array.from(document.head.querySelectorAll("script")),
|
|
479
|
+
...Array.from(document.head.querySelectorAll("base")),
|
|
480
|
+
...Array.from(document.head.querySelectorAll("style"))
|
|
481
|
+
]);
|
|
482
|
+
const newTags = Array.from([
|
|
483
|
+
...Array.from(newPage.head.querySelectorAll("link")),
|
|
484
|
+
...Array.from(newPage.head.querySelectorAll("meta")),
|
|
485
|
+
...Array.from(newPage.head.querySelectorAll("script")),
|
|
486
|
+
...Array.from(newPage.head.querySelectorAll("base")),
|
|
487
|
+
...Array.from(newPage.head.querySelectorAll("style"))
|
|
488
|
+
]);
|
|
489
|
+
update(newTags, oldTags, (node) => document.head.appendChild(node));
|
|
490
|
+
update(oldTags, newTags, (node) => node.remove());
|
|
491
|
+
}
|
|
492
|
+
if (pushState) history.pushState(null, "", targetURL.href);
|
|
493
|
+
await loadPage(currentPage);
|
|
494
|
+
currentPage = pathname;
|
|
495
|
+
if (targetURL.hash) {
|
|
496
|
+
doc.getElementById(targetURL.hash.slice(1))?.scrollIntoView();
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
window.onpopstate = async (event) => {
|
|
500
|
+
event.preventDefault();
|
|
501
|
+
const target = event.target;
|
|
502
|
+
await navigateLocally(target.location.href, false);
|
|
503
|
+
history.replaceState(null, "", target.location.href);
|
|
504
|
+
};
|
|
505
|
+
var renderRecursively = (element, attributes) => {
|
|
506
|
+
if (typeof element === "boolean") {
|
|
507
|
+
return null;
|
|
508
|
+
}
|
|
509
|
+
if (typeof element === "number" || typeof element === "string") {
|
|
510
|
+
return document.createTextNode(element.toString());
|
|
511
|
+
}
|
|
512
|
+
if (Array.isArray(element)) {
|
|
513
|
+
const fragment = document.createDocumentFragment();
|
|
514
|
+
element.forEach((item) => {
|
|
515
|
+
const childNode = renderRecursively(item, attributes);
|
|
516
|
+
if (childNode) fragment.appendChild(childNode);
|
|
517
|
+
});
|
|
518
|
+
return fragment;
|
|
519
|
+
}
|
|
520
|
+
const domElement = document.createElement(element.tag);
|
|
521
|
+
if (typeof element.options !== "object" && element.options !== void 0) {
|
|
396
522
|
const childNode = renderRecursively(element.options, attributes);
|
|
397
523
|
if (childNode) domElement.appendChild(childNode);
|
|
398
|
-
} else {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
524
|
+
} else if (typeof element.options === "object") {
|
|
525
|
+
const { tag, options, children } = element.options;
|
|
526
|
+
if (tag !== void 0 || options !== void 0 || children !== void 0) {
|
|
527
|
+
const childNode = renderRecursively(element.options, attributes);
|
|
528
|
+
if (childNode) domElement.appendChild(childNode);
|
|
529
|
+
} else {
|
|
530
|
+
for (const [attrName, attrValue] of Object.entries(element.options)) {
|
|
531
|
+
if (typeof attrValue === "object") {
|
|
532
|
+
const { isAttribute } = attrValue;
|
|
533
|
+
if (isAttribute === void 0 || isAttribute === false) {
|
|
534
|
+
console.error("Objects are not valid option property values.");
|
|
535
|
+
throw "";
|
|
536
|
+
}
|
|
537
|
+
attributes.push({
|
|
538
|
+
...attrValue,
|
|
539
|
+
field: attrName,
|
|
540
|
+
element: domElement
|
|
541
|
+
});
|
|
542
|
+
continue;
|
|
405
543
|
}
|
|
406
|
-
|
|
407
|
-
...attrValue,
|
|
408
|
-
field: attrName,
|
|
409
|
-
element: domElement
|
|
410
|
-
});
|
|
411
|
-
continue;
|
|
544
|
+
domElement.setAttribute(attrName.toLowerCase(), attrValue);
|
|
412
545
|
}
|
|
413
|
-
domElement.setAttribute(attrName.toLowerCase(), attrValue);
|
|
414
546
|
}
|
|
415
547
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
548
|
+
if (element.children !== null) {
|
|
549
|
+
if (Array.isArray(element.children)) {
|
|
550
|
+
element.children.forEach((child) => {
|
|
551
|
+
const childNode = renderRecursively(child, attributes);
|
|
552
|
+
if (childNode) domElement.appendChild(childNode);
|
|
553
|
+
});
|
|
554
|
+
} else {
|
|
555
|
+
const childNode = renderRecursively(element.children, attributes);
|
|
421
556
|
if (childNode) domElement.appendChild(childNode);
|
|
422
|
-
}
|
|
423
|
-
} else {
|
|
424
|
-
const childNode = renderRecursively(element.children, attributes);
|
|
425
|
-
if (childNode) domElement.appendChild(childNode);
|
|
557
|
+
}
|
|
426
558
|
}
|
|
559
|
+
return domElement;
|
|
560
|
+
};
|
|
561
|
+
globalThis.client = {
|
|
562
|
+
navigateLocally,
|
|
563
|
+
fetchPage,
|
|
564
|
+
currentPage,
|
|
565
|
+
sanitizePathname,
|
|
566
|
+
getReference: (id) => document.querySelector(`[ref="${id}"]`),
|
|
567
|
+
renderRecursively
|
|
568
|
+
};
|
|
569
|
+
try {
|
|
570
|
+
loadPage();
|
|
571
|
+
} catch (e) {
|
|
572
|
+
console.error(e);
|
|
427
573
|
}
|
|
428
|
-
|
|
429
|
-
};
|
|
430
|
-
globalThis.client = {
|
|
431
|
-
navigateLocally,
|
|
432
|
-
fetchPage,
|
|
433
|
-
currentPage,
|
|
434
|
-
sanitizePathname,
|
|
435
|
-
getReference: (id) => document.querySelector(`[ref="${id}"]`),
|
|
436
|
-
renderRecursively
|
|
437
|
-
};
|
|
438
|
-
try {
|
|
439
|
-
loadPage();
|
|
440
|
-
} catch (e) {
|
|
441
|
-
console.error(e);
|
|
442
|
-
}
|
|
574
|
+
})();
|
|
@@ -511,7 +511,9 @@ async function buildLayout(filePath, directory, generateDynamic = false) {
|
|
|
511
511
|
const { pageContentHTML, metadataHTML } = result;
|
|
512
512
|
function splitAround(str, sub) {
|
|
513
513
|
const i = str.indexOf(sub);
|
|
514
|
-
if (i === -1)
|
|
514
|
+
if (i === -1) {
|
|
515
|
+
throw new Error(`Whilst layout ${directory}, the splitter could not be found. Make sure to use the "child" prop passed into the layout.`);
|
|
516
|
+
}
|
|
515
517
|
return {
|
|
516
518
|
startHTML: str.substring(0, i),
|
|
517
519
|
endHTML: str.substring(i + sub.length)
|
|
@@ -519,7 +521,9 @@ async function buildLayout(filePath, directory, generateDynamic = false) {
|
|
|
519
521
|
}
|
|
520
522
|
function splitAt(str, sub) {
|
|
521
523
|
const i = str.indexOf(sub) + sub.length;
|
|
522
|
-
if (i === -1)
|
|
524
|
+
if (i === -1) {
|
|
525
|
+
throw new Error(`Whilst layout ${directory}, the splitter could not be found. Make sure to use the "child" prop passed into the layout's metadata.`);
|
|
526
|
+
}
|
|
523
527
|
return {
|
|
524
528
|
startHTML: str.substring(0, i),
|
|
525
529
|
endHTML: str.substring(i)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "elegance-js",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.20",
|
|
4
4
|
"description": "Web-Framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"native": "./scripts/native-test.js"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
|
-
"build": "esbuild --format=esm --platform=node --bundle=false --outdir=./dist --
|
|
13
|
+
"build": "esbuild --format=esm --platform=node --bundle=false --outdir=./dist --out-extension:.js=.mjs \"./src/**/*.ts\" && esbuild --format=iife --platform=browser --bundle=true --outfile=./dist/client/client.mjs --out-extension:.js=.mjs ./src/client/client.ts && tsc ",
|
|
14
14
|
"compile-docs": "node ./dist/compile_docs.mjs --environment=development",
|
|
15
15
|
"compile-docs-bun": "bun run ./dist/compile_docs.mjs --environment=development",
|
|
16
16
|
"prepare": "npm run build"
|