]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/nodes/index.ts
Lexical: Started media node support
[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
23 /**
24  * Load the nodes for lexical.
25  */
26 export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> | LexicalNodeReplacement)[] {
27     return [
28         CalloutNode, // Todo - Create custom
29         HeadingNode, // Todo - Create custom
30         QuoteNode, // Todo - Create custom
31         ListNode, // Todo - Create custom
32         ListItemNode,
33         CustomTableNode,
34         TableRowNode,
35         TableCellNode,
36         ImageNode,
37         HorizontalRuleNode,
38         DetailsNode, SummaryNode,
39         CodeBlockNode,
40         DiagramNode,
41         MediaNode,
42         CustomParagraphNode,
43         LinkNode,
44         {
45             replace: ParagraphNode,
46             with: (node: ParagraphNode) => {
47                 return new CustomParagraphNode();
48             }
49         },
50         {
51             replace: TableNode,
52             with(node: TableNode) {
53                 return new CustomTableNode();
54             }
55         },
56     ];
57 }
58
59 export function registerCommonNodeMutationListeners(context: EditorUiContext): void {
60     const decorated = [ImageNode, CodeBlockNode, DiagramNode];
61
62     const decorationDestroyListener = (mutations: Map<string, NodeMutation>): void => {
63         for (let [nodeKey, mutation] of mutations) {
64             if (mutation === "destroyed") {
65                 const decorator = context.manager.getDecoratorByNodeKey(nodeKey);
66                 if (decorator) {
67                     decorator.destroy(context);
68                 }
69             }
70         }
71     };
72
73     for (let decoratedNode of decorated) {
74         // Have to pass a unique function here since they are stored by lexical keyed on listener function.
75         context.editor.registerMutationListener(decoratedNode, (mutations) => decorationDestroyListener(mutations));
76     }
77 }
78
79 export type LexicalNodeMatcher = (node: LexicalNode|null|undefined) => boolean;
80 export type LexicalElementNodeCreator = () => ElementNode;