diff --git a/packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/ensureImageHasSpanParent.ts b/packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/ensureImageHasSpanParent.ts
deleted file mode 100644
index 7ede477d9a8..00000000000
--- a/packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/ensureImageHasSpanParent.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { isElementOfType, isNodeOfType, wrap } from 'roosterjs-content-model-dom';
-
-/**
- * @internal
- * Ensure image is wrapped by a span element
- * @param image
- * @returns the image
- */
-export function ensureImageHasSpanParent(image: HTMLImageElement): HTMLImageElement {
- const parent = image.parentElement;
-
- if (
- parent &&
- isNodeOfType(parent, 'ELEMENT_NODE') &&
- isElementOfType(parent, 'span') &&
- parent.firstChild == image &&
- parent.lastChild == image
- ) {
- return image;
- }
-
- wrap(image.ownerDocument, image, 'span');
- return image;
-}
diff --git a/packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/setDOMSelection.ts b/packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/setDOMSelection.ts
index c615fc24963..c8570dd8ee9 100644
--- a/packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/setDOMSelection.ts
+++ b/packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/setDOMSelection.ts
@@ -1,6 +1,5 @@
import { addRangeToSelection } from './addRangeToSelection';
import { areSameSelections } from '../../corePlugin/cache/areSameSelections';
-import { ensureImageHasSpanParent } from './ensureImageHasSpanParent';
import { ensureUniqueId } from '../setEditorStyle/ensureUniqueId';
import { findLastedCoInMergedCell } from './findLastedCoInMergedCell';
import { findTableCellElement } from './findTableCellElement';
@@ -20,6 +19,7 @@ const TABLE_ID = 'table';
const CARET_CSS_RULE = 'caret-color: transparent';
const TRANSPARENT_SELECTION_CSS_RULE = 'background-color: transparent !important;';
const SELECTION_SELECTOR = '*::selection';
+const DEFAULT_SELECTION_BORDER_COLOR = '#DB626C';
/**
* @internal
@@ -45,12 +45,10 @@ export const setDOMSelection: SetDOMSelection = (core, selection, skipSelectionC
try {
switch (selection?.type) {
case 'image':
- const image = ensureImageHasSpanParent(selection.image);
+ const image = selection.image;
+
+ core.selection.selection = selection;
- core.selection.selection = {
- type: 'image',
- image,
- };
const imageSelectionColor = isDarkMode
? core.selection.imageSelectionBorderColorDark
: core.selection.imageSelectionBorderColor;
@@ -58,10 +56,10 @@ export const setDOMSelection: SetDOMSelection = (core, selection, skipSelectionC
core.api.setEditorStyle(
core,
DOM_SELECTION_CSS_KEY,
- `outline-style:solid!important; outline-color:${imageSelectionColor}!important;display: ${
- core.environment.isSafari ? '-webkit-inline-flex' : 'inline-flex'
- };`,
- [`span:has(>img#${ensureUniqueId(image, IMAGE_ID)})`]
+ `outline-style:auto!important; outline-color:${
+ imageSelectionColor || DEFAULT_SELECTION_BORDER_COLOR
+ }!important;`,
+ [`#${ensureUniqueId(image, IMAGE_ID)}`]
);
core.api.setEditorStyle(
core,
diff --git a/packages/roosterjs-content-model-core/test/coreApi/setDOMSelection/setDOMSelectionTest.ts b/packages/roosterjs-content-model-core/test/coreApi/setDOMSelection/setDOMSelectionTest.ts
index ebe6864382c..ec858920bc3 100644
--- a/packages/roosterjs-content-model-core/test/coreApi/setDOMSelection/setDOMSelectionTest.ts
+++ b/packages/roosterjs-content-model-core/test/coreApi/setDOMSelection/setDOMSelectionTest.ts
@@ -1,7 +1,7 @@
import * as addRangeToSelection from '../../../lib/coreApi/setDOMSelection/addRangeToSelection';
-import * as ensureImageHasSpanParent from '../../../lib/coreApi/setDOMSelection/ensureImageHasSpanParent';
import { DOMSelection, EditorCore } from 'roosterjs-content-model-types';
import { setDOMSelection } from '../../../lib/coreApi/setDOMSelection/setDOMSelection';
+
import {
DEFAULT_SELECTION_BORDER_COLOR,
DEFAULT_TABLE_CELL_SELECTION_BACKGROUND_COLOR,
@@ -314,8 +314,8 @@ describe('setDOMSelection', () => {
expect(setEditorStyleSpy).toHaveBeenCalledWith(
core,
'_DOMSelection',
- 'outline-style:solid!important; outline-color:#DB626C!important;display: inline-flex;',
- ['span:has(>img#image_0)']
+ 'outline-style:auto!important; outline-color:#DB626C!important;',
+ ['#image_0']
);
expect(setEditorStyleSpy).toHaveBeenCalledWith(
core,
@@ -374,8 +374,8 @@ describe('setDOMSelection', () => {
expect(setEditorStyleSpy).toHaveBeenCalledWith(
core,
'_DOMSelection',
- 'outline-style:solid!important; outline-color:red!important;display: inline-flex;',
- ['span:has(>img#image_0)']
+ 'outline-style:auto!important; outline-color:red!important;',
+ ['#image_0']
);
expect(setEditorStyleSpy).toHaveBeenCalledWith(
core,
@@ -441,8 +441,8 @@ describe('setDOMSelection', () => {
expect(setEditorStyleSpy).toHaveBeenCalledWith(
coreValue,
'_DOMSelection',
- 'outline-style:solid!important; outline-color:DarkColorMock-red!important;display: inline-flex;',
- ['span:has(>img#image_0)']
+ 'outline-style:auto!important; outline-color:DarkColorMock-red!important;',
+ ['#image_0']
);
expect(setEditorStyleSpy).toHaveBeenCalledWith(
coreValue,
@@ -502,8 +502,8 @@ describe('setDOMSelection', () => {
expect(setEditorStyleSpy).toHaveBeenCalledWith(
core,
'_DOMSelection',
- 'outline-style:solid!important; outline-color:#DB626C!important;display: inline-flex;',
- ['span:has(>img#image_0)']
+ 'outline-style:auto!important; outline-color:#DB626C!important;',
+ ['#image_0']
);
expect(setEditorStyleSpy).toHaveBeenCalledWith(
core,
@@ -563,8 +563,8 @@ describe('setDOMSelection', () => {
expect(setEditorStyleSpy).toHaveBeenCalledWith(
core,
'_DOMSelection',
- 'outline-style:solid!important; outline-color:#DB626C!important;display: inline-flex;',
- ['span:has(>img#image_0_0)']
+ 'outline-style:auto!important; outline-color:#DB626C!important;',
+ ['#image_0_0']
);
expect(setEditorStyleSpy).toHaveBeenCalledWith(
core,
@@ -927,9 +927,6 @@ describe('setDOMSelection', () => {
describe('Same selection', () => {
beforeEach(() => {
querySelectorAllSpy.and.returnValue([]);
- spyOn(ensureImageHasSpanParent, 'ensureImageHasSpanParent').and.callFake(
- image => image
- );
});
function runTest(
diff --git a/packages/roosterjs-content-model-dom/lib/modelToDom/optimizers/removeUnnecessarySpan.ts b/packages/roosterjs-content-model-dom/lib/modelToDom/optimizers/removeUnnecessarySpan.ts
index 3b0ccb11b88..ee048a395bb 100644
--- a/packages/roosterjs-content-model-dom/lib/modelToDom/optimizers/removeUnnecessarySpan.ts
+++ b/packages/roosterjs-content-model-dom/lib/modelToDom/optimizers/removeUnnecessarySpan.ts
@@ -8,8 +8,7 @@ export function removeUnnecessarySpan(root: Node) {
if (
isNodeOfType(child, 'ELEMENT_NODE') &&
child.tagName == 'SPAN' &&
- child.attributes.length == 0 &&
- !isImageSpan(child)
+ child.attributes.length == 0
) {
const node = child;
let refNode = child.nextSibling;
@@ -27,11 +26,3 @@ export function removeUnnecessarySpan(root: Node) {
}
}
}
-
-const isImageSpan = (child: HTMLElement) => {
- return (
- isNodeOfType(child.firstChild, 'ELEMENT_NODE') &&
- child.firstChild.tagName == 'IMG' &&
- child.firstChild == child.lastChild
- );
-};
diff --git a/packages/roosterjs-content-model-dom/test/modelToDom/optimizers/removeUnnecessarySpanTest.ts b/packages/roosterjs-content-model-dom/test/modelToDom/optimizers/removeUnnecessarySpanTest.ts
index f2aab1c27e2..e3e1b42d363 100644
--- a/packages/roosterjs-content-model-dom/test/modelToDom/optimizers/removeUnnecessarySpanTest.ts
+++ b/packages/roosterjs-content-model-dom/test/modelToDom/optimizers/removeUnnecessarySpanTest.ts
@@ -54,12 +54,12 @@ describe('removeUnnecessarySpan', () => {
expect(div.innerHTML).toBe('test1test2test3');
});
- it('Do not remove image span', () => {
+ it('Remove image span', () => {
const div = document.createElement('div');
- div.innerHTML = '';
+ div.innerHTML = '';
removeUnnecessarySpan(div);
- expect(div.innerHTML).toBe('');
+ expect(div.innerHTML).toBe('');
});
});
diff --git a/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts b/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts
index 6cccb46a8e4..128d76a1113 100644
--- a/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts
+++ b/packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts
@@ -125,10 +125,6 @@ export class ImageEditPlugin implements ImageEditor, EditorPlugin {
image: HTMLImageElement,
apiOperation?: ImageEditOperation
) {
- const imageSpan = image.parentElement;
- if (!imageSpan || (imageSpan && !isElementOfType(imageSpan, 'span'))) {
- return;
- }
this.imageEditInfo = getSelectedImageMetadata(editor, image);
this.lastSrc = image.getAttribute('src');
this.imageHTMLOptions = getHTMLImageOptions(editor, this.options, this.imageEditInfo);
@@ -142,7 +138,6 @@ export class ImageEditPlugin implements ImageEditor, EditorPlugin {
} = createImageWrapper(
editor,
image,
- imageSpan,
this.options,
this.imageEditInfo,
this.imageHTMLOptions,
diff --git a/packages/roosterjs-content-model-plugins/lib/imageEdit/utils/createImageWrapper.ts b/packages/roosterjs-content-model-plugins/lib/imageEdit/utils/createImageWrapper.ts
index 9a11e44565f..3fc0e5fe92c 100644
--- a/packages/roosterjs-content-model-plugins/lib/imageEdit/utils/createImageWrapper.ts
+++ b/packages/roosterjs-content-model-plugins/lib/imageEdit/utils/createImageWrapper.ts
@@ -1,6 +1,7 @@
import { createImageCropper } from '../Cropper/createImageCropper';
import { createImageResizer } from '../Resizer/createImageResizer';
import { createImageRotator } from '../Rotator/createImageRotator';
+import { wrap } from 'roosterjs-content-model-dom';
import type {
IEditor,
@@ -28,7 +29,6 @@ export interface WrapperElements {
export function createImageWrapper(
editor: IEditor,
image: HTMLImageElement,
- imageSpan: HTMLSpanElement,
options: ImageEditOptions,
editInfo: ImageMetadataFormat,
htmlOptions: ImageHtmlOptions,
@@ -60,6 +60,7 @@ export function createImageWrapper(
rotators,
croppers
);
+ const imageSpan = wrap(doc, image, 'span');
const shadowSpan = createShadowSpan(wrapper, imageSpan);
return { wrapper, shadowSpan, imageClone, resizers, rotators, croppers };
}
@@ -97,7 +98,9 @@ const createWrapper = (
editInfo.angleRad ?? 0
}rad); text-align: left;`
);
- wrapper.style.display = editor.getEnvironment().isSafari ? 'inline-block' : 'inline-flex';
+ wrapper.style.display = editor.getEnvironment().isSafari
+ ? '-webkit-inline-flex'
+ : 'inline-flex';
const border = createBorder(editor, options.borderColor);
wrapper.appendChild(imageBox);
diff --git a/packages/roosterjs-content-model-plugins/test/imageEdit/Rotator/updateRotateHandleTest.ts b/packages/roosterjs-content-model-plugins/test/imageEdit/Rotator/updateRotateHandleTest.ts
index 98cbfaa7155..4deb0b7eb64 100644
--- a/packages/roosterjs-content-model-plugins/test/imageEdit/Rotator/updateRotateHandleTest.ts
+++ b/packages/roosterjs-content-model-plugins/test/imageEdit/Rotator/updateRotateHandleTest.ts
@@ -57,15 +57,7 @@ xdescribe('updateRotateHandlePosition', () => {
bottomPercent: 0,
angleRad: 0,
};
- const { wrapper } = createImageWrapper(
- editor,
- image,
- imageSpan,
- {},
- imageInfo,
- options,
- 'rotate'
- );
+ const { wrapper } = createImageWrapper(editor, image, {}, imageInfo, options, 'rotate');
const rotateCenter = wrapper.querySelector('.r_rotateC')! as HTMLElement;
const rotateHandle = wrapper.querySelector('.r_rotateH')! as HTMLElement;
spyOn(rotateHandle, 'getBoundingClientRect').and.returnValues(rotatePosition);
diff --git a/packages/roosterjs-content-model-plugins/test/imageEdit/utils/createImageWrapperTest.ts b/packages/roosterjs-content-model-plugins/test/imageEdit/utils/createImageWrapperTest.ts
index b2cf97173e9..ff8382d7ae8 100644
--- a/packages/roosterjs-content-model-plugins/test/imageEdit/utils/createImageWrapperTest.ts
+++ b/packages/roosterjs-content-model-plugins/test/imageEdit/utils/createImageWrapperTest.ts
@@ -24,7 +24,7 @@ describe('createImageWrapper', () => {
const result = createImageWrapper(
editor,
image,
- imageSpan,
+
options,
editInfo,
htmlOptions,
diff --git a/packages/roosterjs-content-model-plugins/test/imageEdit/utils/updateWrapperTest.ts b/packages/roosterjs-content-model-plugins/test/imageEdit/utils/updateWrapperTest.ts
index df74a226e3b..65d99d4ddbc 100644
--- a/packages/roosterjs-content-model-plugins/test/imageEdit/utils/updateWrapperTest.ts
+++ b/packages/roosterjs-content-model-plugins/test/imageEdit/utils/updateWrapperTest.ts
@@ -32,15 +32,12 @@ describe('updateWrapper', () => {
isSmallImage: false,
};
const image = document.createElement('img');
- const imageSpan = document.createElement('span');
- imageSpan.appendChild(image);
- document.body.appendChild(imageSpan);
+ document.body.appendChild(image);
it('should update size', () => {
const { wrapper, imageClone, resizers } = createImageWrapper(
editor,
image,
- imageSpan,
options,
editInfo,
htmlOptions,