Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

fix regional emojis converted to flags #9294

Merged
merged 29 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
028760a
fix regional emojis converted to flags
grimhilt Sep 16, 2022
59590eb
Merge branch 'develop' into regional-emojis
t3chguy Sep 20, 2022
b114390
add test and typing to c
grimhilt Sep 21, 2022
d637a47
Merge branch 'regional-emojis' of github-grimhilt:grimhilt/matrix-rea…
grimhilt Sep 21, 2022
5cf6683
fix conflicts
grimhilt Sep 21, 2022
2a72496
better test
grimhilt Sep 24, 2022
a17f382
forgot small changes in parts-test
grimhilt Sep 24, 2022
796289e
Merge branch 'develop' of https://github.com/matrix-org/matrix-react-…
grimhilt Sep 24, 2022
828cb09
small improvement
grimhilt Sep 24, 2022
6a1048b
use zero width space
grimhilt Sep 30, 2022
237905c
forgot lint
grimhilt Sep 30, 2022
4421e37
rename and combine regex
grimhilt Oct 7, 2022
e8c8fa3
Merge branch 'develop' of https://github.com/matrix-org/matrix-react-…
grimhilt Oct 7, 2022
bfd97f7
Update src/HtmlUtils.tsx
duxovni Oct 8, 2022
f7cf343
Merge branch 'develop' into regional-emojis
duxovni Oct 8, 2022
66bdc95
Fix codepoint range
duxovni Oct 8, 2022
2c6f8d2
improve existing test
grimhilt Oct 8, 2022
2f75f76
Merge branch 'develop' into regional-emojis
t3chguy Oct 10, 2022
b0389f9
Merge branch 'matrix-org:develop' into regional-emojis
grimhilt Oct 15, 2022
4193709
Merge branch 'regional-emojis' of github-grimhilt:grimhilt/matrix-rea…
grimhilt Oct 15, 2022
0a3a208
Merge branch 'develop' into regional-emojis
t3chguy Oct 19, 2022
f4d230a
Merge remote-tracking branch 'matrix/develop' into regional-emojis
grimhilt Nov 13, 2022
1db5a93
add cypress test
grimhilt Nov 14, 2022
9b27471
fix some typescript error
grimhilt Nov 14, 2022
4152aa6
fix more tsc type error
grimhilt Nov 15, 2022
a90cf76
Remove ` in favor of " and wait for element instead of using delay
grimhilt Dec 14, 2022
2d8aa96
fix conflicts
grimhilt Dec 14, 2022
3707d09
Merge branch 'develop' into regional-emojis
grimhilt Jan 5, 2023
19ddf56
apply prettier formatting
grimhilt Jan 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions cypress/e2e/timeline/timeline.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,5 +383,24 @@ describe("Timeline", () => {
1,
);
});

it("should not be possible to send flag with regional emojis", () => {
cy.visit("/#/room/" + roomId);

// Send a message
cy.getComposer().type(":regional_indicator_a");
cy.contains(".mx_Autocomplete_Completion_title", ":regional_indicator_a:").click();
cy.getComposer().type(":regional_indicator_r");
cy.contains(".mx_Autocomplete_Completion_title", ":regional_indicator_r:").click();
cy.getComposer().type(" :regional_indicator_z");
cy.contains(".mx_Autocomplete_Completion_title", ":regional_indicator_z:").click();
cy.getComposer().type(":regional_indicator_a");
cy.contains(".mx_Autocomplete_Completion_title", ":regional_indicator_a:").click();
cy.getComposer().type("{enter}");

cy.get(".mx_RoomView_body .mx_EventTile .mx_EventTile_line .mx_MTextBody .mx_EventTile_bigEmoji")
.children()
.should("have.length", 4);
});
});
});
20 changes: 7 additions & 13 deletions src/HtmlUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -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 =
Expand Down
20 changes: 17 additions & 3 deletions src/editor/parts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,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;
Expand Down Expand Up @@ -210,9 +212,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;
}
Expand Down Expand Up @@ -622,8 +628,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
Expand All @@ -634,6 +645,9 @@ export class PartCreator {
plainText = "";
}
parts.push(this.emoji(char));
if (PartCreator.isRegionalIndicator(text)) {
parts.push(this.plain(REGIONAL_EMOJI_SEPARATOR));
}
} else {
plainText += char;
}
Expand Down
28 changes: 28 additions & 0 deletions test/editor/model-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,4 +348,32 @@ describe("editor/model", function () {
expect(model.parts[0].text).toBe("foo@a");
});
});
describe("emojis", function () {
it("regional emojis should be separated to prevent them to be converted to flag", () => {
const renderer = createRenderer();
const pc = createPartCreator();
const model = new EditorModel([], pc, renderer);
const regionalEmojiA = String.fromCodePoint(127462);
const regionalEmojiZ = String.fromCodePoint(127487);
const caret = new DocumentOffset(0, true);

const regionalEmojis: string[] = [];
regionalEmojis.push(regionalEmojiA);
regionalEmojis.push(regionalEmojiZ);
for (let i = 0; i < 2; i++) {
const position = model.positionForOffset(caret.offset, caret.atNodeEnd);
model.transform(() => {
const addedLen = model.insert(pc.plainWithEmoji(regionalEmojis[i]), position);
caret.offset += addedLen;
return model.positionForOffset(caret.offset, true);
});
}

expect(model.parts.length).toBeGreaterThanOrEqual(4);
expect(model.parts[0].type).toBe("emoji");
expect(model.parts[1].type).not.toBe("emoji");
expect(model.parts[2].type).toBe("emoji");
expect(model.parts[3].type).not.toBe("emoji");
});
});
});