@very-simple/ajax 1.0.0-beta.4 → 1.0.0-beta.6
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/index.d.ts +5 -0
- package/dist/index.js +46 -39
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -74,6 +74,11 @@ type EventMap = {
|
|
|
74
74
|
'before-visit': Payload;
|
|
75
75
|
'before-swap': Payload;
|
|
76
76
|
'after-swap': Payload;
|
|
77
|
+
'progress-start': Record<string, never>;
|
|
78
|
+
progress: {
|
|
79
|
+
progress: number;
|
|
80
|
+
};
|
|
81
|
+
'progress-end': Record<string, never>;
|
|
77
82
|
};
|
|
78
83
|
type DomEventMap = {
|
|
79
84
|
[K in keyof EventMap as `ajax:${K & string}`]: CustomEvent<EventMap[K]>;
|
package/dist/index.js
CHANGED
|
@@ -13,18 +13,20 @@ var config = {
|
|
|
13
13
|
// src/load.ts
|
|
14
14
|
var parser = new DOMParser();
|
|
15
15
|
var currentLoadController;
|
|
16
|
+
var progressDelayTimeout;
|
|
16
17
|
var progress = 0;
|
|
17
18
|
var trickleInterval;
|
|
19
|
+
var emit = (type, payload) => document.dispatchEvent(new CustomEvent(`ajax:${type}`, { detail: payload }));
|
|
18
20
|
var cache = /* @__PURE__ */ new Map();
|
|
19
21
|
var load = async (url, regions, options) => {
|
|
20
|
-
let
|
|
22
|
+
let aborted = false;
|
|
21
23
|
try {
|
|
22
24
|
currentLoadController?.abort();
|
|
25
|
+
clearTimeout(progressDelayTimeout);
|
|
23
26
|
currentLoadController = new AbortController();
|
|
24
27
|
setProgress(0);
|
|
25
28
|
progressDelayTimeout = window.setTimeout(() => {
|
|
26
|
-
|
|
27
|
-
toggleProgress(true);
|
|
29
|
+
emit("progress-start", {});
|
|
28
30
|
startTrickle();
|
|
29
31
|
}, options.loadingDelay);
|
|
30
32
|
const response = await fetch(url, {
|
|
@@ -41,17 +43,18 @@ var load = async (url, regions, options) => {
|
|
|
41
43
|
const document2 = parseHtml(html);
|
|
42
44
|
return { document: document2, response };
|
|
43
45
|
} catch (e) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
aborted = e instanceof DOMException && e.name === "AbortError";
|
|
47
|
+
if (!aborted) {
|
|
48
|
+
setProgress(0);
|
|
47
49
|
window.location.reload();
|
|
48
50
|
}
|
|
49
51
|
} finally {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
if (!aborted) {
|
|
53
|
+
clearTimeout(progressDelayTimeout);
|
|
54
|
+
stopTrickle();
|
|
55
|
+
setProgress(1);
|
|
56
|
+
setTimeout(() => emit("progress-end", {}), options.progressHideDelay);
|
|
57
|
+
}
|
|
55
58
|
}
|
|
56
59
|
};
|
|
57
60
|
var parseHtml = (html) => parser.parseFromString(html, "text/html");
|
|
@@ -59,17 +62,18 @@ var trickle = () => {
|
|
|
59
62
|
const amount = -0.095 * progress + 0.1;
|
|
60
63
|
setProgress(progress + Math.random() * amount);
|
|
61
64
|
};
|
|
62
|
-
var startTrickle = () =>
|
|
63
|
-
|
|
65
|
+
var startTrickle = () => {
|
|
66
|
+
stopTrickle();
|
|
67
|
+
trickleInterval = window.setInterval(trickle, 300);
|
|
68
|
+
};
|
|
69
|
+
var stopTrickle = () => {
|
|
70
|
+
clearInterval(trickleInterval);
|
|
71
|
+
trickleInterval = void 0;
|
|
72
|
+
};
|
|
64
73
|
var setProgress = (value) => {
|
|
65
74
|
progress = value;
|
|
66
|
-
|
|
67
|
-
"--ajax-progress",
|
|
68
|
-
`${Math.round(value * 1e4) / 100}%`
|
|
69
|
-
);
|
|
75
|
+
emit("progress", { progress: value });
|
|
70
76
|
};
|
|
71
|
-
var toggleProgress = (state) => document.documentElement.toggleAttribute(`${config.prefix}progress`, state);
|
|
72
|
-
var toggleLoading = (state) => document.documentElement.toggleAttribute(`${config.prefix}loading`, state);
|
|
73
77
|
|
|
74
78
|
// src/merge.ts
|
|
75
79
|
import { Idiomorph } from "idiomorph/dist/idiomorph.esm.js";
|
|
@@ -82,7 +86,7 @@ var merge = (region, newRegion, strategy) => {
|
|
|
82
86
|
Array.from(
|
|
83
87
|
newRegion.querySelectorAll(`[${escapedPrefix}permanent][id]`)
|
|
84
88
|
).forEach((el) => {
|
|
85
|
-
const original = region.querySelector(`#${el.id}`);
|
|
89
|
+
const original = region.querySelector(`#${CSS.escape(el.id)}`);
|
|
86
90
|
if (original) {
|
|
87
91
|
permanents.set(el.id, original);
|
|
88
92
|
original.remove();
|
|
@@ -91,13 +95,12 @@ var merge = (region, newRegion, strategy) => {
|
|
|
91
95
|
unmount?.(region);
|
|
92
96
|
if (strategy === "replace") region.replaceWith(newRegion);
|
|
93
97
|
else region.replaceChildren(...Array.from(newRegion.children));
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
).forEach((el) => {
|
|
98
|
+
const target = strategy === "replace" ? newRegion : region;
|
|
99
|
+
target.querySelectorAll(`[${escapedPrefix}permanent][id]`).forEach((el) => {
|
|
97
100
|
const original = permanents.get(el.id);
|
|
98
101
|
if (original) el.replaceWith(original);
|
|
99
102
|
});
|
|
100
|
-
mount?.(
|
|
103
|
+
mount?.(target);
|
|
101
104
|
} else if (strategy === "before") {
|
|
102
105
|
region.insertAdjacentElement("beforebegin", newRegion);
|
|
103
106
|
mount?.(newRegion);
|
|
@@ -114,6 +117,7 @@ var merge = (region, newRegion, strategy) => {
|
|
|
114
117
|
const result = morph(region, newRegion);
|
|
115
118
|
autoFocusEl = result.autoFocusEl;
|
|
116
119
|
}
|
|
120
|
+
if (strategy === "morph") return { autoFocusEl };
|
|
117
121
|
if (newRegion.hasAttribute(`${prefix}autofocus`) || newRegion.autofocus) {
|
|
118
122
|
autoFocusEl ??= newRegion;
|
|
119
123
|
}
|
|
@@ -123,7 +127,7 @@ var merge = (region, newRegion, strategy) => {
|
|
|
123
127
|
var morph = (container, newContainer) => {
|
|
124
128
|
const { prefix, mount, unmount } = config;
|
|
125
129
|
const manualReplacements = [];
|
|
126
|
-
|
|
130
|
+
const autoFocusEls = [];
|
|
127
131
|
let currentNodeKeepAttributes = [];
|
|
128
132
|
Idiomorph.morph(container, newContainer, {
|
|
129
133
|
callbacks: {
|
|
@@ -138,6 +142,7 @@ var morph = (container, newContainer) => {
|
|
|
138
142
|
const isSameComponent = oldIsComponent && newIsComponent && oldNode.getAttribute(`${prefix}component`) === newNode.getAttribute(`${prefix}component`);
|
|
139
143
|
if (!oldIsComponent || isSameComponent) return true;
|
|
140
144
|
manualReplacements.push([oldNode, newNode]);
|
|
145
|
+
return false;
|
|
141
146
|
},
|
|
142
147
|
beforeAttributeUpdated: (name) => {
|
|
143
148
|
return !currentNodeKeepAttributes.includes(name);
|
|
@@ -153,9 +158,9 @@ var morph = (container, newContainer) => {
|
|
|
153
158
|
mount?.(node);
|
|
154
159
|
}
|
|
155
160
|
},
|
|
156
|
-
afterNodeMorphed(
|
|
157
|
-
if (
|
|
158
|
-
autoFocusEls.push(
|
|
161
|
+
afterNodeMorphed(oldNode) {
|
|
162
|
+
if (oldNode instanceof HTMLElement && (oldNode.autofocus || oldNode.hasAttribute(`${prefix}autofocus`))) {
|
|
163
|
+
autoFocusEls.push(oldNode);
|
|
159
164
|
}
|
|
160
165
|
}
|
|
161
166
|
}
|
|
@@ -205,7 +210,7 @@ var normalizeUrl = (url) => {
|
|
|
205
210
|
return url;
|
|
206
211
|
}
|
|
207
212
|
};
|
|
208
|
-
var
|
|
213
|
+
var emit2 = (type, payload) => {
|
|
209
214
|
const waiting = [];
|
|
210
215
|
const waitUntil = (promise) => waiting.push(Promise.resolve(promise));
|
|
211
216
|
payload = { ...payload, waitUntil };
|
|
@@ -213,7 +218,7 @@ var emit = (type, payload) => {
|
|
|
213
218
|
document.dispatchEvent(event);
|
|
214
219
|
if (waiting.length) return Promise.allSettled(waiting);
|
|
215
220
|
};
|
|
216
|
-
var currentUrl = window.location.pathname;
|
|
221
|
+
var currentUrl = window.location.pathname + window.location.search;
|
|
217
222
|
var currentState = history.state;
|
|
218
223
|
var currentVisitController;
|
|
219
224
|
var scrollPositions = /* @__PURE__ */ new Map();
|
|
@@ -239,7 +244,7 @@ var visit = async (url, {
|
|
|
239
244
|
currentVisitController = new AbortController();
|
|
240
245
|
const { signal } = currentVisitController;
|
|
241
246
|
if (url === currentUrl) historyMode = "none";
|
|
242
|
-
await
|
|
247
|
+
await emit2("before-visit", {
|
|
243
248
|
from: { url: fromUrl, state: fromState, document },
|
|
244
249
|
to: { url, state },
|
|
245
250
|
signal,
|
|
@@ -260,13 +265,14 @@ var visit = async (url, {
|
|
|
260
265
|
}
|
|
261
266
|
}
|
|
262
267
|
if (!newDocument) return;
|
|
268
|
+
if (signal.aborted) return;
|
|
263
269
|
currentUrl = url;
|
|
264
270
|
currentState = state;
|
|
265
271
|
if (historyMode === "replace") history.replaceState(state, "", url);
|
|
266
272
|
else if (historyMode === "push") history.pushState(state, "", url);
|
|
267
273
|
const from = { url: fromUrl, state: fromState, document };
|
|
268
274
|
const to = { url, state, document: newDocument };
|
|
269
|
-
await
|
|
275
|
+
await emit2("before-swap", { from, to, isBackForward, signal });
|
|
270
276
|
if (signal.aborted) return;
|
|
271
277
|
const getMergeStrategy = (oldEl, newEl) => newEl.getAttribute(`${config.prefix}merge`) || oldEl.getAttribute(`${config.prefix}merge`) || mergeStrategy;
|
|
272
278
|
let autoFocusEl;
|
|
@@ -278,8 +284,9 @@ var visit = async (url, {
|
|
|
278
284
|
if (hasMatchingRegions) {
|
|
279
285
|
for (const id of regions) {
|
|
280
286
|
const region = document.querySelector(id);
|
|
281
|
-
const
|
|
282
|
-
if (!region || !
|
|
287
|
+
const parsedRegion = newDocument.querySelector(id);
|
|
288
|
+
if (!region || !parsedRegion) continue;
|
|
289
|
+
const newRegion = document.importNode(parsedRegion, true);
|
|
283
290
|
const strategy = getMergeStrategy(region, newRegion);
|
|
284
291
|
const result = merge(region, newRegion, strategy);
|
|
285
292
|
autoFocusEl ??= result.autoFocusEl;
|
|
@@ -290,7 +297,7 @@ var visit = async (url, {
|
|
|
290
297
|
}
|
|
291
298
|
} else {
|
|
292
299
|
const region = document.body;
|
|
293
|
-
const newRegion = newDocument.body;
|
|
300
|
+
const newRegion = document.importNode(newDocument.body, true);
|
|
294
301
|
const strategy = getMergeStrategy(region, newRegion);
|
|
295
302
|
const result = merge(region, newRegion, strategy);
|
|
296
303
|
autoFocusEl = result.autoFocusEl;
|
|
@@ -319,18 +326,18 @@ var visit = async (url, {
|
|
|
319
326
|
await document.startViewTransition(async () => {
|
|
320
327
|
if (morphHeads) Idiomorph2.morph(document.head, newDocument.head);
|
|
321
328
|
await mergeRegions();
|
|
322
|
-
await
|
|
329
|
+
await emit2("after-swap", { from, to, isBackForward, signal });
|
|
323
330
|
applyScrollBehavior();
|
|
324
|
-
}).
|
|
331
|
+
}).updateCallbackDone;
|
|
325
332
|
} else {
|
|
326
333
|
if (morphHeads) Idiomorph2.morph(document.head, newDocument.head);
|
|
327
334
|
await mergeRegions();
|
|
328
|
-
await
|
|
335
|
+
await emit2("after-swap", { from, to, isBackForward, signal });
|
|
329
336
|
applyScrollBehavior();
|
|
330
337
|
}
|
|
331
338
|
if (signal.aborted) return;
|
|
332
339
|
if (autoFocus) autoFocusEl?.focus({ preventScroll: true });
|
|
333
|
-
|
|
340
|
+
emit2("load", { from, to, isBackForward });
|
|
334
341
|
};
|
|
335
342
|
|
|
336
343
|
// src/intercept.ts
|