From 208bf914b8a5efb3f4474361e4d247826b25788c Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 18 Sep 2015 11:29:52 -0400 Subject: Removed unnecessary conversion of newlines to html line breaks --- web/react/utils/text_formatting.jsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'web/react/utils') diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 54d010dbf..5bf3ca52c 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -33,7 +33,9 @@ export function formatText(text, options = {}) { output = replaceTokens(output, tokens); // replace newlines with html line breaks - output = replaceNewlines(output, options.singleline); + if (options.singleline) { + output = replaceNewlines(output); + } return output; } @@ -246,11 +248,7 @@ function replaceTokens(text, tokens) { return output; } -function replaceNewlines(text, singleline) { - if (!singleline) { - return text.replace(/\n/g, '
'); - } - +function replaceNewlines(text) { return text.replace(/\n/g, ' '); } -- cgit v1.2.3-1-g7c22 From ae5a1e3ea84fcde2cf0375c1cad778eab6f2634b Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 18 Sep 2015 11:31:39 -0400 Subject: Removed underscores surrounding formatting tokens since they won't work with markdown --- web/react/utils/text_formatting.jsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'web/react/utils') diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 5bf3ca52c..c00193e37 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -63,7 +63,7 @@ function autolinkUrls(text, tokens) { } const index = tokens.size; - const alias = `__MM_LINK${index}__`; + const alias = `MM_LINK${index}`; tokens.set(alias, { value: `${linkText}`, @@ -93,7 +93,7 @@ function autolinkAtMentions(text, tokens) { const usernameLower = username.toLowerCase(); if (Constants.SPECIAL_MENTIONS.indexOf(usernameLower) !== -1 || UserStore.getProfileByUsername(usernameLower)) { const index = tokens.size; - const alias = `__MM_ATMENTION${index}__`; + const alias = `MM_ATMENTION${index}`; tokens.set(alias, { value: `${mention}`, @@ -121,7 +121,7 @@ function highlightCurrentMentions(text, tokens) { for (const [alias, token] of tokens) { if (mentionKeys.indexOf(token.originalText) !== -1) { const index = tokens.size + newTokens.size; - const newAlias = `__MM_SELFMENTION${index}__`; + const newAlias = `MM_SELFMENTION${index}`; newTokens.set(newAlias, { value: `${alias}`, @@ -140,7 +140,7 @@ function highlightCurrentMentions(text, tokens) { // look for self mentions in the text function replaceCurrentMentionWithToken(fullMatch, prefix, mention) { const index = tokens.size; - const alias = `__MM_SELFMENTION${index}__`; + const alias = `MM_SELFMENTION${index}`; tokens.set(alias, { value: `${mention}`, @@ -164,7 +164,7 @@ function autolinkHashtags(text, tokens) { for (const [alias, token] of tokens) { if (token.originalText.lastIndexOf('#', 0) === 0) { const index = tokens.size + newTokens.size; - const newAlias = `__MM_HASHTAG${index}__`; + const newAlias = `MM_HASHTAG${index}`; newTokens.set(newAlias, { value: `${token.originalText}`, @@ -183,7 +183,7 @@ function autolinkHashtags(text, tokens) { // look for hashtags in the text function replaceHashtagWithToken(fullMatch, prefix, hashtag) { const index = tokens.size; - const alias = `__MM_HASHTAG${index}__`; + const alias = `MM_HASHTAG${index}`; tokens.set(alias, { value: `${hashtag}`, @@ -203,7 +203,7 @@ function highlightSearchTerm(text, tokens, searchTerm) { for (const [alias, token] of tokens) { if (token.originalText === searchTerm) { const index = tokens.size + newTokens.size; - const newAlias = `__MM_SEARCHTERM${index}__`; + const newAlias = `MM_SEARCHTERM${index}`; newTokens.set(newAlias, { value: `${alias}`, @@ -221,7 +221,7 @@ function highlightSearchTerm(text, tokens, searchTerm) { function replaceSearchTermWithToken(fullMatch, prefix, word) { const index = tokens.size; - const alias = `__MM_SEARCHTERM${index}__`; + const alias = `MM_SEARCHTERM${index}`; tokens.set(alias, { value: `${word}`, -- cgit v1.2.3-1-g7c22 From bb330b662a60c6581eda6dde0d94eb3a57579b15 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Fri, 18 Sep 2015 13:41:00 -0400 Subject: Added marked library to text_formatting.jsx --- web/react/utils/text_formatting.jsx | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'web/react/utils') diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index c00193e37..62e6978a9 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -6,6 +6,10 @@ const Constants = require('./constants.jsx'); const UserStore = require('../stores/user_store.jsx'); const Utils = require('./utils.jsx'); +const marked = require('marked'); + +const markdownRenderer = new marked.Renderer(); + // Performs formatting of user posts including highlighting mentions and search terms and converting urls, hashtags, and // @mentions to links by taking a user's message and returning a string of formatted html. Also takes a number of options // as part of the second parameter: @@ -29,6 +33,11 @@ export function formatText(text, options = {}) { output = highlightCurrentMentions(output, tokens); } + // perform markdown parsing while we have an html-free input string + console.log('output before marked ' + output); + output = marked(output, {renderer: markdownRenderer}); + console.log('output after marked ' + output); + // reinsert tokens with formatted versions of the important words and phrases output = replaceTokens(output, tokens); -- cgit v1.2.3-1-g7c22 From efb3462a683d1f4d88c56327b14256adda11115d Mon Sep 17 00:00:00 2001 From: hmhealey Date: Sat, 19 Sep 2015 10:31:48 -0400 Subject: Prevented our url autolinking from breaking markdown links --- web/react/utils/text_formatting.jsx | 40 +++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'web/react/utils') diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 62e6978a9..da0595326 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -17,11 +17,14 @@ const markdownRenderer = new marked.Renderer(); // - mentionHighlight - Specifies whether or not to highlight mentions of the current user. Defaults to true. // - singleline - Specifies whether or not to remove newlines. Defaults to false. export function formatText(text, options = {}) { + // TODO remove me + options.markdown = true; + let output = sanitizeHtml(text); const tokens = new Map(); // replace important words and phrases with tokens - output = autolinkUrls(output, tokens); + output = autolinkUrls(output, tokens, !!options.markdown); output = autolinkAtMentions(output, tokens); output = autolinkHashtags(output, tokens); @@ -34,9 +37,11 @@ export function formatText(text, options = {}) { } // perform markdown parsing while we have an html-free input string - console.log('output before marked ' + output); - output = marked(output, {renderer: markdownRenderer}); - console.log('output after marked ' + output); + if (options.markdown) { + console.log('output before marked ' + output); + output = marked(output, {renderer: markdownRenderer}); + console.log('output after marked ' + output); + } // reinsert tokens with formatted versions of the important words and phrases output = replaceTokens(output, tokens); @@ -62,7 +67,7 @@ export function sanitizeHtml(text) { return output; } -function autolinkUrls(text, tokens) { +function autolinkUrls(text, tokens, markdown) { function replaceUrlWithToken(autolinker, match) { const linkText = match.getMatchedText(); let url = linkText; @@ -92,7 +97,30 @@ function autolinkUrls(text, tokens) { replaceFn: replaceUrlWithToken }); - return autolinker.link(text); + let output = text; + + // temporarily replace markdown links if markdown is enabled so that we don't accidentally parse them twice + const markdownLinkTokens = new Map(); + if (markdown) { + function replaceMarkdownLinkWithToken(markdownLink) { + const index = markdownLinkTokens.size; + const alias = `MM_MARKDOWNLINK${index}`; + + markdownLinkTokens.set(alias, {value: markdownLink}); + + return alias; + } + + output = output.replace(/\]\([^\)]*\)/g, replaceMarkdownLinkWithToken); + } + + output = autolinker.link(output); + + if (markdown) { + output = replaceTokens(output, markdownLinkTokens); + } + + return output; } function autolinkAtMentions(text, tokens) { -- cgit v1.2.3-1-g7c22 From 2eb320f48a66b42832b758e5fc6700358aef34ed Mon Sep 17 00:00:00 2001 From: hmhealey Date: Sat, 19 Sep 2015 10:33:13 -0400 Subject: Changed markdown link parsing to automatically add an explicit protocol to urls --- web/react/utils/markdown.jsx | 14 ++++++++++++++ web/react/utils/text_formatting.jsx | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 web/react/utils/markdown.jsx (limited to 'web/react/utils') diff --git a/web/react/utils/markdown.jsx b/web/react/utils/markdown.jsx new file mode 100644 index 000000000..880e41a18 --- /dev/null +++ b/web/react/utils/markdown.jsx @@ -0,0 +1,14 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +const marked = require('marked'); + +export class MattermostMarkdownRenderer extends marked.Renderer { + link(href, title, text) { + if (href.lastIndexOf('http', 0) !== 0) { + href = `http://${href}`; + } + + return super.link(href, title, text); + } +} diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index da0595326..537ddb394 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -3,12 +3,13 @@ const Autolinker = require('autolinker'); const Constants = require('./constants.jsx'); +const Markdown = require('./markdown.jsx'); const UserStore = require('../stores/user_store.jsx'); const Utils = require('./utils.jsx'); const marked = require('marked'); -const markdownRenderer = new marked.Renderer(); +const markdownRenderer = new Markdown.MattermostMarkdownRenderer(); // Performs formatting of user posts including highlighting mentions and search terms and converting urls, hashtags, and // @mentions to links by taking a user's message and returning a string of formatted html. Also takes a number of options -- cgit v1.2.3-1-g7c22 From 5f18c71d07e8ea0ac3f9053ad0a67c5380e613ef Mon Sep 17 00:00:00 2001 From: hmhealey Date: Sat, 19 Sep 2015 11:01:38 -0400 Subject: Deferred to marked.js's html sanitization when markdown is enabled --- web/react/utils/text_formatting.jsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'web/react/utils') diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 537ddb394..47b56cc3c 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -21,7 +21,14 @@ export function formatText(text, options = {}) { // TODO remove me options.markdown = true; - let output = sanitizeHtml(text); + // wait until marked can sanitize the html so that we don't break markdown block quotes + let output; + if (!options.markdown) { + output = sanitizeHtml(text); + } else { + output = text; + } + const tokens = new Map(); // replace important words and phrases with tokens @@ -40,7 +47,10 @@ export function formatText(text, options = {}) { // perform markdown parsing while we have an html-free input string if (options.markdown) { console.log('output before marked ' + output); - output = marked(output, {renderer: markdownRenderer}); + output = marked(output, { + renderer: markdownRenderer, + sanitize: true + }); console.log('output after marked ' + output); } -- cgit v1.2.3-1-g7c22 From 144a277a44350af14993d439b3bd9999f75e84e7 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Sat, 19 Sep 2015 11:08:39 -0400 Subject: Cleaned up markdown formatting code and removed debug statements --- web/react/utils/markdown.jsx | 8 +++++--- web/react/utils/text_formatting.jsx | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'web/react/utils') diff --git a/web/react/utils/markdown.jsx b/web/react/utils/markdown.jsx index 880e41a18..8c63810cd 100644 --- a/web/react/utils/markdown.jsx +++ b/web/react/utils/markdown.jsx @@ -5,10 +5,12 @@ const marked = require('marked'); export class MattermostMarkdownRenderer extends marked.Renderer { link(href, title, text) { - if (href.lastIndexOf('http', 0) !== 0) { - href = `http://${href}`; + let outHref = href; + + if (outHref.lastIndexOf('http', 0) !== 0) { + outHref = `http://${outHref}`; } - return super.link(href, title, text); + return super.link(outHref, title, text); } } diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 47b56cc3c..4e390f708 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -17,9 +17,11 @@ const markdownRenderer = new Markdown.MattermostMarkdownRenderer(); // - searchTerm - If specified, this word is highlighted in the resulting html. Defaults to nothing. // - mentionHighlight - Specifies whether or not to highlight mentions of the current user. Defaults to true. // - singleline - Specifies whether or not to remove newlines. Defaults to false. +// - markdown - Enables markdown parsing. Defaults to true. export function formatText(text, options = {}) { - // TODO remove me - options.markdown = true; + if (!('markdown' in options)) { + options.markdown = true; + } // wait until marked can sanitize the html so that we don't break markdown block quotes let output; @@ -46,12 +48,10 @@ export function formatText(text, options = {}) { // perform markdown parsing while we have an html-free input string if (options.markdown) { - console.log('output before marked ' + output); output = marked(output, { renderer: markdownRenderer, sanitize: true }); - console.log('output after marked ' + output); } // reinsert tokens with formatted versions of the important words and phrases -- cgit v1.2.3-1-g7c22