feat: Add support for markdown in messages (#1642)

Co-authored-by: Pranav <pranav@chatwoot.com>
This commit is contained in:
Nithin David Thomas 2021-01-15 14:40:50 +05:30 committed by GitHub
parent 5adbc84e0c
commit a5c3c4301c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 208 additions and 40 deletions

View file

@ -1,4 +1,7 @@
import marked from 'marked';
import DOMPurify from 'dompurify';
import { escapeHtml } from './HTMLSanitizer';
const TWITTER_USERNAME_REGEX = /(^|[^@\w])@(\w{1,15})\b/g;
const TWITTER_USERNAME_REPLACEMENT =
'$1<a href="http://twitter.com/$2" target="_blank" rel="noreferrer nofollow noopener">@$2</a>';
@ -9,41 +12,49 @@ const TWITTER_HASH_REPLACEMENT =
class MessageFormatter {
constructor(message, isATweet = false) {
this.message = escapeHtml(message || '') || '';
this.message = DOMPurify.sanitize(escapeHtml(message) || '');
this.isATweet = isATweet;
this.marked = marked;
const renderer = {
heading(text) {
return `<strong>${text}</strong>`;
},
link(url, title, text) {
return `<a rel="noreferrer noopener nofollow" href="${url}" class="link" title="${title ||
''}" target="_blank">${text}</a>`;
},
};
this.marked.use({ renderer });
}
formatMessage() {
const linkifiedMessage = this.linkify();
const messageWithNextLines = linkifiedMessage.replace(/\n/g, '<br>');
if (this.isATweet) {
const messageWithUserName = messageWithNextLines.replace(
const withUserName = this.message.replace(
TWITTER_USERNAME_REGEX,
TWITTER_USERNAME_REPLACEMENT
);
return messageWithUserName.replace(
const withHash = withUserName.replace(
TWITTER_HASH_REGEX,
TWITTER_HASH_REPLACEMENT
);
const markedDownOutput = marked(withHash);
return markedDownOutput;
}
return messageWithNextLines;
}
linkify() {
if (!this.message) {
return '';
}
const urlRegex = /(https?:\/\/[^\s]+)/g;
return this.message.replace(
urlRegex,
url =>
`<a rel="noreferrer noopener nofollow" href="${url}" class="link" target="_blank">${url}</a>`
);
return marked(this.message);
}
get formattedMessage() {
return this.formatMessage();
}
get plainText() {
const strippedOutHtml = new DOMParser().parseFromString(
this.formattedMessage,
'text/html'
);
return strippedOutHtml.body.textContent || '';
}
}
export default MessageFormatter;