]> BookStack Code Mirror - bookstack/blobdiff - resources/js/wysiwyg/nodes/image.ts
System CLI: Updated to 126de5599c state
[bookstack] / resources / js / wysiwyg / nodes / image.ts
index 1e2cbd83c113f0dd827077a00445fa1b3c0cb9e3..b6d362b62c91afe2ee79514c8af89b75ffd44030 100644 (file)
@@ -1,14 +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 {CommonBlockAlignment, extractAlignmentFromElement} from "./_common";
+import {$selectSingleNode} from "../utils/selection";
+import {SerializedElementNode} from "lexical/nodes/LexicalElementNode";
 
 export interface ImageNodeOptions {
     alt?: string;
@@ -21,25 +21,28 @@ export type SerializedImageNode = Spread<{
     alt: string;
     width: number;
     height: number;
-}, SerializedLexicalNode>
+    alignment: CommonBlockAlignment;
+}, SerializedElementNode>
 
-export class ImageNode extends DecoratorNode<HTMLElement> {
+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) {
@@ -56,6 +59,16 @@ export class ImageNode extends DecoratorNode<HTMLElement> {
         }
     }
 
+    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;
@@ -86,21 +99,23 @@ export class ImageNode extends DecoratorNode<HTMLElement> {
         return self.__width;
     }
 
-    isInline(): boolean {
-        return true;
+    setAlignment(alignment: CommonBlockAlignment) {
+        const self = this.getWritable();
+        self.__alignment = alignment;
+    }
+
+    getAlignment(): CommonBlockAlignment {
+        const self = this.getLatest();
+        return self.__alignment;
     }
 
-    decorate(editor: LexicalEditor, config: EditorConfig): HTMLElement {
-        console.log('decorate!');
-        return el('div', {
-            class: 'editor-image-decorator',
-        }, ['decoration!!!']);
+    isInline(): boolean {
+        return true;
     }
 
     createDOM(_config: EditorConfig, _editor: LexicalEditor) {
         const element = document.createElement('img');
         element.setAttribute('src', this.__src);
-        element.textContent
 
         if (this.__width) {
             element.setAttribute('width', String(this.__width));
@@ -111,14 +126,58 @@ export class ImageNode extends DecoratorNode<HTMLElement> {
         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: unknown, dom: HTMLElement) {
-        // Returning false tells Lexical that this node does not need its
-        // DOM element replacing with a new copy from createDOM.
+    updateDOM(prevNode: ImageNode, dom: HTMLElement) {
+        if (prevNode.__src !== this.__src) {
+            dom.setAttribute('src', this.__src);
+        }
+
+        if (prevNode.__width !== this.__width) {
+            if (this.__width) {
+                dom.setAttribute('width', String(this.__width));
+            } else {
+                dom.removeAttribute('width');
+            }
+        }
+
+        if (prevNode.__height !== this.__height) {
+            if (this.__height) {
+                dom.setAttribute('height', String(this.__height));
+            } else {
+                dom.removeAttribute('height');
+            }
+        }
+
+        if (prevNode.__alt !== this.__alt) {
+            if (this.__alt) {
+                dom.setAttribute('alt', String(this.__alt));
+            } else {
+                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);
+            }
+        }
+
         return false;
     }
 
@@ -135,9 +194,10 @@ export class ImageNode extends DecoratorNode<HTMLElement> {
                             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,
                 };
@@ -147,21 +207,25 @@ export class ImageNode extends DecoratorNode<HTMLElement> {
 
     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;
     }
 }