diff options
Diffstat (limited to 'webapp')
-rw-r--r-- | webapp/package.json | 2 | ||||
-rw-r--r-- | webapp/utils/markdown.jsx | 52 |
2 files changed, 50 insertions, 4 deletions
diff --git a/webapp/package.json b/webapp/package.json index df699b773..ccc88c18c 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -16,7 +16,7 @@ "jasny-bootstrap": "3.1.3", "jquery": "2.2.3", "keymirror": "0.1.1", - "marked": "mattermost/marked#43e7e590944ea308a4d36f21917118d51a261e74", + "marked": "mattermost/marked#cb85e5cc81bc7937dbb73c3c53d9532b1b97e3ca", "match-at": "0.1.0", "mattermost": "mattermost/mattermost-javascript#master", "object-assign": "4.1.0", diff --git a/webapp/utils/markdown.jsx b/webapp/utils/markdown.jsx index 69b18faee..2ddd3fe11 100644 --- a/webapp/utils/markdown.jsx +++ b/webapp/utils/markdown.jsx @@ -13,6 +13,40 @@ function markdownImageLoaded(image) { } window.markdownImageLoaded = markdownImageLoaded; +class MattermostInlineLexer extends marked.InlineLexer { + constructor(links, options) { + super(links, options); + + this.rules = Object.assign({}, this.rules); + + // modified version of the regex that allows for links starting with www and those surrounded by parentheses + // the original is /^[\s\S]+?(?=[\\<!\[_*`~]|https?:\/\/| {2,}\n|$)/ + this.rules.text = /^[\s\S]+?(?=[\\<!\[_*`~]|https?:\/\/|www\.|\(| {2,}\n|$)/; + + // modified version of the regex that allows links starting with www and those surrounded by parentheses + // the original is /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/ + this.rules.url = /^(\(?(?:https?:\/\/|www\.)[^\s<.][^\s<]*[^<.,:;"'\]\s])/; + + // modified version of the regex that allows <links> starting with www. + // the original is /^<([^ >]+(@|:\/)[^ >]+)>/ + this.rules.autolink = /^<((?:[^ >]+(@|:\/)|www\.)[^ >]+)>/; + } +} + +class MattermostParser extends marked.Parser { + parse(src) { + this.inline = new MattermostInlineLexer(src.links, this.options, this.renderer); + this.tokens = src.reverse(); + + var out = ''; + while (this.next()) { + out += this.tok(); + } + + return out; + } +} + class MattermostMarkdownRenderer extends marked.Renderer { constructor(options, formattingOptions = {}) { super(options); @@ -75,6 +109,18 @@ class MattermostMarkdownRenderer extends marked.Renderer { link(href, title, text) { let outHref = href; + let outText = text; + let prefix = ''; + let suffix = ''; + + // some links like https://en.wikipedia.org/wiki/Rendering_(computer_graphics) contain brackets + // and we try our best to differentiate those from ones just wrapped in brackets when autolinking + if (outHref.startsWith('(') && outHref.endsWith(')') && text === outHref) { + prefix = '('; + suffix = ')'; + outText = text.substring(1, text.length - 1); + outHref = outHref.substring(1, outHref.length - 1); + } try { const unescaped = decodeURIComponent(unescape(href)).replace(/[^\w:]/g, '').toLowerCase(); @@ -103,9 +149,9 @@ class MattermostMarkdownRenderer extends marked.Renderer { output += ' title="' + title + '"'; } - output += '>' + text + '</a>'; + output += '>' + outText + '</a>'; - return output; + return prefix + output + suffix; } paragraph(text) { @@ -440,7 +486,7 @@ export function format(text, options) { const tokens = new MattermostLexer(markdownOptions).lex(text); - return new marked.Parser(markdownOptions).parse(tokens); + return new MattermostParser(markdownOptions).parse(tokens); } // Marked helper functions that should probably just be exported |