From 1941275f93002f6ef5e4bb803c09a170234435a9 Mon Sep 17 00:00:00 2001 From: Bettenbuk Zoltan Date: Fri, 23 Aug 2019 16:41:10 +0200 Subject: [PATCH] feat: mobile chat emojis --- package-lock.json | 6 +- package.json | 2 +- react/features/base/util/helpers.js | 18 ++++++ .../chat/components/native/ChatMessage.js | 5 +- react/features/chat/functions.js | 55 +++++++++++++++++++ 5 files changed, 81 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 63365fac0..9f0132360 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13766,9 +13766,9 @@ } }, "react-emoji-render": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/react-emoji-render/-/react-emoji-render-0.4.6.tgz", - "integrity": "sha512-ARB8E4j/dndQxC7Bn4b+Oymt7pqhh9GjP87NYcxC8KONejysnXD5O9KpnJeW/U3Ke3+XsWrWAr9K5riVA6emfg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/react-emoji-render/-/react-emoji-render-1.0.0.tgz", + "integrity": "sha512-14iNQ1bOqijkIwfmuYMnG0lew2GJhRmSEPEYi7Dc3RDgklaXXwbLB0bmJF/0LUpDH1hy3I1H3EyrKb//FdwCmg==", "requires": { "classnames": "^2.2.5", "emoji-regex": "^6.4.1", diff --git a/package.json b/package.json index 0c529339e..9c8d2f1e9 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "postis": "2.2.0", "react": "16.8.6", "react-dom": "16.8.6", - "react-emoji-render": "0.4.6", + "react-emoji-render": "1.0.0", "react-i18next": "10.11.4", "react-linkify": "1.0.0-alpha", "react-native": "0.60.5", diff --git a/react/features/base/util/helpers.js b/react/features/base/util/helpers.js index 1f11fc879..e7e870d30 100644 --- a/react/features/base/util/helpers.js +++ b/react/features/base/util/helpers.js @@ -18,6 +18,24 @@ export function createDeferred(): Object { return deferred; } +const MATCH_OPERATOR_REGEXP = /[|\\{}()[\]^$+*?.-]/g; + +/** + * Escape RegExp special characters. + * + * Based on https://github.com/sindresorhus/escape-string-regexp. + * + * @param {string} s - The regexp string to escape. + * @returns {string} + */ +export function escapeRegexp(s: string) { + if (typeof s !== 'string') { + throw new TypeError('Expected a string'); + } + + return s.replace(MATCH_OPERATOR_REGEXP, '\\$&'); +} + /** * Returns the base URL of the app. * diff --git a/react/features/chat/components/native/ChatMessage.js b/react/features/chat/components/native/ChatMessage.js index 48f732ae8..1fa5d999e 100644 --- a/react/features/chat/components/native/ChatMessage.js +++ b/react/features/chat/components/native/ChatMessage.js @@ -7,7 +7,10 @@ import { Avatar } from '../../../base/avatar'; import { translate } from '../../../base/i18n'; import { Linkify } from '../../../base/react'; +import { replaceNonUnicodeEmojis } from '../../functions'; + import AbstractChatMessage, { type Props } from '../AbstractChatMessage'; + import styles from './styles'; /** @@ -60,7 +63,7 @@ class ChatMessage extends AbstractChatMessage { && this._renderDisplayName() } - { messageText } + { replaceNonUnicodeEmojis(messageText) } { this.props.showTimestamp && this._renderTimestamp() } diff --git a/react/features/chat/functions.js b/react/features/chat/functions.js index 47a1332fc..c28e85f7a 100644 --- a/react/features/chat/functions.js +++ b/react/features/chat/functions.js @@ -1,5 +1,60 @@ // @flow +import aliases from 'react-emoji-render/data/aliases'; +import emojiAsciiAliases from 'react-emoji-render/data/asciiAliases'; + +import { escapeRegexp } from '../base/util'; + +/** + * An ASCII emoticon regexp array to find and replace old-style ASCII + * emoticons (such as :O) to new Unicode representation, so then devices + * and browsers that support them can render these natively without + * a 3rd party component. + * + * NOTE: this is currently only used on mobile, but it can be used + * on web too once we drop support for browsers that don't support + * unicode emoji rendering. + */ +const EMOTICON_REGEXP_ARRAY: Array> = []; + +(function() { + for (const [ key, value ] of Object.entries(aliases)) { + let escapedValues; + const asciiEmojies = emojiAsciiAliases[key]; + + // Adding ascii emoticons + if (asciiEmojies) { + escapedValues = asciiEmojies.map(v => escapeRegexp(v)); + } else { + escapedValues = []; + } + + // Adding slack-type emoji format + escapedValues.push(escapeRegexp(`:${key}:`)); + + const regexp = `(${escapedValues.join('|')})`; + + EMOTICON_REGEXP_ARRAY.push([ new RegExp(regexp, 'g'), value ]); + } +})(); + +/** + * Replaces ascii and other non-unicode emoticons with unicode emojis to let the emojis be rendered + * by the platform native renderer. + * + * @param {string} message - The message to parse and replace. + * @returns {string} + */ +export function replaceNonUnicodeEmojis(message: string) { + let replacedMessage = message; + + for (const [ regexp, replaceValue ] of EMOTICON_REGEXP_ARRAY) { + replacedMessage = replacedMessage.replace(regexp, replaceValue); + } + + return replacedMessage; +} + /** * Selector for calculating the number of unread chat messages. *