From a7e583717825b47142d9877472ad177a6afbe04d Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Tue, 1 Nov 2016 17:58:44 -0400 Subject: PLT-4454 Autolink anything that looks like an at mention (#4416) * PLT-4454 Added autolinking for anything that looks like an at mention * PLT-4454 Added unit tests for at mention autolinking --- webapp/tests/formatting_at_mentions.test.jsx | 81 ++++++++++++++++++++++++++++ webapp/utils/text_formatting.jsx | 34 ++++-------- 2 files changed, 92 insertions(+), 23 deletions(-) create mode 100644 webapp/tests/formatting_at_mentions.test.jsx (limited to 'webapp') diff --git a/webapp/tests/formatting_at_mentions.test.jsx b/webapp/tests/formatting_at_mentions.test.jsx new file mode 100644 index 000000000..babcb2ca9 --- /dev/null +++ b/webapp/tests/formatting_at_mentions.test.jsx @@ -0,0 +1,81 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import assert from 'assert'; + +import * as TextFormatting from 'utils/text_formatting.jsx'; + +describe('TextFormatting.AtMentions', function() { + this.timeout(10000); + + it('At mentions', function() { + assert.equal( + TextFormatting.autolinkAtMentions('@user', new Map(), {user: {}}), + 'MM_ATMENTION0', + 'should replace explicit mention with token' + ); + + assert.equal( + TextFormatting.autolinkAtMentions('abc"@user"def', new Map(), {user: {}}), + 'abc"MM_ATMENTION0"def', + 'should replace explicit mention surrounded by punctuation with token' + ); + + assert.equal( + TextFormatting.autolinkAtMentions('@user1 @user2', new Map(), {user1: {}, user2: {}}), + 'MM_ATMENTION0 MM_ATMENTION1', + 'should replace multiple explicit mentions with tokens' + ); + + assert.equal( + TextFormatting.autolinkAtMentions('@us_-e.r', new Map(), {'us_-e.r': {}}), + 'MM_ATMENTION0', + 'should replace multiple explicit mentions containing punctuation with token' + ); + + assert.equal( + TextFormatting.autolinkAtMentions('@us_-e.r', new Map(), {'us_-e.r': {}}), + 'MM_ATMENTION0', + 'should replace multiple explicit mentions containing valid punctuation with token' + ); + + assert.equal( + TextFormatting.autolinkAtMentions('@user.', new Map(), {user: {}}), + 'MM_ATMENTION0.', + 'should replace explicit mention followed by period with token' + ); + + assert.equal( + TextFormatting.autolinkAtMentions('@user.', new Map(), {'user.': {}}), + 'MM_ATMENTION0', + 'should replace explicit mention ending with period with token' + ); + }); + + it('Implied at mentions', function() { + // PLT-4454 Assume users exist for things that look like at mentions until we support the new mention syntax + assert.equal( + TextFormatting.autolinkAtMentions('@user', new Map(), {}), + 'MM_ATMENTION0', + 'should imply user exists and replace mention with token' + ); + + assert.equal( + TextFormatting.autolinkAtMentions('@user.', new Map(), {}), + 'MM_ATMENTION0.', + 'should assume username doesn\'t end in punctuation' + ); + }); + + it('Not at mentions', function() { + assert.equal( + TextFormatting.autolinkAtMentions('user@host', new Map(), {user: {}, host: {}}), + 'user@host' + ); + + assert.equal( + TextFormatting.autolinkAtMentions('user@email.com', new Map(), {user: {}, email: {}}), + 'user@email.com' + ); + }); +}); diff --git a/webapp/utils/text_formatting.jsx b/webapp/utils/text_formatting.jsx index 9834f4b9b..dbd6a4e32 100644 --- a/webapp/utils/text_formatting.jsx +++ b/webapp/utils/text_formatting.jsx @@ -152,7 +152,7 @@ function autolinkEmails(text, tokens) { const punctuation = XRegExp.cache('[^\\pL\\d]'); -function autolinkAtMentions(text, tokens, usernameMap) { +export function autolinkAtMentions(text, tokens, usernameMap) { // Test if provided text needs to be highlighted, special mention or current user function mentionExists(u) { return (Constants.SPECIAL_MENTIONS.indexOf(u) !== -1 || Boolean(usernameMap[u])); @@ -169,30 +169,18 @@ function autolinkAtMentions(text, tokens, usernameMap) { return alias; } - function replaceAtMentionWithToken(fullMatch, mention, username) { - let usernameLower = username.toLowerCase(); - - if (mentionExists(usernameLower)) { - // Exact match - const alias = addToken(usernameLower, mention, ''); - return alias; - } - - // Not an exact match, attempt to truncate any punctuation to see if we can find a user - const originalUsername = usernameLower; + function replaceAtMentionWithToken(fullMatch, prefix, mention, username) { + const usernameLower = username.toLowerCase(); + // Check if the text makes up an explicit mention, possible trimming extra punctuation from the end of the name if necessary for (let c = usernameLower.length; c > 0; c--) { - if (punctuation.test(usernameLower[c - 1])) { - usernameLower = usernameLower.substring(0, c - 1); + const truncated = usernameLower.substring(0, c); + const suffix = usernameLower.substring(c); - if (mentionExists(usernameLower)) { - const suffix = originalUsername.substr(c - 1); - const alias = addToken(usernameLower, '@' + usernameLower); - return alias + suffix; - } - } else { - // If the last character is not punctuation, no point in going any further - break; + // If we've found a username or run out of punctuation to trim off, render it as an at mention + if (mentionExists(truncated) || !punctuation.test(truncated[truncated.length - 1])) { + const alias = addToken(truncated, '@' + truncated); + return prefix + alias + suffix; } } @@ -200,7 +188,7 @@ function autolinkAtMentions(text, tokens, usernameMap) { } let output = text; - output = output.replace(/(@([a-z0-9.\-_]*))/gi, replaceAtMentionWithToken); + output = output.replace(/(^|\W)(@([a-z0-9.\-_]*))/gi, replaceAtMentionWithToken); return output; } -- cgit v1.2.3-1-g7c22