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 <migbot@users.noreply.github.com>

Co-authored-by: Miguel Alatzar <migbot@users.noreply.github.com>
(cherry picked from commit 1d0fc0510c)

Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
This commit is contained in:
Mattermost Build 2020-08-28 13:16:24 -04:00 committed by GitHub
parent dccdf1a238
commit 537acefb2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 100 additions and 35 deletions

View file

@ -1,8 +1,21 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AtMention should match snapshot, no highlight 1`] = `
<Text>
@John.Smith
<Text
style={Object {}}
>
<Text
style={
Array [
null,
Object {
"backgroundColor": "yellow",
},
]
}
>
@John.Smith
</Text>
</Text>
`;
@ -10,9 +23,17 @@ exports[`AtMention should match snapshot, with highlight 1`] = `
<Text
onLongPress={[Function]}
onPress={[Function]}
style={Object {}}
>
<Text
style={null}
style={
Array [
null,
Object {
"backgroundColor": "yellow",
},
]
}
>
@John.Smith
</Text>
@ -24,12 +45,18 @@ exports[`AtMention should match snapshot, without highlight 1`] = `
<Text
onLongPress={[Function]}
onPress={[Function]}
style={Object {}}
>
<Text
style={
Object {
"color": "#ff0000",
}
Array [
Object {
"color": "#ff0000",
},
Object {
"backgroundColor": "yellow",
},
]
}
>
@Victor.Welch

View file

@ -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 (
<Text
style={textStyle}
>
<Text style={highlighted ? null : mentionStyle}>
{`@${group.name}`}
</Text>
</Text>
);
}
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 <Text style={textStyle}>{'@' + mentionName}</Text>;
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 (
<Text
style={textStyle}
onPress={isSearchResult ? onPostPress : this.goToUserProfile}
onLongPress={this.handleLongPress}
style={styleText}
onPress={onPress}
onLongPress={onLongPress}
>
<Text style={highlighted ? null : mentionStyle}>
{'@' + displayUsername(user, teammateNameDisplay)}
<Text style={[highlighted ? null : mentionStyle, {backgroundColor}]}>
{'@' + mention}
</Text>
{suffix}
</Text>

View file

@ -12,6 +12,7 @@ describe('AtMention', () => {
teammateNameDisplay: '',
mentionName: 'John.Smith',
mentionStyle: {color: '#ff0000'},
textStyle: {backgroundColor: 'yellow'},
theme: {},
};

View file

@ -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) {

View file

@ -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) {