Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 41 additions & 24 deletions packages/fresh/src/runtime/client/partials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,29 +83,38 @@ if (!history.state) {
history.replaceState(state, document.title);
}

function maybeUpdateHistory(nextUrl: URL) {
function saveScrollPosition() {
const state: FreshHistoryState = {
fClientNav: true,
index,
scrollX: globalThis.scrollX,
scrollY: globalThis.scrollY,
};
history.replaceState(state, "", location.href);
}

function maybePushHistory(nextUrl: URL) {
// Only add history entry when URL is new. Still apply
// the partials because sometimes users click a link to
// "refresh" the current page.
if (nextUrl.href !== globalThis.location.href) {
index++;
const state: FreshHistoryState = {
fClientNav: true,
index,
scrollX: globalThis.scrollX,
scrollY: globalThis.scrollY,
scrollX: 0,
scrollY: 0,
};

// Store current scroll position
history.replaceState({ ...state }, "", location.href);

// Now store the new position
index++;
state.scrollX = 0;
state.scrollY = 0;
history.pushState(state, "", nextUrl.href);
}
}

function maybeReplaceHistory(nextUrl: URL) {
if (nextUrl.href !== globalThis.location.href) {
history.replaceState(history.state, "", nextUrl.href);
}
}

document.addEventListener("click", async (e) => {
let el = e.target;
if (el && (el instanceof HTMLElement || el instanceof SVGElement)) {
Expand Down Expand Up @@ -154,15 +163,20 @@ document.addEventListener("click", async (e) => {

const nextUrl = new URL(el.href);
try {
maybeUpdateHistory(nextUrl);
saveScrollPosition();
maybePushHistory(nextUrl);

const partialUrl = new URL(
partial ? partial : nextUrl.href,
location.href,
);
let finalUrl = nextUrl;
await withViewTransition(async () => {
await fetchPartials(nextUrl, partialUrl, true);
updateLinks(nextUrl);
finalUrl = await fetchPartials(nextUrl, partialUrl);
if (finalUrl.href !== nextUrl.href) {
maybeReplaceHistory(finalUrl);
}
updateLinks(finalUrl);
});
scrollTo({ left: 0, top: 0, behavior: "instant" });
} finally {
Expand All @@ -185,7 +199,7 @@ document.addEventListener("click", async (e) => {
partial,
location.href,
);
await fetchPartials(partialUrl, partialUrl, false);
await fetchPartials(partialUrl, partialUrl);
}
}
});
Expand Down Expand Up @@ -223,8 +237,11 @@ addEventListener("popstate", async (e) => {
const url = new URL(location.href, location.origin);
try {
await withViewTransition(async () => {
await fetchPartials(url, url, true);
updateLinks(url);
const finalUrl = await fetchPartials(url, url);
if (finalUrl.href !== url.href) {
maybeReplaceHistory(finalUrl);
}
updateLinks(finalUrl);
});
scrollTo({
left: state.scrollX ?? 0,
Expand Down Expand Up @@ -304,8 +321,10 @@ document.addEventListener("submit", async (e) => {
}

try {
saveScrollPosition();
await withViewTransition(async () => {
await fetchPartials(actionUrl, partialUrl, true, init);
const finalUrl = await fetchPartials(actionUrl, partialUrl, init);
maybePushHistory(finalUrl);
});
} finally {
if (indicator !== undefined) {
Expand Down Expand Up @@ -347,9 +366,8 @@ function updateLinks(url: URL) {
async function fetchPartials(
actualUrl: URL,
partialUrl: URL,
shouldNavigate: boolean,
init: RequestInit = {},
) {
): Promise<URL> {
init.redirect = "follow";
partialUrl = new URL(partialUrl);
partialUrl.searchParams.set(PARTIAL_SEARCH_PARAM, "true");
Expand All @@ -361,6 +379,7 @@ async function fetchPartials(
actualUrl = nextUrl;
}
}
actualUrl.searchParams.delete(PARTIAL_SEARCH_PARAM);

try {
await applyPartials(res);
Expand All @@ -369,14 +388,12 @@ async function fetchPartials(
// to a full page navigation instead of silently failing.
if (err instanceof NoPartialsError && res.redirected) {
location.href = actualUrl.href;
return;
return actualUrl;
}
throw err;
}

if (shouldNavigate) {
maybeUpdateHistory(actualUrl);
}
return actualUrl;
}

interface PartialReviveCtx {
Expand Down