diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index 2266522bfe..2b7384a5aa 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -53,7 +53,6 @@ const ZWJ_REGEX = new RegExp("\u200D|\u2003", "g"); const WHITESPACE_REGEX = new RegExp("\\s", "g"); const BIGEMOJI_REGEX = new RegExp(`^(${EMOJIBASE_REGEX.source})+$`, 'i'); -const SINGLE_EMOJI_REGEX = new RegExp(`^(${EMOJIBASE_REGEX.source})$`, 'i'); const COLOR_REGEX = /^#[0-9a-fA-F]{6}$/; @@ -72,6 +71,21 @@ function mightContainEmoji(str) { return SURROGATE_PAIR_PATTERN.test(str) || SYMBOL_PATTERN.test(str); } +/** + * Find emoji data in emojibase by character. + * + * @param {String} char The emoji character + * @return {Object} The emoji data + */ +export function findEmojiData(char) { + // Check against both the char and the char with an empty variation selector + // appended because that's how emojibase stores its base emojis which have + // variations. + // See also https://github.com/vector-im/riot-web/issues/9785. + const emptyVariation = char + VARIATION_SELECTOR; + return EMOJIBASE.find(e => e.unicode === char || e.unicode === emptyVariation); +} + /** * Returns the shortcode for an emoji character. * @@ -79,10 +93,7 @@ function mightContainEmoji(str) { * @return {String} The shortcode (such as :thumbup:) */ export function unicodeToShortcode(char) { - // Check against both the char and the char with an empty variation selector appended because that's how - // emoji-base stores its base emojis which have variations. https://github.com/vector-im/riot-web/issues/9785 - const emptyVariation = char + VARIATION_SELECTOR; - const data = EMOJIBASE.find(e => e.unicode === char || e.unicode === emptyVariation); + const data = findEmojiData(char); return (data && data.shortcodes ? `:${data.shortcodes[0]}:` : ''); } diff --git a/src/components/views/emojipicker/EmojiPicker.js b/src/components/views/emojipicker/EmojiPicker.js index 48713b90d8..9fe8b4c81e 100644 --- a/src/components/views/emojipicker/EmojiPicker.js +++ b/src/components/views/emojipicker/EmojiPicker.js @@ -48,7 +48,14 @@ const DATA_BY_CATEGORY = { }; const DATA_BY_EMOJI = {}; +const VARIATION_SELECTOR = String.fromCharCode(0xFE0F); EMOJIBASE.forEach(emoji => { + if (emoji.unicode.includes(VARIATION_SELECTOR)) { + // Clone data into variation-less version + emoji = Object.assign({}, emoji, { + unicode: emoji.unicode.replace(VARIATION_SELECTOR, ""), + }); + } DATA_BY_EMOJI[emoji.unicode] = emoji; const categoryId = EMOJIBASE_CATEGORY_IDS[emoji.group]; if (DATA_BY_CATEGORY.hasOwnProperty(categoryId)) { @@ -82,7 +89,10 @@ class EmojiPicker extends React.Component { viewportHeight: 280, }; - this.recentlyUsed = recent.get().map(unicode => DATA_BY_EMOJI[unicode]); + // Convert recent emoji characters to emoji data, removing unknowns. + this.recentlyUsed = recent.get() + .map(unicode => DATA_BY_EMOJI[unicode]) + .filter(data => !!data); this.memoizedDataByCategory = { recent: this.recentlyUsed, ...DATA_BY_CATEGORY, diff --git a/src/components/views/emojipicker/QuickReactions.js b/src/components/views/emojipicker/QuickReactions.js index 71a53984cc..8444fb2d9c 100644 --- a/src/components/views/emojipicker/QuickReactions.js +++ b/src/components/views/emojipicker/QuickReactions.js @@ -16,17 +16,19 @@ limitations under the License. import React from 'react'; import PropTypes from 'prop-types'; -import EMOJIBASE from 'emojibase-data/en/compact.json'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; +import { findEmojiData } from '../../../HtmlUtils'; -const QUICK_REACTIONS = ["👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀"]; -EMOJIBASE.forEach(emoji => { - const index = QUICK_REACTIONS.indexOf(emoji.unicode); - if (index !== -1) { - QUICK_REACTIONS[index] = emoji; +const QUICK_REACTIONS = ["👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀"].map(emoji => { + const data = findEmojiData(emoji); + if (!data) { + throw new Error(`Emoji ${emoji} doesn't exist in emojibase`); } + // Prefer our unicode value for quick reactions (which does not have + // variation selectors). + return Object.assign({}, data, { unicode: emoji }); }); class QuickReactions extends React.Component {