From 4dd107d18ca7fbe60dfb31f07074ae6eb37a3949 Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Sun, 19 Sep 2021 11:46:48 +0300 Subject: [PATCH] fix(docs-infra): correctly handle in-page anchor links (#43460) Previously, anchor links that were supposed to point to fragments inside the current page (e.g. `href="#something"`) would end up navigating to the homepage (`/`). This was due to them being resolved relative to the base URL, which is set to `/` (via ``). See also https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base#in-page_anchors. This commit fixes this issue by handling such links specially in `LocationService#handleAnchorClick()` and prepending the current path to the URL. This will also be useful for implementing a "skip to content" link as described in #42936. PR Close #43460 --- aio/src/app/shared/location.service.spec.ts | 8 ++++++++ aio/src/app/shared/location.service.ts | 9 +++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/aio/src/app/shared/location.service.spec.ts b/aio/src/app/shared/location.service.spec.ts index a42844bb85e..1fff1357b27 100644 --- a/aio/src/app/shared/location.service.spec.ts +++ b/aio/src/app/shared/location.service.spec.ts @@ -436,6 +436,14 @@ describe('LocationService', () => { expect(result).toBe(false); }); + it('local fragment-only URL', () => { + location.internalPath = '/some/path'; + anchor.href = '#some-fragment'; + const result = service.handleAnchorClick(anchor); + expect(service.go).toHaveBeenCalledWith('/some/path#some-fragment'); + expect(result).toBe(false); + }); + it('local url with query params', () => { anchor.href = 'some/local/url?query=xxx&other=yyy'; const result = service.handleAnchorClick(anchor); diff --git a/aio/src/app/shared/location.service.ts b/aio/src/app/shared/location.service.ts index 41d7ff6662c..0d314929362 100644 --- a/aio/src/app/shared/location.service.ts +++ b/aio/src/app/shared/location.service.ts @@ -145,11 +145,16 @@ export class LocationService { } const { pathname, search, hash } = anchor; - const relativeUrl = pathname + search + hash; + // Fix in-page anchors that are supposed to point to fragments inside the page, but are resolved + // relative the the root path (`/`), due to the base URL being set to `/`. + // (See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base#in-page_anchors.) + const isInPageAnchor = anchor.getAttribute('href')?.startsWith('#') ?? false; + const correctPathname = isInPageAnchor ? this.location.path() : pathname; + const relativeUrl = correctPathname + search + hash; this.urlParser.href = relativeUrl; // don't navigate if external link or has extension - if ( anchor.href !== this.urlParser.href || + if ( (!isInPageAnchor && anchor.href !== this.urlParser.href) || !/\/[^/.]*$/.test(pathname) ) { return true; }