kdu-router 3.1.3 → 3.4.0-beta.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/src/index.js CHANGED
@@ -1,261 +1,277 @@
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
- // $flow-disable-line
154
- if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
155
- return new Promise((resolve, reject) => {
156
- this.history.push(location, resolve, reject)
157
- })
158
- } else {
159
- this.history.push(location, onComplete, onAbort)
160
- }
161
- }
162
-
163
- replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
164
- // $flow-disable-line
165
- if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
166
- return new Promise((resolve, reject) => {
167
- this.history.replace(location, resolve, reject)
168
- })
169
- } else {
170
- this.history.replace(location, onComplete, onAbort)
171
- }
172
- }
173
-
174
- go (n: number) {
175
- this.history.go(n)
176
- }
177
-
178
- back () {
179
- this.go(-1)
180
- }
181
-
182
- forward () {
183
- this.go(1)
184
- }
185
-
186
- getMatchedComponents (to?: RawLocation | Route): Array<any> {
187
- const route: any = to
188
- ? to.matched
189
- ? to
190
- : this.resolve(to).route
191
- : this.currentRoute
192
- if (!route) {
193
- return []
194
- }
195
- return [].concat.apply([], route.matched.map(m => {
196
- return Object.keys(m.components).map(key => {
197
- return m.components[key]
198
- })
199
- }))
200
- }
201
-
202
- resolve (
203
- to: RawLocation,
204
- current?: Route,
205
- append?: boolean
206
- ): {
207
- location: Location,
208
- route: Route,
209
- href: string,
210
- // for backwards compat
211
- normalizedTo: Location,
212
- resolved: Route
213
- } {
214
- current = current || this.history.current
215
- const location = normalizeLocation(
216
- to,
217
- current,
218
- append,
219
- this
220
- )
221
- const route = this.match(location, current)
222
- const fullPath = route.redirectedFrom || route.fullPath
223
- const base = this.history.base
224
- const href = createHref(base, fullPath, this.mode)
225
- return {
226
- location,
227
- route,
228
- href,
229
- // for backwards compat
230
- normalizedTo: location,
231
- resolved: route
232
- }
233
- }
234
-
235
- addRoutes (routes: Array<RouteConfig>) {
236
- this.matcher.addRoutes(routes)
237
- if (this.history.current !== START) {
238
- this.history.transitionTo(this.history.getCurrentLocation())
239
- }
240
- }
241
- }
242
-
243
- function registerHook (list: Array<any>, fn: Function): Function {
244
- list.push(fn)
245
- return () => {
246
- const i = list.indexOf(fn)
247
- if (i > -1) list.splice(i, 1)
248
- }
249
- }
250
-
251
- function createHref (base: string, fullPath: string, mode) {
252
- var path = mode === 'hash' ? '#' + fullPath : fullPath
253
- return base ? cleanPath(base + '/' + path) : path
254
- }
255
-
256
- KduRouter.install = install
257
- KduRouter.version = '__VERSION__'
258
-
259
- if (inBrowser && window.Kdu) {
260
- window.Kdu.use(KduRouter)
261
- }
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
+ import { handleScroll } from './util/scroll'
12
+
13
+ import { HashHistory } from './history/hash'
14
+ import { HTML5History } from './history/html5'
15
+ import { AbstractHistory } from './history/abstract'
16
+
17
+ import type { Matcher } from './create-matcher'
18
+
19
+ import { isNavigationFailure, NavigationFailureType } from './util/errors'
20
+
21
+ export default class KduRouter {
22
+ static install: () => void
23
+ static version: string
24
+ static isNavigationFailure: Function
25
+ static NavigationFailureType: any
26
+
27
+ app: any
28
+ apps: Array<any>
29
+ ready: boolean
30
+ readyCbs: Array<Function>
31
+ options: RouterOptions
32
+ mode: string
33
+ history: HashHistory | HTML5History | AbstractHistory
34
+ matcher: Matcher
35
+ fallback: boolean
36
+ beforeHooks: Array<?NavigationGuard>
37
+ resolveHooks: Array<?NavigationGuard>
38
+ afterHooks: Array<?AfterNavigationHook>
39
+
40
+ constructor (options: RouterOptions = {}) {
41
+ this.app = null
42
+ this.apps = []
43
+ this.options = options
44
+ this.beforeHooks = []
45
+ this.resolveHooks = []
46
+ this.afterHooks = []
47
+ this.matcher = createMatcher(options.routes || [], this)
48
+
49
+ let mode = options.mode || 'hash'
50
+ this.fallback =
51
+ mode === 'history' && !supportsPushState && options.fallback !== false
52
+ if (this.fallback) {
53
+ mode = 'hash'
54
+ }
55
+ if (!inBrowser) {
56
+ mode = 'abstract'
57
+ }
58
+ this.mode = mode
59
+
60
+ switch (mode) {
61
+ case 'history':
62
+ this.history = new HTML5History(this, options.base)
63
+ break
64
+ case 'hash':
65
+ this.history = new HashHistory(this, options.base, this.fallback)
66
+ break
67
+ case 'abstract':
68
+ this.history = new AbstractHistory(this, options.base)
69
+ break
70
+ default:
71
+ if (process.env.NODE_ENV !== 'production') {
72
+ assert(false, `invalid mode: ${mode}`)
73
+ }
74
+ }
75
+ }
76
+
77
+ match (raw: RawLocation, current?: Route, redirectedFrom?: Location): Route {
78
+ return this.matcher.match(raw, current, redirectedFrom)
79
+ }
80
+
81
+ get currentRoute (): ?Route {
82
+ return this.history && this.history.current
83
+ }
84
+
85
+ init (app: any /* Kdu component instance */) {
86
+ process.env.NODE_ENV !== 'production' &&
87
+ assert(
88
+ install.installed,
89
+ `not installed. Make sure to call \`Kdu.use(KduRouter)\` ` +
90
+ `before creating root instance.`
91
+ )
92
+
93
+ this.apps.push(app)
94
+
95
+ // set up app destroyed handler
96
+ app.$once('hook:destroyed', () => {
97
+ // clean out app from this.apps array once destroyed
98
+ const index = this.apps.indexOf(app)
99
+ if (index > -1) this.apps.splice(index, 1)
100
+ // ensure we still have a main app or null if no apps
101
+ // we do not release the router so it can be reused
102
+ if (this.app === app) this.app = this.apps[0] || null
103
+
104
+ if (!this.app) {
105
+ // clean up event listeners
106
+ this.history.teardownListeners()
107
+ }
108
+ })
109
+
110
+ // main app previously initialized
111
+ // return as we don't need to set up new history listener
112
+ if (this.app) {
113
+ return
114
+ }
115
+
116
+ this.app = app
117
+
118
+ const history = this.history
119
+
120
+ if (history instanceof HTML5History || history instanceof HashHistory) {
121
+ const handleInitialScroll = routeOrError => {
122
+ const from = history.current
123
+ const expectScroll = this.options.scrollBehavior
124
+ const supportsScroll = supportsPushState && expectScroll
125
+
126
+ if (supportsScroll && 'fullPath' in routeOrError) {
127
+ handleScroll(this, routeOrError, from, false)
128
+ }
129
+ }
130
+ const setupListeners = routeOrError => {
131
+ history.setupListeners()
132
+ handleInitialScroll(routeOrError)
133
+ }
134
+ history.transitionTo(
135
+ history.getCurrentLocation(),
136
+ setupListeners,
137
+ setupListeners
138
+ )
139
+ }
140
+
141
+ history.listen(route => {
142
+ this.apps.forEach(app => {
143
+ app._route = route
144
+ })
145
+ })
146
+ }
147
+
148
+ beforeEach (fn: Function): Function {
149
+ return registerHook(this.beforeHooks, fn)
150
+ }
151
+
152
+ beforeResolve (fn: Function): Function {
153
+ return registerHook(this.resolveHooks, fn)
154
+ }
155
+
156
+ afterEach (fn: Function): Function {
157
+ return registerHook(this.afterHooks, fn)
158
+ }
159
+
160
+ onReady (cb: Function, errorCb?: Function) {
161
+ this.history.onReady(cb, errorCb)
162
+ }
163
+
164
+ onError (errorCb: Function) {
165
+ this.history.onError(errorCb)
166
+ }
167
+
168
+ push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
169
+ // $flow-disable-line
170
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
171
+ return new Promise((resolve, reject) => {
172
+ this.history.push(location, resolve, reject)
173
+ })
174
+ } else {
175
+ this.history.push(location, onComplete, onAbort)
176
+ }
177
+ }
178
+
179
+ replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
180
+ // $flow-disable-line
181
+ if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
182
+ return new Promise((resolve, reject) => {
183
+ this.history.replace(location, resolve, reject)
184
+ })
185
+ } else {
186
+ this.history.replace(location, onComplete, onAbort)
187
+ }
188
+ }
189
+
190
+ go (n: number) {
191
+ this.history.go(n)
192
+ }
193
+
194
+ back () {
195
+ this.go(-1)
196
+ }
197
+
198
+ forward () {
199
+ this.go(1)
200
+ }
201
+
202
+ getMatchedComponents (to?: RawLocation | Route): Array<any> {
203
+ const route: any = to
204
+ ? to.matched
205
+ ? to
206
+ : this.resolve(to).route
207
+ : this.currentRoute
208
+ if (!route) {
209
+ return []
210
+ }
211
+ return [].concat.apply(
212
+ [],
213
+ route.matched.map(m => {
214
+ return Object.keys(m.components).map(key => {
215
+ return m.components[key]
216
+ })
217
+ })
218
+ )
219
+ }
220
+
221
+ resolve (
222
+ to: RawLocation,
223
+ current?: Route,
224
+ append?: boolean
225
+ ): {
226
+ location: Location,
227
+ route: Route,
228
+ href: string,
229
+ // for backwards compat
230
+ normalizedTo: Location,
231
+ resolved: Route
232
+ } {
233
+ current = current || this.history.current
234
+ const location = normalizeLocation(to, current, append, this)
235
+ const route = this.match(location, current)
236
+ const fullPath = route.redirectedFrom || route.fullPath
237
+ const base = this.history.base
238
+ const href = createHref(base, fullPath, this.mode)
239
+ return {
240
+ location,
241
+ route,
242
+ href,
243
+ // for backwards compat
244
+ normalizedTo: location,
245
+ resolved: route
246
+ }
247
+ }
248
+
249
+ addRoutes (routes: Array<RouteConfig>) {
250
+ this.matcher.addRoutes(routes)
251
+ if (this.history.current !== START) {
252
+ this.history.transitionTo(this.history.getCurrentLocation())
253
+ }
254
+ }
255
+ }
256
+
257
+ function registerHook (list: Array<any>, fn: Function): Function {
258
+ list.push(fn)
259
+ return () => {
260
+ const i = list.indexOf(fn)
261
+ if (i > -1) list.splice(i, 1)
262
+ }
263
+ }
264
+
265
+ function createHref (base: string, fullPath: string, mode) {
266
+ var path = mode === 'hash' ? '#' + fullPath : fullPath
267
+ return base ? cleanPath(base + '/' + path) : path
268
+ }
269
+
270
+ KduRouter.install = install
271
+ KduRouter.version = '__VERSION__'
272
+ KduRouter.isNavigationFailure = isNavigationFailure
273
+ KduRouter.NavigationFailureType = NavigationFailureType
274
+
275
+ if (inBrowser && window.Kdu) {
276
+ window.Kdu.use(KduRouter)
277
+ }
package/src/install.js CHANGED
@@ -1,52 +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._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('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
- }
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
+ }
@@ -0,0 +1,18 @@
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
+ }