From 429e25864b86b7b5976348860a302c2843687ef4 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Thu, 8 Oct 2015 18:18:51 -0400 Subject: Modified markdown lexer to not break up words written in snake_case --- web/react/utils/markdown.jsx | 38 ++++++++++++++++++++++++++++++++++++- web/react/utils/text_formatting.jsx | 9 ++------- 2 files changed, 39 insertions(+), 8 deletions(-) (limited to 'web') diff --git a/web/react/utils/markdown.jsx b/web/react/utils/markdown.jsx index 26587dd6e..4fb4c6089 100644 --- a/web/react/utils/markdown.jsx +++ b/web/react/utils/markdown.jsx @@ -6,7 +6,31 @@ const Utils = require('./utils.jsx'); const marked = require('marked'); -export class MattermostMarkdownRenderer extends marked.Renderer { +class MattermostInlineLexer extends marked.InlineLexer { + constructor(links, options) { + super(links, options); + + // modified version of the regex that doesn't break up words in snake_case + // the original is /^[\s\S]+?(?=[\\ Date: Wed, 28 Oct 2015 14:21:47 -0400 Subject: Updated markdown regexes to better handle underscores and links --- web/react/utils/markdown.jsx | 52 ++++++++++++++++++++++++------------- web/react/utils/text_formatting.jsx | 23 ++++++---------- 2 files changed, 42 insertions(+), 33 deletions(-) (limited to 'web') diff --git a/web/react/utils/markdown.jsx b/web/react/utils/markdown.jsx index 4fb4c6089..e34f3d00a 100644 --- a/web/react/utils/markdown.jsx +++ b/web/react/utils/markdown.jsx @@ -10,9 +10,21 @@ class MattermostInlineLexer extends marked.InlineLexer { constructor(links, options) { super(links, options); - // modified version of the regex that doesn't break up words in snake_case - // the original is /^[\s\S]+?(?=[\\ starting with www. + // the original is /^<([^ >]+(@|:\/)[^ >]+)>/ + this.rules.autolink = /^<((?:[^ >]+(@|:\/)|www\.)[^ >]+)>/; } } @@ -56,8 +68,20 @@ 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); + } - if (!(/^(mailto|https?|ftp)/.test(outHref))) { + if (!(/[a-z+.-]+:/i).test(outHref)) { outHref = `http://${outHref}`; } @@ -72,26 +96,17 @@ class MattermostMarkdownRenderer extends marked.Renderer { output += ' target="_blank">'; } - output += text + ''; + output += outText + ''; - return output; + return prefix + output + suffix; } paragraph(text) { - let outText = text; - - // required so markdown does not strip '_' from @user_names - outText = TextFormatting.doFormatMentions(text); - - if (!('emoticons' in this.options) || this.options.emoticon) { - outText = TextFormatting.doFormatEmoticons(outText); - } - if (this.formattingOptions.singleline) { - return `

${outText}

`; + return `

${text}

`; } - return super.paragraph(outText); + return super.paragraph(text); } table(header, body) { @@ -106,7 +121,8 @@ class MattermostMarkdownRenderer extends marked.Renderer { export function format(text, options) { const markdownOptions = { renderer: new MattermostMarkdownRenderer(null, options), - sanitize: true + sanitize: true, + gfm: true }; const tokens = marked.lexer(text, markdownOptions); diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 9c87d2693..2de858a17 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -43,7 +43,7 @@ export function doFormatText(text, options) { // replace important words and phrases with tokens output = autolinkAtMentions(output, tokens); - output = autolinkUrls(output, tokens); + output = autolinkEmails(output, tokens); output = autolinkHashtags(output, tokens); if (!('emoticons' in options) || options.emoticon) { @@ -93,28 +93,21 @@ export function sanitizeHtml(text) { return output; } -// Convert URLs into tokens -function autolinkUrls(text, tokens) { - function replaceUrlWithToken(autolinker, match) { +// Convert emails into tokens +function autolinkEmails(text, tokens) { + function replaceEmailWithToken(autolinker, match) { const linkText = match.getMatchedText(); let url = linkText; if (match.getType() === 'email') { url = `mailto:${url}`; - } else if (!(/^(mailto|https?|ftp)/.test(url))) { - url = `http://${url}`; } const index = tokens.size; - const alias = `MM_LINK${index}`; - - var target = 'target="_blank"'; - if (url.lastIndexOf(Utils.getTeamURLFromAddressBar(), 0) === 0) { - target = ''; - } + const alias = `MM_EMAIL${index}`; tokens.set(alias, { - value: `${linkText}`, + value: `${linkText}`, originalText: linkText }); @@ -123,12 +116,12 @@ function autolinkUrls(text, tokens) { // we can't just use a static autolinker because we need to set replaceFn const autolinker = new Autolinker({ - urls: true, + urls: false, email: true, phone: false, twitter: false, hashtag: false, - replaceFn: replaceUrlWithToken + replaceFn: replaceEmailWithToken }); return autolinker.link(text); -- cgit v1.2.3-1-g7c22