]> BookStack Code Mirror - bookstack/blobdiff - resources/js/wysiwyg/nodes/index.ts
respective book and chapter structure added.
[bookstack] / resources / js / wysiwyg / nodes / index.ts
index 9f772df1e5c8232d3f614d7c4f67156024751b9d..b5483c5009cc613ca4bbc0113e20cbf700695f31 100644 (file)
 import {HeadingNode, QuoteNode} from '@lexical/rich-text';
 import {CalloutNode} from './callout';
-import {ElementNode, KlassConstructor, LexicalNode, LexicalNodeReplacement, ParagraphNode} from "lexical";
+import {
+    ElementNode,
+    KlassConstructor,
+    LexicalNode,
+    LexicalNodeReplacement, NodeMutation,
+    ParagraphNode
+} from "lexical";
 import {CustomParagraphNode} from "./custom-paragraph";
 import {LinkNode} from "@lexical/link";
+import {ImageNode} from "./image";
+import {DetailsNode, SummaryNode} from "./details";
+import {ListItemNode, ListNode} from "@lexical/list";
+import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
+import {CustomTableNode} from "./custom-table";
+import {HorizontalRuleNode} from "./horizontal-rule";
+import {CodeBlockNode} from "./code-block";
+import {DiagramNode} from "./diagram";
+import {EditorUiContext} from "../ui/framework/core";
+import {MediaNode} from "./media";
+import {CustomListItemNode} from "./custom-list-item";
+import {CustomTableCellNode} from "./custom-table-cell";
+import {CustomTableRowNode} from "./custom-table-row";
+import {CustomHeadingNode} from "./custom-heading";
+import {CustomQuoteNode} from "./custom-quote";
+import {CustomListNode} from "./custom-list";
 
 /**
  * Load the nodes for lexical.
  */
 export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> | LexicalNodeReplacement)[] {
     return [
-        CalloutNode, // Todo - Create custom
-        HeadingNode, // Todo - Create custom
-        QuoteNode, // Todo - Create custom
+        CalloutNode,
+        CustomHeadingNode,
+        CustomQuoteNode,
+        CustomListNode,
+        CustomListItemNode, // TODO - Alignment?
+        CustomTableNode,
+        CustomTableRowNode,
+        CustomTableCellNode,
+        ImageNode, // TODO - Alignment
+        HorizontalRuleNode,
+        DetailsNode, SummaryNode,
+        CodeBlockNode,
+        DiagramNode,
+        MediaNode, // TODO - Alignment
         CustomParagraphNode,
+        LinkNode,
         {
             replace: ParagraphNode,
             with: (node: ParagraphNode) => {
                 return new CustomParagraphNode();
             }
         },
-        LinkNode,
+        {
+            replace: HeadingNode,
+            with: (node: HeadingNode) => {
+                return new CustomHeadingNode(node.__tag);
+            }
+        },
+        {
+            replace: QuoteNode,
+            with: (node: QuoteNode) => {
+                return new CustomQuoteNode();
+            }
+        },
+        {
+            replace: ListNode,
+            with: (node: ListNode) => {
+                return new CustomListNode(node.getListType(), node.getStart());
+            }
+        },
+        {
+            replace: ListItemNode,
+            with: (node: ListItemNode) => {
+                return new CustomListItemNode(node.__value, node.__checked);
+            }
+        },
+        {
+            replace: TableNode,
+            with(node: TableNode) {
+                return new CustomTableNode();
+            }
+        },
+        {
+            replace: TableRowNode,
+            with(node: TableRowNode) {
+                return new CustomTableRowNode();
+            }
+        },
+        {
+            replace: TableCellNode,
+            with: (node: TableCellNode) => {
+                const cell = new CustomTableCellNode(
+                    node.__headerState,
+                    node.__colSpan,
+                    node.__width,
+                );
+                cell.__rowSpan = node.__rowSpan;
+                return cell;
+            }
+        },
     ];
 }
 
+export function registerCommonNodeMutationListeners(context: EditorUiContext): void {
+    const decorated = [ImageNode, CodeBlockNode, DiagramNode];
+
+    const decorationDestroyListener = (mutations: Map<string, NodeMutation>): void => {
+        for (let [nodeKey, mutation] of mutations) {
+            if (mutation === "destroyed") {
+                const decorator = context.manager.getDecoratorByNodeKey(nodeKey);
+                if (decorator) {
+                    decorator.destroy(context);
+                }
+            }
+        }
+    };
+
+    for (let decoratedNode of decorated) {
+        // Have to pass a unique function here since they are stored by lexical keyed on listener function.
+        context.editor.registerMutationListener(decoratedNode, (mutations) => decorationDestroyListener(mutations));
+    }
+}
+
 export type LexicalNodeMatcher = (node: LexicalNode|null|undefined) => boolean;
 export type LexicalElementNodeCreator = () => ElementNode;
\ No newline at end of file