Remove emoji, mentions and links when calculating text direction
This commit is contained in:
parent
07cc399550
commit
50222558bf
2 changed files with 70 additions and 1 deletions
|
@ -5,6 +5,8 @@ import { identity, isEqual, isNumber, isObject, map, omit, pick } from 'lodash';
|
||||||
import { createSelector, createSelectorCreator } from 'reselect';
|
import { createSelector, createSelectorCreator } from 'reselect';
|
||||||
import filesize from 'filesize';
|
import filesize from 'filesize';
|
||||||
import getDirection from 'direction';
|
import getDirection from 'direction';
|
||||||
|
import emojiRegex from 'emoji-regex';
|
||||||
|
import LinkifyIt from 'linkify-it';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
LastMessageStatus,
|
LastMessageStatus,
|
||||||
|
@ -93,6 +95,7 @@ import { DAY, HOUR } from '../../util/durations';
|
||||||
import { getStoryReplyText } from '../../util/getStoryReplyText';
|
import { getStoryReplyText } from '../../util/getStoryReplyText';
|
||||||
|
|
||||||
const THREE_HOURS = 3 * HOUR;
|
const THREE_HOURS = 3 * HOUR;
|
||||||
|
const linkify = LinkifyIt();
|
||||||
|
|
||||||
type FormattedContact = Partial<ConversationType> &
|
type FormattedContact = Partial<ConversationType> &
|
||||||
Pick<
|
Pick<
|
||||||
|
@ -716,12 +719,44 @@ function getTextAttachment(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function cleanBodyForDirectionCheck(text: string): string {
|
||||||
|
const MENTIONS_REGEX = /\uFFFC/g;
|
||||||
|
const EMOJI_REGEX = emojiRegex();
|
||||||
|
const initial = text.replace(MENTIONS_REGEX, '').replace(EMOJI_REGEX, '');
|
||||||
|
|
||||||
|
const linkMatches = linkify.match(initial);
|
||||||
|
|
||||||
|
if (!linkMatches || linkMatches.length === 0) {
|
||||||
|
return initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = '';
|
||||||
|
let lastIndex = 0;
|
||||||
|
|
||||||
|
linkMatches.forEach(match => {
|
||||||
|
if (lastIndex < match.index) {
|
||||||
|
result += initial.slice(lastIndex, match.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop the actual contents of the match
|
||||||
|
|
||||||
|
lastIndex = match.lastIndex;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (lastIndex < initial.length) {
|
||||||
|
result += initial.slice(lastIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
function getTextDirection(body?: string): TextDirection {
|
function getTextDirection(body?: string): TextDirection {
|
||||||
if (!body) {
|
if (!body) {
|
||||||
return TextDirection.None;
|
return TextDirection.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
const direction = getDirection(body);
|
const cleaned = cleanBodyForDirectionCheck(body);
|
||||||
|
const direction = getDirection(cleaned);
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case 'ltr':
|
case 'ltr':
|
||||||
return TextDirection.LeftToRight;
|
return TextDirection.LeftToRight;
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
canDeleteForEveryone,
|
canDeleteForEveryone,
|
||||||
canReact,
|
canReact,
|
||||||
canReply,
|
canReply,
|
||||||
|
cleanBodyForDirectionCheck,
|
||||||
getMessagePropStatus,
|
getMessagePropStatus,
|
||||||
isEndSession,
|
isEndSession,
|
||||||
isGroupUpdate,
|
isGroupUpdate,
|
||||||
|
@ -29,6 +30,39 @@ describe('state/selectors/messages', () => {
|
||||||
ourConversationId = uuid();
|
ourConversationId = uuid();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('cleanBodyForDirectionCheck', () => {
|
||||||
|
it('drops emoji', () => {
|
||||||
|
const body = "😮😮😮😮 that's wild!";
|
||||||
|
const expected = " that's wild!";
|
||||||
|
const actual = cleanBodyForDirectionCheck(body);
|
||||||
|
assert.strictEqual(actual, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('drops mentions', () => {
|
||||||
|
const body = "heyo, how's it going \uFFFC? And \uFFFC too!";
|
||||||
|
const expected = "heyo, how's it going ? And too!";
|
||||||
|
const actual = cleanBodyForDirectionCheck(body);
|
||||||
|
assert.strictEqual(actual, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('drops links', () => {
|
||||||
|
const body =
|
||||||
|
'You should download it from https://signal.org/download. Then read something on https://signal.org/blog. Then donate at https://signal.org/donate.';
|
||||||
|
const expected =
|
||||||
|
'You should download it from . Then read something on . Then donate at .';
|
||||||
|
const actual = cleanBodyForDirectionCheck(body);
|
||||||
|
assert.strictEqual(actual, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('drops all of them at the same time', () => {
|
||||||
|
const body =
|
||||||
|
'https://signal.org/download 😮 \uFFFC Did you really join Signal?';
|
||||||
|
const expected = ' Did you really join Signal?';
|
||||||
|
const actual = cleanBodyForDirectionCheck(body);
|
||||||
|
assert.strictEqual(actual, expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('canDeleteForEveryone', () => {
|
describe('canDeleteForEveryone', () => {
|
||||||
it('returns false for incoming messages', () => {
|
it('returns false for incoming messages', () => {
|
||||||
const message = {
|
const message = {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue