X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/e959c468f664b937925d39d0188dd94db546d2cb..refs/pull/5313/head:/resources/js/wysiwyg/nodes/image.ts diff --git a/resources/js/wysiwyg/nodes/image.ts b/resources/js/wysiwyg/nodes/image.ts index 9f017b5fe..b6d362b62 100644 --- a/resources/js/wysiwyg/nodes/image.ts +++ b/resources/js/wysiwyg/nodes/image.ts @@ -1,15 +1,14 @@ import { - DecoratorNode, DOMConversion, DOMConversionMap, - DOMConversionOutput, + DOMConversionOutput, ElementNode, LexicalEditor, LexicalNode, - SerializedLexicalNode, Spread } from "lexical"; import type {EditorConfig} from "lexical/LexicalEditor"; -import {el} from "../helpers"; -import {EditorDecoratorAdapter} from "../ui/framework/decorator"; +import {CommonBlockAlignment, extractAlignmentFromElement} from "./_common"; +import {$selectSingleNode} from "../utils/selection"; +import {SerializedElementNode} from "lexical/nodes/LexicalElementNode"; export interface ImageNodeOptions { alt?: string; @@ -22,25 +21,28 @@ export type SerializedImageNode = Spread<{ alt: string; width: number; height: number; -}, SerializedLexicalNode> + alignment: CommonBlockAlignment; +}, SerializedElementNode> -export class ImageNode extends DecoratorNode { +export class ImageNode extends ElementNode { __src: string = ''; __alt: string = ''; __width: number = 0; __height: number = 0; - // TODO - Alignment + __alignment: CommonBlockAlignment = ''; static getType(): string { return 'image'; } static clone(node: ImageNode): ImageNode { - return new ImageNode(node.__src, { + const newNode = new ImageNode(node.__src, { alt: node.__alt, width: node.__width, height: node.__height, - }); + }, node.__key); + newNode.__alignment = node.__alignment; + return newNode; } constructor(src: string, options: ImageNodeOptions, key?: string) { @@ -57,6 +59,16 @@ export class ImageNode extends DecoratorNode { } } + setSrc(src: string): void { + const self = this.getWritable(); + self.__src = src; + } + + getSrc(): string { + const self = this.getLatest(); + return self.__src; + } + setAltText(altText: string): void { const self = this.getWritable(); self.__alt = altText; @@ -87,15 +99,18 @@ export class ImageNode extends DecoratorNode { return self.__width; } - isInline(): boolean { - return true; + setAlignment(alignment: CommonBlockAlignment) { + const self = this.getWritable(); + self.__alignment = alignment; } - decorate(editor: LexicalEditor, config: EditorConfig): EditorDecoratorAdapter { - return { - type: 'image', - getNode: () => this, - }; + getAlignment(): CommonBlockAlignment { + const self = this.getLatest(); + return self.__alignment; + } + + isInline(): boolean { + return true; } createDOM(_config: EditorConfig, _editor: LexicalEditor) { @@ -111,40 +126,55 @@ export class ImageNode extends DecoratorNode { if (this.__alt) { element.setAttribute('alt', this.__alt); } - return el('span', {class: 'editor-image-wrap'}, [ - element, - ]); + + if (this.__alignment) { + element.classList.add('align-' + this.__alignment); + } + + element.addEventListener('click', e => { + _editor.update(() => { + $selectSingleNode(this); + }); + }); + + return element; } updateDOM(prevNode: ImageNode, dom: HTMLElement) { - const image = dom.querySelector('img'); - if (!image) return false; - if (prevNode.__src !== this.__src) { - image.setAttribute('src', this.__src); + dom.setAttribute('src', this.__src); } if (prevNode.__width !== this.__width) { if (this.__width) { - image.setAttribute('width', String(this.__width)); + dom.setAttribute('width', String(this.__width)); } else { - image.removeAttribute('width'); + dom.removeAttribute('width'); } } if (prevNode.__height !== this.__height) { if (this.__height) { - image.setAttribute('height', String(this.__height)); + dom.setAttribute('height', String(this.__height)); } else { - image.removeAttribute('height'); + dom.removeAttribute('height'); } } if (prevNode.__alt !== this.__alt) { if (this.__alt) { - image.setAttribute('alt', String(this.__alt)); + dom.setAttribute('alt', String(this.__alt)); } else { - image.removeAttribute('alt'); + dom.removeAttribute('alt'); + } + } + + if (prevNode.__alignment !== this.__alignment) { + if (prevNode.__alignment) { + dom.classList.remove('align-' + prevNode.__alignment); + } + if (this.__alignment) { + dom.classList.add('align-' + this.__alignment); } } @@ -164,9 +194,10 @@ export class ImageNode extends DecoratorNode { width: Number.parseInt(element.getAttribute('width') || '0'), } - return { - node: new ImageNode(src, options), - }; + const node = new ImageNode(src, options); + node.setAlignment(extractAlignmentFromElement(element)); + + return { node }; }, priority: 3, }; @@ -176,21 +207,25 @@ export class ImageNode extends DecoratorNode { exportJSON(): SerializedImageNode { return { + ...super.exportJSON(), type: 'image', version: 1, src: this.__src, alt: this.__alt, height: this.__height, - width: this.__width + width: this.__width, + alignment: this.__alignment, }; } static importJSON(serializedNode: SerializedImageNode): ImageNode { - return $createImageNode(serializedNode.src, { + const node = $createImageNode(serializedNode.src, { alt: serializedNode.alt, width: serializedNode.width, height: serializedNode.height, }); + node.setAlignment(serializedNode.alignment); + return node; } }