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.
@@ -0,0 +1,149 @@
1
+ import { warn } from '../util/warn'
2
+ import { extend } from '../util/misc'
3
+
4
+ export default {
5
+ name: 'RouterView',
6
+ functional: true,
7
+ props: {
8
+ name: {
9
+ type: String,
10
+ default: 'default'
11
+ }
12
+ },
13
+ render (_, { props, children, parent, data }) {
14
+ // used by devtools to display a router-view badge
15
+ data.routerView = true
16
+
17
+ // directly use parent context's createElement() function
18
+ // so that components rendered by router-view can resolve named slots
19
+ const h = parent.$createElement
20
+ const name = props.name
21
+ const route = parent.$route
22
+ const cache = parent._routerViewCache || (parent._routerViewCache = {})
23
+
24
+ // determine current view depth, also check to see if the tree
25
+ // has been toggled inactive but kept-alive.
26
+ let depth = 0
27
+ let inactive = false
28
+ while (parent && parent._routerRoot !== parent) {
29
+ const knodeData = parent.$knode ? parent.$knode.data : {}
30
+ if (knodeData.routerView) {
31
+ depth++
32
+ }
33
+ if (knodeData.keepAlive && parent._directInactive && parent._inactive) {
34
+ inactive = true
35
+ }
36
+ parent = parent.$parent
37
+ }
38
+ data.routerViewDepth = depth
39
+
40
+ // render previous view if the tree is inactive and kept-alive
41
+ if (inactive) {
42
+ const cachedData = cache[name]
43
+ const cachedComponent = cachedData && cachedData.component
44
+ if (cachedComponent) {
45
+ // #2301
46
+ // pass props
47
+ if (cachedData.configProps) {
48
+ fillPropsinData(cachedComponent, data, cachedData.route, cachedData.configProps)
49
+ }
50
+ return h(cachedComponent, data, children)
51
+ } else {
52
+ // render previous empty view
53
+ return h()
54
+ }
55
+ }
56
+
57
+ const matched = route.matched[depth]
58
+ const component = matched && matched.components[name]
59
+
60
+ // render empty node if no matched route or no config component
61
+ if (!matched || !component) {
62
+ cache[name] = null
63
+ return h()
64
+ }
65
+
66
+ // cache component
67
+ cache[name] = { component }
68
+
69
+ // attach instance registration hook
70
+ // this will be called in the instance's injected lifecycle hooks
71
+ data.registerRouteInstance = (vm, val) => {
72
+ // val could be undefined for unregistration
73
+ const current = matched.instances[name]
74
+ if (
75
+ (val && current !== vm) ||
76
+ (!val && current === vm)
77
+ ) {
78
+ matched.instances[name] = val
79
+ }
80
+ }
81
+
82
+ // also register instance in prepatch hook
83
+ // in case the same component instance is reused across different routes
84
+ ;(data.hook || (data.hook = {})).prepatch = (_, knode) => {
85
+ matched.instances[name] = knode.componentInstance
86
+ }
87
+
88
+ // register instance in init hook
89
+ // in case kept-alive component be actived when routes changed
90
+ data.hook.init = (knode) => {
91
+ if (knode.data.keepAlive &&
92
+ knode.componentInstance &&
93
+ knode.componentInstance !== matched.instances[name]
94
+ ) {
95
+ matched.instances[name] = knode.componentInstance
96
+ }
97
+ }
98
+
99
+ const configProps = matched.props && matched.props[name]
100
+ // save route and configProps in cache
101
+ if (configProps) {
102
+ extend(cache[name], {
103
+ route,
104
+ configProps
105
+ })
106
+ fillPropsinData(component, data, route, configProps)
107
+ }
108
+
109
+ return h(component, data, children)
110
+ }
111
+ }
112
+
113
+ function fillPropsinData (component, data, route, configProps) {
114
+ // resolve props
115
+ let propsToPass = data.props = resolveProps(route, configProps)
116
+ if (propsToPass) {
117
+ // clone to prevent mutation
118
+ propsToPass = data.props = extend({}, propsToPass)
119
+ // pass non-declared props as attrs
120
+ const attrs = data.attrs = data.attrs || {}
121
+ for (const key in propsToPass) {
122
+ if (!component.props || !(key in component.props)) {
123
+ attrs[key] = propsToPass[key]
124
+ delete propsToPass[key]
125
+ }
126
+ }
127
+ }
128
+ }
129
+
130
+ function resolveProps (route, config) {
131
+ switch (typeof config) {
132
+ case 'undefined':
133
+ return
134
+ case 'object':
135
+ return config
136
+ case 'function':
137
+ return config(route)
138
+ case 'boolean':
139
+ return config ? route.params : undefined
140
+ default:
141
+ if (process.env.NODE_ENV !== 'production') {
142
+ warn(
143
+ false,
144
+ `props in "${route.path}" is a ${typeof config}, ` +
145
+ `expecting an object, function or boolean.`
146
+ )
147
+ }
148
+ }
149
+ }
@@ -1,200 +1,200 @@
1
- /* @flow */
2
-
3
- import type KduRouter from './index'
4
- import { resolvePath } from './util/path'
5
- import { assert, warn } from './util/warn'
6
- import { createRoute } from './util/route'
7
- import { fillParams } from './util/params'
8
- import { createRouteMap } from './create-route-map'
9
- import { normalizeLocation } from './util/location'
10
-
11
- export type Matcher = {
12
- match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route;
13
- addRoutes: (routes: Array<RouteConfig>) => void;
14
- };
15
-
16
- export function createMatcher (
17
- routes: Array<RouteConfig>,
18
- router: KduRouter
19
- ): Matcher {
20
- const { pathList, pathMap, nameMap } = createRouteMap(routes)
21
-
22
- function addRoutes (routes) {
23
- createRouteMap(routes, pathList, pathMap, nameMap)
24
- }
25
-
26
- function match (
27
- raw: RawLocation,
28
- currentRoute?: Route,
29
- redirectedFrom?: Location
30
- ): Route {
31
- const location = normalizeLocation(raw, currentRoute, false, router)
32
- const { name } = location
33
-
34
- if (name) {
35
- const record = nameMap[name]
36
- if (process.env.NODE_ENV !== 'production') {
37
- warn(record, `Route with name '${name}' does not exist`)
38
- }
39
- if (!record) return _createRoute(null, location)
40
- const paramNames = record.regex.keys
41
- .filter(key => !key.optional)
42
- .map(key => key.name)
43
-
44
- if (typeof location.params !== 'object') {
45
- location.params = {}
46
- }
47
-
48
- if (currentRoute && typeof currentRoute.params === 'object') {
49
- for (const key in currentRoute.params) {
50
- if (!(key in location.params) && paramNames.indexOf(key) > -1) {
51
- location.params[key] = currentRoute.params[key]
52
- }
53
- }
54
- }
55
-
56
- location.path = fillParams(record.path, location.params, `named route "${name}"`)
57
- return _createRoute(record, location, redirectedFrom)
58
- } else if (location.path) {
59
- location.params = {}
60
- for (let i = 0; i < pathList.length; i++) {
61
- const path = pathList[i]
62
- const record = pathMap[path]
63
- if (matchRoute(record.regex, location.path, location.params)) {
64
- return _createRoute(record, location, redirectedFrom)
65
- }
66
- }
67
- }
68
- // no match
69
- return _createRoute(null, location)
70
- }
71
-
72
- function redirect (
73
- record: RouteRecord,
74
- location: Location
75
- ): Route {
76
- const originalRedirect = record.redirect
77
- let redirect = typeof originalRedirect === 'function'
78
- ? originalRedirect(createRoute(record, location, null, router))
79
- : originalRedirect
80
-
81
- if (typeof redirect === 'string') {
82
- redirect = { path: redirect }
83
- }
84
-
85
- if (!redirect || typeof redirect !== 'object') {
86
- if (process.env.NODE_ENV !== 'production') {
87
- warn(
88
- false, `invalid redirect option: ${JSON.stringify(redirect)}`
89
- )
90
- }
91
- return _createRoute(null, location)
92
- }
93
-
94
- const re: Object = redirect
95
- const { name, path } = re
96
- let { query, hash, params } = location
97
- query = re.hasOwnProperty('query') ? re.query : query
98
- hash = re.hasOwnProperty('hash') ? re.hash : hash
99
- params = re.hasOwnProperty('params') ? re.params : params
100
-
101
- if (name) {
102
- // resolved named direct
103
- const targetRecord = nameMap[name]
104
- if (process.env.NODE_ENV !== 'production') {
105
- assert(targetRecord, `redirect failed: named route "${name}" not found.`)
106
- }
107
- return match({
108
- _normalized: true,
109
- name,
110
- query,
111
- hash,
112
- params
113
- }, undefined, location)
114
- } else if (path) {
115
- // 1. resolve relative redirect
116
- const rawPath = resolveRecordPath(path, record)
117
- // 2. resolve params
118
- const resolvedPath = fillParams(rawPath, params, `redirect route with path "${rawPath}"`)
119
- // 3. rematch with existing query and hash
120
- return match({
121
- _normalized: true,
122
- path: resolvedPath,
123
- query,
124
- hash
125
- }, undefined, location)
126
- } else {
127
- if (process.env.NODE_ENV !== 'production') {
128
- warn(false, `invalid redirect option: ${JSON.stringify(redirect)}`)
129
- }
130
- return _createRoute(null, location)
131
- }
132
- }
133
-
134
- function alias (
135
- record: RouteRecord,
136
- location: Location,
137
- matchAs: string
138
- ): Route {
139
- const aliasedPath = fillParams(matchAs, location.params, `aliased route with path "${matchAs}"`)
140
- const aliasedMatch = match({
141
- _normalized: true,
142
- path: aliasedPath
143
- })
144
- if (aliasedMatch) {
145
- const matched = aliasedMatch.matched
146
- const aliasedRecord = matched[matched.length - 1]
147
- location.params = aliasedMatch.params
148
- return _createRoute(aliasedRecord, location)
149
- }
150
- return _createRoute(null, location)
151
- }
152
-
153
- function _createRoute (
154
- record: ?RouteRecord,
155
- location: Location,
156
- redirectedFrom?: Location
157
- ): Route {
158
- if (record && record.redirect) {
159
- return redirect(record, redirectedFrom || location)
160
- }
161
- if (record && record.matchAs) {
162
- return alias(record, location, record.matchAs)
163
- }
164
- return createRoute(record, location, redirectedFrom, router)
165
- }
166
-
167
- return {
168
- match,
169
- addRoutes
170
- }
171
- }
172
-
173
- function matchRoute (
174
- regex: RouteRegExp,
175
- path: string,
176
- params: Object
177
- ): boolean {
178
- const m = path.match(regex)
179
-
180
- if (!m) {
181
- return false
182
- } else if (!params) {
183
- return true
184
- }
185
-
186
- for (let i = 1, len = m.length; i < len; ++i) {
187
- const key = regex.keys[i - 1]
188
- const val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i]
189
- if (key) {
190
- // Fix #1994: using * with props: true generates a param named 0
191
- params[key.name || 'pathMatch'] = val
192
- }
193
- }
194
-
195
- return true
196
- }
197
-
198
- function resolveRecordPath (path: string, record: RouteRecord): string {
199
- return resolvePath(path, record.parent ? record.parent.path : '/', true)
200
- }
1
+ /* @flow */
2
+
3
+ import type KduRouter from './index'
4
+ import { resolvePath } from './util/path'
5
+ import { assert, warn } from './util/warn'
6
+ import { createRoute } from './util/route'
7
+ import { fillParams } from './util/params'
8
+ import { createRouteMap } from './create-route-map'
9
+ import { normalizeLocation } from './util/location'
10
+
11
+ export type Matcher = {
12
+ match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route;
13
+ addRoutes: (routes: Array<RouteConfig>) => void;
14
+ };
15
+
16
+ export function createMatcher (
17
+ routes: Array<RouteConfig>,
18
+ router: KduRouter
19
+ ): Matcher {
20
+ const { pathList, pathMap, nameMap } = createRouteMap(routes)
21
+
22
+ function addRoutes (routes) {
23
+ createRouteMap(routes, pathList, pathMap, nameMap)
24
+ }
25
+
26
+ function match (
27
+ raw: RawLocation,
28
+ currentRoute?: Route,
29
+ redirectedFrom?: Location
30
+ ): Route {
31
+ const location = normalizeLocation(raw, currentRoute, false, router)
32
+ const { name } = location
33
+
34
+ if (name) {
35
+ const record = nameMap[name]
36
+ if (process.env.NODE_ENV !== 'production') {
37
+ warn(record, `Route with name '${name}' does not exist`)
38
+ }
39
+ if (!record) return _createRoute(null, location)
40
+ const paramNames = record.regex.keys
41
+ .filter(key => !key.optional)
42
+ .map(key => key.name)
43
+
44
+ if (typeof location.params !== 'object') {
45
+ location.params = {}
46
+ }
47
+
48
+ if (currentRoute && typeof currentRoute.params === 'object') {
49
+ for (const key in currentRoute.params) {
50
+ if (!(key in location.params) && paramNames.indexOf(key) > -1) {
51
+ location.params[key] = currentRoute.params[key]
52
+ }
53
+ }
54
+ }
55
+
56
+ location.path = fillParams(record.path, location.params, `named route "${name}"`)
57
+ return _createRoute(record, location, redirectedFrom)
58
+ } else if (location.path) {
59
+ location.params = {}
60
+ for (let i = 0; i < pathList.length; i++) {
61
+ const path = pathList[i]
62
+ const record = pathMap[path]
63
+ if (matchRoute(record.regex, location.path, location.params)) {
64
+ return _createRoute(record, location, redirectedFrom)
65
+ }
66
+ }
67
+ }
68
+ // no match
69
+ return _createRoute(null, location)
70
+ }
71
+
72
+ function redirect (
73
+ record: RouteRecord,
74
+ location: Location
75
+ ): Route {
76
+ const originalRedirect = record.redirect
77
+ let redirect = typeof originalRedirect === 'function'
78
+ ? originalRedirect(createRoute(record, location, null, router))
79
+ : originalRedirect
80
+
81
+ if (typeof redirect === 'string') {
82
+ redirect = { path: redirect }
83
+ }
84
+
85
+ if (!redirect || typeof redirect !== 'object') {
86
+ if (process.env.NODE_ENV !== 'production') {
87
+ warn(
88
+ false, `invalid redirect option: ${JSON.stringify(redirect)}`
89
+ )
90
+ }
91
+ return _createRoute(null, location)
92
+ }
93
+
94
+ const re: Object = redirect
95
+ const { name, path } = re
96
+ let { query, hash, params } = location
97
+ query = re.hasOwnProperty('query') ? re.query : query
98
+ hash = re.hasOwnProperty('hash') ? re.hash : hash
99
+ params = re.hasOwnProperty('params') ? re.params : params
100
+
101
+ if (name) {
102
+ // resolved named direct
103
+ const targetRecord = nameMap[name]
104
+ if (process.env.NODE_ENV !== 'production') {
105
+ assert(targetRecord, `redirect failed: named route "${name}" not found.`)
106
+ }
107
+ return match({
108
+ _normalized: true,
109
+ name,
110
+ query,
111
+ hash,
112
+ params
113
+ }, undefined, location)
114
+ } else if (path) {
115
+ // 1. resolve relative redirect
116
+ const rawPath = resolveRecordPath(path, record)
117
+ // 2. resolve params
118
+ const resolvedPath = fillParams(rawPath, params, `redirect route with path "${rawPath}"`)
119
+ // 3. rematch with existing query and hash
120
+ return match({
121
+ _normalized: true,
122
+ path: resolvedPath,
123
+ query,
124
+ hash
125
+ }, undefined, location)
126
+ } else {
127
+ if (process.env.NODE_ENV !== 'production') {
128
+ warn(false, `invalid redirect option: ${JSON.stringify(redirect)}`)
129
+ }
130
+ return _createRoute(null, location)
131
+ }
132
+ }
133
+
134
+ function alias (
135
+ record: RouteRecord,
136
+ location: Location,
137
+ matchAs: string
138
+ ): Route {
139
+ const aliasedPath = fillParams(matchAs, location.params, `aliased route with path "${matchAs}"`)
140
+ const aliasedMatch = match({
141
+ _normalized: true,
142
+ path: aliasedPath
143
+ })
144
+ if (aliasedMatch) {
145
+ const matched = aliasedMatch.matched
146
+ const aliasedRecord = matched[matched.length - 1]
147
+ location.params = aliasedMatch.params
148
+ return _createRoute(aliasedRecord, location)
149
+ }
150
+ return _createRoute(null, location)
151
+ }
152
+
153
+ function _createRoute (
154
+ record: ?RouteRecord,
155
+ location: Location,
156
+ redirectedFrom?: Location
157
+ ): Route {
158
+ if (record && record.redirect) {
159
+ return redirect(record, redirectedFrom || location)
160
+ }
161
+ if (record && record.matchAs) {
162
+ return alias(record, location, record.matchAs)
163
+ }
164
+ return createRoute(record, location, redirectedFrom, router)
165
+ }
166
+
167
+ return {
168
+ match,
169
+ addRoutes
170
+ }
171
+ }
172
+
173
+ function matchRoute (
174
+ regex: RouteRegExp,
175
+ path: string,
176
+ params: Object
177
+ ): boolean {
178
+ const m = path.match(regex)
179
+
180
+ if (!m) {
181
+ return false
182
+ } else if (!params) {
183
+ return true
184
+ }
185
+
186
+ for (let i = 1, len = m.length; i < len; ++i) {
187
+ const key = regex.keys[i - 1]
188
+ const val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i]
189
+ if (key) {
190
+ // Fix #1994: using * with props: true generates a param named 0
191
+ params[key.name || 'pathMatch'] = val
192
+ }
193
+ }
194
+
195
+ return true
196
+ }
197
+
198
+ function resolveRecordPath (path: string, record: RouteRecord): string {
199
+ return resolvePath(path, record.parent ? record.parent.path : '/', true)
200
+ }