From ea1e139acd02bb8cd77eddd50adc19a11e4bf929 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Sat, 3 Mar 2018 10:39:59 +0100 Subject: [PATCH] feat(config): Add 404 page options. This feature add the notFoundPage options to customize the default 404 page with a markdown file. It also support the localisation. --- docs/configuration.md | 31 ++++++++ docs/de-de/configuration.md | 29 ++++++++ docs/zh-cn/configuration.md | 31 ++++++++ src/core/fetch/index.js | 144 ++++++++++++++++++++++++------------ src/core/render/index.js | 3 +- 5 files changed, 189 insertions(+), 49 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 532eccd8d..e4078ede0 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -435,3 +435,34 @@ window.$docsify = { ] }; ``` + + +## notFoundPage + +* type: `Boolean` | `String` | `Object` + +Load the `_404.md` file: +```js +window.$docsify = { + notFoundPage: true +}; +``` + +Load the customised path of the 404 page: +```js +window.$docsify = { + notFoundPage: 'my404.md' +}; +``` + +Load the right 404 page according to the localisation: +```js +window.$docsify = { + notFoundPage: { + '/': '_404.md', + '/de': 'de/_404.md', + } +}; +``` +> Note: The options with fallbackLanguages didn't work with the `notFoundPage` options. + diff --git a/docs/de-de/configuration.md b/docs/de-de/configuration.md index 87e4869c2..2f5ebdcb4 100644 --- a/docs/de-de/configuration.md +++ b/docs/de-de/configuration.md @@ -419,3 +419,32 @@ window.$docsify = { fallbackLanguages: ['fr', 'de'] }; ``` + +## notFoundPage + +* type: `Boolean` | `String` | `Object` + +Load the `_404.md` file: +```js +window.$docsify = { + notFoundPage: true +}; +``` + +Load the customised path of the 404 page: +```js +window.$docsify = { + notFoundPage: 'my404.md' +}; +``` + +Load the right 404 page according to the localisation: +```js +window.$docsify = { + notFoundPage: { + '/': '_404.md', + '/de': 'de/_404.md', + } +}; +``` +> Note: The options with fallbackLanguages didn't work with the `notFoundPage` options. diff --git a/docs/zh-cn/configuration.md b/docs/zh-cn/configuration.md index f91355f22..3b8a0da28 100644 --- a/docs/zh-cn/configuration.md +++ b/docs/zh-cn/configuration.md @@ -431,3 +431,34 @@ window.$docsify = { fallbackLanguages: ['fr', 'de'] }; ``` + +## notFoundPage + +* type: `Boolean` | `String` | `Object` + +Load the `_404.md` file: +```js +window.$docsify = { + notFoundPage: true +}; +``` + +Load the customised path of the 404 page: +```js +window.$docsify = { + notFoundPage: 'my404.md' +}; +``` + +Load the right 404 page according to the localisation: +```js +window.$docsify = { + notFoundPage: { + '/': '_404.md', + '/de': 'de/_404.md', + } +}; +``` +> Note: The options with fallbackLanguages didn't work with the `notFoundPage` options. + + diff --git a/src/core/fetch/index.js b/src/core/fetch/index.js index 035f2ef3f..1b3db8f11 100644 --- a/src/core/fetch/index.js +++ b/src/core/fetch/index.js @@ -19,44 +19,35 @@ function loadNested (path, qs, file, next, vm, first) { export function fetchMixin (proto) { let last - proto._fetch = function (cb = noop) { - const { path, query } = this.route - const qs = stringifyQuery(query, ['id']) - const { loadNavbar, loadSidebar, requestHeaders, fallbackLanguages } = this.config - // Abort last request - last && last.abort && last.abort() - - const file = this.router.getFile(path) - last = get(file + qs, true, requestHeaders) - - // Current page is html - this.isHTML = /\.html$/g.test(file) - - const getFallBackPage = (file) => { - if (!fallbackLanguages) { - return false - } - const local = file.split('/')[1] - - if (fallbackLanguages.indexOf(local) === -1) { - return false - } - - file = file.replace(new RegExp(`^/${local}`), '') + const abort = () => last && last.abort && last.abort() + const request = (url, hasbar, requestHeaders) => { + abort() + last = get(url, true, requestHeaders) + return last + } - return get(file + qs, true, requestHeaders) - .then( - (text, opt) => { - this._renderMain(text, opt, loadSideAndNav) - }, - _ => { - return this._renderMain(null, {}, loadSideAndNav) - } - ) + const get404Path = (path, config) => { + const { notFoundPage, ext } = config + const defaultPath = '_404' + (ext || '.md') + + switch (typeof notFoundPage) { + case 'boolean': + return defaultPath + case 'string': + return notFoundPage + case 'object': + const key = Object + .keys(notFoundPage) + .sort((a, b) => b.length - a.length) + .find((key) => path.match(new RegExp('^' + key))) + + return key && notFoundPage[key] || defaultPath } + } - const loadSideAndNav = () => { + proto._loadSideAndNav = function (path, qs, loadSidebar, cb) { + return () => { if (!loadSidebar) return cb() const fn = result => { @@ -67,28 +58,39 @@ export function fetchMixin (proto) { // Load sidebar loadNested(path, qs, loadSidebar, fn, this, true) } + } + + proto._fetch = function (cb = noop) { + const { path, query } = this.route + const qs = stringifyQuery(query, ['id']) + const { loadNavbar, requestHeaders, loadSidebar } = this.config + // Abort last request + + const file = this.router.getFile(path) + const req = request(file + qs, true, requestHeaders) + + // Current page is html + this.isHTML = /\.html$/g.test(file) // Load main content - last + req .then( - (text, opt) => { - this._renderMain(text, opt, loadSideAndNav) - }, + (text, opt) => this._renderMain(text, opt, this._loadSideAndNav(path, qs, loadSidebar, cb)), _ => { - return getFallBackPage(file) || this._renderMain(null, {}, loadSideAndNav) + this._fetchFallbackPage(file, qs, cb) || this._fetch404(file, qs, cb) } ) // Load nav loadNavbar && - loadNested( - path, - qs, - loadNavbar, - text => this._renderNav(text), - this, - true - ) + loadNested( + path, + qs, + loadNavbar, + text => this._renderNav(text), + this, + true + ) } proto._fetchCover = function () { @@ -141,6 +143,54 @@ export function fetchMixin (proto) { }) } } + + proto._fetchFallbackPage = function (path, qs, cb = noop) { + const { requestHeaders, fallbackLanguages, loadSidebar } = this.config + + if (!fallbackLanguages) { + return false + } + + const local = path.split('/')[1] + + if (fallbackLanguages.indexOf(local) === -1) { + return false + } + const newPath = path.replace(new RegExp(`^/${local}`), '') + const req = request(newPath + qs, true, requestHeaders) + + req.then( + (text, opt) => this._renderMain(text, opt, this._loadSideAndNav(path, qs, loadSidebar, cb)), + () => this._fetch404(path, qs, cb) + ) + + return true + } + /** + * Load the 404 page + * @param path + * @param qs + * @param cb + * @returns {*} + * @private + */ + proto._fetch404 = function (path, qs, cb = noop) { + const { loadSidebar, requestHeaders, notFoundPage } = this.config + + const fnLoadSideAndNav = this._loadSideAndNav(path, qs, loadSidebar, cb) + + if (notFoundPage) { + request(get404Path(path, this.config), true, requestHeaders) + .then( + (text, opt) => this._renderMain(text, opt, fnLoadSideAndNav), + () => this._renderMain(null, {}, fnLoadSideAndNav) + ) + return true + } + + this._renderMain(null, {}, fnLoadSideAndNav) + return false + } } export function initFetch (vm) { diff --git a/src/core/render/index.js b/src/core/render/index.js index 1bea205a5..4b430ef11 100644 --- a/src/core/render/index.js +++ b/src/core/render/index.js @@ -35,8 +35,7 @@ function formatUpdated (html, updated, fn) { function renderMain (html) { if (!html) { - // TODO: Custom 404 page - html = 'not found' + html = '

404 - Not found

' } this._renderTo('.markdown-section', html)