mirror of
https://github.com/showdownjs/showdown.git
synced 2024-03-22 13:30:55 +08:00
feat(relativePathBaseUrl): Add support for prepending a base URL
This feature enables support for prepending a base URL to relative paths in links and images when converting Markdown to HTML. Closes #536
This commit is contained in:
parent
9c362e832e
commit
e3a5b5928f
|
@ -400,6 +400,34 @@ showdown.helper._hashHTMLSpan = function (html, globals) {
|
|||
return '¨C' + (globals.gHtmlSpans.push(html) - 1) + 'C';
|
||||
};
|
||||
|
||||
/**
|
||||
* Prepends a base URL to relative paths.
|
||||
*
|
||||
* @param {string} baseUrl the base URL to prepend to a relative path
|
||||
* @param {string} url the path to modify, which may be relative
|
||||
* @returns {string} the full URL
|
||||
*/
|
||||
showdown.helper.applyBaseUrl = function (baseUrl, url) {
|
||||
// Only prepend if given a base URL and the path is not absolute.
|
||||
if (baseUrl && !this.isAbsolutePath(url)) {
|
||||
var urlResolve = require('url').resolve;
|
||||
url = urlResolve(baseUrl, url);
|
||||
}
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the given path is absolute.
|
||||
*
|
||||
* @param {string} path the path to test for absolution
|
||||
* @returns {boolean} `true` if the given path is absolute, else `false`
|
||||
*/
|
||||
showdown.helper.isAbsolutePath = function (path) {
|
||||
// Absolute paths begin with '[protocol:]//' or '#' (anchors)
|
||||
return /(^([a-z]+:)?\/\/)|(^#)/i.test(path);
|
||||
};
|
||||
|
||||
/**
|
||||
* Showdown's Event Object
|
||||
* @param {string} name Name of the event
|
||||
|
@ -476,7 +504,7 @@ showdown.helper.Event = function (name, text, params) {
|
|||
/**
|
||||
* POLYFILLS
|
||||
*/
|
||||
// use this instead of builtin is undefined for IE8 compatibility
|
||||
// use this instead if builtin is undefined for IE8 compatibility
|
||||
if (typeof(console) === 'undefined') {
|
||||
console = {
|
||||
warn: function (msg) {
|
||||
|
|
|
@ -160,7 +160,12 @@ function getDefaultOpts (simple) {
|
|||
defaultValue: false,
|
||||
description: 'Split adjacent blockquote blocks',
|
||||
type: 'boolean'
|
||||
}
|
||||
},
|
||||
relativePathBaseUrl: {
|
||||
defaultValue: false,
|
||||
describe: 'Prepends a base URL to relative paths',
|
||||
type: 'string'
|
||||
},
|
||||
};
|
||||
if (simple === false) {
|
||||
return JSON.parse(JSON.stringify(defaultOptions));
|
||||
|
|
|
@ -17,6 +17,12 @@ showdown.subParser('makehtml.images', function (text, options, globals) {
|
|||
return writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title);
|
||||
}
|
||||
|
||||
function writeImageTagBaseUrl (wholeMatch, altText, linkId, url, width, height, m5, title) {
|
||||
url = showdown.helper.applyBaseUrl(options.relativePathBaseUrl, url);
|
||||
|
||||
return writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title);
|
||||
}
|
||||
|
||||
function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) {
|
||||
|
||||
var gUrls = globals.gUrls,
|
||||
|
@ -91,10 +97,10 @@ showdown.subParser('makehtml.images', function (text, options, globals) {
|
|||
text = text.replace(base64RegExp, writeImageTagBase64);
|
||||
|
||||
// cases with crazy urls like ./image/cat1).png
|
||||
text = text.replace(crazyRegExp, writeImageTag);
|
||||
text = text.replace(crazyRegExp, writeImageTagBaseUrl);
|
||||
|
||||
// normal cases
|
||||
text = text.replace(inlineRegExp, writeImageTag);
|
||||
text = text.replace(inlineRegExp, writeImageTagBaseUrl);
|
||||
|
||||
// handle reference-style shortcuts: ![img text]
|
||||
text = text.replace(refShortcutRegExp, writeImageTag);
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
* @param {{}} globals
|
||||
* @returns {Function}
|
||||
*/
|
||||
function replaceAnchorTag (rgx, evtRootName, options, globals, emptyCase) {
|
||||
function replaceAnchorTagReference (rgx, evtRootName, options, globals, emptyCase) {
|
||||
emptyCase = !!emptyCase;
|
||||
return function (wholeMatch, text, id, url, m5, m6, title) {
|
||||
// bail we we find 2 newlines somewhere
|
||||
|
@ -36,6 +36,15 @@
|
|||
};
|
||||
}
|
||||
|
||||
function replaceAnchorTagBaseUrl (rgx, evtRootName, options, globals, emptyCase) {
|
||||
return function (wholeMatch, text, id, url, m5, m6, title) {
|
||||
url = showdown.helper.applyBaseUrl(options.relativePathBaseUrl, url);
|
||||
|
||||
var evt = createEvent(rgx, evtRootName + '.captureStart', wholeMatch, text, id, url, title, options, globals);
|
||||
return writeAnchorTag(evt, options, globals, emptyCase);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Normalize this
|
||||
* Helper function: Create a capture event
|
||||
|
@ -192,21 +201,21 @@
|
|||
|
||||
// 1. Look for empty cases: []() and [empty]() and []("title")
|
||||
var rgxEmpty = /\[(.*?)]()()()()\(<? ?>? ?(?:["'](.*)["'])?\)/g;
|
||||
text = text.replace(rgxEmpty, replaceAnchorTag(rgxEmpty, evtRootName, options, globals, true));
|
||||
text = text.replace(rgxEmpty, replaceAnchorTagBaseUrl(rgxEmpty, evtRootName, options, globals, true));
|
||||
|
||||
// 2. Look for cases with crazy urls like ./image/cat1).png
|
||||
var rgxCrazy = /\[((?:\[[^\]]*]|[^\[\]])*)]()\s?\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g;
|
||||
text = text.replace(rgxCrazy, replaceAnchorTag(rgxCrazy, evtRootName, options, globals));
|
||||
text = text.replace(rgxCrazy, replaceAnchorTagBaseUrl(rgxCrazy, evtRootName, options, globals));
|
||||
|
||||
// 3. inline links with no title or titles wrapped in ' or ":
|
||||
// [text](url.com) || [text](<url.com>) || [text](url.com "title") || [text](<url.com> "title")
|
||||
//var rgx2 = /\[[ ]*[\s]?[ ]*([^\n\[\]]*?)[ ]*[\s]?[ ]*] ?()\(<?[ ]*[\s]?[ ]*([^\s'"]*)>?(?:[ ]*[\n]?[ ]*()(['"])(.*?)\5)?[ ]*[\s]?[ ]*\)/; // this regex is too slow!!!
|
||||
var rgx2 = /\[([\S ]*?)]\s?()\( *<?([^\s'"]*?(?:\([\S]*?\)[\S]*?)?)>?\s*(?:()(['"])(.*?)\5)? *\)/g;
|
||||
text = text.replace(rgx2, replaceAnchorTag(rgx2, evtRootName, options, globals));
|
||||
text = text.replace(rgx2, replaceAnchorTagBaseUrl(rgx2, evtRootName, options, globals));
|
||||
|
||||
// 4. inline links with titles wrapped in (): [foo](bar.com (title))
|
||||
var rgx3 = /\[([\S ]*?)]\s?()\( *<?([^\s'"]*?(?:\([\S]*?\)[\S]*?)?)>?\s+()()\((.*?)\) *\)/g;
|
||||
text = text.replace(rgx3, replaceAnchorTag(rgx3, evtRootName, options, globals));
|
||||
text = text.replace(rgx3, replaceAnchorTagBaseUrl(rgx3, evtRootName, options, globals));
|
||||
|
||||
text = globals.converter._dispatch(evtRootName + '.end', text, options, globals).getText();
|
||||
|
||||
|
@ -222,7 +231,7 @@
|
|||
text = globals.converter._dispatch(evtRootName + '.start', text, options, globals).getText();
|
||||
|
||||
var rgx = /\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g;
|
||||
text = text.replace(rgx, replaceAnchorTag(rgx, evtRootName, options, globals));
|
||||
text = text.replace(rgx, replaceAnchorTagReference(rgx, evtRootName, options, globals));
|
||||
|
||||
text = globals.converter._dispatch(evtRootName + '.end', text, options, globals).getText();
|
||||
|
||||
|
@ -238,7 +247,7 @@
|
|||
text = globals.converter._dispatch(evtRootName + '.start', text, options, globals).getText();
|
||||
|
||||
var rgx = /\[([^\[\]]+)]()()()()()/g;
|
||||
text = text.replace(rgx, replaceAnchorTag(rgx, evtRootName, options, globals));
|
||||
text = text.replace(rgx, replaceAnchorTagReference(rgx, evtRootName, options, globals));
|
||||
|
||||
text = globals.converter._dispatch(evtRootName + '.end', text, options, globals).getText();
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ showdown.subParser('makehtml.stripLinkDefinitions', function (text, options, glo
|
|||
// remove newlines
|
||||
globals.gUrls[linkId] = url.replace(/\s/g, '');
|
||||
} else {
|
||||
url = showdown.helper.applyBaseUrl(options.relativePathBaseUrl, url);
|
||||
|
||||
globals.gUrls[linkId] = showdown.subParser('makehtml.encodeAmpsAndAngles')(url, options, globals); // Link IDs are case-insensitive
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<p><a href="http://my.site.com/that_dude_mike.js">inline relative linky</a></p>
|
||||
<p><a href="ftp://wikis.com/micky.txt">inline absolute linky</a></p>
|
||||
<p><a href="http://my.site.com/painters/Michelangelo.html">global relative linky</a></p>
|
||||
<p><a href="https://www.my-wikis-site.com/peeps/Michelangelo.html">global absolute linky</a></p>
|
||||
<p><img src="http://my.site.com/mona-lisa.png" alt="inline relative image" /></p>
|
||||
<p><img src="http://images.com/mona-lisa.png" alt="inline absolute image" /></p>
|
||||
<p><img src="http://my.site.com/mona-lisa.png" alt="global relative image" /></p>
|
||||
<p><img src="https://www.my-photo-site.com/mona-lisa.png" alt="global absolute image" /></p>
|
||||
<p><a href="#holdin_it_down">just an anchor</a></p>
|
|
@ -0,0 +1,22 @@
|
|||
[inline relative linky](that_dude_mike.js)
|
||||
|
||||
[inline absolute linky](ftp://wikis.com/micky.txt)
|
||||
|
||||
[global relative linky][relative_linky]
|
||||
|
||||
[global absolute linky][absolute_linky]
|
||||
|
||||
![inline relative image](mona-lisa.png)
|
||||
|
||||
![inline absolute image](http://images.com/mona-lisa.png)
|
||||
|
||||
![global relative image][relative_image]
|
||||
|
||||
![global absolute image][absolute_image]
|
||||
|
||||
[just an anchor](#holdin_it_down)
|
||||
|
||||
[relative_linky]: painters/Michelangelo.html
|
||||
[relative_image]: ./mona-lisa.png
|
||||
[absolute_linky]: https://www.my-wikis-site.com/peeps/Michelangelo.html
|
||||
[absolute_image]: https://www.my-photo-site.com/mona-lisa.png
|
|
@ -95,6 +95,8 @@ describe('makeHtml() features testsuite', function () {
|
|||
converter = new showdown.Converter({openLinksInNewWindow: true});
|
||||
} else if (testsuite[i].name === '#355.simplifiedAutoLink-URLs-inside-parenthesis-followed-by-another-character-are-not-parsed-correctly') {
|
||||
converter = new showdown.Converter({simplifiedAutoLink: true});
|
||||
} else if (testsuite[i].name === 'relativePathBaseUrl') {
|
||||
converter = new showdown.Converter({relativePathBaseUrl: 'http://my.site.com/'});
|
||||
} else {
|
||||
converter = new showdown.Converter();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user