Merge pull request #714 from ENOVACOM/relative-path
feat: allows relative path, fixed #590
This commit is contained in:
commit
bba44fb536
6 changed files with 155 additions and 3 deletions
|
|
@ -150,6 +150,46 @@ window.$docsify = {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## relativePath
|
||||||
|
|
||||||
|
- Type: `Boolean`
|
||||||
|
- Default: `false`
|
||||||
|
|
||||||
|
If **true** links are relative to the current context.
|
||||||
|
|
||||||
|
For example, the directory structure is as follows:
|
||||||
|
|
||||||
|
```text
|
||||||
|
.
|
||||||
|
└── docs
|
||||||
|
├── README.md
|
||||||
|
├── guide.md
|
||||||
|
└── zh-cn
|
||||||
|
├── README.md
|
||||||
|
├── guide.md
|
||||||
|
└── config
|
||||||
|
└── example.md
|
||||||
|
```
|
||||||
|
|
||||||
|
With relative path **enabled** and current URL `http://domain.com/zh-cn/README`, given links will resolve to:
|
||||||
|
|
||||||
|
```text
|
||||||
|
guide.md => http://domain.com/zh-cn/guide
|
||||||
|
config/example.md => http://domain.com/zh-cn/config/example
|
||||||
|
../README.md => http://domain.com/README
|
||||||
|
/README.md => http://domain.com/README
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
window.$docsify = {
|
||||||
|
// Relative path enabled
|
||||||
|
relativePath: true,
|
||||||
|
|
||||||
|
// Relative path disabled (default value)
|
||||||
|
relativePath: false
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## coverpage
|
## coverpage
|
||||||
|
|
||||||
- Type: `Boolean|String|String[]|Object`
|
- Type: `Boolean|String|String[]|Object`
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ export default function () {
|
||||||
formatUpdated: '',
|
formatUpdated: '',
|
||||||
externalLinkTarget: '_blank',
|
externalLinkTarget: '_blank',
|
||||||
routerMode: 'hash',
|
routerMode: 'hash',
|
||||||
noCompileLinks: []
|
noCompileLinks: [],
|
||||||
|
relativePath: false
|
||||||
},
|
},
|
||||||
window.$docsify
|
window.$docsify
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ import {
|
||||||
isAbsolutePath,
|
isAbsolutePath,
|
||||||
stringifyQuery,
|
stringifyQuery,
|
||||||
cleanPath,
|
cleanPath,
|
||||||
replaceSlug
|
replaceSlug,
|
||||||
|
resolvePath
|
||||||
} from '../util'
|
} from '../util'
|
||||||
import {noop, merge} from '../../util/core'
|
import {noop, merge} from '../../util/core'
|
||||||
|
|
||||||
|
|
@ -73,9 +74,13 @@ export class History {
|
||||||
if (local) {
|
if (local) {
|
||||||
const idIndex = currentRoute.indexOf('?')
|
const idIndex = currentRoute.indexOf('?')
|
||||||
path =
|
path =
|
||||||
(idIndex > 0 ? currentRoute.substr(0, idIndex) : currentRoute) + path
|
(idIndex > 0 ? currentRoute.substring(0, idIndex) : currentRoute) + path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.config.relativePath && path.indexOf('/') !== 0) {
|
||||||
|
const currentDir = currentRoute.substring(0, currentRoute.lastIndexOf('/') + 1)
|
||||||
|
return cleanPath(resolvePath(currentDir + path))
|
||||||
|
}
|
||||||
return cleanPath('/' + path)
|
return cleanPath('/' + path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,20 @@ export const cleanPath = cached(path => {
|
||||||
return path.replace(/^\/+/, '/').replace(/([^:])\/{2,}/g, '$1/')
|
return path.replace(/^\/+/, '/').replace(/([^:])\/{2,}/g, '$1/')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const resolvePath = cached(path => {
|
||||||
|
const segments = path.replace(/^\//, '').split('/')
|
||||||
|
let resolved = []
|
||||||
|
for (let i = 0, len = segments.length; i < len; i++) {
|
||||||
|
const segment = segments[i]
|
||||||
|
if (segment === '..') {
|
||||||
|
resolved.pop()
|
||||||
|
} else if (segment !== '.') {
|
||||||
|
resolved.push(segment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '/' + resolved.join('/')
|
||||||
|
})
|
||||||
|
|
||||||
export function getPath(...args) {
|
export function getPath(...args) {
|
||||||
return cleanPath(args.join('/'))
|
return cleanPath(args.join('/'))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
62
test/unit/base.js
Normal file
62
test/unit/base.js
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* eslint-env node, chai, mocha */
|
||||||
|
require = require('esm')(module/*, options*/)
|
||||||
|
const {expect} = require('chai')
|
||||||
|
const {History} = require('../../src/core/router/history/base')
|
||||||
|
|
||||||
|
class MockHistory extends History {
|
||||||
|
parse(path) {
|
||||||
|
return {path}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('router/history/base', function () {
|
||||||
|
describe('relativePath true', function () {
|
||||||
|
var history
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
history = new MockHistory({relativePath: true})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toURL', function () {
|
||||||
|
// WHEN
|
||||||
|
const url = history.toURL('guide.md', {}, '/zh-ch/')
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
expect(url).equal('/zh-ch/guide')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toURL with double dot', function () {
|
||||||
|
// WHEN
|
||||||
|
const url = history.toURL('../README.md', {}, '/zh-ch/')
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
expect(url).equal('/README')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toURL child path', function () {
|
||||||
|
// WHEN
|
||||||
|
const url = history.toURL('config/example.md', {}, '/zh-ch/')
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
expect(url).equal('/zh-ch/config/example')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toURL absolute path', function () {
|
||||||
|
// WHEN
|
||||||
|
const url = history.toURL('/README', {}, '/zh-ch/')
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
expect(url).equal('/README')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toURL without relative path', function () {
|
||||||
|
const history = new MockHistory({relativePath: false})
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
const url = history.toURL('README', {}, '/zh-ch/')
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
expect(url).equal('/README')
|
||||||
|
})
|
||||||
|
})
|
||||||
30
test/unit/util.js
Normal file
30
test/unit/util.js
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* eslint-env node, chai, mocha */
|
||||||
|
require = require('esm')(module/*, options*/)
|
||||||
|
const {expect} = require('chai')
|
||||||
|
const {resolvePath} = require('../../src/core/router/util')
|
||||||
|
|
||||||
|
describe('router/util', function () {
|
||||||
|
it('resolvePath', async function () {
|
||||||
|
// WHEN
|
||||||
|
const result = resolvePath('hello.md')
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
expect(result).equal('/hello.md')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('resolvePath with dot', async function () {
|
||||||
|
// WHEN
|
||||||
|
const result = resolvePath('./hello.md')
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
expect(result).equal('/hello.md')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('resolvePath with two dots', async function () {
|
||||||
|
// WHEN
|
||||||
|
const result = resolvePath('test/../hello.md')
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
expect(result).equal('/hello.md')
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Add table
Add a link
Reference in a new issue