kdu-router 2.7.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +2 -25
- package/dist/kdu-router.common.js +164 -57
- package/dist/kdu-router.esm.js +164 -57
- package/dist/kdu-router.js +164 -57
- package/dist/kdu-router.min.js +2 -2
- package/package.json +22 -37
- package/types/index.d.ts +13 -18
- package/types/kdu.d.ts +2 -3
- package/types/router.d.ts +5 -5
- package/src/components/link.js +0 -138
- package/src/components/view.js +0 -96
- package/src/create-matcher.js +0 -201
- package/src/create-route-map.js +0 -165
- package/src/history/abstract.js +0 -51
- package/src/history/base.js +0 -328
- package/src/history/hash.js +0 -97
- package/src/history/html5.js +0 -69
- package/src/index.js +0 -235
- package/src/install.js +0 -52
- package/src/util/async.js +0 -18
- package/src/util/dom.js +0 -3
- package/src/util/location.js +0 -68
- package/src/util/params.js +0 -26
- package/src/util/path.js +0 -74
- package/src/util/push-state.js +0 -59
- package/src/util/query.js +0 -96
- package/src/util/resolve-components.js +0 -100
- package/src/util/route.js +0 -110
- package/src/util/scroll.js +0 -111
- package/src/util/warn.js +0 -17
package/src/index.js
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
import { install } from './install'
|
|
4
|
-
import { START } from './util/route'
|
|
5
|
-
import { assert } from './util/warn'
|
|
6
|
-
import { inBrowser } from './util/dom'
|
|
7
|
-
import { cleanPath } from './util/path'
|
|
8
|
-
import { createMatcher } from './create-matcher'
|
|
9
|
-
import { normalizeLocation } from './util/location'
|
|
10
|
-
import { supportsPushState } from './util/push-state'
|
|
11
|
-
|
|
12
|
-
import { HashHistory } from './history/hash'
|
|
13
|
-
import { HTML5History } from './history/html5'
|
|
14
|
-
import { AbstractHistory } from './history/abstract'
|
|
15
|
-
|
|
16
|
-
import type { Matcher } from './create-matcher'
|
|
17
|
-
|
|
18
|
-
export default class KduRouter {
|
|
19
|
-
static install: () => void;
|
|
20
|
-
static version: string;
|
|
21
|
-
|
|
22
|
-
app: any;
|
|
23
|
-
apps: Array<any>;
|
|
24
|
-
ready: boolean;
|
|
25
|
-
readyCbs: Array<Function>;
|
|
26
|
-
options: RouterOptions;
|
|
27
|
-
mode: string;
|
|
28
|
-
history: HashHistory | HTML5History | AbstractHistory;
|
|
29
|
-
matcher: Matcher;
|
|
30
|
-
fallback: boolean;
|
|
31
|
-
beforeHooks: Array<?NavigationGuard>;
|
|
32
|
-
resolveHooks: Array<?NavigationGuard>;
|
|
33
|
-
afterHooks: Array<?AfterNavigationHook>;
|
|
34
|
-
|
|
35
|
-
constructor (options: RouterOptions = {}) {
|
|
36
|
-
this.app = null
|
|
37
|
-
this.apps = []
|
|
38
|
-
this.options = options
|
|
39
|
-
this.beforeHooks = []
|
|
40
|
-
this.resolveHooks = []
|
|
41
|
-
this.afterHooks = []
|
|
42
|
-
this.matcher = createMatcher(options.routes || [], this)
|
|
43
|
-
|
|
44
|
-
let mode = options.mode || 'hash'
|
|
45
|
-
this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false
|
|
46
|
-
if (this.fallback) {
|
|
47
|
-
mode = 'hash'
|
|
48
|
-
}
|
|
49
|
-
if (!inBrowser) {
|
|
50
|
-
mode = 'abstract'
|
|
51
|
-
}
|
|
52
|
-
this.mode = mode
|
|
53
|
-
|
|
54
|
-
switch (mode) {
|
|
55
|
-
case 'history':
|
|
56
|
-
this.history = new HTML5History(this, options.base)
|
|
57
|
-
break
|
|
58
|
-
case 'hash':
|
|
59
|
-
this.history = new HashHistory(this, options.base, this.fallback)
|
|
60
|
-
break
|
|
61
|
-
case 'abstract':
|
|
62
|
-
this.history = new AbstractHistory(this, options.base)
|
|
63
|
-
break
|
|
64
|
-
default:
|
|
65
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
66
|
-
assert(false, `invalid mode: ${mode}`)
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
match (
|
|
72
|
-
raw: RawLocation,
|
|
73
|
-
current?: Route,
|
|
74
|
-
redirectedFrom?: Location
|
|
75
|
-
): Route {
|
|
76
|
-
return this.matcher.match(raw, current, redirectedFrom)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
get currentRoute (): ?Route {
|
|
80
|
-
return this.history && this.history.current
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
init (app: any /* Kdu component instance */) {
|
|
84
|
-
process.env.NODE_ENV !== 'production' && assert(
|
|
85
|
-
install.installed,
|
|
86
|
-
`not installed. Make sure to call \`Kdu.use(KduRouter)\` ` +
|
|
87
|
-
`before creating root instance.`
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
this.apps.push(app)
|
|
91
|
-
|
|
92
|
-
// main app already initialized.
|
|
93
|
-
if (this.app) {
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
this.app = app
|
|
98
|
-
|
|
99
|
-
const history = this.history
|
|
100
|
-
|
|
101
|
-
if (history instanceof HTML5History) {
|
|
102
|
-
history.transitionTo(history.getCurrentLocation())
|
|
103
|
-
} else if (history instanceof HashHistory) {
|
|
104
|
-
const setupHashListener = () => {
|
|
105
|
-
history.setupListeners()
|
|
106
|
-
}
|
|
107
|
-
history.transitionTo(
|
|
108
|
-
history.getCurrentLocation(),
|
|
109
|
-
setupHashListener,
|
|
110
|
-
setupHashListener
|
|
111
|
-
)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
history.listen(route => {
|
|
115
|
-
this.apps.forEach((app) => {
|
|
116
|
-
app._route = route
|
|
117
|
-
})
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
beforeEach (fn: Function): Function {
|
|
122
|
-
return registerHook(this.beforeHooks, fn)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
beforeResolve (fn: Function): Function {
|
|
126
|
-
return registerHook(this.resolveHooks, fn)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
afterEach (fn: Function): Function {
|
|
130
|
-
return registerHook(this.afterHooks, fn)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
onReady (cb: Function, errorCb?: Function) {
|
|
134
|
-
this.history.onReady(cb, errorCb)
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
onError (errorCb: Function) {
|
|
138
|
-
this.history.onError(errorCb)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
|
|
142
|
-
this.history.push(location, onComplete, onAbort)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
|
|
146
|
-
this.history.replace(location, onComplete, onAbort)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
go (n: number) {
|
|
150
|
-
this.history.go(n)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
back () {
|
|
154
|
-
this.go(-1)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
forward () {
|
|
158
|
-
this.go(1)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
getMatchedComponents (to?: RawLocation | Route): Array<any> {
|
|
162
|
-
const route: any = to
|
|
163
|
-
? to.matched
|
|
164
|
-
? to
|
|
165
|
-
: this.resolve(to).route
|
|
166
|
-
: this.currentRoute
|
|
167
|
-
if (!route) {
|
|
168
|
-
return []
|
|
169
|
-
}
|
|
170
|
-
return [].concat.apply([], route.matched.map(m => {
|
|
171
|
-
return Object.keys(m.components).map(key => {
|
|
172
|
-
return m.components[key]
|
|
173
|
-
})
|
|
174
|
-
}))
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
resolve (
|
|
178
|
-
to: RawLocation,
|
|
179
|
-
current?: Route,
|
|
180
|
-
append?: boolean
|
|
181
|
-
): {
|
|
182
|
-
location: Location,
|
|
183
|
-
route: Route,
|
|
184
|
-
href: string,
|
|
185
|
-
// for backwards compat
|
|
186
|
-
normalizedTo: Location,
|
|
187
|
-
resolved: Route
|
|
188
|
-
} {
|
|
189
|
-
const location = normalizeLocation(
|
|
190
|
-
to,
|
|
191
|
-
current || this.history.current,
|
|
192
|
-
append,
|
|
193
|
-
this
|
|
194
|
-
)
|
|
195
|
-
const route = this.match(location, current)
|
|
196
|
-
const fullPath = route.redirectedFrom || route.fullPath
|
|
197
|
-
const base = this.history.base
|
|
198
|
-
const href = createHref(base, fullPath, this.mode)
|
|
199
|
-
return {
|
|
200
|
-
location,
|
|
201
|
-
route,
|
|
202
|
-
href,
|
|
203
|
-
// for backwards compat
|
|
204
|
-
normalizedTo: location,
|
|
205
|
-
resolved: route
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
addRoutes (routes: Array<RouteConfig>) {
|
|
210
|
-
this.matcher.addRoutes(routes)
|
|
211
|
-
if (this.history.current !== START) {
|
|
212
|
-
this.history.transitionTo(this.history.getCurrentLocation())
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function registerHook (list: Array<any>, fn: Function): Function {
|
|
218
|
-
list.push(fn)
|
|
219
|
-
return () => {
|
|
220
|
-
const i = list.indexOf(fn)
|
|
221
|
-
if (i > -1) list.splice(i, 1)
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function createHref (base: string, fullPath: string, mode) {
|
|
226
|
-
var path = mode === 'hash' ? '#' + fullPath : fullPath
|
|
227
|
-
return base ? cleanPath(base + '/' + path) : path
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
KduRouter.install = install
|
|
231
|
-
KduRouter.version = '__VERSION__'
|
|
232
|
-
|
|
233
|
-
if (inBrowser && window.Kdu) {
|
|
234
|
-
window.Kdu.use(KduRouter)
|
|
235
|
-
}
|
package/src/install.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import View from './components/view'
|
|
2
|
-
import Link from './components/link'
|
|
3
|
-
|
|
4
|
-
export let _Kdu
|
|
5
|
-
|
|
6
|
-
export function install (Kdu) {
|
|
7
|
-
if (install.installed) return
|
|
8
|
-
install.installed = true
|
|
9
|
-
|
|
10
|
-
_Kdu = Kdu
|
|
11
|
-
|
|
12
|
-
const isDef = v => v !== undefined
|
|
13
|
-
|
|
14
|
-
const registerInstance = (vm, callVal) => {
|
|
15
|
-
let i = vm.$options._parentVnode
|
|
16
|
-
if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
|
|
17
|
-
i(vm, callVal)
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
Kdu.mixin({
|
|
22
|
-
beforeCreate () {
|
|
23
|
-
if (isDef(this.$options.router)) {
|
|
24
|
-
this._routerRoot = this
|
|
25
|
-
this._router = this.$options.router
|
|
26
|
-
this._router.init(this)
|
|
27
|
-
Kdu.util.defineReactive(this, '_route', this._router.history.current)
|
|
28
|
-
} else {
|
|
29
|
-
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
|
|
30
|
-
}
|
|
31
|
-
registerInstance(this, this)
|
|
32
|
-
},
|
|
33
|
-
destroyed () {
|
|
34
|
-
registerInstance(this)
|
|
35
|
-
}
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
Object.defineProperty(Kdu.prototype, '$router', {
|
|
39
|
-
get () { return this._routerRoot._router }
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
Object.defineProperty(Kdu.prototype, '$route', {
|
|
43
|
-
get () { return this._routerRoot._route }
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
Kdu.component('router-view', View)
|
|
47
|
-
Kdu.component('router-link', Link)
|
|
48
|
-
|
|
49
|
-
const strats = Kdu.config.optionMergeStrategies
|
|
50
|
-
// use the same hook merging strategy for route hooks
|
|
51
|
-
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
|
|
52
|
-
}
|
package/src/util/async.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
export function runQueue (queue: Array<?NavigationGuard>, fn: Function, cb: Function) {
|
|
4
|
-
const step = index => {
|
|
5
|
-
if (index >= queue.length) {
|
|
6
|
-
cb()
|
|
7
|
-
} else {
|
|
8
|
-
if (queue[index]) {
|
|
9
|
-
fn(queue[index], () => {
|
|
10
|
-
step(index + 1)
|
|
11
|
-
})
|
|
12
|
-
} else {
|
|
13
|
-
step(index + 1)
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
step(0)
|
|
18
|
-
}
|
package/src/util/dom.js
DELETED
package/src/util/location.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
import type KduRouter from '../index'
|
|
4
|
-
import { parsePath, resolvePath } from './path'
|
|
5
|
-
import { resolveQuery } from './query'
|
|
6
|
-
import { fillParams } from './params'
|
|
7
|
-
import { warn } from './warn'
|
|
8
|
-
|
|
9
|
-
export function normalizeLocation (
|
|
10
|
-
raw: RawLocation,
|
|
11
|
-
current: ?Route,
|
|
12
|
-
append: ?boolean,
|
|
13
|
-
router: ?KduRouter
|
|
14
|
-
): Location {
|
|
15
|
-
let next: Location = typeof raw === 'string' ? { path: raw } : raw
|
|
16
|
-
// named target
|
|
17
|
-
if (next.name || next._normalized) {
|
|
18
|
-
return next
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// relative params
|
|
22
|
-
if (!next.path && next.params && current) {
|
|
23
|
-
next = assign({}, next)
|
|
24
|
-
next._normalized = true
|
|
25
|
-
const params: any = assign(assign({}, current.params), next.params)
|
|
26
|
-
if (current.name) {
|
|
27
|
-
next.name = current.name
|
|
28
|
-
next.params = params
|
|
29
|
-
} else if (current.matched.length) {
|
|
30
|
-
const rawPath = current.matched[current.matched.length - 1].path
|
|
31
|
-
next.path = fillParams(rawPath, params, `path ${current.path}`)
|
|
32
|
-
} else if (process.env.NODE_ENV !== 'production') {
|
|
33
|
-
warn(false, `relative params navigation requires a current route.`)
|
|
34
|
-
}
|
|
35
|
-
return next
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const parsedPath = parsePath(next.path || '')
|
|
39
|
-
const basePath = (current && current.path) || '/'
|
|
40
|
-
const path = parsedPath.path
|
|
41
|
-
? resolvePath(parsedPath.path, basePath, append || next.append)
|
|
42
|
-
: basePath
|
|
43
|
-
|
|
44
|
-
const query = resolveQuery(
|
|
45
|
-
parsedPath.query,
|
|
46
|
-
next.query,
|
|
47
|
-
router && router.options.parseQuery
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
let hash = next.hash || parsedPath.hash
|
|
51
|
-
if (hash && hash.charAt(0) !== '#') {
|
|
52
|
-
hash = `#${hash}`
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
_normalized: true,
|
|
57
|
-
path,
|
|
58
|
-
query,
|
|
59
|
-
hash
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function assign (a, b) {
|
|
64
|
-
for (const key in b) {
|
|
65
|
-
a[key] = b[key]
|
|
66
|
-
}
|
|
67
|
-
return a
|
|
68
|
-
}
|
package/src/util/params.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
import { warn } from './warn'
|
|
4
|
-
import Regexp from 'path-to-regexp'
|
|
5
|
-
|
|
6
|
-
const regexpCompileCache: {
|
|
7
|
-
[key: string]: Function
|
|
8
|
-
} = Object.create(null)
|
|
9
|
-
|
|
10
|
-
export function fillParams (
|
|
11
|
-
path: string,
|
|
12
|
-
params: ?Object,
|
|
13
|
-
routeMsg: string
|
|
14
|
-
): string {
|
|
15
|
-
try {
|
|
16
|
-
const filler =
|
|
17
|
-
regexpCompileCache[path] ||
|
|
18
|
-
(regexpCompileCache[path] = Regexp.compile(path))
|
|
19
|
-
return filler(params || {}, { pretty: true })
|
|
20
|
-
} catch (e) {
|
|
21
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
22
|
-
warn(false, `missing param for ${routeMsg}: ${e.message}`)
|
|
23
|
-
}
|
|
24
|
-
return ''
|
|
25
|
-
}
|
|
26
|
-
}
|
package/src/util/path.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
export function resolvePath (
|
|
4
|
-
relative: string,
|
|
5
|
-
base: string,
|
|
6
|
-
append?: boolean
|
|
7
|
-
): string {
|
|
8
|
-
const firstChar = relative.charAt(0)
|
|
9
|
-
if (firstChar === '/') {
|
|
10
|
-
return relative
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (firstChar === '?' || firstChar === '#') {
|
|
14
|
-
return base + relative
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const stack = base.split('/')
|
|
18
|
-
|
|
19
|
-
// remove trailing segment if:
|
|
20
|
-
// - not appending
|
|
21
|
-
// - appending to trailing slash (last segment is empty)
|
|
22
|
-
if (!append || !stack[stack.length - 1]) {
|
|
23
|
-
stack.pop()
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// resolve relative path
|
|
27
|
-
const segments = relative.replace(/^\//, '').split('/')
|
|
28
|
-
for (let i = 0; i < segments.length; i++) {
|
|
29
|
-
const segment = segments[i]
|
|
30
|
-
if (segment === '..') {
|
|
31
|
-
stack.pop()
|
|
32
|
-
} else if (segment !== '.') {
|
|
33
|
-
stack.push(segment)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// ensure leading slash
|
|
38
|
-
if (stack[0] !== '') {
|
|
39
|
-
stack.unshift('')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return stack.join('/')
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function parsePath (path: string): {
|
|
46
|
-
path: string;
|
|
47
|
-
query: string;
|
|
48
|
-
hash: string;
|
|
49
|
-
} {
|
|
50
|
-
let hash = ''
|
|
51
|
-
let query = ''
|
|
52
|
-
|
|
53
|
-
const hashIndex = path.indexOf('#')
|
|
54
|
-
if (hashIndex >= 0) {
|
|
55
|
-
hash = path.slice(hashIndex)
|
|
56
|
-
path = path.slice(0, hashIndex)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const queryIndex = path.indexOf('?')
|
|
60
|
-
if (queryIndex >= 0) {
|
|
61
|
-
query = path.slice(queryIndex + 1)
|
|
62
|
-
path = path.slice(0, queryIndex)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
path,
|
|
67
|
-
query,
|
|
68
|
-
hash
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function cleanPath (path: string): string {
|
|
73
|
-
return path.replace(/\/\//g, '/')
|
|
74
|
-
}
|
package/src/util/push-state.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
import { inBrowser } from './dom'
|
|
4
|
-
import { saveScrollPosition } from './scroll'
|
|
5
|
-
|
|
6
|
-
export const supportsPushState = inBrowser && (function () {
|
|
7
|
-
const ua = window.navigator.userAgent
|
|
8
|
-
|
|
9
|
-
if (
|
|
10
|
-
(ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
|
|
11
|
-
ua.indexOf('Mobile Safari') !== -1 &&
|
|
12
|
-
ua.indexOf('Chrome') === -1 &&
|
|
13
|
-
ua.indexOf('Windows Phone') === -1
|
|
14
|
-
) {
|
|
15
|
-
return false
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return window.history && 'pushState' in window.history
|
|
19
|
-
})()
|
|
20
|
-
|
|
21
|
-
// use User Timing api (if present) for more accurate key precision
|
|
22
|
-
const Time = inBrowser && window.performance && window.performance.now
|
|
23
|
-
? window.performance
|
|
24
|
-
: Date
|
|
25
|
-
|
|
26
|
-
let _key: string = genKey()
|
|
27
|
-
|
|
28
|
-
function genKey (): string {
|
|
29
|
-
return Time.now().toFixed(3)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function getStateKey () {
|
|
33
|
-
return _key
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function setStateKey (key: string) {
|
|
37
|
-
_key = key
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function pushState (url?: string, replace?: boolean) {
|
|
41
|
-
saveScrollPosition()
|
|
42
|
-
// try...catch the pushState call to get around Safari
|
|
43
|
-
// DOM Exception 18 where it limits to 100 pushState calls
|
|
44
|
-
const history = window.history
|
|
45
|
-
try {
|
|
46
|
-
if (replace) {
|
|
47
|
-
history.replaceState({ key: _key }, '', url)
|
|
48
|
-
} else {
|
|
49
|
-
_key = genKey()
|
|
50
|
-
history.pushState({ key: _key }, '', url)
|
|
51
|
-
}
|
|
52
|
-
} catch (e) {
|
|
53
|
-
window.location[replace ? 'replace' : 'assign'](url)
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function replaceState (url?: string) {
|
|
58
|
-
pushState(url, true)
|
|
59
|
-
}
|
package/src/util/query.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
import { warn } from './warn'
|
|
4
|
-
|
|
5
|
-
const encodeReserveRE = /[!'()*]/g
|
|
6
|
-
const encodeReserveReplacer = c => '%' + c.charCodeAt(0).toString(16)
|
|
7
|
-
const commaRE = /%2C/g
|
|
8
|
-
|
|
9
|
-
// fixed encodeURIComponent which is more conformant to RFC3986:
|
|
10
|
-
// - escapes [!'()*]
|
|
11
|
-
// - preserve commas
|
|
12
|
-
const encode = str => encodeURIComponent(str)
|
|
13
|
-
.replace(encodeReserveRE, encodeReserveReplacer)
|
|
14
|
-
.replace(commaRE, ',')
|
|
15
|
-
|
|
16
|
-
const decode = decodeURIComponent
|
|
17
|
-
|
|
18
|
-
export function resolveQuery (
|
|
19
|
-
query: ?string,
|
|
20
|
-
extraQuery: Dictionary<string> = {},
|
|
21
|
-
_parseQuery: ?Function
|
|
22
|
-
): Dictionary<string> {
|
|
23
|
-
const parse = _parseQuery || parseQuery
|
|
24
|
-
let parsedQuery
|
|
25
|
-
try {
|
|
26
|
-
parsedQuery = parse(query || '')
|
|
27
|
-
} catch (e) {
|
|
28
|
-
process.env.NODE_ENV !== 'production' && warn(false, e.message)
|
|
29
|
-
parsedQuery = {}
|
|
30
|
-
}
|
|
31
|
-
for (const key in extraQuery) {
|
|
32
|
-
const val = extraQuery[key]
|
|
33
|
-
parsedQuery[key] = Array.isArray(val) ? val.slice() : val
|
|
34
|
-
}
|
|
35
|
-
return parsedQuery
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function parseQuery (query: string): Dictionary<string> {
|
|
39
|
-
const res = {}
|
|
40
|
-
|
|
41
|
-
query = query.trim().replace(/^(\?|#|&)/, '')
|
|
42
|
-
|
|
43
|
-
if (!query) {
|
|
44
|
-
return res
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
query.split('&').forEach(param => {
|
|
48
|
-
const parts = param.replace(/\+/g, ' ').split('=')
|
|
49
|
-
const key = decode(parts.shift())
|
|
50
|
-
const val = parts.length > 0
|
|
51
|
-
? decode(parts.join('='))
|
|
52
|
-
: null
|
|
53
|
-
|
|
54
|
-
if (res[key] === undefined) {
|
|
55
|
-
res[key] = val
|
|
56
|
-
} else if (Array.isArray(res[key])) {
|
|
57
|
-
res[key].push(val)
|
|
58
|
-
} else {
|
|
59
|
-
res[key] = [res[key], val]
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
return res
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function stringifyQuery (obj: Dictionary<string>): string {
|
|
67
|
-
const res = obj ? Object.keys(obj).map(key => {
|
|
68
|
-
const val = obj[key]
|
|
69
|
-
|
|
70
|
-
if (val === undefined) {
|
|
71
|
-
return ''
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (val === null) {
|
|
75
|
-
return encode(key)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (Array.isArray(val)) {
|
|
79
|
-
const result = []
|
|
80
|
-
val.forEach(val2 => {
|
|
81
|
-
if (val2 === undefined) {
|
|
82
|
-
return
|
|
83
|
-
}
|
|
84
|
-
if (val2 === null) {
|
|
85
|
-
result.push(encode(key))
|
|
86
|
-
} else {
|
|
87
|
-
result.push(encode(key) + '=' + encode(val2))
|
|
88
|
-
}
|
|
89
|
-
})
|
|
90
|
-
return result.join('&')
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return encode(key) + '=' + encode(val)
|
|
94
|
-
}).filter(x => x.length > 0).join('&') : null
|
|
95
|
-
return res ? `?${res}` : ''
|
|
96
|
-
}
|