import { ListenerRemover } from '../types'
-import { encodeQueryProperty, encodeHash } from '../utils/encoding'
+// import { encodeQueryProperty, encodeHash } from '../utils/encoding'
-export type HistoryQuery = Record<string, string | string[]>
-// TODO: is it reall worth allowing null to form queries like ?q&b&c
-// When parsing using URLSearchParams, `q&c=` yield an empty string for q and c
-// I think it's okay to allow this by default and allow extending it
-// a more permissive history query
// TODO: allow numbers
-export type RawHistoryQuery = Record<string, string | string[] | null>
+export type HistoryQuery = Record<string, string | string[]>
interface HistoryLocation {
// pathname section
path: string
// search string parsed
- query?: RawHistoryQuery
+ query?: HistoryQuery
// hash with the #
hash?: string
}
)
// TODO: can we remove the normalize call?
- query = normalizeQuery(parseQuery(searchString))
+ query = parseQuery(searchString)
}
if (hashPos > -1) {
}
}
-// TODO: the encoding would be handled at a router level instead where encoding functions can be customized
-// that way the matcher can encode/decode params properly
-
-// function safeDecodeUriComponent(value: string): string {
-// try {
-// value = decodeURIComponent(value)
-// } catch (err) {
-// // TODO: handling only URIError?
-// console.warn(
-// `[vue-router] error decoding query "${value}". Keeping the original value.`
-// )
-// }
-
-// return value
-// }
-
-// function safeEncodeUriComponent(value: string): string {
-// try {
-// value = encodeURIComponent(value)
-// } catch (err) {
-// // TODO: handling only URIError?
-// console.warn(
-// `[vue-router] error encoding query "${value}". Keeping the original value.`
-// )
-// }
+/**
+ * Stringify a URL object
+ * @param location
+ */
+export function stringifyURL(location: HistoryLocation): string {
+ let url = location.path
+ let query = location.query ? stringifyQuery(location.query) : ''
-// return value
-// }
+ return url + (query && '?' + query) + (location.hash || '')
+}
/**
* Transform a queryString into a query object. Accept both, a version with the leading `?` and without
}
return query
}
-
-/**
- * Stringify a URL object
- * @param location
- */
-export function stringifyURL(location: HistoryLocation): string {
- let url = location.path
- let query = location.query ? stringifyQuery(location.query) : ''
-
- return url + (query && '?' + query) + encodeHash(location.hash || '')
-}
-
/**
* Stringify an object query. Works like URLSearchParams. Doesn't prepend a `?`
* @param query
*/
-export function stringifyQuery(query: RawHistoryQuery): string {
+export function stringifyQuery(query: HistoryQuery): string {
let search = ''
for (const key in query) {
if (search.length > 1) search += '&'
search += key
continue
}
- const encodedKey = encodeQueryProperty(key)
+ // const encodedKey = encodeQueryProperty(key)
let values: string[] = Array.isArray(value) ? value : [value]
- const encodedValues = values.map(encodeQueryProperty)
+ // const encodedValues = values.map(encodeQueryProperty)
- search += `${encodedKey}=${values[0]}`
+ search += `${key}=${values[0]}`
for (let i = 1; i < values.length; i++) {
- search += `&${encodedKey}=${encodedValues[i]}`
+ search += `&${key}=${values[i]}`
}
}
return search
}
-export function normalizeQuery(query: RawHistoryQuery): HistoryQuery {
- // TODO: properly test
- const normalizedQuery: HistoryQuery = {}
- for (const key in query) {
- const value = query[key]
- if (value === null) normalizedQuery[key] = ''
- else normalizedQuery[key] = value
- }
- return normalizedQuery
-}
-
-// use regular decodeURI
-// Use a renamed export instead of global.decodeURI
-// to support node and browser at the same time
-const originalDecodeURI = decodeURI
-export { originalDecodeURI as decodeURI }
-
/**
* Normalize a History location object or string into a HistoryLocationNoramlized
* @param location
return {
fullPath: stringifyURL(location),
path: location.path,
- query: location.query ? normalizeQuery(location.query) : {},
+ query: location.query || {},
hash: location.hash || '',
}
}
import {
RouterHistory,
NavigationCallback,
- parseQuery,
normalizeLocation,
stripBase,
NavigationType,
NavigationDirection,
HistoryLocationNormalized,
HistoryState,
- parseURL,
RawHistoryLocation,
ValueContainer,
} from './common'
/**
* Creates a noramlized history location from a window.location object
- * TODO: encoding is not handled like this
* @param location
*/
function createCurrentLocation(
// allows hash based url
if (base.indexOf('#') > -1) {
// prepend the starting slash to hash so the url starts with /#
- return parseURL(stripBase('/' + hash, base))
+ return normalizeLocation(stripBase('/' + hash, base))
}
const path = stripBase(pathname, base)
- return {
- fullPath: path + search + hash,
- path,
- query: parseQuery(search),
- hash: hash,
- }
+ return normalizeLocation(path + search + hash)
}
function useHistoryListeners(
TODO,
Immutable,
} from './types'
-import {
- RouterHistory,
- normalizeLocation,
- stringifyURL,
- normalizeQuery,
-} from './history/common'
+import { RouterHistory, normalizeLocation } from './history/common'
import {
ScrollToPosition,
ScrollPosition,
} from './errors'
import { extractComponentsGuards, guardToPromiseFn } from './utils'
import { useCallbacks } from './utils/callbacks'
-import { encodeParam } from './utils/encoding'
-import { decode } from './utils/encoding'
+import { encodeParam, decode } from './utils/encoding'
import { ref, Ref, markNonReactive, nextTick, App } from 'vue'
import { RouteRecordMatched } from './matcher/types'
import Link from './components/Link'
// target location normalized, used if we want to redirect again
const normalizedLocation: RouteLocationNormalized = {
...matchedRoute.normalizedLocation,
- fullPath: stringifyURL({
+ ...normalizeLocation({
path: matchedRoute.normalizedLocation.path,
query: location.query,
hash: location.hash,
}),
- query: normalizeQuery(location.query || {}),
- hash: location.hash,
redirectedFrom,
meta: {},
}
return resolveLocation(
{
...newLocation,
- query: normalizeQuery(newLocation.query || {}),
+ query: newLocation.query || {},
hash: newLocation.hash || '',
},
currentLocation,
return resolveLocation(
{
...redirect,
- query: normalizeQuery(redirect.query || {}),
+ query: redirect.query || {},
hash: redirect.hash || '',
},
currentLocation,
record.leaveGuards = []
}
- // change URL only if the user did a push/replace
+ // only consider as push if it's not the first navigation
+ const isFirstNavigation = from === START_LOCATION_NORMALIZED
+
+ // change URL only if the user did a push/replace and if it's not the initial navigation because
+ // it's just reflecting the url
if (isPush) {
- if (replace) history.replace(toLocation)
+ if (replace || isFirstNavigation) history.replace(toLocation)
else history.push(toLocation)
}