]> BookStack Code Mirror - bookstack/blobdiff - resources/js/wysiwyg/nodes/custom-list.ts
Search: Added exact/filter/tag term negation support
[bookstack] / resources / js / wysiwyg / nodes / custom-list.ts
index 953bcb8cd15f5bc0fdb65a2b07bc12ad43ebc973..4b05fa62e255860e3e2d644f0262b6c3c38fe45e 100644 (file)
@@ -1,11 +1,12 @@
 import {
     DOMConversionFn,
-    DOMConversionMap,
+    DOMConversionMap, EditorConfig,
     LexicalNode,
     Spread
 } from "lexical";
-import {EditorConfig} from "lexical/LexicalEditor";
-import {ListNode, ListType, SerializedListNode} from "@lexical/list";
+import {$isListItemNode, ListItemNode, ListNode, ListType, SerializedListNode} from "@lexical/list";
+import {$createCustomListItemNode} from "./custom-list-item";
+import {extractDirectionFromElement} from "./_common";
 
 
 export type SerializedCustomListNode = Spread<{
@@ -30,8 +31,9 @@ export class CustomListNode extends ListNode {
     }
 
     static clone(node: CustomListNode) {
-        const newNode = new CustomListNode(node.__listType, 0, node.__key);
+        const newNode = new CustomListNode(node.__listType, node.__start, node.__key);
         newNode.__id = node.__id;
+        newNode.__dir = node.__dir;
         return newNode;
     }
 
@@ -41,9 +43,18 @@ export class CustomListNode extends ListNode {
             dom.setAttribute('id', this.__id);
         }
 
+        if (this.__dir) {
+            dom.setAttribute('dir', this.__dir);
+        }
+
         return dom;
     }
 
+    updateDOM(prevNode: ListNode, dom: HTMLElement, config: EditorConfig): boolean {
+        return super.updateDOM(prevNode, dom, config) ||
+            prevNode.__dir !== this.__dir;
+    }
+
     exportJSON(): SerializedCustomListNode {
         return {
             ...super.exportJSON(),
@@ -56,6 +67,7 @@ export class CustomListNode extends ListNode {
     static importJSON(serializedNode: SerializedCustomListNode): CustomListNode {
         const node = $createCustomListNode(serializedNode.listType);
         node.setId(serializedNode.id);
+        node.setDirection(serializedNode.direction);
         return node;
     }
 
@@ -67,6 +79,15 @@ export class CustomListNode extends ListNode {
             if (element.id && baseResult?.node) {
                 (baseResult.node as CustomListNode).setId(element.id);
             }
+
+            if (element.dir && baseResult?.node) {
+                (baseResult.node as CustomListNode).setDirection(extractDirectionFromElement(element));
+            }
+
+            if (baseResult) {
+                baseResult.after = $normalizeChildren;
+            }
+
             return baseResult;
         };
 
@@ -83,8 +104,34 @@ export class CustomListNode extends ListNode {
     }
 }
 
+/*
+ * This function is a custom normalization function to allow nested lists within list item elements.
+ * Original taken from https://github.com/facebook/lexical/blob/6e10210fd1e113ccfafdc999b1d896733c5c5bea/packages/lexical-list/src/LexicalListNode.ts#L284-L303
+ * With modifications made.
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ * MIT license
+ */
+function $normalizeChildren(nodes: Array<LexicalNode>): Array<ListItemNode> {
+    const normalizedListItems: Array<ListItemNode> = [];
+
+    for (const node of nodes) {
+        if ($isListItemNode(node)) {
+            normalizedListItems.push(node);
+        } else {
+            normalizedListItems.push($wrapInListItem(node));
+        }
+    }
+
+    return normalizedListItems;
+}
+
+function $wrapInListItem(node: LexicalNode): ListItemNode {
+    const listItemWrapper = $createCustomListItemNode();
+    return listItemWrapper.append(node);
+}
+
 export function $createCustomListNode(type: ListType): CustomListNode {
-    return new CustomListNode(type, 0);
+    return new CustomListNode(type, 1);
 }
 
 export function $isCustomListNode(node: LexicalNode | null | undefined): node is CustomListNode {