@takazudo/zfb-runtime 2.5.2 → 2.7.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/README.md +47 -16
- package/dist/client-router/events.js +2 -1
- package/dist/client-router/events.js.map +1 -1
- package/dist/client-router/history-safe.d.ts +2 -0
- package/dist/client-router/history-safe.js +34 -0
- package/dist/client-router/history-safe.js.map +1 -0
- package/dist/client-router/index.js +5 -1
- package/dist/client-router/index.js.map +1 -1
- package/dist/client-router/router.d.ts +8 -2
- package/dist/client-router/router.js +187 -99
- package/dist/client-router/router.js.map +1 -1
- package/dist/client-router-component.d.ts +74 -0
- package/dist/client-router-component.js +157 -0
- package/dist/client-router-component.js.map +1 -0
- package/dist/client-router.d.ts +1 -72
- package/dist/client-router.js +19 -146
- package/dist/client-router.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/snapshot.d.ts +31 -0
- package/dist/snapshot.js.map +1 -1
- package/package.json +3 -3
|
@@ -30,9 +30,11 @@
|
|
|
30
30
|
// W3C2 additions (this file):
|
|
31
31
|
// - `navigate()` public entry.
|
|
32
32
|
// - `onPopState`, `onScrollEnd`.
|
|
33
|
-
// -
|
|
34
|
-
//
|
|
35
|
-
//
|
|
33
|
+
// - Seeding `currentHistoryIndex` from `history.state`, registering popstate /
|
|
34
|
+
// load / scrollend listeners, and marking already-executed scripts with
|
|
35
|
+
// `dataset["zfbExec"] = ""`. W3C2 did all of this in two bare top-level
|
|
36
|
+
// `if (inBrowser)` blocks; #2436 folded both into `init()` (see the two
|
|
37
|
+
// once-guards there) so evaluating this module has no side effect at all.
|
|
36
38
|
//
|
|
37
39
|
// W3C1 items deferred to — and since implemented in — W3C3:
|
|
38
40
|
// - `announce()` route-announcer implementation (see the route-announcer block below;
|
|
@@ -50,6 +52,7 @@
|
|
|
50
52
|
// - `derivePopDirection` hardens the popstate forward/back calc against an unchanged or
|
|
51
53
|
// missing/NaN `state.index` that a bfcache restore can leave behind (#1076).
|
|
52
54
|
import { doPreparation, doSwap, onPageLoad, triggerEvent, updateScrollPosition, } from "./events.js";
|
|
55
|
+
import { safePushState, safeReplaceState } from "./history-safe.js";
|
|
53
56
|
import { detectScriptExecuted } from "./swap-functions.js";
|
|
54
57
|
// Island re-bootstrap and deferred-cancel after body swap (W1B §12.2, §12.5).
|
|
55
58
|
// mountNewIslands() is called after runScripts() and before onPageLoad().
|
|
@@ -145,19 +148,31 @@ let parser;
|
|
|
145
148
|
// you can figure it using an index. On pushState the index is incremented so you
|
|
146
149
|
// can use that to determine popstate if going forward or back.
|
|
147
150
|
let currentHistoryIndex = 0;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
151
|
+
// Once-guard for the navigation bookkeeping below. `init()` sets it too, so a
|
|
152
|
+
// later ensureNavigationState() can never clobber the activation-time seed.
|
|
153
|
+
let navigationStateSeeded = false;
|
|
154
|
+
/**
|
|
155
|
+
* Seed the module's navigation bookkeeping — `originalLocation` (declared
|
|
156
|
+
* without an initializer) and the tracked history index — from the live
|
|
157
|
+
* document, once.
|
|
158
|
+
*
|
|
159
|
+
* Deliberately side-effect free beyond those two variables: it registers no
|
|
160
|
+
* listener, writes no history entry, never scrolls, and never marks scripts.
|
|
161
|
+
* All of that belongs to {@link init}. Its only job is to keep an init-less
|
|
162
|
+
* `navigate()` / `syncHistoryEntry()` from reading `undefined` or stamping a
|
|
163
|
+
* fresh entry with the module default index — using the router without
|
|
164
|
+
* activating it is documented as unsupported, but it must not throw and must
|
|
165
|
+
* not mis-stamp. An existing finite `history.state.index` is ADOPTED, never
|
|
166
|
+
* reset: on a page whose entry is already index 7, the next push must be 8. (#2436)
|
|
167
|
+
*/
|
|
168
|
+
function ensureNavigationState() {
|
|
169
|
+
if (navigationStateSeeded || !inBrowser)
|
|
170
|
+
return;
|
|
171
|
+
navigationStateSeeded = true;
|
|
172
|
+
originalLocation = new URL(location.href);
|
|
173
|
+
const index = history.state?.index;
|
|
174
|
+
if (Number.isFinite(index))
|
|
175
|
+
currentHistoryIndex = index;
|
|
161
176
|
}
|
|
162
177
|
// returns the contents of the page or null if the router can't deal with it.
|
|
163
178
|
async function fetchHTML(href, init) {
|
|
@@ -274,7 +289,7 @@ historyCommittedEarly = false) => {
|
|
|
274
289
|
scrollX,
|
|
275
290
|
scrollY,
|
|
276
291
|
};
|
|
277
|
-
|
|
292
|
+
safeReplaceState({
|
|
278
293
|
...options.state,
|
|
279
294
|
index: current.index,
|
|
280
295
|
scrollX: current.scrollX,
|
|
@@ -282,7 +297,7 @@ historyCommittedEarly = false) => {
|
|
|
282
297
|
}, "", to.href);
|
|
283
298
|
}
|
|
284
299
|
else {
|
|
285
|
-
|
|
300
|
+
safePushState({ ...options.state, index: ++currentHistoryIndex, scrollX: 0, scrollY: 0 }, "", to.href);
|
|
286
301
|
}
|
|
287
302
|
}
|
|
288
303
|
document.title = targetPageTitle;
|
|
@@ -311,7 +326,7 @@ historyCommittedEarly = false) => {
|
|
|
311
326
|
const savedState = history.state;
|
|
312
327
|
location.href = to.href; // this kills the history state on Firefox
|
|
313
328
|
if (!history.state) {
|
|
314
|
-
|
|
329
|
+
safeReplaceState(savedState, ""); // this restores the history state
|
|
315
330
|
if (intraPage) {
|
|
316
331
|
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
317
332
|
}
|
|
@@ -368,6 +383,9 @@ export function syncHistoryEntry(url, options = {}) {
|
|
|
368
383
|
}
|
|
369
384
|
return;
|
|
370
385
|
}
|
|
386
|
+
// Adopt this page's existing history index before stamping an entry — an
|
|
387
|
+
// init-less caller must not reset a live entry's index to the module default.
|
|
388
|
+
ensureNavigationState();
|
|
371
389
|
const to = new URL(url, location.href);
|
|
372
390
|
// Cross-origin is not ours to manage. The History API would throw a native
|
|
373
391
|
// SecurityError for a cross-origin URL, but we guard explicitly so the failure
|
|
@@ -382,7 +400,7 @@ export function syncHistoryEntry(url, options = {}) {
|
|
|
382
400
|
// the tracked index rather than stamping NaN/undefined.
|
|
383
401
|
const current = history.state;
|
|
384
402
|
const index = current != null && Number.isFinite(current.index) ? current.index : currentHistoryIndex;
|
|
385
|
-
|
|
403
|
+
safeReplaceState({
|
|
386
404
|
...options.state,
|
|
387
405
|
index,
|
|
388
406
|
scrollX: Number.isFinite(current?.scrollX) ? current.scrollX : scrollX,
|
|
@@ -401,7 +419,7 @@ export function syncHistoryEntry(url, options = {}) {
|
|
|
401
419
|
// historyState branch below) scrollTo(0,0) when this entry is later
|
|
402
420
|
// Forward-reopened, snapping the page to the top under the reopened
|
|
403
421
|
// dialog. #1398.
|
|
404
|
-
|
|
422
|
+
safePushState({ ...options.state, index: ++currentHistoryIndex, scrollX, scrollY }, "", to.href);
|
|
405
423
|
}
|
|
406
424
|
// Always re-point originalLocation so the next transition()/onPopState uses the
|
|
407
425
|
// correct "from" URL. Skipping this is exactly what makes a raw pushState
|
|
@@ -693,7 +711,7 @@ async function transition(direction, from, to, options, historyState, hasUAVisua
|
|
|
693
711
|
scrollX,
|
|
694
712
|
scrollY,
|
|
695
713
|
};
|
|
696
|
-
|
|
714
|
+
safeReplaceState({
|
|
697
715
|
...options.state,
|
|
698
716
|
index: current.index,
|
|
699
717
|
scrollX: current.scrollX,
|
|
@@ -701,7 +719,7 @@ async function transition(direction, from, to, options, historyState, hasUAVisua
|
|
|
701
719
|
}, "", prepEvent.to.href);
|
|
702
720
|
}
|
|
703
721
|
else {
|
|
704
|
-
|
|
722
|
+
safePushState({ ...options.state, index: ++currentHistoryIndex, scrollX: 0, scrollY: 0 }, "", prepEvent.to.href);
|
|
705
723
|
}
|
|
706
724
|
}
|
|
707
725
|
if (supportsViewTransitions && !hasUAVisualTransition) {
|
|
@@ -809,6 +827,9 @@ export async function navigate(href, options) {
|
|
|
809
827
|
}
|
|
810
828
|
return;
|
|
811
829
|
}
|
|
830
|
+
// `originalLocation` is seeded by init(); seed it here too so an init-less
|
|
831
|
+
// caller never hands transition() an undefined "from" URL.
|
|
832
|
+
ensureNavigationState();
|
|
812
833
|
await transition("forward", originalLocation, new URL(href, location.href), options ?? {});
|
|
813
834
|
}
|
|
814
835
|
function onPopState(ev) {
|
|
@@ -863,22 +884,22 @@ const onScrollEnd = () => {
|
|
|
863
884
|
};
|
|
864
885
|
// zfb-only addition (no Astro upstream — see file header "zfb-only additions").
|
|
865
886
|
// WebKit serves Back navigations after an SPA route change from the bfcache:
|
|
866
|
-
// the page is restored without re-evaluating this module
|
|
867
|
-
//
|
|
868
|
-
// never re-runs and the tracked index can desync from
|
|
869
|
-
// A desynced index makes onPopState's direction calc
|
|
870
|
-
// entry. On a persisted (bfcache) restore we re-seed
|
|
871
|
-
// `originalLocation` "from" URL from the live state,
|
|
872
|
-
// mirroring
|
|
873
|
-
// falsy/absent) and idempotent (re-seeding from the same state
|
|
874
|
-
// nothing and fires no transition).
|
|
887
|
+
// the page is restored without re-evaluating this module or re-running init(),
|
|
888
|
+
// so `seedPageState()` below (which sets `currentHistoryIndex` from
|
|
889
|
+
// `history.state.index`) never re-runs and the tracked index can desync from
|
|
890
|
+
// the live history stack. A desynced index makes onPopState's direction calc
|
|
891
|
+
// misfire, so Back skips an entry. On a persisted (bfcache) restore we re-seed
|
|
892
|
+
// the tracked index and the `originalLocation` "from" URL from the live state,
|
|
893
|
+
// and restore scroll — mirroring that seed. This is a no-op on a normal load
|
|
894
|
+
// (`persisted` falsy/absent) and idempotent (re-seeding from the same state
|
|
895
|
+
// twice changes nothing and fires no transition).
|
|
875
896
|
const onPageShow = (ev) => {
|
|
876
|
-
// Normal (non-bfcache) loads already ran
|
|
897
|
+
// Normal (non-bfcache) loads already ran init()'s seed; leave them be.
|
|
877
898
|
if (!ev.persisted)
|
|
878
899
|
return;
|
|
879
|
-
//
|
|
880
|
-
//
|
|
881
|
-
//
|
|
900
|
+
// init() seeds `originalLocation` and `currentHistoryIndex` together; re-sync
|
|
901
|
+
// both here so the next transition() gets the correct `from` URL (a stale
|
|
902
|
+
// `originalLocation` would feed onPopState the wrong origin).
|
|
882
903
|
originalLocation = new URL(location.href);
|
|
883
904
|
const index = history.state?.index;
|
|
884
905
|
if (Number.isFinite(index)) {
|
|
@@ -888,67 +909,116 @@ const onPageShow = (ev) => {
|
|
|
888
909
|
scrollTo({ left: history.state.scrollX, top: history.state.scrollY });
|
|
889
910
|
}
|
|
890
911
|
};
|
|
891
|
-
// initialization
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
intervalId = undefined;
|
|
931
|
-
onScrollEnd();
|
|
932
|
-
return;
|
|
933
|
-
}
|
|
934
|
-
else {
|
|
935
|
-
((lastY = scrollY), (lastX = scrollX));
|
|
936
|
-
}
|
|
937
|
-
};
|
|
938
|
-
// We can't know when or how often scroll events fire, so we'll just use them to start intervals
|
|
939
|
-
addEventListener("scroll", () => {
|
|
940
|
-
if (intervalId !== undefined)
|
|
941
|
-
return;
|
|
942
|
-
((lastIndex = history.state?.index), (lastY = scrollY), (lastX = scrollX));
|
|
943
|
-
intervalId = window.setInterval(scrollInterval, 50);
|
|
944
|
-
}, { passive: true });
|
|
912
|
+
// ---- initialization (folded out of module scope by #2436) ----
|
|
913
|
+
// Once-guard for the page-state phase of init(). Deliberately SEPARATE from the
|
|
914
|
+
// `initialized` latch below, because the two phases have different eligibility:
|
|
915
|
+
// this one runs on EVERY browser page — including one where view transitions
|
|
916
|
+
// are ineligible (no native support and fallback "none") — while the activation
|
|
917
|
+
// listeners are VT-gated. A single shared latch would either skip this phase
|
|
918
|
+
// forever after an ineligible early call, or latch activation on a page that
|
|
919
|
+
// never qualified for it. (#2436)
|
|
920
|
+
let pageStateSeeded = false;
|
|
921
|
+
/**
|
|
922
|
+
* Everything module evaluation used to do for EVERY browser page, regardless
|
|
923
|
+
* of view-transition eligibility: restore (or seed) this page's history entry
|
|
924
|
+
* and its scroll position, and mark the scripts the initial page load already
|
|
925
|
+
* executed so runScripts() does not re-run them after a swap.
|
|
926
|
+
*
|
|
927
|
+
* Called from init() BEFORE its eligibility early-return — that gating
|
|
928
|
+
* asymmetry is load-bearing and predates the fold: a page with fallback "none"
|
|
929
|
+
* still needs its history entry restored and its scripts marked. (#2436)
|
|
930
|
+
*/
|
|
931
|
+
function seedPageState() {
|
|
932
|
+
if (pageStateSeeded)
|
|
933
|
+
return;
|
|
934
|
+
pageStateSeeded = true;
|
|
935
|
+
if (history.state) {
|
|
936
|
+
// Here we reloaded a page with history state
|
|
937
|
+
// (e.g. history navigation from non-transition page or browser reload)
|
|
938
|
+
// Adopt only a finite index — a foreign pre-init history.state (e.g. a
|
|
939
|
+
// consumer's own replaceState({modal: true})) has no router index, and
|
|
940
|
+
// adopting undefined would stamp the next push with NaN. Same guard as
|
|
941
|
+
// ensureNavigationState() and onPageShow(). (#2436)
|
|
942
|
+
const index = history.state.index;
|
|
943
|
+
if (Number.isFinite(index))
|
|
944
|
+
currentHistoryIndex = index;
|
|
945
|
+
// Skip the scroll restore when an init-less navigate()/syncHistoryEntry()
|
|
946
|
+
// already ran on this page (navigationStateSeeded latched before init):
|
|
947
|
+
// the entry it pushed is stamped scrollX/scrollY 0, and a late-activating
|
|
948
|
+
// init() must not yank the already-scrolled viewport to the top. (#2436)
|
|
949
|
+
if (!navigationStateSeeded) {
|
|
950
|
+
scrollTo({ left: history.state.scrollX, top: history.state.scrollY });
|
|
945
951
|
}
|
|
946
952
|
}
|
|
953
|
+
else if (transitionEnabledOnThisPage()) {
|
|
954
|
+
// This page is loaded from the browser address bar or via a link from extern,
|
|
955
|
+
// it needs a state in the history
|
|
956
|
+
safeReplaceState({ index: currentHistoryIndex, scrollX, scrollY }, "");
|
|
957
|
+
history.scrollRestoration = "manual";
|
|
958
|
+
}
|
|
947
959
|
for (const script of document.getElementsByTagName("script")) {
|
|
948
960
|
detectScriptExecuted(script);
|
|
949
961
|
script.dataset["zfbExec"] = "";
|
|
950
962
|
}
|
|
951
963
|
}
|
|
964
|
+
/**
|
|
965
|
+
* Register the window-level navigation listeners. Called from init() only
|
|
966
|
+
* after the view-transition eligibility check, and only once — the
|
|
967
|
+
* `initialized` latch owns this phase.
|
|
968
|
+
*/
|
|
969
|
+
function registerNavigationListeners() {
|
|
970
|
+
addEventListener("popstate", onPopState);
|
|
971
|
+
addEventListener("load", onPageLoad);
|
|
972
|
+
// Re-sync the tracked history index + scroll on a WebKit bfcache restore;
|
|
973
|
+
// a no-op on normal loads. See onPageShow above.
|
|
974
|
+
addEventListener("pageshow", onPageShow);
|
|
975
|
+
// There's not a good way to record scroll position before a history back
|
|
976
|
+
// navigation, so we will record it when the user has stopped scrolling.
|
|
977
|
+
if ("onscrollend" in window)
|
|
978
|
+
addEventListener("scrollend", onScrollEnd);
|
|
979
|
+
else {
|
|
980
|
+
// Keep track of state between intervals
|
|
981
|
+
let intervalId, lastY, lastX, lastIndex;
|
|
982
|
+
const scrollInterval = () => {
|
|
983
|
+
// The interval can outlive its document context — a test-env teardown or a
|
|
984
|
+
// real page unload removes window/history before the 50ms tick. `typeof`
|
|
985
|
+
// never throws even when the global is gone: stop the interval and bail
|
|
986
|
+
// rather than dereferencing a torn-down global (the #1061 bug class; #1063).
|
|
987
|
+
// In a real browser these globals always exist, so this path is test-env
|
|
988
|
+
// only. clearInterval may itself be mid-teardown, so guard the call too.
|
|
989
|
+
if (typeof window === "undefined" || typeof history === "undefined") {
|
|
990
|
+
if (typeof clearInterval === "function")
|
|
991
|
+
clearInterval(intervalId);
|
|
992
|
+
intervalId = undefined;
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
// Check the index to see if a popstate event was fired
|
|
996
|
+
if (lastIndex !== history.state?.index) {
|
|
997
|
+
clearInterval(intervalId);
|
|
998
|
+
intervalId = undefined;
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
// Check if the user stopped scrolling
|
|
1002
|
+
if (lastY === scrollY && lastX === scrollX) {
|
|
1003
|
+
// Cancel the interval and update scroll positions
|
|
1004
|
+
clearInterval(intervalId);
|
|
1005
|
+
intervalId = undefined;
|
|
1006
|
+
onScrollEnd();
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
else {
|
|
1010
|
+
((lastY = scrollY), (lastX = scrollX));
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
// We can't know when or how often scroll events fire, so we'll just use them to start intervals
|
|
1014
|
+
addEventListener("scroll", () => {
|
|
1015
|
+
if (intervalId !== undefined)
|
|
1016
|
+
return;
|
|
1017
|
+
((lastIndex = history.state?.index), (lastY = scrollY), (lastX = scrollX));
|
|
1018
|
+
intervalId = window.setInterval(scrollInterval, 50);
|
|
1019
|
+
}, { passive: true });
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
952
1022
|
// ---- W3C3: click + form intercept, public idempotent init() ----
|
|
953
1023
|
// Returns true when the modifier-key combo or mouse button means "open in new tab / download".
|
|
954
1024
|
// Matches Astro's `leavesWindow` helper in ClientRouter.astro.
|
|
@@ -1045,26 +1115,44 @@ function handleSubmit(ev) {
|
|
|
1045
1115
|
ev.preventDefault();
|
|
1046
1116
|
navigate(action, options);
|
|
1047
1117
|
}
|
|
1048
|
-
// Guard flag — ensures
|
|
1049
|
-
//
|
|
1118
|
+
// Guard flag — ensures the activation listeners (popstate/load/pageshow/scroll
|
|
1119
|
+
// plus click + submit) are registered only once even if init() is called
|
|
1120
|
+
// multiple times (e.g. two <ClientRouter> mounts on the same page).
|
|
1050
1121
|
let initialized = false;
|
|
1051
1122
|
/**
|
|
1052
|
-
*
|
|
1053
|
-
*
|
|
1123
|
+
* Bootstrap the client router on this page: restore its history entry, mark
|
|
1124
|
+
* the already-executed scripts, and wire up the navigation, click and
|
|
1125
|
+
* form-submit listeners. Safe to call multiple times — each of the two phases
|
|
1126
|
+
* runs at most once (idempotent).
|
|
1127
|
+
*
|
|
1128
|
+
* Evaluating this module does nothing; every side effect the router performs
|
|
1129
|
+
* at startup happens here (#2436). Two once-guards rather than one, because
|
|
1130
|
+
* the phases have different eligibility — see `pageStateSeeded`.
|
|
1054
1131
|
*
|
|
1055
1132
|
* @param _options - Forward-compat hook matching Astro's init() signature. Ignored in v1.
|
|
1056
1133
|
*/
|
|
1057
1134
|
export function init(_options) {
|
|
1058
|
-
if (initialized)
|
|
1059
|
-
return;
|
|
1060
|
-
// Latch the guard only AFTER the early-return guards below: an ineligible
|
|
1061
|
-
// early call (no browser, or fallback "none") must not permanently latch
|
|
1062
|
-
// `initialized`, or a later legitimately-eligible init() would no-op forever.
|
|
1063
1135
|
if (!inBrowser)
|
|
1064
1136
|
return;
|
|
1137
|
+
// Phase 1 — runs on every browser page, even a view-transition-ineligible
|
|
1138
|
+
// one, and therefore BEFORE the eligibility early-return below.
|
|
1139
|
+
seedPageState();
|
|
1140
|
+
if (initialized)
|
|
1141
|
+
return;
|
|
1142
|
+
// Phase 2 — activation. Latch the guard only AFTER this eligibility check:
|
|
1143
|
+
// an ineligible early call (fallback "none" and no native view transitions)
|
|
1144
|
+
// must not permanently latch `initialized`, or a later legitimately-eligible
|
|
1145
|
+
// init() would no-op forever.
|
|
1065
1146
|
if (!supportsViewTransitions && getFallback() === "none")
|
|
1066
1147
|
return;
|
|
1067
1148
|
initialized = true;
|
|
1149
|
+
// Where we came from, for the first transition() of this page. Re-seeded
|
|
1150
|
+
// unconditionally at activation (as module evaluation used to do), so it
|
|
1151
|
+
// reflects the URL at activation time even if an init-less navigate() or
|
|
1152
|
+
// syncHistoryEntry() already primed it via ensureNavigationState().
|
|
1153
|
+
navigationStateSeeded = true;
|
|
1154
|
+
originalLocation = new URL(location.href);
|
|
1155
|
+
registerNavigationListeners();
|
|
1068
1156
|
document.addEventListener("click", handleClick);
|
|
1069
1157
|
document.addEventListener("submit", handleSubmit);
|
|
1070
1158
|
// Prefetch hook intentionally omitted from v1 — see https://github.com/zudolab/zudo-doc/issues/1527
|