Skip to content

Commit 8a66365

Browse files
committed
Lexical: Added support for table caption nodes
Needs linking up to the table form still.
1 parent 04cca77 commit 8a66365

File tree

5 files changed

+101
-8
lines changed

5 files changed

+101
-8
lines changed

resources/js/wysiwyg/lexical/core/LexicalNode.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,16 @@ export class LexicalNode {
11651165
markDirty(): void {
11661166
this.getWritable();
11671167
}
1168+
1169+
/**
1170+
* Insert the DOM of this node into that of the parent.
1171+
* Allows this node to implement custom DOM attachment logic.
1172+
* Boolean result indicates if the insertion was handled by the function.
1173+
* A true return value prevents default insertion logic from taking place.
1174+
*/
1175+
insertDOMIntoParent(nodeDOM: HTMLElement, parentDOM: HTMLElement): boolean {
1176+
return false;
1177+
}
11681178
}
11691179

11701180
function errorOnTypeKlassMismatch(

resources/js/wysiwyg/lexical/core/LexicalReconciler.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,21 @@ function $createNode(
171171
}
172172

173173
if (parentDOM !== null) {
174-
if (insertDOM != null) {
175-
parentDOM.insertBefore(dom, insertDOM);
176-
} else {
177-
// @ts-expect-error: internal field
178-
const possibleLineBreak = parentDOM.__lexicalLineBreak;
179174

180-
if (possibleLineBreak != null) {
181-
parentDOM.insertBefore(dom, possibleLineBreak);
175+
const inserted = node?.insertDOMIntoParent(dom, parentDOM);
176+
177+
if (!inserted) {
178+
if (insertDOM != null) {
179+
parentDOM.insertBefore(dom, insertDOM);
182180
} else {
183-
parentDOM.appendChild(dom);
181+
// @ts-expect-error: internal field
182+
const possibleLineBreak = parentDOM.__lexicalLineBreak;
183+
184+
if (possibleLineBreak != null) {
185+
parentDOM.insertBefore(dom, possibleLineBreak);
186+
} else {
187+
parentDOM.appendChild(dom);
188+
}
184189
}
185190
}
186191
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import {
2+
DOMConversionMap,
3+
DOMExportOutput,
4+
EditorConfig,
5+
ElementNode,
6+
LexicalEditor,
7+
LexicalNode,
8+
SerializedElementNode
9+
} from "lexical";
10+
11+
12+
export class CaptionNode extends ElementNode {
13+
static getType(): string {
14+
return 'caption';
15+
}
16+
17+
static clone(node: CaptionNode): CaptionNode {
18+
return new CaptionNode(node.__key);
19+
}
20+
21+
createDOM(_config: EditorConfig, _editor: LexicalEditor): HTMLElement {
22+
return document.createElement('caption');
23+
}
24+
25+
updateDOM(_prevNode: unknown, _dom: HTMLElement, _config: EditorConfig): boolean {
26+
return false;
27+
}
28+
29+
isParentRequired(): true {
30+
return true;
31+
}
32+
33+
canBeEmpty(): boolean {
34+
return false;
35+
}
36+
37+
exportJSON(): SerializedElementNode {
38+
return {
39+
...super.exportJSON(),
40+
type: 'caption',
41+
version: 1,
42+
};
43+
}
44+
45+
insertDOMIntoParent(nodeDOM: HTMLElement, parentDOM: HTMLElement): boolean {
46+
parentDOM.insertBefore(nodeDOM, parentDOM.firstChild);
47+
return true;
48+
}
49+
50+
static importJSON(serializedNode: SerializedElementNode): CaptionNode {
51+
return $createCaptionNode();
52+
}
53+
54+
static importDOM(): DOMConversionMap | null {
55+
return {
56+
caption: (node: Node) => ({
57+
conversion(domNode: Node) {
58+
return {
59+
node: $createCaptionNode(),
60+
}
61+
},
62+
priority: 0,
63+
}),
64+
};
65+
}
66+
}
67+
68+
export function $createCaptionNode(): CaptionNode {
69+
return new CaptionNode();
70+
}
71+
72+
export function $isCaptionNode(node: LexicalNode | null | undefined): node is CaptionNode {
73+
return node instanceof CaptionNode;
74+
}

resources/js/wysiwyg/lexical/table/LexicalTableNode.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ export class TableNode extends CommonBlockNode {
139139
for (const child of Array.from(tableElement.children)) {
140140
if (child.nodeName === 'TR') {
141141
tBody.append(child);
142+
} else if (child.nodeName === 'CAPTION') {
143+
newElement.insertBefore(child, newElement.firstChild);
142144
} else {
143145
newElement.append(child);
144146
}

resources/js/wysiwyg/nodes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {EditorUiContext} from "./ui/framework/core";
1818
import {MediaNode} from "@lexical/rich-text/LexicalMediaNode";
1919
import {HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
2020
import {QuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
21+
import {CaptionNode} from "@lexical/table/LexicalCaptionNode";
2122

2223
/**
2324
* Load the nodes for lexical.
@@ -32,6 +33,7 @@ export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> |
3233
TableNode,
3334
TableRowNode,
3435
TableCellNode,
36+
CaptionNode,
3537
ImageNode, // TODO - Alignment
3638
HorizontalRuleNode,
3739
DetailsNode,

0 commit comments

Comments
 (0)