summaryrefslogtreecommitdiffstats
path: root/web/react/utils/text_formatting.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/utils/text_formatting.jsx')
-rw-r--r--web/react/utils/text_formatting.jsx74
1 files changed, 58 insertions, 16 deletions
diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx
index 5c2e68f1e..9f1a5a53f 100644
--- a/web/react/utils/text_formatting.jsx
+++ b/web/react/utils/text_formatting.jsx
@@ -47,8 +47,8 @@ export function doFormatText(text, options) {
const tokens = new Map();
// replace important words and phrases with tokens
- output = autolinkUrls(output, tokens);
output = autolinkAtMentions(output, tokens);
+ output = autolinkUrls(output, tokens);
output = autolinkHashtags(output, tokens);
if (!('emoticons' in options) || options.emoticon) {
@@ -78,6 +78,13 @@ export function doFormatEmoticons(text) {
return output;
}
+export function doFormatMentions(text) {
+ const tokens = new Map();
+ let output = autolinkAtMentions(text, tokens);
+ output = replaceTokens(output, tokens);
+ return output;
+}
+
export function sanitizeHtml(text) {
let output = text;
@@ -91,6 +98,7 @@ export function sanitizeHtml(text) {
return output;
}
+// Convert URLs into tokens
function autolinkUrls(text, tokens) {
function replaceUrlWithToken(autolinker, match) {
const linkText = match.getMatchedText();
@@ -132,26 +140,61 @@ function autolinkUrls(text, tokens) {
}
function autolinkAtMentions(text, tokens) {
- let output = text;
+ // Return true if provided character is punctuation
+ function isPunctuation(character) {
+ const re = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@\[\]^_`{|}~]/g;
+ return re.test(character);
+ }
+
+ // Test if provided text needs to be highlighted, special mention or current user
+ function mentionExists(u) {
+ return (Constants.SPECIAL_MENTIONS.indexOf(u) !== -1 || UserStore.getProfileByUsername(u));
+ }
+
+ function addToken(username, mention, extraText) {
+ const index = tokens.size;
+ const alias = `MM_ATMENTION${index}`;
+
+ tokens.set(alias, {
+ value: `<a class='mention-link' href='#' data-mention='${username}'>${mention}</a>`,
+ originalText: mention,
+ extraText
+ });
+ return alias;
+ }
function replaceAtMentionWithToken(fullMatch, prefix, mention, username) {
- const usernameLower = username.toLowerCase();
- if (Constants.SPECIAL_MENTIONS.indexOf(usernameLower) !== -1 || UserStore.getProfileByUsername(usernameLower)) {
- const index = tokens.size;
- const alias = `MM_ATMENTION${index}`;
-
- tokens.set(alias, {
- value: `<a class='mention-link' href='#' data-mention='${usernameLower}'>${mention}</a>`,
- originalText: mention
- });
+ let usernameLower = username.toLowerCase();
+ if (mentionExists(usernameLower)) {
+ // Exact match
+ const alias = addToken(usernameLower, mention, '');
return prefix + alias;
}
+ // Not an exact match, attempt to truncate any punctuation to see if we can find a user
+ const originalUsername = usernameLower;
+
+ for (let c = usernameLower.length; c > 0; c--) {
+ if (isPunctuation(usernameLower[c - 1])) {
+ usernameLower = usernameLower.substring(0, c - 1);
+
+ if (mentionExists(usernameLower)) {
+ const extraText = originalUsername.substr(c - 1);
+ const alias = addToken(usernameLower, '@' + usernameLower, extraText);
+ return prefix + alias;
+ }
+ } else {
+ // If the last character is not punctuation, no point in going any further
+ break;
+ }
+ }
+
return fullMatch;
}
- output = output.replace(/(^|\s)(@([a-z0-9.\-_]*[a-z0-9]))/gi, replaceAtMentionWithToken);
+ let output = text;
+ output = output.replace(/(^|\s)(@([a-z0-9.\-_]*))/gi, replaceAtMentionWithToken);
return output;
}
@@ -169,10 +212,9 @@ function highlightCurrentMentions(text, tokens) {
const newAlias = `MM_SELFMENTION${index}`;
newTokens.set(newAlias, {
- value: `<span class='mention-highlight'>${alias}</span>`,
+ value: `<span class='mention-highlight'>${alias}</span>` + token.extraText,
originalText: token.originalText
});
-
output = output.replace(alias, newAlias);
}
}
@@ -246,7 +288,7 @@ function highlightSearchTerm(text, tokens, searchTerm) {
var newTokens = new Map();
for (const [alias, token] of tokens) {
- if (token.originalText === searchTerm) {
+ if (token.originalText.indexOf(searchTerm.replace(/\*$/, '')) > -1) {
const index = tokens.size + newTokens.size;
const newAlias = `MM_SEARCHTERM${index}`;
@@ -276,7 +318,7 @@ function highlightSearchTerm(text, tokens, searchTerm) {
return prefix + alias;
}
- return output.replace(new RegExp(`(^|\\W)(${searchTerm})\\b`, 'gi'), replaceSearchTermWithToken);
+ return output.replace(new RegExp(`()(${searchTerm})`, 'gi'), replaceSearchTermWithToken);
}
function replaceTokens(text, tokens) {