From: Eduardo San Martin Morote Date: Mon, 13 Apr 2020 14:50:12 +0000 (+0200) Subject: fix(history): allow hash history with no origin X-Git-Tag: v4.0.0-alpha.6~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=760d21672051b6338d40f2cdfdac80dc16209e13;p=thirdparty%2Fvuejs%2Frouter.git fix(history): allow hash history with no origin Close #163 --- diff --git a/__tests__/history/hash.spec.ts b/__tests__/history/hash.spec.ts new file mode 100644 index 00000000..07eb78ed --- /dev/null +++ b/__tests__/history/hash.spec.ts @@ -0,0 +1,81 @@ +import { JSDOM } from 'jsdom' +import createWebHashHistory from '../../src/history/hash' +import createWebHistory from '../../src/history/html5' +import { createDom } from '../utils' + +jest.mock('../../src/history/html5') + +describe('History Hash', () => { + let dom: JSDOM + beforeAll(() => { + dom = createDom() + }) + + beforeEach(() => { + ;(createWebHistory as jest.Mock).mockClear() + }) + + afterAll(() => { + dom.window.close() + }) + + afterEach(() => { + // ensure no base element is left after a test as only the first is + // respected + for (let element of Array.from(document.getElementsByTagName('base'))) + element.remove() + }) + + describe('url', () => { + beforeEach(() => { + dom.reconfigure({ url: 'https://example.com' }) + }) + + it('should use a correct', () => { + createWebHashHistory() + expect(createWebHistory).toHaveBeenCalledWith('/#') + }) + + it('should be able to provide a base', () => { + createWebHashHistory('/folder/') + expect(createWebHistory).toHaveBeenCalledWith('/folder/#') + }) + + it('should be able to provide a base with no trailing slash', () => { + createWebHashHistory('/folder') + expect(createWebHistory).toHaveBeenCalledWith('/folder/#') + }) + + it('should read the base tag', () => { + const baseEl = document.createElement('base') + baseEl.href = '/foo/' + document.head.appendChild(baseEl) + createWebHashHistory() + expect(createWebHistory).toHaveBeenCalledWith('/foo/#') + }) + + it('should use the base option over the base tag', () => { + const baseEl = document.createElement('base') + baseEl.href = '/foo/' + document.head.appendChild(baseEl) + createWebHashHistory('/bar/') + expect(createWebHistory).toHaveBeenCalledWith('/bar/#') + }) + }) + + describe('file://', () => { + beforeEach(() => { + dom.reconfigure({ url: 'file:///usr/some-file.html' }) + }) + + it('should use a correct base', () => { + createWebHashHistory() + // both, a trailing / and none work + expect(createWebHistory).toHaveBeenCalledWith( + expect.stringMatching(/^#\/?$/) + ) + }) + + it.todo('warns if we provide a base with file://') + }) +}) diff --git a/__tests__/history/html5.spec.ts b/__tests__/history/html5.spec.ts index e0b48448..1d6f0e41 100644 --- a/__tests__/history/html5.spec.ts +++ b/__tests__/history/html5.spec.ts @@ -68,4 +68,14 @@ describe('History HTMl5', () => { expect(createWebHistory('/foo/').base).toBe('/foo') expect(createWebHistory('/foo').base).toBe('/foo') }) + + it('handles a single hash base', () => { + expect(createWebHistory('#').base).toBe('#') + expect(createWebHistory('#/').base).toBe('#') + }) + + it('handles a non-empty hash base', () => { + expect(createWebHistory('#/bar').base).toBe('#/bar') + expect(createWebHistory('#/bar/').base).toBe('#/bar') + }) }) diff --git a/src/history/common.ts b/src/history/common.ts index 314f006f..3fbdd0a1 100644 --- a/src/history/common.ts +++ b/src/history/common.ts @@ -145,3 +145,32 @@ export function normalizeHistoryLocation( fullPath: (location as HistoryLocation).fullPath || (location as string), } } + +/** + * Normalizes a base by removing any trailing slash and reading the base tag if + * present. + * + * @param base base to normalize + */ +export function normalizeBase(base?: string): string { + if (!base) { + if (__BROWSER__) { + // respect tag + const baseEl = document.querySelector('base') + base = (baseEl && baseEl.getAttribute('href')) || '/' + // strip full URL origin + base = base.replace(/^\w+:\/\/[^\/]+/, '') + } else { + base = '/' + } + } + + // ensure leading slash when it was removed by the regex above avoid leading + // slash with hash because the file could be read from the disk like file:// + // and the leading slash would cause problems + if (base.charAt(0) !== '/' && base.charAt(0) !== '#') base = '/' + base + + // remove the trailing slash so all other method can just do `base + fullPath` + // to build an href + return base.replace(/\/$/, '') +} diff --git a/src/history/hash.ts b/src/history/hash.ts index baff0341..6b687e93 100644 --- a/src/history/hash.ts +++ b/src/history/hash.ts @@ -1,7 +1,7 @@ -import { RouterHistory } from './common' +import { RouterHistory, normalizeBase } from './common' import createWebHistory from './html5' -export default function createWebHashHistory(base: string = ''): RouterHistory { +export default function createWebHashHistory(base?: string): RouterHistory { // Make sure this implementation is fine in terms of encoding, specially for IE11 - return createWebHistory(base + '/#') + return createWebHistory(location.host ? normalizeBase(base) + '/#' : '#') } diff --git a/src/history/html5.ts b/src/history/html5.ts index 8ac97dd4..f5cb3220 100644 --- a/src/history/html5.ts +++ b/src/history/html5.ts @@ -8,6 +8,7 @@ import { HistoryState, RawHistoryLocation, ValueContainer, + normalizeBase, } from './common' import { computeScrollPosition, ScrollToPosition } from '../utils/scroll' import { warn } from 'vue' @@ -262,33 +263,6 @@ function useHistoryStateNavigation(base: string) { } } -/** - * Normalizes a base by removing any trailing slash and reading the base tag if - * present. - * - * @param base base to normalize - */ -function normalizeBase(base?: string): string { - if (!base) { - if (__BROWSER__) { - // respect tag - const baseEl = document.querySelector('base') - base = (baseEl && baseEl.getAttribute('href')) || '/' - // strip full URL origin - base = base.replace(/^\w+:\/\/[^\/]+/, '') - } else { - base = '/' - } - } - - // ensure leading slash when it was removed by the regex above - if (base.charAt(0) !== '/') base = '/' + base - - // remove the trailing slash so all other method can just do `base + fullPath` - // to build an href - return base.replace(/\/$/, '') -} - export default function createWebHistory(base?: string): RouterHistory { base = normalizeBase(base)