From a5a4a3f2aa0d85819136614fdabc6d49dacb236b Mon Sep 17 00:00:00 2001 From: Hamza Benkhaldoun Date: Wed, 12 Mar 2025 13:06:03 +0000 Subject: [PATCH 1/7] INT-3226: Fix onEditorChange called three times after inserting content on a selection --- src/main/ts/components/Editor.tsx | 20 +++++++----------- src/stories/Editor.stories.tsx | 6 ++++-- src/test/ts/browser/EditorBehaviorTest.ts | 25 +++++++++++++++++++---- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/main/ts/components/Editor.tsx b/src/main/ts/components/Editor.tsx index e6c1d214..16f3a873 100644 --- a/src/main/ts/components/Editor.tsx +++ b/src/main/ts/components/Editor.tsx @@ -1,10 +1,12 @@ import * as React from 'react'; +import type { Bookmark, EditorEvent, TinyMCE, Editor as TinyMCEEditor } from 'tinymce'; import { IEvents } from '../Events'; import { ScriptItem, ScriptLoader } from '../ScriptLoader2'; import { getTinymce } from '../TinyMCE'; -import { isFunction, isTextareaOrInput, mergePlugins, uuid, configHandlers, isBeforeInputEventAvailable, isInDoc, setMode } from '../Utils'; +import { configHandlers, isBeforeInputEventAvailable, isFunction, isInDoc, isTextareaOrInput, mergePlugins, setMode, uuid } from '../Utils'; import { EditorPropTypes, IEditorPropTypes } from './EditorPropTypes'; -import type { Bookmark, Editor as TinyMCEEditor, EditorEvent, TinyMCE } from 'tinymce'; + +const changeEvents = 'change input compositionend setcontent CommentChange'; type OmitStringIndexSignature = { [K in keyof T as string extends K ? never : K]: T[K] }; @@ -241,7 +243,7 @@ export class Editor extends React.Component { public componentWillUnmount() { const editor = this.editor; if (editor) { - editor.off(this.changeEvents(), this.handleEditorChange); + editor.off(changeEvents, this.handleEditorChange); editor.off(this.beforeInputEvent(), this.handleBeforeInput); editor.off('keypress', this.handleEditorChangeSpecial); editor.off('keydown', this.handleBeforeInputSpecial); @@ -259,14 +261,6 @@ export class Editor extends React.Component { return this.inline ? this.renderInline() : this.renderIframe(); } - private changeEvents() { - const isIE = getTinymce(this.view)?.Env?.browser?.isIE(); - return (isIE - ? 'change keyup compositionend setcontent CommentChange' - : 'change input compositionend setcontent CommentChange' - ); - } - private beforeInputEvent() { return isBeforeInputEventAvailable() ? 'beforeinput SelectionChange' : 'SelectionChange'; } @@ -335,13 +329,13 @@ export class Editor extends React.Component { const wasControlled = isValueControlled(prevProps); const nowControlled = isValueControlled(this.props); if (!wasControlled && nowControlled) { - this.editor.on(this.changeEvents(), this.handleEditorChange); + this.editor.on(changeEvents, this.handleEditorChange); this.editor.on(this.beforeInputEvent(), this.handleBeforeInput); this.editor.on('keydown', this.handleBeforeInputSpecial); this.editor.on('keyup', this.handleEditorChangeSpecial); this.editor.on('NewBlock', this.handleEditorChange); } else if (wasControlled && !nowControlled) { - this.editor.off(this.changeEvents(), this.handleEditorChange); + this.editor.off(changeEvents, this.handleEditorChange); this.editor.off(this.beforeInputEvent(), this.handleBeforeInput); this.editor.off('keydown', this.handleBeforeInputSpecial); this.editor.off('keyup', this.handleEditorChangeSpecial); diff --git a/src/stories/Editor.stories.tsx b/src/stories/Editor.stories.tsx index 184f2596..145ccc5f 100644 --- a/src/stories/Editor.stories.tsx +++ b/src/stories/Editor.stories.tsx @@ -1,6 +1,6 @@ +import { StoryObj } from '@storybook/react'; import React from 'react'; import { EditorEvent, Events, Editor as TinyMCEEditor } from 'tinymce'; -import { StoryObj } from '@storybook/react'; import { Editor, IAllProps } from '../main/ts/components/Editor'; const apiKey = 'qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc'; @@ -60,7 +60,9 @@ export const ControlledInput: StoryObj = { setData(e)} + onEditorChange={(e) => { + setData(e); + }} />