vue-rails 2.0.1 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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;