Skip to content

Commit b862f12

Browse files
committed
Lexical: Further improvements to table selection and captions
- Fixed errors with selection and range handling due to captions existing. - Updated TableNode change handling to update existing DOM instead of re-creating, which avoids breaking an attached selection helper. - To support, Added function to handle node change detection and apply relevant dom updates for common properties.
1 parent d9ea525 commit b862f12

File tree

6 files changed

+84
-21
lines changed

6 files changed

+84
-21
lines changed

resources/js/wysiwyg/lexical/core/nodes/common.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {sizeToPixels} from "../../../utils/dom";
22
import {SerializedCommonBlockNode} from "lexical/nodes/CommonBlockNode";
3+
import {elem} from "../../../../services/dom";
34

45
export type CommonBlockAlignment = 'left' | 'right' | 'center' | 'justify' | '';
56
const validAlignments: CommonBlockAlignment[] = ['left', 'right', 'center', 'justify'];
@@ -82,6 +83,38 @@ export function commonPropertiesDifferent(nodeA: CommonBlockInterface, nodeB: Co
8283
nodeA.__dir !== nodeB.__dir;
8384
}
8485

86+
export function applyCommonPropertyChanges(prevNode: CommonBlockInterface, currentNode: CommonBlockInterface, element: HTMLElement): void {
87+
if (prevNode.__id !== currentNode.__id) {
88+
element.setAttribute('id', currentNode.__id);
89+
}
90+
91+
if (prevNode.__alignment !== currentNode.__alignment) {
92+
for (const alignment of validAlignments) {
93+
element.classList.remove('align-' + alignment);
94+
}
95+
96+
if (currentNode.__alignment) {
97+
element.classList.add('align-' + currentNode.__alignment);
98+
}
99+
}
100+
101+
if (prevNode.__inset !== currentNode.__inset) {
102+
if (currentNode.__inset) {
103+
element.style.paddingLeft = `${currentNode.__inset}px`;
104+
} else {
105+
element.style.removeProperty('paddingLeft');
106+
}
107+
}
108+
109+
if (prevNode.__dir !== currentNode.__dir) {
110+
if (currentNode.__dir) {
111+
element.dir = currentNode.__dir;
112+
} else {
113+
element.removeAttribute('dir');
114+
}
115+
}
116+
}
117+
85118
export function updateElementWithCommonBlockProps(element: HTMLElement, node: CommonBlockInterface): void {
86119
if (node.__id) {
87120
element.setAttribute('id', node.__id);

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

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ import {TableDOMCell, TableDOMTable} from './LexicalTableObserver';
3030
import {getTable} from './LexicalTableSelectionHelpers';
3131
import {CommonBlockNode, copyCommonBlockProperties, SerializedCommonBlockNode} from "lexical/nodes/CommonBlockNode";
3232
import {
33+
applyCommonPropertyChanges,
3334
commonPropertiesDifferent, deserializeCommonBlockNode,
3435
setCommonBlockPropsFromElement,
3536
updateElementWithCommonBlockProps
3637
} from "lexical/nodes/common";
3738
import {el, extractStyleMapFromElement, StyleMap} from "../../utils/dom";
38-
import {getTableColumnWidths} from "../../utils/tables";
39+
import {buildColgroupFromTableWidths, getTableColumnWidths} from "../../utils/tables";
3940

4041
export type SerializedTableNode = Spread<{
4142
colWidths: string[];
@@ -98,15 +99,8 @@ export class TableNode extends CommonBlockNode {
9899
updateElementWithCommonBlockProps(tableElement, this);
99100

100101
const colWidths = this.getColWidths();
101-
if (colWidths.length > 0) {
102-
const colgroup = el('colgroup');
103-
for (const width of colWidths) {
104-
const col = el('col');
105-
if (width) {
106-
col.style.width = width;
107-
}
108-
colgroup.append(col);
109-
}
102+
const colgroup = buildColgroupFromTableWidths(colWidths);
103+
if (colgroup) {
110104
tableElement.append(colgroup);
111105
}
112106

@@ -117,11 +111,29 @@ export class TableNode extends CommonBlockNode {
117111
return tableElement;
118112
}
119113

120-
updateDOM(_prevNode: TableNode): boolean {
121-
return commonPropertiesDifferent(_prevNode, this)
122-
|| this.__colWidths.join(':') !== _prevNode.__colWidths.join(':')
123-
|| this.__styles.size !== _prevNode.__styles.size
124-
|| (Array.from(this.__styles.values()).join(':') !== (Array.from(_prevNode.__styles.values()).join(':')));
114+
updateDOM(_prevNode: TableNode, dom: HTMLElement): boolean {
115+
applyCommonPropertyChanges(_prevNode, this, dom);
116+
117+
if (this.__colWidths.join(':') !== _prevNode.__colWidths.join(':')) {
118+
const existingColGroup = Array.from(dom.children).find(child => child.nodeName === 'COLGROUP');
119+
const newColGroup = buildColgroupFromTableWidths(this.__colWidths);
120+
if (existingColGroup) {
121+
existingColGroup.remove();
122+
}
123+
124+
if (newColGroup) {
125+
dom.prepend(newColGroup);
126+
}
127+
}
128+
129+
if (Array.from(this.__styles.values()).join(':') !== Array.from(_prevNode.__styles.values()).join(':')) {
130+
dom.style.cssText = '';
131+
for (const [name, value] of this.__styles.entries()) {
132+
dom.style.setProperty(name, value);
133+
}
134+
}
135+
136+
return false;
125137
}
126138

127139
exportDOM(editor: LexicalEditor): DOMExportOutput {

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -916,14 +916,14 @@ export function getTable(tableElement: HTMLElement): TableDOMTable {
916916
domRows.length = 0;
917917

918918
while (currentNode != null) {
919-
const nodeMame = currentNode.nodeName;
919+
const nodeName = currentNode.nodeName;
920920

921-
if (nodeMame === 'COLGROUP') {
921+
if (nodeName === 'COLGROUP' || nodeName === 'CAPTION') {
922922
currentNode = currentNode.nextSibling;
923923
continue;
924924
}
925925

926-
if (nodeMame === 'TD' || nodeMame === 'TH') {
926+
if (nodeName === 'TD' || nodeName === 'TH') {
927927
const elem = currentNode as HTMLElement;
928928
const cell = {
929929
elem,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
TableRowNode,
3636
} from './LexicalTableRowNode';
3737
import {$isTableSelection} from './LexicalTableSelection';
38+
import {$isCaptionNode} from "@lexical/table/LexicalCaptionNode";
3839

3940
export function $createTableNodeWithDimensions(
4041
rowCount: number,
@@ -779,7 +780,7 @@ export function $computeTableMapSkipCellCheck(
779780
return tableMap[row] === undefined || tableMap[row][column] === undefined;
780781
}
781782

782-
const gridChildren = grid.getChildren();
783+
const gridChildren = grid.getChildren().filter(node => !$isCaptionNode(node));
783784
for (let i = 0; i < gridChildren.length; i++) {
784785
const row = gridChildren[i];
785786
invariant(

resources/js/wysiwyg/ui/framework/helpers/table-selection-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class TableSelectionHandler {
5656
tableNode,
5757
tableElement,
5858
this.editor,
59-
false,
59+
true,
6060
);
6161
this.tableSelections.set(nodeKey, tableSelection);
6262
}

resources/js/wysiwyg/utils/tables.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
} from "@lexical/table";
1010
import {$getParentOfType} from "./nodes";
1111
import {$getNodeFromSelection} from "./selection";
12-
import {formatSizeValue} from "./dom";
12+
import {el, formatSizeValue} from "./dom";
1313
import {TableMap} from "./table-map";
1414

1515
function $getTableFromCell(cell: TableCellNode): TableNode|null {
@@ -140,6 +140,23 @@ export function $getTableCellColumnWidth(editor: LexicalEditor, cell: TableCellN
140140
return (widths.length > index) ? widths[index] : '';
141141
}
142142

143+
export function buildColgroupFromTableWidths(colWidths: string[]): HTMLElement|null {
144+
if (colWidths.length === 0) {
145+
return null
146+
}
147+
148+
const colgroup = el('colgroup');
149+
for (const width of colWidths) {
150+
const col = el('col');
151+
if (width) {
152+
col.style.width = width;
153+
}
154+
colgroup.append(col);
155+
}
156+
157+
return colgroup;
158+
}
159+
143160
export function $getTableCellsFromSelection(selection: BaseSelection|null): TableCellNode[] {
144161
if ($isTableSelection(selection)) {
145162
const nodes = selection.getNodes();

0 commit comments

Comments
 (0)