]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
fix(hash): use relative links in hash mode
authorEduardo San Martin Morote <posva13@gmail.com>
Wed, 1 Jul 2020 13:28:45 +0000 (15:28 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Wed, 1 Jul 2020 13:28:45 +0000 (15:28 +0200)
Close #342

__tests__/router.spec.ts
src/history/common.ts
src/history/html5.ts
src/history/memory.ts
src/router.ts

index 9bde89d2cf2819b289ace9ad1518308120e5fb7b..8fb84dc0ebff1ee6bf51a6a345701d7b54059d33 100644 (file)
@@ -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')
index aaa72afc56a48a182ac025cd429a52dddae5cfe4..5fe96ef3a5af59317dbbf31cb5eac348879efaad 100644 (file)
@@ -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
+}
index 8a53c064b09d7103867f74e67b542c5aba8d0dc5..1a2081b0117f7f561b613570f1b4e4429fb51215 100644 (file)
@@ -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,
index f24c4e446cd419aeda09c1d1378e764574837b45..86a1a3f550d23093fe04ab316c11b9a1194ec2ef 100644 (file)
@@ -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)
index 0820e6ea34ca2d4228909879d28cb92dbc3972e6..fc0da57b916298219d725d1883606d3fca6be84f 100644 (file)
@@ -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,
       }
     )
   }