diff --git a/ts/quill/emoji/completion.tsx b/ts/quill/emoji/completion.tsx index e314333c207b..355cba5f431f 100644 --- a/ts/quill/emoji/completion.tsx +++ b/ts/quill/emoji/completion.tsx @@ -65,8 +65,26 @@ export class EmojiCompletion { this.quill.keyboard.addBinding({ key: 38 }, changeIndex(-1)); // 38 = Up this.quill.keyboard.addBinding({ key: 39 }, clearResults); // 39 = Right this.quill.keyboard.addBinding({ key: 40 }, changeIndex(1)); // 40 = Down + this.quill.keyboard.addBinding( + { + // 186 + Shift = Colon + key: 186, + shiftKey: true, + }, + () => this.onTextChange(true) + ); + this.quill.keyboard.addBinding( + { + // 58 = Also Colon + key: 58, + }, + () => this.onTextChange(true) + ); - this.quill.on('text-change', _.debounce(this.onTextChange.bind(this), 100)); + this.quill.on( + 'text-change', + _.debounce(() => this.onTextChange(), 100) + ); this.quill.on('selection-change', this.onSelectionChange.bind(this)); } @@ -91,10 +109,13 @@ export class EmojiCompletion { this.reset(); } - onTextChange(): void { + onTextChange(justPressedColon = false): boolean { + const PASS_THROUGH = true; + const INTERCEPT = false; + const range = this.quill.getSelection(); - if (!range) return; + if (!range) return PASS_THROUGH; const [blot, index] = this.quill.getLeaf(range.index); const [leftTokenTextMatch, rightTokenTextMatch] = matchBlotTextPartitions( @@ -107,24 +128,26 @@ export class EmojiCompletion { if (leftTokenTextMatch) { const [, leftTokenText, isSelfClosing] = leftTokenTextMatch; - if (isSelfClosing) { + if (isSelfClosing || justPressedColon) { if (isShortName(leftTokenText)) { const emojiData = convertShortNameToData( leftTokenText, this.options.skinTone ); + const numberOfColons = isSelfClosing ? 2 : 1; + if (emojiData) { this.insertEmoji( emojiData, - range.index - leftTokenText.length - 2, - leftTokenText.length + 2 + range.index - leftTokenText.length - numberOfColons, + leftTokenText.length + numberOfColons ); - return; + return INTERCEPT; } } else { this.reset(); - return; + return PASS_THROUGH; } } @@ -144,14 +167,14 @@ export class EmojiCompletion { range.index - leftTokenText.length - 1, tokenText.length + 2 ); - return; + return INTERCEPT; } } } if (leftTokenText.length < 2) { this.reset(); - return; + return PASS_THROUGH; } const showEmojiResults = search(leftTokenText, 10); @@ -165,6 +188,8 @@ export class EmojiCompletion { } else if (this.results.length !== 0) { this.reset(); } + + return PASS_THROUGH; } completeEmoji(): void { diff --git a/ts/test/quill/emoji/completion_test.tsx b/ts/test/quill/emoji/completion_test.tsx index e5a0f2fb4854..291abc02616d 100644 --- a/ts/test/quill/emoji/completion_test.tsx +++ b/ts/test/quill/emoji/completion_test.tsx @@ -336,6 +336,40 @@ describe('emojiCompletion', () => { }); }); }); + + describe('given a completeable emoji and colon was just pressed', () => { + beforeEach(function beforeEach() { + mockQuill.getSelection.returns({ + index: 6, + length: 0, + }); + }); + + describe('and given it matches a short name', () => { + const text = ':smile'; + + beforeEach(function beforeEach() { + const blot = { + text, + }; + mockQuill.getLeaf.returns([blot, 6]); + + emojiCompletion.onTextChange(true); + }); + + it('inserts the emoji at the current cursor position', () => { + const [emoji, index, range] = insertEmojiStub.args[0]; + + assert.equal(emoji.short_name, 'smile'); + assert.equal(index, 0); + assert.equal(range, 6); + }); + + it('does not show results', () => { + assert.equal(emojiCompletion.results.length, 0); + }); + }); + }); }); describe('completeEmoji', () => {