]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/nodes/index.ts
Move settings category layouts into their own view folder
[bookstack] / resources / js / wysiwyg / nodes / index.ts
1 import {HeadingNode, QuoteNode} from '@lexical/rich-text';
2 import {CalloutNode} from './callout';
3 import {
4     ElementNode,
5     KlassConstructor,
6     LexicalNode,
7     LexicalNodeReplacement, NodeMutation,
8     ParagraphNode
9 } from "lexical";
10 import {CustomParagraphNode} from "./custom-paragraph";
11 import {LinkNode} from "@lexical/link";
12 import {ImageNode} from "./image";
13 import {DetailsNode, SummaryNode} from "./details";
14 import {ListItemNode, ListNode} from "@lexical/list";
15 import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
16 import {CustomTableNode} from "./custom-table";
17 import {HorizontalRuleNode} from "./horizontal-rule";
18 import {CodeBlockNode} from "./code-block";
19 import {DiagramNode} from "./diagram";
20 import {EditorUiContext} from "../ui/framework/core";
21 import {MediaNode} from "./media";
22 import {CustomListItemNode} from "./custom-list-item";
23 import {CustomTableCellNode} from "./custom-table-cell";
24 import {CustomTableRowNode} from "./custom-table-row";
25 import {CustomHeadingNode} from "./custom-heading";
26 import {CustomQuoteNode} from "./custom-quote";
27 import {CustomListNode} from "./custom-list";
28
29 /**
30  * Load the nodes for lexical.
31  */
32 export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> | LexicalNodeReplacement)[] {
33     return [
34         CalloutNode,
35         CustomHeadingNode,
36         CustomQuoteNode,
37         CustomListNode,
38         CustomListItemNode, // TODO - Alignment?
39         CustomTableNode,
40         CustomTableRowNode,
41         CustomTableCellNode,
42         ImageNode, // TODO - Alignment
43         HorizontalRuleNode,
44         DetailsNode, SummaryNode,
45         CodeBlockNode,
46         DiagramNode,
47         MediaNode, // TODO - Alignment
48         CustomParagraphNode,
49         LinkNode,
50         {
51             replace: ParagraphNode,
52             with: (node: ParagraphNode) => {
53                 return new CustomParagraphNode();
54             }
55         },
56         {
57             replace: HeadingNode,
58             with: (node: HeadingNode) => {
59                 return new CustomHeadingNode(node.__tag);
60             }
61         },
62         {
63             replace: QuoteNode,
64             with: (node: QuoteNode) => {
65                 return new CustomQuoteNode();
66             }
67         },
68         {
69             replace: ListNode,
70             with: (node: ListNode) => {
71                 return new CustomListNode(node.getListType(), node.getStart());
72             }
73         },
74         {
75             replace: ListItemNode,
76             with: (node: ListItemNode) => {
77                 return new CustomListItemNode(node.__value, node.__checked);
78             }
79         },
80         {
81             replace: TableNode,
82             with(node: TableNode) {
83                 return new CustomTableNode();
84             }
85         },
86         {
87             replace: TableRowNode,
88             with(node: TableRowNode) {
89                 return new CustomTableRowNode();
90             }
91         },
92         {
93             replace: TableCellNode,
94             with: (node: TableCellNode) => {
95                 const cell = new CustomTableCellNode(
96                     node.__headerState,
97                     node.__colSpan,
98                     node.__width,
99                 );
100                 cell.__rowSpan = node.__rowSpan;
101                 return cell;
102             }
103         },
104     ];
105 }
106
107 export function registerCommonNodeMutationListeners(context: EditorUiContext): void {
108     const decorated = [ImageNode, CodeBlockNode, DiagramNode];
109
110     const decorationDestroyListener = (mutations: Map<string, NodeMutation>): void => {
111         for (let [nodeKey, mutation] of mutations) {
112             if (mutation === "destroyed") {
113                 const decorator = context.manager.getDecoratorByNodeKey(nodeKey);
114                 if (decorator) {
115                     decorator.destroy(context);
116                 }
117             }
118         }
119     };
120
121     for (let decoratedNode of decorated) {
122         // Have to pass a unique function here since they are stored by lexical keyed on listener function.
123         context.editor.registerMutationListener(decoratedNode, (mutations) => decorationDestroyListener(mutations));
124     }
125 }
126
127 export type LexicalNodeMatcher = (node: LexicalNode|null|undefined) => boolean;
128 export type LexicalElementNodeCreator = () => ElementNode;