diff --git a/README.md b/README.md index 833a274..d7730c3 100644 --- a/README.md +++ b/README.md @@ -210,7 +210,7 @@ var defaultOptions = showdown.getDefaultOptions();

foo

``` - * **simplifiedAutoLink**: (boolean) [default false] Turning this on will enable GFM autolink style. This means that + * **simplifiedAutoLink**: (boolean) [default false] Turning this option on will enable automatic linking to urls. This means that ```md some text www.google.com @@ -219,6 +219,17 @@ var defaultOptions = showdown.getDefaultOptions(); ````

some text www.google.com ``` + + * **excludeTrailingPunctuationFromURLs**: (boolean) [default false] This option excludes trailing punctuation from autolinking urls. + Punctuation excluded: `. ! ? ( )`. Only applies if **simplifiedAutoLink** option is set to `true`. + + ```md + check this link www.google.com! + ``` + will be parsed as + ```html +

check this link www.google.com!

+ ``` * **literalMidWordUnderscores**: (boolean) [default false] Turning this on will stop showdown from interpreting underscores in the middle of words as `` and `` and instead treat them as literal underscores. diff --git a/dist/showdown.js b/dist/showdown.js index 1a6716c..4f9b208 100644 Binary files a/dist/showdown.js and b/dist/showdown.js differ diff --git a/dist/showdown.js.map b/dist/showdown.js.map index 47da287..48868f6 100644 Binary files a/dist/showdown.js.map and b/dist/showdown.js.map differ diff --git a/dist/showdown.min.js b/dist/showdown.min.js index 9832e0a..7e6668e 100644 Binary files a/dist/showdown.min.js and b/dist/showdown.min.js differ diff --git a/dist/showdown.min.js.map b/dist/showdown.min.js.map index 9d46f6c..5c4352e 100644 Binary files a/dist/showdown.min.js.map and b/dist/showdown.min.js.map differ diff --git a/src/options.js b/src/options.js index 307260e..6e075a1 100644 --- a/src/options.js +++ b/src/options.js @@ -36,6 +36,11 @@ function getDefaultOpts(simple) { describe: 'Turn on/off GFM autolink style', type: 'boolean' }, + excludeTrailingPunctuationFromURLs: { + defaultValue: false, + describe: 'Excludes trailing punctuation from links generated with autoLinking', + type: 'boolean' + }, literalMidWordUnderscores: { defaultValue: false, describe: 'Parse midword underscores as literal underscores', diff --git a/src/showdown.js b/src/showdown.js index 42ab14f..ed64ee8 100644 --- a/src/showdown.js +++ b/src/showdown.js @@ -12,6 +12,7 @@ var showdown = {}, omitExtraWLInCodeBlocks: true, prefixHeaderId: 'user-content-', simplifiedAutoLink: true, + excludeTrailingPunctuationFromURLs: true, literalMidWordUnderscores: true, strikethrough: true, tables: true, diff --git a/src/subParsers/autoLinks.js b/src/subParsers/autoLinks.js index 4772150..0d5583d 100644 --- a/src/subParsers/autoLinks.js +++ b/src/subParsers/autoLinks.js @@ -3,9 +3,10 @@ showdown.subParser('autoLinks', function (text, options, globals) { text = globals.converter._dispatch('autoLinks.before', text, options, globals); - var simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)(?=\s|$)(?!["<>])/gi, + var simpleURLRegex = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)()(?=\s|$)(?!["<>])/gi, + simpleURLRegex2 = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?()]?)(?=\s|$)(?!["<>])/gi, delimUrlRegex = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)>/gi, - simpleMailRegex = /(?:^|\s)([A-Za-z0-9!#$%&'*+-/=?^_`\{|}~\.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?:$|\s)/gi, + simpleMailRegex = /(?:^|\s)([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?:$|\s)/gi, delimMailRegex = /<(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi; text = text.replace(delimUrlRegex, replaceLink); @@ -14,20 +15,28 @@ showdown.subParser('autoLinks', function (text, options, globals) { // Email addresses: if (options.simplifiedAutoLink) { - text = text.replace(simpleURLRegex, replaceLink); + if (options.excludeTrailingPunctuationFromURLs) { + text = text.replace(simpleURLRegex2, replaceLink); + } else { + text = text.replace(simpleURLRegex, replaceLink); + } text = text.replace(simpleMailRegex, replaceMail); } - function replaceLink(wm, link) { - var lnkTxt = link; + function replaceLink(wm, link, m2, m3, trailingPunctuation) { + var lnkTxt = link, + append = ''; if (/^www\./i.test(link)) { link = link.replace(/^www\./i, 'http://www.'); } - return '' + lnkTxt + ''; + if (options.excludeTrailingPunctuationFromURLs && trailingPunctuation) { + append = trailingPunctuation; + } + return '' + lnkTxt + '' + append; } - function replaceMail(wholeMatch, m1) { - var unescapedStr = showdown.subParser('unescapeSpecialChars')(m1); + function replaceMail(wholeMatch, mail) { + var unescapedStr = showdown.subParser('unescapeSpecialChars')(mail); return showdown.subParser('encodeEmailAddress')(unescapedStr); } diff --git a/test/features/excludeTrailingPunctuationFromURLs-option.html b/test/features/excludeTrailingPunctuationFromURLs-option.html new file mode 100644 index 0000000..6b33489 --- /dev/null +++ b/test/features/excludeTrailingPunctuationFromURLs-option.html @@ -0,0 +1,4 @@ +

url http://www.google.com.

+

url http://www.google.com!

+

url http://www.google.com? foo

+

url (http://www.google.com) bazinga

diff --git a/test/features/excludeTrailingPunctuationFromURLs-option.md b/test/features/excludeTrailingPunctuationFromURLs-option.md new file mode 100644 index 0000000..c5fcdd6 --- /dev/null +++ b/test/features/excludeTrailingPunctuationFromURLs-option.md @@ -0,0 +1,7 @@ +url http://www.google.com. + +url http://www.google.com! + +url http://www.google.com? foo + +url (http://www.google.com) bazinga diff --git a/test/node/testsuite.features.js b/test/node/testsuite.features.js index 6831cce..c1a13d6 100644 --- a/test/node/testsuite.features.js +++ b/test/node/testsuite.features.js @@ -37,6 +37,8 @@ describe('makeHtml() features testsuite', function () { converter = new showdown.Converter({disableForced4SpacesIndentedSublists: true}); } else if (testsuite[i].name === '#206.treat-single-line-breaks-as-br') { converter = new showdown.Converter({simpleLineBreaks: true}); + } else if (testsuite[i].name === 'excludeTrailingPunctuationFromURLs-option') { + converter = new showdown.Converter({simplifiedAutoLink: true, excludeTrailingPunctuationFromURLs: true}); } else { converter = new showdown.Converter(); }