From 028760a97df4fc48441590a41fa1a44121d2da1e Mon Sep 17 00:00:00 2001 From: grimhilt Date: Fri, 16 Sep 2022 17:49:13 +0200 Subject: [PATCH 01/16] fix regional emojis converted to flags --- src/editor/parts.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/editor/parts.ts b/src/editor/parts.ts index 8d98c398b54..86dc24f4836 100644 --- a/src/editor/parts.ts +++ b/src/editor/parts.ts @@ -32,6 +32,8 @@ import defaultDispatcher from "../dispatcher/dispatcher"; import { Action } from "../dispatcher/actions"; import SettingsStore from "../settings/SettingsStore"; +const HAIR_SPACE = String.fromCodePoint(0x200A); + interface ISerializedPart { type: Type.Plain | Type.Newline | Type.Emoji | Type.Command | Type.PillCandidate; text: string; @@ -214,9 +216,9 @@ 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 a hair space // or if it is a + and this is a : - return this._text[offset - 1] !== " " && + return (this._text[offset - 1] !== " " && this._text[offset - 1] !== HAIR_SPACE) && (this._text[offset - 1] !== "+" || chr !== ":"); } return true; @@ -631,6 +633,10 @@ export class PartCreator { return new UserPillPart(userId, displayName, member); } + private static isRegionalIndicator(c): boolean { + return c.length == 2 && 127462 < c.codePointAt() && c.codePointAt() < 127488; + } + public plainWithEmoji(text: string): (PlainPart | EmojiPart)[] { const parts = []; let plainText = ""; @@ -643,6 +649,9 @@ export class PartCreator { plainText = ""; } parts.push(this.emoji(char)); + if (PartCreator.isRegionalIndicator(text)) { + parts.push(this.plain(HAIR_SPACE)); + } } else { plainText += char; } From b1143904ad47655c83071e72056dc4b045716f78 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Wed, 21 Sep 2022 22:21:30 +0200 Subject: [PATCH 02/16] add test and typing to c --- src/editor/parts.ts | 4 ++-- test/editor/parts-test.ts | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/editor/parts.ts b/src/editor/parts.ts index 86dc24f4836..a918e45c379 100644 --- a/src/editor/parts.ts +++ b/src/editor/parts.ts @@ -633,8 +633,8 @@ export class PartCreator { return new UserPillPart(userId, displayName, member); } - private static isRegionalIndicator(c): boolean { - return c.length == 2 && 127462 < c.codePointAt() && c.codePointAt() < 127488; + private static isRegionalIndicator(c: string): boolean { + return c.length == 2 && 127462 < c.codePointAt(0) && c.codePointAt(0) < 127488; } public plainWithEmoji(text: string): (PlainPart | EmojiPart)[] { diff --git a/test/editor/parts-test.ts b/test/editor/parts-test.ts index b77971c2aa7..078ec5b9cd5 100644 --- a/test/editor/parts-test.ts +++ b/test/editor/parts-test.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { EmojiPart, PlainPart } from "../../src/editor/parts"; +import { EmojiPart, PlainPart, PartCreator } from "../../src/editor/parts"; describe("editor/parts", () => { describe("appendUntilRejected", () => { @@ -32,4 +32,16 @@ describe("editor/parts", () => { expect(part.text).toEqual(femaleFacepalmEmoji); }); }); + + describe("plainWithEmoji", () => { + it("should append an hair space after a regional emoji", () => { + const regionalEmojiF = String.fromCodePoint(127467); + const hairSpace = String.fromCodePoint(0x200A); + const part = new PartCreator(null, null); + const parts = part.plainWithEmoji(regionalEmojiF); + expect(parts.length).toBe(2); + expect(parts[0].text).toBe(regionalEmojiF); + expect(parts[1].text).toBe(hairSpace); + }); + }); }); From 2a72496a96d5a2480690edb58a7c7e5eb1818600 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Sat, 24 Sep 2022 15:51:08 +0200 Subject: [PATCH 03/16] better test --- test/editor/model-test.ts | 23 +++++++++++++++++++++++ test/editor/parts-test.ts | 12 +----------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/test/editor/model-test.ts b/test/editor/model-test.ts index 6b3bd8fb2ca..08c570cb430 100644 --- a/test/editor/model-test.ts +++ b/test/editor/model-test.ts @@ -321,4 +321,27 @@ 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 { partCreator } = model; + const regionalEmojiF = String.fromCodePoint(127467); + const caret = new DocumentOffset(0, true); + + for (let i = 0; i < 2; i++) { + const position = model.positionForOffset(caret.offset, caret.atNodeEnd); + model.transform(() => { + const addedLen = model.insert(partCreator.plainWithEmoji(regionalEmojiF), position); + caret.offset += addedLen; + return model.positionForOffset(caret.offset, true); + }); + } + + expect(model.parts.length).toBeGreaterThanOrEqual(2); + expect(model.parts[0].type).toBe("emoji"); + expect(model.parts[1].type).not.toBe("emoji"); + }); + }); }); diff --git a/test/editor/parts-test.ts b/test/editor/parts-test.ts index e5405e37a98..ff7bff3fa52 100644 --- a/test/editor/parts-test.ts +++ b/test/editor/parts-test.ts @@ -33,17 +33,7 @@ describe("editor/parts", () => { expect(part.text).toEqual(femaleFacepalmEmoji); }); }); - describe("plainWithEmoji", () => { - it("should append an hair space after a regional emoji", () => { - const regionalEmojiF = String.fromCodePoint(127467); - const hairSpace = String.fromCodePoint(0x200A); - const part = new PartCreator(null, null); - const parts = part.plainWithEmoji(regionalEmojiF); - expect(parts.length).toBe(2); - expect(parts[0].text).toBe(regionalEmojiF); - expect(parts[1].text).toBe(hairSpace); - }); - }); + it("should not explode on room pills for unknown rooms", () => { const pc = createPartCreator(); const part = pc.roomPill("#room:server"); From a17f382affc66152806a0d592cf33f039827aa76 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Sat, 24 Sep 2022 15:52:47 +0200 Subject: [PATCH 04/16] forgot small changes in parts-test --- test/editor/parts-test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/editor/parts-test.ts b/test/editor/parts-test.ts index ff7bff3fa52..534221ece3a 100644 --- a/test/editor/parts-test.ts +++ b/test/editor/parts-test.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { EmojiPart, PlainPart, PartCreator } from "../../src/editor/parts"; +import { EmojiPart, PlainPart } from "../../src/editor/parts"; import { createPartCreator } from "./mock"; describe("editor/parts", () => { @@ -33,7 +33,7 @@ describe("editor/parts", () => { expect(part.text).toEqual(femaleFacepalmEmoji); }); }); - + it("should not explode on room pills for unknown rooms", () => { const pc = createPartCreator(); const part = pc.roomPill("#room:server"); From 828cb09446611a5ba0000809682a0d676ea1784b Mon Sep 17 00:00:00 2001 From: grimhilt Date: Sat, 24 Sep 2022 18:30:56 +0200 Subject: [PATCH 05/16] small improvement --- test/editor/model-test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/editor/model-test.ts b/test/editor/model-test.ts index 08c570cb430..fbfdb4a76af 100644 --- a/test/editor/model-test.ts +++ b/test/editor/model-test.ts @@ -326,14 +326,13 @@ describe('editor/model', function() { const renderer = createRenderer(); const pc = createPartCreator(); const model = new EditorModel([], pc, renderer); - const { partCreator } = model; const regionalEmojiF = String.fromCodePoint(127467); const caret = new DocumentOffset(0, true); for (let i = 0; i < 2; i++) { const position = model.positionForOffset(caret.offset, caret.atNodeEnd); model.transform(() => { - const addedLen = model.insert(partCreator.plainWithEmoji(regionalEmojiF), position); + const addedLen = model.insert(pc.plainWithEmoji(regionalEmojiF), position); caret.offset += addedLen; return model.positionForOffset(caret.offset, true); }); From 6a1048b7f7b8ae39446de9e1533adb85fc5c17bd Mon Sep 17 00:00:00 2001 From: grimhilt Date: Fri, 30 Sep 2022 18:33:23 +0200 Subject: [PATCH 06/16] use zero width space --- src/HtmlUtils.tsx | 2 +- src/editor/parts.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 15fc2e075ef..c0f35052b70 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -50,7 +50,7 @@ const SURROGATE_PAIR_PATTERN = /([\ud800-\udbff])([\udc00-\udfff])/; const SYMBOL_PATTERN = /([\u2100-\u2bff])/; // Regex pattern for Zero-Width joiner unicode characters -const ZWJ_REGEX = /[\u200D\u2003]/g; +const ZWJ_REGEX = /[\u200B\u200D\u2003]/g; // Regex pattern for whitespace characters const WHITESPACE_REGEX = /\s/g; diff --git a/src/editor/parts.ts b/src/editor/parts.ts index 29883242088..914db33e50a 100644 --- a/src/editor/parts.ts +++ b/src/editor/parts.ts @@ -32,7 +32,7 @@ import defaultDispatcher from "../dispatcher/dispatcher"; import { Action } from "../dispatcher/actions"; import SettingsStore from "../settings/SettingsStore"; -const HAIR_SPACE = String.fromCodePoint(0x200A); +const REGIONAL_EMOJI_SEPARATOR = String.fromCodePoint(0x200B); interface ISerializedPart { type: Type.Plain | Type.Newline | Type.Emoji | Type.Command | Type.PillCandidate; @@ -216,9 +216,9 @@ abstract class PlainBasePart extends BasePart { return false; } - // or split if the previous character is a space or a hair 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] !== HAIR_SPACE) && + return (this._text[offset - 1] !== " " && this._text[offset - 1] !== REGIONAL_EMOJI_SEPARATOR) && (this._text[offset - 1] !== "+" || chr !== ":"); } return true; @@ -650,7 +650,7 @@ export class PartCreator { } parts.push(this.emoji(char)); if (PartCreator.isRegionalIndicator(text)) { - parts.push(this.plain(HAIR_SPACE)); + parts.push(this.plain(REGIONAL_EMOJI_SEPARATOR)); } } else { plainText += char; From 237905ce4c34a7a3572b10a6bf097621eadcb1a1 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Sat, 1 Oct 2022 00:25:44 +0200 Subject: [PATCH 07/16] forgot lint --- src/HtmlUtils.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index c0f35052b70..4c91c27f9e3 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -50,7 +50,7 @@ const SURROGATE_PAIR_PATTERN = /([\ud800-\udbff])([\udc00-\udfff])/; const SYMBOL_PATTERN = /([\u2100-\u2bff])/; // Regex pattern for Zero-Width joiner unicode characters -const ZWJ_REGEX = /[\u200B\u200D\u2003]/g; +const ZWJ_REGEX = /[\u200D\u2003\u200B]/g; // Regex pattern for whitespace characters const WHITESPACE_REGEX = /\s/g; From 4421e37a6ba00daa1c8b54b6ea51b063c4599161 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Fri, 7 Oct 2022 20:49:59 +0200 Subject: [PATCH 08/16] rename and combine regex --- src/HtmlUtils.tsx | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 4c91c27f9e3..de555d7ff04 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -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\u200B]/g; - -// Regex pattern for whitespace characters -const WHITESPACE_REGEX = /\s/g; +// Regex pattern for Emoji Separator unicode characters (Zero-Width joiner and Zero-Width space) +const EMOJI_SEPARATOR_REGEX = /[\u200D\u200B/\s]/g; const BIGEMOJI_REGEX = new RegExp(`^(${EMOJIBASE_REGEX.source})+$`, 'i'); @@ -547,14 +544,11 @@ export function bodyToHtml(content: IContent, highlights: Optional, 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 = match && match[0] && match[0].length === contentBodyTrimmed.length && From bfd97f70f1056cc0261d8e12c8de42874414a139 Mon Sep 17 00:00:00 2001 From: Faye Duxovni Date: Fri, 7 Oct 2022 23:18:56 -0400 Subject: [PATCH 09/16] Update src/HtmlUtils.tsx --- src/HtmlUtils.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index de555d7ff04..5d21bd7f119 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -49,8 +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 Emoji Separator unicode characters (Zero-Width joiner and Zero-Width space) -const EMOJI_SEPARATOR_REGEX = /[\u200D\u200B/\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'); From 66bdc9516794dd9668b402cfcb4205a915f33464 Mon Sep 17 00:00:00 2001 From: Faye Duxovni Date: Fri, 7 Oct 2022 23:36:29 -0400 Subject: [PATCH 10/16] Fix codepoint range --- src/editor/parts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editor/parts.ts b/src/editor/parts.ts index 914db33e50a..324e86d8e6c 100644 --- a/src/editor/parts.ts +++ b/src/editor/parts.ts @@ -634,7 +634,7 @@ export class PartCreator { } private static isRegionalIndicator(c: string): boolean { - return c.length == 2 && 127462 < c.codePointAt(0) && c.codePointAt(0) < 127488; + return c.length == 2 && 0x1F1E6 <= c.codePointAt(0) && c.codePointAt(0) <= 0x1F1FF; } public plainWithEmoji(text: string): (PlainPart | EmojiPart)[] { From 2c6f8d223143e636c7e44327129e397a6cd7b3b2 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Sat, 8 Oct 2022 18:24:47 +0200 Subject: [PATCH 11/16] improve existing test --- test/editor/model-test.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/editor/model-test.ts b/test/editor/model-test.ts index fbfdb4a76af..e2b904101f9 100644 --- a/test/editor/model-test.ts +++ b/test/editor/model-test.ts @@ -326,21 +326,26 @@ describe('editor/model', function() { const renderer = createRenderer(); const pc = createPartCreator(); const model = new EditorModel([], pc, renderer); - const regionalEmojiF = String.fromCodePoint(127467); + const regionalEmojiA = String.fromCodePoint(127462); + const regionalEmojiZ = String.fromCodePoint(127487); const caret = new DocumentOffset(0, true); - + const regionalEmojis = []; + 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(regionalEmojiF), position); + const addedLen = model.insert(pc.plainWithEmoji(regionalEmojis[i]), position); caret.offset += addedLen; return model.positionForOffset(caret.offset, true); }); } - expect(model.parts.length).toBeGreaterThanOrEqual(2); + 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"); }); }); }); From 1db5a9367c6654aa2d08eb13987d9f1fb5f9659c Mon Sep 17 00:00:00 2001 From: grimhilt Date: Mon, 14 Nov 2022 18:53:26 +0100 Subject: [PATCH 12/16] add cypress test --- cypress/e2e/timeline/timeline.spec.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cypress/e2e/timeline/timeline.spec.ts b/cypress/e2e/timeline/timeline.spec.ts index 68e0300ce35..0eecd356ec8 100644 --- a/cypress/e2e/timeline/timeline.spec.ts +++ b/cypress/e2e/timeline/timeline.spec.ts @@ -360,5 +360,24 @@ describe("Timeline", () => { cy.get(".mx_RoomView_body .mx_EventTile > .mx_EventTile_line > .mx_MVoiceMessageBody") .should("have.length", 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.wait(300); + cy.getComposer().type(`{enter}:regional_indicator_r`); + cy.wait(300); + cy.getComposer().type(`{enter} :regional_indicator_z`); + cy.wait(300); + cy.getComposer().type(`{enter}:regional_indicator_a`); + cy.wait(300); + cy.getComposer().type(`{enter}{enter}`); + + cy.get(".mx_RoomView_body .mx_EventTile .mx_EventTile_line .mx_MTextBody .mx_EventTile_bigEmoji") + .children() + .should("have.length", 4); + }); }); }); From 9b2747166c8b932496f3297a7b911c19e411c65f Mon Sep 17 00:00:00 2001 From: grimhilt Date: Mon, 14 Nov 2022 23:55:44 +0100 Subject: [PATCH 13/16] fix some typescript error --- src/editor/parts.ts | 5 +++-- test/editor/model-test.ts | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/editor/parts.ts b/src/editor/parts.ts index 324e86d8e6c..33e9f3eec74 100644 --- a/src/editor/parts.ts +++ b/src/editor/parts.ts @@ -634,11 +634,12 @@ export class PartCreator { } private static isRegionalIndicator(c: string): boolean { - return c.length == 2 && 0x1F1E6 <= c.codePointAt(0) && c.codePointAt(0) <= 0x1F1FF; + const codePoint = c.codePointAt(0) ?? 0; + return codePoint && 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 diff --git a/test/editor/model-test.ts b/test/editor/model-test.ts index e2b904101f9..dcba7af0fa2 100644 --- a/test/editor/model-test.ts +++ b/test/editor/model-test.ts @@ -329,7 +329,8 @@ describe('editor/model', function() { const regionalEmojiA = String.fromCodePoint(127462); const regionalEmojiZ = String.fromCodePoint(127487); const caret = new DocumentOffset(0, true); - const regionalEmojis = []; + + const regionalEmojis: string[] = []; regionalEmojis.push(regionalEmojiA); regionalEmojis.push(regionalEmojiZ); for (let i = 0; i < 2; i++) { From 4152aa62063c86e012f97b1cee079b8431538561 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Tue, 15 Nov 2022 11:40:37 +0100 Subject: [PATCH 14/16] fix more tsc type error --- src/editor/parts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editor/parts.ts b/src/editor/parts.ts index 33e9f3eec74..b4279f99d38 100644 --- a/src/editor/parts.ts +++ b/src/editor/parts.ts @@ -635,7 +635,7 @@ export class PartCreator { private static isRegionalIndicator(c: string): boolean { const codePoint = c.codePointAt(0) ?? 0; - return codePoint && c.length == 2 && 0x1F1E6 <= codePoint && codePoint <= 0x1F1FF; + return codePoint != 0 && c.length == 2 && 0x1F1E6 <= codePoint && codePoint <= 0x1F1FF; } public plainWithEmoji(text: string): (PlainPart | EmojiPart)[] { From a90cf765c7321ff7ad65734227a51b08389275c7 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Wed, 14 Dec 2022 21:48:28 +0100 Subject: [PATCH 15/16] Remove ` in favor of " and wait for element instead of using delay --- cypress/e2e/timeline/timeline.spec.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cypress/e2e/timeline/timeline.spec.ts b/cypress/e2e/timeline/timeline.spec.ts index 0eecd356ec8..98c95967972 100644 --- a/cypress/e2e/timeline/timeline.spec.ts +++ b/cypress/e2e/timeline/timeline.spec.ts @@ -365,15 +365,15 @@ describe("Timeline", () => { cy.visit("/#/room/" + roomId); // Send a message - cy.getComposer().type(`:regional_indicator_a`); - cy.wait(300); - cy.getComposer().type(`{enter}:regional_indicator_r`); - cy.wait(300); - cy.getComposer().type(`{enter} :regional_indicator_z`); - cy.wait(300); - cy.getComposer().type(`{enter}:regional_indicator_a`); - cy.wait(300); - cy.getComposer().type(`{enter}{enter}`); + 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() From 19ddf56e8f1a26351d82e989144f4ea2ef7747de Mon Sep 17 00:00:00 2001 From: grimhilt Date: Thu, 5 Jan 2023 20:01:41 +0100 Subject: [PATCH 16/16] apply prettier formatting --- src/HtmlUtils.tsx | 2 +- src/editor/parts.ts | 11 +++++++---- test/editor/model-test.ts | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index b2289894fc3..95405ccacf0 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -592,7 +592,7 @@ export function bodyToHtml(content: IContent, highlights: Optional, op // 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, ''); + contentBodyTrimmed = contentBodyTrimmed.replace(EMOJI_SEPARATOR_REGEX, ""); const match = BIGEMOJI_REGEX.exec(contentBodyTrimmed); emojiBody = diff --git a/src/editor/parts.ts b/src/editor/parts.ts index b430cdb7046..4647f2e83bf 100644 --- a/src/editor/parts.ts +++ b/src/editor/parts.ts @@ -28,7 +28,7 @@ import defaultDispatcher from "../dispatcher/dispatcher"; import { Action } from "../dispatcher/actions"; import SettingsStore from "../settings/SettingsStore"; -const REGIONAL_EMOJI_SEPARATOR = String.fromCodePoint(0x200B); +const REGIONAL_EMOJI_SEPARATOR = String.fromCodePoint(0x200b); interface ISerializedPart { type: Type.Plain | Type.Newline | Type.Emoji | Type.Command | Type.PillCandidate; @@ -214,8 +214,11 @@ abstract class PlainBasePart extends BasePart { // 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] !== REGIONAL_EMOJI_SEPARATOR) && - (this._text[offset - 1] !== "+" || chr !== ":"); + return ( + this._text[offset - 1] !== " " && + this._text[offset - 1] !== REGIONAL_EMOJI_SEPARATOR && + (this._text[offset - 1] !== "+" || chr !== ":") + ); } return true; } @@ -627,7 +630,7 @@ export class PartCreator { private static isRegionalIndicator(c: string): boolean { const codePoint = c.codePointAt(0) ?? 0; - return codePoint != 0 && c.length == 2 && 0x1F1E6 <= codePoint && codePoint <= 0x1F1FF; + return codePoint != 0 && c.length == 2 && 0x1f1e6 <= codePoint && codePoint <= 0x1f1ff; } public plainWithEmoji(text: string): (PlainPart | EmojiPart)[] { diff --git a/test/editor/model-test.ts b/test/editor/model-test.ts index e1f67b6b2a0..04d2667f191 100644 --- a/test/editor/model-test.ts +++ b/test/editor/model-test.ts @@ -348,8 +348,8 @@ 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', () => { + 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);