-
Notifications
You must be signed in to change notification settings - Fork 167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modify Image wrapper to insert image wrapper outside the editor #1377
Conversation
…u/juliaroldi/image-wrapper
const clone = this.image.cloneNode(); | ||
const wrappedImage = wrap(clone, KnownCreateElementDataIndex.ImageEditWrapper); | ||
|
||
this.clonedImage = wrappedImage.firstElementChild as HTMLImageElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just use "clone" instead of "wrappedImage.firstElementChild as HTMLImageElement" here?
|
||
this.clonedImage = wrappedImage.firstElementChild as HTMLImageElement; | ||
|
||
// Wrap the cloned image with an entity so that we can easily retrieve it later | ||
const { wrapper } = insertEntity( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the editing wrapper is not part of editor now, I don't think we still need to "insertEntity"
@@ -352,9 +373,11 @@ export default class ImageEdit implements EditorPlugin { | |||
this.lastSrc = this.image.getAttribute('src'); | |||
|
|||
// Set image src to original src to help show editing UI, also it will be used when regenerate image dataURL after editing | |||
this.image.style.visibility = 'hidden'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this will still modify the editor content.
Can we add this visibility rule to image selection's global CSS so that editor content is not impacted?
@@ -352,9 +373,11 @@ export default class ImageEdit implements EditorPlugin { | |||
this.lastSrc = this.image.getAttribute('src'); | |||
|
|||
// Set image src to original src to help show editing UI, also it will be used when regenerate image dataURL after editing | |||
this.image.style.visibility = 'hidden'; | |||
this.image.src = this.editInfo.src; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need to change original image's src?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, because when we applyFormat we compare the image edited with the previous src, so to make sure apply format works as expected we also need to change this src.
|
||
return entity?.type == IMAGE_EDIT_WRAPPER_ENTITY_TYPE ? entity.wrapper : null; | ||
private getImageWrapper(): HTMLElement { | ||
return document.getElementById(this.imageId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the cloned image will have the same id with the original one, how can we guarantee this will return the cloned one?
And if there are 2 editors in the same document, it is possible two editors both have image with the same id. Better change the image id to combine editor id and image id to make it unique
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And instead of querying by image id, since there will be only one image editing per editor, you can just hold the reference to the wrapper element in this plugin. So it will be easier to get it
Generally, the behavior is good. Only one issue, if editor is zoomed, the editing image is not zoomed together, so when select and edit the image, its size changes. |
@@ -195,6 +190,7 @@ export default class ImageEdit implements EditorPlugin { | |||
e.selectionRangeEx.image, | |||
ImageEditOperation.ResizeAndRotate | |||
); | |||
this.addVisibilityCssTag(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this call need to be inside setEditingImage() function. Because setEditingImage() is a public function and other code can also call it. When it is called we should show/hide the original image
this.wrapper = this.editor.getDocument().createElement('span'); | ||
this.wrapper.appendChild(wrappedImage); | ||
this.wrapper.style.maxWidth = '100%'; | ||
this.wrapper.style.position = 'fixed'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be added into KnownCreateElementDataIndex.ImageEditWrapper so that one single wrap() call should make all of them working?
|
||
// Cache current src so that we can compare it after edit see if src is changed | ||
this.lastSrc = this.image.getAttribute('src'); | ||
|
||
// Set image src to original src to help show editing UI, also it will be used when regenerate image dataURL after editing | ||
this.image.style.visibility = 'hidden'; | ||
this.image.className = STYLE_IMAGE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually the image should already have id. If not, you add some API in editor to ensure it. So no need to change its className
|
||
private addVisibilityCssTag() { | ||
const doc = this.editor.getDocument(); | ||
let styleTag = doc.getElementById(STYLE_IMAGE) as HTMLStyleElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why reuse the same string for style tag and image class?
Also, if there are multiple editor in the same page, there will be duplicated id for style tags then hard to distinguish.
We already have code in editor core to generate STYLE tag and add style rule. Consider reuse that code by adding some editor API or parameter to existing API. The reuse part can be in separate PR, but at least make sure the style element id is unique. You can use editor DIV id.
const doc = this.editor.getDocument(); | ||
let styleTag = doc.getElementById(STYLE_IMAGE) as HTMLStyleElement; | ||
if (!styleTag) { | ||
const cssRule = `.${STYLE_IMAGE} {visibility: hidden}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use editor id and image id, just like how we do selection border for image
if (!styleTag) { | ||
const cssRule = `.${STYLE_IMAGE} {visibility: hidden}`; | ||
styleTag = doc.createElement('style'); | ||
styleTag.id = STYLE_IMAGE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I think you can hold a reference to this style element so no id is needed at all.
@@ -174,6 +168,7 @@ export default class ImageEdit implements EditorPlugin { | |||
* Dispose this plugin | |||
*/ | |||
dispose() { | |||
this.removeVisibilityCssTag(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also need to remove the editing image DOM element here, and the call to removeVisibilityCssTag() can be part of it.
}; | ||
|
||
/** | ||
* Update image edit elements to reflect current editing result | ||
* @param context | ||
*/ | ||
private updateWrapper = (context?: DragAndDropContext) => { | ||
const wrapper = this.getImageWrapper(); | ||
if (wrapper) { | ||
if (this.wrapper) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consider do
const wrapper = this.wrapper;
if (wrapper) {
...
So no need to do use "this.wrapper" everywhere to save some bytes
@@ -49,7 +53,7 @@ export const selectImage: SelectImage = (core: EditorCore, image: HTMLImageEleme | |||
const select = (core: EditorCore, image: HTMLImageElement) => { | |||
removeImportantStyleRule(image, ['border', 'margin']); | |||
const borderCSS = buildBorderCSS(core, image.id); | |||
addSelectionStyle(core, borderCSS, STYLE_ID); | |||
setGlobalCssStyles(core.contentDiv.ownerDocument, borderCSS, STYLE_ID + core.contentDiv.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use removeGlobalCssStyle() in line 67.
Same for selectTable()
const wrappedImage = wrap(this.clonedImage, KnownCreateElementDataIndex.ImageEditWrapper); | ||
this.wrapper = wrap(wrappedImage, KnownCreateElementDataIndex.ImageEditContainer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I mean merge these two into one. Because wrappedImage is only used here. So we can do
this.wrapper = wrap(this.clonedImage, KnownCreateElementDataIndex.ImageEditWrapper);
Then you can modify the definition of ImageEditWrapper to make it has two layers of wrapper.
} | ||
|
||
wrapper.style.display = Browser.isSafari ? 'inline-block' : 'inline-flex'; | ||
this.wrapper.style.display = Browser.isSafari ? 'inline-block' : 'inline-flex'; | ||
|
||
// Cache current src so that we can compare it after edit see if src is changed | ||
this.lastSrc = this.image.getAttribute('src'); | ||
|
||
// Set image src to original src to help show editing UI, also it will be used when regenerate image dataURL after editing | ||
this.image.src = this.editInfo.src; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still have concern here. If you need to compare, can you compare with the cloned image?
My primary goal here is not to do any change to editor content when edit.
7a7562b
to
98f41cc
Compare
export default function removeGlobalCssStyle(doc: Document, styleId: string) { | ||
const styleTag = doc.getElementById(styleId) as HTMLStyleElement; | ||
if (styleTag) { | ||
doc.head.removeChild(styleTag); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use styleTag.parentNode?.removeChild(styleTag)
instead
Although accoding to our code, style tag should always be under HEAD. But if we changed that behavior, there will be no build time error or test case to remind us change here. So better make it more robust
After this change, when in editing the image will be cloned and it's clone will be added to a wrapper outside the editor.
Every change made to cloned image will be reflected to image when the quite editing, the editing process will happen outside the editor and DOM structure of the editor will not change while editing.