From 0592f0245dc589b0b7216f20bc27420e62df2c33 Mon Sep 17 00:00:00 2001 From: Zihua Li Date: Mon, 20 Nov 2023 20:18:30 +0800 Subject: [PATCH] Handle multiple navigation shortcuts --- modules/uiNode.ts | 7 ++++-- test/unit/modules/uiNode.spec.ts | 41 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 test/unit/modules/uiNode.spec.ts diff --git a/modules/uiNode.ts b/modules/uiNode.ts index 488eb2cb2e..4b88b1a24c 100644 --- a/modules/uiNode.ts +++ b/modules/uiNode.ts @@ -4,6 +4,9 @@ import Quill from '../core/quill'; const isMac = /Mac/i.test(navigator.platform); +// Export for testing +export const TTL_FOR_VALID_SELECTION_CHANGE = 100; + // A loose check to determine if the shortcut can move the caret before a UI node: // [CARET]
[CONTENT]
const canMoveCaretBeforeUINode = (event: KeyboardEvent) => { @@ -78,10 +81,10 @@ class UINode extends Module { * the selection within the handler of a `selectionchange` event. */ private ensureListeningToSelectionChange() { - if (this.isListening) return; + this.selectionChangeDeadline = Date.now() + TTL_FOR_VALID_SELECTION_CHANGE; + if (this.isListening) return; this.isListening = true; - this.selectionChangeDeadline = Date.now() + 100; const listener = () => { this.isListening = false; diff --git a/test/unit/modules/uiNode.spec.ts b/test/unit/modules/uiNode.spec.ts new file mode 100644 index 0000000000..3f271b565c --- /dev/null +++ b/test/unit/modules/uiNode.spec.ts @@ -0,0 +1,41 @@ +import '../../../quill'; +import { describe, expect, test } from 'vitest'; +import UINode, { + TTL_FOR_VALID_SELECTION_CHANGE, +} from '../../../modules/uiNode'; +import Quill, { Delta } from '../../../core'; + +// Fake timer is not supported in browser mode yet. +const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +describe('uiNode', () => { + test('extends deadline when multiple possible shortcuts are pressed', async () => { + const quill = new Quill(document.createElement('div')); + document.body.appendChild(quill.container); + quill.setContents( + new Delta().insert('item 1').insert('\n', { list: 'bullet' }), + ); + new UINode(quill, {}); + + for (let i = 0; i < 2; i += 1) { + quill.root.dispatchEvent( + new KeyboardEvent('keydown', { key: 'ArrowRight', metaKey: true }), + ); + await delay(TTL_FOR_VALID_SELECTION_CHANGE / 2); + } + + quill.root.dispatchEvent( + new KeyboardEvent('keydown', { key: 'ArrowLeft', metaKey: true }), + ); + const range = document.createRange(); + range.setStart(quill.root.querySelector('li')!, 0); + range.setEnd(quill.root.querySelector('li')!, 0); + + const selection = document.getSelection(); + selection?.removeAllRanges(); + selection?.addRange(range); + + await delay(TTL_FOR_VALID_SELECTION_CHANGE / 2); + expect(selection?.getRangeAt(0).startOffset).toEqual(1); + }); +});