vueonrails 0.1.0

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