Skip to content

Commit fda242d

Browse files
committed
Lexical: Fixed tiny image resizer on image insert
Added specific focus on image insert, and updated resize handler to watch for load events and toggle a resize once loaded.
1 parent aac5479 commit fda242d

File tree

2 files changed

+39
-22
lines changed

2 files changed

+39
-22
lines changed

resources/js/wysiwyg/ui/defaults/buttons/objects.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export const image: EditorButtonDefinition = {
9292
context.editor.update(() => {
9393
const link = $createLinkedImageNodeFromImageData(image);
9494
$insertNodes([link]);
95+
link.select();
9596
});
9697
})
9798
});

resources/js/wysiwyg/ui/framework/helpers/node-resizer.ts

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,21 @@ function isNodeWithSize(node: LexicalNode): node is NodeHasSize&LexicalNode {
1212

1313
class NodeResizer {
1414
protected context: EditorUiContext;
15-
protected dom: HTMLElement|null = null;
15+
protected resizerDOM: HTMLElement|null = null;
16+
protected targetDOM: HTMLElement|null = null;
1617
protected scrollContainer: HTMLElement;
1718

1819
protected mouseTracker: MouseDragTracker|null = null;
1920
protected activeSelection: string = '';
21+
protected loadAbortController = new AbortController();
2022

2123
constructor(context: EditorUiContext) {
2224
this.context = context;
2325
this.scrollContainer = context.scrollDOM;
2426

2527
this.onSelectionChange = this.onSelectionChange.bind(this);
28+
this.onTargetDOMLoad = this.onTargetDOMLoad.bind(this);
29+
2630
context.manager.onSelectionChange(this.onSelectionChange);
2731
}
2832

@@ -47,56 +51,68 @@ class NodeResizer {
4751
}
4852
}
4953

54+
onTargetDOMLoad(): void {
55+
this.updateResizerPosition();
56+
}
57+
5058
teardown() {
5159
this.context.manager.offSelectionChange(this.onSelectionChange);
5260
this.hide();
5361
}
5462

55-
protected showForNode(node: NodeHasSize&LexicalNode, dom: HTMLElement) {
56-
this.dom = this.buildDOM();
63+
protected showForNode(node: NodeHasSize&LexicalNode, targetDOM: HTMLElement) {
64+
this.resizerDOM = this.buildDOM();
65+
this.targetDOM = targetDOM;
5766

5867
let ghost = el('span', {class: 'editor-node-resizer-ghost'});
5968
if ($isImageNode(node)) {
60-
ghost = el('img', {src: dom.getAttribute('src'), class: 'editor-node-resizer-ghost'});
69+
ghost = el('img', {src: targetDOM.getAttribute('src'), class: 'editor-node-resizer-ghost'});
6170
}
62-
this.dom.append(ghost);
71+
this.resizerDOM.append(ghost);
6372

64-
this.context.scrollDOM.append(this.dom);
65-
this.updateDOMPosition(dom);
73+
this.context.scrollDOM.append(this.resizerDOM);
74+
this.updateResizerPosition();
6675

67-
this.mouseTracker = this.setupTracker(this.dom, node, dom);
76+
this.mouseTracker = this.setupTracker(this.resizerDOM, node, targetDOM);
6877
this.activeSelection = node.getKey();
78+
79+
if (targetDOM.matches('img, embed, iframe, object')) {
80+
this.loadAbortController = new AbortController();
81+
targetDOM.addEventListener('load', this.onTargetDOMLoad, { signal: this.loadAbortController.signal });
82+
}
6983
}
7084

71-
protected updateDOMPosition(nodeDOM: HTMLElement) {
72-
if (!this.dom) {
85+
protected updateResizerPosition() {
86+
if (!this.resizerDOM || !this.targetDOM) {
7387
return;
7488
}
7589

7690
const scrollAreaRect = this.scrollContainer.getBoundingClientRect();
77-
const nodeRect = nodeDOM.getBoundingClientRect();
91+
const nodeRect = this.targetDOM.getBoundingClientRect();
7892
const top = nodeRect.top - (scrollAreaRect.top - this.scrollContainer.scrollTop);
7993
const left = nodeRect.left - scrollAreaRect.left;
8094

81-
this.dom.style.top = `${top}px`;
82-
this.dom.style.left = `${left}px`;
83-
this.dom.style.width = nodeRect.width + 'px';
84-
this.dom.style.height = nodeRect.height + 'px';
95+
this.resizerDOM.style.top = `${top}px`;
96+
this.resizerDOM.style.left = `${left}px`;
97+
this.resizerDOM.style.width = nodeRect.width + 'px';
98+
this.resizerDOM.style.height = nodeRect.height + 'px';
8599
}
86100

87101
protected updateDOMSize(width: number, height: number): void {
88-
if (!this.dom) {
102+
if (!this.resizerDOM) {
89103
return;
90104
}
91105

92-
this.dom.style.width = width + 'px';
93-
this.dom.style.height = height + 'px';
106+
this.resizerDOM.style.width = width + 'px';
107+
this.resizerDOM.style.height = height + 'px';
94108
}
95109

96110
protected hide() {
97111
this.mouseTracker?.teardown();
98-
this.dom?.remove();
112+
this.resizerDOM?.remove();
113+
this.targetDOM = null;
99114
this.activeSelection = '';
115+
this.loadAbortController.abort();
100116
}
101117

102118
protected buildDOM() {
@@ -140,7 +156,7 @@ class NodeResizer {
140156

141157
return new MouseDragTracker(container, '.editor-node-resizer-handle', {
142158
down(event: MouseEvent, handle: HTMLElement) {
143-
_this.dom?.classList.add('active');
159+
_this.resizerDOM?.classList.add('active');
144160
_this.context.editor.getEditorState().read(() => {
145161
const domRect = nodeDOM.getBoundingClientRect();
146162
startingWidth = node.getWidth() || domRect.width;
@@ -165,10 +181,10 @@ class NodeResizer {
165181
node.setHeight(hasHeight ? size.height : 0);
166182
_this.context.manager.triggerLayoutUpdate();
167183
requestAnimationFrame(() => {
168-
_this.updateDOMPosition(nodeDOM);
184+
_this.updateResizerPosition();
169185
})
170186
});
171-
_this.dom?.classList.remove('active');
187+
_this.resizerDOM?.classList.remove('active');
172188
}
173189
});
174190
}

0 commit comments

Comments
 (0)