From ad211c25f18092ff8d299ddfd34c0d81c294e6eb Mon Sep 17 00:00:00 2001 From: fantactuka Date: Thu, 30 Jun 2022 11:19:39 -0400 Subject: [PATCH] Ensure to call existing listeners only (not newly added ones) --- packages/lexical/src/LexicalUpdates.ts | 27 ++++---- .../src/__tests__/unit/LexicalEditor.test.tsx | 63 ++++++++++++++++++- 2 files changed, 77 insertions(+), 13 deletions(-) diff --git a/packages/lexical/src/LexicalUpdates.ts b/packages/lexical/src/LexicalUpdates.ts index 3714ceb8945..ad429a54b6c 100644 --- a/packages/lexical/src/LexicalUpdates.ts +++ b/packages/lexical/src/LexicalUpdates.ts @@ -598,16 +598,16 @@ function triggerMutationListeners( pendingEditorState: EditorState, mutatedNodes: MutatedNodes, ): void { - const listeners = editor._listeners.mutation; - listeners.forEach((klass, listener) => { - const mutatedNodesByType = mutatedNodes.get(klass); + const listeners = Array.from(editor._listeners.mutation); + const listenersLength = listeners.length; - if (mutatedNodesByType === undefined) { - return; + for (let i = 0; i < listenersLength; i++) { + const [listener, klass] = listeners[i]; + const mutatedNodesByType = mutatedNodes.get(klass); + if (mutatedNodesByType !== undefined) { + listener(mutatedNodesByType); } - - listener(mutatedNodesByType); - }); + } } export function triggerListeners( @@ -652,11 +652,14 @@ export function triggerCommandListeners

( const listenerInPriorityOrder = commandListeners.get(type); if (listenerInPriorityOrder !== undefined) { - const listeners = listenerInPriorityOrder[i]; + const listenersSet = listenerInPriorityOrder[i]; + + if (listenersSet !== undefined) { + const listeners = Array.from(listenersSet); + const listenersLength = listeners.length; - if (listeners !== undefined) { - for (const listener of listeners) { - if (listener(payload, editor) === true) { + for (let j = 0; j < listenersLength; j++) { + if (listeners[j](payload, editor) === true) { return true; } } diff --git a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx index 668b66ccd28..ab26a978032 100644 --- a/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx +++ b/packages/lexical/src/__tests__/unit/LexicalEditor.test.tsx @@ -29,6 +29,7 @@ import { $setCompositionKey, $setSelection, COMMAND_PRIORITY_EDITOR, + COMMAND_PRIORITY_LOW, createCommand, ElementNode, LexicalEditor, @@ -2065,6 +2066,13 @@ describe('LexicalEditor tests', () => { it('does not add new listeners while triggering existing', async () => { const updateListener = jest.fn(); + const mutationListener = jest.fn(); + const nodeTransformListener = jest.fn(); + const textContentListener = jest.fn(); + const readOnlyListener = jest.fn(); + const commandListener = jest.fn(); + const TEST_COMMAND = createCommand(); + init(); editor.registerUpdateListener(() => { @@ -2075,10 +2083,63 @@ describe('LexicalEditor tests', () => { }); }); + editor.registerMutationListener(TextNode, (map) => { + mutationListener(); + editor.registerMutationListener(TextNode, () => { + mutationListener(); + }); + }); + + editor.registerNodeTransform(ParagraphNode, () => { + nodeTransformListener(); + editor.registerNodeTransform(ParagraphNode, () => { + nodeTransformListener(); + }); + }); + + editor.registerReadOnlyListener(() => { + readOnlyListener(); + editor.registerReadOnlyListener(() => { + readOnlyListener(); + }); + }); + + editor.registerTextContentListener(() => { + textContentListener(); + editor.registerTextContentListener(() => { + textContentListener(); + }); + }); + + editor.registerCommand( + TEST_COMMAND, + (): boolean => { + commandListener(); + editor.registerCommand( + TEST_COMMAND, + commandListener, + COMMAND_PRIORITY_LOW, + ); + return false; + }, + COMMAND_PRIORITY_LOW, + ); + await update(() => { - $getRoot().getFirstChild().replace($createParagraphNode()); + $getRoot().append( + $createParagraphNode().append($createTextNode('Hello world')), + ); }); + editor.dispatchCommand(TEST_COMMAND, false); + + editor.setReadOnly(true); + expect(updateListener).toHaveBeenCalledTimes(1); + expect(readOnlyListener).toHaveBeenCalledTimes(1); + expect(commandListener).toHaveBeenCalledTimes(1); + expect(textContentListener).toHaveBeenCalledTimes(1); + expect(nodeTransformListener).toHaveBeenCalledTimes(1); + expect(mutationListener).toHaveBeenCalledTimes(1); }); });