From: Eduardo San Martin Morote Date: Wed, 1 Jul 2020 13:28:45 +0000 (+0200) Subject: fix(hash): use relative links in hash mode X-Git-Tag: v4.0.0-alpha.14~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=32c9590db89e69c8f7c61905a5eaf19df2054e42;p=thirdparty%2Fvuejs%2Frouter.git fix(hash): use relative links in hash mode Close #342 --- diff --git a/__tests__/router.spec.ts b/__tests__/router.spec.ts index 9bde89d2..8fb84dc0 100644 --- a/__tests__/router.spec.ts +++ b/__tests__/router.spec.ts @@ -1,5 +1,10 @@ import fakePromise from 'faked-promise' -import { createRouter, createMemoryHistory, createWebHistory } from '../src' +import { + createRouter, + createMemoryHistory, + createWebHistory, + createWebHashHistory, +} from '../src' import { NavigationFailureType } from '../src/errors' import { createDom, components, tick, nextNavigation } from './utils' import { @@ -178,6 +183,27 @@ describe('Router', () => { expect(router.currentRoute.value).not.toBe(START_LOCATION_NORMALIZED) }) + it('resolves hash history as a relative hash link', async () => { + let history = createWebHashHistory() + let { router } = await newRouter({ history }) + expect(router.resolve('/foo?bar=baz#hey')).toMatchObject({ + fullPath: '/foo?bar=baz#hey', + href: '#/foo?bar=baz#hey', + }) + history = createWebHashHistory('/with/base/') + ;({ router } = await newRouter({ history })) + expect(router.resolve('/foo?bar=baz#hey')).toMatchObject({ + fullPath: '/foo?bar=baz#hey', + href: '#/foo?bar=baz#hey', + }) + history = createWebHashHistory('/with/#/base/') + ;({ router } = await newRouter({ history })) + expect(router.resolve('/foo?bar=baz#hey')).toMatchObject({ + fullPath: '/foo?bar=baz#hey', + href: '#/base/foo?bar=baz#hey', + }) + }) + it('can await router.go', async () => { const { router } = await newRouter() await router.push('/foo') diff --git a/src/history/common.ts b/src/history/common.ts index aaa72afc..5fe96ef3 100644 --- a/src/history/common.ts +++ b/src/history/common.ts @@ -128,6 +128,17 @@ export interface RouterHistory { * @returns a callback to remove the listener */ listen(callback: NavigationCallback): () => void + + /** + * Generates the corresponding href to be used in an anchor tag. + * + * @param location + */ + createHref(location: HistoryLocationNormalized): string + + /** + * Clears any event listener attached by the history implementation. + */ destroy(): void } @@ -170,3 +181,12 @@ export function normalizeBase(base?: string): string { // to build an href return removeTrailingSlash(base) } + +// remove any character before the hash +const BEFORE_HASH_RE = /^[^#]+#/ +export function createHref( + base: string, + location: HistoryLocationNormalized +): string { + return base.replace(BEFORE_HASH_RE, '#') + location.fullPath +} diff --git a/src/history/html5.ts b/src/history/html5.ts index 8a53c064..1a2081b0 100644 --- a/src/history/html5.ts +++ b/src/history/html5.ts @@ -9,6 +9,7 @@ import { RawHistoryLocation, ValueContainer, normalizeBase, + createHref, } from './common' import { computeScrollPosition, @@ -288,6 +289,7 @@ export function createWebHistory(base?: string): RouterHistory { location: ('' as unknown) as HistoryLocationNormalized, base, go, + createHref: createHref.bind(null, base), }, historyNavigation, diff --git a/src/history/memory.ts b/src/history/memory.ts index f24c4e44..86a1a3f5 100644 --- a/src/history/memory.ts +++ b/src/history/memory.ts @@ -8,6 +8,7 @@ import { NavigationType, NavigationDirection, NavigationInformation, + createHref, } from './common' // TODO: verify base is working for SSR @@ -55,6 +56,7 @@ export function createMemoryHistory(base: string = ''): RouterHistory { location: START, state: {}, base, + createHref: createHref.bind(null, base), replace(to) { const toNormalized = normalizeHistoryLocation(to) diff --git a/src/router.ts b/src/router.ts index 0820e6ea..fc0da57b 100644 --- a/src/router.ts +++ b/src/router.ts @@ -253,8 +253,8 @@ export function createRouter(options: RouterOptions): Router { currentLocation ) + let href = routerHistory.createHref(locationNormalized) if (__DEV__) { - let href = routerHistory.base + locationNormalized.fullPath if (href.startsWith('//')) warn( `Location "${rawLocation}" resolved to "${href}". A resolved location cannot start with multiple slashes.` @@ -268,7 +268,7 @@ export function createRouter(options: RouterOptions): Router { return assign(locationNormalized, matchedRoute, { params: decodeParams(matchedRoute.params), redirectedFrom: undefined, - href: routerHistory.base + locationNormalized.fullPath, + href, }) } @@ -300,7 +300,7 @@ export function createRouter(options: RouterOptions): Router { let matchedRoute = matcher.resolve(matcherLocation, currentLocation) const hash = encodeHash(rawLocation.hash || '') - if (__DEV__ && hash && hash[0] !== '#') { + if (__DEV__ && hash && !hash.startsWith('#')) { warn( `A \`hash\` should always start with the character "#". Replace "${hash}" with "#${hash}".` ) @@ -320,8 +320,8 @@ export function createRouter(options: RouterOptions): Router { }) ) + let href = routerHistory.createHref({ fullPath }) if (__DEV__) { - let href = routerHistory.base + fullPath if (href.startsWith('//')) warn( `Location "${rawLocation}" resolved to "${href}". A resolved location cannot start with multiple slashes.` @@ -354,7 +354,7 @@ export function createRouter(options: RouterOptions): Router { matchedRoute, { redirectedFrom: undefined, - href: routerHistory.base + fullPath, + href, } ) }