Skip to content

Commit ff9d463

Browse files
authored
Merge branch 'develop' into fix-877&850
2 parents f8f1050 + 150236a commit ff9d463

File tree

18 files changed

+579
-30
lines changed

18 files changed

+579
-30
lines changed

.eslintrc.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,14 @@ module.exports = {
4141
'no-shadow': [
4242
'error',
4343
{
44-
allow: ['Events', 'Fetch', 'Lifecycle', 'Render', 'Router'],
44+
allow: [
45+
'Events',
46+
'Fetch',
47+
'Lifecycle',
48+
'Render',
49+
'Router',
50+
'VirtualRoutes',
51+
],
4552
},
4653
],
4754
'no-unused-vars': ['error', { args: 'none' }],

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Move to [awesome-docsify](https://github.com/docsifyjs/awesome-docsify#showcase)
7070

7171
### Online one-click setup for Contributing
7272

73-
You can use Gitpod(A free online VS Code-like IDE) for contributing. With single click it'll launch a workspace and automatically:
73+
You can use Gitpod (a free online VS Code-like IDE) for contributing. With a single click it'll launch a workspace and automatically:
7474

7575
- clone the docsify repo.
7676
- install the dependencies.

docs/_navbar.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
- Translations
22
- [:uk: English](/)
3-
- [:cn: 中文](/zh-cn/)
3+
- [:cn: 简体中文](/zh-cn/)
44
- [:de: Deutsch](/de-de/)
55
- [:es: Español](/es/)
66
- [:ru: Русский](/ru-ru/)

docs/configuration.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ The config can also be defined as a function, in which case the first argument i
3535
- Type: `Object`
3636

3737
Set the route alias. You can freely manage routing rules. Supports RegExp.
38+
Do note that order matters! If a route can be matched by multiple aliases, the one you declared first takes precedence.
3839

3940
```js
4041
window.$docsify = {
@@ -680,6 +681,91 @@ window.$docsify = {
680681
};
681682
```
682683

684+
## routes
685+
686+
- Type: `Object`
687+
688+
Define "virtual" routes that can provide content dynamically. A route is a map between the expected path, to either a string or a function. If the mapped value is a string, it is treated as markdown and parsed accordingly. If it is a function, it is expected to return markdown content.
689+
690+
A route function receives up to three parameters:
691+
1. `route` - the path of the route that was requested (e.g. `/bar/baz`)
692+
2. `matched` - the [`RegExpMatchArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match) that was matched by the route (e.g. for `/bar/(.+)`, you get `['/bar/baz', 'baz']`)
693+
3. `next` - this is a callback that you may call when your route function is async
694+
695+
Do note that order matters! Routes are matched the same order you declare them in, which means that in cases where you have overlapping routes, you might want to list the more specific ones first.
696+
697+
```js
698+
window.$docsify = {
699+
routes: {
700+
// Basic match w/ return string
701+
'/foo': '# Custom Markdown',
702+
703+
// RegEx match w/ synchronous function
704+
'/bar/(.*)': function(route, matched) {
705+
return '# Custom Markdown';
706+
},
707+
708+
// RegEx match w/ asynchronous function
709+
'/baz/(.*)': function(route, matched, next) {
710+
// Requires `fetch` polyfill for legacy browsers (https://github.github.io/fetch/)
711+
fetch('/api/users?id=12345')
712+
.then(function(response) {
713+
next('# Custom Markdown');
714+
})
715+
.catch(function(err) {
716+
// Handle error...
717+
});
718+
}
719+
}
720+
}
721+
```
722+
723+
Other than strings, route functions can return a falsy value (`null` \ `undefined`) to indicate that they ignore the current request:
724+
725+
```js
726+
window.$docsify = {
727+
routes: {
728+
// accepts everything other than dogs (synchronous)
729+
'/pets/(.+)': function(route, matched) {
730+
if (matched[0] === 'dogs') {
731+
return null;
732+
} else {
733+
return 'I like all pets but dogs';
734+
}
735+
}
736+
737+
// accepts everything other than cats (asynchronous)
738+
'/pets/(.*)': function(route, matched, next) {
739+
if (matched[0] === 'cats') {
740+
next();
741+
} else {
742+
// Async task(s)...
743+
next('I like all pets but cats');
744+
}
745+
}
746+
}
747+
}
748+
```
749+
750+
Finally, if you have a specific path that has a real markdown file (and therefore should not be matched by your route), you can opt it out by returning an explicit `false` value:
751+
752+
```js
753+
window.$docsify = {
754+
routes: {
755+
// if you look up /pets/cats, docsify will skip all routes and look for "pets/cats.md"
756+
'/pets/cats': function(route, matched) {
757+
return false;
758+
}
759+
760+
// but any other pet should generate dynamic content right here
761+
'/pets/(.+)': function(route, matched) {
762+
const pet = matched[0];
763+
return `your pet is ${pet} (but not a cat)`;
764+
}
765+
}
766+
}
767+
```
768+
683769
## subMaxLevel
684770

685771
- Type: `Number`

docs/custom-navbar.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ If you need custom navigation, you can create a HTML-based navigation bar.
1212
<body>
1313
<nav>
1414
<a href="#/">EN</a>
15-
<a href="#/zh-cn/">中文</a>
15+
<a href="#/zh-cn/">简体中文</a>
1616
</nav>
1717
<div id="app"></div>
1818
</body>

src/core/Docsify.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Router } from './router/index.js';
22
import { Render } from './render/index.js';
33
import { Fetch } from './fetch/index.js';
44
import { Events } from './event/index.js';
5+
import { VirtualRoutes } from './virtual-routes/index.js';
56
import initGlobalAPI from './global-api.js';
67

78
import config from './config.js';
@@ -11,7 +12,10 @@ import { Lifecycle } from './init/lifecycle';
1112
/** @typedef {new (...args: any[]) => any} Constructor */
1213

1314
// eslint-disable-next-line new-cap
14-
export class Docsify extends Fetch(Events(Render(Router(Lifecycle(Object))))) {
15+
export class Docsify extends Fetch(
16+
// eslint-disable-next-line new-cap
17+
Events(Render(VirtualRoutes(Router(Lifecycle(Object)))))
18+
) {
1519
constructor() {
1620
super();
1721

src/core/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export default function (vm) {
3333
notFoundPage: true,
3434
relativePath: false,
3535
repo: '',
36+
routes: {},
3637
routerMode: 'hash',
3738
subMaxLevel: 0,
3839
themeColor: '',

src/core/fetch/index.js

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -96,25 +96,44 @@ export function Fetch(Base) {
9696
// Abort last request
9797

9898
const file = this.router.getFile(path);
99-
const req = request(file + qs, true, requestHeaders);
10099

101100
this.isRemoteUrl = isExternal(file);
102101
// Current page is html
103102
this.isHTML = /\.html$/g.test(file);
104103

105-
// Load main content
106-
req.then(
107-
(text, opt) =>
108-
this._renderMain(
109-
text,
110-
opt,
111-
this._loadSideAndNav(path, qs, loadSidebar, cb)
112-
),
113-
_ => {
114-
this._fetchFallbackPage(path, qs, cb) ||
115-
this._fetch404(file, qs, cb);
116-
}
117-
);
104+
// create a handler that should be called if content was fetched successfully
105+
const contentFetched = (text, opt) => {
106+
this._renderMain(
107+
text,
108+
opt,
109+
this._loadSideAndNav(path, qs, loadSidebar, cb)
110+
);
111+
};
112+
113+
// and a handler that is called if content failed to fetch
114+
const contentFailedToFetch = _ => {
115+
this._fetchFallbackPage(path, qs, cb) || this._fetch404(file, qs, cb);
116+
};
117+
118+
// attempt to fetch content from a virtual route, and fallback to fetching the actual file
119+
if (!this.isRemoteUrl) {
120+
this.matchVirtualRoute(path).then(contents => {
121+
if (typeof contents === 'string') {
122+
contentFetched(contents);
123+
} else {
124+
request(file + qs, true, requestHeaders).then(
125+
contentFetched,
126+
contentFailedToFetch
127+
);
128+
}
129+
});
130+
} else {
131+
// if the requested url is not local, just fetch the file
132+
request(file + qs, true, requestHeaders).then(
133+
contentFetched,
134+
contentFailedToFetch
135+
);
136+
}
118137

119138
// Load nav
120139
loadNavbar &&

src/core/render/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ export function Render(Base) {
413413

414414
if (el) {
415415
if (config.repo) {
416-
html += tpl.corner(config.repo, config.cornerExternalLinkTarge);
416+
html += tpl.corner(config.repo, config.cornerExternalLinkTarget);
417417
}
418418

419419
if (config.coverpage) {

src/core/render/tpl.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/**
22
* Render github corner
33
* @param {Object} data URL for the View Source on Github link
4-
* @param {String} cornerExternalLinkTarge value of the target attribute of the link
4+
* @param {String} cornerExternalLinkTarget value of the target attribute of the link
55
* @return {String} SVG element as string
66
*/
7-
export function corner(data, cornerExternalLinkTarge) {
7+
export function corner(data, cornerExternalLinkTarget) {
88
if (!data) {
99
return '';
1010
}
@@ -15,10 +15,10 @@ export function corner(data, cornerExternalLinkTarge) {
1515

1616
data = data.replace(/^git\+/, '');
1717
// Double check
18-
cornerExternalLinkTarge = cornerExternalLinkTarge || '_blank';
18+
cornerExternalLinkTarget = cornerExternalLinkTarget || '_blank';
1919

2020
return (
21-
`<a href="${data}" target="${cornerExternalLinkTarge}" class="github-corner" aria-label="View source on Github">` +
21+
`<a href="${data}" target="${cornerExternalLinkTarget}" class="github-corner" aria-label="View source on Github">` +
2222
'<svg viewBox="0 0 250 250" aria-hidden="true">' +
2323
'<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>' +
2424
'<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>' +

0 commit comments

Comments
 (0)