MIT License | |||||
Copyright (c) 2013-present Evan You | |||||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
of this software and associated documentation files (the "Software"), to deal | |||||
in the Software without restriction, including without limitation the rights | |||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
copies of the Software, and to permit persons to whom the Software is | |||||
furnished to do so, subject to the following conditions: | |||||
The above copyright notice and this permission notice shall be included in all | |||||
copies or substantial portions of the Software. | |||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
SOFTWARE. |
# vue-router [![Build Status](https://img.shields.io/circleci/project/github/vuejs/vue-router/dev.svg)](https://circleci.com/gh/vuejs/vue-router) | |||||
> This is vue-router 2.0 which works only with Vue 2.0. For the 1.x router see the [1.0 branch](https://github.com/vuejs/vue-router/tree/1.0). | |||||
### Introduction | |||||
`vue-router` is the official router for [Vue.js](http://vuejs.org). It deeply integrates with Vue.js core to make building Single Page Applications with Vue.js a breeze. Features include: | |||||
- Nested route/view mapping | |||||
- Modular, component-based router configuration | |||||
- Route params, query, wildcards | |||||
- View transition effects powered by Vue.js' transition system | |||||
- Fine-grained navigation control | |||||
- Links with automatic active CSS classes | |||||
- HTML5 history mode or hash mode, with auto-fallback in IE9 | |||||
- Customizable Scroll Behavior | |||||
Get started with the [documentation](http://vuejs.github.io/vue-router), or play with the [examples](https://github.com/vuejs/vue-router/tree/dev/examples) (see how to run them below). | |||||
### Development Setup | |||||
``` bash | |||||
# install deps | |||||
npm install | |||||
# build dist files | |||||
npm run build | |||||
# serve examples at localhost:8080 | |||||
npm run dev | |||||
# lint & run all tests | |||||
npm test | |||||
# serve docs at localhost:8080 | |||||
npm run docs | |||||
``` | |||||
## Questions | |||||
For questions and support please use the [Discord chat server](https://chat.vuejs.org) or [the official forum](http://forum.vuejs.org). The issue list of this repo is **exclusively** for bug reports and feature requests. | |||||
## Issues | |||||
Please make sure to read the [Issue Reporting Checklist](https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately. | |||||
## Contribution | |||||
Please make sure to read the [Contributing Guide](https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md) before making a pull request. | |||||
## Changelog | |||||
Details changes for each release are documented in the [release notes](https://github.com/vuejs/vue-router/releases). | |||||
## Stay In Touch | |||||
- For latest releases and announcements, follow on Twitter: [@vuejs](https://twitter.com/vuejs) | |||||
## License | |||||
[MIT](http://opensource.org/licenses/MIT) | |||||
Copyright (c) 2013-present Evan You | |||||
{ | |||||
"_from": "vue-router", | |||||
"_id": "vue-router@3.0.2", | |||||
"_inBundle": false, | |||||
"_integrity": "sha512-opKtsxjp9eOcFWdp6xLQPLmRGgfM932Tl56U9chYTnoWqKxQ8M20N7AkdEbM5beUh6wICoFGYugAX9vQjyJLFg==", | |||||
"_location": "/vue-router", | |||||
"_phantomChildren": {}, | |||||
"_requested": { | |||||
"type": "tag", | |||||
"registry": true, | |||||
"raw": "vue-router", | |||||
"name": "vue-router", | |||||
"escapedName": "vue-router", | |||||
"rawSpec": "", | |||||
"saveSpec": null, | |||||
"fetchSpec": "latest" | |||||
}, | |||||
"_requiredBy": [ | |||||
"#USER", | |||||
"/" | |||||
], | |||||
"_resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.2.tgz", | |||||
"_shasum": "dedc67afe6c4e2bc25682c8b1c2a8c0d7c7e56be", | |||||
"_spec": "vue-router", | |||||
"_where": "/Users/edwinab/BME-5/project/om", | |||||
"author": { | |||||
"name": "Evan You" | |||||
}, | |||||
"bugs": { | |||||
"url": "https://github.com/vuejs/vue-router/issues" | |||||
}, | |||||
"bundleDependencies": false, | |||||
"deprecated": false, | |||||
"description": "Official router for Vue.js 2", | |||||
"devDependencies": { | |||||
"babel-core": "^6.24.1", | |||||
"babel-eslint": "^8.2.2", | |||||
"babel-loader": "^7.1.3", | |||||
"babel-plugin-syntax-dynamic-import": "^6.18.0", | |||||
"babel-preset-env": "^1.6.1", | |||||
"babel-preset-flow-vue": "^1.0.0", | |||||
"buble": "^0.19.3", | |||||
"chromedriver": "^2.35.0", | |||||
"cross-spawn": "^5.0.1", | |||||
"css-loader": "^0.28.10", | |||||
"es6-promise": "^4.2.4", | |||||
"eslint": "^4.19.1", | |||||
"eslint-plugin-flowtype": "^2.46.1", | |||||
"eslint-plugin-vue-libs": "^2.1.0", | |||||
"express": "^4.16.2", | |||||
"express-urlrewrite": "^1.2.0", | |||||
"flow-bin": "^0.66.0", | |||||
"jasmine": "2.8.0", | |||||
"nightwatch": "^0.9.20", | |||||
"nightwatch-helpers": "^1.0.0", | |||||
"path-to-regexp": "^1.7.0", | |||||
"phantomjs-prebuilt": "^2.1.16", | |||||
"rollup": "^0.56.4", | |||||
"rollup-plugin-buble": "^0.19.2", | |||||
"rollup-plugin-commonjs": "^9.0.0", | |||||
"rollup-plugin-flow-no-whitespace": "^1.0.0", | |||||
"rollup-plugin-node-resolve": "^3.0.3", | |||||
"rollup-plugin-replace": "^2.0.0", | |||||
"rollup-watch": "^4.0.0", | |||||
"selenium-server": "^2.53.1", | |||||
"typescript": "^2.7.2", | |||||
"uglify-js": "^3.3.13", | |||||
"vue": "^2.5.16", | |||||
"vue-loader": "^15.2.1", | |||||
"vue-template-compiler": "^2.5.16", | |||||
"vuepress": "^0.14.1", | |||||
"vuepress-theme-vue": "^1.1.0", | |||||
"webpack": "^4.9.0", | |||||
"webpack-dev-middleware": "^3.1.3" | |||||
}, | |||||
"files": [ | |||||
"src/*.js", | |||||
"dist/*.js", | |||||
"types/*.d.ts" | |||||
], | |||||
"homepage": "https://github.com/vuejs/vue-router#readme", | |||||
"jsdelivr": "dist/vue-router.js", | |||||
"keywords": [ | |||||
"vue", | |||||
"router", | |||||
"routing" | |||||
], | |||||
"license": "MIT", | |||||
"main": "dist/vue-router.common.js", | |||||
"module": "dist/vue-router.esm.js", | |||||
"name": "vue-router", | |||||
"repository": { | |||||
"type": "git", | |||||
"url": "git+https://github.com/vuejs/vue-router.git" | |||||
}, | |||||
"scripts": { | |||||
"build": "node build/build.js", | |||||
"dev": "node examples/server.js", | |||||
"dev:dist": "rollup -wm -c build/rollup.dev.config.js", | |||||
"docs": "vuepress dev docs", | |||||
"docs:build": "vuepress build docs", | |||||
"flow": "flow check", | |||||
"lint": "eslint src examples", | |||||
"release": "bash build/release.sh", | |||||
"test": "npm run lint && npm run flow && npm run test:unit && npm run test:e2e && npm run test:types", | |||||
"test:e2e": "node test/e2e/runner.js", | |||||
"test:types": "tsc -p types/test", | |||||
"test:unit": "jasmine JASMINE_CONFIG_PATH=test/unit/jasmine.json" | |||||
}, | |||||
"sideEffects": false, | |||||
"typings": "types/index.d.ts", | |||||
"unpkg": "dist/vue-router.js", | |||||
"version": "3.0.2" | |||||
} |
/* @flow */ | |||||
import type VueRouter from './index' | |||||
import { resolvePath } from './util/path' | |||||
import { assert, warn } from './util/warn' | |||||
import { createRoute } from './util/route' | |||||
import { fillParams } from './util/params' | |||||
import { createRouteMap } from './create-route-map' | |||||
import { normalizeLocation } from './util/location' | |||||
export type Matcher = { | |||||
match: (raw: RawLocation, current?: Route, redirectedFrom?: Location) => Route; | |||||
addRoutes: (routes: Array<RouteConfig>) => void; | |||||
}; | |||||
export function createMatcher ( | |||||
routes: Array<RouteConfig>, | |||||
router: VueRouter | |||||
): Matcher { | |||||
const { pathList, pathMap, nameMap } = createRouteMap(routes) | |||||
function addRoutes (routes) { | |||||
createRouteMap(routes, pathList, pathMap, nameMap) | |||||
} | |||||
function match ( | |||||
raw: RawLocation, | |||||
currentRoute?: Route, | |||||
redirectedFrom?: Location | |||||
): Route { | |||||
const location = normalizeLocation(raw, currentRoute, false, router) | |||||
const { name } = location | |||||
if (name) { | |||||
const record = nameMap[name] | |||||
if (process.env.NODE_ENV !== 'production') { | |||||
warn(record, `Route with name '${name}' does not exist`) | |||||
} | |||||
if (!record) return _createRoute(null, location) | |||||
const paramNames = record.regex.keys | |||||
.filter(key => !key.optional) | |||||
.map(key => key.name) | |||||
if (typeof location.params !== 'object') { | |||||
location.params = {} | |||||
} | |||||
if (currentRoute && typeof currentRoute.params === 'object') { | |||||
for (const key in currentRoute.params) { | |||||
if (!(key in location.params) && paramNames.indexOf(key) > -1) { | |||||
location.params[key] = currentRoute.params[key] | |||||
} | |||||
} | |||||
} | |||||
if (record) { | |||||
location.path = fillParams(record.path, location.params, `named route "${name}"`) | |||||
return _createRoute(record, location, redirectedFrom) | |||||
} | |||||
} else if (location.path) { | |||||
location.params = {} | |||||
for (let i = 0; i < pathList.length; i++) { | |||||
const path = pathList[i] | |||||
const record = pathMap[path] | |||||
if (matchRoute(record.regex, location.path, location.params)) { | |||||
return _createRoute(record, location, redirectedFrom) | |||||
} | |||||
} | |||||
} | |||||
// no match | |||||
return _createRoute(null, location) | |||||
} | |||||
function redirect ( | |||||
record: RouteRecord, | |||||
location: Location | |||||
): Route { | |||||
const originalRedirect = record.redirect | |||||
let redirect = typeof originalRedirect === 'function' | |||||
? originalRedirect(createRoute(record, location, null, router)) | |||||
: originalRedirect | |||||
if (typeof redirect === 'string') { | |||||
redirect = { path: redirect } | |||||
} | |||||
if (!redirect || typeof redirect !== 'object') { | |||||
if (process.env.NODE_ENV !== 'production') { | |||||
warn( | |||||
false, `invalid redirect option: ${JSON.stringify(redirect)}` | |||||
) | |||||
} | |||||
return _createRoute(null, location) | |||||
} | |||||
const re: Object = redirect | |||||
const { name, path } = re | |||||
let { query, hash, params } = location | |||||
query = re.hasOwnProperty('query') ? re.query : query | |||||
hash = re.hasOwnProperty('hash') ? re.hash : hash | |||||
params = re.hasOwnProperty('params') ? re.params : params | |||||
if (name) { | |||||
// resolved named direct | |||||
const targetRecord = nameMap[name] | |||||
if (process.env.NODE_ENV !== 'production') { | |||||
assert(targetRecord, `redirect failed: named route "${name}" not found.`) | |||||
} | |||||
return match({ | |||||
_normalized: true, | |||||
name, | |||||
query, | |||||
hash, | |||||
params | |||||
}, undefined, location) | |||||
} else if (path) { | |||||
// 1. resolve relative redirect | |||||
const rawPath = resolveRecordPath(path, record) | |||||
// 2. resolve params | |||||
const resolvedPath = fillParams(rawPath, params, `redirect route with path "${rawPath}"`) | |||||
// 3. rematch with existing query and hash | |||||
return match({ | |||||
_normalized: true, | |||||
path: resolvedPath, | |||||
query, | |||||
hash | |||||
}, undefined, location) | |||||
} else { | |||||
if (process.env.NODE_ENV !== 'production') { | |||||
warn(false, `invalid redirect option: ${JSON.stringify(redirect)}`) | |||||
} | |||||
return _createRoute(null, location) | |||||
} | |||||
} | |||||
function alias ( | |||||
record: RouteRecord, | |||||
location: Location, | |||||
matchAs: string | |||||
): Route { | |||||
const aliasedPath = fillParams(matchAs, location.params, `aliased route with path "${matchAs}"`) | |||||
const aliasedMatch = match({ | |||||
_normalized: true, | |||||
path: aliasedPath | |||||
}) | |||||
if (aliasedMatch) { | |||||
const matched = aliasedMatch.matched | |||||
const aliasedRecord = matched[matched.length - 1] | |||||
location.params = aliasedMatch.params | |||||
return _createRoute(aliasedRecord, location) | |||||
} | |||||
return _createRoute(null, location) | |||||
} | |||||
function _createRoute ( | |||||
record: ?RouteRecord, | |||||
location: Location, | |||||
redirectedFrom?: Location | |||||
): Route { | |||||
if (record && record.redirect) { | |||||
return redirect(record, redirectedFrom || location) | |||||
} | |||||
if (record && record.matchAs) { | |||||
return alias(record, location, record.matchAs) | |||||
} | |||||
return createRoute(record, location, redirectedFrom, router) | |||||
} | |||||
return { | |||||
match, | |||||
addRoutes | |||||
} | |||||
} | |||||
function matchRoute ( | |||||
regex: RouteRegExp, | |||||
path: string, | |||||
params: Object | |||||
): boolean { | |||||
const m = path.match(regex) | |||||
if (!m) { | |||||
return false | |||||
} else if (!params) { | |||||
return true | |||||
} | |||||
for (let i = 1, len = m.length; i < len; ++i) { | |||||
const key = regex.keys[i - 1] | |||||
const val = typeof m[i] === 'string' ? decodeURIComponent(m[i]) : m[i] | |||||
if (key) { | |||||
// Fix #1994: using * with props: true generates a param named 0 | |||||
params[key.name || 'pathMatch'] = val | |||||
} | |||||
} | |||||
return true | |||||
} | |||||
function resolveRecordPath (path: string, record: RouteRecord): string { | |||||
return resolvePath(path, record.parent ? record.parent.path : '/', true) | |||||
} |
/* @flow */ | |||||
import Regexp from 'path-to-regexp' | |||||
import { cleanPath } from './util/path' | |||||
import { assert, warn } from './util/warn' | |||||
export function createRouteMap ( | |||||
routes: Array<RouteConfig>, | |||||
oldPathList?: Array<string>, | |||||
oldPathMap?: Dictionary<RouteRecord>, | |||||
oldNameMap?: Dictionary<RouteRecord> | |||||
): { | |||||
pathList: Array<string>; | |||||
pathMap: Dictionary<RouteRecord>; | |||||
nameMap: Dictionary<RouteRecord>; | |||||
} { | |||||
// the path list is used to control path matching priority | |||||
const pathList: Array<string> = oldPathList || [] | |||||
// $flow-disable-line | |||||
const pathMap: Dictionary<RouteRecord> = oldPathMap || Object.create(null) | |||||
// $flow-disable-line | |||||
const nameMap: Dictionary<RouteRecord> = oldNameMap || Object.create(null) | |||||
routes.forEach(route => { | |||||
addRouteRecord(pathList, pathMap, nameMap, route) | |||||
}) | |||||
// ensure wildcard routes are always at the end | |||||
for (let i = 0, l = pathList.length; i < l; i++) { | |||||
if (pathList[i] === '*') { | |||||
pathList.push(pathList.splice(i, 1)[0]) | |||||
l-- | |||||
i-- | |||||
} | |||||
} | |||||
return { | |||||
pathList, | |||||
pathMap, | |||||
nameMap | |||||
} | |||||
} | |||||
function addRouteRecord ( | |||||
pathList: Array<string>, | |||||
pathMap: Dictionary<RouteRecord>, | |||||
nameMap: Dictionary<RouteRecord>, | |||||
route: RouteConfig, | |||||
parent?: RouteRecord, | |||||
matchAs?: string | |||||
) { | |||||
const { path, name } = route | |||||
if (process.env.NODE_ENV !== 'production') { | |||||
assert(path != null, `"path" is required in a route configuration.`) | |||||
assert( | |||||
typeof route.component !== 'string', | |||||
`route config "component" for path: ${String(path || name)} cannot be a ` + | |||||
`string id. Use an actual component instead.` | |||||
) | |||||
} | |||||
const pathToRegexpOptions: PathToRegexpOptions = route.pathToRegexpOptions || {} | |||||
const normalizedPath = normalizePath( | |||||
path, | |||||
parent, | |||||
pathToRegexpOptions.strict | |||||
) | |||||
if (typeof route.caseSensitive === 'boolean') { | |||||
pathToRegexpOptions.sensitive = route.caseSensitive | |||||
} | |||||
const record: RouteRecord = { | |||||
path: normalizedPath, | |||||
regex: compileRouteRegex(normalizedPath, pathToRegexpOptions), | |||||
components: route.components || { default: route.component }, | |||||
instances: {}, | |||||
name, | |||||
parent, | |||||
matchAs, | |||||
redirect: route.redirect, | |||||
beforeEnter: route.beforeEnter, | |||||
meta: route.meta || {}, | |||||
props: route.props == null | |||||
? {} | |||||
: route.components | |||||
? route.props | |||||
: { default: route.props } | |||||
} | |||||
if (route.children) { | |||||
// Warn if route is named, does not redirect and has a default child route. | |||||
// If users navigate to this route by name, the default child will | |||||
// not be rendered (GH Issue #629) | |||||
if (process.env.NODE_ENV !== 'production') { | |||||
if (route.name && !route.redirect && route.children.some(child => /^\/?$/.test(child.path))) { | |||||
warn( | |||||
false, | |||||
`Named Route '${route.name}' has a default child route. ` + | |||||
`When navigating to this named route (:to="{name: '${route.name}'"), ` + | |||||
`the default child route will not be rendered. Remove the name from ` + | |||||
`this route and use the name of the default child route for named ` + | |||||
`links instead.` | |||||
) | |||||
} | |||||
} | |||||
route.children.forEach(child => { | |||||
const childMatchAs = matchAs | |||||
? cleanPath(`${matchAs}/${child.path}`) | |||||
: undefined | |||||
addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs) | |||||
}) | |||||
} | |||||
if (route.alias !== undefined) { | |||||
const aliases = Array.isArray(route.alias) | |||||
? route.alias | |||||
: [route.alias] | |||||
aliases.forEach(alias => { | |||||
const aliasRoute = { | |||||
path: alias, | |||||
children: route.children | |||||
} | |||||
addRouteRecord( | |||||
pathList, | |||||
pathMap, | |||||
nameMap, | |||||
aliasRoute, | |||||
parent, | |||||
record.path || '/' // matchAs | |||||
) | |||||
}) | |||||
} | |||||
if (!pathMap[record.path]) { | |||||
pathList.push(record.path) | |||||
pathMap[record.path] = record | |||||
} | |||||
if (name) { | |||||
if (!nameMap[name]) { | |||||
nameMap[name] = record | |||||
} else if (process.env.NODE_ENV !== 'production' && !matchAs) { | |||||
warn( | |||||
false, | |||||
`Duplicate named routes definition: ` + | |||||
`{ name: "${name}", path: "${record.path}" }` | |||||
) | |||||
} | |||||
} | |||||
} | |||||
function compileRouteRegex (path: string, pathToRegexpOptions: PathToRegexpOptions): RouteRegExp { | |||||
const regex = Regexp(path, [], pathToRegexpOptions) | |||||
if (process.env.NODE_ENV !== 'production') { | |||||
const keys: any = Object.create(null) | |||||
regex.keys.forEach(key => { | |||||
warn(!keys[key.name], `Duplicate param keys in route with path: "${path}"`) | |||||
keys[key.name] = true | |||||
}) | |||||
} | |||||
return regex | |||||
} | |||||
function normalizePath (path: string, parent?: RouteRecord, strict?: boolean): string { | |||||
if (!strict) path = path.replace(/\/$/, '') | |||||
if (path[0] === '/') return path | |||||
if (parent == null) return path | |||||
return cleanPath(`${parent.path}/${path}`) | |||||
} |
/* @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 { HashHistory } from './history/hash' | |||||
import { HTML5History } from './history/html5' | |||||
import { AbstractHistory } from './history/abstract' | |||||
import type { Matcher } from './create-matcher' | |||||
export default class VueRouter { | |||||
static install: () => void; | |||||
static version: string; | |||||
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) | |||||
// main app already initialized. | |||||
if (this.app) { | |||||
return | |||||
} | |||||
this.app = app | |||||
const history = this.history | |||||
if (history instanceof HTML5History) { | |||||
history.transitionTo(history.getCurrentLocation()) | |||||
} else if (history instanceof HashHistory) { | |||||
const setupHashListener = () => { | |||||
history.setupListeners() | |||||
} | |||||
history.transitionTo( | |||||
history.getCurrentLocation(), | |||||
setupHashListener, | |||||
setupHashListener | |||||
) | |||||
} | |||||
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) { | |||||
this.history.push(location, onComplete, onAbort) | |||||
} | |||||
replace (location: RawLocation, onComplete?: Function, onAbort?: Function) { | |||||
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 | |||||
} { | |||||
const location = normalizeLocation( | |||||
to, | |||||
current || this.history.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__' | |||||
if (inBrowser && window.Vue) { | |||||
window.Vue.use(VueRouter) | |||||
} |
import View from './components/view' | |||||
import Link from './components/link' | |||||
export let _Vue | |||||
export function install (Vue) { | |||||
if (install.installed && _Vue === Vue) return | |||||
install.installed = true | |||||
_Vue = Vue | |||||
const isDef = v => v !== undefined | |||||
const registerInstance = (vm, callVal) => { | |||||
let i = vm.$options._parentVnode | |||||
if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) { | |||||
i(vm, callVal) | |||||
} | |||||
} | |||||
Vue.mixin({ | |||||
beforeCreate () { | |||||
if (isDef(this.$options.router)) { | |||||
this._routerRoot = this | |||||
this._router = this.$options.router | |||||
this._router.init(this) | |||||
Vue.util.defineReactive(this, '_route', this._router.history.current) | |||||
} else { | |||||
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this | |||||
} | |||||
registerInstance(this, this) | |||||
}, | |||||
destroyed () { | |||||
registerInstance(this) | |||||
} | |||||
}) | |||||
Object.defineProperty(Vue.prototype, '$router', { | |||||
get () { return this._routerRoot._router } | |||||
}) | |||||
Object.defineProperty(Vue.prototype, '$route', { | |||||
get () { return this._routerRoot._route } | |||||
}) | |||||
Vue.component('RouterView', View) | |||||
Vue.component('RouterLink', Link) | |||||
const strats = Vue.config.optionMergeStrategies | |||||
// use the same hook merging strategy for route hooks | |||||
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created | |||||
} |
import "./vue"; | |||||
import { VueRouter } from "./router"; | |||||
export default VueRouter; | |||||
export { | |||||
RouterMode, | |||||
RawLocation, | |||||
RedirectOption, | |||||
RouterOptions, | |||||
RouteConfig, | |||||
RouteRecord, | |||||
Location, | |||||
Route, | |||||
NavigationGuard | |||||
} from "./router"; |
import Vue, { ComponentOptions, PluginFunction, AsyncComponent } from "vue"; | |||||
type Component = ComponentOptions<Vue> | typeof Vue | AsyncComponent; | |||||
type Dictionary<T> = { [key: string]: T }; | |||||
type ErrorHandler = (err: Error) => void; | |||||
export type RouterMode = "hash" | "history" | "abstract"; | |||||
export type RawLocation = string | Location; | |||||
export type RedirectOption = RawLocation | ((to: Route) => RawLocation); | |||||
export type NavigationGuard<V extends Vue = Vue> = ( | |||||
to: Route, | |||||
from: Route, | |||||
next: (to?: RawLocation | false | ((vm: V) => any) | void) => void | |||||
) => any | |||||
export declare class VueRouter { | |||||
constructor (options?: RouterOptions); | |||||
app: Vue; | |||||
mode: RouterMode; | |||||
currentRoute: Route; | |||||
beforeEach (guard: NavigationGuard): Function; | |||||
beforeResolve (guard: NavigationGuard): Function; | |||||
afterEach (hook: (to: Route, from: Route) => any): Function; | |||||
push (location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void; | |||||
replace (location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void; | |||||
go (n: number): void; | |||||
back (): void; | |||||
forward (): void; | |||||
getMatchedComponents (to?: RawLocation | Route): Component[]; | |||||
onReady (cb: Function, errorCb?: ErrorHandler): void; | |||||
onError (cb: ErrorHandler): void; | |||||
addRoutes (routes: RouteConfig[]): void; | |||||
resolve (to: RawLocation, current?: Route, append?: boolean): { | |||||
location: Location; | |||||
route: Route; | |||||
href: string; | |||||
// backwards compat | |||||
normalizedTo: Location; | |||||
resolved: Route; | |||||
}; | |||||
static install: PluginFunction<never>; | |||||
} | |||||
type Position = { x: number, y: number }; | |||||
type PositionResult = Position | { selector: string, offset?: Position } | void; | |||||
export interface RouterOptions { | |||||
routes?: RouteConfig[]; | |||||
mode?: RouterMode; | |||||
fallback?: boolean; | |||||
base?: string; | |||||
linkActiveClass?: string; | |||||
linkExactActiveClass?: string; | |||||
parseQuery?: (query: string) => Object; | |||||
stringifyQuery?: (query: Object) => string; | |||||
scrollBehavior?: ( | |||||
to: Route, | |||||
from: Route, | |||||
savedPosition: Position | void | |||||
) => PositionResult | Promise<PositionResult>; | |||||
} | |||||
type RoutePropsFunction = (route: Route) => Object; | |||||
export interface PathToRegexpOptions { | |||||
sensitive?: boolean; | |||||
strict?: boolean; | |||||
end?: boolean; | |||||
} | |||||
export interface RouteConfig { | |||||
path: string; | |||||
name?: string; | |||||
component?: Component; | |||||
components?: Dictionary<Component>; | |||||
redirect?: RedirectOption; | |||||
alias?: string | string[]; | |||||
children?: RouteConfig[]; | |||||
meta?: any; | |||||
beforeEnter?: NavigationGuard; | |||||
props?: boolean | Object | RoutePropsFunction; | |||||
caseSensitive?: boolean; | |||||
pathToRegexpOptions?: PathToRegexpOptions; | |||||
} | |||||
export interface RouteRecord { | |||||
path: string; | |||||
regex: RegExp; | |||||
components: Dictionary<Component>; | |||||
instances: Dictionary<Vue>; | |||||
name?: string; | |||||
parent?: RouteRecord; | |||||
redirect?: RedirectOption; | |||||
matchAs?: string; | |||||
meta: any; | |||||
beforeEnter?: ( | |||||
route: Route, | |||||
redirect: (location: RawLocation) => void, | |||||
next: () => void | |||||
) => any; | |||||
props: boolean | Object | RoutePropsFunction | Dictionary<boolean | Object | RoutePropsFunction>; | |||||
} | |||||
export interface Location { | |||||
name?: string; | |||||
path?: string; | |||||
hash?: string; | |||||
query?: Dictionary<string | string[]>; | |||||
params?: Dictionary<string>; | |||||
append?: boolean; | |||||
replace?: boolean; | |||||
} | |||||
export interface Route { | |||||
path: string; | |||||
name?: string; | |||||
hash: string; | |||||
query: Dictionary<string | string[]>; | |||||
params: Dictionary<string>; | |||||
fullPath: string; | |||||
matched: RouteRecord[]; | |||||
redirectedFrom?: string; | |||||
meta?: any; | |||||
} |
/** | |||||
* Augment the typings of Vue.js | |||||
*/ | |||||
import Vue from "vue"; | |||||
import VueRouter, { Route, RawLocation, NavigationGuard } from "./index"; | |||||
declare module "vue/types/vue" { | |||||
interface Vue { | |||||
$router: VueRouter; | |||||
$route: Route; | |||||
} | |||||
} | |||||
declare module "vue/types/options" { | |||||
interface ComponentOptions<V extends Vue> { | |||||
router?: VueRouter; | |||||
beforeRouteEnter?: NavigationGuard<V>; | |||||
beforeRouteLeave?: NavigationGuard<V>; | |||||
beforeRouteUpdate?: NavigationGuard<V>; | |||||
} | |||||
} |
"resolved": "https://registry.npmjs.org/vue/-/vue-2.5.17.tgz", | "resolved": "https://registry.npmjs.org/vue/-/vue-2.5.17.tgz", | ||||
"integrity": "sha512-mFbcWoDIJi0w0Za4emyLiW72Jae0yjANHbCVquMKijcavBGypqlF7zHRgMa5k4sesdv7hv2rB4JPdZfR+TPfhQ==" | "integrity": "sha512-mFbcWoDIJi0w0Za4emyLiW72Jae0yjANHbCVquMKijcavBGypqlF7zHRgMa5k4sesdv7hv2rB4JPdZfR+TPfhQ==" | ||||
}, | }, | ||||
"vue-router": { | |||||
"version": "3.0.2", | |||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.2.tgz", | |||||
"integrity": "sha512-opKtsxjp9eOcFWdp6xLQPLmRGgfM932Tl56U9chYTnoWqKxQ8M20N7AkdEbM5beUh6wICoFGYugAX9vQjyJLFg==" | |||||
}, | |||||
"which": { | "which": { | ||||
"version": "1.3.1", | "version": "1.3.1", | ||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", |
"express": "^4.16.4", | "express": "^4.16.4", | ||||
"express-session": "^1.15.6", | "express-session": "^1.15.6", | ||||
"morgan": "^1.9.1", | "morgan": "^1.9.1", | ||||
"vue": "^2.5.17" | |||||
"vue": "^2.5.17", | |||||
"vue-router": "^3.0.2" | |||||
} | } | ||||
} | } |
Vue.component('Files', { | |||||
data: function() { | |||||
return { | |||||
count: 0 | |||||
} | |||||
}, | |||||
template: `<button v-on:click="count++"> You clicked me {{ count }} times. </button>` | |||||
}) |
Vue.component('msg-item', { | |||||
template: `<div class="om-card card"> | |||||
const ('Home', { | |||||
template: ` <div id="message-list" v-for="(msg, index) in messages" :key="msg.id" :subject="msg.subject" :message="msg.message" :tag="msg.tag" :user="msg.user"> | |||||
<div class="om-card card"> | |||||
<h6 class="msg-head"> | <h6 class="msg-head"> | ||||
<b>{{ subject }}</b> | <b>{{ subject }}</b> | ||||
<img src="favicon.ico" width=20px height=20px> | <img src="favicon.ico" width=20px height=20px> | ||||
<div class="om-user-line"> | <div class="om-user-line"> | ||||
<i class="material-icons">account_circle</i> | <i class="material-icons">account_circle</i> | ||||
Erstellt von {{ user }} | Erstellt von {{ user }} | ||||
</div>`, | |||||
</div></div>`, | |||||
props: ['subject', 'message', 'tag', 'user'] | props: ['subject', 'message', 'tag', 'user'] | ||||
}) | }) | ||||
<link rel="stylesheet" href="https://unpkg.com/bootstrap-material-design@4.1.1/dist/css/bootstrap-material-design.min.css" integrity="sha384-wXznGJNEXNG1NFsbm0ugrLFMQPWswR3lds2VeinahP8N0zJw9VWSopbjv2x7WCvX" crossorigin="anonymous"> | <link rel="stylesheet" href="https://unpkg.com/bootstrap-material-design@4.1.1/dist/css/bootstrap-material-design.min.css" integrity="sha384-wXznGJNEXNG1NFsbm0ugrLFMQPWswR3lds2VeinahP8N0zJw9VWSopbjv2x7WCvX" crossorigin="anonymous"> | ||||
<!-- NOTE: VUE.js und VueRouter --> | <!-- NOTE: VUE.js und VueRouter --> | ||||
<script src="https://unpkg.com/vue"></script> | |||||
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> | |||||
<script src=lib/vue.js></script> | |||||
<script src=lib/vue-router.js></script> | |||||
<script src=lib/jquery-3.3.1.min.js></script> | |||||
<!-- CSS_Custom Design --> | <!-- CSS_Custom Design --> | ||||
<link rel="stylesheet" type="text/css" href="style.css"> | <link rel="stylesheet" type="text/css" href="style.css"> | ||||
</head> | </head> | ||||
<body> | <body> | ||||
<div id="app"> | |||||
<div class="om-header-container"> | <div class="om-header-container"> | ||||
<div class="om-header"> | <div class="om-header"> | ||||
<a href="index.html"><img src="th_nbg_ohmicon_amp.png" width=55px height=55px></a> | <a href="index.html"><img src="th_nbg_ohmicon_amp.png" width=55px height=55px></a> | ||||
</div> | </div> | ||||
<div class="om-content"> | |||||
<router-view class="om-content"> | |||||
<Home></Home> | |||||
<!-- | |||||
<div id="message-list"> | <div id="message-list"> | ||||
<msg-item | |||||
<Home | |||||
v-for="(msg, index) in messages" | v-for="(msg, index) in messages" | ||||
:key="msg.id" | :key="msg.id" | ||||
:subject="msg.subject" | :subject="msg.subject" | ||||
:message="msg.message" | :message="msg.message" | ||||
:tag="msg.tag" | :tag="msg.tag" | ||||
:user="msg.user" | :user="msg.user" | ||||
></msg-item> | |||||
></Home> | |||||
</div> | </div> | ||||
</div> | |||||
--> | |||||
</router-view> | |||||
<nav class="nav nav-tabs nav-justified om-nav "> | |||||
<router-link to="/home" class="nav-item nav-link"><i class="material-icons">home</i></router-link> | |||||
<router-link to="/files" class="nav-item nav-link"><i class="material-icons">folder</i></router-link> | |||||
<router-link to="/createMessage" class="nav-item nav-link outlined"><i class="material-icons">add_circle</i></router-link> | |||||
<router-link to="/bookmark" class="nav-item nav-link"><i class="material-icons">bookmark</i></router-link> | |||||
<router-link to="/profil" class="nav-item nav-link"><i class="material-icons">person</i></router-link> | |||||
</nav> | |||||
<!--first try of vue.js data-binding | |||||
<div class="om-content"> | |||||
<div id="sample"> | |||||
<div class="om-card card" v-for="msgs in private.messages"> | |||||
<div v-for="elements in msgs.message"> | |||||
<h6 class="msg-head"> | |||||
<b>{{elements.subject}}</b> | |||||
<img src="favicon.ico" width=20px height=20px> | |||||
</h6> | |||||
<p>{{elements.msg}} | |||||
<a href="#">{{elements.tags}}</a></p> | |||||
{{elements.user}} | |||||
</div> | |||||
<div class="om-user-line"> | |||||
<i class="material-icons">account_circle</i> | |||||
Erstellt von | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | </div> | ||||
--> | |||||
<!--HTML Mockup | |||||
<div class="om-card card"> | |||||
<h6 class="msg-head"> | |||||
<b>Betreff</b> | |||||
<img src="favicon.ico" width=20px height=20px> | |||||
</h6> | |||||
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam.<br> | |||||
<a href="#">#efi</a> <a href="#">#me</a> <a href="#">#projekt</a></p> | |||||
<div class="om-user-line"> | |||||
<i class="material-icons">account_circle</i> | |||||
Erstellt von User1 | |||||
</div> | |||||
</div> | |||||
<div class="om-card card"> | |||||
<h6 class="msg-head"> | |||||
<b>Betreff</b> | |||||
<img src="favicon.ico" width=20px height=20px> | |||||
</h6> | |||||
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam.<br> | |||||
<a href="#">#efi</a> <a href="#">#me</a> <a href="#">#projekt</a></p> | |||||
<div class="om-user-line"> | |||||
<i class="material-icons">account_circle</i> | |||||
Erstellt von User1 | |||||
</div> | |||||
</div> | |||||
<div class="om-card card"> | |||||
<h6 class="msg-head"> | |||||
<b>Betreff</b> | |||||
<img src="favicon.ico" width=20px height=20px> | |||||
</h6> | |||||
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam.<br> | |||||
<a href="#">#efi</a> <a href="#">#me</a> <a href="#">#projekt</a></p> | |||||
<div class="om-user-line"> | |||||
<i class="material-icons">account_circle</i> | |||||
Erstellt von User1 | |||||
</div> | |||||
</div> | |||||
<div class="om-card card"> | |||||
<h6 class="msg-head"> | |||||
<b>Betreff</b> | |||||
<img src="favicon.ico" width=20px height=20px> | |||||
</h6> | |||||
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam.<br> | |||||
<a href="#">#efi</a> <a href="#">#me</a> <a href="#">#projekt</a></p> | |||||
<div class="om-user-line"> | |||||
<i class="material-icons">account_circle</i> | |||||
Erstellt von User1 | |||||
</div> | |||||
</div> | |||||
<div class="om-card card"> | |||||
<h6 class="msg-head"> | |||||
<b>Betreff</b> | |||||
<img src="favicon.ico" width=20px height=20px> | |||||
</h6> | |||||
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam.<br> | |||||
<a href="#">#efi</a> <a href="#">#me</a> <a href="#">#projekt</a></p> | |||||
<div class="om-user-line"> | |||||
<i class="material-icons">account_circle</i> | |||||
Erstellt von User1 | |||||
</div> | |||||
</div> | |||||
</div> | |||||
--> | |||||
<nav class="nav nav-tabs nav-justified om-nav "> | |||||
<a class="nav-item nav-link" href="#"><i class="material-icons">home</i></a> | |||||
<a class="nav-item nav-link" href="#"><i class="material-icons">folder</i></a> | |||||
<a class="nav-item nav-link outlined" href="message.html"><i class="material-icons">add_circle</i></a> | |||||
<a class="nav-item nav-link" href="#"><i class="material-icons">bookmark</i></a> | |||||
<a class="nav-item nav-link" href="#"><i class="material-icons">person</i></a> | |||||
</nav> | |||||
<script> | |||||
const routes = [ | |||||
{ path: "/home", component: Home }, | |||||
{ path: "/files", component: Files }, | |||||
{ path: "/createMessage", component: CreateMsg }, | |||||
{ path: "/bookmark", component: Bookmark }, | |||||
{ path: "/profil", component: Profil }, | |||||
]; | |||||
const router = new VueRouter({ | |||||
routes | |||||
}); | |||||
var app = new Vue({ | |||||
router, | |||||
el: '#app' | |||||
}); | |||||
</script> | |||||
<!-- NOTE: JavaScript Libs & Files --> | <!-- NOTE: JavaScript Libs & Files --> | ||||
<!-- NOTE: Call home.js --> | |||||
<!-- NOTE: Call Vue Components --> | |||||
<script src="home.js"></script> | <script src="home.js"></script> | ||||
<!-- <script src="files.js"></script> --> | |||||
<script src="createMessage.js"></script> | |||||
<script src="bookmark.js"></script> | |||||
<script src="profil.js"></script> | |||||
<!-- CDN_Vue.js developmement lib --> | <!-- CDN_Vue.js developmement lib --> | ||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script> | <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script> | ||||
<!-- CDN_Vue.js minified lib --> | <!-- CDN_Vue.js minified lib --> |