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