mirror of
				https://github.com/BookStackApp/BookStack.git
				synced 2025-11-03 02:13:16 +03:00 
			
		
		
		
	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.
This commit is contained in:
		@@ -92,6 +92,7 @@ export const image: EditorButtonDefinition = {
 | 
				
			|||||||
                context.editor.update(() => {
 | 
					                context.editor.update(() => {
 | 
				
			||||||
                    const link = $createLinkedImageNodeFromImageData(image);
 | 
					                    const link = $createLinkedImageNodeFromImageData(image);
 | 
				
			||||||
                    $insertNodes([link]);
 | 
					                    $insertNodes([link]);
 | 
				
			||||||
 | 
					                    link.select();
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,17 +12,21 @@ function isNodeWithSize(node: LexicalNode): node is NodeHasSize&LexicalNode {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class NodeResizer {
 | 
					class NodeResizer {
 | 
				
			||||||
    protected context: EditorUiContext;
 | 
					    protected context: EditorUiContext;
 | 
				
			||||||
    protected dom: HTMLElement|null = null;
 | 
					    protected resizerDOM: HTMLElement|null = null;
 | 
				
			||||||
 | 
					    protected targetDOM: HTMLElement|null = null;
 | 
				
			||||||
    protected scrollContainer: HTMLElement;
 | 
					    protected scrollContainer: HTMLElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected mouseTracker: MouseDragTracker|null = null;
 | 
					    protected mouseTracker: MouseDragTracker|null = null;
 | 
				
			||||||
    protected activeSelection: string = '';
 | 
					    protected activeSelection: string = '';
 | 
				
			||||||
 | 
					    protected loadAbortController = new AbortController();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(context: EditorUiContext) {
 | 
					    constructor(context: EditorUiContext) {
 | 
				
			||||||
        this.context = context;
 | 
					        this.context = context;
 | 
				
			||||||
        this.scrollContainer = context.scrollDOM;
 | 
					        this.scrollContainer = context.scrollDOM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.onSelectionChange = this.onSelectionChange.bind(this);
 | 
					        this.onSelectionChange = this.onSelectionChange.bind(this);
 | 
				
			||||||
 | 
					        this.onTargetDOMLoad = this.onTargetDOMLoad.bind(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        context.manager.onSelectionChange(this.onSelectionChange);
 | 
					        context.manager.onSelectionChange(this.onSelectionChange);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,56 +51,68 @@ class NodeResizer {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onTargetDOMLoad(): void {
 | 
				
			||||||
 | 
					        this.updateResizerPosition();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    teardown() {
 | 
					    teardown() {
 | 
				
			||||||
        this.context.manager.offSelectionChange(this.onSelectionChange);
 | 
					        this.context.manager.offSelectionChange(this.onSelectionChange);
 | 
				
			||||||
        this.hide();
 | 
					        this.hide();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected showForNode(node: NodeHasSize&LexicalNode, dom: HTMLElement) {
 | 
					    protected showForNode(node: NodeHasSize&LexicalNode, targetDOM: HTMLElement) {
 | 
				
			||||||
        this.dom = this.buildDOM();
 | 
					        this.resizerDOM = this.buildDOM();
 | 
				
			||||||
 | 
					        this.targetDOM = targetDOM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let ghost = el('span', {class: 'editor-node-resizer-ghost'});
 | 
					        let ghost = el('span', {class: 'editor-node-resizer-ghost'});
 | 
				
			||||||
        if ($isImageNode(node)) {
 | 
					        if ($isImageNode(node)) {
 | 
				
			||||||
            ghost = el('img', {src: dom.getAttribute('src'), class: 'editor-node-resizer-ghost'});
 | 
					            ghost = el('img', {src: targetDOM.getAttribute('src'), class: 'editor-node-resizer-ghost'});
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        this.dom.append(ghost);
 | 
					        this.resizerDOM.append(ghost);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.context.scrollDOM.append(this.dom);
 | 
					        this.context.scrollDOM.append(this.resizerDOM);
 | 
				
			||||||
        this.updateDOMPosition(dom);
 | 
					        this.updateResizerPosition();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.mouseTracker = this.setupTracker(this.dom, node, dom);
 | 
					        this.mouseTracker = this.setupTracker(this.resizerDOM, node, targetDOM);
 | 
				
			||||||
        this.activeSelection = node.getKey();
 | 
					        this.activeSelection = node.getKey();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (targetDOM.matches('img, embed, iframe, object')) {
 | 
				
			||||||
 | 
					            this.loadAbortController = new AbortController();
 | 
				
			||||||
 | 
					            targetDOM.addEventListener('load', this.onTargetDOMLoad, { signal: this.loadAbortController.signal });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected updateDOMPosition(nodeDOM: HTMLElement) {
 | 
					    protected updateResizerPosition() {
 | 
				
			||||||
        if (!this.dom) {
 | 
					        if (!this.resizerDOM || !this.targetDOM) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const scrollAreaRect = this.scrollContainer.getBoundingClientRect();
 | 
					        const scrollAreaRect = this.scrollContainer.getBoundingClientRect();
 | 
				
			||||||
        const nodeRect = nodeDOM.getBoundingClientRect();
 | 
					        const nodeRect = this.targetDOM.getBoundingClientRect();
 | 
				
			||||||
        const top = nodeRect.top - (scrollAreaRect.top - this.scrollContainer.scrollTop);
 | 
					        const top = nodeRect.top - (scrollAreaRect.top - this.scrollContainer.scrollTop);
 | 
				
			||||||
        const left = nodeRect.left - scrollAreaRect.left;
 | 
					        const left = nodeRect.left - scrollAreaRect.left;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.dom.style.top = `${top}px`;
 | 
					        this.resizerDOM.style.top = `${top}px`;
 | 
				
			||||||
        this.dom.style.left = `${left}px`;
 | 
					        this.resizerDOM.style.left = `${left}px`;
 | 
				
			||||||
        this.dom.style.width = nodeRect.width + 'px';
 | 
					        this.resizerDOM.style.width = nodeRect.width + 'px';
 | 
				
			||||||
        this.dom.style.height = nodeRect.height + 'px';
 | 
					        this.resizerDOM.style.height = nodeRect.height + 'px';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected updateDOMSize(width: number, height: number): void {
 | 
					    protected updateDOMSize(width: number, height: number): void {
 | 
				
			||||||
        if (!this.dom) {
 | 
					        if (!this.resizerDOM) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.dom.style.width = width + 'px';
 | 
					        this.resizerDOM.style.width = width + 'px';
 | 
				
			||||||
        this.dom.style.height = height + 'px';
 | 
					        this.resizerDOM.style.height = height + 'px';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected hide() {
 | 
					    protected hide() {
 | 
				
			||||||
        this.mouseTracker?.teardown();
 | 
					        this.mouseTracker?.teardown();
 | 
				
			||||||
        this.dom?.remove();
 | 
					        this.resizerDOM?.remove();
 | 
				
			||||||
 | 
					        this.targetDOM = null;
 | 
				
			||||||
        this.activeSelection = '';
 | 
					        this.activeSelection = '';
 | 
				
			||||||
 | 
					        this.loadAbortController.abort();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected buildDOM() {
 | 
					    protected buildDOM() {
 | 
				
			||||||
@@ -140,7 +156,7 @@ class NodeResizer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return new MouseDragTracker(container, '.editor-node-resizer-handle', {
 | 
					        return new MouseDragTracker(container, '.editor-node-resizer-handle', {
 | 
				
			||||||
            down(event: MouseEvent, handle: HTMLElement) {
 | 
					            down(event: MouseEvent, handle: HTMLElement) {
 | 
				
			||||||
                _this.dom?.classList.add('active');
 | 
					                _this.resizerDOM?.classList.add('active');
 | 
				
			||||||
                _this.context.editor.getEditorState().read(() => {
 | 
					                _this.context.editor.getEditorState().read(() => {
 | 
				
			||||||
                    const domRect = nodeDOM.getBoundingClientRect();
 | 
					                    const domRect = nodeDOM.getBoundingClientRect();
 | 
				
			||||||
                    startingWidth = node.getWidth() || domRect.width;
 | 
					                    startingWidth = node.getWidth() || domRect.width;
 | 
				
			||||||
@@ -165,10 +181,10 @@ class NodeResizer {
 | 
				
			|||||||
                    node.setHeight(hasHeight ? size.height : 0);
 | 
					                    node.setHeight(hasHeight ? size.height : 0);
 | 
				
			||||||
                    _this.context.manager.triggerLayoutUpdate();
 | 
					                    _this.context.manager.triggerLayoutUpdate();
 | 
				
			||||||
                    requestAnimationFrame(() => {
 | 
					                    requestAnimationFrame(() => {
 | 
				
			||||||
                        _this.updateDOMPosition(nodeDOM);
 | 
					                        _this.updateResizerPosition();
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
                _this.dom?.classList.remove('active');
 | 
					                _this.resizerDOM?.classList.remove('active');
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user