diff --git a/src/core/operations/RenderMarkdown.mjs b/src/core/operations/RenderMarkdown.mjs index c656bf5b..824643ed 100644 --- a/src/core/operations/RenderMarkdown.mjs +++ b/src/core/operations/RenderMarkdown.mjs @@ -35,6 +35,11 @@ class RenderMarkdown extends Operation { name: "Enable syntax highlighting", type: "boolean", value: true + }, + { + name: "Open links in new tab.", + type: "boolean", + value: false } ]; } @@ -45,7 +50,7 @@ class RenderMarkdown extends Operation { * @returns {html} */ run(input, args) { - const [convertLinks, enableHighlighting] = args, + const [convertLinks, enableHighlighting, openLinksBlank] = args, md = new MarkdownIt({ linkify: convertLinks, html: false, // Explicitly disable HTML rendering @@ -58,12 +63,37 @@ class RenderMarkdown extends Operation { return ""; } - }), - rendered = md.render(input); - + }); + if (openLinksBlank) { + this.makeLinksOpenInNewTab(md); + } + const rendered = md.render(input); return `
${rendered}
`; } + /** + * Adds target="_blank" to links. + * @param {MarkdownIt} md + */ + makeLinksOpenInNewTab(md) { + // Adapted from: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer + // Remember old renderer, if overridden, or proxy to default renderer + const defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) { + return self.renderToken(tokens, idx, options); + }; + + md.renderer.rules.link_open = function (tokens, idx, options, env, self) { + const token = tokens[idx]; + if (token.attrIndex('target') >= 0) { + // Target attribute already set, do not replace. + return; + } + token.attrPush(['target', '_blank']); // add new attribute + + // pass token to default renderer. + return defaultRender(tokens, idx, options, env, self); + }; + } } export default RenderMarkdown;