mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 19:48:08 +00:00
feat: Add support for markdown in messages (#1642)
Co-authored-by: Pranav <pranav@chatwoot.com>
This commit is contained in:
committed by
GitHub
parent
5adbc84e0c
commit
a5c3c4301c
@@ -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;
|
||||
|
||||
@@ -4,9 +4,25 @@ describe('#MessageFormatter', () => {
|
||||
describe('content with links', () => {
|
||||
it('should format correctly', () => {
|
||||
const message =
|
||||
'Chatwoot is an opensource tool\nSee more at https://www.chatwoot.com';
|
||||
expect(new MessageFormatter(message).formattedMessage).toEqual(
|
||||
'Chatwoot is an opensource tool<br>See more at <a rel="noreferrer noopener nofollow" href="https://www.chatwoot.com" class="link" target="_blank">https://www.chatwoot.com</a>'
|
||||
'Chatwoot is an opensource tool. [Chatwoot](https://www.chatwoot.com)';
|
||||
expect(new MessageFormatter(message).formattedMessage).toMatch(
|
||||
'<p>Chatwoot is an opensource tool. <a rel="noreferrer noopener nofollow" href="https://www.chatwoot.com" class="link" title="" target="_blank">Chatwoot</a></p>'
|
||||
);
|
||||
});
|
||||
it('should format correctly', () => {
|
||||
const message =
|
||||
'Chatwoot is an opensource tool. https://www.chatwoot.com';
|
||||
expect(new MessageFormatter(message).formattedMessage).toMatch(
|
||||
'<p>Chatwoot is an opensource tool. <a rel="noreferrer noopener nofollow" href="https://www.chatwoot.com" class="link" title="" target="_blank">https://www.chatwoot.com</a></p>'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parses heading to strong', () => {
|
||||
it('should format correctly', () => {
|
||||
const message = '### opensource \n ## tool';
|
||||
expect(new MessageFormatter(message).formattedMessage).toMatch(
|
||||
'<strong>opensource</strong><strong>tool</strong>'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -14,21 +30,31 @@ describe('#MessageFormatter', () => {
|
||||
describe('tweets', () => {
|
||||
it('should return the same string if not tags or @mentions', () => {
|
||||
const message = 'Chatwoot is an opensource tool';
|
||||
expect(new MessageFormatter(message).formattedMessage).toEqual(message);
|
||||
expect(new MessageFormatter(message).formattedMessage).toMatch(message);
|
||||
});
|
||||
|
||||
it('should add links to @mentions', () => {
|
||||
const message =
|
||||
'@chatwootapp is an opensource tool thanks @longnonexistenttwitterusername';
|
||||
expect(new MessageFormatter(message, true).formattedMessage).toEqual(
|
||||
'<a href="http://twitter.com/chatwootapp" target="_blank" rel="noreferrer nofollow noopener">@chatwootapp</a> is an opensource tool thanks @longnonexistenttwitterusername'
|
||||
expect(new MessageFormatter(message, true).formattedMessage).toMatch(
|
||||
'<p><a href="http://twitter.com/chatwootapp" target="_blank" rel="noreferrer nofollow noopener">@chatwootapp</a> is an opensource tool thanks @longnonexistenttwitterusername</p>'
|
||||
);
|
||||
});
|
||||
|
||||
it('should add links to #tags', () => {
|
||||
const message = '#chatwootapp is an opensource tool';
|
||||
expect(new MessageFormatter(message, true).formattedMessage).toEqual(
|
||||
'<a href="https://twitter.com/hashtag/chatwootapp" target="_blank" rel="noreferrer nofollow noopener">#chatwootapp</a> is an opensource tool'
|
||||
expect(new MessageFormatter(message, true).formattedMessage).toMatch(
|
||||
'<p><a href="https://twitter.com/hashtag/chatwootapp" target="_blank" rel="noreferrer nofollow noopener">#chatwootapp</a> is an opensource tool</p>'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('plain text content', () => {
|
||||
it('returns the plain text without HTML', () => {
|
||||
const message =
|
||||
'<b>Chatwoot is an opensource tool. https://www.chatwoot.com</b>';
|
||||
expect(new MessageFormatter(message).plainText).toMatch(
|
||||
'Chatwoot is an opensource tool. https://www.chatwoot.com'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user