diff --git a/docs/configuration.md b/docs/configuration.md index 11797c794..49eea2fbe 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -203,6 +203,14 @@ window.$docsify = { }; ``` +## sidebarAbsolutePath + +In some case, you have only one sidebar.md in your project. But you may put doc files in different directories. You can set `sidebarAbsolutePath` to be `true`, so that it will automaticly make the given `loadSidebar` to be the only one to point at. + +It should works with `loadSidebar`. If you do not set `loadSidebar`, don't set this option any more. + +It works well with `relativePath` and `basePath`. You do not need to worry about the path conflict. + ## coverpage - Type: `Boolean|String|String[]|Object` @@ -587,4 +595,4 @@ Adds a space on top when scrolling content page to reach the selected section. T window.$docsify = { topMargin: 90, // default: 0 }; -``` \ No newline at end of file +``` diff --git a/packages/docsify-server-renderer/index.js b/packages/docsify-server-renderer/index.js index 0d87dffdd..e6f5f9666 100644 --- a/packages/docsify-server-renderer/index.js +++ b/packages/docsify-server-renderer/index.js @@ -1,13 +1,13 @@ import { readFileSync } from 'fs'; import { resolve, basename } from 'path'; import resolvePathname from 'resolve-pathname'; +import fetch from 'node-fetch'; +import debug from 'debug'; import { AbstractHistory } from '../../src/core/router/history/abstract'; import { Compiler } from '../../src/core/render/compiler'; import { isAbsolutePath } from '../../src/core/router/util'; import * as tpl from '../../src/core/render/tpl'; import { prerenderEmbed } from '../../src/core/render/embed'; -import fetch from 'node-fetch'; -import debug from 'debug'; function cwd(...args) { return resolve(process.cwd(), ...args); diff --git a/src/core/event/scroll.js b/src/core/event/scroll.js index ef78443ba..7458ec0a6 100644 --- a/src/core/event/scroll.js +++ b/src/core/event/scroll.js @@ -1,7 +1,7 @@ +import Tweezer from 'tweezer.js'; import { isMobile } from '../util/env'; import * as dom from '../util/dom'; import config from '../config'; -import Tweezer from 'tweezer.js'; const nav = {}; let hoverOver = false; diff --git a/src/core/global-api.js b/src/core/global-api.js index 5529bdaf3..189309af0 100644 --- a/src/core/global-api.js +++ b/src/core/global-api.js @@ -1,10 +1,10 @@ +import prism from 'prismjs'; +import marked from 'marked'; import * as util from './util'; import * as dom from './util/dom'; import { Compiler } from './render/compiler'; import { slugify } from './render/slugify'; import { get } from './fetch/ajax'; -import prism from 'prismjs'; -import marked from 'marked'; export default function() { window.Docsify = { diff --git a/src/core/render/compiler.js b/src/core/render/compiler.js index c4c026205..5b0f2cb73 100644 --- a/src/core/render/compiler.js +++ b/src/core/render/compiler.js @@ -1,3 +1,4 @@ +import marked from 'marked'; import { isAbsolutePath, getPath, getParentPath } from '../router/util'; import { isFn, merge, cached, isPrimitive } from '../util/core'; import { tree as treeTpl } from './tpl'; @@ -11,7 +12,6 @@ import { paragraphCompiler } from './compiler/paragraph'; import { taskListCompiler } from './compiler/taskList'; import { taskListItemCompiler } from './compiler/taskListItem'; import { linkCompiler } from './compiler/link'; -import marked from 'marked'; const cachedLinks = {}; @@ -70,9 +70,12 @@ export class Compiler { this.contentBase = router.getBasePath(); const renderer = this._initRenderer(); + const mdConf = config.markdown || {}; + + this.renderer = renderer; this.heading = renderer.heading; + let compile; - const mdConf = config.markdown || {}; if (isFn(mdConf)) { compile = mdConf(marked, renderer); @@ -218,7 +221,7 @@ export class Compiler { renderer, router, linkTarget, - compilerClass: _self, + compiler: _self, }); origin.paragraph = paragraphCompiler({ renderer }); origin.image = imageCompiler({ renderer, contentBase, router }); @@ -230,6 +233,26 @@ export class Compiler { return renderer; } + compileSidebar(text) { + if (!this.config.sidebarAbsolutePath) { + return this.compile(text); + } + + const { renderer, linkTarget, router } = this; + + linkCompiler({ + renderer, + router, + linkTarget, + compiler: this, + isSidebar: true, + }); + + const html = this.compile(text); + this.renderer.link = this.renderer.origin.link; + return html; + } + /** * Compile sidebar * @param {String} text Text content @@ -242,7 +265,7 @@ export class Compiler { let html = ''; if (text) { - html = this.compile(text); + html = this.compileSidebar(text); } else { for (let i = 0; i < toc.length; i++) { if (toc[i].ignoreSubHeading) { diff --git a/src/core/render/compiler/link.js b/src/core/render/compiler/link.js index faf2e4f7c..198366603 100644 --- a/src/core/render/compiler/link.js +++ b/src/core/render/compiler/link.js @@ -1,8 +1,14 @@ import { getAndRemoveConfig } from '../utils'; import { isAbsolutePath } from '../../router/util'; -export const linkCompiler = ({ renderer, router, linkTarget, compilerClass }) => - (renderer.link = (href, title = '', text) => { +export const linkCompiler = ({ + renderer, + router, + linkTarget, + compiler, + isSidebar = false, +}) => { + const link = (href, title = '', text) => { let attrs = []; const { str, config } = getAndRemoveConfig(title); @@ -10,14 +16,22 @@ export const linkCompiler = ({ renderer, router, linkTarget, compilerClass }) => if ( !isAbsolutePath(href) && - !compilerClass._matchNotCompileLink(href) && + !compiler._matchNotCompileLink(href) && !config.ignore ) { - if (href === compilerClass.config.homepage) { + const sidebarAbsolutePath = compiler.config.sidebarAbsolutePath; + const basePath = + typeof sidebarAbsolutePath === 'string' + ? sidebarAbsolutePath + : router.getBasePath(); + const relativeTo = + isSidebar && sidebarAbsolutePath ? basePath : router.getCurrentPath(); + + if (href === compiler.config.homepage) { href = 'README'; } - href = router.toURL(href, null, router.getCurrentPath()); + href = router.toURL(href, null, relativeTo); } else { if (!isAbsolutePath(href) && href.startsWith('./')) { href = @@ -48,4 +62,7 @@ export const linkCompiler = ({ renderer, router, linkTarget, compilerClass }) => } return `${text}`; - }); + }; + renderer.link = link; + return link; +}; diff --git a/src/core/render/embed.js b/src/core/render/embed.js index 083fb7f97..b64d11a8b 100644 --- a/src/core/render/embed.js +++ b/src/core/render/embed.js @@ -1,6 +1,6 @@ +import stripIndent from 'strip-indent'; import { get } from '../fetch/ajax'; import { merge } from '../util/core'; -import stripIndent from 'strip-indent'; const cached = {}; diff --git a/src/core/render/index.js b/src/core/render/index.js index 9b50dc708..37cd6af34 100644 --- a/src/core/render/index.js +++ b/src/core/render/index.js @@ -1,4 +1,5 @@ /* eslint-disable no-unused-vars */ +import tinydate from 'tinydate'; import * as dom from '../util/dom'; import cssVars from '../util/polyfill/css-vars'; import { callHook } from '../init/lifecycle'; @@ -10,7 +11,6 @@ import { scrollActiveSidebar } from '../event/scroll'; import { Compiler } from './compiler'; import * as tpl from './tpl'; import { prerenderEmbed } from './embed'; -import tinydate from 'tinydate'; function executeScript() { const script = dom diff --git a/src/core/router/history/base.js b/src/core/router/history/base.js index 68c98b7f5..486811fc2 100644 --- a/src/core/router/history/base.js +++ b/src/core/router/history/base.js @@ -42,8 +42,20 @@ export class History { const { config } = this; const base = this.getBasePath(); const ext = typeof config.ext === 'string' ? config.ext : '.md'; + const alias = config.alias || {}; + const rules = Object.assign({}, alias); + + // auto alias sidebar which is set to be absolute path + if (config.sidebarAbsolutePath) { + const sidebar = config.loadSidebar || '_sidebar.md'; + const base = + typeof config.sidebarAbsolutePath === 'string' + ? config.sidebarAbsolutePath + : this.getBasePath(); + rules['/.*/' + sidebar] = base + sidebar; + } - path = config.alias ? getAlias(path, config.alias) : path; + path = getAlias(path, rules); path = getFileName(path, ext); path = path === `/README${ext}` ? config.homepage || path : path; path = isAbsolutePath(path) ? path : getPath(base, path); diff --git a/test/unit/base.test.js b/test/unit/base.test.js index 736b70ac6..ed050424a 100644 --- a/test/unit/base.test.js +++ b/test/unit/base.test.js @@ -2,8 +2,8 @@ require = require('esm')( module /* , options */ ); /* eslint-disable-line no-global-assign */ -const { History } = require('../../src/core/router/history/base'); const { expect } = require('chai'); +const { History } = require('../../src/core/router/history/base'); class MockHistory extends History { parse(path) { diff --git a/test/unit/render.test.js b/test/unit/render.test.js index 67d3bcf09..c3ed7b140 100644 --- a/test/unit/render.test.js +++ b/test/unit/render.test.js @@ -1,5 +1,5 @@ -const { init, expectSameDom } = require('../_helper'); const { expect } = require('chai'); +const { init, expectSameDom } = require('../_helper'); describe('render', function() { it('important content (tips)', async function() { diff --git a/test/unit/util.test.js b/test/unit/util.test.js index e4e8a0e3b..9dadf28a3 100644 --- a/test/unit/util.test.js +++ b/test/unit/util.test.js @@ -2,8 +2,8 @@ require = require('esm')( module /* , options */ ); /* eslint-disable-line no-global-assign */ -const { resolvePath } = require('../../src/core/router/util'); const { expect } = require('chai'); +const { resolvePath } = require('../../src/core/router/util'); describe('router/util', function() { it('resolvePath', async function() {