vuejs-rails 1.0.26 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,2709 +1,1837 @@
1
- /*!
2
- * vue-router v0.7.13
1
+ /**
2
+ * vue-router v2.0.0
3
3
  * (c) 2016 Evan You
4
- * Released under the MIT License.
4
+ * @license MIT
5
5
  */
6
6
  (function (global, factory) {
7
7
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
8
8
  typeof define === 'function' && define.amd ? define(factory) :
9
- global.VueRouter = factory();
10
- }(this, function () { 'use strict';
11
-
12
- var babelHelpers = {};
13
-
14
- babelHelpers.classCallCheck = function (instance, Constructor) {
15
- if (!(instance instanceof Constructor)) {
16
- throw new TypeError("Cannot call a class as a function");
9
+ (global.VueRouter = factory());
10
+ }(this, (function () { 'use strict';
11
+
12
+ var View = {
13
+ name: 'router-view',
14
+ functional: true,
15
+ props: {
16
+ name: {
17
+ type: String,
18
+ default: 'default'
17
19
  }
18
- };
19
- function Target(path, matcher, delegate) {
20
- this.path = path;
21
- this.matcher = matcher;
22
- this.delegate = delegate;
23
- }
20
+ },
21
+ render: function render (h, ref) {
22
+ var props = ref.props;
23
+ var children = ref.children;
24
+ var parent = ref.parent;
25
+ var data = ref.data;
24
26
 
25
- Target.prototype = {
26
- to: function to(target, callback) {
27
- var delegate = this.delegate;
27
+ data.routerView = true
28
28
 
29
- if (delegate && delegate.willAddRoute) {
30
- target = delegate.willAddRoute(this.matcher.target, target);
29
+ var route = parent.$route
30
+ var cache = parent._routerViewCache || (parent._routerViewCache = {})
31
+ var depth = 0
32
+ var inactive = false
33
+
34
+ while (parent) {
35
+ if (parent.$vnode && parent.$vnode.data.routerView) {
36
+ depth++
37
+ }
38
+ if (parent._inactive) {
39
+ inactive = true
31
40
  }
41
+ parent = parent.$parent
42
+ }
32
43
 
33
- this.matcher.add(this.path, target);
44
+ data.routerViewDepth = depth
45
+ var matched = route.matched[depth]
46
+ if (!matched) {
47
+ return h()
48
+ }
34
49
 
35
- if (callback) {
36
- if (callback.length === 0) {
37
- throw new Error("You must have an argument in the function passed to `to`");
38
- }
39
- this.matcher.addChild(this.path, target, callback, this.delegate);
50
+ var component = inactive
51
+ ? cache[props.name]
52
+ : (cache[props.name] = matched.components[props.name])
53
+
54
+ if (!inactive) {
55
+ (data.hook || (data.hook = {})).init = function (vnode) {
56
+ matched.instances[props.name] = vnode.child
40
57
  }
41
- return this;
42
58
  }
43
- };
44
59
 
45
- function Matcher(target) {
46
- this.routes = {};
47
- this.children = {};
48
- this.target = target;
60
+ return h(component, data, children)
49
61
  }
62
+ }
50
63
 
51
- Matcher.prototype = {
52
- add: function add(path, handler) {
53
- this.routes[path] = handler;
54
- },
55
-
56
- addChild: function addChild(path, target, callback, delegate) {
57
- var matcher = new Matcher(target);
58
- this.children[path] = matcher;
59
-
60
- var match = generateMatch(path, matcher, delegate);
64
+ /* */
61
65
 
62
- if (delegate && delegate.contextEntered) {
63
- delegate.contextEntered(target, match);
64
- }
66
+ function resolvePath (
67
+ relative,
68
+ base,
69
+ append
70
+ ) {
71
+ if (relative.charAt(0) === '/') {
72
+ return relative
73
+ }
65
74
 
66
- callback(match);
67
- }
68
- };
75
+ if (relative.charAt(0) === '?' || relative.charAt(0) === '#') {
76
+ return base + relative
77
+ }
69
78
 
70
- function generateMatch(startingPath, matcher, delegate) {
71
- return function (path, nestedCallback) {
72
- var fullPath = startingPath + path;
79
+ var stack = base.split('/')
73
80
 
74
- if (nestedCallback) {
75
- nestedCallback(generateMatch(fullPath, matcher, delegate));
76
- } else {
77
- return new Target(startingPath + path, matcher, delegate);
78
- }
79
- };
81
+ // remove trailing segment if:
82
+ // - not appending
83
+ // - appending to trailing slash (last segment is empty)
84
+ if (!append || !stack[stack.length - 1]) {
85
+ stack.pop()
80
86
  }
81
87
 
82
- function addRoute(routeArray, path, handler) {
83
- var len = 0;
84
- for (var i = 0, l = routeArray.length; i < l; i++) {
85
- len += routeArray[i].path.length;
88
+ // resolve relative path
89
+ var segments = relative.replace(/^\//, '').split('/')
90
+ for (var i = 0; i < segments.length; i++) {
91
+ var segment = segments[i]
92
+ if (segment === '.') {
93
+ continue
94
+ } else if (segment === '..') {
95
+ stack.pop()
96
+ } else {
97
+ stack.push(segment)
86
98
  }
99
+ }
87
100
 
88
- path = path.substr(len);
89
- var route = { path: path, handler: handler };
90
- routeArray.push(route);
101
+ // ensure leading slash
102
+ if (stack[0] !== '') {
103
+ stack.unshift('')
91
104
  }
92
105
 
93
- function eachRoute(baseRoute, matcher, callback, binding) {
94
- var routes = matcher.routes;
106
+ return stack.join('/')
107
+ }
95
108
 
96
- for (var path in routes) {
97
- if (routes.hasOwnProperty(path)) {
98
- var routeArray = baseRoute.slice();
99
- addRoute(routeArray, path, routes[path]);
109
+ function parsePath (path) {
110
+ var hash = ''
111
+ var query = ''
100
112
 
101
- if (matcher.children[path]) {
102
- eachRoute(routeArray, matcher.children[path], callback, binding);
103
- } else {
104
- callback.call(binding, routeArray);
105
- }
106
- }
107
- }
113
+ var hashIndex = path.indexOf('#')
114
+ if (hashIndex >= 0) {
115
+ hash = path.slice(hashIndex)
116
+ path = path.slice(0, hashIndex)
108
117
  }
109
118
 
110
- function map (callback, addRouteCallback) {
111
- var matcher = new Matcher();
112
-
113
- callback(generateMatch("", matcher, this.delegate));
119
+ var queryIndex = path.indexOf('?')
120
+ if (queryIndex >= 0) {
121
+ query = path.slice(queryIndex + 1)
122
+ path = path.slice(0, queryIndex)
123
+ }
114
124
 
115
- eachRoute([], matcher, function (route) {
116
- if (addRouteCallback) {
117
- addRouteCallback(this, route);
118
- } else {
119
- this.add(route);
120
- }
121
- }, this);
125
+ return {
126
+ path: path,
127
+ query: query,
128
+ hash: hash
122
129
  }
130
+ }
123
131
 
124
- var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'];
132
+ function cleanPath (path) {
133
+ return path.replace(/\/\//g, '/')
134
+ }
125
135
 
126
- var escapeRegex = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
136
+ /* */
127
137
 
128
- var noWarning = false;
129
- function warn(msg) {
130
- if (!noWarning && typeof console !== 'undefined') {
131
- console.error('[vue-router] ' + msg);
132
- }
138
+ function assert (condition, message) {
139
+ if (!condition) {
140
+ throw new Error(("[vue-router] " + message))
133
141
  }
142
+ }
134
143
 
135
- function tryDecode(uri, asComponent) {
136
- try {
137
- return asComponent ? decodeURIComponent(uri) : decodeURI(uri);
138
- } catch (e) {
139
- warn('malformed URI' + (asComponent ? ' component: ' : ': ') + uri);
140
- }
144
+ function warn (condition, message) {
145
+ if (!condition) {
146
+ typeof console !== 'undefined' && console.warn(("[vue-router] " + message))
141
147
  }
148
+ }
142
149
 
143
- function isArray(test) {
144
- return Object.prototype.toString.call(test) === "[object Array]";
145
- }
150
+ /* */
146
151
 
147
- // A Segment represents a segment in the original route description.
148
- // Each Segment type provides an `eachChar` and `regex` method.
149
- //
150
- // The `eachChar` method invokes the callback with one or more character
151
- // specifications. A character specification consumes one or more input
152
- // characters.
153
- //
154
- // The `regex` method returns a regex fragment for the segment. If the
155
- // segment is a dynamic of star segment, the regex fragment also includes
156
- // a capture.
157
- //
158
- // A character specification contains:
159
- //
160
- // * `validChars`: a String with a list of all valid characters, or
161
- // * `invalidChars`: a String with a list of all invalid characters
162
- // * `repeat`: true if the character specification can repeat
152
+ var encode = encodeURIComponent
153
+ var decode = decodeURIComponent
163
154
 
164
- function StaticSegment(string) {
165
- this.string = string;
166
- }
167
- StaticSegment.prototype = {
168
- eachChar: function eachChar(callback) {
169
- var string = this.string,
170
- ch;
155
+ function resolveQuery (
156
+ query,
157
+ extraQuery
158
+ ) {
159
+ if ( extraQuery === void 0 ) extraQuery = {};
171
160
 
172
- for (var i = 0, l = string.length; i < l; i++) {
173
- ch = string.charAt(i);
174
- callback({ validChars: ch });
175
- }
176
- },
161
+ if (query) {
162
+ var parsedQuery
163
+ try {
164
+ parsedQuery = parseQuery(query)
165
+ } catch (e) {
166
+ warn(false, e.message)
167
+ parsedQuery = {}
168
+ }
169
+ for (var key in extraQuery) {
170
+ parsedQuery[key] = extraQuery[key]
171
+ }
172
+ return parsedQuery
173
+ } else {
174
+ return extraQuery
175
+ }
176
+ }
177
177
 
178
- regex: function regex() {
179
- return this.string.replace(escapeRegex, '\\$1');
180
- },
178
+ function parseQuery (query) {
179
+ var res = Object.create(null)
181
180
 
182
- generate: function generate() {
183
- return this.string;
184
- }
185
- };
181
+ query = query.trim().replace(/^(\?|#|&)/, '')
186
182
 
187
- function DynamicSegment(name) {
188
- this.name = name;
183
+ if (!query) {
184
+ return res
189
185
  }
190
- DynamicSegment.prototype = {
191
- eachChar: function eachChar(callback) {
192
- callback({ invalidChars: "/", repeat: true });
193
- },
194
186
 
195
- regex: function regex() {
196
- return "([^/]+)";
197
- },
198
-
199
- generate: function generate(params) {
200
- var val = params[this.name];
201
- return val == null ? ":" + this.name : val;
187
+ query.split('&').forEach(function (param) {
188
+ var parts = param.replace(/\+/g, ' ').split('=')
189
+ var key = decode(parts.shift())
190
+ var val = parts.length > 0
191
+ ? decode(parts.join('='))
192
+ : null
193
+
194
+ if (res[key] === undefined) {
195
+ res[key] = val
196
+ } else if (Array.isArray(res[key])) {
197
+ res[key].push(val)
198
+ } else {
199
+ res[key] = [res[key], val]
202
200
  }
203
- };
201
+ })
204
202
 
205
- function StarSegment(name) {
206
- this.name = name;
207
- }
208
- StarSegment.prototype = {
209
- eachChar: function eachChar(callback) {
210
- callback({ invalidChars: "", repeat: true });
211
- },
203
+ return res
204
+ }
212
205
 
213
- regex: function regex() {
214
- return "(.+)";
215
- },
206
+ function stringifyQuery (obj) {
207
+ var res = obj ? Object.keys(obj).sort().map(function (key) {
208
+ var val = obj[key]
216
209
 
217
- generate: function generate(params) {
218
- var val = params[this.name];
219
- return val == null ? ":" + this.name : val;
210
+ if (val === undefined) {
211
+ return ''
220
212
  }
221
- };
222
213
 
223
- function EpsilonSegment() {}
224
- EpsilonSegment.prototype = {
225
- eachChar: function eachChar() {},
226
- regex: function regex() {
227
- return "";
228
- },
229
- generate: function generate() {
230
- return "";
214
+ if (val === null) {
215
+ return encode(key)
231
216
  }
232
- };
233
217
 
234
- function parse(route, names, specificity) {
235
- // normalize route as not starting with a "/". Recognition will
236
- // also normalize.
237
- if (route.charAt(0) === "/") {
238
- route = route.substr(1);
218
+ if (Array.isArray(val)) {
219
+ var result = []
220
+ val.slice().forEach(function (val2) {
221
+ if (val2 === undefined) {
222
+ return
223
+ }
224
+ if (val2 === null) {
225
+ result.push(encode(key))
226
+ } else {
227
+ result.push(encode(key) + '=' + encode(val2))
228
+ }
229
+ })
230
+ return result.join('&')
239
231
  }
240
232
 
241
- var segments = route.split("/"),
242
- results = [];
243
-
244
- // A routes has specificity determined by the order that its different segments
245
- // appear in. This system mirrors how the magnitude of numbers written as strings
246
- // works.
247
- // Consider a number written as: "abc". An example would be "200". Any other number written
248
- // "xyz" will be smaller than "abc" so long as `a > z`. For instance, "199" is smaller
249
- // then "200", even though "y" and "z" (which are both 9) are larger than "0" (the value
250
- // of (`b` and `c`). This is because the leading symbol, "2", is larger than the other
251
- // leading symbol, "1".
252
- // The rule is that symbols to the left carry more weight than symbols to the right
253
- // when a number is written out as a string. In the above strings, the leading digit
254
- // represents how many 100's are in the number, and it carries more weight than the middle
255
- // number which represents how many 10's are in the number.
256
- // This system of number magnitude works well for route specificity, too. A route written as
257
- // `a/b/c` will be more specific than `x/y/z` as long as `a` is more specific than
258
- // `x`, irrespective of the other parts.
259
- // Because of this similarity, we assign each type of segment a number value written as a
260
- // string. We can find the specificity of compound routes by concatenating these strings
261
- // together, from left to right. After we have looped through all of the segments,
262
- // we convert the string to a number.
263
- specificity.val = '';
264
-
265
- for (var i = 0, l = segments.length; i < l; i++) {
266
- var segment = segments[i],
267
- match;
268
-
269
- if (match = segment.match(/^:([^\/]+)$/)) {
270
- results.push(new DynamicSegment(match[1]));
271
- names.push(match[1]);
272
- specificity.val += '3';
273
- } else if (match = segment.match(/^\*([^\/]+)$/)) {
274
- results.push(new StarSegment(match[1]));
275
- specificity.val += '2';
276
- names.push(match[1]);
277
- } else if (segment === "") {
278
- results.push(new EpsilonSegment());
279
- specificity.val += '1';
280
- } else {
281
- results.push(new StaticSegment(segment));
282
- specificity.val += '4';
283
- }
284
- }
233
+ return encode(key) + '=' + encode(val)
234
+ }).filter(function (x) { return x.length > 0; }).join('&') : null
235
+ return res ? ("?" + res) : ''
236
+ }
237
+
238
+ /* */
239
+
240
+ function createRoute (
241
+ record,
242
+ location,
243
+ redirectedFrom
244
+ ) {
245
+ var route = {
246
+ name: location.name || (record && record.name),
247
+ meta: (record && record.meta) || {},
248
+ path: location.path || '/',
249
+ hash: location.hash || '',
250
+ query: location.query || {},
251
+ params: location.params || {},
252
+ fullPath: getFullPath(location),
253
+ matched: record ? formatMatch(record) : []
254
+ }
255
+ if (redirectedFrom) {
256
+ route.redirectedFrom = getFullPath(redirectedFrom)
257
+ }
258
+ return Object.freeze(route)
259
+ }
260
+
261
+ // the starting route that represents the initial state
262
+ var START = createRoute(null, {
263
+ path: '/'
264
+ })
265
+
266
+ function formatMatch (record) {
267
+ var res = []
268
+ while (record) {
269
+ res.unshift(record)
270
+ record = record.parent
271
+ }
272
+ return res
273
+ }
274
+
275
+ function getFullPath (ref) {
276
+ var path = ref.path;
277
+ var query = ref.query; if ( query === void 0 ) query = {};
278
+ var hash = ref.hash; if ( hash === void 0 ) hash = '';
279
+
280
+ return (path || '/') + stringifyQuery(query) + hash
281
+ }
282
+
283
+ var trailingSlashRE = /\/$/
284
+ function isSameRoute (a, b) {
285
+ if (b === START) {
286
+ return a === b
287
+ } else if (!b) {
288
+ return false
289
+ } else if (a.path && b.path) {
290
+ return (
291
+ a.path.replace(trailingSlashRE, '') === b.path.replace(trailingSlashRE, '') &&
292
+ a.hash === b.hash &&
293
+ isObjectEqual(a.query, b.query)
294
+ )
295
+ } else if (a.name && b.name) {
296
+ return (
297
+ a.name === b.name &&
298
+ a.hash === b.hash &&
299
+ isObjectEqual(a.query, b.query) &&
300
+ isObjectEqual(a.params, b.params)
301
+ )
302
+ } else {
303
+ return false
304
+ }
305
+ }
285
306
 
286
- specificity.val = +specificity.val;
307
+ function isObjectEqual (a, b) {
308
+ if ( a === void 0 ) a = {};
309
+ if ( b === void 0 ) b = {};
287
310
 
288
- return results;
311
+ var aKeys = Object.keys(a)
312
+ var bKeys = Object.keys(b)
313
+ if (aKeys.length !== bKeys.length) {
314
+ return false
315
+ }
316
+ return aKeys.every(function (key) { return String(a[key]) === String(b[key]); })
317
+ }
318
+
319
+ function isIncludedRoute (current, target) {
320
+ return (
321
+ current.path.indexOf(target.path) === 0 &&
322
+ (!target.hash || current.hash === target.hash) &&
323
+ queryIncludes(current.query, target.query)
324
+ )
325
+ }
326
+
327
+ function queryIncludes (current, target) {
328
+ for (var key in target) {
329
+ if (!(key in current)) {
330
+ return false
331
+ }
332
+ }
333
+ return true
334
+ }
335
+
336
+ /* */
337
+
338
+ function normalizeLocation (
339
+ raw,
340
+ current,
341
+ append
342
+ ) {
343
+ var next = typeof raw === 'string' ? { path: raw } : raw
344
+ if (next.name || next._normalized) {
345
+ return next
289
346
  }
290
347
 
291
- // A State has a character specification and (`charSpec`) and a list of possible
292
- // subsequent states (`nextStates`).
293
- //
294
- // If a State is an accepting state, it will also have several additional
295
- // properties:
296
- //
297
- // * `regex`: A regular expression that is used to extract parameters from paths
298
- // that reached this accepting state.
299
- // * `handlers`: Information on how to convert the list of captures into calls
300
- // to registered handlers with the specified parameters
301
- // * `types`: How many static, dynamic or star segments in this route. Used to
302
- // decide which route to use if multiple registered routes match a path.
303
- //
304
- // Currently, State is implemented naively by looping over `nextStates` and
305
- // comparing a character specification against a character. A more efficient
306
- // implementation would use a hash of keys pointing at one or more next states.
307
-
308
- function State(charSpec) {
309
- this.charSpec = charSpec;
310
- this.nextStates = [];
348
+ var parsedPath = parsePath(next.path || '')
349
+ var basePath = (current && current.path) || '/'
350
+ var path = parsedPath.path
351
+ ? resolvePath(parsedPath.path, basePath, append)
352
+ : (current && current.path) || '/'
353
+ var query = resolveQuery(parsedPath.query, next.query)
354
+ var hash = next.hash || parsedPath.hash
355
+ if (hash && hash.charAt(0) !== '#') {
356
+ hash = "#" + hash
311
357
  }
312
358
 
313
- State.prototype = {
314
- get: function get(charSpec) {
315
- var nextStates = this.nextStates;
359
+ return {
360
+ _normalized: true,
361
+ path: path,
362
+ query: query,
363
+ hash: hash
364
+ }
365
+ }
316
366
 
317
- for (var i = 0, l = nextStates.length; i < l; i++) {
318
- var child = nextStates[i];
367
+ /* */
319
368
 
320
- var isEqual = child.charSpec.validChars === charSpec.validChars;
321
- isEqual = isEqual && child.charSpec.invalidChars === charSpec.invalidChars;
369
+ // work around weird flow bug
370
+ var toTypes = [String, Object]
322
371
 
323
- if (isEqual) {
324
- return child;
325
- }
326
- }
372
+ var Link = {
373
+ name: 'router-link',
374
+ props: {
375
+ to: {
376
+ type: toTypes,
377
+ required: true
327
378
  },
328
-
329
- put: function put(charSpec) {
330
- var state;
331
-
332
- // If the character specification already exists in a child of the current
333
- // state, just return that state.
334
- if (state = this.get(charSpec)) {
335
- return state;
336
- }
337
-
338
- // Make a new state for the character spec
339
- state = new State(charSpec);
340
-
341
- // Insert the new state as a child of the current state
342
- this.nextStates.push(state);
343
-
344
- // If this character specification repeats, insert the new state as a child
345
- // of itself. Note that this will not trigger an infinite loop because each
346
- // transition during recognition consumes a character.
347
- if (charSpec.repeat) {
348
- state.nextStates.push(state);
349
- }
350
-
351
- // Return the new state
352
- return state;
379
+ tag: {
380
+ type: String,
381
+ default: 'a'
353
382
  },
354
-
355
- // Find a list of child states matching the next character
356
- match: function match(ch) {
357
- // DEBUG "Processing `" + ch + "`:"
358
- var nextStates = this.nextStates,
359
- child,
360
- charSpec,
361
- chars;
362
-
363
- // DEBUG " " + debugState(this)
364
- var returned = [];
365
-
366
- for (var i = 0, l = nextStates.length; i < l; i++) {
367
- child = nextStates[i];
368
-
369
- charSpec = child.charSpec;
370
-
371
- if (typeof (chars = charSpec.validChars) !== 'undefined') {
372
- if (chars.indexOf(ch) !== -1) {
373
- returned.push(child);
374
- }
375
- } else if (typeof (chars = charSpec.invalidChars) !== 'undefined') {
376
- if (chars.indexOf(ch) === -1) {
377
- returned.push(child);
378
- }
383
+ exact: Boolean,
384
+ append: Boolean,
385
+ replace: Boolean,
386
+ activeClass: String
387
+ },
388
+ render: function render (h) {
389
+ var this$1 = this;
390
+
391
+ var router = this.$router
392
+ var current = this.$route
393
+ var to = normalizeLocation(this.to, current, this.append)
394
+ var resolved = router.match(to)
395
+ var fullPath = resolved.redirectedFrom || resolved.fullPath
396
+ var base = router.history.base
397
+ var href = base ? cleanPath(base + fullPath) : fullPath
398
+ var classes = {}
399
+ var activeClass = this.activeClass || router.options.linkActiveClass || 'router-link-active'
400
+ var compareTarget = to.path ? createRoute(null, to) : resolved
401
+ classes[activeClass] = this.exact
402
+ ? isSameRoute(current, compareTarget)
403
+ : isIncludedRoute(current, compareTarget)
404
+
405
+ var on = {
406
+ click: function (e) {
407
+ e.preventDefault()
408
+ if (this$1.replace) {
409
+ router.replace(to)
410
+ } else {
411
+ router.push(to)
379
412
  }
380
413
  }
414
+ }
381
415
 
382
- return returned;
416
+ var data = {
417
+ class: classes
383
418
  }
384
419
 
385
- /** IF DEBUG
386
- , debug: function() {
387
- var charSpec = this.charSpec,
388
- debug = "[",
389
- chars = charSpec.validChars || charSpec.invalidChars;
390
- if (charSpec.invalidChars) { debug += "^"; }
391
- debug += chars;
392
- debug += "]";
393
- if (charSpec.repeat) { debug += "+"; }
394
- return debug;
420
+ if (this.tag === 'a') {
421
+ data.on = on
422
+ data.attrs = { href: href }
423
+ } else {
424
+ // find the first <a> child and apply listener and href
425
+ var a = findAnchor(this.$slots.default)
426
+ if (a) {
427
+ var aData = a.data || (a.data = {})
428
+ aData.on = on
429
+ var aAttrs = aData.attrs || (aData.attrs = {})
430
+ aAttrs.href = href
431
+ }
395
432
  }
396
- END IF **/
397
- };
398
433
 
399
- /** IF DEBUG
400
- function debug(log) {
401
- console.log(log);
434
+ return h(this.tag, data, this.$slots.default)
402
435
  }
436
+ }
403
437
 
404
- function debugState(state) {
405
- return state.nextStates.map(function(n) {
406
- if (n.nextStates.length === 0) { return "( " + n.debug() + " [accepting] )"; }
407
- return "( " + n.debug() + " <then> " + n.nextStates.map(function(s) { return s.debug() }).join(" or ") + " )";
408
- }).join(", ")
438
+ function findAnchor (children) {
439
+ if (children) {
440
+ var child
441
+ for (var i = 0; i < children.length; i++) {
442
+ child = children[i]
443
+ if (child.tag === 'a') {
444
+ return child
445
+ }
446
+ if (child.children && (child = findAnchor(child.children))) {
447
+ return child
448
+ }
449
+ }
409
450
  }
410
- END IF **/
451
+ }
411
452
 
412
- // Sort the routes by specificity
413
- function sortSolutions(states) {
414
- return states.sort(function (a, b) {
415
- return b.specificity.val - a.specificity.val;
416
- });
417
- }
453
+ function install (Vue) {
454
+ if (install.installed) { return }
455
+ install.installed = true
418
456
 
419
- function recognizeChar(states, ch) {
420
- var nextStates = [];
457
+ Object.defineProperty(Vue.prototype, '$router', {
458
+ get: function get () { return this.$root._router }
459
+ })
421
460
 
422
- for (var i = 0, l = states.length; i < l; i++) {
423
- var state = states[i];
461
+ Object.defineProperty(Vue.prototype, '$route', {
462
+ get: function get$1 () { return this.$root._route }
463
+ })
424
464
 
425
- nextStates = nextStates.concat(state.match(ch));
465
+ Vue.mixin({
466
+ beforeCreate: function beforeCreate () {
467
+ if (this.$options.router) {
468
+ this._router = this.$options.router
469
+ this._router.init(this)
470
+ Vue.util.defineReactive(this, '_route', this._router.history.current)
471
+ }
426
472
  }
473
+ })
427
474
 
428
- return nextStates;
429
- }
475
+ Vue.component('router-view', View)
476
+ Vue.component('router-link', Link)
477
+ }
430
478
 
431
- var oCreate = Object.create || function (proto) {
432
- function F() {}
433
- F.prototype = proto;
434
- return new F();
435
- };
479
+ var __moduleExports = Array.isArray || function (arr) {
480
+ return Object.prototype.toString.call(arr) == '[object Array]';
481
+ };
436
482
 
437
- function RecognizeResults(queryParams) {
438
- this.queryParams = queryParams || {};
439
- }
440
- RecognizeResults.prototype = oCreate({
441
- splice: Array.prototype.splice,
442
- slice: Array.prototype.slice,
443
- push: Array.prototype.push,
444
- length: 0,
445
- queryParams: null
446
- });
447
-
448
- function findHandler(state, path, queryParams) {
449
- var handlers = state.handlers,
450
- regex = state.regex;
451
- var captures = path.match(regex),
452
- currentCapture = 1;
453
- var result = new RecognizeResults(queryParams);
454
-
455
- for (var i = 0, l = handlers.length; i < l; i++) {
456
- var handler = handlers[i],
457
- names = handler.names,
458
- params = {};
459
-
460
- for (var j = 0, m = names.length; j < m; j++) {
461
- params[names[j]] = captures[currentCapture++];
462
- }
483
+ var isarray = __moduleExports
463
484
 
464
- result.push({ handler: handler.handler, params: params, isDynamic: !!names.length });
485
+ /**
486
+ * Expose `pathToRegexp`.
487
+ */
488
+ var index = pathToRegexp
489
+ var parse_1 = parse
490
+ var compile_1 = compile
491
+ var tokensToFunction_1 = tokensToFunction
492
+ var tokensToRegExp_1 = tokensToRegExp
493
+
494
+ /**
495
+ * The main path matching regexp utility.
496
+ *
497
+ * @type {RegExp}
498
+ */
499
+ var PATH_REGEXP = new RegExp([
500
+ // Match escaped characters that would otherwise appear in future matches.
501
+ // This allows the user to escape special characters that won't transform.
502
+ '(\\\\.)',
503
+ // Match Express-style parameters and un-named parameters with a prefix
504
+ // and optional suffixes. Matches appear as:
505
+ //
506
+ // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
507
+ // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
508
+ // "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
509
+ '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
510
+ ].join('|'), 'g')
511
+
512
+ /**
513
+ * Parse a string for the raw tokens.
514
+ *
515
+ * @param {string} str
516
+ * @return {!Array}
517
+ */
518
+ function parse (str) {
519
+ var tokens = []
520
+ var key = 0
521
+ var index = 0
522
+ var path = ''
523
+ var res
524
+
525
+ while ((res = PATH_REGEXP.exec(str)) != null) {
526
+ var m = res[0]
527
+ var escaped = res[1]
528
+ var offset = res.index
529
+ path += str.slice(index, offset)
530
+ index = offset + m.length
531
+
532
+ // Ignore already escaped sequences.
533
+ if (escaped) {
534
+ path += escaped[1]
535
+ continue
465
536
  }
466
537
 
467
- return result;
468
- }
538
+ var next = str[index]
539
+ var prefix = res[2]
540
+ var name = res[3]
541
+ var capture = res[4]
542
+ var group = res[5]
543
+ var modifier = res[6]
544
+ var asterisk = res[7]
545
+
546
+ // Push the current path onto the tokens.
547
+ if (path) {
548
+ tokens.push(path)
549
+ path = ''
550
+ }
469
551
 
470
- function addSegment(currentState, segment) {
471
- segment.eachChar(function (ch) {
472
- var state;
552
+ var partial = prefix != null && next != null && next !== prefix
553
+ var repeat = modifier === '+' || modifier === '*'
554
+ var optional = modifier === '?' || modifier === '*'
555
+ var delimiter = res[2] || '/'
556
+ var pattern = capture || group || (asterisk ? '.*' : '[^' + delimiter + ']+?')
557
+
558
+ tokens.push({
559
+ name: name || key++,
560
+ prefix: prefix || '',
561
+ delimiter: delimiter,
562
+ optional: optional,
563
+ repeat: repeat,
564
+ partial: partial,
565
+ asterisk: !!asterisk,
566
+ pattern: escapeGroup(pattern)
567
+ })
568
+ }
473
569
 
474
- currentState = currentState.put(ch);
475
- });
570
+ // Match any characters still remaining.
571
+ if (index < str.length) {
572
+ path += str.substr(index)
573
+ }
476
574
 
477
- return currentState;
575
+ // If the path exists, push it onto the end.
576
+ if (path) {
577
+ tokens.push(path)
478
578
  }
479
579
 
480
- function decodeQueryParamPart(part) {
481
- // http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
482
- part = part.replace(/\+/gm, '%20');
483
- return tryDecode(part, true);
580
+ return tokens
581
+ }
582
+
583
+ /**
584
+ * Compile a string to a template function for the path.
585
+ *
586
+ * @param {string} str
587
+ * @return {!function(Object=, Object=)}
588
+ */
589
+ function compile (str) {
590
+ return tokensToFunction(parse(str))
591
+ }
592
+
593
+ /**
594
+ * Prettier encoding of URI path segments.
595
+ *
596
+ * @param {string}
597
+ * @return {string}
598
+ */
599
+ function encodeURIComponentPretty (str) {
600
+ return encodeURI(str).replace(/[\/?#]/g, function (c) {
601
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
602
+ })
603
+ }
604
+
605
+ /**
606
+ * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
607
+ *
608
+ * @param {string}
609
+ * @return {string}
610
+ */
611
+ function encodeAsterisk (str) {
612
+ return encodeURI(str).replace(/[?#]/g, function (c) {
613
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
614
+ })
615
+ }
616
+
617
+ /**
618
+ * Expose a method for transforming tokens into the path function.
619
+ */
620
+ function tokensToFunction (tokens) {
621
+ // Compile all the tokens into regexps.
622
+ var matches = new Array(tokens.length)
623
+
624
+ // Compile all the patterns before compilation.
625
+ for (var i = 0; i < tokens.length; i++) {
626
+ if (typeof tokens[i] === 'object') {
627
+ matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$')
628
+ }
484
629
  }
485
630
 
486
- // The main interface
631
+ return function (obj, opts) {
632
+ var path = ''
633
+ var data = obj || {}
634
+ var options = opts || {}
635
+ var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent
487
636
 
488
- var RouteRecognizer = function RouteRecognizer() {
489
- this.rootState = new State();
490
- this.names = {};
491
- };
637
+ for (var i = 0; i < tokens.length; i++) {
638
+ var token = tokens[i]
492
639
 
493
- RouteRecognizer.prototype = {
494
- add: function add(routes, options) {
495
- var currentState = this.rootState,
496
- regex = "^",
497
- specificity = {},
498
- handlers = [],
499
- allSegments = [],
500
- name;
640
+ if (typeof token === 'string') {
641
+ path += token
501
642
 
502
- var isEmpty = true;
643
+ continue
644
+ }
503
645
 
504
- for (var i = 0, l = routes.length; i < l; i++) {
505
- var route = routes[i],
506
- names = [];
646
+ var value = data[token.name]
647
+ var segment
507
648
 
508
- var segments = parse(route.path, names, specificity);
649
+ if (value == null) {
650
+ if (token.optional) {
651
+ // Prepend partial segment prefixes.
652
+ if (token.partial) {
653
+ path += token.prefix
654
+ }
509
655
 
510
- allSegments = allSegments.concat(segments);
656
+ continue
657
+ } else {
658
+ throw new TypeError('Expected "' + token.name + '" to be defined')
659
+ }
660
+ }
511
661
 
512
- for (var j = 0, m = segments.length; j < m; j++) {
513
- var segment = segments[j];
662
+ if (isarray(value)) {
663
+ if (!token.repeat) {
664
+ throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
665
+ }
514
666
 
515
- if (segment instanceof EpsilonSegment) {
516
- continue;
667
+ if (value.length === 0) {
668
+ if (token.optional) {
669
+ continue
670
+ } else {
671
+ throw new TypeError('Expected "' + token.name + '" to not be empty')
517
672
  }
673
+ }
518
674
 
519
- isEmpty = false;
675
+ for (var j = 0; j < value.length; j++) {
676
+ segment = encode(value[j])
520
677
 
521
- // Add a "/" for the new segment
522
- currentState = currentState.put({ validChars: "/" });
523
- regex += "/";
678
+ if (!matches[i].test(segment)) {
679
+ throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
680
+ }
524
681
 
525
- // Add a representation of the segment to the NFA and regex
526
- currentState = addSegment(currentState, segment);
527
- regex += segment.regex();
682
+ path += (j === 0 ? token.prefix : token.delimiter) + segment
528
683
  }
529
684
 
530
- var handler = { handler: route.handler, names: names };
531
- handlers.push(handler);
685
+ continue
532
686
  }
533
687
 
534
- if (isEmpty) {
535
- currentState = currentState.put({ validChars: "/" });
536
- regex += "/";
688
+ segment = token.asterisk ? encodeAsterisk(value) : encode(value)
689
+
690
+ if (!matches[i].test(segment)) {
691
+ throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
537
692
  }
538
693
 
539
- currentState.handlers = handlers;
540
- currentState.regex = new RegExp(regex + "$");
541
- currentState.specificity = specificity;
694
+ path += token.prefix + segment
695
+ }
542
696
 
543
- if (name = options && options.as) {
544
- this.names[name] = {
545
- segments: allSegments,
546
- handlers: handlers
547
- };
548
- }
549
- },
697
+ return path
698
+ }
699
+ }
550
700
 
551
- handlersFor: function handlersFor(name) {
552
- var route = this.names[name],
553
- result = [];
554
- if (!route) {
555
- throw new Error("There is no route named " + name);
556
- }
701
+ /**
702
+ * Escape a regular expression string.
703
+ *
704
+ * @param {string} str
705
+ * @return {string}
706
+ */
707
+ function escapeString (str) {
708
+ return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1')
709
+ }
710
+
711
+ /**
712
+ * Escape the capturing group by escaping special characters and meaning.
713
+ *
714
+ * @param {string} group
715
+ * @return {string}
716
+ */
717
+ function escapeGroup (group) {
718
+ return group.replace(/([=!:$\/()])/g, '\\$1')
719
+ }
720
+
721
+ /**
722
+ * Attach the keys as a property of the regexp.
723
+ *
724
+ * @param {!RegExp} re
725
+ * @param {Array} keys
726
+ * @return {!RegExp}
727
+ */
728
+ function attachKeys (re, keys) {
729
+ re.keys = keys
730
+ return re
731
+ }
732
+
733
+ /**
734
+ * Get the flags for a regexp from the options.
735
+ *
736
+ * @param {Object} options
737
+ * @return {string}
738
+ */
739
+ function flags (options) {
740
+ return options.sensitive ? '' : 'i'
741
+ }
742
+
743
+ /**
744
+ * Pull out keys from a regexp.
745
+ *
746
+ * @param {!RegExp} path
747
+ * @param {!Array} keys
748
+ * @return {!RegExp}
749
+ */
750
+ function regexpToRegexp (path, keys) {
751
+ // Use a negative lookahead to match only capturing groups.
752
+ var groups = path.source.match(/\((?!\?)/g)
753
+
754
+ if (groups) {
755
+ for (var i = 0; i < groups.length; i++) {
756
+ keys.push({
757
+ name: i,
758
+ prefix: null,
759
+ delimiter: null,
760
+ optional: false,
761
+ repeat: false,
762
+ partial: false,
763
+ asterisk: false,
764
+ pattern: null
765
+ })
766
+ }
767
+ }
557
768
 
558
- for (var i = 0, l = route.handlers.length; i < l; i++) {
559
- result.push(route.handlers[i]);
560
- }
769
+ return attachKeys(path, keys)
770
+ }
561
771
 
562
- return result;
563
- },
772
+ /**
773
+ * Transform an array into a regexp.
774
+ *
775
+ * @param {!Array} path
776
+ * @param {Array} keys
777
+ * @param {!Object} options
778
+ * @return {!RegExp}
779
+ */
780
+ function arrayToRegexp (path, keys, options) {
781
+ var parts = []
564
782
 
565
- hasRoute: function hasRoute(name) {
566
- return !!this.names[name];
567
- },
783
+ for (var i = 0; i < path.length; i++) {
784
+ parts.push(pathToRegexp(path[i], keys, options).source)
785
+ }
568
786
 
569
- generate: function generate(name, params) {
570
- var route = this.names[name],
571
- output = "";
572
- if (!route) {
573
- throw new Error("There is no route named " + name);
574
- }
787
+ var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options))
575
788
 
576
- var segments = route.segments;
789
+ return attachKeys(regexp, keys)
790
+ }
577
791
 
578
- for (var i = 0, l = segments.length; i < l; i++) {
579
- var segment = segments[i];
792
+ /**
793
+ * Create a path regexp from string input.
794
+ *
795
+ * @param {string} path
796
+ * @param {!Array} keys
797
+ * @param {!Object} options
798
+ * @return {!RegExp}
799
+ */
800
+ function stringToRegexp (path, keys, options) {
801
+ var tokens = parse(path)
802
+ var re = tokensToRegExp(tokens, options)
803
+
804
+ // Attach keys back to the regexp.
805
+ for (var i = 0; i < tokens.length; i++) {
806
+ if (typeof tokens[i] !== 'string') {
807
+ keys.push(tokens[i])
808
+ }
809
+ }
580
810
 
581
- if (segment instanceof EpsilonSegment) {
582
- continue;
583
- }
811
+ return attachKeys(re, keys)
812
+ }
584
813
 
585
- output += "/";
586
- output += segment.generate(params);
587
- }
814
+ /**
815
+ * Expose a function for taking tokens and returning a RegExp.
816
+ *
817
+ * @param {!Array} tokens
818
+ * @param {Object=} options
819
+ * @return {!RegExp}
820
+ */
821
+ function tokensToRegExp (tokens, options) {
822
+ options = options || {}
588
823
 
589
- if (output.charAt(0) !== '/') {
590
- output = '/' + output;
591
- }
824
+ var strict = options.strict
825
+ var end = options.end !== false
826
+ var route = ''
827
+ var lastToken = tokens[tokens.length - 1]
828
+ var endsWithSlash = typeof lastToken === 'string' && /\/$/.test(lastToken)
592
829
 
593
- if (params && params.queryParams) {
594
- output += this.generateQueryString(params.queryParams);
595
- }
830
+ // Iterate over the tokens and create our regexp string.
831
+ for (var i = 0; i < tokens.length; i++) {
832
+ var token = tokens[i]
596
833
 
597
- return output;
598
- },
834
+ if (typeof token === 'string') {
835
+ route += escapeString(token)
836
+ } else {
837
+ var prefix = escapeString(token.prefix)
838
+ var capture = '(?:' + token.pattern + ')'
599
839
 
600
- generateQueryString: function generateQueryString(params) {
601
- var pairs = [];
602
- var keys = [];
603
- for (var key in params) {
604
- if (params.hasOwnProperty(key)) {
605
- keys.push(key);
606
- }
840
+ if (token.repeat) {
841
+ capture += '(?:' + prefix + capture + ')*'
607
842
  }
608
- keys.sort();
609
- for (var i = 0, len = keys.length; i < len; i++) {
610
- key = keys[i];
611
- var value = params[key];
612
- if (value == null) {
613
- continue;
614
- }
615
- var pair = encodeURIComponent(key);
616
- if (isArray(value)) {
617
- for (var j = 0, l = value.length; j < l; j++) {
618
- var arrayPair = key + '[]' + '=' + encodeURIComponent(value[j]);
619
- pairs.push(arrayPair);
620
- }
843
+
844
+ if (token.optional) {
845
+ if (!token.partial) {
846
+ capture = '(?:' + prefix + '(' + capture + '))?'
621
847
  } else {
622
- pair += "=" + encodeURIComponent(value);
623
- pairs.push(pair);
848
+ capture = prefix + '(' + capture + ')?'
624
849
  }
850
+ } else {
851
+ capture = prefix + '(' + capture + ')'
625
852
  }
626
853
 
627
- if (pairs.length === 0) {
628
- return '';
629
- }
854
+ route += capture
855
+ }
856
+ }
630
857
 
631
- return "?" + pairs.join("&");
632
- },
858
+ // In non-strict mode we allow a slash at the end of match. If the path to
859
+ // match already ends with a slash, we remove it for consistency. The slash
860
+ // is valid at the end of a path match, not in the middle. This is important
861
+ // in non-ending mode, where "/test/" shouldn't match "/test//route".
862
+ if (!strict) {
863
+ route = (endsWithSlash ? route.slice(0, -2) : route) + '(?:\\/(?=$))?'
864
+ }
633
865
 
634
- parseQueryString: function parseQueryString(queryString) {
635
- var pairs = queryString.split("&"),
636
- queryParams = {};
637
- for (var i = 0; i < pairs.length; i++) {
638
- var pair = pairs[i].split('='),
639
- key = decodeQueryParamPart(pair[0]),
640
- keyLength = key.length,
641
- isArray = false,
642
- value;
643
- if (pair.length === 1) {
644
- value = 'true';
645
- } else {
646
- //Handle arrays
647
- if (keyLength > 2 && key.slice(keyLength - 2) === '[]') {
648
- isArray = true;
649
- key = key.slice(0, keyLength - 2);
650
- if (!queryParams[key]) {
651
- queryParams[key] = [];
652
- }
653
- }
654
- value = pair[1] ? decodeQueryParamPart(pair[1]) : '';
655
- }
656
- if (isArray) {
657
- queryParams[key].push(value);
658
- } else {
659
- queryParams[key] = value;
660
- }
661
- }
662
- return queryParams;
663
- },
866
+ if (end) {
867
+ route += '$'
868
+ } else {
869
+ // In non-ending mode, we need the capturing groups to match as much as
870
+ // possible by using a positive lookahead to the end or next path segment.
871
+ route += strict && endsWithSlash ? '' : '(?=\\/|$)'
872
+ }
664
873
 
665
- recognize: function recognize(path, silent) {
666
- noWarning = silent;
667
- var states = [this.rootState],
668
- pathLen,
669
- i,
670
- l,
671
- queryStart,
672
- queryParams = {},
673
- isSlashDropped = false;
674
-
675
- queryStart = path.indexOf('?');
676
- if (queryStart !== -1) {
677
- var queryString = path.substr(queryStart + 1, path.length);
678
- path = path.substr(0, queryStart);
679
- if (queryString) {
680
- queryParams = this.parseQueryString(queryString);
681
- }
682
- }
874
+ return new RegExp('^' + route, flags(options))
875
+ }
876
+
877
+ /**
878
+ * Normalize the given path string, returning a regular expression.
879
+ *
880
+ * An empty array can be passed in for the keys, which will hold the
881
+ * placeholder key descriptions. For example, using `/user/:id`, `keys` will
882
+ * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
883
+ *
884
+ * @param {(string|RegExp|Array)} path
885
+ * @param {(Array|Object)=} keys
886
+ * @param {Object=} options
887
+ * @return {!RegExp}
888
+ */
889
+ function pathToRegexp (path, keys, options) {
890
+ keys = keys || []
891
+
892
+ if (!isarray(keys)) {
893
+ options = /** @type {!Object} */ (keys)
894
+ keys = []
895
+ } else if (!options) {
896
+ options = {}
897
+ }
683
898
 
684
- path = tryDecode(path);
685
- if (!path) return;
899
+ if (path instanceof RegExp) {
900
+ return regexpToRegexp(path, /** @type {!Array} */ (keys))
901
+ }
686
902
 
687
- // DEBUG GROUP path
903
+ if (isarray(path)) {
904
+ return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)
905
+ }
688
906
 
689
- if (path.charAt(0) !== "/") {
690
- path = "/" + path;
691
- }
907
+ return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)
908
+ }
692
909
 
693
- pathLen = path.length;
694
- if (pathLen > 1 && path.charAt(pathLen - 1) === "/") {
695
- path = path.substr(0, pathLen - 1);
696
- isSlashDropped = true;
697
- }
910
+ index.parse = parse_1;
911
+ index.compile = compile_1;
912
+ index.tokensToFunction = tokensToFunction_1;
913
+ index.tokensToRegExp = tokensToRegExp_1;
698
914
 
699
- for (i = 0, l = path.length; i < l; i++) {
700
- states = recognizeChar(states, path.charAt(i));
701
- if (!states.length) {
702
- break;
703
- }
704
- }
915
+ /* */
705
916
 
706
- // END DEBUG GROUP
917
+ function createRouteMap (routes) {
918
+ var pathMap = Object.create(null)
919
+ var nameMap = Object.create(null)
707
920
 
708
- var solutions = [];
709
- for (i = 0, l = states.length; i < l; i++) {
710
- if (states[i].handlers) {
711
- solutions.push(states[i]);
712
- }
713
- }
921
+ routes.forEach(function (route) {
922
+ addRouteRecord(pathMap, nameMap, route)
923
+ })
714
924
 
715
- states = sortSolutions(solutions);
925
+ return {
926
+ pathMap: pathMap,
927
+ nameMap: nameMap
928
+ }
929
+ }
930
+
931
+ function addRouteRecord (
932
+ pathMap,
933
+ nameMap,
934
+ route,
935
+ parent,
936
+ matchAs
937
+ ) {
938
+ var path = route.path;
939
+ var name = route.name;
940
+ assert(path != null, "\"path\" is required in a route configuration.")
941
+
942
+ var record = {
943
+ path: normalizePath(path, parent),
944
+ components: route.components || { default: route.component },
945
+ instances: {},
946
+ name: name,
947
+ parent: parent,
948
+ matchAs: matchAs,
949
+ redirect: route.redirect,
950
+ beforeEnter: route.beforeEnter,
951
+ meta: route.meta || {}
952
+ }
716
953
 
717
- var state = solutions[0];
954
+ if (route.children) {
955
+ // Warn if route is named and has a default child route.
956
+ // If users navigate to this route by name, the default child will
957
+ // not be rendered (GH Issue #629)
958
+ if ("production" !== 'production') {}
959
+ route.children.forEach(function (child) {
960
+ addRouteRecord(pathMap, nameMap, child, record)
961
+ })
962
+ }
718
963
 
719
- if (state && state.handlers) {
720
- // if a trailing slash was dropped and a star segment is the last segment
721
- // specified, put the trailing slash back
722
- if (isSlashDropped && state.regex.source.slice(-5) === "(.+)$") {
723
- path = path + "/";
724
- }
725
- return findHandler(state, path, queryParams);
726
- }
964
+ if (route.alias) {
965
+ if (Array.isArray(route.alias)) {
966
+ route.alias.forEach(function (alias) {
967
+ addRouteRecord(pathMap, nameMap, { path: alias }, parent, record.path)
968
+ })
969
+ } else {
970
+ addRouteRecord(pathMap, nameMap, { path: route.alias }, parent, record.path)
727
971
  }
728
- };
972
+ }
729
973
 
730
- RouteRecognizer.prototype.map = map;
974
+ pathMap[record.path] = record
975
+ if (name) { nameMap[name] = record }
976
+ }
731
977
 
732
- var genQuery = RouteRecognizer.prototype.generateQueryString;
978
+ function normalizePath (path, parent) {
979
+ path = path.replace(/\/$/, '')
980
+ if (path[0] === '/') { return path }
981
+ if (parent == null) { return path }
982
+ return cleanPath(((parent.path) + "/" + path))
983
+ }
733
984
 
734
- // export default for holding the Vue reference
735
- var exports$1 = {};
736
- /**
737
- * Warn stuff.
738
- *
739
- * @param {String} msg
740
- */
985
+ /* */
741
986
 
742
- function warn$1(msg) {
743
- /* istanbul ignore next */
744
- if (typeof console !== 'undefined') {
745
- console.error('[vue-router] ' + msg);
987
+ var regexpCache = Object.create(null)
988
+
989
+ var regexpCompileCache = Object.create(null)
990
+
991
+ function createMatcher (routes) {
992
+ var ref = createRouteMap(routes);
993
+ var pathMap = ref.pathMap;
994
+ var nameMap = ref.nameMap;
995
+
996
+ function match (
997
+ raw,
998
+ currentRoute,
999
+ redirectedFrom
1000
+ ) {
1001
+ var location = normalizeLocation(raw, currentRoute)
1002
+ var name = location.name;
1003
+
1004
+ if (name) {
1005
+ var record = nameMap[name]
1006
+ if (record) {
1007
+ location.path = fillParams(record.path, location.params, ("named route \"" + name + "\""))
1008
+ return _createRoute(record, location, redirectedFrom)
1009
+ }
1010
+ } else if (location.path) {
1011
+ location.params = {}
1012
+ for (var path in pathMap) {
1013
+ if (matchRoute(path, location.params, location.path)) {
1014
+ return _createRoute(pathMap[path], location, redirectedFrom)
1015
+ }
1016
+ }
746
1017
  }
1018
+ // no match
1019
+ return _createRoute(null, location)
747
1020
  }
748
1021
 
749
- /**
750
- * Resolve a relative path.
751
- *
752
- * @param {String} base
753
- * @param {String} relative
754
- * @param {Boolean} append
755
- * @return {String}
756
- */
757
-
758
- function resolvePath(base, relative, append) {
759
- var query = base.match(/(\?.*)$/);
760
- if (query) {
761
- query = query[1];
762
- base = base.slice(0, -query.length);
1022
+ function redirect (
1023
+ record,
1024
+ location
1025
+ ) {
1026
+ var originalRedirect = record.redirect
1027
+ var redirect = typeof originalRedirect === 'function'
1028
+ ? originalRedirect(createRoute(record, location))
1029
+ : originalRedirect
1030
+
1031
+ if (typeof redirect === 'string') {
1032
+ redirect = { path: redirect }
763
1033
  }
764
- // a query!
765
- if (relative.charAt(0) === '?') {
766
- return base + relative;
1034
+
1035
+ if (!redirect || typeof redirect !== 'object') {
1036
+ warn(false, ("invalid redirect option: " + (JSON.stringify(redirect))))
1037
+ return _createRoute(null, location)
767
1038
  }
768
- var stack = base.split('/');
769
- // remove trailing segment if:
770
- // - not appending
771
- // - appending to trailing slash (last segment is empty)
772
- if (!append || !stack[stack.length - 1]) {
773
- stack.pop();
1039
+
1040
+ var re = redirect
1041
+ var name = re.name;
1042
+ var path = re.path;
1043
+ var query = location.query;
1044
+ var hash = location.hash;
1045
+ var params = location.params;
1046
+ query = re.hasOwnProperty('query') ? re.query : query
1047
+ hash = re.hasOwnProperty('hash') ? re.hash : hash
1048
+ params = re.hasOwnProperty('params') ? re.params : params
1049
+
1050
+ if (name) {
1051
+ // resolved named direct
1052
+ var targetRecord = nameMap[name]
1053
+ assert(targetRecord, ("redirect failed: named route \"" + name + "\" not found."))
1054
+ return match({
1055
+ _normalized: true,
1056
+ name: name,
1057
+ query: query,
1058
+ hash: hash,
1059
+ params: params
1060
+ }, undefined, location)
1061
+ } else if (path) {
1062
+ // 1. resolve relative redirect
1063
+ var rawPath = resolveRecordPath(path, record)
1064
+ // 2. resolve params
1065
+ var resolvedPath = fillParams(rawPath, params, ("redirect route with path \"" + rawPath + "\""))
1066
+ // 3. rematch with existing query and hash
1067
+ return match({
1068
+ _normalized: true,
1069
+ path: resolvedPath,
1070
+ query: query,
1071
+ hash: hash
1072
+ }, undefined, location)
1073
+ } else {
1074
+ warn(false, ("invalid redirect option: " + (JSON.stringify(redirect))))
1075
+ return _createRoute(null, location)
774
1076
  }
775
- // resolve relative path
776
- var segments = relative.replace(/^\//, '').split('/');
777
- for (var i = 0; i < segments.length; i++) {
778
- var segment = segments[i];
779
- if (segment === '.') {
780
- continue;
781
- } else if (segment === '..') {
782
- stack.pop();
783
- } else {
784
- stack.push(segment);
785
- }
1077
+ }
1078
+
1079
+ function alias (
1080
+ record,
1081
+ location,
1082
+ matchAs
1083
+ ) {
1084
+ var aliasedPath = fillParams(matchAs, location.params, ("aliased route with path \"" + matchAs + "\""))
1085
+ var aliasedMatch = match({
1086
+ _normalized: true,
1087
+ path: aliasedPath
1088
+ })
1089
+ if (aliasedMatch) {
1090
+ var matched = aliasedMatch.matched
1091
+ var aliasedRecord = matched[matched.length - 1]
1092
+ location.params = aliasedMatch.params
1093
+ return _createRoute(aliasedRecord, location)
786
1094
  }
787
- // ensure leading slash
788
- if (stack[0] !== '') {
789
- stack.unshift('');
1095
+ return _createRoute(null, location)
1096
+ }
1097
+
1098
+ function _createRoute (
1099
+ record,
1100
+ location,
1101
+ redirectedFrom
1102
+ ) {
1103
+ if (record && record.redirect) {
1104
+ return redirect(record, redirectedFrom || location)
790
1105
  }
791
- return stack.join('/');
792
- }
793
-
794
- /**
795
- * Forgiving check for a promise
796
- *
797
- * @param {Object} p
798
- * @return {Boolean}
799
- */
800
-
801
- function isPromise(p) {
802
- return p && typeof p.then === 'function';
803
- }
804
-
805
- /**
806
- * Retrive a route config field from a component instance
807
- * OR a component contructor.
808
- *
809
- * @param {Function|Vue} component
810
- * @param {String} name
811
- * @return {*}
812
- */
813
-
814
- function getRouteConfig(component, name) {
815
- var options = component && (component.$options || component.options);
816
- return options && options.route && options.route[name];
817
- }
818
-
819
- /**
820
- * Resolve an async component factory. Have to do a dirty
821
- * mock here because of Vue core's internal API depends on
822
- * an ID check.
823
- *
824
- * @param {Object} handler
825
- * @param {Function} cb
826
- */
827
-
828
- var resolver = undefined;
829
-
830
- function resolveAsyncComponent(handler, cb) {
831
- if (!resolver) {
832
- resolver = {
833
- resolve: exports$1.Vue.prototype._resolveComponent,
834
- $options: {
835
- components: {
836
- _: handler.component
837
- }
838
- }
839
- };
840
- } else {
841
- resolver.$options.components._ = handler.component;
1106
+ if (record && record.matchAs) {
1107
+ return alias(record, location, record.matchAs)
842
1108
  }
843
- resolver.resolve('_', function (Component) {
844
- handler.component = Component;
845
- cb(Component);
846
- });
847
- }
848
-
849
- /**
850
- * Map the dynamic segments in a path to params.
851
- *
852
- * @param {String} path
853
- * @param {Object} params
854
- * @param {Object} query
855
- */
856
-
857
- function mapParams(path, params, query) {
858
- if (params === undefined) params = {};
859
-
860
- path = path.replace(/:([^\/]+)/g, function (_, key) {
861
- var val = params[key];
862
- /* istanbul ignore if */
863
- if (!val) {
864
- warn$1('param "' + key + '" not found when generating ' + 'path for "' + path + '" with params ' + JSON.stringify(params));
865
- }
866
- return val || '';
867
- });
868
- if (query) {
869
- path += genQuery(query);
870
- }
871
- return path;
1109
+ return createRoute(record, location, redirectedFrom)
872
1110
  }
873
1111
 
874
- var hashRE = /#.*$/;
1112
+ return match
1113
+ }
1114
+
1115
+ function matchRoute (
1116
+ path,
1117
+ params,
1118
+ pathname
1119
+ ) {
1120
+ var keys, regexp
1121
+ var hit = regexpCache[path]
1122
+ if (hit) {
1123
+ keys = hit.keys
1124
+ regexp = hit.regexp
1125
+ } else {
1126
+ keys = []
1127
+ regexp = index(path, keys)
1128
+ regexpCache[path] = { keys: keys, regexp: regexp }
1129
+ }
1130
+ var m = pathname.match(regexp)
875
1131
 
876
- var HTML5History = (function () {
877
- function HTML5History(_ref) {
878
- var root = _ref.root;
879
- var onChange = _ref.onChange;
880
- babelHelpers.classCallCheck(this, HTML5History);
1132
+ if (!m) {
1133
+ return false
1134
+ } else if (!params) {
1135
+ return true
1136
+ }
881
1137
 
882
- if (root && root !== '/') {
883
- // make sure there's the starting slash
884
- if (root.charAt(0) !== '/') {
885
- root = '/' + root;
886
- }
887
- // remove trailing slash
888
- this.root = root.replace(/\/$/, '');
889
- this.rootRE = new RegExp('^\\' + this.root);
890
- } else {
891
- this.root = null;
892
- }
893
- this.onChange = onChange;
894
- // check base tag
895
- var baseEl = document.querySelector('base');
896
- this.base = baseEl && baseEl.getAttribute('href');
897
- }
1138
+ for (var i = 1, len = m.length; i < len; ++i) {
1139
+ var key = keys[i - 1]
1140
+ var val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i]
1141
+ if (key) { params[key.name] = val }
1142
+ }
898
1143
 
899
- HTML5History.prototype.start = function start() {
900
- var _this = this;
1144
+ return true
1145
+ }
1146
+
1147
+ function fillParams (
1148
+ path,
1149
+ params,
1150
+ routeMsg
1151
+ ) {
1152
+ try {
1153
+ var filler =
1154
+ regexpCompileCache[path] ||
1155
+ (regexpCompileCache[path] = index.compile(path))
1156
+ return filler(params || {}, { pretty: true })
1157
+ } catch (e) {
1158
+ assert(false, ("missing param for " + routeMsg + ": " + (e.message)))
1159
+ return ''
1160
+ }
1161
+ }
901
1162
 
902
- this.listener = function (e) {
903
- var url = location.pathname + location.search;
904
- if (_this.root) {
905
- url = url.replace(_this.rootRE, '');
906
- }
907
- _this.onChange(url, e && e.state, location.hash);
908
- };
909
- window.addEventListener('popstate', this.listener);
910
- this.listener();
911
- };
912
-
913
- HTML5History.prototype.stop = function stop() {
914
- window.removeEventListener('popstate', this.listener);
915
- };
916
-
917
- HTML5History.prototype.go = function go(path, replace, append) {
918
- var url = this.formatPath(path, append);
919
- if (replace) {
920
- history.replaceState({}, '', url);
921
- } else {
922
- // record scroll position by replacing current state
923
- history.replaceState({
924
- pos: {
925
- x: window.pageXOffset,
926
- y: window.pageYOffset
927
- }
928
- }, '', location.href);
929
- // then push new state
930
- history.pushState({}, '', url);
931
- }
932
- var hashMatch = path.match(hashRE);
933
- var hash = hashMatch && hashMatch[0];
934
- path = url
935
- // strip hash so it doesn't mess up params
936
- .replace(hashRE, '')
937
- // remove root before matching
938
- .replace(this.rootRE, '');
939
- this.onChange(path, null, hash);
940
- };
941
-
942
- HTML5History.prototype.formatPath = function formatPath(path, append) {
943
- return path.charAt(0) === '/'
944
- // absolute path
945
- ? this.root ? this.root + '/' + path.replace(/^\//, '') : path : resolvePath(this.base || location.pathname, path, append);
946
- };
947
-
948
- return HTML5History;
949
- })();
950
-
951
- var HashHistory = (function () {
952
- function HashHistory(_ref) {
953
- var hashbang = _ref.hashbang;
954
- var onChange = _ref.onChange;
955
- babelHelpers.classCallCheck(this, HashHistory);
956
-
957
- this.hashbang = hashbang;
958
- this.onChange = onChange;
959
- }
1163
+ function resolveRecordPath (path, record) {
1164
+ return resolvePath(path, record.parent ? record.parent.path : '/', true)
1165
+ }
960
1166
 
961
- HashHistory.prototype.start = function start() {
962
- var self = this;
963
- this.listener = function () {
964
- var path = location.hash;
965
- var raw = path.replace(/^#!?/, '');
966
- // always
967
- if (raw.charAt(0) !== '/') {
968
- raw = '/' + raw;
969
- }
970
- var formattedPath = self.formatPath(raw);
971
- if (formattedPath !== path) {
972
- location.replace(formattedPath);
973
- return;
974
- }
975
- // determine query
976
- // note it's possible to have queries in both the actual URL
977
- // and the hash fragment itself.
978
- var query = location.search && path.indexOf('?') > -1 ? '&' + location.search.slice(1) : location.search;
979
- self.onChange(path.replace(/^#!?/, '') + query);
980
- };
981
- window.addEventListener('hashchange', this.listener);
982
- this.listener();
983
- };
984
-
985
- HashHistory.prototype.stop = function stop() {
986
- window.removeEventListener('hashchange', this.listener);
987
- };
988
-
989
- HashHistory.prototype.go = function go(path, replace, append) {
990
- path = this.formatPath(path, append);
991
- if (replace) {
992
- location.replace(path);
993
- } else {
994
- location.hash = path;
995
- }
996
- };
1167
+ /* */
997
1168
 
998
- HashHistory.prototype.formatPath = function formatPath(path, append) {
999
- var isAbsoloute = path.charAt(0) === '/';
1000
- var prefix = '#' + (this.hashbang ? '!' : '');
1001
- return isAbsoloute ? prefix + path : prefix + resolvePath(location.hash.replace(/^#!?/, ''), path, append);
1002
- };
1169
+ var inBrowser = typeof window !== 'undefined'
1003
1170
 
1004
- return HashHistory;
1005
- })();
1171
+ var supportsHistory = inBrowser && (function () {
1172
+ var ua = window.navigator.userAgent
1006
1173
 
1007
- var AbstractHistory = (function () {
1008
- function AbstractHistory(_ref) {
1009
- var onChange = _ref.onChange;
1010
- babelHelpers.classCallCheck(this, AbstractHistory);
1174
+ if (
1175
+ (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
1176
+ ua.indexOf('Mobile Safari') !== -1 &&
1177
+ ua.indexOf('Chrome') === -1 &&
1178
+ ua.indexOf('Windows Phone') === -1
1179
+ ) {
1180
+ return false
1181
+ }
1011
1182
 
1012
- this.onChange = onChange;
1013
- this.currentPath = '/';
1014
- }
1183
+ return window.history && 'pushState' in window.history
1184
+ })()
1015
1185
 
1016
- AbstractHistory.prototype.start = function start() {
1017
- this.onChange('/');
1018
- };
1019
-
1020
- AbstractHistory.prototype.stop = function stop() {
1021
- // noop
1022
- };
1023
-
1024
- AbstractHistory.prototype.go = function go(path, replace, append) {
1025
- path = this.currentPath = this.formatPath(path, append);
1026
- this.onChange(path);
1027
- };
1028
-
1029
- AbstractHistory.prototype.formatPath = function formatPath(path, append) {
1030
- return path.charAt(0) === '/' ? path : resolvePath(this.currentPath, path, append);
1031
- };
1032
-
1033
- return AbstractHistory;
1034
- })();
1035
-
1036
- /**
1037
- * Determine the reusability of an existing router view.
1038
- *
1039
- * @param {Directive} view
1040
- * @param {Object} handler
1041
- * @param {Transition} transition
1042
- */
1043
-
1044
- function canReuse(view, handler, transition) {
1045
- var component = view.childVM;
1046
- if (!component || !handler) {
1047
- return false;
1048
- }
1049
- // important: check view.Component here because it may
1050
- // have been changed in activate hook
1051
- if (view.Component !== handler.component) {
1052
- return false;
1053
- }
1054
- var canReuseFn = getRouteConfig(component, 'canReuse');
1055
- return typeof canReuseFn === 'boolean' ? canReuseFn : canReuseFn ? canReuseFn.call(component, {
1056
- to: transition.to,
1057
- from: transition.from
1058
- }) : true; // defaults to true
1059
- }
1060
-
1061
- /**
1062
- * Check if a component can deactivate.
1063
- *
1064
- * @param {Directive} view
1065
- * @param {Transition} transition
1066
- * @param {Function} next
1067
- */
1068
-
1069
- function canDeactivate(view, transition, next) {
1070
- var fromComponent = view.childVM;
1071
- var hook = getRouteConfig(fromComponent, 'canDeactivate');
1072
- if (!hook) {
1073
- next();
1186
+ /* */
1187
+
1188
+ function runQueue (queue, fn, cb) {
1189
+ var step = function (index) {
1190
+ if (index >= queue.length) {
1191
+ cb()
1074
1192
  } else {
1075
- transition.callHook(hook, fromComponent, next, {
1076
- expectBoolean: true
1077
- });
1193
+ if (queue[index]) {
1194
+ fn(queue[index], function () {
1195
+ step(index + 1)
1196
+ })
1197
+ } else {
1198
+ step(index + 1)
1199
+ }
1078
1200
  }
1079
1201
  }
1202
+ step(0)
1203
+ }
1204
+
1205
+ /* */
1206
+
1207
+
1208
+ var History = function History (router, base) {
1209
+ this.router = router
1210
+ this.base = normalizeBase(base)
1211
+ // start with a route object that stands for "nowhere"
1212
+ this.current = START
1213
+ this.pending = null
1214
+ };
1215
+
1216
+ History.prototype.listen = function listen (cb) {
1217
+ this.cb = cb
1218
+ };
1219
+
1220
+ History.prototype.transitionTo = function transitionTo (location, cb) {
1221
+ var this$1 = this;
1222
+
1223
+ var route = this.router.match(location, this.current)
1224
+ this.confirmTransition(route, function () {
1225
+ this$1.updateRoute(route)
1226
+ cb && cb(route)
1227
+ this$1.ensureURL()
1228
+ })
1229
+ };
1230
+
1231
+ History.prototype.confirmTransition = function confirmTransition (route, cb) {
1232
+ var this$1 = this;
1233
+
1234
+ var current = this.current
1235
+ if (isSameRoute(route, current)) {
1236
+ this.ensureURL()
1237
+ return
1238
+ }
1080
1239
 
1081
- /**
1082
- * Check if a component can activate.
1083
- *
1084
- * @param {Object} handler
1085
- * @param {Transition} transition
1086
- * @param {Function} next
1087
- */
1088
-
1089
- function canActivate(handler, transition, next) {
1090
- resolveAsyncComponent(handler, function (Component) {
1091
- // have to check due to async-ness
1092
- if (transition.aborted) {
1093
- return;
1094
- }
1095
- // determine if this component can be activated
1096
- var hook = getRouteConfig(Component, 'canActivate');
1097
- if (!hook) {
1098
- next();
1240
+ var ref = resolveQueue(this.current.matched, route.matched);
1241
+ var deactivated = ref.deactivated;
1242
+ var activated = ref.activated;
1243
+
1244
+ var queue = [].concat(
1245
+ // in-component leave guards
1246
+ extractLeaveGuards(deactivated),
1247
+ // global before hooks
1248
+ this.router.beforeHooks,
1249
+ // enter guards
1250
+ activated.map(function (m) { return m.beforeEnter; }),
1251
+ // async components
1252
+ resolveAsyncComponents(activated)
1253
+ )
1254
+
1255
+ this.pending = route
1256
+ var iterator = function (hook, next) {
1257
+ if (this$1.pending !== route) { return }
1258
+ hook(route, current, function (to) {
1259
+ if (to === false) {
1260
+ // next(false) -> abort navigation, ensure current URL
1261
+ this$1.ensureURL()
1262
+ } else if (typeof to === 'string' || typeof to === 'object') {
1263
+ // next('/') or next({ path: '/' }) -> redirect
1264
+ this$1.push(to)
1099
1265
  } else {
1100
- transition.callHook(hook, null, next, {
1101
- expectBoolean: true
1102
- });
1266
+ // confirm transition and pass on the value
1267
+ next(to)
1103
1268
  }
1104
- });
1105
- }
1106
-
1107
- /**
1108
- * Call deactivate hooks for existing router-views.
1109
- *
1110
- * @param {Directive} view
1111
- * @param {Transition} transition
1112
- * @param {Function} next
1113
- */
1114
-
1115
- function deactivate(view, transition, next) {
1116
- var component = view.childVM;
1117
- var hook = getRouteConfig(component, 'deactivate');
1118
- if (!hook) {
1119
- next();
1269
+ })
1270
+ }
1271
+
1272
+ runQueue(queue, iterator, function () {
1273
+ var postEnterCbs = []
1274
+ // wait until async components are resolved before
1275
+ // extracting in-component enter guards
1276
+ runQueue(extractEnterGuards(activated, postEnterCbs), iterator, function () {
1277
+ if (this$1.pending === route) {
1278
+ this$1.pending = null
1279
+ cb(route)
1280
+ this$1.router.app.$nextTick(function () {
1281
+ postEnterCbs.forEach(function (cb) { return cb(); })
1282
+ })
1283
+ }
1284
+ })
1285
+ })
1286
+ };
1287
+
1288
+ History.prototype.updateRoute = function updateRoute (route) {
1289
+ var prev = this.current
1290
+ this.current = route
1291
+ this.cb && this.cb(route)
1292
+ this.router.afterHooks.forEach(function (hook) {
1293
+ hook && hook(route, prev)
1294
+ })
1295
+ };
1296
+
1297
+ function normalizeBase (base) {
1298
+ if (!base) {
1299
+ if (inBrowser) {
1300
+ // respect <base> tag
1301
+ var baseEl = document.querySelector('base')
1302
+ base = baseEl ? baseEl.getAttribute('href') : '/'
1120
1303
  } else {
1121
- transition.callHooks(hook, component, next);
1304
+ base = '/'
1122
1305
  }
1123
1306
  }
1307
+ // make sure there's the starting slash
1308
+ if (base.charAt(0) !== '/') {
1309
+ base = '/' + base
1310
+ }
1311
+ // remove trailing slash
1312
+ return base.replace(/\/$/, '')
1313
+ }
1314
+
1315
+ function resolveQueue (
1316
+ current,
1317
+ next
1318
+ ) {
1319
+ var i
1320
+ var max = Math.max(current.length, next.length)
1321
+ for (i = 0; i < max; i++) {
1322
+ if (current[i] !== next[i]) {
1323
+ break
1324
+ }
1325
+ }
1326
+ return {
1327
+ activated: next.slice(i),
1328
+ deactivated: current.slice(i)
1329
+ }
1330
+ }
1124
1331
 
1125
- /**
1126
- * Activate / switch component for a router-view.
1127
- *
1128
- * @param {Directive} view
1129
- * @param {Transition} transition
1130
- * @param {Number} depth
1131
- * @param {Function} [cb]
1132
- */
1133
-
1134
- function activate(view, transition, depth, cb, reuse) {
1135
- var handler = transition.activateQueue[depth];
1136
- if (!handler) {
1137
- saveChildView(view);
1138
- if (view._bound) {
1139
- view.setComponent(null);
1332
+ function extractLeaveGuards (matched) {
1333
+ return flatMapComponents(matched, function (def, instance) {
1334
+ var guard = def && def.beforeRouteLeave
1335
+ if (guard) {
1336
+ return function routeLeaveGuard () {
1337
+ return guard.apply(instance, arguments)
1140
1338
  }
1141
- cb && cb();
1142
- return;
1143
1339
  }
1144
-
1145
- var Component = view.Component = handler.component;
1146
- var activateHook = getRouteConfig(Component, 'activate');
1147
- var dataHook = getRouteConfig(Component, 'data');
1148
- var waitForData = getRouteConfig(Component, 'waitForData');
1149
-
1150
- view.depth = depth;
1151
- view.activated = false;
1152
-
1153
- var component = undefined;
1154
- var loading = !!(dataHook && !waitForData);
1155
-
1156
- // "reuse" is a flag passed down when the parent view is
1157
- // either reused via keep-alive or as a child of a kept-alive view.
1158
- // of course we can only reuse if the current kept-alive instance
1159
- // is of the correct type.
1160
- reuse = reuse && view.childVM && view.childVM.constructor === Component;
1161
-
1162
- if (reuse) {
1163
- // just reuse
1164
- component = view.childVM;
1165
- component.$loadingRouteData = loading;
1166
- } else {
1167
- saveChildView(view);
1168
-
1169
- // unbuild current component. this step also destroys
1170
- // and removes all nested child views.
1171
- view.unbuild(true);
1172
-
1173
- // build the new component. this will also create the
1174
- // direct child view of the current one. it will register
1175
- // itself as view.childView.
1176
- component = view.build({
1177
- _meta: {
1178
- $loadingRouteData: loading
1179
- },
1180
- created: function created() {
1181
- this._routerView = view;
1182
- }
1183
- });
1184
-
1185
- // handle keep-alive.
1186
- // when a kept-alive child vm is restored, we need to
1187
- // add its cached child views into the router's view list,
1188
- // and also properly update current view's child view.
1189
- if (view.keepAlive) {
1190
- component.$loadingRouteData = loading;
1191
- var cachedChildView = component._keepAliveRouterView;
1192
- if (cachedChildView) {
1193
- view.childView = cachedChildView;
1194
- component._keepAliveRouterView = null;
1195
- }
1340
+ }).reverse()
1341
+ }
1342
+
1343
+ function extractEnterGuards (matched, cbs) {
1344
+ return flatMapComponents(matched, function (def, _, match, key) {
1345
+ var guard = def && def.beforeRouteEnter
1346
+ if (guard) {
1347
+ return function routeEnterGuard (to, from, next) {
1348
+ return guard(to, from, function (cb) {
1349
+ next(cb)
1350
+ if (typeof cb === 'function') {
1351
+ cbs.push(function () {
1352
+ cb(match.instances[key])
1353
+ })
1354
+ }
1355
+ })
1196
1356
  }
1197
1357
  }
1358
+ })
1359
+ }
1198
1360
 
1199
- // cleanup the component in case the transition is aborted
1200
- // before the component is ever inserted.
1201
- var cleanup = function cleanup() {
1202
- component.$destroy();
1203
- };
1204
-
1205
- // actually insert the component and trigger transition
1206
- var insert = function insert() {
1207
- if (reuse) {
1208
- cb && cb();
1209
- return;
1210
- }
1211
- var router = transition.router;
1212
- if (router._rendered || router._transitionOnLoad) {
1213
- view.transition(component);
1214
- } else {
1215
- // no transition on first render, manual transition
1216
- /* istanbul ignore if */
1217
- if (view.setCurrent) {
1218
- // 0.12 compat
1219
- view.setCurrent(component);
1220
- } else {
1221
- // 1.0
1222
- view.childVM = component;
1361
+ function resolveAsyncComponents (matched) {
1362
+ return flatMapComponents(matched, function (def, _, match, key) {
1363
+ // if it's a function and doesn't have Vue options attached,
1364
+ // assume it's an async component resolve function.
1365
+ // we are not using Vue's default async resolving mechanism because
1366
+ // we want to halt the navigation until the incoming component has been
1367
+ // resolved.
1368
+ if (typeof def === 'function' && !def.options) {
1369
+ return function (to, from, next) {
1370
+ var resolve = function (resolvedDef) {
1371
+ match.components[key] = resolvedDef
1372
+ next()
1223
1373
  }
1224
- component.$before(view.anchor, null, false);
1225
- }
1226
- cb && cb();
1227
- };
1228
1374
 
1229
- var afterData = function afterData() {
1230
- // activate the child view
1231
- if (view.childView) {
1232
- activate(view.childView, transition, depth + 1, null, reuse || view.keepAlive);
1233
- }
1234
- insert();
1235
- };
1236
-
1237
- // called after activation hook is resolved
1238
- var afterActivate = function afterActivate() {
1239
- view.activated = true;
1240
- if (dataHook && waitForData) {
1241
- // wait until data loaded to insert
1242
- loadData(component, transition, dataHook, afterData, cleanup);
1243
- } else {
1244
- // load data and insert at the same time
1245
- if (dataHook) {
1246
- loadData(component, transition, dataHook);
1375
+ var reject = function (reason) {
1376
+ warn(false, ("Failed to resolve async component " + key + ": " + reason))
1377
+ next(false)
1247
1378
  }
1248
- afterData();
1249
- }
1250
- };
1251
1379
 
1252
- if (activateHook) {
1253
- transition.callHooks(activateHook, component, afterActivate, {
1254
- cleanup: cleanup,
1255
- postActivate: true
1256
- });
1257
- } else {
1258
- afterActivate();
1380
+ var res = def(resolve, reject)
1381
+ if (res && typeof res.then === 'function') {
1382
+ res.then(resolve, reject)
1383
+ }
1384
+ }
1259
1385
  }
1386
+ })
1387
+ }
1388
+
1389
+ function flatMapComponents (
1390
+ matched,
1391
+ fn
1392
+ ) {
1393
+ return Array.prototype.concat.apply([], matched.map(function (m) {
1394
+ return Object.keys(m.components).map(function (key) { return fn(
1395
+ m.components[key],
1396
+ m.instances[key],
1397
+ m, key
1398
+ ); })
1399
+ }))
1400
+ }
1401
+
1402
+ /* */
1403
+
1404
+ function saveScrollPosition (key) {
1405
+ if (!key) { return }
1406
+ window.sessionStorage.setItem(key, JSON.stringify({
1407
+ x: window.pageXOffset,
1408
+ y: window.pageYOffset
1409
+ }))
1410
+ }
1411
+
1412
+ function getScrollPosition (key) {
1413
+ if (!key) { return }
1414
+ return JSON.parse(window.sessionStorage.getItem(key))
1415
+ }
1416
+
1417
+ function getElementPosition (el) {
1418
+ var docRect = document.documentElement.getBoundingClientRect()
1419
+ var elRect = el.getBoundingClientRect()
1420
+ return {
1421
+ x: elRect.left - docRect.left,
1422
+ y: elRect.top - docRect.top
1260
1423
  }
1424
+ }
1261
1425
 
1262
- /**
1263
- * Reuse a view, just reload data if necessary.
1264
- *
1265
- * @param {Directive} view
1266
- * @param {Transition} transition
1267
- */
1426
+ function isValidPosition (obj) {
1427
+ return isNumber(obj.x) || isNumber(obj.y)
1428
+ }
1268
1429
 
1269
- function reuse(view, transition) {
1270
- var component = view.childVM;
1271
- var dataHook = getRouteConfig(component, 'data');
1272
- if (dataHook) {
1273
- loadData(component, transition, dataHook);
1274
- }
1430
+ function normalizePosition (obj) {
1431
+ return {
1432
+ x: isNumber(obj.x) ? obj.x : window.pageXOffset,
1433
+ y: isNumber(obj.y) ? obj.y : window.pageYOffset
1275
1434
  }
1435
+ }
1276
1436
 
1277
- /**
1278
- * Asynchronously load and apply data to component.
1279
- *
1280
- * @param {Vue} component
1281
- * @param {Transition} transition
1282
- * @param {Function} hook
1283
- * @param {Function} cb
1284
- * @param {Function} cleanup
1285
- */
1286
-
1287
- function loadData(component, transition, hook, cb, cleanup) {
1288
- component.$loadingRouteData = true;
1289
- transition.callHooks(hook, component, function () {
1290
- component.$loadingRouteData = false;
1291
- component.$emit('route-data-loaded', component);
1292
- cb && cb();
1293
- }, {
1294
- cleanup: cleanup,
1295
- postActivate: true,
1296
- processData: function processData(data) {
1297
- // handle promise sugar syntax
1298
- var promises = [];
1299
- if (isPlainObject(data)) {
1300
- Object.keys(data).forEach(function (key) {
1301
- var val = data[key];
1302
- if (isPromise(val)) {
1303
- promises.push(val.then(function (resolvedVal) {
1304
- component.$set(key, resolvedVal);
1305
- }));
1306
- } else {
1307
- component.$set(key, val);
1308
- }
1309
- });
1310
- }
1311
- if (promises.length) {
1312
- return promises[0].constructor.all(promises);
1313
- }
1314
- }
1315
- });
1316
- }
1437
+ function isNumber (v) {
1438
+ return typeof v === 'number'
1439
+ }
1317
1440
 
1318
- /**
1319
- * Save the child view for a kept-alive view so that
1320
- * we can restore it when it is switched back to.
1321
- *
1322
- * @param {Directive} view
1323
- */
1441
+ /* */
1324
1442
 
1325
- function saveChildView(view) {
1326
- if (view.keepAlive && view.childVM && view.childView) {
1327
- view.childVM._keepAliveRouterView = view.childView;
1328
- }
1329
- view.childView = null;
1330
- }
1331
-
1332
- /**
1333
- * Check plain object.
1334
- *
1335
- * @param {*} val
1336
- */
1337
-
1338
- function isPlainObject(val) {
1339
- return Object.prototype.toString.call(val) === '[object Object]';
1340
- }
1341
-
1342
- /**
1343
- * A RouteTransition object manages the pipeline of a
1344
- * router-view switching process. This is also the object
1345
- * passed into user route hooks.
1346
- *
1347
- * @param {Router} router
1348
- * @param {Route} to
1349
- * @param {Route} from
1350
- */
1351
-
1352
- var RouteTransition = (function () {
1353
- function RouteTransition(router, to, from) {
1354
- babelHelpers.classCallCheck(this, RouteTransition);
1355
-
1356
- this.router = router;
1357
- this.to = to;
1358
- this.from = from;
1359
- this.next = null;
1360
- this.aborted = false;
1361
- this.done = false;
1362
- }
1363
1443
 
1364
- /**
1365
- * Abort current transition and return to previous location.
1366
- */
1367
-
1368
- RouteTransition.prototype.abort = function abort() {
1369
- if (!this.aborted) {
1370
- this.aborted = true;
1371
- // if the root path throws an error during validation
1372
- // on initial load, it gets caught in an infinite loop.
1373
- var abortingOnLoad = !this.from.path && this.to.path === '/';
1374
- if (!abortingOnLoad) {
1375
- this.router.replace(this.from.path || '/');
1376
- }
1377
- }
1378
- };
1379
-
1380
- /**
1381
- * Abort current transition and redirect to a new location.
1382
- *
1383
- * @param {String} path
1384
- */
1385
-
1386
- RouteTransition.prototype.redirect = function redirect(path) {
1387
- if (!this.aborted) {
1388
- this.aborted = true;
1389
- if (typeof path === 'string') {
1390
- path = mapParams(path, this.to.params, this.to.query);
1391
- } else {
1392
- path.params = path.params || this.to.params;
1393
- path.query = path.query || this.to.query;
1394
- }
1395
- this.router.replace(path);
1396
- }
1397
- };
1398
-
1399
- /**
1400
- * A router view transition's pipeline can be described as
1401
- * follows, assuming we are transitioning from an existing
1402
- * <router-view> chain [Component A, Component B] to a new
1403
- * chain [Component A, Component C]:
1404
- *
1405
- * A A
1406
- * | => |
1407
- * B C
1408
- *
1409
- * 1. Reusablity phase:
1410
- * -> canReuse(A, A)
1411
- * -> canReuse(B, C)
1412
- * -> determine new queues:
1413
- * - deactivation: [B]
1414
- * - activation: [C]
1415
- *
1416
- * 2. Validation phase:
1417
- * -> canDeactivate(B)
1418
- * -> canActivate(C)
1419
- *
1420
- * 3. Activation phase:
1421
- * -> deactivate(B)
1422
- * -> activate(C)
1423
- *
1424
- * Each of these steps can be asynchronous, and any
1425
- * step can potentially abort the transition.
1426
- *
1427
- * @param {Function} cb
1428
- */
1429
-
1430
- RouteTransition.prototype.start = function start(cb) {
1431
- var transition = this;
1432
-
1433
- // determine the queue of views to deactivate
1434
- var deactivateQueue = [];
1435
- var view = this.router._rootView;
1436
- while (view) {
1437
- deactivateQueue.unshift(view);
1438
- view = view.childView;
1439
- }
1440
- var reverseDeactivateQueue = deactivateQueue.slice().reverse();
1441
-
1442
- // determine the queue of route handlers to activate
1443
- var activateQueue = this.activateQueue = toArray(this.to.matched).map(function (match) {
1444
- return match.handler;
1445
- });
1446
-
1447
- // 1. Reusability phase
1448
- var i = undefined,
1449
- reuseQueue = undefined;
1450
- for (i = 0; i < reverseDeactivateQueue.length; i++) {
1451
- if (!canReuse(reverseDeactivateQueue[i], activateQueue[i], transition)) {
1452
- break;
1453
- }
1454
- }
1455
- if (i > 0) {
1456
- reuseQueue = reverseDeactivateQueue.slice(0, i);
1457
- deactivateQueue = reverseDeactivateQueue.slice(i).reverse();
1458
- activateQueue = activateQueue.slice(i);
1459
- }
1444
+ var genKey = function () { return String(Date.now()); }
1445
+ var _key = genKey()
1460
1446
 
1461
- // 2. Validation phase
1462
- transition.runQueue(deactivateQueue, canDeactivate, function () {
1463
- transition.runQueue(activateQueue, canActivate, function () {
1464
- transition.runQueue(deactivateQueue, deactivate, function () {
1465
- // 3. Activation phase
1466
-
1467
- // Update router current route
1468
- transition.router._onTransitionValidated(transition);
1469
-
1470
- // trigger reuse for all reused views
1471
- reuseQueue && reuseQueue.forEach(function (view) {
1472
- return reuse(view, transition);
1473
- });
1474
-
1475
- // the root of the chain that needs to be replaced
1476
- // is the top-most non-reusable view.
1477
- if (deactivateQueue.length) {
1478
- var _view = deactivateQueue[deactivateQueue.length - 1];
1479
- var depth = reuseQueue ? reuseQueue.length : 0;
1480
- activate(_view, transition, depth, cb);
1481
- } else {
1482
- cb();
1483
- }
1484
- });
1485
- });
1486
- });
1487
- };
1488
-
1489
- /**
1490
- * Asynchronously and sequentially apply a function to a
1491
- * queue.
1492
- *
1493
- * @param {Array} queue
1494
- * @param {Function} fn
1495
- * @param {Function} cb
1496
- */
1497
-
1498
- RouteTransition.prototype.runQueue = function runQueue(queue, fn, cb) {
1499
- var transition = this;
1500
- step(0);
1501
- function step(index) {
1502
- if (index >= queue.length) {
1503
- cb();
1504
- } else {
1505
- fn(queue[index], transition, function () {
1506
- step(index + 1);
1507
- });
1508
- }
1509
- }
1510
- };
1511
-
1512
- /**
1513
- * Call a user provided route transition hook and handle
1514
- * the response (e.g. if the user returns a promise).
1515
- *
1516
- * If the user neither expects an argument nor returns a
1517
- * promise, the hook is assumed to be synchronous.
1518
- *
1519
- * @param {Function} hook
1520
- * @param {*} [context]
1521
- * @param {Function} [cb]
1522
- * @param {Object} [options]
1523
- * - {Boolean} expectBoolean
1524
- * - {Boolean} postActive
1525
- * - {Function} processData
1526
- * - {Function} cleanup
1527
- */
1528
-
1529
- RouteTransition.prototype.callHook = function callHook(hook, context, cb) {
1530
- var _ref = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
1531
-
1532
- var _ref$expectBoolean = _ref.expectBoolean;
1533
- var expectBoolean = _ref$expectBoolean === undefined ? false : _ref$expectBoolean;
1534
- var _ref$postActivate = _ref.postActivate;
1535
- var postActivate = _ref$postActivate === undefined ? false : _ref$postActivate;
1536
- var processData = _ref.processData;
1537
- var cleanup = _ref.cleanup;
1538
-
1539
- var transition = this;
1540
- var nextCalled = false;
1541
-
1542
- // abort the transition
1543
- var abort = function abort() {
1544
- cleanup && cleanup();
1545
- transition.abort();
1546
- };
1547
-
1548
- // handle errors
1549
- var onError = function onError(err) {
1550
- postActivate ? next() : abort();
1551
- if (err && !transition.router._suppress) {
1552
- warn$1('Uncaught error during transition: ');
1553
- throw err instanceof Error ? err : new Error(err);
1554
- }
1555
- };
1556
-
1557
- // since promise swallows errors, we have to
1558
- // throw it in the next tick...
1559
- var onPromiseError = function onPromiseError(err) {
1560
- try {
1561
- onError(err);
1562
- } catch (e) {
1563
- setTimeout(function () {
1564
- throw e;
1565
- }, 0);
1566
- }
1567
- };
1447
+ var HTML5History = (function (History) {
1448
+ function HTML5History (router, base) {
1449
+ var this$1 = this;
1568
1450
 
1569
- // advance the transition to the next step
1570
- var next = function next() {
1571
- if (nextCalled) {
1572
- warn$1('transition.next() should be called only once.');
1573
- return;
1574
- }
1575
- nextCalled = true;
1576
- if (transition.aborted) {
1577
- cleanup && cleanup();
1578
- return;
1579
- }
1580
- cb && cb();
1581
- };
1582
-
1583
- var nextWithBoolean = function nextWithBoolean(res) {
1584
- if (typeof res === 'boolean') {
1585
- res ? next() : abort();
1586
- } else if (isPromise(res)) {
1587
- res.then(function (ok) {
1588
- ok ? next() : abort();
1589
- }, onPromiseError);
1590
- } else if (!hook.length) {
1591
- next();
1592
- }
1593
- };
1594
-
1595
- var nextWithData = function nextWithData(data) {
1596
- var res = undefined;
1597
- try {
1598
- res = processData(data);
1599
- } catch (err) {
1600
- return onError(err);
1601
- }
1602
- if (isPromise(res)) {
1603
- res.then(next, onPromiseError);
1604
- } else {
1605
- next();
1606
- }
1607
- };
1608
-
1609
- // expose a clone of the transition object, so that each
1610
- // hook gets a clean copy and prevent the user from
1611
- // messing with the internals.
1612
- var exposed = {
1613
- to: transition.to,
1614
- from: transition.from,
1615
- abort: abort,
1616
- next: processData ? nextWithData : next,
1617
- redirect: function redirect() {
1618
- transition.redirect.apply(transition, arguments);
1619
- }
1620
- };
1621
-
1622
- // actually call the hook
1623
- var res = undefined;
1624
- try {
1625
- res = hook.call(context, exposed);
1626
- } catch (err) {
1627
- return onError(err);
1628
- }
1451
+ History.call(this, router, base)
1629
1452
 
1630
- if (expectBoolean) {
1631
- // boolean hooks
1632
- nextWithBoolean(res);
1633
- } else if (isPromise(res)) {
1634
- // promise
1635
- if (processData) {
1636
- res.then(nextWithData, onPromiseError);
1637
- } else {
1638
- res.then(next, onPromiseError);
1639
- }
1640
- } else if (processData && isPlainOjbect(res)) {
1641
- // data promise sugar
1642
- nextWithData(res);
1643
- } else if (!hook.length) {
1644
- next();
1645
- }
1646
- };
1647
-
1648
- /**
1649
- * Call a single hook or an array of async hooks in series.
1650
- *
1651
- * @param {Array} hooks
1652
- * @param {*} context
1653
- * @param {Function} cb
1654
- * @param {Object} [options]
1655
- */
1656
-
1657
- RouteTransition.prototype.callHooks = function callHooks(hooks, context, cb, options) {
1658
- var _this = this;
1659
-
1660
- if (Array.isArray(hooks)) {
1661
- this.runQueue(hooks, function (hook, _, next) {
1662
- if (!_this.aborted) {
1663
- _this.callHook(hook, context, next, options);
1664
- }
1665
- }, cb);
1666
- } else {
1667
- this.callHook(hooks, context, cb, options);
1668
- }
1669
- };
1453
+ this.transitionTo(getLocation(this.base))
1670
1454
 
1671
- return RouteTransition;
1672
- })();
1455
+ var expectScroll = router.options.scrollBehavior
1456
+ window.addEventListener('popstate', function (e) {
1457
+ _key = e.state && e.state.key
1458
+ var current = this$1.current
1459
+ this$1.transitionTo(getLocation(this$1.base), function (next) {
1460
+ if (expectScroll) {
1461
+ this$1.handleScroll(next, current, true)
1462
+ }
1463
+ })
1464
+ })
1673
1465
 
1674
- function isPlainOjbect(val) {
1675
- return Object.prototype.toString.call(val) === '[object Object]';
1466
+ if (expectScroll) {
1467
+ window.addEventListener('scroll', function () {
1468
+ saveScrollPosition(_key)
1469
+ })
1470
+ }
1676
1471
  }
1677
1472
 
1678
- function toArray(val) {
1679
- return val ? Array.prototype.slice.call(val) : [];
1680
- }
1473
+ if ( History ) HTML5History.__proto__ = History;
1474
+ HTML5History.prototype = Object.create( History && History.prototype );
1475
+ HTML5History.prototype.constructor = HTML5History;
1681
1476
 
1682
- var internalKeysRE = /^(component|subRoutes|fullPath)$/;
1477
+ HTML5History.prototype.go = function go (n) {
1478
+ window.history.go(n)
1479
+ };
1683
1480
 
1684
- /**
1685
- * Route Context Object
1686
- *
1687
- * @param {String} path
1688
- * @param {Router} router
1689
- */
1481
+ HTML5History.prototype.push = function push (location) {
1482
+ var this$1 = this;
1690
1483
 
1691
- var Route = function Route(path, router) {
1692
- var _this = this;
1484
+ var current = this.current
1485
+ this.transitionTo(location, function (route) {
1486
+ pushState(cleanPath(this$1.base + route.fullPath))
1487
+ this$1.handleScroll(route, current, false)
1488
+ })
1489
+ };
1693
1490
 
1694
- babelHelpers.classCallCheck(this, Route);
1491
+ HTML5History.prototype.replace = function replace (location) {
1492
+ var this$1 = this;
1695
1493
 
1696
- var matched = router._recognizer.recognize(path);
1697
- if (matched) {
1698
- // copy all custom fields from route configs
1699
- [].forEach.call(matched, function (match) {
1700
- for (var key in match.handler) {
1701
- if (!internalKeysRE.test(key)) {
1702
- _this[key] = match.handler[key];
1703
- }
1704
- }
1705
- });
1706
- // set query and params
1707
- this.query = matched.queryParams;
1708
- this.params = [].reduce.call(matched, function (prev, cur) {
1709
- if (cur.params) {
1710
- for (var key in cur.params) {
1711
- prev[key] = cur.params[key];
1712
- }
1713
- }
1714
- return prev;
1715
- }, {});
1494
+ var current = this.current
1495
+ this.transitionTo(location, function (route) {
1496
+ replaceState(cleanPath(this$1.base + route.fullPath))
1497
+ this$1.handleScroll(route, current, false)
1498
+ })
1499
+ };
1500
+
1501
+ HTML5History.prototype.ensureURL = function ensureURL () {
1502
+ if (getLocation(this.base) !== this.current.fullPath) {
1503
+ replaceState(cleanPath(this.base + this.current.fullPath))
1716
1504
  }
1717
- // expose path and router
1718
- this.path = path;
1719
- // for internal use
1720
- this.matched = matched || router._notFoundHandler;
1721
- // internal reference to router
1722
- Object.defineProperty(this, 'router', {
1723
- enumerable: false,
1724
- value: router
1725
- });
1726
- // Important: freeze self to prevent observation
1727
- Object.freeze(this);
1728
1505
  };
1729
1506
 
1730
- function applyOverride (Vue) {
1731
- var _Vue$util = Vue.util;
1732
- var extend = _Vue$util.extend;
1733
- var isArray = _Vue$util.isArray;
1734
- var defineReactive = _Vue$util.defineReactive;
1735
-
1736
- // override Vue's init and destroy process to keep track of router instances
1737
- var init = Vue.prototype._init;
1738
- Vue.prototype._init = function (options) {
1739
- options = options || {};
1740
- var root = options._parent || options.parent || this;
1741
- var router = root.$router;
1742
- var route = root.$route;
1743
- if (router) {
1744
- // expose router
1745
- this.$router = router;
1746
- router._children.push(this);
1747
- /* istanbul ignore if */
1748
- if (this._defineMeta) {
1749
- // 0.12
1750
- this._defineMeta('$route', route);
1751
- } else {
1752
- // 1.0
1753
- defineReactive(this, '$route', route);
1507
+ HTML5History.prototype.handleScroll = function handleScroll (to, from, isPop) {
1508
+ var router = this.router
1509
+ if (!router.app) {
1510
+ return
1511
+ }
1512
+
1513
+ var behavior = router.options.scrollBehavior
1514
+ if (!behavior) {
1515
+ return
1516
+ }
1517
+ assert(typeof behavior === 'function', "scrollBehavior must be a function")
1518
+
1519
+ // wait until re-render finishes before scrolling
1520
+ router.app.$nextTick(function () {
1521
+ var position = getScrollPosition(_key)
1522
+ var shouldScroll = behavior(to, from, isPop ? position : null)
1523
+ if (!shouldScroll) {
1524
+ return
1525
+ }
1526
+ var isObject = typeof shouldScroll === 'object'
1527
+ if (isObject && typeof shouldScroll.selector === 'string') {
1528
+ var el = document.querySelector(shouldScroll.selector)
1529
+ if (el) {
1530
+ position = getElementPosition(el)
1531
+ } else if (isValidPosition(shouldScroll)) {
1532
+ position = normalizePosition(shouldScroll)
1754
1533
  }
1534
+ } else if (isObject && isValidPosition(shouldScroll)) {
1535
+ position = normalizePosition(shouldScroll)
1755
1536
  }
1756
- init.call(this, options);
1757
- };
1758
1537
 
1759
- var destroy = Vue.prototype._destroy;
1760
- Vue.prototype._destroy = function () {
1761
- if (!this._isBeingDestroyed && this.$router) {
1762
- this.$router._children.$remove(this);
1538
+ if (position) {
1539
+ window.scrollTo(position.x, position.y)
1763
1540
  }
1764
- destroy.apply(this, arguments);
1765
- };
1766
-
1767
- // 1.0 only: enable route mixins
1768
- var strats = Vue.config.optionMergeStrategies;
1769
- var hooksToMergeRE = /^(data|activate|deactivate)$/;
1770
-
1771
- if (strats) {
1772
- strats.route = function (parentVal, childVal) {
1773
- if (!childVal) return parentVal;
1774
- if (!parentVal) return childVal;
1775
- var ret = {};
1776
- extend(ret, parentVal);
1777
- for (var key in childVal) {
1778
- var a = ret[key];
1779
- var b = childVal[key];
1780
- // for data, activate and deactivate, we need to merge them into
1781
- // arrays similar to lifecycle hooks.
1782
- if (a && hooksToMergeRE.test(key)) {
1783
- ret[key] = (isArray(a) ? a : [a]).concat(b);
1784
- } else {
1785
- ret[key] = b;
1786
- }
1787
- }
1788
- return ret;
1789
- };
1541
+ })
1542
+ };
1543
+
1544
+ return HTML5History;
1545
+ }(History));
1546
+
1547
+ function getLocation (base) {
1548
+ var path = window.location.pathname
1549
+ if (base && path.indexOf(base) === 0) {
1550
+ path = path.slice(base.length)
1551
+ }
1552
+ return (path || '/') + window.location.search + window.location.hash
1553
+ }
1554
+
1555
+ function pushState (url, replace) {
1556
+ // try...catch the pushState call to get around Safari
1557
+ // DOM Exception 18 where it limits to 100 pushState calls
1558
+ var history = window.history
1559
+ try {
1560
+ if (replace) {
1561
+ history.replaceState({ key: _key }, '', url)
1562
+ } else {
1563
+ _key = genKey()
1564
+ history.pushState({ key: _key }, '', url)
1790
1565
  }
1566
+ saveScrollPosition(_key)
1567
+ } catch (e) {
1568
+ window.location[replace ? 'assign' : 'replace'](url)
1791
1569
  }
1570
+ }
1792
1571
 
1793
- function View (Vue) {
1572
+ function replaceState (url) {
1573
+ pushState(url, true)
1574
+ }
1794
1575
 
1795
- var _ = Vue.util;
1796
- var componentDef =
1797
- // 0.12
1798
- Vue.directive('_component') ||
1799
- // 1.0
1800
- Vue.internalDirectives.component;
1801
- // <router-view> extends the internal component directive
1802
- var viewDef = _.extend({}, componentDef);
1576
+ /* */
1803
1577
 
1804
- // with some overrides
1805
- _.extend(viewDef, {
1806
1578
 
1807
- _isRouterView: true,
1579
+ var HashHistory = (function (History) {
1580
+ function HashHistory (router, base, fallback) {
1581
+ var this$1 = this;
1808
1582
 
1809
- bind: function bind() {
1810
- var route = this.vm.$route;
1811
- /* istanbul ignore if */
1812
- if (!route) {
1813
- warn$1('<router-view> can only be used inside a ' + 'router-enabled app.');
1814
- return;
1815
- }
1816
- // force dynamic directive so v-component doesn't
1817
- // attempt to build right now
1818
- this._isDynamicLiteral = true;
1819
- // finally, init by delegating to v-component
1820
- componentDef.bind.call(this);
1821
-
1822
- // locate the parent view
1823
- var parentView = undefined;
1824
- var parent = this.vm;
1825
- while (parent) {
1826
- if (parent._routerView) {
1827
- parentView = parent._routerView;
1828
- break;
1829
- }
1830
- parent = parent.$parent;
1831
- }
1832
- if (parentView) {
1833
- // register self as a child of the parent view,
1834
- // instead of activating now. This is so that the
1835
- // child's activate hook is called after the
1836
- // parent's has resolved.
1837
- this.parentView = parentView;
1838
- parentView.childView = this;
1839
- } else {
1840
- // this is the root view!
1841
- var router = route.router;
1842
- router._rootView = this;
1843
- }
1583
+ History.call(this, router, base)
1844
1584
 
1845
- // handle late-rendered view
1846
- // two possibilities:
1847
- // 1. root view rendered after transition has been
1848
- // validated;
1849
- // 2. child view rendered after parent view has been
1850
- // activated.
1851
- var transition = route.router._currentTransition;
1852
- if (!parentView && transition.done || parentView && parentView.activated) {
1853
- var depth = parentView ? parentView.depth + 1 : 0;
1854
- activate(this, transition, depth);
1855
- }
1856
- },
1585
+ // check history fallback deeplinking
1586
+ if (fallback && this.checkFallback()) {
1587
+ return
1588
+ }
1857
1589
 
1858
- unbind: function unbind() {
1859
- if (this.parentView) {
1860
- this.parentView.childView = null;
1861
- }
1862
- componentDef.unbind.call(this);
1863
- }
1864
- });
1865
-
1866
- Vue.elementDirective('router-view', viewDef);
1867
- }
1868
-
1869
- var trailingSlashRE = /\/$/;
1870
- var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g;
1871
- var queryStringRE = /\?.*$/;
1872
-
1873
- // install v-link, which provides navigation support for
1874
- // HTML5 history mode
1875
- function Link (Vue) {
1876
- var _Vue$util = Vue.util;
1877
- var _bind = _Vue$util.bind;
1878
- var isObject = _Vue$util.isObject;
1879
- var addClass = _Vue$util.addClass;
1880
- var removeClass = _Vue$util.removeClass;
1881
-
1882
- var onPriority = Vue.directive('on').priority;
1883
- var LINK_UPDATE = '__vue-router-link-update__';
1884
-
1885
- var activeId = 0;
1886
-
1887
- Vue.directive('link-active', {
1888
- priority: 9999,
1889
- bind: function bind() {
1890
- var _this = this;
1891
-
1892
- var id = String(activeId++);
1893
- // collect v-links contained within this element.
1894
- // we need do this here before the parent-child relationship
1895
- // gets messed up by terminal directives (if, for, components)
1896
- var childLinks = this.el.querySelectorAll('[v-link]');
1897
- for (var i = 0, l = childLinks.length; i < l; i++) {
1898
- var link = childLinks[i];
1899
- var existingId = link.getAttribute(LINK_UPDATE);
1900
- var value = existingId ? existingId + ',' + id : id;
1901
- // leave a mark on the link element which can be persisted
1902
- // through fragment clones.
1903
- link.setAttribute(LINK_UPDATE, value);
1904
- }
1905
- this.vm.$on(LINK_UPDATE, this.cb = function (link, path) {
1906
- if (link.activeIds.indexOf(id) > -1) {
1907
- link.updateClasses(path, _this.el);
1908
- }
1909
- });
1910
- },
1911
- unbind: function unbind() {
1912
- this.vm.$off(LINK_UPDATE, this.cb);
1913
- }
1914
- });
1590
+ ensureSlash()
1591
+ this.transitionTo(getHash())
1915
1592
 
1916
- Vue.directive('link', {
1917
- priority: onPriority - 2,
1593
+ window.addEventListener('hashchange', function () {
1594
+ this$1.onHashChange()
1595
+ })
1596
+ }
1918
1597
 
1919
- bind: function bind() {
1920
- var vm = this.vm;
1921
- /* istanbul ignore if */
1922
- if (!vm.$route) {
1923
- warn$1('v-link can only be used inside a router-enabled app.');
1924
- return;
1925
- }
1926
- this.router = vm.$route.router;
1927
- // update things when the route changes
1928
- this.unwatch = vm.$watch('$route', _bind(this.onRouteUpdate, this));
1929
- // check v-link-active ids
1930
- var activeIds = this.el.getAttribute(LINK_UPDATE);
1931
- if (activeIds) {
1932
- this.el.removeAttribute(LINK_UPDATE);
1933
- this.activeIds = activeIds.split(',');
1934
- }
1935
- // no need to handle click if link expects to be opened
1936
- // in a new window/tab.
1937
- /* istanbul ignore if */
1938
- if (this.el.tagName === 'A' && this.el.getAttribute('target') === '_blank') {
1939
- return;
1940
- }
1941
- // handle click
1942
- this.handler = _bind(this.onClick, this);
1943
- this.el.addEventListener('click', this.handler);
1944
- },
1945
-
1946
- update: function update(target) {
1947
- this.target = target;
1948
- if (isObject(target)) {
1949
- this.append = target.append;
1950
- this.exact = target.exact;
1951
- this.prevActiveClass = this.activeClass;
1952
- this.activeClass = target.activeClass;
1953
- }
1954
- this.onRouteUpdate(this.vm.$route);
1955
- },
1956
-
1957
- onClick: function onClick(e) {
1958
- // don't redirect with control keys
1959
- /* istanbul ignore if */
1960
- if (e.metaKey || e.ctrlKey || e.shiftKey) return;
1961
- // don't redirect when preventDefault called
1962
- /* istanbul ignore if */
1963
- if (e.defaultPrevented) return;
1964
- // don't redirect on right click
1965
- /* istanbul ignore if */
1966
- if (e.button !== 0) return;
1967
-
1968
- var target = this.target;
1969
- if (target) {
1970
- // v-link with expression, just go
1971
- e.preventDefault();
1972
- this.router.go(target);
1973
- } else {
1974
- // no expression, delegate for an <a> inside
1975
- var el = e.target;
1976
- while (el.tagName !== 'A' && el !== this.el) {
1977
- el = el.parentNode;
1978
- }
1979
- if (el.tagName === 'A' && sameOrigin(el)) {
1980
- e.preventDefault();
1981
- var path = el.pathname;
1982
- if (this.router.history.root) {
1983
- path = path.replace(this.router.history.rootRE, '');
1984
- }
1985
- this.router.go({
1986
- path: path,
1987
- replace: target && target.replace,
1988
- append: target && target.append
1989
- });
1990
- }
1991
- }
1992
- },
1993
-
1994
- onRouteUpdate: function onRouteUpdate(route) {
1995
- // router.stringifyPath is dependent on current route
1996
- // and needs to be called again whenver route changes.
1997
- var newPath = this.router.stringifyPath(this.target);
1998
- if (this.path !== newPath) {
1999
- this.path = newPath;
2000
- this.updateActiveMatch();
2001
- this.updateHref();
2002
- }
2003
- if (this.activeIds) {
2004
- this.vm.$emit(LINK_UPDATE, this, route.path);
2005
- } else {
2006
- this.updateClasses(route.path, this.el);
2007
- }
2008
- },
1598
+ if ( History ) HashHistory.__proto__ = History;
1599
+ HashHistory.prototype = Object.create( History && History.prototype );
1600
+ HashHistory.prototype.constructor = HashHistory;
1601
+
1602
+ HashHistory.prototype.checkFallback = function checkFallback () {
1603
+ var location = getLocation(this.base)
1604
+ if (!/^\/#/.test(location)) {
1605
+ window.location.replace(
1606
+ cleanPath(this.base + '/#' + location)
1607
+ )
1608
+ return true
1609
+ }
1610
+ };
2009
1611
 
2010
- updateActiveMatch: function updateActiveMatch() {
2011
- this.activeRE = this.path && !this.exact ? new RegExp('^' + this.path.replace(/\/$/, '').replace(queryStringRE, '').replace(regexEscapeRE, '\\$&') + '(\\/|$)') : null;
2012
- },
1612
+ HashHistory.prototype.onHashChange = function onHashChange () {
1613
+ if (!ensureSlash()) {
1614
+ return
1615
+ }
1616
+ this.transitionTo(getHash(), function (route) {
1617
+ replaceHash(route.fullPath)
1618
+ })
1619
+ };
2013
1620
 
2014
- updateHref: function updateHref() {
2015
- if (this.el.tagName !== 'A') {
2016
- return;
2017
- }
2018
- var path = this.path;
2019
- var router = this.router;
2020
- var isAbsolute = path.charAt(0) === '/';
2021
- // do not format non-hash relative paths
2022
- var href = path && (router.mode === 'hash' || isAbsolute) ? router.history.formatPath(path, this.append) : path;
2023
- if (href) {
2024
- this.el.href = href;
2025
- } else {
2026
- this.el.removeAttribute('href');
2027
- }
2028
- },
1621
+ HashHistory.prototype.push = function push (location) {
1622
+ History.prototype.transitionTo.call(this, location, function (route) {
1623
+ pushHash(route.fullPath)
1624
+ })
1625
+ };
2029
1626
 
2030
- updateClasses: function updateClasses(path, el) {
2031
- var activeClass = this.activeClass || this.router._linkActiveClass;
2032
- // clear old class
2033
- if (this.prevActiveClass && this.prevActiveClass !== activeClass) {
2034
- toggleClasses(el, this.prevActiveClass, removeClass);
2035
- }
2036
- // remove query string before matching
2037
- var dest = this.path.replace(queryStringRE, '');
2038
- path = path.replace(queryStringRE, '');
2039
- // add new class
2040
- if (this.exact) {
2041
- if (dest === path ||
2042
- // also allow additional trailing slash
2043
- dest.charAt(dest.length - 1) !== '/' && dest === path.replace(trailingSlashRE, '')) {
2044
- toggleClasses(el, activeClass, addClass);
2045
- } else {
2046
- toggleClasses(el, activeClass, removeClass);
2047
- }
2048
- } else {
2049
- if (this.activeRE && this.activeRE.test(path)) {
2050
- toggleClasses(el, activeClass, addClass);
2051
- } else {
2052
- toggleClasses(el, activeClass, removeClass);
2053
- }
2054
- }
2055
- },
1627
+ HashHistory.prototype.replace = function replace (location) {
1628
+ History.prototype.transitionTo.call(this, location, function (route) {
1629
+ replaceHash(route.fullPath)
1630
+ })
1631
+ };
2056
1632
 
2057
- unbind: function unbind() {
2058
- this.el.removeEventListener('click', this.handler);
2059
- this.unwatch && this.unwatch();
2060
- }
2061
- });
1633
+ HashHistory.prototype.go = function go (n) {
1634
+ window.history.go(n)
1635
+ };
2062
1636
 
2063
- function sameOrigin(link) {
2064
- return link.protocol === location.protocol && link.hostname === location.hostname && link.port === location.port;
1637
+ HashHistory.prototype.ensureURL = function ensureURL () {
1638
+ if (getHash() !== this.current.fullPath) {
1639
+ replaceHash(this.current.fullPath)
2065
1640
  }
1641
+ };
2066
1642
 
2067
- // this function is copied from v-bind:class implementation until
2068
- // we properly expose it...
2069
- function toggleClasses(el, key, fn) {
2070
- key = key.trim();
2071
- if (key.indexOf(' ') === -1) {
2072
- fn(el, key);
2073
- return;
2074
- }
2075
- var keys = key.split(/\s+/);
2076
- for (var i = 0, l = keys.length; i < l; i++) {
2077
- fn(el, keys[i]);
2078
- }
2079
- }
1643
+ return HashHistory;
1644
+ }(History));
1645
+
1646
+ function ensureSlash () {
1647
+ var path = getHash()
1648
+ if (path.charAt(0) === '/') {
1649
+ return true
1650
+ }
1651
+ replaceHash('/' + path)
1652
+ return false
1653
+ }
1654
+
1655
+ function getHash () {
1656
+ // We can't use window.location.hash here because it's not
1657
+ // consistent across browsers - Firefox will pre-decode it!
1658
+ var href = window.location.href
1659
+ var index = href.indexOf('#')
1660
+ return index === -1 ? '' : href.slice(index + 1)
1661
+ }
1662
+
1663
+ function pushHash (path) {
1664
+ window.location.hash = path
1665
+ }
1666
+
1667
+ function replaceHash (path) {
1668
+ var i = window.location.href.indexOf('#')
1669
+ window.location.replace(
1670
+ window.location.href.slice(0, i >= 0 ? i : 0) + '#' + path
1671
+ )
1672
+ }
1673
+
1674
+ /* */
1675
+
1676
+
1677
+ var AbstractHistory = (function (History) {
1678
+ function AbstractHistory (router) {
1679
+ History.call(this, router)
1680
+ this.stack = []
1681
+ this.index = 0
2080
1682
  }
2081
1683
 
2082
- var historyBackends = {
2083
- abstract: AbstractHistory,
2084
- hash: HashHistory,
2085
- html5: HTML5History
1684
+ if ( History ) AbstractHistory.__proto__ = History;
1685
+ AbstractHistory.prototype = Object.create( History && History.prototype );
1686
+ AbstractHistory.prototype.constructor = AbstractHistory;
1687
+
1688
+ AbstractHistory.prototype.push = function push (location) {
1689
+ var this$1 = this;
1690
+
1691
+ History.prototype.transitionTo.call(this, location, function (route) {
1692
+ this$1.stack = this$1.stack.slice(0, this$1.index + 1).concat(route)
1693
+ this$1.index++
1694
+ })
2086
1695
  };
2087
1696
 
2088
- // late bind during install
2089
- var Vue = undefined;
2090
-
2091
- /**
2092
- * Router constructor
2093
- *
2094
- * @param {Object} [options]
2095
- */
2096
-
2097
- var Router = (function () {
2098
- function Router() {
2099
- var _this = this;
2100
-
2101
- var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
2102
-
2103
- var _ref$hashbang = _ref.hashbang;
2104
- var hashbang = _ref$hashbang === undefined ? true : _ref$hashbang;
2105
- var _ref$abstract = _ref.abstract;
2106
- var abstract = _ref$abstract === undefined ? false : _ref$abstract;
2107
- var _ref$history = _ref.history;
2108
- var history = _ref$history === undefined ? false : _ref$history;
2109
- var _ref$saveScrollPosition = _ref.saveScrollPosition;
2110
- var saveScrollPosition = _ref$saveScrollPosition === undefined ? false : _ref$saveScrollPosition;
2111
- var _ref$transitionOnLoad = _ref.transitionOnLoad;
2112
- var transitionOnLoad = _ref$transitionOnLoad === undefined ? false : _ref$transitionOnLoad;
2113
- var _ref$suppressTransitionError = _ref.suppressTransitionError;
2114
- var suppressTransitionError = _ref$suppressTransitionError === undefined ? false : _ref$suppressTransitionError;
2115
- var _ref$root = _ref.root;
2116
- var root = _ref$root === undefined ? null : _ref$root;
2117
- var _ref$linkActiveClass = _ref.linkActiveClass;
2118
- var linkActiveClass = _ref$linkActiveClass === undefined ? 'v-link-active' : _ref$linkActiveClass;
2119
- babelHelpers.classCallCheck(this, Router);
2120
-
2121
- /* istanbul ignore if */
2122
- if (!Router.installed) {
2123
- throw new Error('Please install the Router with Vue.use() before ' + 'creating an instance.');
2124
- }
1697
+ AbstractHistory.prototype.replace = function replace (location) {
1698
+ var this$1 = this;
2125
1699
 
2126
- // Vue instances
2127
- this.app = null;
2128
- this._children = [];
2129
-
2130
- // route recognizer
2131
- this._recognizer = new RouteRecognizer();
2132
- this._guardRecognizer = new RouteRecognizer();
2133
-
2134
- // state
2135
- this._started = false;
2136
- this._startCb = null;
2137
- this._currentRoute = {};
2138
- this._currentTransition = null;
2139
- this._previousTransition = null;
2140
- this._notFoundHandler = null;
2141
- this._notFoundRedirect = null;
2142
- this._beforeEachHooks = [];
2143
- this._afterEachHooks = [];
2144
-
2145
- // trigger transition on initial render?
2146
- this._rendered = false;
2147
- this._transitionOnLoad = transitionOnLoad;
2148
-
2149
- // history mode
2150
- this._root = root;
2151
- this._abstract = abstract;
2152
- this._hashbang = hashbang;
2153
-
2154
- // check if HTML5 history is available
2155
- var hasPushState = typeof window !== 'undefined' && window.history && window.history.pushState;
2156
- this._history = history && hasPushState;
2157
- this._historyFallback = history && !hasPushState;
2158
-
2159
- // create history object
2160
- var inBrowser = Vue.util.inBrowser;
2161
- this.mode = !inBrowser || this._abstract ? 'abstract' : this._history ? 'html5' : 'hash';
2162
-
2163
- var History = historyBackends[this.mode];
2164
- this.history = new History({
2165
- root: root,
2166
- hashbang: this._hashbang,
2167
- onChange: function onChange(path, state, anchor) {
2168
- _this._match(path, state, anchor);
2169
- }
2170
- });
1700
+ History.prototype.transitionTo.call(this, location, function (route) {
1701
+ this$1.stack = this$1.stack.slice(0, this$1.index).concat(route)
1702
+ })
1703
+ };
1704
+
1705
+ AbstractHistory.prototype.go = function go (n) {
1706
+ var this$1 = this;
2171
1707
 
2172
- // other options
2173
- this._saveScrollPosition = saveScrollPosition;
2174
- this._linkActiveClass = linkActiveClass;
2175
- this._suppress = suppressTransitionError;
1708
+ var targetIndex = this.index + n
1709
+ if (targetIndex < 0 || targetIndex >= this.stack.length) {
1710
+ return
2176
1711
  }
1712
+ var location = this.stack[targetIndex]
1713
+ this.confirmTransition(location, function () {
1714
+ this$1.index = targetIndex
1715
+ this$1.updateRoute(location)
1716
+ })
1717
+ };
2177
1718
 
2178
- /**
2179
- * Allow directly passing components to a route
2180
- * definition.
2181
- *
2182
- * @param {String} path
2183
- * @param {Object} handler
2184
- */
2185
-
2186
- // API ===================================================
2187
-
2188
- /**
2189
- * Register a map of top-level paths.
2190
- *
2191
- * @param {Object} map
2192
- */
2193
-
2194
- Router.prototype.map = function map(_map) {
2195
- for (var route in _map) {
2196
- this.on(route, _map[route]);
2197
- }
2198
- return this;
2199
- };
2200
-
2201
- /**
2202
- * Register a single root-level path
2203
- *
2204
- * @param {String} rootPath
2205
- * @param {Object} handler
2206
- * - {String} component
2207
- * - {Object} [subRoutes]
2208
- * - {Boolean} [forceRefresh]
2209
- * - {Function} [before]
2210
- * - {Function} [after]
2211
- */
2212
-
2213
- Router.prototype.on = function on(rootPath, handler) {
2214
- if (rootPath === '*') {
2215
- this._notFound(handler);
2216
- } else {
2217
- this._addRoute(rootPath, handler, []);
2218
- }
2219
- return this;
2220
- };
2221
-
2222
- /**
2223
- * Set redirects.
2224
- *
2225
- * @param {Object} map
2226
- */
2227
-
2228
- Router.prototype.redirect = function redirect(map) {
2229
- for (var path in map) {
2230
- this._addRedirect(path, map[path]);
2231
- }
2232
- return this;
2233
- };
2234
-
2235
- /**
2236
- * Set aliases.
2237
- *
2238
- * @param {Object} map
2239
- */
2240
-
2241
- Router.prototype.alias = function alias(map) {
2242
- for (var path in map) {
2243
- this._addAlias(path, map[path]);
2244
- }
2245
- return this;
2246
- };
2247
-
2248
- /**
2249
- * Set global before hook.
2250
- *
2251
- * @param {Function} fn
2252
- */
2253
-
2254
- Router.prototype.beforeEach = function beforeEach(fn) {
2255
- this._beforeEachHooks.push(fn);
2256
- return this;
2257
- };
2258
-
2259
- /**
2260
- * Set global after hook.
2261
- *
2262
- * @param {Function} fn
2263
- */
2264
-
2265
- Router.prototype.afterEach = function afterEach(fn) {
2266
- this._afterEachHooks.push(fn);
2267
- return this;
2268
- };
2269
-
2270
- /**
2271
- * Navigate to a given path.
2272
- * The path can be an object describing a named path in
2273
- * the format of { name: '...', params: {}, query: {}}
2274
- * The path is assumed to be already decoded, and will
2275
- * be resolved against root (if provided)
2276
- *
2277
- * @param {String|Object} path
2278
- * @param {Boolean} [replace]
2279
- */
2280
-
2281
- Router.prototype.go = function go(path) {
2282
- var replace = false;
2283
- var append = false;
2284
- if (Vue.util.isObject(path)) {
2285
- replace = path.replace;
2286
- append = path.append;
2287
- }
2288
- path = this.stringifyPath(path);
2289
- if (path) {
2290
- this.history.go(path, replace, append);
2291
- }
2292
- };
1719
+ AbstractHistory.prototype.ensureURL = function ensureURL () {
1720
+ // noop
1721
+ };
2293
1722
 
2294
- /**
2295
- * Short hand for replacing current path
2296
- *
2297
- * @param {String} path
2298
- */
1723
+ return AbstractHistory;
1724
+ }(History));
2299
1725
 
2300
- Router.prototype.replace = function replace(path) {
2301
- if (typeof path === 'string') {
2302
- path = { path: path };
2303
- }
2304
- path.replace = true;
2305
- this.go(path);
2306
- };
2307
-
2308
- /**
2309
- * Start the router.
2310
- *
2311
- * @param {VueConstructor} App
2312
- * @param {String|Element} container
2313
- * @param {Function} [cb]
2314
- */
2315
-
2316
- Router.prototype.start = function start(App, container, cb) {
2317
- /* istanbul ignore if */
2318
- if (this._started) {
2319
- warn$1('already started.');
2320
- return;
2321
- }
2322
- this._started = true;
2323
- this._startCb = cb;
2324
- if (!this.app) {
2325
- /* istanbul ignore if */
2326
- if (!App || !container) {
2327
- throw new Error('Must start vue-router with a component and a ' + 'root container.');
2328
- }
2329
- /* istanbul ignore if */
2330
- if (App instanceof Vue) {
2331
- throw new Error('Must start vue-router with a component, not a ' + 'Vue instance.');
2332
- }
2333
- this._appContainer = container;
2334
- var Ctor = this._appConstructor = typeof App === 'function' ? App : Vue.extend(App);
2335
- // give it a name for better debugging
2336
- Ctor.options.name = Ctor.options.name || 'RouterApp';
2337
- }
1726
+ /* */
2338
1727
 
2339
- // handle history fallback in browsers that do not
2340
- // support HTML5 history API
2341
- if (this._historyFallback) {
2342
- var _location = window.location;
2343
- var _history = new HTML5History({ root: this._root });
2344
- var path = _history.root ? _location.pathname.replace(_history.rootRE, '') : _location.pathname;
2345
- if (path && path !== '/') {
2346
- _location.assign((_history.root || '') + '/' + this.history.formatPath(path) + _location.search);
2347
- return;
2348
- }
2349
- }
1728
+ var VueRouter = function VueRouter (options) {
1729
+ if ( options === void 0 ) options = {};
2350
1730
 
2351
- this.history.start();
2352
- };
2353
-
2354
- /**
2355
- * Stop listening to route changes.
2356
- */
2357
-
2358
- Router.prototype.stop = function stop() {
2359
- this.history.stop();
2360
- this._started = false;
2361
- };
2362
-
2363
- /**
2364
- * Normalize named route object / string paths into
2365
- * a string.
2366
- *
2367
- * @param {Object|String|Number} path
2368
- * @return {String}
2369
- */
2370
-
2371
- Router.prototype.stringifyPath = function stringifyPath(path) {
2372
- var generatedPath = '';
2373
- if (path && typeof path === 'object') {
2374
- if (path.name) {
2375
- var extend = Vue.util.extend;
2376
- var currentParams = this._currentTransition && this._currentTransition.to.params;
2377
- var targetParams = path.params || {};
2378
- var params = currentParams ? extend(extend({}, currentParams), targetParams) : targetParams;
2379
- generatedPath = encodeURI(this._recognizer.generate(path.name, params));
2380
- } else if (path.path) {
2381
- generatedPath = encodeURI(path.path);
2382
- }
2383
- if (path.query) {
2384
- // note: the generated query string is pre-URL-encoded by the recognizer
2385
- var query = this._recognizer.generateQueryString(path.query);
2386
- if (generatedPath.indexOf('?') > -1) {
2387
- generatedPath += '&' + query.slice(1);
2388
- } else {
2389
- generatedPath += query;
2390
- }
2391
- }
2392
- } else {
2393
- generatedPath = encodeURI(path ? path + '' : '');
2394
- }
2395
- return generatedPath;
2396
- };
2397
-
2398
- // Internal methods ======================================
2399
-
2400
- /**
2401
- * Add a route containing a list of segments to the internal
2402
- * route recognizer. Will be called recursively to add all
2403
- * possible sub-routes.
2404
- *
2405
- * @param {String} path
2406
- * @param {Object} handler
2407
- * @param {Array} segments
2408
- */
2409
-
2410
- Router.prototype._addRoute = function _addRoute(path, handler, segments) {
2411
- guardComponent(path, handler);
2412
- handler.path = path;
2413
- handler.fullPath = (segments.reduce(function (path, segment) {
2414
- return path + segment.path;
2415
- }, '') + path).replace('//', '/');
2416
- segments.push({
2417
- path: path,
2418
- handler: handler
2419
- });
2420
- this._recognizer.add(segments, {
2421
- as: handler.name
2422
- });
2423
- // add sub routes
2424
- if (handler.subRoutes) {
2425
- for (var subPath in handler.subRoutes) {
2426
- // recursively walk all sub routes
2427
- this._addRoute(subPath, handler.subRoutes[subPath],
2428
- // pass a copy in recursion to avoid mutating
2429
- // across branches
2430
- segments.slice());
2431
- }
2432
- }
2433
- };
2434
-
2435
- /**
2436
- * Set the notFound route handler.
2437
- *
2438
- * @param {Object} handler
2439
- */
2440
-
2441
- Router.prototype._notFound = function _notFound(handler) {
2442
- guardComponent('*', handler);
2443
- this._notFoundHandler = [{ handler: handler }];
2444
- };
2445
-
2446
- /**
2447
- * Add a redirect record.
2448
- *
2449
- * @param {String} path
2450
- * @param {String} redirectPath
2451
- */
2452
-
2453
- Router.prototype._addRedirect = function _addRedirect(path, redirectPath) {
2454
- if (path === '*') {
2455
- this._notFoundRedirect = redirectPath;
2456
- } else {
2457
- this._addGuard(path, redirectPath, this.replace);
2458
- }
2459
- };
2460
-
2461
- /**
2462
- * Add an alias record.
2463
- *
2464
- * @param {String} path
2465
- * @param {String} aliasPath
2466
- */
2467
-
2468
- Router.prototype._addAlias = function _addAlias(path, aliasPath) {
2469
- this._addGuard(path, aliasPath, this._match);
2470
- };
2471
-
2472
- /**
2473
- * Add a path guard.
2474
- *
2475
- * @param {String} path
2476
- * @param {String} mappedPath
2477
- * @param {Function} handler
2478
- */
2479
-
2480
- Router.prototype._addGuard = function _addGuard(path, mappedPath, _handler) {
2481
- var _this2 = this;
2482
-
2483
- this._guardRecognizer.add([{
2484
- path: path,
2485
- handler: function handler(match, query) {
2486
- var realPath = mapParams(mappedPath, match.params, query);
2487
- _handler.call(_this2, realPath);
2488
- }
2489
- }]);
2490
- };
2491
-
2492
- /**
2493
- * Check if a path matches any redirect records.
2494
- *
2495
- * @param {String} path
2496
- * @return {Boolean} - if true, will skip normal match.
2497
- */
2498
-
2499
- Router.prototype._checkGuard = function _checkGuard(path) {
2500
- var matched = this._guardRecognizer.recognize(path, true);
2501
- if (matched) {
2502
- matched[0].handler(matched[0], matched.queryParams);
2503
- return true;
2504
- } else if (this._notFoundRedirect) {
2505
- matched = this._recognizer.recognize(path);
2506
- if (!matched) {
2507
- this.replace(this._notFoundRedirect);
2508
- return true;
2509
- }
2510
- }
2511
- };
2512
-
2513
- /**
2514
- * Match a URL path and set the route context on vm,
2515
- * triggering view updates.
2516
- *
2517
- * @param {String} path
2518
- * @param {Object} [state]
2519
- * @param {String} [anchor]
2520
- */
2521
-
2522
- Router.prototype._match = function _match(path, state, anchor) {
2523
- var _this3 = this;
2524
-
2525
- if (this._checkGuard(path)) {
2526
- return;
2527
- }
1731
+ this.app = null
1732
+ this.options = options
1733
+ this.beforeHooks = []
1734
+ this.afterHooks = []
1735
+ this.match = createMatcher(options.routes || [])
2528
1736
 
2529
- var currentRoute = this._currentRoute;
2530
- var currentTransition = this._currentTransition;
2531
-
2532
- if (currentTransition) {
2533
- if (currentTransition.to.path === path) {
2534
- // do nothing if we have an active transition going to the same path
2535
- return;
2536
- } else if (currentRoute.path === path) {
2537
- // We are going to the same path, but we also have an ongoing but
2538
- // not-yet-validated transition. Abort that transition and reset to
2539
- // prev transition.
2540
- currentTransition.aborted = true;
2541
- this._currentTransition = this._prevTransition;
2542
- return;
2543
- } else {
2544
- // going to a totally different path. abort ongoing transition.
2545
- currentTransition.aborted = true;
2546
- }
2547
- }
1737
+ var mode = options.mode || 'hash'
1738
+ this.fallback = mode === 'history' && !supportsHistory
1739
+ if (this.fallback) {
1740
+ mode = 'hash'
1741
+ }
1742
+ if (!inBrowser) {
1743
+ mode = 'abstract'
1744
+ }
1745
+ this.mode = mode
1746
+ };
1747
+
1748
+ var prototypeAccessors = { currentRoute: {} };
1749
+
1750
+ prototypeAccessors.currentRoute.get = function () {
1751
+ return this.history && this.history.current
1752
+ };
1753
+
1754
+ VueRouter.prototype.init = function init (app /* Vue component instance */) {
1755
+ var this$1 = this;
1756
+
1757
+ assert(
1758
+ install.installed,
1759
+ "not installed. Make sure to call `Vue.use(VueRouter)` " +
1760
+ "before creating root instance."
1761
+ )
1762
+
1763
+ this.app = app
1764
+
1765
+ var ref = this;
1766
+ var mode = ref.mode;
1767
+ var options = ref.options;
1768
+ var fallback = ref.fallback;
1769
+ switch (mode) {
1770
+ case 'history':
1771
+ this.history = new HTML5History(this, options.base)
1772
+ break
1773
+ case 'hash':
1774
+ this.history = new HashHistory(this, options.base, fallback)
1775
+ break
1776
+ case 'abstract':
1777
+ this.history = new AbstractHistory(this)
1778
+ break
1779
+ default:
1780
+ assert(false, ("invalid mode: " + mode))
1781
+ }
2548
1782
 
2549
- // construct new route and transition context
2550
- var route = new Route(path, this);
2551
- var transition = new RouteTransition(this, route, currentRoute);
2552
-
2553
- // current transition is updated right now.
2554
- // however, current route will only be updated after the transition has
2555
- // been validated.
2556
- this._prevTransition = currentTransition;
2557
- this._currentTransition = transition;
2558
-
2559
- if (!this.app) {
2560
- (function () {
2561
- // initial render
2562
- var router = _this3;
2563
- _this3.app = new _this3._appConstructor({
2564
- el: _this3._appContainer,
2565
- created: function created() {
2566
- this.$router = router;
2567
- },
2568
- _meta: {
2569
- $route: route
2570
- }
2571
- });
2572
- })();
2573
- }
1783
+ this.history.listen(function (route) {
1784
+ this$1.app._route = route
1785
+ })
1786
+ };
2574
1787
 
2575
- // check global before hook
2576
- var beforeHooks = this._beforeEachHooks;
2577
- var startTransition = function startTransition() {
2578
- transition.start(function () {
2579
- _this3._postTransition(route, state, anchor);
2580
- });
2581
- };
2582
-
2583
- if (beforeHooks.length) {
2584
- transition.runQueue(beforeHooks, function (hook, _, next) {
2585
- if (transition === _this3._currentTransition) {
2586
- transition.callHook(hook, null, next, {
2587
- expectBoolean: true
2588
- });
2589
- }
2590
- }, startTransition);
2591
- } else {
2592
- startTransition();
2593
- }
1788
+ VueRouter.prototype.beforeEach = function beforeEach (fn) {
1789
+ this.beforeHooks.push(fn)
1790
+ };
2594
1791
 
2595
- if (!this._rendered && this._startCb) {
2596
- this._startCb.call(null);
2597
- }
1792
+ VueRouter.prototype.afterEach = function afterEach (fn) {
1793
+ this.afterHooks.push(fn)
1794
+ };
2598
1795
 
2599
- // HACK:
2600
- // set rendered to true after the transition start, so
2601
- // that components that are acitvated synchronously know
2602
- // whether it is the initial render.
2603
- this._rendered = true;
2604
- };
2605
-
2606
- /**
2607
- * Set current to the new transition.
2608
- * This is called by the transition object when the
2609
- * validation of a route has succeeded.
2610
- *
2611
- * @param {Transition} transition
2612
- */
2613
-
2614
- Router.prototype._onTransitionValidated = function _onTransitionValidated(transition) {
2615
- // set current route
2616
- var route = this._currentRoute = transition.to;
2617
- // update route context for all children
2618
- if (this.app.$route !== route) {
2619
- this.app.$route = route;
2620
- this._children.forEach(function (child) {
2621
- child.$route = route;
2622
- });
2623
- }
2624
- // call global after hook
2625
- if (this._afterEachHooks.length) {
2626
- this._afterEachHooks.forEach(function (hook) {
2627
- return hook.call(null, {
2628
- to: transition.to,
2629
- from: transition.from
2630
- });
2631
- });
2632
- }
2633
- this._currentTransition.done = true;
2634
- };
2635
-
2636
- /**
2637
- * Handle stuff after the transition.
2638
- *
2639
- * @param {Route} route
2640
- * @param {Object} [state]
2641
- * @param {String} [anchor]
2642
- */
2643
-
2644
- Router.prototype._postTransition = function _postTransition(route, state, anchor) {
2645
- // handle scroll positions
2646
- // saved scroll positions take priority
2647
- // then we check if the path has an anchor
2648
- var pos = state && state.pos;
2649
- if (pos && this._saveScrollPosition) {
2650
- Vue.nextTick(function () {
2651
- window.scrollTo(pos.x, pos.y);
2652
- });
2653
- } else if (anchor) {
2654
- Vue.nextTick(function () {
2655
- var el = document.getElementById(anchor.slice(1));
2656
- if (el) {
2657
- window.scrollTo(window.scrollX, el.offsetTop);
2658
- }
2659
- });
2660
- }
2661
- };
1796
+ VueRouter.prototype.push = function push (location) {
1797
+ this.history.push(location)
1798
+ };
2662
1799
 
2663
- return Router;
2664
- })();
1800
+ VueRouter.prototype.replace = function replace (location) {
1801
+ this.history.replace(location)
1802
+ };
2665
1803
 
2666
- function guardComponent(path, handler) {
2667
- var comp = handler.component;
2668
- if (Vue.util.isPlainObject(comp)) {
2669
- comp = handler.component = Vue.extend(comp);
2670
- }
2671
- /* istanbul ignore if */
2672
- if (typeof comp !== 'function') {
2673
- handler.component = null;
2674
- warn$1('invalid component for route "' + path + '".');
2675
- }
2676
- }
1804
+ VueRouter.prototype.go = function go (n) {
1805
+ this.history.go(n)
1806
+ };
2677
1807
 
2678
- /* Installation */
1808
+ VueRouter.prototype.back = function back () {
1809
+ this.go(-1)
1810
+ };
2679
1811
 
2680
- Router.installed = false;
1812
+ VueRouter.prototype.forward = function forward () {
1813
+ this.go(1)
1814
+ };
2681
1815
 
2682
- /**
2683
- * Installation interface.
2684
- * Install the necessary directives.
2685
- */
1816
+ VueRouter.prototype.getMatchedComponents = function getMatchedComponents () {
1817
+ if (!this.currentRoute) {
1818
+ return []
1819
+ }
1820
+ return [].concat.apply([], this.currentRoute.matched.map(function (m) {
1821
+ return Object.keys(m.components).map(function (key) {
1822
+ return m.components[key]
1823
+ })
1824
+ }))
1825
+ };
2686
1826
 
2687
- Router.install = function (externalVue) {
2688
- /* istanbul ignore if */
2689
- if (Router.installed) {
2690
- warn$1('already installed.');
2691
- return;
2692
- }
2693
- Vue = externalVue;
2694
- applyOverride(Vue);
2695
- View(Vue);
2696
- Link(Vue);
2697
- exports$1.Vue = Vue;
2698
- Router.installed = true;
2699
- };
1827
+ Object.defineProperties( VueRouter.prototype, prototypeAccessors );
2700
1828
 
2701
- // auto install
2702
- /* istanbul ignore if */
2703
- if (typeof window !== 'undefined' && window.Vue) {
2704
- window.Vue.use(Router);
2705
- }
1829
+ VueRouter.install = install
1830
+
1831
+ if (inBrowser && window.Vue) {
1832
+ window.Vue.use(VueRouter)
1833
+ }
2706
1834
 
2707
- return Router;
1835
+ return VueRouter;
2708
1836
 
2709
- }));
1837
+ })));