From 537acefb2dfdcb387dc34207ef7f8b3821b29e8b Mon Sep 17 00:00:00 2001 From: Mattermost Build Date: Fri, 28 Aug 2020 13:16:24 -0400 Subject: [PATCH] MM-25684 Highlight at-mention followed by a period (#4733) (#4747) * MM-25684 Highlight at-mention followed by a period * Refactor at_mention to not highlight the period * Do not add a link for invalid mentions * Suggested review Co-authored-by: Miguel Alatzar Co-authored-by: Miguel Alatzar (cherry picked from commit 1d0fc0510c852a3c462bd348d81b63aa54338d68) Co-authored-by: Elias Nahum --- .../__snapshots__/at_mention.test.js.snap | 39 ++++++++++-- app/components/at_mention/at_mention.js | 63 ++++++++++++------- app/components/at_mention/at_mention.test.js | 1 + app/components/markdown/transform.js | 8 +-- app/components/markdown/transform.test.js | 24 +++++++ 5 files changed, 100 insertions(+), 35 deletions(-) diff --git a/app/components/at_mention/__snapshots__/at_mention.test.js.snap b/app/components/at_mention/__snapshots__/at_mention.test.js.snap index 0ce3a4bdb..47405ba7c 100644 --- a/app/components/at_mention/__snapshots__/at_mention.test.js.snap +++ b/app/components/at_mention/__snapshots__/at_mention.test.js.snap @@ -1,8 +1,21 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`AtMention should match snapshot, no highlight 1`] = ` - - @John.Smith + + + @John.Smith + `; @@ -10,9 +23,17 @@ exports[`AtMention should match snapshot, with highlight 1`] = ` @John.Smith @@ -24,12 +45,18 @@ exports[`AtMention should match snapshot, without highlight 1`] = ` @Victor.Welch diff --git a/app/components/at_mention/at_mention.js b/app/components/at_mention/at_mention.js index 43c0f5abe..76c661e11 100644 --- a/app/components/at_mention/at_mention.js +++ b/app/components/at_mention/at_mention.js @@ -3,17 +3,16 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {Text} from 'react-native'; +import {StyleSheet, Text} from 'react-native'; import Clipboard from '@react-native-community/clipboard'; import {intlShape} from 'react-intl'; import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; +import {showModal} from '@actions/navigation'; import {displayUsername} from '@mm-redux/utils/user_utils'; - -import CustomPropTypes from 'app/constants/custom_prop_types'; +import CustomPropTypes from '@constants/custom_prop_types'; import mattermostManaged from 'app/mattermost_managed'; -import BottomSheet from 'app/utils/bottom_sheet'; -import {showModal} from 'app/actions/navigation'; +import BottomSheet from '@utils/bottom_sheet'; export default class AtMention extends React.PureComponent { static propTypes = { @@ -142,37 +141,53 @@ export default class AtMention extends React.PureComponent { render() { const {isSearchResult, mentionName, mentionStyle, onPostPress, teammateNameDisplay, textStyle, mentionKeys} = this.props; const {user} = this.state; + const {backgroundColor, ...styleText} = StyleSheet.flatten(textStyle); + let canPress = false; let highlighted; + let mention; + let suffix; - if (!user.username) { + if (user?.username) { + suffix = this.props.mentionName.substring(user.username.length); + highlighted = mentionKeys.some((item) => item.key === user.username); + mention = displayUsername(user, teammateNameDisplay); + canPress = true; + } else { const group = this.getGroupFromMentionName(); if (group.allow_reference) { highlighted = mentionKeys.some((item) => item.key === group.name); - return ( - - - {`@${group.name}`} - - - ); - } + mention = group.name; + suffix = this.props.mentionName.substring(group.name.length); + } else { + const pattern = new RegExp(/(all|channel|here)\.?/, 'i'); + const mentionMatch = pattern.exec(mentionName); - return {'@' + mentionName}; + if (mentionMatch) { + highlighted = false; + mention = mentionMatch.length > 1 ? mentionMatch[1] : mentionMatch[0]; + suffix = mentionName.replace(mention, ''); + } else { + highlighted = true; + mention = mentionName; + } + } } - const suffix = this.props.mentionName.substring(user.username.length); - highlighted = mentionKeys.some((item) => item.key === user.username); + let onPress; + let onLongPress; + if (canPress) { + onLongPress = this.handleLongPress; + onPress = isSearchResult ? onPostPress : this.goToUserProfile; + } return ( - - {'@' + displayUsername(user, teammateNameDisplay)} + + {'@' + mention} {suffix} diff --git a/app/components/at_mention/at_mention.test.js b/app/components/at_mention/at_mention.test.js index 293abac02..5090d3acf 100644 --- a/app/components/at_mention/at_mention.test.js +++ b/app/components/at_mention/at_mention.test.js @@ -12,6 +12,7 @@ describe('AtMention', () => { teammateNameDisplay: '', mentionName: 'John.Smith', mentionStyle: {color: '#ff0000'}, + textStyle: {backgroundColor: 'yellow'}, theme: {}, }; diff --git a/app/components/markdown/transform.js b/app/components/markdown/transform.js index 48b0847a9..7a5643c04 100644 --- a/app/components/markdown/transform.js +++ b/app/components/markdown/transform.js @@ -281,12 +281,10 @@ export function highlightMentions(ast, mentionKeys) { } else if (node.type === 'at_mention') { const matches = mentionKeys.some((mention) => { const mentionName = '@' + node.mentionName; + const flags = mention.caseSensitive ? '' : 'i'; + const pattern = new RegExp(`${escapeRegex(mention.key)}\\.?`, flags); - if (mention.caseSensitive) { - return mention.key === mentionName; - } - - return mention.key.toLowerCase() === mentionName.toLowerCase(); + return pattern.test(mentionName); }); if (!matches) { diff --git a/app/components/markdown/transform.test.js b/app/components/markdown/transform.test.js index 1f155d836..93e07ca89 100644 --- a/app/components/markdown/transform.test.js +++ b/app/components/markdown/transform.test.js @@ -2751,6 +2751,30 @@ describe('Components.Markdown.transform', () => { }], }], }, + }, { + name: 'Mention followed by a period', + input: 'This is a mention for @channel.', + mentionKeys: [{key: 'channel'}], + expected: { + type: 'document', + children: [{ + type: 'paragraph', + children: [{ + type: 'text', + literal: 'This is a mention for ', + }, { + type: 'mention_highlight', + children: [{ + type: 'at_mention', + _mentionName: 'channel.', + children: [{ + type: 'text', + literal: '@channel.', + }], + }], + }], + }], + }, }]; for (const test of tests) {