diff --git a/templates/src/client/app.ts b/templates/src/client/app.ts index a9666e71f..5603dca9f 100644 --- a/templates/src/client/app.ts +++ b/templates/src/client/app.ts @@ -106,18 +106,17 @@ export function scroll_state() { }; } -export function navigate(target: Target, id: number, noscroll = false): Promise { +export function navigate(target: Target, id: number, scroll_to?: ScrollPosition | string): Promise { + let scroll: ScrollPosition | string; if (id) { // popstate or initial navigation cid = id; + scroll = scroll_to ? scroll_to : scroll_history[id]; } else { - const current_scroll = scroll_state(); - // clicked on a link. preserve scroll state - scroll_history[cid] = current_scroll; - + scroll_history[cid] = scroll_state(); id = cid = ++uid; - scroll_history[cid] = noscroll ? current_scroll : { x: 0, y: 0 }; + scroll = scroll_to ? scroll_to : { x: 0, y: 0 }; } cid = id; @@ -137,13 +136,12 @@ export function navigate(target: Target, id: number, noscroll = false): Promise< if (redirect) { return goto(redirect.location, { replaceState: true }); } - - render(data, nullable_depth, scroll_history[id], token); + render(data, nullable_depth, scroll, token); if (document.activeElement) document.activeElement.blur(); }); } -function render(data: any, nullable_depth: number, scroll: ScrollPosition, token: {}) { +function render(data: any, nullable_depth: number, scroll: ScrollPosition | string, token: {}) { if (current_token !== token) return; if (root_component) { @@ -183,7 +181,18 @@ function render(data: any, nullable_depth: number, scroll: ScrollPosition, token } if (scroll) { - scrollTo(scroll.x, scroll.y); + let scrollPos: ScrollPosition; + if (typeof scroll === 'string') { + // scroll is an element id (from a hash), we need to compute y. + const deep_linked = document.getElementById(scroll); + scrollPos = deep_linked ? + { x: 0, y: deep_linked.getBoundingClientRect().top } : + scroll_state(); + } else { + scrollPos = scroll; + } + scroll_history[cid] = scrollPos; + scrollTo(scrollPos.x, scrollPos.y); } Object.assign(root_props, data); diff --git a/templates/src/client/start/index.ts b/templates/src/client/start/index.ts index 17979a3b4..7ab212836 100644 --- a/templates/src/client/start/index.ts +++ b/templates/src/client/start/index.ts @@ -13,7 +13,7 @@ import { set_cid } from '../app'; import prefetch from '../prefetch/index'; -import { Store } from '../types'; +import { Store, ScrollPosition } from '../types'; export default function start(opts: { target: Node, @@ -35,17 +35,13 @@ export default function start(opts: { return Promise.resolve().then(() => { const { hash, href } = location; - - const deep_linked = hash && document.getElementById(hash.slice(1)); - scroll_history[uid] = deep_linked ? - { x: 0, y: deep_linked.getBoundingClientRect().top } : - scroll_state(); + const scroll_to = hash ? hash.slice(1) : scroll_state(); history.replaceState({ id: uid }, '', href); if (!initial_data.error) { const target = select_route(new URL(location.href)); - if (target) return navigate(target, uid); + if (target) return navigate(target, uid, scroll_to); } }); } @@ -104,7 +100,16 @@ function handle_click(event: MouseEvent) { const target = select_route(url); if (target) { const noscroll = a.hasAttribute('sapper-noscroll'); - navigate(target, null, noscroll); + let scroll_to: ScrollPosition | string; + if (noscroll) { + scroll_to = scroll_state(); + } else if (url.hash) { + scroll_to = url.hash.slice(1); + } else { + scroll_to = { x: 0, y: 0 }; + } + + navigate(target, null, scroll_to); event.preventDefault(); history.pushState({ id: cid }, '', url.href); } diff --git a/test/apps/scroll/src/routes/another-tall-page.html b/test/apps/scroll/src/routes/another-tall-page.html index d3e148ce5..d66879b36 100644 --- a/test/apps/scroll/src/routes/another-tall-page.html +++ b/test/apps/scroll/src/routes/another-tall-page.html @@ -1 +1,2 @@ -
\ No newline at end of file +
+

element

\ No newline at end of file diff --git a/test/apps/scroll/src/routes/tall-page.html b/test/apps/scroll/src/routes/tall-page.html index 7e42ff94e..361e9000c 100644 --- a/test/apps/scroll/src/routes/tall-page.html +++ b/test/apps/scroll/src/routes/tall-page.html @@ -3,4 +3,21 @@ \ No newline at end of file + {#if barLink} + link + {/if} + + + \ No newline at end of file diff --git a/test/apps/scroll/test.ts b/test/apps/scroll/test.ts index 0c0db39b0..e6874052f 100644 --- a/test/apps/scroll/test.ts +++ b/test/apps/scroll/test.ts @@ -59,4 +59,15 @@ describe('scroll', function() { assert.ok(scrollY > 0); }); + + it('scrolls into a deeplink on a new page', async () => { + await page.goto(`${base}/tall-page#foo`); + await start(); + await prefetchRoutes(); + + await page.click('[href="another-tall-page#bar"]'); + await wait(50); + const scrollY = await page.evaluate(() => window.scrollY); + assert.ok(scrollY > 0); + }); }); \ No newline at end of file