kdu-router 3.0.1 → 3.0.7
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/README.md +0 -2
- package/dist/kdu-router.common.js +117 -68
- package/dist/kdu-router.esm.browser.js +2632 -0
- package/dist/kdu-router.esm.browser.min.js +11 -0
- package/dist/kdu-router.esm.js +117 -68
- package/dist/kdu-router.js +117 -68
- package/dist/kdu-router.min.js +8 -3
- package/package.json +43 -26
- package/src/create-matcher.js +200 -0
- package/src/create-route-map.js +171 -0
- package/src/index.js +247 -0
- package/src/install.js +52 -0
- package/types/kdu.d.ts +3 -3
- package/types/router.d.ts +9 -8
package/src/index.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
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
|
+
// set up app destroyed handler
|
|
93
|
+
app.$once('hook:destroyed', () => {
|
|
94
|
+
// clean out app from this.apps array once destroyed
|
|
95
|
+
const index = this.apps.indexOf(app)
|
|
96
|
+
if (index > -1) this.apps.splice(index, 1)
|
|
97
|
+
// ensure we still have a main app or null if no apps
|
|
98
|
+
// we do not release the router so it can be reused
|
|
99
|
+
if (this.app === app) this.app = this.apps[0] || null
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// main app previously initialized
|
|
103
|
+
// return as we don't need to set up new history listener
|
|
104
|
+
if (this.app) {
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this.app = app
|
|
109
|
+
|
|
110
|
+
const history = this.history
|
|
111
|
+
|
|
112
|
+
if (history instanceof HTML5History) {
|
|
113
|
+
history.transitionTo(history.getCurrentLocation())
|
|
114
|
+
} else if (history instanceof HashHistory) {
|
|
115
|
+
const setupHashListener = () => {
|
|
116
|
+
history.setupListeners()
|
|
117
|
+
}
|
|
118
|
+
history.transitionTo(
|
|
119
|
+
history.getCurrentLocation(),
|
|
120
|
+
setupHashListener,
|
|
121
|
+
setupHashListener
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
history.listen(route => {
|
|
126
|
+
this.apps.forEach((app) => {
|
|
127
|
+
app._route = route
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
beforeEach (fn: Function): Function {
|
|
133
|
+
return registerHook(this.beforeHooks, fn)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
beforeResolve (fn: Function): Function {
|
|
137
|
+
return registerHook(this.resolveHooks, fn)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
afterEach (fn: Function): Function {
|
|
141
|
+
return registerHook(this.afterHooks, fn)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
onReady (cb: Function, errorCb?: Function) {
|
|
145
|
+
this.history.onReady(cb, errorCb)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
onError (errorCb: Function) {
|
|
149
|
+
this.history.onError(errorCb)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
|
|
153
|
+
this.history.push(location, onComplete, onAbort)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
|
|
157
|
+
this.history.replace(location, onComplete, onAbort)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
go (n: number) {
|
|
161
|
+
this.history.go(n)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
back () {
|
|
165
|
+
this.go(-1)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
forward () {
|
|
169
|
+
this.go(1)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
getMatchedComponents (to?: RawLocation | Route): Array<any> {
|
|
173
|
+
const route: any = to
|
|
174
|
+
? to.matched
|
|
175
|
+
? to
|
|
176
|
+
: this.resolve(to).route
|
|
177
|
+
: this.currentRoute
|
|
178
|
+
if (!route) {
|
|
179
|
+
return []
|
|
180
|
+
}
|
|
181
|
+
return [].concat.apply([], route.matched.map(m => {
|
|
182
|
+
return Object.keys(m.components).map(key => {
|
|
183
|
+
return m.components[key]
|
|
184
|
+
})
|
|
185
|
+
}))
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
resolve (
|
|
189
|
+
to: RawLocation,
|
|
190
|
+
current?: Route,
|
|
191
|
+
append?: boolean
|
|
192
|
+
): {
|
|
193
|
+
location: Location,
|
|
194
|
+
route: Route,
|
|
195
|
+
href: string,
|
|
196
|
+
// for backwards compat
|
|
197
|
+
normalizedTo: Location,
|
|
198
|
+
resolved: Route
|
|
199
|
+
} {
|
|
200
|
+
current = current || this.history.current
|
|
201
|
+
const location = normalizeLocation(
|
|
202
|
+
to,
|
|
203
|
+
current,
|
|
204
|
+
append,
|
|
205
|
+
this
|
|
206
|
+
)
|
|
207
|
+
const route = this.match(location, current)
|
|
208
|
+
const fullPath = route.redirectedFrom || route.fullPath
|
|
209
|
+
const base = this.history.base
|
|
210
|
+
const href = createHref(base, fullPath, this.mode)
|
|
211
|
+
return {
|
|
212
|
+
location,
|
|
213
|
+
route,
|
|
214
|
+
href,
|
|
215
|
+
// for backwards compat
|
|
216
|
+
normalizedTo: location,
|
|
217
|
+
resolved: route
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
addRoutes (routes: Array<RouteConfig>) {
|
|
222
|
+
this.matcher.addRoutes(routes)
|
|
223
|
+
if (this.history.current !== START) {
|
|
224
|
+
this.history.transitionTo(this.history.getCurrentLocation())
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function registerHook (list: Array<any>, fn: Function): Function {
|
|
230
|
+
list.push(fn)
|
|
231
|
+
return () => {
|
|
232
|
+
const i = list.indexOf(fn)
|
|
233
|
+
if (i > -1) list.splice(i, 1)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function createHref (base: string, fullPath: string, mode) {
|
|
238
|
+
var path = mode === 'hash' ? '#' + fullPath : fullPath
|
|
239
|
+
return base ? cleanPath(base + '/' + path) : path
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
KduRouter.install = install
|
|
243
|
+
KduRouter.version = '__VERSION__'
|
|
244
|
+
|
|
245
|
+
if (inBrowser && window.Kdu) {
|
|
246
|
+
window.Kdu.use(KduRouter)
|
|
247
|
+
}
|
package/src/install.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
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 && _Kdu === Kdu) 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._parentKnode
|
|
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('RouterView', View)
|
|
47
|
+
Kdu.component('RouterLink', 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/types/kdu.d.ts
CHANGED
|
@@ -15,8 +15,8 @@ declare module "kdu/types/kdu" {
|
|
|
15
15
|
declare module "kdu/types/options" {
|
|
16
16
|
interface ComponentOptions<V extends Kdu> {
|
|
17
17
|
router?: KduRouter;
|
|
18
|
-
beforeRouteEnter?: NavigationGuard
|
|
19
|
-
beforeRouteLeave?: NavigationGuard
|
|
20
|
-
beforeRouteUpdate?: NavigationGuard
|
|
18
|
+
beforeRouteEnter?: NavigationGuard<V>;
|
|
19
|
+
beforeRouteLeave?: NavigationGuard<V>;
|
|
20
|
+
beforeRouteUpdate?: NavigationGuard<V>;
|
|
21
21
|
}
|
|
22
22
|
}
|
package/types/router.d.ts
CHANGED
|
@@ -2,14 +2,15 @@ import Kdu, { ComponentOptions, PluginFunction, AsyncComponent } from "kdu";
|
|
|
2
2
|
|
|
3
3
|
type Component = ComponentOptions<Kdu> | typeof Kdu | AsyncComponent;
|
|
4
4
|
type Dictionary<T> = { [key: string]: T };
|
|
5
|
+
type ErrorHandler = (err: Error) => void;
|
|
5
6
|
|
|
6
7
|
export type RouterMode = "hash" | "history" | "abstract";
|
|
7
8
|
export type RawLocation = string | Location;
|
|
8
9
|
export type RedirectOption = RawLocation | ((to: Route) => RawLocation);
|
|
9
|
-
export type NavigationGuard = (
|
|
10
|
+
export type NavigationGuard<V extends Kdu = Kdu> = (
|
|
10
11
|
to: Route,
|
|
11
12
|
from: Route,
|
|
12
|
-
next: (to?: RawLocation | false | ((vm:
|
|
13
|
+
next: (to?: RawLocation | false | ((vm: V) => any) | void) => void
|
|
13
14
|
) => any
|
|
14
15
|
|
|
15
16
|
export declare class KduRouter {
|
|
@@ -22,14 +23,14 @@ export declare class KduRouter {
|
|
|
22
23
|
beforeEach (guard: NavigationGuard): Function;
|
|
23
24
|
beforeResolve (guard: NavigationGuard): Function;
|
|
24
25
|
afterEach (hook: (to: Route, from: Route) => any): Function;
|
|
25
|
-
push (location: RawLocation, onComplete?: Function, onAbort?:
|
|
26
|
-
replace (location: RawLocation, onComplete?: Function, onAbort?:
|
|
26
|
+
push (location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void;
|
|
27
|
+
replace (location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void;
|
|
27
28
|
go (n: number): void;
|
|
28
29
|
back (): void;
|
|
29
30
|
forward (): void;
|
|
30
31
|
getMatchedComponents (to?: RawLocation | Route): Component[];
|
|
31
|
-
onReady (cb: Function, errorCb?:
|
|
32
|
-
onError (cb:
|
|
32
|
+
onReady (cb: Function, errorCb?: ErrorHandler): void;
|
|
33
|
+
onError (cb: ErrorHandler): void;
|
|
33
34
|
addRoutes (routes: RouteConfig[]): void;
|
|
34
35
|
resolve (to: RawLocation, current?: Route, append?: boolean): {
|
|
35
36
|
location: Location;
|
|
@@ -107,7 +108,7 @@ export interface Location {
|
|
|
107
108
|
name?: string;
|
|
108
109
|
path?: string;
|
|
109
110
|
hash?: string;
|
|
110
|
-
query?: Dictionary<string>;
|
|
111
|
+
query?: Dictionary<string | (string | null)[] | null | undefined>;
|
|
111
112
|
params?: Dictionary<string>;
|
|
112
113
|
append?: boolean;
|
|
113
114
|
replace?: boolean;
|
|
@@ -117,7 +118,7 @@ export interface Route {
|
|
|
117
118
|
path: string;
|
|
118
119
|
name?: string;
|
|
119
120
|
hash: string;
|
|
120
|
-
query: Dictionary<string>;
|
|
121
|
+
query: Dictionary<string | (string | null)[]>;
|
|
121
122
|
params: Dictionary<string>;
|
|
122
123
|
fullPath: string;
|
|
123
124
|
matched: RouteRecord[];
|