vueonrails 0.1.0

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