0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-02-24 22:46:02 -05:00

fix: self link does not trigger page reload (#8182)

This commit is contained in:
Martin Trapp 2023-08-22 17:17:30 +02:00 committed by GitHub
parent f224c539c8
commit cfc465ddeb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 22 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
View Transitions: self link (`href=""`) does not trigger page reload

View file

@ -274,30 +274,54 @@ const { fallback = 'animate' } = Astro.props as Props;
// that is going to another page within the same origin. Basically it determines // that is going to another page within the same origin. Basically it determines
// same-origin navigation, but omits special key combos for new tabs, etc. // same-origin navigation, but omits special key combos for new tabs, etc.
if ( if (
link && !link ||
link instanceof HTMLAnchorElement && !(link instanceof HTMLAnchorElement) ||
link.href && !link.href ||
(!link.target || link.target === '_self') && (link.target && link.target !== '_self') ||
link.origin === location.origin && link.origin !== location.origin ||
!( ev.button !== 0 || // left clicks only
// Same page means same path and same query params ev.metaKey || // new tab (mac)
(location.pathname === link.pathname && location.search === link.search) ev.ctrlKey || // new tab (windows)
) && ev.altKey || // download
ev.button === 0 && // left clicks only ev.shiftKey || // new window
!ev.metaKey && // new tab (mac) ev.defaultPrevented ||
!ev.ctrlKey && // new tab (windows) !transitionEnabledOnThisPage()
!ev.altKey && // download )
!ev.shiftKey && // No page transitions in these cases,
!ev.defaultPrevented && // Let the browser standard action handle this
transitionEnabledOnThisPage() return;
) {
// We do not need to handle same page links because there are no page transitions
// Same page means same path and same query params (but different hash)
if (location.pathname === link.pathname && location.search === link.search) {
if (link.hash) {
// The browser default action will handle navigations with hash fragments
return;
} else {
// Special case: self link without hash
// If handed to the browser it will reload the page
// But we want to handle it like any other same page navigation
// So we scroll to the top of the page but do not start page transitions
ev.preventDefault();
persistState({ ...history.state, scrollY });
scrollTo({ left: 0, top: 0, behavior: 'instant' });
if (location.hash) {
// last target was different
const newState: State = { index: ++currentHistoryIndex, scrollY: 0 };
history.pushState(newState, '', link.href);
}
return;
}
}
// these are the cases we will handle: same origin, different page
ev.preventDefault(); ev.preventDefault();
navigate('forward', link.href, { index: ++currentHistoryIndex, scrollY: 0 }); navigate('forward', link.href, { index: ++currentHistoryIndex, scrollY: 0 });
const newState: State = { index: currentHistoryIndex, scrollY }; const newState: State = { index: currentHistoryIndex, scrollY };
persistState({ index: currentHistoryIndex - 1, scrollY }); persistState({ index: currentHistoryIndex - 1, scrollY });
history.pushState(newState, '', link.href); history.pushState(newState, '', link.href);
}
}); });
addEventListener('popstate', (ev) => { addEventListener('popstate', (ev) => {
if (!transitionEnabledOnThisPage()) { if (!transitionEnabledOnThisPage()) {
// The current page doesn't haven't View Transitions, // The current page doesn't haven't View Transitions,

View file

@ -7,6 +7,7 @@ import Layout from '../components/Layout.astro';
<a id="click-two" href="/two">go to 2</a> <a id="click-two" href="/two">go to 2</a>
<a id="click-three" href="/three">go to 3</a> <a id="click-three" href="/three">go to 3</a>
<a id="click-longpage" href="/long-page">go to long page</a> <a id="click-longpage" href="/long-page">go to long page</a>
<a id="click-self" href="">go to top</a>
<div id="test">test content</div> <div id="test">test content</div>
</Layout> </Layout>

View file

@ -190,6 +190,22 @@ test.describe('View Transitions', () => {
await expect(p, 'should have content').toHaveText('Page 1'); await expect(p, 'should have content').toHaveText('Page 1');
}); });
test('click self link (w/o hash) does not do navigation', async ({ page, astro }) => {
const loads = [];
page.addListener('load', (p) => {
loads.push(p.title());
});
// Go to page 1
await page.goto(astro.resolveUrl('/one'));
const p = page.locator('#one');
await expect(p, 'should have content').toHaveText('Page 1');
// Clicking href="" stays on page
await page.click('#click-self');
await expect(p, 'should have content').toHaveText('Page 1');
expect(loads.length, 'There should only be 1 page load').toEqual(1);
});
test('Scroll position restored on back button', async ({ page, astro }) => { test('Scroll position restored on back button', async ({ page, astro }) => {
// Go to page 1 // Go to page 1
await page.goto(astro.resolveUrl('/long-page')); await page.goto(astro.resolveUrl('/long-page'));