vue-rails 2.0.1 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,14 +1,28 @@
1
1
  /**
2
- * vue-router v2.0.0
3
- * (c) 2016 Evan You
4
- * @license MIT
5
- */
2
+ * vue-router v2.2.1
3
+ * (c) 2017 Evan You
4
+ * @license MIT
5
+ */
6
6
  (function (global, factory) {
7
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
8
- typeof define === 'function' && define.amd ? define(factory) :
9
- (global.VueRouter = factory());
7
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
8
+ typeof define === 'function' && define.amd ? define(factory) :
9
+ (global.VueRouter = factory());
10
10
  }(this, (function () { 'use strict';
11
11
 
12
+ /* */
13
+
14
+ function assert (condition, message) {
15
+ if (!condition) {
16
+ throw new Error(("[vue-router] " + message))
17
+ }
18
+ }
19
+
20
+ function warn (condition, message) {
21
+ if (!condition) {
22
+ typeof console !== 'undefined' && console.warn(("[vue-router] " + message));
23
+ }
24
+ }
25
+
12
26
  var View = {
13
27
  name: 'router-view',
14
28
  functional: true,
@@ -24,133 +38,91 @@ var View = {
24
38
  var parent = ref.parent;
25
39
  var data = ref.data;
26
40
 
27
- data.routerView = true
41
+ data.routerView = true;
28
42
 
29
- var route = parent.$route
30
- var cache = parent._routerViewCache || (parent._routerViewCache = {})
31
- var depth = 0
32
- var inactive = false
43
+ var name = props.name;
44
+ var route = parent.$route;
45
+ var cache = parent._routerViewCache || (parent._routerViewCache = {});
33
46
 
47
+ // determine current view depth, also check to see if the tree
48
+ // has been toggled inactive but kept-alive.
49
+ var depth = 0;
50
+ var inactive = false;
34
51
  while (parent) {
35
52
  if (parent.$vnode && parent.$vnode.data.routerView) {
36
- depth++
53
+ depth++;
37
54
  }
38
55
  if (parent._inactive) {
39
- inactive = true
56
+ inactive = true;
40
57
  }
41
- parent = parent.$parent
58
+ parent = parent.$parent;
59
+ }
60
+ data.routerViewDepth = depth;
61
+
62
+ // render previous view if the tree is inactive and kept-alive
63
+ if (inactive) {
64
+ return h(cache[name], data, children)
42
65
  }
43
66
 
44
- data.routerViewDepth = depth
45
- var matched = route.matched[depth]
67
+ var matched = route.matched[depth];
68
+ // render empty node if no matched route
46
69
  if (!matched) {
70
+ cache[name] = null;
47
71
  return h()
48
72
  }
49
73
 
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
74
+ var component = cache[name] = matched.components[name];
75
+
76
+ // inject instance registration hooks
77
+ var hooks = data.hook || (data.hook = {});
78
+ hooks.init = function (vnode) {
79
+ matched.instances[name] = vnode.child;
80
+ };
81
+ hooks.prepatch = function (oldVnode, vnode) {
82
+ matched.instances[name] = vnode.child;
83
+ };
84
+ hooks.destroy = function (vnode) {
85
+ if (matched.instances[name] === vnode.child) {
86
+ matched.instances[name] = undefined;
57
87
  }
58
- }
59
-
60
- return h(component, data, children)
61
- }
62
- }
63
-
64
- /* */
65
-
66
- function resolvePath (
67
- relative,
68
- base,
69
- append
70
- ) {
71
- if (relative.charAt(0) === '/') {
72
- return relative
73
- }
74
-
75
- if (relative.charAt(0) === '?' || relative.charAt(0) === '#') {
76
- return base + relative
77
- }
78
-
79
- var stack = base.split('/')
80
-
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()
86
- }
87
-
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)
98
- }
99
- }
100
-
101
- // ensure leading slash
102
- if (stack[0] !== '') {
103
- stack.unshift('')
104
- }
105
-
106
- return stack.join('/')
107
- }
88
+ };
108
89
 
109
- function parsePath (path) {
110
- var hash = ''
111
- var query = ''
112
-
113
- var hashIndex = path.indexOf('#')
114
- if (hashIndex >= 0) {
115
- hash = path.slice(hashIndex)
116
- path = path.slice(0, hashIndex)
117
- }
90
+ // resolve props
91
+ data.props = resolveProps(route, matched.props && matched.props[name]);
118
92
 
119
- var queryIndex = path.indexOf('?')
120
- if (queryIndex >= 0) {
121
- query = path.slice(queryIndex + 1)
122
- path = path.slice(0, queryIndex)
93
+ return h(component, data, children)
123
94
  }
95
+ };
124
96
 
125
- return {
126
- path: path,
127
- query: query,
128
- hash: hash
97
+ function resolveProps (route, config) {
98
+ switch (typeof config) {
99
+ case 'undefined':
100
+ return
101
+ case 'object':
102
+ return config
103
+ case 'function':
104
+ return config(route)
105
+ case 'boolean':
106
+ return config ? route.params : undefined
107
+ default:
108
+ warn(false, ("props in \"" + (route.path) + "\" is a " + (typeof config) + ", expecting an object, function or boolean."));
129
109
  }
130
110
  }
131
111
 
132
- function cleanPath (path) {
133
- return path.replace(/\/\//g, '/')
134
- }
135
-
136
112
  /* */
137
113
 
138
- function assert (condition, message) {
139
- if (!condition) {
140
- throw new Error(("[vue-router] " + message))
141
- }
142
- }
143
-
144
- function warn (condition, message) {
145
- if (!condition) {
146
- typeof console !== 'undefined' && console.warn(("[vue-router] " + message))
147
- }
148
- }
114
+ var encodeReserveRE = /[!'()*]/g;
115
+ var encodeReserveReplacer = function (c) { return '%' + c.charCodeAt(0).toString(16); };
116
+ var commaRE = /%2C/g;
149
117
 
150
- /* */
118
+ // fixed encodeURIComponent which is more comformant to RFC3986:
119
+ // - escapes [!'()*]
120
+ // - preserve commas
121
+ var encode = function (str) { return encodeURIComponent(str)
122
+ .replace(encodeReserveRE, encodeReserveReplacer)
123
+ .replace(commaRE, ','); };
151
124
 
152
- var encode = encodeURIComponent
153
- var decode = decodeURIComponent
125
+ var decode = decodeURIComponent;
154
126
 
155
127
  function resolveQuery (
156
128
  query,
@@ -159,15 +131,15 @@ function resolveQuery (
159
131
  if ( extraQuery === void 0 ) extraQuery = {};
160
132
 
161
133
  if (query) {
162
- var parsedQuery
134
+ var parsedQuery;
163
135
  try {
164
- parsedQuery = parseQuery(query)
136
+ parsedQuery = parseQuery(query);
165
137
  } catch (e) {
166
- warn(false, e.message)
167
- parsedQuery = {}
138
+ "development" !== 'production' && warn(false, e.message);
139
+ parsedQuery = {};
168
140
  }
169
141
  for (var key in extraQuery) {
170
- parsedQuery[key] = extraQuery[key]
142
+ parsedQuery[key] = extraQuery[key];
171
143
  }
172
144
  return parsedQuery
173
145
  } else {
@@ -176,36 +148,36 @@ function resolveQuery (
176
148
  }
177
149
 
178
150
  function parseQuery (query) {
179
- var res = Object.create(null)
151
+ var res = {};
180
152
 
181
- query = query.trim().replace(/^(\?|#|&)/, '')
153
+ query = query.trim().replace(/^(\?|#|&)/, '');
182
154
 
183
155
  if (!query) {
184
156
  return res
185
157
  }
186
158
 
187
159
  query.split('&').forEach(function (param) {
188
- var parts = param.replace(/\+/g, ' ').split('=')
189
- var key = decode(parts.shift())
160
+ var parts = param.replace(/\+/g, ' ').split('=');
161
+ var key = decode(parts.shift());
190
162
  var val = parts.length > 0
191
163
  ? decode(parts.join('='))
192
- : null
164
+ : null;
193
165
 
194
166
  if (res[key] === undefined) {
195
- res[key] = val
167
+ res[key] = val;
196
168
  } else if (Array.isArray(res[key])) {
197
- res[key].push(val)
169
+ res[key].push(val);
198
170
  } else {
199
- res[key] = [res[key], val]
171
+ res[key] = [res[key], val];
200
172
  }
201
- })
173
+ });
202
174
 
203
175
  return res
204
176
  }
205
177
 
206
178
  function stringifyQuery (obj) {
207
- var res = obj ? Object.keys(obj).sort().map(function (key) {
208
- var val = obj[key]
179
+ var res = obj ? Object.keys(obj).map(function (key) {
180
+ var val = obj[key];
209
181
 
210
182
  if (val === undefined) {
211
183
  return ''
@@ -216,27 +188,29 @@ function stringifyQuery (obj) {
216
188
  }
217
189
 
218
190
  if (Array.isArray(val)) {
219
- var result = []
191
+ var result = [];
220
192
  val.slice().forEach(function (val2) {
221
193
  if (val2 === undefined) {
222
194
  return
223
195
  }
224
196
  if (val2 === null) {
225
- result.push(encode(key))
197
+ result.push(encode(key));
226
198
  } else {
227
- result.push(encode(key) + '=' + encode(val2))
199
+ result.push(encode(key) + '=' + encode(val2));
228
200
  }
229
- })
201
+ });
230
202
  return result.join('&')
231
203
  }
232
204
 
233
205
  return encode(key) + '=' + encode(val)
234
- }).filter(function (x) { return x.length > 0; }).join('&') : null
206
+ }).filter(function (x) { return x.length > 0; }).join('&') : null;
235
207
  return res ? ("?" + res) : ''
236
208
  }
237
209
 
238
210
  /* */
239
211
 
212
+ var trailingSlashRE = /\/?$/;
213
+
240
214
  function createRoute (
241
215
  record,
242
216
  location,
@@ -251,9 +225,9 @@ function createRoute (
251
225
  params: location.params || {},
252
226
  fullPath: getFullPath(location),
253
227
  matched: record ? formatMatch(record) : []
254
- }
228
+ };
255
229
  if (redirectedFrom) {
256
- route.redirectedFrom = getFullPath(redirectedFrom)
230
+ route.redirectedFrom = getFullPath(redirectedFrom);
257
231
  }
258
232
  return Object.freeze(route)
259
233
  }
@@ -261,13 +235,13 @@ function createRoute (
261
235
  // the starting route that represents the initial state
262
236
  var START = createRoute(null, {
263
237
  path: '/'
264
- })
238
+ });
265
239
 
266
240
  function formatMatch (record) {
267
- var res = []
241
+ var res = [];
268
242
  while (record) {
269
- res.unshift(record)
270
- record = record.parent
243
+ res.unshift(record);
244
+ record = record.parent;
271
245
  }
272
246
  return res
273
247
  }
@@ -280,7 +254,6 @@ function getFullPath (ref) {
280
254
  return (path || '/') + stringifyQuery(query) + hash
281
255
  }
282
256
 
283
- var trailingSlashRE = /\/$/
284
257
  function isSameRoute (a, b) {
285
258
  if (b === START) {
286
259
  return a === b
@@ -308,8 +281,8 @@ function isObjectEqual (a, b) {
308
281
  if ( a === void 0 ) a = {};
309
282
  if ( b === void 0 ) b = {};
310
283
 
311
- var aKeys = Object.keys(a)
312
- var bKeys = Object.keys(b)
284
+ var aKeys = Object.keys(a);
285
+ var bKeys = Object.keys(b);
313
286
  if (aKeys.length !== bKeys.length) {
314
287
  return false
315
288
  }
@@ -318,7 +291,9 @@ function isObjectEqual (a, b) {
318
291
 
319
292
  function isIncludedRoute (current, target) {
320
293
  return (
321
- current.path.indexOf(target.path) === 0 &&
294
+ current.path.replace(trailingSlashRE, '/').indexOf(
295
+ target.path.replace(trailingSlashRE, '/')
296
+ ) === 0 &&
322
297
  (!target.hash || current.hash === target.hash) &&
323
298
  queryIncludes(current.query, target.query)
324
299
  )
@@ -335,39 +310,9 @@ function queryIncludes (current, target) {
335
310
 
336
311
  /* */
337
312
 
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
346
- }
347
-
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
357
- }
358
-
359
- return {
360
- _normalized: true,
361
- path: path,
362
- query: query,
363
- hash: hash
364
- }
365
- }
366
-
367
- /* */
368
-
369
313
  // work around weird flow bug
370
- var toTypes = [String, Object]
314
+ var toTypes = [String, Object];
315
+ var eventTypes = [String, Array];
371
316
 
372
317
  var Link = {
373
318
  name: 'router-link',
@@ -383,63 +328,97 @@ var Link = {
383
328
  exact: Boolean,
384
329
  append: Boolean,
385
330
  replace: Boolean,
386
- activeClass: String
331
+ activeClass: String,
332
+ event: {
333
+ type: eventTypes,
334
+ default: 'click'
335
+ }
387
336
  },
388
337
  render: function render (h) {
389
338
  var this$1 = this;
390
339
 
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
340
+ var router = this.$router;
341
+ var current = this.$route;
342
+ var ref = router.resolve(this.to, current, this.append);
343
+ var location = ref.location;
344
+ var route = ref.route;
345
+ var href = ref.href;
346
+ var classes = {};
347
+ var activeClass = this.activeClass || router.options.linkActiveClass || 'router-link-active';
348
+ var compareTarget = location.path ? createRoute(null, location) : route;
401
349
  classes[activeClass] = this.exact
402
350
  ? isSameRoute(current, compareTarget)
403
- : isIncludedRoute(current, compareTarget)
351
+ : isIncludedRoute(current, compareTarget);
404
352
 
405
- var on = {
406
- click: function (e) {
407
- e.preventDefault()
353
+ var handler = function (e) {
354
+ if (guardEvent(e)) {
408
355
  if (this$1.replace) {
409
- router.replace(to)
356
+ router.replace(location);
410
357
  } else {
411
- router.push(to)
358
+ router.push(location);
412
359
  }
413
360
  }
361
+ };
362
+
363
+ var on = { click: guardEvent };
364
+ if (Array.isArray(this.event)) {
365
+ this.event.forEach(function (e) { on[e] = handler; });
366
+ } else {
367
+ on[this.event] = handler;
414
368
  }
415
369
 
416
370
  var data = {
417
371
  class: classes
418
- }
372
+ };
419
373
 
420
374
  if (this.tag === 'a') {
421
- data.on = on
422
- data.attrs = { href: href }
375
+ data.on = on;
376
+ data.attrs = { href: href };
423
377
  } else {
424
378
  // find the first <a> child and apply listener and href
425
- var a = findAnchor(this.$slots.default)
379
+ var a = findAnchor(this.$slots.default);
426
380
  if (a) {
427
- var aData = a.data || (a.data = {})
428
- aData.on = on
429
- var aAttrs = aData.attrs || (aData.attrs = {})
430
- aAttrs.href = href
381
+ // in case the <a> is a static node
382
+ a.isStatic = false;
383
+ var extend = _Vue.util.extend;
384
+ var aData = a.data = extend({}, a.data);
385
+ aData.on = on;
386
+ var aAttrs = a.data.attrs = extend({}, a.data.attrs);
387
+ aAttrs.href = href;
388
+ } else {
389
+ // doesn't have <a> child, apply listener to self
390
+ data.on = on;
431
391
  }
432
392
  }
433
393
 
434
394
  return h(this.tag, data, this.$slots.default)
435
395
  }
396
+ };
397
+
398
+ function guardEvent (e) {
399
+ // don't redirect with control keys
400
+ if (e.metaKey || e.ctrlKey || e.shiftKey) { return }
401
+ // don't redirect when preventDefault called
402
+ if (e.defaultPrevented) { return }
403
+ // don't redirect on right click
404
+ if (e.button !== undefined && e.button !== 0) { return }
405
+ // don't redirect if `target="_blank"`
406
+ if (e.target && e.target.getAttribute) {
407
+ var target = e.target.getAttribute('target');
408
+ if (/\b_blank\b/i.test(target)) { return }
409
+ }
410
+ // this may be a Weex event which doesn't have this method
411
+ if (e.preventDefault) {
412
+ e.preventDefault();
413
+ }
414
+ return true
436
415
  }
437
416
 
438
417
  function findAnchor (children) {
439
418
  if (children) {
440
- var child
419
+ var child;
441
420
  for (var i = 0; i < children.length; i++) {
442
- child = children[i]
421
+ child = children[i];
443
422
  if (child.tag === 'a') {
444
423
  return child
445
424
  }
@@ -450,46 +429,251 @@ function findAnchor (children) {
450
429
  }
451
430
  }
452
431
 
432
+ var _Vue;
433
+
453
434
  function install (Vue) {
454
435
  if (install.installed) { return }
455
- install.installed = true
436
+ install.installed = true;
437
+
438
+ _Vue = Vue;
456
439
 
457
440
  Object.defineProperty(Vue.prototype, '$router', {
458
441
  get: function get () { return this.$root._router }
459
- })
442
+ });
460
443
 
461
444
  Object.defineProperty(Vue.prototype, '$route', {
462
- get: function get$1 () { return this.$root._route }
463
- })
445
+ get: function get () { return this.$root._route }
446
+ });
464
447
 
465
448
  Vue.mixin({
466
449
  beforeCreate: function beforeCreate () {
467
450
  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)
451
+ this._router = this.$options.router;
452
+ this._router.init(this);
453
+ Vue.util.defineReactive(this, '_route', this._router.history.current);
471
454
  }
472
455
  }
473
- })
456
+ });
457
+
458
+ Vue.component('router-view', View);
459
+ Vue.component('router-link', Link);
460
+
461
+ var strats = Vue.config.optionMergeStrategies;
462
+ // use the same hook merging strategy for route hooks
463
+ strats.beforeRouteEnter = strats.beforeRouteLeave = strats.created;
464
+ }
465
+
466
+ /* */
467
+
468
+ var inBrowser = typeof window !== 'undefined';
469
+
470
+ /* */
471
+
472
+ function resolvePath (
473
+ relative,
474
+ base,
475
+ append
476
+ ) {
477
+ if (relative.charAt(0) === '/') {
478
+ return relative
479
+ }
480
+
481
+ if (relative.charAt(0) === '?' || relative.charAt(0) === '#') {
482
+ return base + relative
483
+ }
484
+
485
+ var stack = base.split('/');
486
+
487
+ // remove trailing segment if:
488
+ // - not appending
489
+ // - appending to trailing slash (last segment is empty)
490
+ if (!append || !stack[stack.length - 1]) {
491
+ stack.pop();
492
+ }
493
+
494
+ // resolve relative path
495
+ var segments = relative.replace(/^\//, '').split('/');
496
+ for (var i = 0; i < segments.length; i++) {
497
+ var segment = segments[i];
498
+ if (segment === '.') {
499
+ continue
500
+ } else if (segment === '..') {
501
+ stack.pop();
502
+ } else {
503
+ stack.push(segment);
504
+ }
505
+ }
506
+
507
+ // ensure leading slash
508
+ if (stack[0] !== '') {
509
+ stack.unshift('');
510
+ }
511
+
512
+ return stack.join('/')
513
+ }
514
+
515
+ function parsePath (path) {
516
+ var hash = '';
517
+ var query = '';
518
+
519
+ var hashIndex = path.indexOf('#');
520
+ if (hashIndex >= 0) {
521
+ hash = path.slice(hashIndex);
522
+ path = path.slice(0, hashIndex);
523
+ }
524
+
525
+ var queryIndex = path.indexOf('?');
526
+ if (queryIndex >= 0) {
527
+ query = path.slice(queryIndex + 1);
528
+ path = path.slice(0, queryIndex);
529
+ }
530
+
531
+ return {
532
+ path: path,
533
+ query: query,
534
+ hash: hash
535
+ }
536
+ }
537
+
538
+ function cleanPath (path) {
539
+ return path.replace(/\/\//g, '/')
540
+ }
474
541
 
475
- Vue.component('router-view', View)
476
- Vue.component('router-link', Link)
542
+ /* */
543
+
544
+ function createRouteMap (
545
+ routes,
546
+ oldPathMap,
547
+ oldNameMap
548
+ ) {
549
+ var pathMap = oldPathMap || Object.create(null);
550
+ var nameMap = oldNameMap || Object.create(null);
551
+
552
+ routes.forEach(function (route) {
553
+ addRouteRecord(pathMap, nameMap, route);
554
+ });
555
+
556
+ return {
557
+ pathMap: pathMap,
558
+ nameMap: nameMap
559
+ }
560
+ }
561
+
562
+ function addRouteRecord (
563
+ pathMap,
564
+ nameMap,
565
+ route,
566
+ parent,
567
+ matchAs
568
+ ) {
569
+ var path = route.path;
570
+ var name = route.name;
571
+ {
572
+ assert(path != null, "\"path\" is required in a route configuration.");
573
+ assert(
574
+ typeof route.component !== 'string',
575
+ "route config \"component\" for path: " + (String(path || name)) + " cannot be a " +
576
+ "string id. Use an actual component instead."
577
+ );
578
+ }
579
+
580
+ var record = {
581
+ path: normalizePath(path, parent),
582
+ components: route.components || { default: route.component },
583
+ instances: {},
584
+ name: name,
585
+ parent: parent,
586
+ matchAs: matchAs,
587
+ redirect: route.redirect,
588
+ beforeEnter: route.beforeEnter,
589
+ meta: route.meta || {},
590
+ props: route.props == null
591
+ ? {}
592
+ : route.components
593
+ ? route.props
594
+ : { default: route.props }
595
+ };
596
+
597
+ if (route.children) {
598
+ // Warn if route is named and has a default child route.
599
+ // If users navigate to this route by name, the default child will
600
+ // not be rendered (GH Issue #629)
601
+ {
602
+ if (route.name && route.children.some(function (child) { return /^\/?$/.test(child.path); })) {
603
+ warn(
604
+ false,
605
+ "Named Route '" + (route.name) + "' has a default child route. " +
606
+ "When navigating to this named route (:to=\"{name: '" + (route.name) + "'\"), " +
607
+ "the default child route will not be rendered. Remove the name from " +
608
+ "this route and use the name of the default child route for named " +
609
+ "links instead."
610
+ );
611
+ }
612
+ }
613
+ route.children.forEach(function (child) {
614
+ var childMatchAs = matchAs
615
+ ? cleanPath((matchAs + "/" + (child.path)))
616
+ : undefined;
617
+ addRouteRecord(pathMap, nameMap, child, record, childMatchAs);
618
+ });
619
+ }
620
+
621
+ if (route.alias !== undefined) {
622
+ if (Array.isArray(route.alias)) {
623
+ route.alias.forEach(function (alias) {
624
+ var aliasRoute = {
625
+ path: alias,
626
+ children: route.children
627
+ };
628
+ addRouteRecord(pathMap, nameMap, aliasRoute, parent, record.path);
629
+ });
630
+ } else {
631
+ var aliasRoute = {
632
+ path: route.alias,
633
+ children: route.children
634
+ };
635
+ addRouteRecord(pathMap, nameMap, aliasRoute, parent, record.path);
636
+ }
637
+ }
638
+
639
+ if (!pathMap[record.path]) {
640
+ pathMap[record.path] = record;
641
+ }
642
+
643
+ if (name) {
644
+ if (!nameMap[name]) {
645
+ nameMap[name] = record;
646
+ } else if ("development" !== 'production' && !matchAs) {
647
+ warn(
648
+ false,
649
+ "Duplicate named routes definition: " +
650
+ "{ name: \"" + name + "\", path: \"" + (record.path) + "\" }"
651
+ );
652
+ }
653
+ }
654
+ }
655
+
656
+ function normalizePath (path, parent) {
657
+ path = path.replace(/\/$/, '');
658
+ if (path[0] === '/') { return path }
659
+ if (parent == null) { return path }
660
+ return cleanPath(((parent.path) + "/" + path))
477
661
  }
478
662
 
479
- var __moduleExports = Array.isArray || function (arr) {
663
+ var index$1 = Array.isArray || function (arr) {
480
664
  return Object.prototype.toString.call(arr) == '[object Array]';
481
665
  };
482
666
 
483
- var isarray = __moduleExports
667
+ var isarray = index$1;
484
668
 
485
669
  /**
486
670
  * Expose `pathToRegexp`.
487
671
  */
488
- var index = pathToRegexp
489
- var parse_1 = parse
490
- var compile_1 = compile
491
- var tokensToFunction_1 = tokensToFunction
492
- var tokensToRegExp_1 = tokensToRegExp
672
+ var index = pathToRegexp;
673
+ var parse_1 = parse;
674
+ var compile_1 = compile;
675
+ var tokensToFunction_1 = tokensToFunction;
676
+ var tokensToRegExp_1 = tokensToRegExp;
493
677
 
494
678
  /**
495
679
  * The main path matching regexp utility.
@@ -507,53 +691,55 @@ var PATH_REGEXP = new RegExp([
507
691
  // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
508
692
  // "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
509
693
  '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
510
- ].join('|'), 'g')
694
+ ].join('|'), 'g');
511
695
 
512
696
  /**
513
697
  * Parse a string for the raw tokens.
514
698
  *
515
- * @param {string} str
699
+ * @param {string} str
700
+ * @param {Object=} options
516
701
  * @return {!Array}
517
702
  */
518
- function parse (str) {
519
- var tokens = []
520
- var key = 0
521
- var index = 0
522
- var path = ''
523
- var res
703
+ function parse (str, options) {
704
+ var tokens = [];
705
+ var key = 0;
706
+ var index = 0;
707
+ var path = '';
708
+ var defaultDelimiter = options && options.delimiter || '/';
709
+ var res;
524
710
 
525
711
  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
712
+ var m = res[0];
713
+ var escaped = res[1];
714
+ var offset = res.index;
715
+ path += str.slice(index, offset);
716
+ index = offset + m.length;
531
717
 
532
718
  // Ignore already escaped sequences.
533
719
  if (escaped) {
534
- path += escaped[1]
720
+ path += escaped[1];
535
721
  continue
536
722
  }
537
723
 
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]
724
+ var next = str[index];
725
+ var prefix = res[2];
726
+ var name = res[3];
727
+ var capture = res[4];
728
+ var group = res[5];
729
+ var modifier = res[6];
730
+ var asterisk = res[7];
545
731
 
546
732
  // Push the current path onto the tokens.
547
733
  if (path) {
548
- tokens.push(path)
549
- path = ''
734
+ tokens.push(path);
735
+ path = '';
550
736
  }
551
737
 
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 + ']+?')
738
+ var partial = prefix != null && next != null && next !== prefix;
739
+ var repeat = modifier === '+' || modifier === '*';
740
+ var optional = modifier === '?' || modifier === '*';
741
+ var delimiter = res[2] || defaultDelimiter;
742
+ var pattern = capture || group;
557
743
 
558
744
  tokens.push({
559
745
  name: name || key++,
@@ -563,18 +749,18 @@ function parse (str) {
563
749
  repeat: repeat,
564
750
  partial: partial,
565
751
  asterisk: !!asterisk,
566
- pattern: escapeGroup(pattern)
567
- })
752
+ pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
753
+ });
568
754
  }
569
755
 
570
756
  // Match any characters still remaining.
571
757
  if (index < str.length) {
572
- path += str.substr(index)
758
+ path += str.substr(index);
573
759
  }
574
760
 
575
761
  // If the path exists, push it onto the end.
576
762
  if (path) {
577
- tokens.push(path)
763
+ tokens.push(path);
578
764
  }
579
765
 
580
766
  return tokens
@@ -584,10 +770,11 @@ function parse (str) {
584
770
  * Compile a string to a template function for the path.
585
771
  *
586
772
  * @param {string} str
773
+ * @param {Object=} options
587
774
  * @return {!function(Object=, Object=)}
588
775
  */
589
- function compile (str) {
590
- return tokensToFunction(parse(str))
776
+ function compile (str, options) {
777
+ return tokensToFunction(parse(str, options))
591
778
  }
592
779
 
593
780
  /**
@@ -619,38 +806,38 @@ function encodeAsterisk (str) {
619
806
  */
620
807
  function tokensToFunction (tokens) {
621
808
  // Compile all the tokens into regexps.
622
- var matches = new Array(tokens.length)
809
+ var matches = new Array(tokens.length);
623
810
 
624
811
  // Compile all the patterns before compilation.
625
812
  for (var i = 0; i < tokens.length; i++) {
626
813
  if (typeof tokens[i] === 'object') {
627
- matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$')
814
+ matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$');
628
815
  }
629
816
  }
630
817
 
631
818
  return function (obj, opts) {
632
- var path = ''
633
- var data = obj || {}
634
- var options = opts || {}
635
- var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent
819
+ var path = '';
820
+ var data = obj || {};
821
+ var options = opts || {};
822
+ var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent;
636
823
 
637
824
  for (var i = 0; i < tokens.length; i++) {
638
- var token = tokens[i]
825
+ var token = tokens[i];
639
826
 
640
827
  if (typeof token === 'string') {
641
- path += token
828
+ path += token;
642
829
 
643
830
  continue
644
831
  }
645
832
 
646
- var value = data[token.name]
647
- var segment
833
+ var value = data[token.name];
834
+ var segment;
648
835
 
649
836
  if (value == null) {
650
837
  if (token.optional) {
651
838
  // Prepend partial segment prefixes.
652
839
  if (token.partial) {
653
- path += token.prefix
840
+ path += token.prefix;
654
841
  }
655
842
 
656
843
  continue
@@ -673,25 +860,25 @@ function tokensToFunction (tokens) {
673
860
  }
674
861
 
675
862
  for (var j = 0; j < value.length; j++) {
676
- segment = encode(value[j])
863
+ segment = encode(value[j]);
677
864
 
678
865
  if (!matches[i].test(segment)) {
679
866
  throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
680
867
  }
681
868
 
682
- path += (j === 0 ? token.prefix : token.delimiter) + segment
869
+ path += (j === 0 ? token.prefix : token.delimiter) + segment;
683
870
  }
684
871
 
685
872
  continue
686
873
  }
687
874
 
688
- segment = token.asterisk ? encodeAsterisk(value) : encode(value)
875
+ segment = token.asterisk ? encodeAsterisk(value) : encode(value);
689
876
 
690
877
  if (!matches[i].test(segment)) {
691
878
  throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
692
879
  }
693
880
 
694
- path += token.prefix + segment
881
+ path += token.prefix + segment;
695
882
  }
696
883
 
697
884
  return path
@@ -726,7 +913,7 @@ function escapeGroup (group) {
726
913
  * @return {!RegExp}
727
914
  */
728
915
  function attachKeys (re, keys) {
729
- re.keys = keys
916
+ re.keys = keys;
730
917
  return re
731
918
  }
732
919
 
@@ -749,7 +936,7 @@ function flags (options) {
749
936
  */
750
937
  function regexpToRegexp (path, keys) {
751
938
  // Use a negative lookahead to match only capturing groups.
752
- var groups = path.source.match(/\((?!\?)/g)
939
+ var groups = path.source.match(/\((?!\?)/g);
753
940
 
754
941
  if (groups) {
755
942
  for (var i = 0; i < groups.length; i++) {
@@ -762,7 +949,7 @@ function regexpToRegexp (path, keys) {
762
949
  partial: false,
763
950
  asterisk: false,
764
951
  pattern: null
765
- })
952
+ });
766
953
  }
767
954
  }
768
955
 
@@ -778,13 +965,13 @@ function regexpToRegexp (path, keys) {
778
965
  * @return {!RegExp}
779
966
  */
780
967
  function arrayToRegexp (path, keys, options) {
781
- var parts = []
968
+ var parts = [];
782
969
 
783
970
  for (var i = 0; i < path.length; i++) {
784
- parts.push(pathToRegexp(path[i], keys, options).source)
971
+ parts.push(pathToRegexp(path[i], keys, options).source);
785
972
  }
786
973
 
787
- var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options))
974
+ var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options));
788
975
 
789
976
  return attachKeys(regexp, keys)
790
977
  }
@@ -798,80 +985,79 @@ function arrayToRegexp (path, keys, options) {
798
985
  * @return {!RegExp}
799
986
  */
800
987
  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
- }
810
-
811
- return attachKeys(re, keys)
812
- }
988
+ return tokensToRegExp(parse(path, options), keys, options)
989
+ }
813
990
 
814
991
  /**
815
992
  * Expose a function for taking tokens and returning a RegExp.
816
993
  *
817
- * @param {!Array} tokens
818
- * @param {Object=} options
994
+ * @param {!Array} tokens
995
+ * @param {(Array|Object)=} keys
996
+ * @param {Object=} options
819
997
  * @return {!RegExp}
820
998
  */
821
- function tokensToRegExp (tokens, options) {
822
- options = options || {}
999
+ function tokensToRegExp (tokens, keys, options) {
1000
+ if (!isarray(keys)) {
1001
+ options = /** @type {!Object} */ (keys || options);
1002
+ keys = [];
1003
+ }
1004
+
1005
+ options = options || {};
823
1006
 
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)
1007
+ var strict = options.strict;
1008
+ var end = options.end !== false;
1009
+ var route = '';
829
1010
 
830
1011
  // Iterate over the tokens and create our regexp string.
831
1012
  for (var i = 0; i < tokens.length; i++) {
832
- var token = tokens[i]
1013
+ var token = tokens[i];
833
1014
 
834
1015
  if (typeof token === 'string') {
835
- route += escapeString(token)
1016
+ route += escapeString(token);
836
1017
  } else {
837
- var prefix = escapeString(token.prefix)
838
- var capture = '(?:' + token.pattern + ')'
1018
+ var prefix = escapeString(token.prefix);
1019
+ var capture = '(?:' + token.pattern + ')';
1020
+
1021
+ keys.push(token);
839
1022
 
840
1023
  if (token.repeat) {
841
- capture += '(?:' + prefix + capture + ')*'
1024
+ capture += '(?:' + prefix + capture + ')*';
842
1025
  }
843
1026
 
844
1027
  if (token.optional) {
845
1028
  if (!token.partial) {
846
- capture = '(?:' + prefix + '(' + capture + '))?'
1029
+ capture = '(?:' + prefix + '(' + capture + '))?';
847
1030
  } else {
848
- capture = prefix + '(' + capture + ')?'
1031
+ capture = prefix + '(' + capture + ')?';
849
1032
  }
850
1033
  } else {
851
- capture = prefix + '(' + capture + ')'
1034
+ capture = prefix + '(' + capture + ')';
852
1035
  }
853
1036
 
854
- route += capture
1037
+ route += capture;
855
1038
  }
856
1039
  }
857
1040
 
1041
+ var delimiter = escapeString(options.delimiter || '/');
1042
+ var endsWithDelimiter = route.slice(-delimiter.length) === delimiter;
1043
+
858
1044
  // In non-strict mode we allow a slash at the end of match. If the path to
859
1045
  // match already ends with a slash, we remove it for consistency. The slash
860
1046
  // is valid at the end of a path match, not in the middle. This is important
861
1047
  // in non-ending mode, where "/test/" shouldn't match "/test//route".
862
1048
  if (!strict) {
863
- route = (endsWithSlash ? route.slice(0, -2) : route) + '(?:\\/(?=$))?'
1049
+ route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?';
864
1050
  }
865
1051
 
866
1052
  if (end) {
867
- route += '$'
1053
+ route += '$';
868
1054
  } else {
869
1055
  // In non-ending mode, we need the capturing groups to match as much as
870
1056
  // possible by using a positive lookahead to the end or next path segment.
871
- route += strict && endsWithSlash ? '' : '(?=\\/|$)'
1057
+ route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)';
872
1058
  }
873
1059
 
874
- return new RegExp('^' + route, flags(options))
1060
+ return attachKeys(new RegExp('^' + route, flags(options)), keys)
875
1061
  }
876
1062
 
877
1063
  /**
@@ -887,15 +1073,13 @@ function tokensToRegExp (tokens, options) {
887
1073
  * @return {!RegExp}
888
1074
  */
889
1075
  function pathToRegexp (path, keys, options) {
890
- keys = keys || []
891
-
892
1076
  if (!isarray(keys)) {
893
- options = /** @type {!Object} */ (keys)
894
- keys = []
895
- } else if (!options) {
896
- options = {}
1077
+ options = /** @type {!Object} */ (keys || options);
1078
+ keys = [];
897
1079
  }
898
1080
 
1081
+ options = options || {};
1082
+
899
1083
  if (path instanceof RegExp) {
900
1084
  return regexpToRegexp(path, /** @type {!Array} */ (keys))
901
1085
  }
@@ -914,101 +1098,146 @@ index.tokensToRegExp = tokensToRegExp_1;
914
1098
 
915
1099
  /* */
916
1100
 
917
- function createRouteMap (routes) {
918
- var pathMap = Object.create(null)
919
- var nameMap = Object.create(null)
1101
+ var regexpCache = Object.create(null);
920
1102
 
921
- routes.forEach(function (route) {
922
- addRouteRecord(pathMap, nameMap, route)
923
- })
1103
+ function getRouteRegex (path) {
1104
+ var hit = regexpCache[path];
1105
+ var keys, regexp;
924
1106
 
925
- return {
926
- pathMap: pathMap,
927
- nameMap: nameMap
1107
+ if (hit) {
1108
+ keys = hit.keys;
1109
+ regexp = hit.regexp;
1110
+ } else {
1111
+ keys = [];
1112
+ regexp = index(path, keys);
1113
+ regexpCache[path] = { keys: keys, regexp: regexp };
928
1114
  }
1115
+
1116
+ return { keys: keys, regexp: regexp }
929
1117
  }
930
1118
 
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.")
1119
+ var regexpCompileCache = Object.create(null);
941
1120
 
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 || {}
1121
+ function fillParams (
1122
+ path,
1123
+ params,
1124
+ routeMsg
1125
+ ) {
1126
+ try {
1127
+ var filler =
1128
+ regexpCompileCache[path] ||
1129
+ (regexpCompileCache[path] = index.compile(path));
1130
+ return filler(params || {}, { pretty: true })
1131
+ } catch (e) {
1132
+ {
1133
+ warn(false, ("missing param for " + routeMsg + ": " + (e.message)));
1134
+ }
1135
+ return ''
952
1136
  }
1137
+ }
953
1138
 
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
- })
1139
+ /* */
1140
+
1141
+ function normalizeLocation (
1142
+ raw,
1143
+ current,
1144
+ append
1145
+ ) {
1146
+ var next = typeof raw === 'string' ? { path: raw } : raw;
1147
+ // named target
1148
+ if (next.name || next._normalized) {
1149
+ return next
962
1150
  }
963
1151
 
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
- })
1152
+ // relative params
1153
+ if (!next.path && next.params && current) {
1154
+ next = assign({}, next);
1155
+ next._normalized = true;
1156
+ var params = assign(assign({}, current.params), next.params);
1157
+ if (current.name) {
1158
+ next.name = current.name;
1159
+ next.params = params;
1160
+ } else if (current.matched) {
1161
+ var rawPath = current.matched[current.matched.length - 1].path;
1162
+ next.path = fillParams(rawPath, params, ("path " + (current.path)));
969
1163
  } else {
970
- addRouteRecord(pathMap, nameMap, { path: route.alias }, parent, record.path)
1164
+ warn(false, "relative params navigation requires a current route.");
971
1165
  }
1166
+ return next
1167
+ }
1168
+
1169
+ var parsedPath = parsePath(next.path || '');
1170
+ var basePath = (current && current.path) || '/';
1171
+ var path = parsedPath.path
1172
+ ? resolvePath(parsedPath.path, basePath, append || next.append)
1173
+ : (current && current.path) || '/';
1174
+ var query = resolveQuery(parsedPath.query, next.query);
1175
+ var hash = next.hash || parsedPath.hash;
1176
+ if (hash && hash.charAt(0) !== '#') {
1177
+ hash = "#" + hash;
972
1178
  }
973
1179
 
974
- pathMap[record.path] = record
975
- if (name) { nameMap[name] = record }
1180
+ return {
1181
+ _normalized: true,
1182
+ path: path,
1183
+ query: query,
1184
+ hash: hash
1185
+ }
976
1186
  }
977
1187
 
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))
1188
+ function assign (a, b) {
1189
+ for (var key in b) {
1190
+ a[key] = b[key];
1191
+ }
1192
+ return a
983
1193
  }
984
1194
 
985
1195
  /* */
986
1196
 
987
- var regexpCache = Object.create(null)
988
-
989
- var regexpCompileCache = Object.create(null)
990
-
991
1197
  function createMatcher (routes) {
992
1198
  var ref = createRouteMap(routes);
993
1199
  var pathMap = ref.pathMap;
994
1200
  var nameMap = ref.nameMap;
995
1201
 
1202
+ function addRoutes (routes) {
1203
+ createRouteMap(routes, pathMap, nameMap);
1204
+ }
1205
+
996
1206
  function match (
997
1207
  raw,
998
1208
  currentRoute,
999
1209
  redirectedFrom
1000
1210
  ) {
1001
- var location = normalizeLocation(raw, currentRoute)
1211
+ var location = normalizeLocation(raw, currentRoute);
1002
1212
  var name = location.name;
1003
1213
 
1004
1214
  if (name) {
1005
- var record = nameMap[name]
1215
+ var record = nameMap[name];
1216
+ {
1217
+ warn(record, ("Route with name '" + name + "' does not exist"));
1218
+ }
1219
+ var paramNames = getRouteRegex(record.path).keys
1220
+ .filter(function (key) { return !key.optional; })
1221
+ .map(function (key) { return key.name; });
1222
+
1223
+ if (typeof location.params !== 'object') {
1224
+ location.params = {};
1225
+ }
1226
+
1227
+ if (currentRoute && typeof currentRoute.params === 'object') {
1228
+ for (var key in currentRoute.params) {
1229
+ if (!(key in location.params) && paramNames.indexOf(key) > -1) {
1230
+ location.params[key] = currentRoute.params[key];
1231
+ }
1232
+ }
1233
+ }
1234
+
1006
1235
  if (record) {
1007
- location.path = fillParams(record.path, location.params, ("named route \"" + name + "\""))
1236
+ location.path = fillParams(record.path, location.params, ("named route \"" + name + "\""));
1008
1237
  return _createRoute(record, location, redirectedFrom)
1009
1238
  }
1010
1239
  } else if (location.path) {
1011
- location.params = {}
1240
+ location.params = {};
1012
1241
  for (var path in pathMap) {
1013
1242
  if (matchRoute(path, location.params, location.path)) {
1014
1243
  return _createRoute(pathMap[path], location, redirectedFrom)
@@ -1023,34 +1252,38 @@ function createMatcher (routes) {
1023
1252
  record,
1024
1253
  location
1025
1254
  ) {
1026
- var originalRedirect = record.redirect
1255
+ var originalRedirect = record.redirect;
1027
1256
  var redirect = typeof originalRedirect === 'function'
1028
1257
  ? originalRedirect(createRoute(record, location))
1029
- : originalRedirect
1258
+ : originalRedirect;
1030
1259
 
1031
1260
  if (typeof redirect === 'string') {
1032
- redirect = { path: redirect }
1261
+ redirect = { path: redirect };
1033
1262
  }
1034
1263
 
1035
1264
  if (!redirect || typeof redirect !== 'object') {
1036
- warn(false, ("invalid redirect option: " + (JSON.stringify(redirect))))
1265
+ "development" !== 'production' && warn(
1266
+ false, ("invalid redirect option: " + (JSON.stringify(redirect)))
1267
+ );
1037
1268
  return _createRoute(null, location)
1038
1269
  }
1039
1270
 
1040
- var re = redirect
1271
+ var re = redirect;
1041
1272
  var name = re.name;
1042
1273
  var path = re.path;
1043
1274
  var query = location.query;
1044
1275
  var hash = location.hash;
1045
1276
  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
1277
+ query = re.hasOwnProperty('query') ? re.query : query;
1278
+ hash = re.hasOwnProperty('hash') ? re.hash : hash;
1279
+ params = re.hasOwnProperty('params') ? re.params : params;
1049
1280
 
1050
1281
  if (name) {
1051
1282
  // resolved named direct
1052
- var targetRecord = nameMap[name]
1053
- assert(targetRecord, ("redirect failed: named route \"" + name + "\" not found."))
1283
+ var targetRecord = nameMap[name];
1284
+ {
1285
+ assert(targetRecord, ("redirect failed: named route \"" + name + "\" not found."));
1286
+ }
1054
1287
  return match({
1055
1288
  _normalized: true,
1056
1289
  name: name,
@@ -1060,9 +1293,9 @@ function createMatcher (routes) {
1060
1293
  }, undefined, location)
1061
1294
  } else if (path) {
1062
1295
  // 1. resolve relative redirect
1063
- var rawPath = resolveRecordPath(path, record)
1296
+ var rawPath = resolveRecordPath(path, record);
1064
1297
  // 2. resolve params
1065
- var resolvedPath = fillParams(rawPath, params, ("redirect route with path \"" + rawPath + "\""))
1298
+ var resolvedPath = fillParams(rawPath, params, ("redirect route with path \"" + rawPath + "\""));
1066
1299
  // 3. rematch with existing query and hash
1067
1300
  return match({
1068
1301
  _normalized: true,
@@ -1071,7 +1304,7 @@ function createMatcher (routes) {
1071
1304
  hash: hash
1072
1305
  }, undefined, location)
1073
1306
  } else {
1074
- warn(false, ("invalid redirect option: " + (JSON.stringify(redirect))))
1307
+ warn(false, ("invalid redirect option: " + (JSON.stringify(redirect))));
1075
1308
  return _createRoute(null, location)
1076
1309
  }
1077
1310
  }
@@ -1081,15 +1314,15 @@ function createMatcher (routes) {
1081
1314
  location,
1082
1315
  matchAs
1083
1316
  ) {
1084
- var aliasedPath = fillParams(matchAs, location.params, ("aliased route with path \"" + matchAs + "\""))
1317
+ var aliasedPath = fillParams(matchAs, location.params, ("aliased route with path \"" + matchAs + "\""));
1085
1318
  var aliasedMatch = match({
1086
1319
  _normalized: true,
1087
1320
  path: aliasedPath
1088
- })
1321
+ });
1089
1322
  if (aliasedMatch) {
1090
- var matched = aliasedMatch.matched
1091
- var aliasedRecord = matched[matched.length - 1]
1092
- location.params = aliasedMatch.params
1323
+ var matched = aliasedMatch.matched;
1324
+ var aliasedRecord = matched[matched.length - 1];
1325
+ location.params = aliasedMatch.params;
1093
1326
  return _createRoute(aliasedRecord, location)
1094
1327
  }
1095
1328
  return _createRoute(null, location)
@@ -1109,7 +1342,10 @@ function createMatcher (routes) {
1109
1342
  return createRoute(record, location, redirectedFrom)
1110
1343
  }
1111
1344
 
1112
- return match
1345
+ return {
1346
+ match: match,
1347
+ addRoutes: addRoutes
1348
+ }
1113
1349
  }
1114
1350
 
1115
1351
  function matchRoute (
@@ -1117,17 +1353,10 @@ function matchRoute (
1117
1353
  params,
1118
1354
  pathname
1119
1355
  ) {
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)
1356
+ var ref = getRouteRegex(path);
1357
+ var regexp = ref.regexp;
1358
+ var keys = ref.keys;
1359
+ var m = pathname.match(regexp);
1131
1360
 
1132
1361
  if (!m) {
1133
1362
  return false
@@ -1136,40 +1365,121 @@ function matchRoute (
1136
1365
  }
1137
1366
 
1138
1367
  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 }
1368
+ var key = keys[i - 1];
1369
+ var val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i];
1370
+ if (key) { params[key.name] = val; }
1142
1371
  }
1143
1372
 
1144
1373
  return true
1145
1374
  }
1146
1375
 
1147
- function fillParams (
1148
- path,
1149
- params,
1150
- routeMsg
1376
+ function resolveRecordPath (path, record) {
1377
+ return resolvePath(path, record.parent ? record.parent.path : '/', true)
1378
+ }
1379
+
1380
+ /* */
1381
+
1382
+
1383
+ var positionStore = Object.create(null);
1384
+
1385
+ function setupScroll () {
1386
+ window.addEventListener('popstate', function (e) {
1387
+ saveScrollPosition();
1388
+ if (e.state && e.state.key) {
1389
+ setStateKey(e.state.key);
1390
+ }
1391
+ });
1392
+ }
1393
+
1394
+ function handleScroll (
1395
+ router,
1396
+ to,
1397
+ from,
1398
+ isPop
1151
1399
  ) {
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 ''
1400
+ if (!router.app) {
1401
+ return
1160
1402
  }
1403
+
1404
+ var behavior = router.options.scrollBehavior;
1405
+ if (!behavior) {
1406
+ return
1407
+ }
1408
+
1409
+ {
1410
+ assert(typeof behavior === 'function', "scrollBehavior must be a function");
1411
+ }
1412
+
1413
+ // wait until re-render finishes before scrolling
1414
+ router.app.$nextTick(function () {
1415
+ var position = getScrollPosition();
1416
+ var shouldScroll = behavior(to, from, isPop ? position : null);
1417
+ if (!shouldScroll) {
1418
+ return
1419
+ }
1420
+ var isObject = typeof shouldScroll === 'object';
1421
+ if (isObject && typeof shouldScroll.selector === 'string') {
1422
+ var el = document.querySelector(shouldScroll.selector);
1423
+ if (el) {
1424
+ position = getElementPosition(el);
1425
+ } else if (isValidPosition(shouldScroll)) {
1426
+ position = normalizePosition(shouldScroll);
1427
+ }
1428
+ } else if (isObject && isValidPosition(shouldScroll)) {
1429
+ position = normalizePosition(shouldScroll);
1430
+ }
1431
+
1432
+ if (position) {
1433
+ window.scrollTo(position.x, position.y);
1434
+ }
1435
+ });
1161
1436
  }
1162
1437
 
1163
- function resolveRecordPath (path, record) {
1164
- return resolvePath(path, record.parent ? record.parent.path : '/', true)
1438
+ function saveScrollPosition () {
1439
+ var key = getStateKey();
1440
+ if (key) {
1441
+ positionStore[key] = {
1442
+ x: window.pageXOffset,
1443
+ y: window.pageYOffset
1444
+ };
1445
+ }
1165
1446
  }
1166
1447
 
1167
- /* */
1448
+ function getScrollPosition () {
1449
+ var key = getStateKey();
1450
+ if (key) {
1451
+ return positionStore[key]
1452
+ }
1453
+ }
1168
1454
 
1169
- var inBrowser = typeof window !== 'undefined'
1455
+ function getElementPosition (el) {
1456
+ var docRect = document.documentElement.getBoundingClientRect();
1457
+ var elRect = el.getBoundingClientRect();
1458
+ return {
1459
+ x: elRect.left - docRect.left,
1460
+ y: elRect.top - docRect.top
1461
+ }
1462
+ }
1463
+
1464
+ function isValidPosition (obj) {
1465
+ return isNumber(obj.x) || isNumber(obj.y)
1466
+ }
1467
+
1468
+ function normalizePosition (obj) {
1469
+ return {
1470
+ x: isNumber(obj.x) ? obj.x : window.pageXOffset,
1471
+ y: isNumber(obj.y) ? obj.y : window.pageYOffset
1472
+ }
1473
+ }
1474
+
1475
+ function isNumber (v) {
1476
+ return typeof v === 'number'
1477
+ }
1170
1478
 
1171
- var supportsHistory = inBrowser && (function () {
1172
- var ua = window.navigator.userAgent
1479
+ /* */
1480
+
1481
+ var supportsPushState = inBrowser && (function () {
1482
+ var ua = window.navigator.userAgent;
1173
1483
 
1174
1484
  if (
1175
1485
  (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
@@ -1181,63 +1491,127 @@ var supportsHistory = inBrowser && (function () {
1181
1491
  }
1182
1492
 
1183
1493
  return window.history && 'pushState' in window.history
1184
- })()
1494
+ })();
1495
+
1496
+ // use User Timing api (if present) for more accurate key precision
1497
+ var Time = inBrowser && window.performance && window.performance.now
1498
+ ? window.performance
1499
+ : Date;
1500
+
1501
+ var _key = genKey();
1502
+
1503
+ function genKey () {
1504
+ return Time.now().toFixed(3)
1505
+ }
1506
+
1507
+ function getStateKey () {
1508
+ return _key
1509
+ }
1510
+
1511
+ function setStateKey (key) {
1512
+ _key = key;
1513
+ }
1514
+
1515
+ function pushState (url, replace) {
1516
+ saveScrollPosition();
1517
+ // try...catch the pushState call to get around Safari
1518
+ // DOM Exception 18 where it limits to 100 pushState calls
1519
+ var history = window.history;
1520
+ try {
1521
+ if (replace) {
1522
+ history.replaceState({ key: _key }, '', url);
1523
+ } else {
1524
+ _key = genKey();
1525
+ history.pushState({ key: _key }, '', url);
1526
+ }
1527
+ } catch (e) {
1528
+ window.location[replace ? 'replace' : 'assign'](url);
1529
+ }
1530
+ }
1531
+
1532
+ function replaceState (url) {
1533
+ pushState(url, true);
1534
+ }
1185
1535
 
1186
1536
  /* */
1187
1537
 
1188
1538
  function runQueue (queue, fn, cb) {
1189
1539
  var step = function (index) {
1190
1540
  if (index >= queue.length) {
1191
- cb()
1541
+ cb();
1192
1542
  } else {
1193
1543
  if (queue[index]) {
1194
1544
  fn(queue[index], function () {
1195
- step(index + 1)
1196
- })
1545
+ step(index + 1);
1546
+ });
1197
1547
  } else {
1198
- step(index + 1)
1548
+ step(index + 1);
1199
1549
  }
1200
1550
  }
1201
- }
1202
- step(0)
1551
+ };
1552
+ step(0);
1203
1553
  }
1204
1554
 
1205
1555
  /* */
1206
1556
 
1207
1557
 
1208
1558
  var History = function History (router, base) {
1209
- this.router = router
1210
- this.base = normalizeBase(base)
1559
+ this.router = router;
1560
+ this.base = normalizeBase(base);
1211
1561
  // start with a route object that stands for "nowhere"
1212
- this.current = START
1213
- this.pending = null
1562
+ this.current = START;
1563
+ this.pending = null;
1564
+ this.ready = false;
1565
+ this.readyCbs = [];
1214
1566
  };
1215
1567
 
1216
1568
  History.prototype.listen = function listen (cb) {
1217
- this.cb = cb
1569
+ this.cb = cb;
1218
1570
  };
1219
1571
 
1220
- History.prototype.transitionTo = function transitionTo (location, cb) {
1572
+ History.prototype.onReady = function onReady (cb) {
1573
+ if (this.ready) {
1574
+ cb();
1575
+ } else {
1576
+ this.readyCbs.push(cb);
1577
+ }
1578
+ };
1579
+
1580
+ History.prototype.transitionTo = function transitionTo (location, onComplete, onAbort) {
1221
1581
  var this$1 = this;
1222
1582
 
1223
- var route = this.router.match(location, this.current)
1583
+ var route = this.router.match(location, this.current);
1224
1584
  this.confirmTransition(route, function () {
1225
- this$1.updateRoute(route)
1226
- cb && cb(route)
1227
- this$1.ensureURL()
1228
- })
1585
+ this$1.updateRoute(route);
1586
+ onComplete && onComplete(route);
1587
+ this$1.ensureURL();
1588
+
1589
+ // fire ready cbs once
1590
+ if (!this$1.ready) {
1591
+ this$1.ready = true;
1592
+ this$1.readyCbs.forEach(function (cb) {
1593
+ cb(route);
1594
+ });
1595
+ }
1596
+ }, onAbort);
1229
1597
  };
1230
1598
 
1231
- History.prototype.confirmTransition = function confirmTransition (route, cb) {
1599
+ History.prototype.confirmTransition = function confirmTransition (route, onComplete, onAbort) {
1232
1600
  var this$1 = this;
1233
1601
 
1234
- var current = this.current
1235
- if (isSameRoute(route, current)) {
1236
- this.ensureURL()
1237
- return
1602
+ var current = this.current;
1603
+ var abort = function () { onAbort && onAbort(); };
1604
+ if (
1605
+ isSameRoute(route, current) &&
1606
+ // in the case the route map has been dynamically appended to
1607
+ route.matched.length === current.matched.length
1608
+ ) {
1609
+ this.ensureURL();
1610
+ return abort()
1238
1611
  }
1239
1612
 
1240
1613
  var ref = resolveQueue(this.current.matched, route.matched);
1614
+ var updated = ref.updated;
1241
1615
  var deactivated = ref.deactivated;
1242
1616
  var activated = ref.activated;
1243
1617
 
@@ -1246,67 +1620,78 @@ History.prototype.confirmTransition = function confirmTransition (route, cb) {
1246
1620
  extractLeaveGuards(deactivated),
1247
1621
  // global before hooks
1248
1622
  this.router.beforeHooks,
1249
- // enter guards
1623
+ // in-component update hooks
1624
+ extractUpdateHooks(updated),
1625
+ // in-config enter guards
1250
1626
  activated.map(function (m) { return m.beforeEnter; }),
1251
1627
  // async components
1252
1628
  resolveAsyncComponents(activated)
1253
- )
1629
+ );
1254
1630
 
1255
- this.pending = route
1631
+ this.pending = route;
1256
1632
  var iterator = function (hook, next) {
1257
- if (this$1.pending !== route) { return }
1633
+ if (this$1.pending !== route) {
1634
+ return abort()
1635
+ }
1258
1636
  hook(route, current, function (to) {
1259
1637
  if (to === false) {
1260
1638
  // next(false) -> abort navigation, ensure current URL
1261
- this$1.ensureURL()
1639
+ this$1.ensureURL(true);
1640
+ abort();
1262
1641
  } else if (typeof to === 'string' || typeof to === 'object') {
1263
1642
  // next('/') or next({ path: '/' }) -> redirect
1264
- this$1.push(to)
1643
+ (typeof to === 'object' && to.replace) ? this$1.replace(to) : this$1.push(to);
1644
+ abort();
1265
1645
  } else {
1266
1646
  // confirm transition and pass on the value
1267
- next(to)
1647
+ next(to);
1268
1648
  }
1269
- })
1270
- }
1649
+ });
1650
+ };
1271
1651
 
1272
1652
  runQueue(queue, iterator, function () {
1273
- var postEnterCbs = []
1653
+ var postEnterCbs = [];
1654
+ var isValid = function () { return this$1.current === route; };
1655
+ var enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);
1274
1656
  // wait until async components are resolved before
1275
1657
  // 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)
1658
+ runQueue(enterGuards, iterator, function () {
1659
+ if (this$1.pending !== route) {
1660
+ return abort()
1661
+ }
1662
+ this$1.pending = null;
1663
+ onComplete(route);
1664
+ if (this$1.router.app) {
1280
1665
  this$1.router.app.$nextTick(function () {
1281
- postEnterCbs.forEach(function (cb) { return cb(); })
1282
- })
1666
+ postEnterCbs.forEach(function (cb) { return cb(); });
1667
+ });
1283
1668
  }
1284
- })
1285
- })
1669
+ });
1670
+ });
1286
1671
  };
1287
1672
 
1288
1673
  History.prototype.updateRoute = function updateRoute (route) {
1289
- var prev = this.current
1290
- this.current = route
1291
- this.cb && this.cb(route)
1674
+ var prev = this.current;
1675
+ this.current = route;
1676
+ this.cb && this.cb(route);
1292
1677
  this.router.afterHooks.forEach(function (hook) {
1293
- hook && hook(route, prev)
1294
- })
1678
+ hook && hook(route, prev);
1679
+ });
1295
1680
  };
1296
1681
 
1297
1682
  function normalizeBase (base) {
1298
1683
  if (!base) {
1299
1684
  if (inBrowser) {
1300
1685
  // respect <base> tag
1301
- var baseEl = document.querySelector('base')
1302
- base = baseEl ? baseEl.getAttribute('href') : '/'
1686
+ var baseEl = document.querySelector('base');
1687
+ base = baseEl ? baseEl.getAttribute('href') : '/';
1303
1688
  } else {
1304
- base = '/'
1689
+ base = '/';
1305
1690
  }
1306
1691
  }
1307
1692
  // make sure there's the starting slash
1308
1693
  if (base.charAt(0) !== '/') {
1309
- base = '/' + base
1694
+ base = '/' + base;
1310
1695
  }
1311
1696
  // remove trailing slash
1312
1697
  return base.replace(/\/$/, '')
@@ -1316,48 +1701,111 @@ function resolveQueue (
1316
1701
  current,
1317
1702
  next
1318
1703
  ) {
1319
- var i
1320
- var max = Math.max(current.length, next.length)
1704
+ var i;
1705
+ var max = Math.max(current.length, next.length);
1321
1706
  for (i = 0; i < max; i++) {
1322
1707
  if (current[i] !== next[i]) {
1323
1708
  break
1324
1709
  }
1325
1710
  }
1326
1711
  return {
1712
+ updated: next.slice(0, i),
1327
1713
  activated: next.slice(i),
1328
1714
  deactivated: current.slice(i)
1329
1715
  }
1330
1716
  }
1331
1717
 
1332
- function extractLeaveGuards (matched) {
1333
- return flatMapComponents(matched, function (def, instance) {
1334
- var guard = def && def.beforeRouteLeave
1718
+ function extractGuards (
1719
+ records,
1720
+ name,
1721
+ bind,
1722
+ reverse
1723
+ ) {
1724
+ var guards = flatMapComponents(records, function (def, instance, match, key) {
1725
+ var guard = extractGuard(def, name);
1335
1726
  if (guard) {
1336
- return function routeLeaveGuard () {
1337
- return guard.apply(instance, arguments)
1338
- }
1727
+ return Array.isArray(guard)
1728
+ ? guard.map(function (guard) { return bind(guard, instance, match, key); })
1729
+ : bind(guard, instance, match, key)
1339
1730
  }
1340
- }).reverse()
1731
+ });
1732
+ return flatten(reverse ? guards.reverse() : guards)
1341
1733
  }
1342
1734
 
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
- })
1356
- }
1357
- }
1735
+ function extractGuard (
1736
+ def,
1737
+ key
1738
+ ) {
1739
+ if (typeof def !== 'function') {
1740
+ // extend now so that global mixins are applied.
1741
+ def = _Vue.extend(def);
1742
+ }
1743
+ return def.options[key]
1744
+ }
1745
+
1746
+ function extractLeaveGuards (deactivated) {
1747
+ return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
1748
+ }
1749
+
1750
+ function extractUpdateHooks (updated) {
1751
+ return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
1752
+ }
1753
+
1754
+ function bindGuard (guard, instance) {
1755
+ return function boundRouteGuard () {
1756
+ return guard.apply(instance, arguments)
1757
+ }
1758
+ }
1759
+
1760
+ function extractEnterGuards (
1761
+ activated,
1762
+ cbs,
1763
+ isValid
1764
+ ) {
1765
+ return extractGuards(activated, 'beforeRouteEnter', function (guard, _, match, key) {
1766
+ return bindEnterGuard(guard, match, key, cbs, isValid)
1358
1767
  })
1359
1768
  }
1360
1769
 
1770
+ function bindEnterGuard (
1771
+ guard,
1772
+ match,
1773
+ key,
1774
+ cbs,
1775
+ isValid
1776
+ ) {
1777
+ return function routeEnterGuard (to, from, next) {
1778
+ return guard(to, from, function (cb) {
1779
+ next(cb);
1780
+ if (typeof cb === 'function') {
1781
+ cbs.push(function () {
1782
+ // #750
1783
+ // if a router-view is wrapped with an out-in transition,
1784
+ // the instance may not have been registered at this time.
1785
+ // we will need to poll for registration until current route
1786
+ // is no longer valid.
1787
+ poll(cb, match.instances, key, isValid);
1788
+ });
1789
+ }
1790
+ })
1791
+ }
1792
+ }
1793
+
1794
+ function poll (
1795
+ cb, // somehow flow cannot infer this is a function
1796
+ instances,
1797
+ key,
1798
+ isValid
1799
+ ) {
1800
+ if (instances[key]) {
1801
+ cb(instances[key]);
1802
+ } else if (isValid()) {
1803
+ setTimeout(function () {
1804
+ poll(cb, instances, key, isValid);
1805
+ }, 16);
1806
+ }
1807
+ }
1808
+
1361
1809
  function resolveAsyncComponents (matched) {
1362
1810
  return flatMapComponents(matched, function (def, _, match, key) {
1363
1811
  // if it's a function and doesn't have Vue options attached,
@@ -1367,19 +1815,19 @@ function resolveAsyncComponents (matched) {
1367
1815
  // resolved.
1368
1816
  if (typeof def === 'function' && !def.options) {
1369
1817
  return function (to, from, next) {
1370
- var resolve = function (resolvedDef) {
1371
- match.components[key] = resolvedDef
1372
- next()
1373
- }
1818
+ var resolve = once(function (resolvedDef) {
1819
+ match.components[key] = resolvedDef;
1820
+ next();
1821
+ });
1374
1822
 
1375
- var reject = function (reason) {
1376
- warn(false, ("Failed to resolve async component " + key + ": " + reason))
1377
- next(false)
1378
- }
1823
+ var reject = once(function (reason) {
1824
+ warn(false, ("Failed to resolve async component " + key + ": " + reason));
1825
+ next(false);
1826
+ });
1379
1827
 
1380
- var res = def(resolve, reject)
1828
+ var res = def(resolve, reject);
1381
1829
  if (res && typeof res.then === 'function') {
1382
- res.then(resolve, reject)
1830
+ res.then(resolve, reject);
1383
1831
  }
1384
1832
  }
1385
1833
  }
@@ -1390,7 +1838,7 @@ function flatMapComponents (
1390
1838
  matched,
1391
1839
  fn
1392
1840
  ) {
1393
- return Array.prototype.concat.apply([], matched.map(function (m) {
1841
+ return flatten(matched.map(function (m) {
1394
1842
  return Object.keys(m.components).map(function (key) { return fn(
1395
1843
  m.components[key],
1396
1844
  m.instances[key],
@@ -1399,321 +1847,249 @@ function flatMapComponents (
1399
1847
  }))
1400
1848
  }
1401
1849
 
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
1423
- }
1424
- }
1425
-
1426
- function isValidPosition (obj) {
1427
- return isNumber(obj.x) || isNumber(obj.y)
1850
+ function flatten (arr) {
1851
+ return Array.prototype.concat.apply([], arr)
1428
1852
  }
1429
1853
 
1430
- function normalizePosition (obj) {
1431
- return {
1432
- x: isNumber(obj.x) ? obj.x : window.pageXOffset,
1433
- y: isNumber(obj.y) ? obj.y : window.pageYOffset
1854
+ // in Webpack 2, require.ensure now also returns a Promise
1855
+ // so the resolve/reject functions may get called an extra time
1856
+ // if the user uses an arrow function shorthand that happens to
1857
+ // return that Promise.
1858
+ function once (fn) {
1859
+ var called = false;
1860
+ return function () {
1861
+ if (called) { return }
1862
+ called = true;
1863
+ return fn.apply(this, arguments)
1434
1864
  }
1435
1865
  }
1436
1866
 
1437
- function isNumber (v) {
1438
- return typeof v === 'number'
1439
- }
1440
-
1441
1867
  /* */
1442
1868
 
1443
1869
 
1444
- var genKey = function () { return String(Date.now()); }
1445
- var _key = genKey()
1446
-
1447
- var HTML5History = (function (History) {
1870
+ var HTML5History = (function (History$$1) {
1448
1871
  function HTML5History (router, base) {
1449
1872
  var this$1 = this;
1450
1873
 
1451
- History.call(this, router, base)
1874
+ History$$1.call(this, router, base);
1875
+
1876
+ var expectScroll = router.options.scrollBehavior;
1452
1877
 
1453
- this.transitionTo(getLocation(this.base))
1878
+ if (expectScroll) {
1879
+ setupScroll();
1880
+ }
1454
1881
 
1455
- var expectScroll = router.options.scrollBehavior
1456
1882
  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) {
1883
+ this$1.transitionTo(getLocation(this$1.base), function (route) {
1460
1884
  if (expectScroll) {
1461
- this$1.handleScroll(next, current, true)
1885
+ handleScroll(router, route, this$1.current, true);
1462
1886
  }
1463
- })
1464
- })
1465
-
1466
- if (expectScroll) {
1467
- window.addEventListener('scroll', function () {
1468
- saveScrollPosition(_key)
1469
- })
1470
- }
1887
+ });
1888
+ });
1471
1889
  }
1472
1890
 
1473
- if ( History ) HTML5History.__proto__ = History;
1474
- HTML5History.prototype = Object.create( History && History.prototype );
1891
+ if ( History$$1 ) HTML5History.__proto__ = History$$1;
1892
+ HTML5History.prototype = Object.create( History$$1 && History$$1.prototype );
1475
1893
  HTML5History.prototype.constructor = HTML5History;
1476
1894
 
1477
1895
  HTML5History.prototype.go = function go (n) {
1478
- window.history.go(n)
1896
+ window.history.go(n);
1479
1897
  };
1480
1898
 
1481
- HTML5History.prototype.push = function push (location) {
1899
+ HTML5History.prototype.push = function push (location, onComplete, onAbort) {
1482
1900
  var this$1 = this;
1483
1901
 
1484
- var current = this.current
1485
1902
  this.transitionTo(location, function (route) {
1486
- pushState(cleanPath(this$1.base + route.fullPath))
1487
- this$1.handleScroll(route, current, false)
1488
- })
1903
+ pushState(cleanPath(this$1.base + route.fullPath));
1904
+ handleScroll(this$1.router, route, this$1.current, false);
1905
+ onComplete && onComplete(route);
1906
+ }, onAbort);
1489
1907
  };
1490
1908
 
1491
- HTML5History.prototype.replace = function replace (location) {
1909
+ HTML5History.prototype.replace = function replace (location, onComplete, onAbort) {
1492
1910
  var this$1 = this;
1493
1911
 
1494
- var current = this.current
1495
1912
  this.transitionTo(location, function (route) {
1496
- replaceState(cleanPath(this$1.base + route.fullPath))
1497
- this$1.handleScroll(route, current, false)
1498
- })
1913
+ replaceState(cleanPath(this$1.base + route.fullPath));
1914
+ handleScroll(this$1.router, route, this$1.current, false);
1915
+ onComplete && onComplete(route);
1916
+ }, onAbort);
1499
1917
  };
1500
1918
 
1501
- HTML5History.prototype.ensureURL = function ensureURL () {
1919
+ HTML5History.prototype.ensureURL = function ensureURL (push) {
1502
1920
  if (getLocation(this.base) !== this.current.fullPath) {
1503
- replaceState(cleanPath(this.base + this.current.fullPath))
1921
+ var current = cleanPath(this.base + this.current.fullPath);
1922
+ push ? pushState(current) : replaceState(current);
1504
1923
  }
1505
1924
  };
1506
1925
 
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)
1533
- }
1534
- } else if (isObject && isValidPosition(shouldScroll)) {
1535
- position = normalizePosition(shouldScroll)
1536
- }
1537
-
1538
- if (position) {
1539
- window.scrollTo(position.x, position.y)
1540
- }
1541
- })
1926
+ HTML5History.prototype.getCurrentLocation = function getCurrentLocation () {
1927
+ return getLocation(this.base)
1542
1928
  };
1543
1929
 
1544
1930
  return HTML5History;
1545
1931
  }(History));
1546
1932
 
1547
1933
  function getLocation (base) {
1548
- var path = window.location.pathname
1934
+ var path = window.location.pathname;
1549
1935
  if (base && path.indexOf(base) === 0) {
1550
- path = path.slice(base.length)
1936
+ path = path.slice(base.length);
1551
1937
  }
1552
1938
  return (path || '/') + window.location.search + window.location.hash
1553
1939
  }
1554
1940
 
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)
1565
- }
1566
- saveScrollPosition(_key)
1567
- } catch (e) {
1568
- window.location[replace ? 'assign' : 'replace'](url)
1569
- }
1570
- }
1571
-
1572
- function replaceState (url) {
1573
- pushState(url, true)
1574
- }
1575
-
1576
1941
  /* */
1577
1942
 
1578
1943
 
1579
- var HashHistory = (function (History) {
1944
+ var HashHistory = (function (History$$1) {
1580
1945
  function HashHistory (router, base, fallback) {
1581
- var this$1 = this;
1582
-
1583
- History.call(this, router, base)
1584
-
1946
+ History$$1.call(this, router, base);
1585
1947
  // check history fallback deeplinking
1586
- if (fallback && this.checkFallback()) {
1948
+ if (fallback && checkFallback(this.base)) {
1587
1949
  return
1588
1950
  }
1589
-
1590
- ensureSlash()
1591
- this.transitionTo(getHash())
1592
-
1593
- window.addEventListener('hashchange', function () {
1594
- this$1.onHashChange()
1595
- })
1951
+ ensureSlash();
1596
1952
  }
1597
1953
 
1598
- if ( History ) HashHistory.__proto__ = History;
1599
- HashHistory.prototype = Object.create( History && History.prototype );
1954
+ if ( History$$1 ) HashHistory.__proto__ = History$$1;
1955
+ HashHistory.prototype = Object.create( History$$1 && History$$1.prototype );
1600
1956
  HashHistory.prototype.constructor = HashHistory;
1601
1957
 
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
- };
1958
+ // this is delayed until the app mounts
1959
+ // to avoid the hashchange listener being fired too early
1960
+ HashHistory.prototype.setupListeners = function setupListeners () {
1961
+ var this$1 = this;
1611
1962
 
1612
- HashHistory.prototype.onHashChange = function onHashChange () {
1613
- if (!ensureSlash()) {
1614
- return
1615
- }
1616
- this.transitionTo(getHash(), function (route) {
1617
- replaceHash(route.fullPath)
1618
- })
1963
+ window.addEventListener('hashchange', function () {
1964
+ if (!ensureSlash()) {
1965
+ return
1966
+ }
1967
+ this$1.transitionTo(getHash(), function (route) {
1968
+ replaceHash(route.fullPath);
1969
+ });
1970
+ });
1619
1971
  };
1620
1972
 
1621
- HashHistory.prototype.push = function push (location) {
1622
- History.prototype.transitionTo.call(this, location, function (route) {
1623
- pushHash(route.fullPath)
1624
- })
1973
+ HashHistory.prototype.push = function push (location, onComplete, onAbort) {
1974
+ this.transitionTo(location, function (route) {
1975
+ pushHash(route.fullPath);
1976
+ onComplete && onComplete(route);
1977
+ }, onAbort);
1625
1978
  };
1626
1979
 
1627
- HashHistory.prototype.replace = function replace (location) {
1628
- History.prototype.transitionTo.call(this, location, function (route) {
1629
- replaceHash(route.fullPath)
1630
- })
1980
+ HashHistory.prototype.replace = function replace (location, onComplete, onAbort) {
1981
+ this.transitionTo(location, function (route) {
1982
+ replaceHash(route.fullPath);
1983
+ onComplete && onComplete(route);
1984
+ }, onAbort);
1631
1985
  };
1632
1986
 
1633
1987
  HashHistory.prototype.go = function go (n) {
1634
- window.history.go(n)
1988
+ window.history.go(n);
1635
1989
  };
1636
1990
 
1637
- HashHistory.prototype.ensureURL = function ensureURL () {
1638
- if (getHash() !== this.current.fullPath) {
1639
- replaceHash(this.current.fullPath)
1991
+ HashHistory.prototype.ensureURL = function ensureURL (push) {
1992
+ var current = this.current.fullPath;
1993
+ if (getHash() !== current) {
1994
+ push ? pushHash(current) : replaceHash(current);
1640
1995
  }
1641
1996
  };
1642
1997
 
1998
+ HashHistory.prototype.getCurrentLocation = function getCurrentLocation () {
1999
+ return getHash()
2000
+ };
2001
+
1643
2002
  return HashHistory;
1644
2003
  }(History));
1645
2004
 
2005
+ function checkFallback (base) {
2006
+ var location = getLocation(base);
2007
+ if (!/^\/#/.test(location)) {
2008
+ window.location.replace(
2009
+ cleanPath(base + '/#' + location)
2010
+ );
2011
+ return true
2012
+ }
2013
+ }
2014
+
1646
2015
  function ensureSlash () {
1647
- var path = getHash()
2016
+ var path = getHash();
1648
2017
  if (path.charAt(0) === '/') {
1649
2018
  return true
1650
2019
  }
1651
- replaceHash('/' + path)
2020
+ replaceHash('/' + path);
1652
2021
  return false
1653
2022
  }
1654
2023
 
1655
2024
  function getHash () {
1656
2025
  // We can't use window.location.hash here because it's not
1657
2026
  // consistent across browsers - Firefox will pre-decode it!
1658
- var href = window.location.href
1659
- var index = href.indexOf('#')
2027
+ var href = window.location.href;
2028
+ var index = href.indexOf('#');
1660
2029
  return index === -1 ? '' : href.slice(index + 1)
1661
2030
  }
1662
2031
 
1663
2032
  function pushHash (path) {
1664
- window.location.hash = path
2033
+ window.location.hash = path;
1665
2034
  }
1666
2035
 
1667
2036
  function replaceHash (path) {
1668
- var i = window.location.href.indexOf('#')
2037
+ var i = window.location.href.indexOf('#');
1669
2038
  window.location.replace(
1670
2039
  window.location.href.slice(0, i >= 0 ? i : 0) + '#' + path
1671
- )
2040
+ );
1672
2041
  }
1673
2042
 
1674
2043
  /* */
1675
2044
 
1676
2045
 
1677
- var AbstractHistory = (function (History) {
1678
- function AbstractHistory (router) {
1679
- History.call(this, router)
1680
- this.stack = []
1681
- this.index = 0
2046
+ var AbstractHistory = (function (History$$1) {
2047
+ function AbstractHistory (router, base) {
2048
+ History$$1.call(this, router, base);
2049
+ this.stack = [];
2050
+ this.index = -1;
1682
2051
  }
1683
2052
 
1684
- if ( History ) AbstractHistory.__proto__ = History;
1685
- AbstractHistory.prototype = Object.create( History && History.prototype );
2053
+ if ( History$$1 ) AbstractHistory.__proto__ = History$$1;
2054
+ AbstractHistory.prototype = Object.create( History$$1 && History$$1.prototype );
1686
2055
  AbstractHistory.prototype.constructor = AbstractHistory;
1687
2056
 
1688
- AbstractHistory.prototype.push = function push (location) {
2057
+ AbstractHistory.prototype.push = function push (location, onComplete, onAbort) {
1689
2058
  var this$1 = this;
1690
2059
 
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
- })
2060
+ this.transitionTo(location, function (route) {
2061
+ this$1.stack = this$1.stack.slice(0, this$1.index + 1).concat(route);
2062
+ this$1.index++;
2063
+ onComplete && onComplete(route);
2064
+ }, onAbort);
1695
2065
  };
1696
2066
 
1697
- AbstractHistory.prototype.replace = function replace (location) {
2067
+ AbstractHistory.prototype.replace = function replace (location, onComplete, onAbort) {
1698
2068
  var this$1 = this;
1699
2069
 
1700
- History.prototype.transitionTo.call(this, location, function (route) {
1701
- this$1.stack = this$1.stack.slice(0, this$1.index).concat(route)
1702
- })
2070
+ this.transitionTo(location, function (route) {
2071
+ this$1.stack = this$1.stack.slice(0, this$1.index).concat(route);
2072
+ onComplete && onComplete(route);
2073
+ }, onAbort);
1703
2074
  };
1704
2075
 
1705
2076
  AbstractHistory.prototype.go = function go (n) {
1706
2077
  var this$1 = this;
1707
2078
 
1708
- var targetIndex = this.index + n
2079
+ var targetIndex = this.index + n;
1709
2080
  if (targetIndex < 0 || targetIndex >= this.stack.length) {
1710
2081
  return
1711
2082
  }
1712
- var location = this.stack[targetIndex]
1713
- this.confirmTransition(location, function () {
1714
- this$1.index = targetIndex
1715
- this$1.updateRoute(location)
1716
- })
2083
+ var route = this.stack[targetIndex];
2084
+ this.confirmTransition(route, function () {
2085
+ this$1.index = targetIndex;
2086
+ this$1.updateRoute(route);
2087
+ });
2088
+ };
2089
+
2090
+ AbstractHistory.prototype.getCurrentLocation = function getCurrentLocation () {
2091
+ var current = this.stack[this.stack.length - 1];
2092
+ return current ? current.fullPath : '/'
1717
2093
  };
1718
2094
 
1719
2095
  AbstractHistory.prototype.ensureURL = function ensureURL () {
@@ -1728,25 +2104,50 @@ var AbstractHistory = (function (History) {
1728
2104
  var VueRouter = function VueRouter (options) {
1729
2105
  if ( options === void 0 ) options = {};
1730
2106
 
1731
- this.app = null
1732
- this.options = options
1733
- this.beforeHooks = []
1734
- this.afterHooks = []
1735
- this.match = createMatcher(options.routes || [])
2107
+ this.app = null;
2108
+ this.apps = [];
2109
+ this.options = options;
2110
+ this.beforeHooks = [];
2111
+ this.afterHooks = [];
2112
+ this.matcher = createMatcher(options.routes || []);
1736
2113
 
1737
- var mode = options.mode || 'hash'
1738
- this.fallback = mode === 'history' && !supportsHistory
2114
+ var mode = options.mode || 'hash';
2115
+ this.fallback = mode === 'history' && !supportsPushState;
1739
2116
  if (this.fallback) {
1740
- mode = 'hash'
2117
+ mode = 'hash';
1741
2118
  }
1742
2119
  if (!inBrowser) {
1743
- mode = 'abstract'
2120
+ mode = 'abstract';
2121
+ }
2122
+ this.mode = mode;
2123
+
2124
+ switch (mode) {
2125
+ case 'history':
2126
+ this.history = new HTML5History(this, options.base);
2127
+ break
2128
+ case 'hash':
2129
+ this.history = new HashHistory(this, options.base, this.fallback);
2130
+ break
2131
+ case 'abstract':
2132
+ this.history = new AbstractHistory(this, options.base);
2133
+ break
2134
+ default:
2135
+ {
2136
+ assert(false, ("invalid mode: " + mode));
2137
+ }
1744
2138
  }
1745
- this.mode = mode
1746
2139
  };
1747
2140
 
1748
2141
  var prototypeAccessors = { currentRoute: {} };
1749
2142
 
2143
+ VueRouter.prototype.match = function match (
2144
+ raw,
2145
+ current,
2146
+ redirectedFrom
2147
+ ) {
2148
+ return this.matcher.match(raw, current, redirectedFrom)
2149
+ };
2150
+
1750
2151
  prototypeAccessors.currentRoute.get = function () {
1751
2152
  return this.history && this.history.current
1752
2153
  };
@@ -1754,82 +2155,128 @@ prototypeAccessors.currentRoute.get = function () {
1754
2155
  VueRouter.prototype.init = function init (app /* Vue component instance */) {
1755
2156
  var this$1 = this;
1756
2157
 
1757
- assert(
2158
+ "development" !== 'production' && assert(
1758
2159
  install.installed,
1759
2160
  "not installed. Make sure to call `Vue.use(VueRouter)` " +
1760
2161
  "before creating root instance."
1761
- )
2162
+ );
1762
2163
 
1763
- this.app = app
2164
+ this.apps.push(app);
1764
2165
 
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))
2166
+ // main app already initialized.
2167
+ if (this.app) {
2168
+ return
1781
2169
  }
1782
2170
 
1783
- this.history.listen(function (route) {
1784
- this$1.app._route = route
1785
- })
2171
+ this.app = app;
2172
+
2173
+ var history = this.history;
2174
+
2175
+ if (history instanceof HTML5History) {
2176
+ history.transitionTo(history.getCurrentLocation());
2177
+ } else if (history instanceof HashHistory) {
2178
+ var setupHashListener = function () {
2179
+ history.setupListeners();
2180
+ };
2181
+ history.transitionTo(
2182
+ history.getCurrentLocation(),
2183
+ setupHashListener,
2184
+ setupHashListener
2185
+ );
2186
+ }
2187
+
2188
+ history.listen(function (route) {
2189
+ this$1.apps.forEach(function (app) {
2190
+ app._route = route;
2191
+ });
2192
+ });
1786
2193
  };
1787
2194
 
1788
2195
  VueRouter.prototype.beforeEach = function beforeEach (fn) {
1789
- this.beforeHooks.push(fn)
2196
+ this.beforeHooks.push(fn);
1790
2197
  };
1791
2198
 
1792
2199
  VueRouter.prototype.afterEach = function afterEach (fn) {
1793
- this.afterHooks.push(fn)
2200
+ this.afterHooks.push(fn);
1794
2201
  };
1795
2202
 
1796
- VueRouter.prototype.push = function push (location) {
1797
- this.history.push(location)
2203
+ VueRouter.prototype.onReady = function onReady (cb) {
2204
+ this.history.onReady(cb);
1798
2205
  };
1799
2206
 
1800
- VueRouter.prototype.replace = function replace (location) {
1801
- this.history.replace(location)
2207
+ VueRouter.prototype.push = function push (location, onComplete, onAbort) {
2208
+ this.history.push(location, onComplete, onAbort);
2209
+ };
2210
+
2211
+ VueRouter.prototype.replace = function replace (location, onComplete, onAbort) {
2212
+ this.history.replace(location, onComplete, onAbort);
1802
2213
  };
1803
2214
 
1804
2215
  VueRouter.prototype.go = function go (n) {
1805
- this.history.go(n)
2216
+ this.history.go(n);
1806
2217
  };
1807
2218
 
1808
2219
  VueRouter.prototype.back = function back () {
1809
- this.go(-1)
2220
+ this.go(-1);
1810
2221
  };
1811
2222
 
1812
2223
  VueRouter.prototype.forward = function forward () {
1813
- this.go(1)
2224
+ this.go(1);
1814
2225
  };
1815
2226
 
1816
- VueRouter.prototype.getMatchedComponents = function getMatchedComponents () {
1817
- if (!this.currentRoute) {
2227
+ VueRouter.prototype.getMatchedComponents = function getMatchedComponents (to) {
2228
+ var route = to
2229
+ ? this.resolve(to).route
2230
+ : this.currentRoute;
2231
+ if (!route) {
1818
2232
  return []
1819
2233
  }
1820
- return [].concat.apply([], this.currentRoute.matched.map(function (m) {
2234
+ return [].concat.apply([], route.matched.map(function (m) {
1821
2235
  return Object.keys(m.components).map(function (key) {
1822
2236
  return m.components[key]
1823
2237
  })
1824
2238
  }))
1825
2239
  };
1826
2240
 
2241
+ VueRouter.prototype.resolve = function resolve (
2242
+ to,
2243
+ current,
2244
+ append
2245
+ ) {
2246
+ var location = normalizeLocation(to, current || this.history.current, append);
2247
+ var route = this.match(location, current);
2248
+ var fullPath = route.redirectedFrom || route.fullPath;
2249
+ var base = this.history.base;
2250
+ var href = createHref(base, fullPath, this.mode);
2251
+ return {
2252
+ location: location,
2253
+ route: route,
2254
+ href: href,
2255
+ // for backwards compat
2256
+ normalizedTo: location,
2257
+ resolved: route
2258
+ }
2259
+ };
2260
+
2261
+ VueRouter.prototype.addRoutes = function addRoutes (routes) {
2262
+ this.matcher.addRoutes(routes);
2263
+ if (this.history.current !== START) {
2264
+ this.history.transitionTo(this.history.getCurrentLocation());
2265
+ }
2266
+ };
2267
+
1827
2268
  Object.defineProperties( VueRouter.prototype, prototypeAccessors );
1828
2269
 
1829
- VueRouter.install = install
2270
+ function createHref (base, fullPath, mode) {
2271
+ var path = mode === 'hash' ? '#' + fullPath : fullPath;
2272
+ return base ? cleanPath(base + '/' + path) : path
2273
+ }
2274
+
2275
+ VueRouter.install = install;
2276
+ VueRouter.version = '2.2.1';
1830
2277
 
1831
2278
  if (inBrowser && window.Vue) {
1832
- window.Vue.use(VueRouter)
2279
+ window.Vue.use(VueRouter);
1833
2280
  }
1834
2281
 
1835
2282
  return VueRouter;