]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/lexical/rich-text/LexicalDetailsNode.ts
178b0d9531d424e2a6f90729da7fe7fb3dd4cc56
[bookstack] / resources / js / wysiwyg / lexical / rich-text / LexicalDetailsNode.ts
1 import {
2     DOMConversion,
3     DOMConversionMap, DOMConversionOutput,
4     ElementNode,
5     LexicalEditor,
6     LexicalNode,
7     SerializedElementNode, Spread,
8     EditorConfig,
9 } from 'lexical';
10
11 import {el} from "../../utils/dom";
12 import {extractDirectionFromElement} from "lexical/nodes/common";
13
14 export type SerializedDetailsNode = Spread<{
15     id: string;
16 }, SerializedElementNode>
17
18 export class DetailsNode extends ElementNode {
19     __id: string = '';
20
21     static getType() {
22         return 'details';
23     }
24
25     setId(id: string) {
26         const self = this.getWritable();
27         self.__id = id;
28     }
29
30     getId(): string {
31         const self = this.getLatest();
32         return self.__id;
33     }
34
35     static clone(node: DetailsNode): DetailsNode {
36         const newNode =  new DetailsNode(node.__key);
37         newNode.__id = node.__id;
38         newNode.__dir = node.__dir;
39         return newNode;
40     }
41
42     createDOM(_config: EditorConfig, _editor: LexicalEditor) {
43         const el = document.createElement('details');
44         if (this.__id) {
45             el.setAttribute('id', this.__id);
46         }
47
48         if (this.__dir) {
49             el.setAttribute('dir', this.__dir);
50         }
51
52         return el;
53     }
54
55     updateDOM(prevNode: DetailsNode, dom: HTMLElement) {
56         return prevNode.__id !== this.__id
57         || prevNode.__dir !== this.__dir;
58     }
59
60     static importDOM(): DOMConversionMap|null {
61         return {
62             details(node: HTMLElement): DOMConversion|null {
63                 return {
64                     conversion: (element: HTMLElement): DOMConversionOutput|null => {
65                         const node = new DetailsNode();
66                         if (element.id) {
67                             node.setId(element.id);
68                         }
69
70                         if (element.dir) {
71                             node.setDirection(extractDirectionFromElement(element));
72                         }
73
74                         return {node};
75                     },
76                     priority: 3,
77                 };
78             },
79         };
80     }
81
82     exportJSON(): SerializedDetailsNode {
83         return {
84             ...super.exportJSON(),
85             type: 'details',
86             version: 1,
87             id: this.__id,
88         };
89     }
90
91     static importJSON(serializedNode: SerializedDetailsNode): DetailsNode {
92         const node = $createDetailsNode();
93         node.setId(serializedNode.id);
94         node.setDirection(serializedNode.direction);
95         return node;
96     }
97
98 }
99
100 export function $createDetailsNode() {
101     return new DetailsNode();
102 }
103
104 export function $isDetailsNode(node: LexicalNode | null | undefined): node is DetailsNode {
105     return node instanceof DetailsNode;
106 }
107
108 export class SummaryNode extends ElementNode {
109
110     static getType() {
111         return 'summary';
112     }
113
114     static clone(node: SummaryNode) {
115         return new SummaryNode(node.__key);
116     }
117
118     createDOM(_config: EditorConfig, _editor: LexicalEditor) {
119         return el('summary');
120     }
121
122     updateDOM(prevNode: DetailsNode, dom: HTMLElement) {
123         return false;
124     }
125
126     static importDOM(): DOMConversionMap|null {
127         return {
128             summary(node: HTMLElement): DOMConversion|null {
129                 return {
130                     conversion: (element: HTMLElement): DOMConversionOutput|null => {
131                         return {
132                             node: new SummaryNode(),
133                         };
134                     },
135                     priority: 3,
136                 };
137             },
138         };
139     }
140
141     exportJSON(): SerializedElementNode {
142         return {
143             ...super.exportJSON(),
144             type: 'summary',
145             version: 1,
146         };
147     }
148
149     static importJSON(serializedNode: SerializedElementNode): SummaryNode {
150         return $createSummaryNode();
151     }
152
153 }
154
155 export function $createSummaryNode(): SummaryNode {
156     return new SummaryNode();
157 }
158
159 export function $isSummaryNode(node: LexicalNode | null | undefined): node is SummaryNode {
160     return node instanceof SummaryNode;
161 }