in kit/svelteKitCustomClient/client.js [978:1196]
async function navigate({
url,
scroll,
keepfocus,
redirect_chain,
details,
type,
delta,
nav_token = {},
accepted,
blocked,
}) {
const originalUrl = new URL(url.href);
const renamedPathname = getHfDocFullPath(url.pathname);
if (renamedPathname) {
url.pathname = renamedPathname;
}
const intent = get_navigation_intent(url, false);
const nav = before_navigate({ url, type, delta, intent });
if (!nav) {
blocked();
return;
}
// store this before calling `accepted()`, which may change the index
const previous_history_index = current_history_index;
accepted();
navigating = true;
if (started) {
stores.navigating.set(nav.navigation);
}
token = nav_token;
let navigation_result = intent && (await load_route(intent));
if (!navigation_result) {
if (is_external_url(url, base)) {
return await native_navigation(url);
}
navigation_result = await server_fallback(
url,
{ id: null },
await handle_error(new Error(`Not found: ${url.pathname}`), {
url,
params: {},
route: { id: null },
}),
404
);
}
// if this is an internal navigation intent, use the normalized
// URL for the rest of the function
url = intent?.url || url;
// abort if user navigated during update
if (token !== nav_token) {
nav.reject(new Error("navigation was aborted"));
return false;
}
if (navigation_result.type === "redirect") {
if (redirect_chain.length > 10 || redirect_chain.includes(url.pathname)) {
navigation_result = await load_root_error_page({
status: 500,
error: await handle_error(new Error("Redirect loop"), {
url,
params: {},
route: { id: null },
}),
url,
route: { id: null },
});
} else {
goto(
new URL(navigation_result.location, url).href,
{},
[...redirect_chain, url.pathname],
nav_token
);
return false;
}
} else if (/** @type {number} */ (navigation_result.props.page?.status) >= 400) {
const updated = await stores.updated.check();
if (updated) {
await native_navigation(url);
}
}
// reset invalidation only after a finished navigation. If there are redirects or
// additional invalidations, they should get the same invalidation treatment
invalidated.length = 0;
force_invalidation = false;
updating = true;
update_scroll_positions(previous_history_index);
capture_snapshot(previous_history_index);
// ensure the url pathname matches the page's trailing slash option
if (
navigation_result.props.page?.url &&
navigation_result.props.page.url.pathname !== url.pathname
) {
url.pathname = navigation_result.props.page?.url.pathname;
}
if (details) {
const change = details.replaceState ? 0 : 1;
details.state[INDEX_KEY] = current_history_index += change;
history[details.replaceState ? "replaceState" : "pushState"](details.state, "", originalUrl);
if (!details.replaceState) {
// if we navigated back, then pushed a new state, we can
// release memory by pruning the scroll/snapshot lookup
let i = current_history_index + 1;
while (snapshots[i] || scroll_positions[i]) {
delete snapshots[i];
delete scroll_positions[i];
i += 1;
}
}
}
// reset preload synchronously after the history state has been set to avoid race conditions
load_cache = null;
if (started) {
current = navigation_result.state;
// reset url before updating page store
if (navigation_result.props.page) {
navigation_result.props.page.url = url;
}
const after_navigate = (
await Promise.all(
callbacks.on_navigate.map((fn) =>
fn(/** @type {import('@sveltejs/kit').OnNavigate} */ (nav.navigation))
)
)
).filter((value) => typeof value === "function");
if (after_navigate.length > 0) {
function cleanup() {
callbacks.after_navigate = callbacks.after_navigate.filter(
// @ts-ignore
(fn) => !after_navigate.includes(fn)
);
}
after_navigate.push(cleanup);
// @ts-ignore
callbacks.after_navigate.push(...after_navigate);
}
root.$set(navigation_result.props);
} else {
initialize(navigation_result);
}
const { activeElement } = document;
// need to render the DOM before we can scroll to the rendered elements and do focus management
await tick();
// we reset scroll before dealing with focus, to avoid a flash of unscrolled content
if (autoscroll) {
const deep_linked =
url.hash && document.getElementById(decodeURIComponent(url.hash.slice(1)));
if (scroll) {
scrollTo(scroll.x, scroll.y);
} else if (deep_linked) {
// Here we use `scrollIntoView` on the element instead of `scrollTo`
// because it natively supports the `scroll-margin` and `scroll-behavior`
// CSS properties.
deep_linked.scrollIntoView();
} else {
scrollTo(0, 0);
}
}
const changed_focus =
// reset focus only if any manual focus management didn't override it
document.activeElement !== activeElement &&
// also refocus when activeElement is body already because the
// focus event might not have been fired on it yet
document.activeElement !== document.body;
if (!keepfocus && !changed_focus) {
reset_focus();
}
autoscroll = true;
if (navigation_result.props.page) {
page = navigation_result.props.page;
}
navigating = false;
if (type === "popstate") {
restore_snapshot(current_history_index);
}
nav.fulfil(undefined);
callbacks.after_navigate.forEach((fn) =>
fn(/** @type {import('@sveltejs/kit').AfterNavigate} */ (nav.navigation))
);
stores.navigating.set(null);
updating = false;
}