ValueContainer,
} from './common'
import { computeScrollPosition, ScrollToPosition } from '../utils/scroll'
-
-const cs = console
+import { warn } from 'vue'
type PopStateListener = (this: Window, ev: PopStateEvent) => any
function useHistoryListeners(
base: string,
historyState: ValueContainer<StateEntry>,
- location: ValueContainer<HistoryLocationNormalized>
+ location: ValueContainer<HistoryLocationNormalized>,
+ replace: RouterHistory['replace']
) {
let listeners: NavigationCallback[] = []
let teardowns: Array<() => void> = []
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
}
? 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
}
function pauseListeners() {
- cs.info(`⏸ for ${location.value.fullPath}`)
pauseState = location.value
}
}
}
+/**
+ * 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),
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(
historyState.value.forward,
true
),
+ ...history.state,
...data,
}
if (historyState) state.position = historyState.value.position
// 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(),
}
const historyListeners = useHistoryListeners(
base,
historyNavigation.state,
- historyNavigation.location
+ historyNavigation.location,
+ historyNavigation.replace
)
function back(triggerListeners = true) {
go(-1, triggerListeners)