kdu-router 2.7.0 → 3.1.3
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 +21 -21
- package/README.md +56 -45
- package/dist/kdu-router.common.js +2881 -2507
- package/dist/kdu-router.esm.browser.js +2831 -0
- package/dist/kdu-router.esm.browser.min.js +6 -0
- package/dist/kdu-router.esm.js +2879 -2505
- package/dist/kdu-router.js +2887 -2513
- package/dist/kdu-router.min.js +6 -6
- package/package.json +107 -79
- package/src/create-matcher.js +200 -201
- package/src/create-route-map.js +205 -165
- package/src/index.js +261 -235
- package/src/install.js +52 -52
- package/types/index.d.ts +16 -21
- package/types/kdu.d.ts +22 -23
- package/types/router.d.ts +145 -126
- package/src/components/link.js +0 -138
- package/src/components/view.js +0 -96
- 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/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/history/base.js
DELETED
|
@@ -1,328 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
import { _Kdu } from '../install'
|
|
4
|
-
import type Router from '../index'
|
|
5
|
-
import { inBrowser } from '../util/dom'
|
|
6
|
-
import { runQueue } from '../util/async'
|
|
7
|
-
import { warn, isError } from '../util/warn'
|
|
8
|
-
import { START, isSameRoute } from '../util/route'
|
|
9
|
-
import {
|
|
10
|
-
flatten,
|
|
11
|
-
flatMapComponents,
|
|
12
|
-
resolveAsyncComponents
|
|
13
|
-
} from '../util/resolve-components'
|
|
14
|
-
|
|
15
|
-
export class History {
|
|
16
|
-
router: Router;
|
|
17
|
-
base: string;
|
|
18
|
-
current: Route;
|
|
19
|
-
pending: ?Route;
|
|
20
|
-
cb: (r: Route) => void;
|
|
21
|
-
ready: boolean;
|
|
22
|
-
readyCbs: Array<Function>;
|
|
23
|
-
readyErrorCbs: Array<Function>;
|
|
24
|
-
errorCbs: Array<Function>;
|
|
25
|
-
|
|
26
|
-
// implemented by sub-classes
|
|
27
|
-
+go: (n: number) => void;
|
|
28
|
-
+push: (loc: RawLocation) => void;
|
|
29
|
-
+replace: (loc: RawLocation) => void;
|
|
30
|
-
+ensureURL: (push?: boolean) => void;
|
|
31
|
-
+getCurrentLocation: () => string;
|
|
32
|
-
|
|
33
|
-
constructor (router: Router, base: ?string) {
|
|
34
|
-
this.router = router
|
|
35
|
-
this.base = normalizeBase(base)
|
|
36
|
-
// start with a route object that stands for "nowhere"
|
|
37
|
-
this.current = START
|
|
38
|
-
this.pending = null
|
|
39
|
-
this.ready = false
|
|
40
|
-
this.readyCbs = []
|
|
41
|
-
this.readyErrorCbs = []
|
|
42
|
-
this.errorCbs = []
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
listen (cb: Function) {
|
|
46
|
-
this.cb = cb
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
onReady (cb: Function, errorCb: ?Function) {
|
|
50
|
-
if (this.ready) {
|
|
51
|
-
cb()
|
|
52
|
-
} else {
|
|
53
|
-
this.readyCbs.push(cb)
|
|
54
|
-
if (errorCb) {
|
|
55
|
-
this.readyErrorCbs.push(errorCb)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
onError (errorCb: Function) {
|
|
61
|
-
this.errorCbs.push(errorCb)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
|
|
65
|
-
const route = this.router.match(location, this.current)
|
|
66
|
-
this.confirmTransition(route, () => {
|
|
67
|
-
this.updateRoute(route)
|
|
68
|
-
onComplete && onComplete(route)
|
|
69
|
-
this.ensureURL()
|
|
70
|
-
|
|
71
|
-
// fire ready cbs once
|
|
72
|
-
if (!this.ready) {
|
|
73
|
-
this.ready = true
|
|
74
|
-
this.readyCbs.forEach(cb => { cb(route) })
|
|
75
|
-
}
|
|
76
|
-
}, err => {
|
|
77
|
-
if (onAbort) {
|
|
78
|
-
onAbort(err)
|
|
79
|
-
}
|
|
80
|
-
if (err && !this.ready) {
|
|
81
|
-
this.ready = true
|
|
82
|
-
this.readyErrorCbs.forEach(cb => { cb(err) })
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
confirmTransition (route: Route, onComplete: Function, onAbort?: Function) {
|
|
88
|
-
const current = this.current
|
|
89
|
-
const abort = err => {
|
|
90
|
-
if (isError(err)) {
|
|
91
|
-
if (this.errorCbs.length) {
|
|
92
|
-
this.errorCbs.forEach(cb => { cb(err) })
|
|
93
|
-
} else {
|
|
94
|
-
warn(false, 'uncaught error during route navigation:')
|
|
95
|
-
console.error(err)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
onAbort && onAbort(err)
|
|
99
|
-
}
|
|
100
|
-
if (
|
|
101
|
-
isSameRoute(route, current) &&
|
|
102
|
-
// in the case the route map has been dynamically appended to
|
|
103
|
-
route.matched.length === current.matched.length
|
|
104
|
-
) {
|
|
105
|
-
this.ensureURL()
|
|
106
|
-
return abort()
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const {
|
|
110
|
-
updated,
|
|
111
|
-
deactivated,
|
|
112
|
-
activated
|
|
113
|
-
} = resolveQueue(this.current.matched, route.matched)
|
|
114
|
-
|
|
115
|
-
const queue: Array<?NavigationGuard> = [].concat(
|
|
116
|
-
// in-component leave guards
|
|
117
|
-
extractLeaveGuards(deactivated),
|
|
118
|
-
// global before hooks
|
|
119
|
-
this.router.beforeHooks,
|
|
120
|
-
// in-component update hooks
|
|
121
|
-
extractUpdateHooks(updated),
|
|
122
|
-
// in-config enter guards
|
|
123
|
-
activated.map(m => m.beforeEnter),
|
|
124
|
-
// async components
|
|
125
|
-
resolveAsyncComponents(activated)
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
this.pending = route
|
|
129
|
-
const iterator = (hook: NavigationGuard, next) => {
|
|
130
|
-
if (this.pending !== route) {
|
|
131
|
-
return abort()
|
|
132
|
-
}
|
|
133
|
-
try {
|
|
134
|
-
hook(route, current, (to: any) => {
|
|
135
|
-
if (to === false || isError(to)) {
|
|
136
|
-
// next(false) -> abort navigation, ensure current URL
|
|
137
|
-
this.ensureURL(true)
|
|
138
|
-
abort(to)
|
|
139
|
-
} else if (
|
|
140
|
-
typeof to === 'string' ||
|
|
141
|
-
(typeof to === 'object' && (
|
|
142
|
-
typeof to.path === 'string' ||
|
|
143
|
-
typeof to.name === 'string'
|
|
144
|
-
))
|
|
145
|
-
) {
|
|
146
|
-
// next('/') or next({ path: '/' }) -> redirect
|
|
147
|
-
abort()
|
|
148
|
-
if (typeof to === 'object' && to.replace) {
|
|
149
|
-
this.replace(to)
|
|
150
|
-
} else {
|
|
151
|
-
this.push(to)
|
|
152
|
-
}
|
|
153
|
-
} else {
|
|
154
|
-
// confirm transition and pass on the value
|
|
155
|
-
next(to)
|
|
156
|
-
}
|
|
157
|
-
})
|
|
158
|
-
} catch (e) {
|
|
159
|
-
abort(e)
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
runQueue(queue, iterator, () => {
|
|
164
|
-
const postEnterCbs = []
|
|
165
|
-
const isValid = () => this.current === route
|
|
166
|
-
// wait until async components are resolved before
|
|
167
|
-
// extracting in-component enter guards
|
|
168
|
-
const enterGuards = extractEnterGuards(activated, postEnterCbs, isValid)
|
|
169
|
-
const queue = enterGuards.concat(this.router.resolveHooks)
|
|
170
|
-
runQueue(queue, iterator, () => {
|
|
171
|
-
if (this.pending !== route) {
|
|
172
|
-
return abort()
|
|
173
|
-
}
|
|
174
|
-
this.pending = null
|
|
175
|
-
onComplete(route)
|
|
176
|
-
if (this.router.app) {
|
|
177
|
-
this.router.app.$nextTick(() => {
|
|
178
|
-
postEnterCbs.forEach(cb => { cb() })
|
|
179
|
-
})
|
|
180
|
-
}
|
|
181
|
-
})
|
|
182
|
-
})
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
updateRoute (route: Route) {
|
|
186
|
-
const prev = this.current
|
|
187
|
-
this.current = route
|
|
188
|
-
this.cb && this.cb(route)
|
|
189
|
-
this.router.afterHooks.forEach(hook => {
|
|
190
|
-
hook && hook(route, prev)
|
|
191
|
-
})
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function normalizeBase (base: ?string): string {
|
|
196
|
-
if (!base) {
|
|
197
|
-
if (inBrowser) {
|
|
198
|
-
// respect <base> tag
|
|
199
|
-
const baseEl = document.querySelector('base')
|
|
200
|
-
base = (baseEl && baseEl.getAttribute('href')) || '/'
|
|
201
|
-
// strip full URL origin
|
|
202
|
-
base = base.replace(/^https?:\/\/[^\/]+/, '')
|
|
203
|
-
} else {
|
|
204
|
-
base = '/'
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
// make sure there's the starting slash
|
|
208
|
-
if (base.charAt(0) !== '/') {
|
|
209
|
-
base = '/' + base
|
|
210
|
-
}
|
|
211
|
-
// remove trailing slash
|
|
212
|
-
return base.replace(/\/$/, '')
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function resolveQueue (
|
|
216
|
-
current: Array<RouteRecord>,
|
|
217
|
-
next: Array<RouteRecord>
|
|
218
|
-
): {
|
|
219
|
-
updated: Array<RouteRecord>,
|
|
220
|
-
activated: Array<RouteRecord>,
|
|
221
|
-
deactivated: Array<RouteRecord>
|
|
222
|
-
} {
|
|
223
|
-
let i
|
|
224
|
-
const max = Math.max(current.length, next.length)
|
|
225
|
-
for (i = 0; i < max; i++) {
|
|
226
|
-
if (current[i] !== next[i]) {
|
|
227
|
-
break
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
return {
|
|
231
|
-
updated: next.slice(0, i),
|
|
232
|
-
activated: next.slice(i),
|
|
233
|
-
deactivated: current.slice(i)
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function extractGuards (
|
|
238
|
-
records: Array<RouteRecord>,
|
|
239
|
-
name: string,
|
|
240
|
-
bind: Function,
|
|
241
|
-
reverse?: boolean
|
|
242
|
-
): Array<?Function> {
|
|
243
|
-
const guards = flatMapComponents(records, (def, instance, match, key) => {
|
|
244
|
-
const guard = extractGuard(def, name)
|
|
245
|
-
if (guard) {
|
|
246
|
-
return Array.isArray(guard)
|
|
247
|
-
? guard.map(guard => bind(guard, instance, match, key))
|
|
248
|
-
: bind(guard, instance, match, key)
|
|
249
|
-
}
|
|
250
|
-
})
|
|
251
|
-
return flatten(reverse ? guards.reverse() : guards)
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function extractGuard (
|
|
255
|
-
def: Object | Function,
|
|
256
|
-
key: string
|
|
257
|
-
): NavigationGuard | Array<NavigationGuard> {
|
|
258
|
-
if (typeof def !== 'function') {
|
|
259
|
-
// extend now so that global mixins are applied.
|
|
260
|
-
def = _Kdu.extend(def)
|
|
261
|
-
}
|
|
262
|
-
return def.options[key]
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function extractLeaveGuards (deactivated: Array<RouteRecord>): Array<?Function> {
|
|
266
|
-
return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
function extractUpdateHooks (updated: Array<RouteRecord>): Array<?Function> {
|
|
270
|
-
return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
function bindGuard (guard: NavigationGuard, instance: ?_Kdu): ?NavigationGuard {
|
|
274
|
-
if (instance) {
|
|
275
|
-
return function boundRouteGuard () {
|
|
276
|
-
return guard.apply(instance, arguments)
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
function extractEnterGuards (
|
|
282
|
-
activated: Array<RouteRecord>,
|
|
283
|
-
cbs: Array<Function>,
|
|
284
|
-
isValid: () => boolean
|
|
285
|
-
): Array<?Function> {
|
|
286
|
-
return extractGuards(activated, 'beforeRouteEnter', (guard, _, match, key) => {
|
|
287
|
-
return bindEnterGuard(guard, match, key, cbs, isValid)
|
|
288
|
-
})
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function bindEnterGuard (
|
|
292
|
-
guard: NavigationGuard,
|
|
293
|
-
match: RouteRecord,
|
|
294
|
-
key: string,
|
|
295
|
-
cbs: Array<Function>,
|
|
296
|
-
isValid: () => boolean
|
|
297
|
-
): NavigationGuard {
|
|
298
|
-
return function routeEnterGuard (to, from, next) {
|
|
299
|
-
return guard(to, from, cb => {
|
|
300
|
-
next(cb)
|
|
301
|
-
if (typeof cb === 'function') {
|
|
302
|
-
cbs.push(() => {
|
|
303
|
-
// #750
|
|
304
|
-
// if a router-view is wrapped with an out-in transition,
|
|
305
|
-
// the instance may not have been registered at this time.
|
|
306
|
-
// we will need to poll for registration until current route
|
|
307
|
-
// is no longer valid.
|
|
308
|
-
poll(cb, match.instances, key, isValid)
|
|
309
|
-
})
|
|
310
|
-
}
|
|
311
|
-
})
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function poll (
|
|
316
|
-
cb: any, // somehow flow cannot infer this is a function
|
|
317
|
-
instances: Object,
|
|
318
|
-
key: string,
|
|
319
|
-
isValid: () => boolean
|
|
320
|
-
) {
|
|
321
|
-
if (instances[key]) {
|
|
322
|
-
cb(instances[key])
|
|
323
|
-
} else if (isValid()) {
|
|
324
|
-
setTimeout(() => {
|
|
325
|
-
poll(cb, instances, key, isValid)
|
|
326
|
-
}, 16)
|
|
327
|
-
}
|
|
328
|
-
}
|
package/src/history/hash.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
import type Router from '../index'
|
|
4
|
-
import { History } from './base'
|
|
5
|
-
import { cleanPath } from '../util/path'
|
|
6
|
-
import { getLocation } from './html5'
|
|
7
|
-
|
|
8
|
-
export class HashHistory extends History {
|
|
9
|
-
constructor (router: Router, base: ?string, fallback: boolean) {
|
|
10
|
-
super(router, base)
|
|
11
|
-
// check history fallback deeplinking
|
|
12
|
-
if (fallback && checkFallback(this.base)) {
|
|
13
|
-
return
|
|
14
|
-
}
|
|
15
|
-
ensureSlash()
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// this is delayed until the app mounts
|
|
19
|
-
// to avoid the hashchange listener being fired too early
|
|
20
|
-
setupListeners () {
|
|
21
|
-
window.addEventListener('hashchange', () => {
|
|
22
|
-
if (!ensureSlash()) {
|
|
23
|
-
return
|
|
24
|
-
}
|
|
25
|
-
this.transitionTo(getHash(), route => {
|
|
26
|
-
replaceHash(route.fullPath)
|
|
27
|
-
})
|
|
28
|
-
})
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
|
|
32
|
-
this.transitionTo(location, route => {
|
|
33
|
-
pushHash(route.fullPath)
|
|
34
|
-
onComplete && onComplete(route)
|
|
35
|
-
}, onAbort)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
|
|
39
|
-
this.transitionTo(location, route => {
|
|
40
|
-
replaceHash(route.fullPath)
|
|
41
|
-
onComplete && onComplete(route)
|
|
42
|
-
}, onAbort)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
go (n: number) {
|
|
46
|
-
window.history.go(n)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
ensureURL (push?: boolean) {
|
|
50
|
-
const current = this.current.fullPath
|
|
51
|
-
if (getHash() !== current) {
|
|
52
|
-
push ? pushHash(current) : replaceHash(current)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
getCurrentLocation () {
|
|
57
|
-
return getHash()
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function checkFallback (base) {
|
|
62
|
-
const location = getLocation(base)
|
|
63
|
-
if (!/^\/#/.test(location)) {
|
|
64
|
-
window.location.replace(
|
|
65
|
-
cleanPath(base + '/#' + location)
|
|
66
|
-
)
|
|
67
|
-
return true
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function ensureSlash (): boolean {
|
|
72
|
-
const path = getHash()
|
|
73
|
-
if (path.charAt(0) === '/') {
|
|
74
|
-
return true
|
|
75
|
-
}
|
|
76
|
-
replaceHash('/' + path)
|
|
77
|
-
return false
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function getHash (): string {
|
|
81
|
-
// We can't use window.location.hash here because it's not
|
|
82
|
-
// consistent across browsers - Firefox will pre-decode it!
|
|
83
|
-
const href = window.location.href
|
|
84
|
-
const index = href.indexOf('#')
|
|
85
|
-
return index === -1 ? '' : href.slice(index + 1)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function pushHash (path) {
|
|
89
|
-
window.location.hash = path
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function replaceHash (path) {
|
|
93
|
-
const href = window.location.href
|
|
94
|
-
const i = href.indexOf('#')
|
|
95
|
-
const base = i >= 0 ? href.slice(0, i) : href
|
|
96
|
-
window.location.replace(`${base}#${path}`)
|
|
97
|
-
}
|
package/src/history/html5.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
|
-
import type Router from '../index'
|
|
4
|
-
import { History } from './base'
|
|
5
|
-
import { cleanPath } from '../util/path'
|
|
6
|
-
import { setupScroll, handleScroll } from '../util/scroll'
|
|
7
|
-
import { pushState, replaceState } from '../util/push-state'
|
|
8
|
-
|
|
9
|
-
export class HTML5History extends History {
|
|
10
|
-
constructor (router: Router, base: ?string) {
|
|
11
|
-
super(router, base)
|
|
12
|
-
|
|
13
|
-
const expectScroll = router.options.scrollBehavior
|
|
14
|
-
|
|
15
|
-
if (expectScroll) {
|
|
16
|
-
setupScroll()
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
window.addEventListener('popstate', e => {
|
|
20
|
-
const current = this.current
|
|
21
|
-
this.transitionTo(getLocation(this.base), route => {
|
|
22
|
-
if (expectScroll) {
|
|
23
|
-
handleScroll(router, route, current, true)
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
})
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
go (n: number) {
|
|
30
|
-
window.history.go(n)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
|
|
34
|
-
const { current: fromRoute } = this
|
|
35
|
-
this.transitionTo(location, route => {
|
|
36
|
-
pushState(cleanPath(this.base + route.fullPath))
|
|
37
|
-
handleScroll(this.router, route, fromRoute, false)
|
|
38
|
-
onComplete && onComplete(route)
|
|
39
|
-
}, onAbort)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
|
|
43
|
-
const { current: fromRoute } = this
|
|
44
|
-
this.transitionTo(location, route => {
|
|
45
|
-
replaceState(cleanPath(this.base + route.fullPath))
|
|
46
|
-
handleScroll(this.router, route, fromRoute, false)
|
|
47
|
-
onComplete && onComplete(route)
|
|
48
|
-
}, onAbort)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
ensureURL (push?: boolean) {
|
|
52
|
-
if (getLocation(this.base) !== this.current.fullPath) {
|
|
53
|
-
const current = cleanPath(this.base + this.current.fullPath)
|
|
54
|
-
push ? pushState(current) : replaceState(current)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
getCurrentLocation (): string {
|
|
59
|
-
return getLocation(this.base)
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function getLocation (base: string): string {
|
|
64
|
-
let path = window.location.pathname
|
|
65
|
-
if (base && path.indexOf(base) === 0) {
|
|
66
|
-
path = path.slice(base.length)
|
|
67
|
-
}
|
|
68
|
-
return (path || '/') + window.location.search + window.location.hash
|
|
69
|
-
}
|
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
|
-
}
|