Skip to content

Commit

Permalink
fix(history): use current history state when replacing
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Mar 24, 2020
1 parent 1583d48 commit 5d80209
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 44 deletions.
5 changes: 4 additions & 1 deletion src/components/Link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { RouteLocation, RouteLocationNormalized, Immutable } from '../types'
import { isSameLocationObject, isSameRouteRecord } from '../utils'
import { routerKey } from '../utils/injectionSymbols'
import { RouteRecordNormalized } from '../matcher/types'

type VueUseOptions<T> = {
[k in keyof T]: Ref<T[k]> | T[k]
Expand All @@ -33,7 +34,9 @@ export function useLink(props: UseLinkOptions) {

const activeRecordIndex = computed<number>(() => {
// TODO: handle children with empty path: they should relate to their parent
const currentMatched = route.value.matched[route.value.matched.length - 1]
const currentMatched: RouteRecordNormalized | undefined =
route.value.matched[route.value.matched.length - 1]
if (!currentMatched) return -1
return currentRoute.value.matched.findIndex(
isSameRouteRecord.bind(null, currentMatched)
)
Expand Down
4 changes: 2 additions & 2 deletions src/history/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ export interface RouterHistory {
readonly location: HistoryLocationNormalized
// readonly location: ValueContainer<HistoryLocationNormalized>

push(to: RawHistoryLocation): void
replace(to: RawHistoryLocation): void
push(to: RawHistoryLocation, data?: HistoryState): void
replace(to: RawHistoryLocation, data?: HistoryState): void

back(triggerListeners?: boolean): void
forward(triggerListeners?: boolean): void
Expand Down
76 changes: 35 additions & 41 deletions src/history/html5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import {
ValueContainer,
} from './common'
import { computeScrollPosition, ScrollToPosition } from '../utils/scroll'

const cs = console
import { warn } from 'vue'

type PopStateListener = (this: Window, ev: PopStateEvent) => any

Expand Down Expand Up @@ -49,7 +48,8 @@ function createCurrentLocation(
function useHistoryListeners(
base: string,
historyState: ValueContainer<StateEntry>,
location: ValueContainer<HistoryLocationNormalized>
location: ValueContainer<HistoryLocationNormalized>,
replace: RouterHistory['replace']
) {
let listeners: NavigationCallback[] = []
let teardowns: Array<() => void> = []
Expand All @@ -60,22 +60,19 @@ function useHistoryListeners(
const popStateHandler: PopStateListener = ({
state,
}: {
state: StateEntry
state: StateEntry | null
}) => {
// TODO: state can be null when using links with a `hash` in hash mode
// maybe we should trigger a plain navigation in that case
cs.info('popstate fired', state)
cs.info('currentState', historyState)
const to = createCurrentLocation(base, window.location)

if (!state) return replace(to.fullPath)

const from: HistoryLocationNormalized = location.value
const fromState: StateEntry = historyState.value
const to = createCurrentLocation(base, window.location)
location.value = to
historyState.value = state

// ignore the popstate and reset the pauseState
if (pauseState && pauseState.fullPath === from.fullPath) {
cs.info('❌ Ignored because paused for', pauseState.fullPath)
// reset pauseState
pauseState = null
return
}
Expand All @@ -84,7 +81,7 @@ function useHistoryListeners(
? state.position - fromState.position
: ''
const distance = deltaFromCurrent || 0
console.log({ deltaFromCurrent })
// console.log({ deltaFromCurrent })
// Here we could also revert the navigation by calling history.go(-distance)
// this listener will have to be adapted to not trigger again and to wait for the url
// to be updated before triggering the listeners. Some kind of validation function would also
Expand All @@ -104,7 +101,6 @@ function useHistoryListeners(
}

function pauseListeners() {
cs.info(`⏸ for ${location.value.fullPath}`)
pauseState = location.value
}

Expand Down Expand Up @@ -151,29 +147,29 @@ function useHistoryListeners(
}
}

/**
* Creates a state object
*/
function buildState(
back: HistoryLocationNormalized | null,
current: HistoryLocationNormalized,
forward: HistoryLocationNormalized | null,
replaced: boolean = false,
computeScroll: boolean = false
): StateEntry {
return {
back,
current,
forward,
replaced,
position: window.history.length,
scroll: computeScroll ? computeScrollPosition() : null,
}
}

function useHistoryStateNavigation(base: string) {
const { history } = window

/**
* Creates a state object
*/
function buildState(
back: HistoryLocationNormalized | null,
current: HistoryLocationNormalized,
forward: HistoryLocationNormalized | null,
replaced: boolean = false,
computeScroll: boolean = false
): StateEntry {
return {
back,
current,
forward,
replaced,
position: window.history.length,
scroll: computeScroll ? computeScrollPosition() : null,
}
}

// private variables
let location: ValueContainer<HistoryLocationNormalized> = {
value: createCurrentLocation(base, window.location),
Expand Down Expand Up @@ -205,21 +201,17 @@ function useHistoryStateNavigation(base: string) {
try {
// BROWSER QUIRK
// NOTE: Safari throws a SecurityError when calling this function 100 times in 30 seconds
const newState: StateEntry = replace
? { ...historyState.value, ...state }
: state
history[replace ? 'replaceState' : 'pushState'](newState, '', url)
history[replace ? 'replaceState' : 'pushState'](state, '', url)
historyState.value = state
} catch (err) {
cs.log('[vue-router]: Error with push/replace State', err)
warn('[vue-router]: Error with push/replace State', err)
// Force the navigation, this also resets the call count
window.location[replace ? 'replace' : 'assign'](url)
}
}

function replace(to: RawHistoryLocation, data?: HistoryState) {
const normalized = normalizeHistoryLocation(to)
// cs.info('replace', location, normalized)

const state: StateEntry = {
...buildState(
Expand All @@ -229,6 +221,7 @@ function useHistoryStateNavigation(base: string) {
historyState.value.forward,
true
),
...history.state,
...data,
}
if (historyState) state.position = historyState.value.position
Expand All @@ -244,7 +237,7 @@ function useHistoryStateNavigation(base: string) {
// as well as saving the current position
// TODO: the scroll position computation should be customizable
const currentState: StateEntry = {
...historyState.value,
...history.state,
forward: normalized,
scroll: computeScrollPosition(),
}
Expand Down Expand Up @@ -274,7 +267,8 @@ export default function createWebHistory(base: string = ''): RouterHistory {
const historyListeners = useHistoryListeners(
base,
historyNavigation.state,
historyNavigation.location
historyNavigation.location,
historyNavigation.replace
)
function back(triggerListeners = true) {
go(-1, triggerListeners)
Expand Down

0 comments on commit 5d80209

Please sign in to comment.