Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing behaviour for when an link is root-relative #850 #877 #1339

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -616,3 +616,24 @@ window.$docsify = {
topMargin: 90, // default: 0
};
```

## rootRelativeImageURL

- Type: `Boolean|String`
- Default: `false`

Configure image URL rendering behavior when inserting markdown images when the image URL is root-relative, i.e. starts with '/'.

By default, Docsify resolves all image paths against the current page's parent path.

E.g. if the current path is `/advanced/guide`, `![](/assets/image.png)` would render as `<img src="advanced/assets/image.png">`.

```js
window.$docsify = {
rootRelativeImageURL = false // default behaviour

rootRelativeImageURL = true // ![](/assets/image.png) renders as <img src="/assets/image.png" />

rootRelativeImageURL = 'my-root-path' // ![](/assets/image.png) renders as <img src="/my-root-path/assets/image.png />
}
```
5 changes: 5 additions & 0 deletions src/core/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default function(vm) {
crossOriginLinks: [],
relativePath: false,
topMargin: 0,
rootRelativeImageURL: false,
},
typeof window.$docsify === 'function'
? window.$docsify(vm)
Expand Down Expand Up @@ -79,6 +80,10 @@ export default function(vm) {
config.name = '';
}

if (config.rootRelativeImageURL === true) {
config.rootRelativeImageURL = '';
}

window.$docsify = config;

return config;
Expand Down
16 changes: 14 additions & 2 deletions src/core/render/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export class Compiler {
this.linkRel =
this.linkTarget === '_blank' ? config.externalLinkRel || 'noopener' : '';
this.contentBase = router.getBasePath();
this.rootRelativeImageURL = config.rootRelativeImageURL;
weijunyu marked this conversation as resolved.
Show resolved Hide resolved

const renderer = this._initRenderer();
this.heading = renderer.heading;
Expand Down Expand Up @@ -193,7 +194,13 @@ export class Compiler {

_initRenderer() {
const renderer = new marked.Renderer();
const { linkTarget, linkRel, router, contentBase } = this;
const {
linkTarget,
linkRel,
router,
contentBase,
rootRelativeImageURL,
} = this;
const _self = this;
const origin = {};

Expand Down Expand Up @@ -249,7 +256,12 @@ export class Compiler {
compilerClass: _self,
});
origin.paragraph = paragraphCompiler({ renderer });
origin.image = imageCompiler({ renderer, contentBase, router });
origin.image = imageCompiler({
renderer,
contentBase,
router,
rootRelativeImageURL,
});
origin.list = taskListCompiler({ renderer });
origin.listitem = taskListItemCompiler({ renderer });

Expand Down
21 changes: 17 additions & 4 deletions src/core/render/compiler/image.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { getAndRemoveConfig } from '../utils';
import { isAbsolutePath, getPath, getParentPath } from '../../router/util';

export const imageCompiler = ({ renderer, contentBase, router }) =>
import {
isAbsolutePath,
isPathRootRelative,
getPath,
getParentPath,
} from '../../router/util';

export const imageCompiler = ({
renderer,
contentBase,
router,
rootRelativeImageURL,
}) =>
(renderer.image = (href, title, text) => {
let url = href;
let attrs = [];
Expand Down Expand Up @@ -35,7 +45,10 @@ export const imageCompiler = ({ renderer, contentBase, router }) =>
}

if (!isAbsolutePath(href)) {
url = getPath(contentBase, getParentPath(router.getCurrentPath()), href);
url =
isPathRootRelative(href) && rootRelativeImageURL !== false
? getPath('/' + String(rootRelativeImageURL), href)
: getPath(contentBase, getParentPath(router.getCurrentPath()), href);
}

if (attrs.length > 0) {
Expand Down
4 changes: 4 additions & 0 deletions src/core/router/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export const isAbsolutePath = cached(path => {
return /(:|(\/{2}))/g.test(path);
});

export const isPathRootRelative = cached(path => {
return path[0] === '/';
});

export const removeParams = cached(path => {
return path.split(/[?#]/)[0];
});
Expand Down
4 changes: 3 additions & 1 deletion test/_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ module.exports.init = function(

const rootPath = path.join(__dirname, 'fixtures', fixture);

const dom = initJSDOM(markup);
const runScriptInJSDom =
Object.values(config).length !== 0 ? 'dangerously' : undefined;
const dom = initJSDOM(markup, { runScripts: runScriptInJSDom });
dom.reconfigure({ url: 'file:///' + rootPath });

// Mimic src/core/index.js but for Node.js
Expand Down
65 changes: 65 additions & 0 deletions test/unit/render.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const path = require('path');
const { expect } = require('chai');
const { init, expectSameDom } = require('../_helper');

Expand Down Expand Up @@ -104,6 +105,23 @@ describe('render', function() {
);
});

it('relative image url', async function() {
const { docsify } = await init();
const output = docsify.compiler.compile(
'![alt text](some-path/image.png)'
);
const expectedCompiledPath = path.posix.join(
// must use posix here because if run on windows, paths are joined using backslash (\)
__dirname,
'../fixtures/default',
'some-path/image.png'
);
expectSameDom(
output,
`<p><img src="${expectedCompiledPath}" data-origin="some-path/image.png" alt="alt text"></p>`
);
});

it('class', async function() {
const { docsify } = await init();
const output = docsify.compiler.compile(
Expand Down Expand Up @@ -165,6 +183,53 @@ describe('render', function() {
);
});
});

describe('compiling root-relative image src path', async function() {
it('behaves normally if config.rootRelativeImageURL is set to false', async function() {
const { docsify } = await init('default', {
rootRelativeImageURL: false,
});
const rootRelativePathOutput = docsify.compiler.compile(
'![alt text](/some-path/image.png)'
);
const expectedCompiledPath = path.posix.join(
// must use posix here because if run on windows, file paths use backslash (\)
__dirname,
'../fixtures/default',
'some-path/image.png'
);
expectSameDom(
rootRelativePathOutput,
`<p><img src="${expectedCompiledPath}" data-origin="/some-path/image.png" alt="alt text"></p>`
);
});

it('only uses the image href if config.rootRelativeImageURL is set to true', async function() {
const { docsify } = await init('default', {
rootRelativeImageURL: true,
});
const rootRelativePathOutput = docsify.compiler.compile(
'![alt text](/some-path/image.png)'
);
expectSameDom(
rootRelativePathOutput,
`<p><img src="/some-path/image.png" data-origin="/some-path/image.png" alt="alt text"></p>`
);
});

it('uses config.rootRelativeImageURL as a prefix for the compiled image path, if passed as a string', async function() {
const { docsify } = await init('default', {
rootRelativeImageURL: 'docs',
});
const rootRelativePathOutput = docsify.compiler.compile(
'![alt text](/some-path/image.png)'
);
expectSameDom(
rootRelativePathOutput,
`<p><img src="/docs/some-path/image.png" data-origin="/some-path/image.png" alt="alt text"></p>`
);
});
});
});

describe('heading', function() {
Expand Down