) {
const router = {
history: createMemoryHistory(),
+ createHref(to: RouteLocationNormalized): string {
+ return this.history.base + to.fullPath
+ },
resolve: jest.fn(),
push: jest.fn(),
}
import fakePromise from 'faked-promise'
-import { Router, createMemoryHistory } from '../src'
+import { Router, createMemoryHistory, createHistory } from '../src'
import { NavigationCancelled } from '../src/errors'
import { createDom, components, tick } from './utils'
import { RouteRecord, RouteLocation } from '../src/types'
})
})
+ it('allows base option in abstract history', async () => {
+ const history = createMemoryHistory('/app/')
+ const router = new Router({ history, routes })
+ expect(router.currentRoute).toEqual({
+ name: undefined,
+ fullPath: '/',
+ hash: '',
+ params: {},
+ path: '/',
+ query: {},
+ meta: {},
+ })
+ await router.replace('/foo')
+ expect(router.currentRoute).toMatchObject({
+ name: 'Foo',
+ fullPath: '/foo',
+ hash: '',
+ params: {},
+ path: '/foo',
+ query: {},
+ })
+ })
+
+ it('allows base option with html5 history', async () => {
+ const history = createHistory('/app/')
+ const router = new Router({ history, routes })
+ expect(router.currentRoute).toEqual({
+ name: undefined,
+ fullPath: '/',
+ hash: '',
+ params: {},
+ path: '/',
+ query: {},
+ meta: {},
+ })
+ await router.replace('/foo')
+ expect(router.currentRoute).toMatchObject({
+ name: 'Foo',
+ fullPath: '/foo',
+ hash: '',
+ params: {},
+ path: '/foo',
+ query: {},
+ })
+ })
+
// it('redirects with route record redirect')
})
const to = this.to as RouteLocation
const route = router.resolve(to)
+ const href = router.createHref(route)
// TODO: active classes
// TODO: handle replace prop
const data: any = {
on,
- attrs: { href: route.fullPath },
+ attrs: { href },
}
// @ts-ignore
hash: location.hash || '',
}
}
+
+/**
+ * Strips off the base from the beginning of a location.pathname
+ * @param pathname location.pathname
+ * @param base base to strip off
+ */
+export function stripBase(pathname: string, base: string): string {
+ return (
+ (base && pathname.indexOf(base) === 0 && pathname.replace(base, '')) ||
+ pathname
+ )
+}
import { RouterHistory } from './common'
import createHistory from './html5'
-export default function createHashHistory(): RouterHistory {
+export default function createHashHistory(base: string = ''): RouterHistory {
// Make sure this implementation is fine in terms of encoding, specially for IE11
- // @ts-ignore: TODO: implement it in history first
- return createHistory('/#/')
+ return createHistory('/#' + base)
}
NavigationCallback,
parseQuery,
normalizeLocation,
+ stripBase,
NavigationType,
NavigationDirection,
HistoryLocationNormalized,
HistoryState,
+ parseURL,
} from './common'
import { computeScrollPosition, ScrollToPosition } from '../utils/scroll'
// import consola from 'consola'
scroll: ScrollToPosition | null
}
-export default function createHistory(): RouterHistory {
+export default function createHistory(base: string = ''): RouterHistory {
const { history } = window
/**
function createCurrentLocation(
location: Location
): HistoryLocationNormalized {
+ const { pathname, search, hash } = location
+ // allows hash based url
+ if (base.indexOf('#') > -1) {
+ // prepend the starting slash to hash so the url starts with /#
+ return parseURL(stripBase('/' + hash, base))
+ }
+ const path = stripBase(pathname, base)
return {
- fullPath: location.pathname + location.search + location.hash,
- path: location.pathname,
- query: parseQuery(location.search),
- hash: location.hash,
+ fullPath: path + search + hash,
+ path,
+ query: parseQuery(search),
+ hash: hash,
}
}
function changeLocation(
state: StateEntry,
title: string,
- url: string,
+ fullPath: string,
replace: boolean
): void {
+ const url = base + fullPath
try {
// BROWSER QUIRK
// NOTE: Safari throws a SecurityError when calling this function 100 times in 30 seconds
const routerHistory: RouterHistory = {
// it's overriden right after
location,
- // TODO: implement it
- base: '/',
+ base,
replace(to) {
const normalized = normalizeLocation(to)
// const cs = console
// const cs = consola.withTag('abstract')
-export default function createMemoryHistory(): RouterHistory {
+/**
+ * Creates a in-memory based history. The main purporse of this history is to handle SSR. It starts in a special location that is nowhere.
+ * It's up to the user to replace that location with the starter location.
+ * @param base Base applied to all urls, defaults to '/'
+ * @returns a history object that can be passed to the router constructor
+ */
+export default function createMemoryHistory(base: string = ''): RouterHistory {
let listeners: NavigationCallback[] = []
// TODO: make sure this is right as the first location is nowhere so maybe this should be empty instead
let queue: HistoryLocationNormalized[] = [START]
const routerHistory: RouterHistory = {
// rewritten by Object.defineProperty
location: START,
- // TODO: implement it
- base: '/',
+ // TODO: acutally use it
+ base,
replace(to) {
const toNormalized = normalizeLocation(to)
import { PluginFunction, VueConstructor } from 'vue'
import createHistory from './history/html5'
import createMemoryHistory from './history/memory'
+import createHashHistory from './history/hash'
import View from './components/View'
import Link from './components/Link'
strats.created
}
-export { Router, createHistory, createMemoryHistory, plugin }
+export { Router, createHistory, createMemoryHistory, createHashHistory, plugin }
// TODO: refactor somewhere else
// const inBrowser = typeof window !== 'undefined'
resolve(
to: RouteLocation,
currentLocation?: RouteLocationNormalized /*, append?: boolean */
- ) {
+ ): RouteLocationNormalized {
if (typeof to === 'string')
return this.resolveLocation(
// TODO: refactor and remove import
})
}
+ createHref(to: RouteLocationNormalized): string {
+ return this.history.base + to.fullPath
+ }
+
private resolveLocation(
location: MatcherLocation & Required<RouteQueryAndHash>,
currentLocation?: RouteLocationNormalized,