]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/nodes/index.ts
Lexical: Added code block selection & edit features
[bookstack] / resources / js / wysiwyg / nodes / index.ts
1 import {HeadingNode, QuoteNode} from '@lexical/rich-text';
2 import {CalloutNode} from './callout';
3 import {
4     $getNodeByKey,
5     ElementNode,
6     KlassConstructor,
7     LexicalEditor,
8     LexicalNode,
9     LexicalNodeReplacement, NodeMutation,
10     ParagraphNode
11 } from "lexical";
12 import {CustomParagraphNode} from "./custom-paragraph";
13 import {LinkNode} from "@lexical/link";
14 import {ImageNode} from "./image";
15 import {DetailsNode, SummaryNode} from "./details";
16 import {ListItemNode, ListNode} from "@lexical/list";
17 import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
18 import {CustomTableNode} from "./custom-table";
19 import {HorizontalRuleNode} from "./horizontal-rule";
20 import {CodeBlockNode} from "./code-block";
21 import {DiagramNode} from "./diagram";
22 import {EditorUIManager} from "../ui/framework/manager";
23 import {EditorUiContext} from "../ui/framework/core";
24
25 /**
26  * Load the nodes for lexical.
27  */
28 export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> | LexicalNodeReplacement)[] {
29     return [
30         CalloutNode, // Todo - Create custom
31         HeadingNode, // Todo - Create custom
32         QuoteNode, // Todo - Create custom
33         ListNode, // Todo - Create custom
34         ListItemNode,
35         CustomTableNode,
36         TableRowNode,
37         TableCellNode,
38         ImageNode,
39         HorizontalRuleNode,
40         DetailsNode, SummaryNode,
41         CodeBlockNode,
42         DiagramNode,
43         CustomParagraphNode,
44         LinkNode,
45         {
46             replace: ParagraphNode,
47             with: (node: ParagraphNode) => {
48                 return new CustomParagraphNode();
49             }
50         },
51         {
52             replace: TableNode,
53             with(node: TableNode) {
54                 return new CustomTableNode();
55             }
56         },
57     ];
58 }
59
60 export function registerCommonNodeMutationListeners(context: EditorUiContext): void {
61     const decorated = [ImageNode, CodeBlockNode, DiagramNode];
62
63     const decorationDestroyListener = (mutations: Map<string, NodeMutation>): void => {
64         for (let [nodeKey, mutation] of mutations) {
65             if (mutation === "destroyed") {
66                 const decorator = context.manager.getDecoratorByNodeKey(nodeKey);
67                 if (decorator) {
68                     decorator.destroy(context);
69                 }
70             }
71         }
72     };
73
74     for (let decoratedNode of decorated) {
75         // Have to pass a unique function here since they are stored by lexical keyed on listener function.
76         context.editor.registerMutationListener(decoratedNode, (mutations) => decorationDestroyListener(mutations));
77     }
78 }
79
80 export type LexicalNodeMatcher = (node: LexicalNode|null|undefined) => boolean;
81 export type LexicalElementNodeCreator = () => ElementNode;