From 45786694edc2c5b46e9bd54502edd327b967a442 Mon Sep 17 00:00:00 2001 From: "Julia Roldi (from Dev Box)" Date: Tue, 28 Jan 2025 14:17:29 -0300 Subject: [PATCH 1/3] remove data-istrue --- .../lib/imageEdit/ImageEditPlugin.ts | 9 +++++ .../test/imageEdit/ImageEditPluginTest.ts | 39 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts b/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts index 2c14e9898dd..d4c723df34a 100644 --- a/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts +++ b/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts @@ -55,6 +55,7 @@ const MouseRightButton = 2; const DRAG_ID = '_dragging'; const IMAGE_EDIT_CLASS = 'imageEdit'; const IMAGE_EDIT_CLASS_CARET = 'imageEditCaretColor'; +const IMAGE_EDIT_DATASET = 'data-is-editing="true"'; /** * ImageEdit plugin handles the following image editing features: @@ -177,6 +178,9 @@ export class ImageEditPlugin implements ImageEditor, EditorPlugin { case 'extractContentWithDom': this.removeImageEditing(event.clonedRoot); break; + case 'beforeSetContent': + this.beforeSetContentHandler(this.editor, event.newContent); + break; } } @@ -279,6 +283,11 @@ export class ImageEditPlugin implements ImageEditor, EditorPlugin { } } + private beforeSetContentHandler(editor: IEditor, newContent: string) { + newContent.replace(IMAGE_EDIT_DATASET, ''); + editor?.setEditorStyle(IMAGE_EDIT_CLASS_CARET, null); + } + /** * EXPOSED FOR TESTING PURPOSE ONLY */ diff --git a/packages/roosterjs-content-model-plugins/test/imageEdit/ImageEditPluginTest.ts b/packages/roosterjs-content-model-plugins/test/imageEdit/ImageEditPluginTest.ts index 1bc97e1075c..22e47507008 100644 --- a/packages/roosterjs-content-model-plugins/test/imageEdit/ImageEditPluginTest.ts +++ b/packages/roosterjs-content-model-plugins/test/imageEdit/ImageEditPluginTest.ts @@ -670,6 +670,45 @@ describe('ImageEditPlugin', () => { expect(event.clonedRoot).toEqual(expectedClonedRoot); plugin.dispose(); }); + + it('beforeSetContent - should remove isEditing', () => { + const plugin = new ImageEditPlugin(); + plugin.initialize(editor); + const clonedRoot = document.createElement('div'); + const image = document.createElement('img'); + clonedRoot.appendChild(image); + image.dataset['editingInfo'] = JSON.stringify({ + src: 'test', + }); + image.dataset['isEditing'] = 'true'; + const event = { + eventType: 'beforeSetContent', + newContent: JSON.stringify(clonedRoot), + } as any; + plugin.onPluginEvent(event); + const isEditing = event.newContent.includes('data-is-editing="true"'); + expect(isEditing).toBeFalse(); + plugin.dispose(); + }); + + it('beforeSetContent - should editor caret style', () => { + const plugin = new ImageEditPlugin(); + plugin.initialize(editor); + const clonedRoot = document.createElement('div'); + const image = document.createElement('img'); + clonedRoot.appendChild(image); + image.dataset['editingInfo'] = JSON.stringify({ + src: 'test', + }); + image.dataset['isEditing'] = 'true'; + const event = { + eventType: 'beforeSetContent', + newContent: JSON.stringify(clonedRoot), + } as any; + plugin.onPluginEvent(event); + expect(editor.setEditorStyle).toHaveBeenCalledWith('imageEditCaretColor', null); + plugin.dispose(); + }); }); class TestPlugin extends ImageEditPlugin { From 685ff406cbfbda8e28d7d3f95806c82c0d15242e Mon Sep 17 00:00:00 2001 From: "Julia Roldi (from Dev Box)" Date: Tue, 28 Jan 2025 18:03:02 -0300 Subject: [PATCH 2/3] use content change --- .../lib/imageEdit/ImageEditPlugin.ts | 37 +++++++++---- .../test/imageEdit/ImageEditPluginTest.ts | 54 +++++++++++-------- 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts b/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts index d4c723df34a..f60b99828ad 100644 --- a/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts +++ b/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts @@ -29,6 +29,7 @@ import type { DragAndDropContext } from './types/DragAndDropContext'; import type { ImageHtmlOptions } from './types/ImageHtmlOptions'; import type { ImageEditOptions } from './types/ImageEditOptions'; import type { + ContentChangedEvent, ContentModelImage, EditorPlugin, IEditor, @@ -55,7 +56,7 @@ const MouseRightButton = 2; const DRAG_ID = '_dragging'; const IMAGE_EDIT_CLASS = 'imageEdit'; const IMAGE_EDIT_CLASS_CARET = 'imageEditCaretColor'; -const IMAGE_EDIT_DATASET = 'data-is-editing="true"'; +const IMAGE_EDIT_FORMAT_EVENT = 'ImageEditEvent'; /** * ImageEdit plugin handles the following image editing features: @@ -171,16 +172,11 @@ export class ImageEditPlugin implements ImageEditor, EditorPlugin { this.keyDownHandler(this.editor, event); break; case 'contentChanged': - if (event.source == ChangeSource.Drop) { - this.onDropHandler(this.editor); - } + this.contentChangedHandler(this.editor, event); break; case 'extractContentWithDom': this.removeImageEditing(event.clonedRoot); break; - case 'beforeSetContent': - this.beforeSetContentHandler(this.editor, event.newContent); - break; } } @@ -283,9 +279,29 @@ export class ImageEditPlugin implements ImageEditor, EditorPlugin { } } - private beforeSetContentHandler(editor: IEditor, newContent: string) { - newContent.replace(IMAGE_EDIT_DATASET, ''); - editor?.setEditorStyle(IMAGE_EDIT_CLASS_CARET, null); + private setContentHandler(editor: IEditor) { + const selection = editor.getDOMSelection(); + if (selection?.type == 'image' && selection.image.dataset.isEditing && !this.isEditing) { + delete selection.image.dataset.isEditing; + } + } + + private contentChangedHandler(editor: IEditor, event: ContentChangedEvent) { + switch (event.source) { + case ChangeSource.SetContent: + this.setContentHandler(editor); + break; + case ChangeSource.Format: + if (this.isEditing && event.formatApiName !== IMAGE_EDIT_FORMAT_EVENT) { + this.cleanInfo(); + this.isEditing = false; + this.isCropMode = false; + } + break; + case ChangeSource.Drop: + this.onDropHandler(editor); + break; + } } /** @@ -401,6 +417,7 @@ export class ImageEditPlugin implements ImageEditor, EditorPlugin { } } }, + apiName: IMAGE_EDIT_FORMAT_EVENT, }, { tryGetFromCache: true, diff --git a/packages/roosterjs-content-model-plugins/test/imageEdit/ImageEditPluginTest.ts b/packages/roosterjs-content-model-plugins/test/imageEdit/ImageEditPluginTest.ts index 22e47507008..53a51cd097c 100644 --- a/packages/roosterjs-content-model-plugins/test/imageEdit/ImageEditPluginTest.ts +++ b/packages/roosterjs-content-model-plugins/test/imageEdit/ImageEditPluginTest.ts @@ -10,9 +10,11 @@ import { ContentModelDocument, ContentModelFormatter, DOMEventRecord, + DOMSelection, EditorEnvironment, FormatContentModelOptions, IEditor, + ImageSelection, } from 'roosterjs-content-model-types'; describe('ImageEditPlugin', () => { @@ -671,44 +673,54 @@ describe('ImageEditPlugin', () => { plugin.dispose(); }); - it('beforeSetContent - should remove isEditing', () => { + it('contentChanged - should remove isEditing', () => { const plugin = new ImageEditPlugin(); + const editor = initEditor('image_edit', [plugin], model); plugin.initialize(editor); - const clonedRoot = document.createElement('div'); const image = document.createElement('img'); - clonedRoot.appendChild(image); - image.dataset['editingInfo'] = JSON.stringify({ - src: 'test', - }); image.dataset['isEditing'] = 'true'; + const selection = { + type: 'image', + image, + } as DOMSelection; + spyOn(editor, 'getDOMSelection').and.returnValue(selection); const event = { - eventType: 'beforeSetContent', - newContent: JSON.stringify(clonedRoot), + eventType: 'contentChanged', + source: ChangeSource.SetContent, } as any; plugin.onPluginEvent(event); - const isEditing = event.newContent.includes('data-is-editing="true"'); - expect(isEditing).toBeFalse(); + const newSelection = editor.getDOMSelection() as ImageSelection; + expect(newSelection!.type).toBe('image'); + expect(newSelection!.image.dataset.isEditing).toBeUndefined(); plugin.dispose(); }); - it('beforeSetContent - should editor caret style', () => { - const plugin = new ImageEditPlugin(); + it('contentChanged - should remove editor caret style', () => { + const plugin = new TestPlugin(); plugin.initialize(editor); - const clonedRoot = document.createElement('div'); - const image = document.createElement('img'); - clonedRoot.appendChild(image); - image.dataset['editingInfo'] = JSON.stringify({ - src: 'test', - }); - image.dataset['isEditing'] = 'true'; + plugin.setIsEditing(true); const event = { - eventType: 'beforeSetContent', - newContent: JSON.stringify(clonedRoot), + eventType: 'contentChanged', + source: ChangeSource.Format, } as any; plugin.onPluginEvent(event); expect(editor.setEditorStyle).toHaveBeenCalledWith('imageEditCaretColor', null); plugin.dispose(); }); + + it('contentChanged - should not remove editor caret style', () => { + const plugin = new TestPlugin(); + plugin.initialize(editor); + plugin.setIsEditing(true); + const event = { + eventType: 'contentChanged', + source: ChangeSource.Format, + formatApiName: 'ImageEditEvent', + } as any; + plugin.onPluginEvent(event); + expect(editor.setEditorStyle).not.toHaveBeenCalled(); + plugin.dispose(); + }); }); class TestPlugin extends ImageEditPlugin { From 27c11ffc2702b5d2049072c4a2e667922fe09fbd Mon Sep 17 00:00:00 2001 From: "Julia Roldi (from Dev Box)" Date: Tue, 28 Jan 2025 18:34:43 -0300 Subject: [PATCH 3/3] refactor --- .../lib/imageEdit/ImageEditPlugin.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts b/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts index f60b99828ad..849a9b69e9a 100644 --- a/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts +++ b/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts @@ -286,17 +286,21 @@ export class ImageEditPlugin implements ImageEditor, EditorPlugin { } } + private formatEventHandler(event: ContentChangedEvent) { + if (this.isEditing && event.formatApiName !== IMAGE_EDIT_FORMAT_EVENT) { + this.cleanInfo(); + this.isEditing = false; + this.isCropMode = false; + } + } + private contentChangedHandler(editor: IEditor, event: ContentChangedEvent) { switch (event.source) { case ChangeSource.SetContent: this.setContentHandler(editor); break; case ChangeSource.Format: - if (this.isEditing && event.formatApiName !== IMAGE_EDIT_FORMAT_EVENT) { - this.cleanInfo(); - this.isEditing = false; - this.isCropMode = false; - } + this.formatEventHandler(event); break; case ChangeSource.Drop: this.onDropHandler(editor);