fix regional emojis converted to flags (#9294)

Co-authored-by: grimhilt <grimhilt@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: Faye Duxovni <duxovni@duxovni.org>
Co-authored-by: Faye Duxovni <fayed@element.io>
Fixes https://github.com/vector-im/element-web/issues/19000
This commit is contained in:
grimhilt 2023-01-31 14:08:35 +01:00 committed by GitHub
parent 262c2fcff2
commit 5a08859e37
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 16 deletions

View file

@ -49,11 +49,8 @@ const SURROGATE_PAIR_PATTERN = /([\ud800-\udbff])([\udc00-\udfff])/;
// (with plenty of false positives, but that's OK)
const SYMBOL_PATTERN = /([\u2100-\u2bff])/;
// Regex pattern for Zero-Width joiner unicode characters
const ZWJ_REGEX = /[\u200D\u2003]/g;
// Regex pattern for whitespace characters
const WHITESPACE_REGEX = /\s/g;
// Regex pattern for non-emoji characters that can appear in an "all-emoji" message (Zero-Width Joiner, Zero-Width Space, other whitespace)
const EMOJI_SEPARATOR_REGEX = /[\u200D\u200B\s]/g;
const BIGEMOJI_REGEX = new RegExp(`^(${EMOJIBASE_REGEX.source})+$`, "i");
@ -591,14 +588,11 @@ export function bodyToHtml(content: IContent, highlights: Optional<string[]>, op
if (!opts.disableBigEmoji && bodyHasEmoji) {
let contentBodyTrimmed = contentBody !== undefined ? contentBody.trim() : "";
// Ignore spaces in body text. Emojis with spaces in between should
// still be counted as purely emoji messages.
contentBodyTrimmed = contentBodyTrimmed.replace(WHITESPACE_REGEX, "");
// Remove zero width joiner characters from emoji messages. This ensures
// that emojis that are made up of multiple unicode characters are still
// presented as large.
contentBodyTrimmed = contentBodyTrimmed.replace(ZWJ_REGEX, "");
// Remove zero width joiner, zero width spaces and other spaces in body
// text. This ensures that emojis with spaces in between or that are made
// up of multiple unicode characters are still counted as purely emoji
// messages.
contentBodyTrimmed = contentBodyTrimmed.replace(EMOJI_SEPARATOR_REGEX, "");
const match = BIGEMOJI_REGEX.exec(contentBodyTrimmed);
emojiBody =

View file

@ -27,6 +27,8 @@ import defaultDispatcher from "../dispatcher/dispatcher";
import { Action } from "../dispatcher/actions";
import SettingsStore from "../settings/SettingsStore";
const REGIONAL_EMOJI_SEPARATOR = String.fromCodePoint(0x200b);
interface ISerializedPart {
type: Type.Plain | Type.Newline | Type.Emoji | Type.Command | Type.PillCandidate;
text: string;
@ -209,9 +211,13 @@ abstract class PlainBasePart extends BasePart {
return false;
}
// or split if the previous character is a space
// or split if the previous character is a space or regional emoji separator
// or if it is a + and this is a :
return this._text[offset - 1] !== " " && (this._text[offset - 1] !== "+" || chr !== ":");
return (
this._text[offset - 1] !== " " &&
this._text[offset - 1] !== REGIONAL_EMOJI_SEPARATOR &&
(this._text[offset - 1] !== "+" || chr !== ":")
);
}
return true;
}
@ -626,8 +632,13 @@ export class PartCreator {
return new UserPillPart(userId, displayName, member);
}
private static isRegionalIndicator(c: string): boolean {
const codePoint = c.codePointAt(0) ?? 0;
return codePoint != 0 && c.length == 2 && 0x1f1e6 <= codePoint && codePoint <= 0x1f1ff;
}
public plainWithEmoji(text: string): (PlainPart | EmojiPart)[] {
const parts = [];
const parts: (PlainPart | EmojiPart)[] = [];
let plainText = "";
// We use lodash's grapheme splitter to avoid breaking apart compound emojis
@ -638,6 +649,9 @@ export class PartCreator {
plainText = "";
}
parts.push(this.emoji(char));
if (PartCreator.isRegionalIndicator(text)) {
parts.push(this.plain(REGIONAL_EMOJI_SEPARATOR));
}
} else {
plainText += char;
}