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/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: Kdu) => any) | void) => void
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?: Function): void;
26
- replace (location: RawLocation, onComplete?: Function, onAbort?: Function): void;
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?: Function): void;
32
- onError (cb: Function): void;
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[];