4 DOMConversionOutput, ElementNode,
5 LexicalEditor, LexicalNode,
8 import type {EditorConfig} from "lexical/LexicalEditor";
9 import {CommonBlockAlignment, extractAlignmentFromElement} from "lexical/nodes/common";
10 import {$selectSingleNode} from "../../utils/selection";
11 import {SerializedElementNode} from "lexical/nodes/LexicalElementNode";
13 export interface ImageNodeOptions {
19 export type SerializedImageNode = Spread<{
24 alignment: CommonBlockAlignment;
25 }, SerializedElementNode>
27 export class ImageNode extends ElementNode {
32 __alignment: CommonBlockAlignment = '';
34 static getType(): string {
38 static clone(node: ImageNode): ImageNode {
39 const newNode = new ImageNode(node.__src, {
42 height: node.__height,
44 newNode.__alignment = node.__alignment;
48 constructor(src: string, options: ImageNodeOptions, key?: string) {
52 this.__alt = options.alt;
55 this.__width = options.width;
58 this.__height = options.height;
62 setSrc(src: string): void {
63 const self = this.getWritable();
68 const self = this.getLatest();
72 setAltText(altText: string): void {
73 const self = this.getWritable();
77 getAltText(): string {
78 const self = this.getLatest();
82 setHeight(height: number): void {
83 const self = this.getWritable();
84 self.__height = height;
88 const self = this.getLatest();
92 setWidth(width: number): void {
93 const self = this.getWritable();
98 const self = this.getLatest();
102 setAlignment(alignment: CommonBlockAlignment) {
103 const self = this.getWritable();
104 self.__alignment = alignment;
107 getAlignment(): CommonBlockAlignment {
108 const self = this.getLatest();
109 return self.__alignment;
112 isInline(): boolean {
116 createDOM(_config: EditorConfig, _editor: LexicalEditor) {
117 const element = document.createElement('img');
118 element.setAttribute('src', this.__src);
121 element.setAttribute('width', String(this.__width));
124 element.setAttribute('height', String(this.__height));
127 element.setAttribute('alt', this.__alt);
130 if (this.__alignment) {
131 element.classList.add('align-' + this.__alignment);
134 element.addEventListener('click', e => {
135 _editor.update(() => {
143 updateDOM(prevNode: ImageNode, dom: HTMLElement) {
144 if (prevNode.__src !== this.__src) {
145 dom.setAttribute('src', this.__src);
148 if (prevNode.__width !== this.__width) {
150 dom.setAttribute('width', String(this.__width));
152 dom.removeAttribute('width');
156 if (prevNode.__height !== this.__height) {
158 dom.setAttribute('height', String(this.__height));
160 dom.removeAttribute('height');
164 if (prevNode.__alt !== this.__alt) {
166 dom.setAttribute('alt', String(this.__alt));
168 dom.removeAttribute('alt');
172 if (prevNode.__alignment !== this.__alignment) {
173 if (prevNode.__alignment) {
174 dom.classList.remove('align-' + prevNode.__alignment);
176 if (this.__alignment) {
177 dom.classList.add('align-' + this.__alignment);
184 static importDOM(): DOMConversionMap|null {
186 img(node: HTMLElement): DOMConversion|null {
188 conversion: (element: HTMLElement): DOMConversionOutput|null => {
190 const src = element.getAttribute('src') || '';
191 const options: ImageNodeOptions = {
192 alt: element.getAttribute('alt') || '',
193 height: Number.parseInt(element.getAttribute('height') || '0'),
194 width: Number.parseInt(element.getAttribute('width') || '0'),
197 const node = new ImageNode(src, options);
198 node.setAlignment(extractAlignmentFromElement(element));
208 exportJSON(): SerializedImageNode {
210 ...super.exportJSON(),
215 height: this.__height,
217 alignment: this.__alignment,
221 static importJSON(serializedNode: SerializedImageNode): ImageNode {
222 const node = $createImageNode(serializedNode.src, {
223 alt: serializedNode.alt,
224 width: serializedNode.width,
225 height: serializedNode.height,
227 node.setAlignment(serializedNode.alignment);
232 export function $createImageNode(src: string, options: ImageNodeOptions = {}): ImageNode {
233 return new ImageNode(src, options);
236 export function $isImageNode(node: LexicalNode | null | undefined) {
237 return node instanceof ImageNode;