| /* @flow */ | 
|   | 
| import { install } from './install' | 
| import { START } from './util/route' | 
| import { assert } from './util/warn' | 
| import { inBrowser } from './util/dom' | 
| import { cleanPath } from './util/path' | 
| import { createMatcher } from './create-matcher' | 
| import { normalizeLocation } from './util/location' | 
| import { supportsPushState } from './util/push-state' | 
| import { handleScroll } from './util/scroll' | 
|   | 
| import { HashHistory } from './history/hash' | 
| import { HTML5History } from './history/html5' | 
| import { AbstractHistory } from './history/abstract' | 
|   | 
| import type { Matcher } from './create-matcher' | 
|   | 
| import { isNavigationFailure, NavigationFailureType } from './util/errors' | 
|   | 
| export default class VueRouter { | 
|   static install: () => void | 
|   static version: string | 
|   static isNavigationFailure: Function | 
|   static NavigationFailureType: any | 
|   | 
|   app: any | 
|   apps: Array<any> | 
|   ready: boolean | 
|   readyCbs: Array<Function> | 
|   options: RouterOptions | 
|   mode: string | 
|   history: HashHistory | HTML5History | AbstractHistory | 
|   matcher: Matcher | 
|   fallback: boolean | 
|   beforeHooks: Array<?NavigationGuard> | 
|   resolveHooks: Array<?NavigationGuard> | 
|   afterHooks: Array<?AfterNavigationHook> | 
|   | 
|   constructor (options: RouterOptions = {}) { | 
|     this.app = null | 
|     this.apps = [] | 
|     this.options = options | 
|     this.beforeHooks = [] | 
|     this.resolveHooks = [] | 
|     this.afterHooks = [] | 
|     this.matcher = createMatcher(options.routes || [], this) | 
|   | 
|     let mode = options.mode || 'hash' | 
|     this.fallback = | 
|       mode === 'history' && !supportsPushState && options.fallback !== false | 
|     if (this.fallback) { | 
|       mode = 'hash' | 
|     } | 
|     if (!inBrowser) { | 
|       mode = 'abstract' | 
|     } | 
|     this.mode = mode | 
|   | 
|     switch (mode) { | 
|       case 'history': | 
|         this.history = new HTML5History(this, options.base) | 
|         break | 
|       case 'hash': | 
|         this.history = new HashHistory(this, options.base, this.fallback) | 
|         break | 
|       case 'abstract': | 
|         this.history = new AbstractHistory(this, options.base) | 
|         break | 
|       default: | 
|         if (process.env.NODE_ENV !== 'production') { | 
|           assert(false, `invalid mode: ${mode}`) | 
|         } | 
|     } | 
|   } | 
|   | 
|   match (raw: RawLocation, current?: Route, redirectedFrom?: Location): Route { | 
|     return this.matcher.match(raw, current, redirectedFrom) | 
|   } | 
|   | 
|   get currentRoute (): ?Route { | 
|     return this.history && this.history.current | 
|   } | 
|   | 
|   init (app: any /* Vue component instance */) { | 
|     process.env.NODE_ENV !== 'production' && | 
|       assert( | 
|         install.installed, | 
|         `not installed. Make sure to call \`Vue.use(VueRouter)\` ` + | 
|           `before creating root instance.` | 
|       ) | 
|   | 
|     this.apps.push(app) | 
|   | 
|     // set up app destroyed handler | 
|     // https://github.com/vuejs/vue-router/issues/2639 | 
|     app.$once('hook:destroyed', () => { | 
|       // clean out app from this.apps array once destroyed | 
|       const index = this.apps.indexOf(app) | 
|       if (index > -1) this.apps.splice(index, 1) | 
|       // ensure we still have a main app or null if no apps | 
|       // we do not release the router so it can be reused | 
|       if (this.app === app) this.app = this.apps[0] || null | 
|   | 
|       if (!this.app) this.history.teardown() | 
|     }) | 
|   | 
|     // main app previously initialized | 
|     // return as we don't need to set up new history listener | 
|     if (this.app) { | 
|       return | 
|     } | 
|   | 
|     this.app = app | 
|   | 
|     const history = this.history | 
|   | 
|     if (history instanceof HTML5History || history instanceof HashHistory) { | 
|       const handleInitialScroll = routeOrError => { | 
|         const from = history.current | 
|         const expectScroll = this.options.scrollBehavior | 
|         const supportsScroll = supportsPushState && expectScroll | 
|   | 
|         if (supportsScroll && 'fullPath' in routeOrError) { | 
|           handleScroll(this, routeOrError, from, false) | 
|         } | 
|       } | 
|       const setupListeners = routeOrError => { | 
|         history.setupListeners() | 
|         handleInitialScroll(routeOrError) | 
|       } | 
|       history.transitionTo( | 
|         history.getCurrentLocation(), | 
|         setupListeners, | 
|         setupListeners | 
|       ) | 
|     } | 
|   | 
|     history.listen(route => { | 
|       this.apps.forEach(app => { | 
|         app._route = route | 
|       }) | 
|     }) | 
|   } | 
|   | 
|   beforeEach (fn: Function): Function { | 
|     return registerHook(this.beforeHooks, fn) | 
|   } | 
|   | 
|   beforeResolve (fn: Function): Function { | 
|     return registerHook(this.resolveHooks, fn) | 
|   } | 
|   | 
|   afterEach (fn: Function): Function { | 
|     return registerHook(this.afterHooks, fn) | 
|   } | 
|   | 
|   onReady (cb: Function, errorCb?: Function) { | 
|     this.history.onReady(cb, errorCb) | 
|   } | 
|   | 
|   onError (errorCb: Function) { | 
|     this.history.onError(errorCb) | 
|   } | 
|   | 
|   push (location: RawLocation, onComplete?: Function, onAbort?: Function) { | 
|     // $flow-disable-line | 
|     if (!onComplete && !onAbort && typeof Promise !== 'undefined') { | 
|       return new Promise((resolve, reject) => { | 
|         this.history.push(location, resolve, reject) | 
|       }) | 
|     } else { | 
|       this.history.push(location, onComplete, onAbort) | 
|     } | 
|   } | 
|   | 
|   replace (location: RawLocation, onComplete?: Function, onAbort?: Function) { | 
|     // $flow-disable-line | 
|     if (!onComplete && !onAbort && typeof Promise !== 'undefined') { | 
|       return new Promise((resolve, reject) => { | 
|         this.history.replace(location, resolve, reject) | 
|       }) | 
|     } else { | 
|       this.history.replace(location, onComplete, onAbort) | 
|     } | 
|   } | 
|   | 
|   go (n: number) { | 
|     this.history.go(n) | 
|   } | 
|   | 
|   back () { | 
|     this.go(-1) | 
|   } | 
|   | 
|   forward () { | 
|     this.go(1) | 
|   } | 
|   | 
|   getMatchedComponents (to?: RawLocation | Route): Array<any> { | 
|     const route: any = to | 
|       ? to.matched | 
|         ? to | 
|         : this.resolve(to).route | 
|       : this.currentRoute | 
|     if (!route) { | 
|       return [] | 
|     } | 
|     return [].concat.apply( | 
|       [], | 
|       route.matched.map(m => { | 
|         return Object.keys(m.components).map(key => { | 
|           return m.components[key] | 
|         }) | 
|       }) | 
|     ) | 
|   } | 
|   | 
|   resolve ( | 
|     to: RawLocation, | 
|     current?: Route, | 
|     append?: boolean | 
|   ): { | 
|     location: Location, | 
|     route: Route, | 
|     href: string, | 
|     // for backwards compat | 
|     normalizedTo: Location, | 
|     resolved: Route | 
|   } { | 
|     current = current || this.history.current | 
|     const location = normalizeLocation(to, current, append, this) | 
|     const route = this.match(location, current) | 
|     const fullPath = route.redirectedFrom || route.fullPath | 
|     const base = this.history.base | 
|     const href = createHref(base, fullPath, this.mode) | 
|     return { | 
|       location, | 
|       route, | 
|       href, | 
|       // for backwards compat | 
|       normalizedTo: location, | 
|       resolved: route | 
|     } | 
|   } | 
|   | 
|   addRoutes (routes: Array<RouteConfig>) { | 
|     this.matcher.addRoutes(routes) | 
|     if (this.history.current !== START) { | 
|       this.history.transitionTo(this.history.getCurrentLocation()) | 
|     } | 
|   } | 
| } | 
|   | 
| function registerHook (list: Array<any>, fn: Function): Function { | 
|   list.push(fn) | 
|   return () => { | 
|     const i = list.indexOf(fn) | 
|     if (i > -1) list.splice(i, 1) | 
|   } | 
| } | 
|   | 
| function createHref (base: string, fullPath: string, mode) { | 
|   var path = mode === 'hash' ? '#' + fullPath : fullPath | 
|   return base ? cleanPath(base + '/' + path) : path | 
| } | 
|   | 
| VueRouter.install = install | 
| VueRouter.version = '__VERSION__' | 
| VueRouter.isNavigationFailure = isNavigationFailure | 
| VueRouter.NavigationFailureType = NavigationFailureType | 
|   | 
| if (inBrowser && window.Vue) { | 
|   window.Vue.use(VueRouter) | 
| } |