Skip to content

Commit 555c239

Browse files
authoredJan 28, 2025
Merge pull request #2931 from microsoft/u/juliaroldi/undo-images
Stop editing when content changed
2 parents f960478 + f969062 commit 555c239

File tree

2 files changed

+84
-3
lines changed

2 files changed

+84
-3
lines changed
 

‎packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts

+33-3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import type { DragAndDropContext } from './types/DragAndDropContext';
2929
import type { ImageHtmlOptions } from './types/ImageHtmlOptions';
3030
import type { ImageEditOptions } from './types/ImageEditOptions';
3131
import type {
32+
ContentChangedEvent,
3233
ContentModelImage,
3334
EditorPlugin,
3435
IEditor,
@@ -55,6 +56,7 @@ const MouseRightButton = 2;
5556
const DRAG_ID = '_dragging';
5657
const IMAGE_EDIT_CLASS = 'imageEdit';
5758
const IMAGE_EDIT_CLASS_CARET = 'imageEditCaretColor';
59+
const IMAGE_EDIT_FORMAT_EVENT = 'ImageEditEvent';
5860

5961
/**
6062
* ImageEdit plugin handles the following image editing features:
@@ -170,9 +172,7 @@ export class ImageEditPlugin implements ImageEditor, EditorPlugin {
170172
this.keyDownHandler(this.editor, event);
171173
break;
172174
case 'contentChanged':
173-
if (event.source == ChangeSource.Drop) {
174-
this.onDropHandler(this.editor);
175-
}
175+
this.contentChangedHandler(this.editor, event);
176176
break;
177177
case 'extractContentWithDom':
178178
this.removeImageEditing(event.clonedRoot);
@@ -279,6 +279,35 @@ export class ImageEditPlugin implements ImageEditor, EditorPlugin {
279279
}
280280
}
281281

282+
private setContentHandler(editor: IEditor) {
283+
const selection = editor.getDOMSelection();
284+
if (selection?.type == 'image' && selection.image.dataset.isEditing && !this.isEditing) {
285+
delete selection.image.dataset.isEditing;
286+
}
287+
}
288+
289+
private formatEventHandler(event: ContentChangedEvent) {
290+
if (this.isEditing && event.formatApiName !== IMAGE_EDIT_FORMAT_EVENT) {
291+
this.cleanInfo();
292+
this.isEditing = false;
293+
this.isCropMode = false;
294+
}
295+
}
296+
297+
private contentChangedHandler(editor: IEditor, event: ContentChangedEvent) {
298+
switch (event.source) {
299+
case ChangeSource.SetContent:
300+
this.setContentHandler(editor);
301+
break;
302+
case ChangeSource.Format:
303+
this.formatEventHandler(event);
304+
break;
305+
case ChangeSource.Drop:
306+
this.onDropHandler(editor);
307+
break;
308+
}
309+
}
310+
282311
/**
283312
* EXPOSED FOR TESTING PURPOSE ONLY
284313
*/
@@ -392,6 +421,7 @@ export class ImageEditPlugin implements ImageEditor, EditorPlugin {
392421
}
393422
}
394423
},
424+
apiName: IMAGE_EDIT_FORMAT_EVENT,
395425
},
396426
{
397427
tryGetFromCache: true,

‎packages/roosterjs-content-model-plugins/test/imageEdit/ImageEditPluginTest.ts

+51
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import {
1010
ContentModelDocument,
1111
ContentModelFormatter,
1212
DOMEventRecord,
13+
DOMSelection,
1314
EditorEnvironment,
1415
FormatContentModelOptions,
1516
IEditor,
17+
ImageSelection,
1618
} from 'roosterjs-content-model-types';
1719

1820
describe('ImageEditPlugin', () => {
@@ -670,6 +672,55 @@ describe('ImageEditPlugin', () => {
670672
expect(event.clonedRoot).toEqual(expectedClonedRoot);
671673
plugin.dispose();
672674
});
675+
676+
it('contentChanged - should remove isEditing', () => {
677+
const plugin = new ImageEditPlugin();
678+
const editor = initEditor('image_edit', [plugin], model);
679+
plugin.initialize(editor);
680+
const image = document.createElement('img');
681+
image.dataset['isEditing'] = 'true';
682+
const selection = {
683+
type: 'image',
684+
image,
685+
} as DOMSelection;
686+
spyOn(editor, 'getDOMSelection').and.returnValue(selection);
687+
const event = {
688+
eventType: 'contentChanged',
689+
source: ChangeSource.SetContent,
690+
} as any;
691+
plugin.onPluginEvent(event);
692+
const newSelection = editor.getDOMSelection() as ImageSelection;
693+
expect(newSelection!.type).toBe('image');
694+
expect(newSelection!.image.dataset.isEditing).toBeUndefined();
695+
plugin.dispose();
696+
});
697+
698+
it('contentChanged - should remove editor caret style', () => {
699+
const plugin = new TestPlugin();
700+
plugin.initialize(editor);
701+
plugin.setIsEditing(true);
702+
const event = {
703+
eventType: 'contentChanged',
704+
source: ChangeSource.Format,
705+
} as any;
706+
plugin.onPluginEvent(event);
707+
expect(editor.setEditorStyle).toHaveBeenCalledWith('imageEditCaretColor', null);
708+
plugin.dispose();
709+
});
710+
711+
it('contentChanged - should not remove editor caret style', () => {
712+
const plugin = new TestPlugin();
713+
plugin.initialize(editor);
714+
plugin.setIsEditing(true);
715+
const event = {
716+
eventType: 'contentChanged',
717+
source: ChangeSource.Format,
718+
formatApiName: 'ImageEditEvent',
719+
} as any;
720+
plugin.onPluginEvent(event);
721+
expect(editor.setEditorStyle).not.toHaveBeenCalled();
722+
plugin.dispose();
723+
});
673724
});
674725

675726
class TestPlugin extends ImageEditPlugin {

0 commit comments

Comments
 (0)