@lexical/table 0.12.6 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LexicalTable.dev.js +1723 -1535
- package/LexicalTable.js.flow +97 -53
- package/LexicalTable.prod.js +77 -73
- package/LexicalTableCellNode.d.ts +14 -4
- package/LexicalTableCommands.d.ts +18 -0
- package/LexicalTableNode.d.ts +9 -11
- package/LexicalTableObserver.d.ts +51 -0
- package/LexicalTableRowNode.d.ts +2 -2
- package/LexicalTableSelection.d.ts +42 -41
- package/LexicalTableSelectionHelpers.d.ts +13 -13
- package/LexicalTableUtils.d.ts +14 -4
- package/index.d.ts +9 -18
- package/package.json +3 -3
- package/LexicalGridSelection.d.ts +0 -34
package/LexicalTable.dev.js
CHANGED
@@ -6,256 +6,8 @@
|
|
6
6
|
*/
|
7
7
|
'use strict';
|
8
8
|
|
9
|
-
var lexical = require('lexical');
|
10
9
|
var utils = require('@lexical/utils');
|
11
|
-
|
12
|
-
/**
|
13
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
14
|
-
*
|
15
|
-
* This source code is licensed under the MIT license found in the
|
16
|
-
* LICENSE file in the root directory of this source tree.
|
17
|
-
*
|
18
|
-
*/
|
19
|
-
class GridSelection extends lexical.INTERNAL_PointSelection {
|
20
|
-
constructor(gridKey, anchor, focus) {
|
21
|
-
super(anchor, focus);
|
22
|
-
this.gridKey = gridKey;
|
23
|
-
}
|
24
|
-
getCachedNodes() {
|
25
|
-
return this._cachedNodes;
|
26
|
-
}
|
27
|
-
setCachedNodes(nodes) {
|
28
|
-
this._cachedNodes = nodes;
|
29
|
-
}
|
30
|
-
is(selection) {
|
31
|
-
if (!$isGridSelection(selection)) {
|
32
|
-
return false;
|
33
|
-
}
|
34
|
-
return this.gridKey === selection.gridKey && this.anchor.is(selection.anchor) && this.focus.is(selection.focus);
|
35
|
-
}
|
36
|
-
set(gridKey, anchorCellKey, focusCellKey) {
|
37
|
-
this.dirty = true;
|
38
|
-
this.gridKey = gridKey;
|
39
|
-
this.anchor.key = anchorCellKey;
|
40
|
-
this.focus.key = focusCellKey;
|
41
|
-
this._cachedNodes = null;
|
42
|
-
}
|
43
|
-
clone() {
|
44
|
-
return new GridSelection(this.gridKey, this.anchor, this.focus);
|
45
|
-
}
|
46
|
-
isCollapsed() {
|
47
|
-
return false;
|
48
|
-
}
|
49
|
-
extract() {
|
50
|
-
return this.getNodes();
|
51
|
-
}
|
52
|
-
insertRawText(text) {
|
53
|
-
// Do nothing?
|
54
|
-
}
|
55
|
-
insertText() {
|
56
|
-
// Do nothing?
|
57
|
-
}
|
58
|
-
insertNodes(nodes) {
|
59
|
-
const focusNode = this.focus.getNode();
|
60
|
-
if (!lexical.$isElementNode(focusNode)) {
|
61
|
-
throw Error(`Expected GridSelection focus to be an ElementNode`);
|
62
|
-
}
|
63
|
-
const selection = lexical.$normalizeSelection__EXPERIMENTAL(focusNode.select(0, focusNode.getChildrenSize()));
|
64
|
-
selection.insertNodes(nodes);
|
65
|
-
}
|
66
|
-
|
67
|
-
// TODO Deprecate this method. It's confusing when used with colspan|rowspan
|
68
|
-
getShape() {
|
69
|
-
const anchorCellNode = lexical.$getNodeByKey(this.anchor.key);
|
70
|
-
if (!lexical.DEPRECATED_$isGridCellNode(anchorCellNode)) {
|
71
|
-
throw Error(`Expected GridSelection anchor to be (or a child of) GridCellNode`);
|
72
|
-
}
|
73
|
-
const anchorCellNodeRect = lexical.DEPRECATED_$getGridCellNodeRect(anchorCellNode);
|
74
|
-
if (!(anchorCellNodeRect !== null)) {
|
75
|
-
throw Error(`getCellRect: expected to find AnchorNode`);
|
76
|
-
}
|
77
|
-
const focusCellNode = lexical.$getNodeByKey(this.focus.key);
|
78
|
-
if (!lexical.DEPRECATED_$isGridCellNode(focusCellNode)) {
|
79
|
-
throw Error(`Expected GridSelection focus to be (or a child of) GridCellNode`);
|
80
|
-
}
|
81
|
-
const focusCellNodeRect = lexical.DEPRECATED_$getGridCellNodeRect(focusCellNode);
|
82
|
-
if (!(focusCellNodeRect !== null)) {
|
83
|
-
throw Error(`getCellRect: expected to find focusCellNode`);
|
84
|
-
}
|
85
|
-
const startX = Math.min(anchorCellNodeRect.columnIndex, focusCellNodeRect.columnIndex);
|
86
|
-
const stopX = Math.max(anchorCellNodeRect.columnIndex, focusCellNodeRect.columnIndex);
|
87
|
-
const startY = Math.min(anchorCellNodeRect.rowIndex, focusCellNodeRect.rowIndex);
|
88
|
-
const stopY = Math.max(anchorCellNodeRect.rowIndex, focusCellNodeRect.rowIndex);
|
89
|
-
return {
|
90
|
-
fromX: Math.min(startX, stopX),
|
91
|
-
fromY: Math.min(startY, stopY),
|
92
|
-
toX: Math.max(startX, stopX),
|
93
|
-
toY: Math.max(startY, stopY)
|
94
|
-
};
|
95
|
-
}
|
96
|
-
getNodes() {
|
97
|
-
const cachedNodes = this._cachedNodes;
|
98
|
-
if (cachedNodes !== null) {
|
99
|
-
return cachedNodes;
|
100
|
-
}
|
101
|
-
const anchorNode = this.anchor.getNode();
|
102
|
-
const focusNode = this.focus.getNode();
|
103
|
-
const anchorCell = utils.$findMatchingParent(anchorNode, lexical.DEPRECATED_$isGridCellNode);
|
104
|
-
// todo replace with triplet
|
105
|
-
const focusCell = utils.$findMatchingParent(focusNode, lexical.DEPRECATED_$isGridCellNode);
|
106
|
-
if (!lexical.DEPRECATED_$isGridCellNode(anchorCell)) {
|
107
|
-
throw Error(`Expected GridSelection anchor to be (or a child of) GridCellNode`);
|
108
|
-
}
|
109
|
-
if (!lexical.DEPRECATED_$isGridCellNode(focusCell)) {
|
110
|
-
throw Error(`Expected GridSelection focus to be (or a child of) GridCellNode`);
|
111
|
-
}
|
112
|
-
const anchorRow = anchorCell.getParent();
|
113
|
-
if (!lexical.DEPRECATED_$isGridRowNode(anchorRow)) {
|
114
|
-
throw Error(`Expected anchorCell to have a parent GridRowNode`);
|
115
|
-
}
|
116
|
-
const gridNode = anchorRow.getParent();
|
117
|
-
if (!lexical.DEPRECATED_$isGridNode(gridNode)) {
|
118
|
-
throw Error(`Expected tableNode to have a parent GridNode`);
|
119
|
-
}
|
120
|
-
const focusCellGrid = focusCell.getParents()[1];
|
121
|
-
if (focusCellGrid !== gridNode) {
|
122
|
-
if (!gridNode.isParentOf(focusCell)) {
|
123
|
-
// focus is on higher Grid level than anchor
|
124
|
-
const gridParent = gridNode.getParent();
|
125
|
-
if (!(gridParent != null)) {
|
126
|
-
throw Error(`Expected gridParent to have a parent`);
|
127
|
-
}
|
128
|
-
this.set(this.gridKey, gridParent.getKey(), focusCell.getKey());
|
129
|
-
} else {
|
130
|
-
// anchor is on higher Grid level than focus
|
131
|
-
const focusCellParent = focusCellGrid.getParent();
|
132
|
-
if (!(focusCellParent != null)) {
|
133
|
-
throw Error(`Expected focusCellParent to have a parent`);
|
134
|
-
}
|
135
|
-
this.set(this.gridKey, focusCell.getKey(), focusCellParent.getKey());
|
136
|
-
}
|
137
|
-
return this.getNodes();
|
138
|
-
}
|
139
|
-
|
140
|
-
// TODO Mapping the whole Grid every time not efficient. We need to compute the entire state only
|
141
|
-
// once (on load) and iterate on it as updates occur. However, to do this we need to have the
|
142
|
-
// ability to store a state. Killing GridSelection and moving the logic to the plugin would make
|
143
|
-
// this possible.
|
144
|
-
const [map, cellAMap, cellBMap] = lexical.DEPRECATED_$computeGridMap(gridNode, anchorCell, focusCell);
|
145
|
-
let minColumn = Math.min(cellAMap.startColumn, cellBMap.startColumn);
|
146
|
-
let minRow = Math.min(cellAMap.startRow, cellBMap.startRow);
|
147
|
-
let maxColumn = Math.max(cellAMap.startColumn + cellAMap.cell.__colSpan - 1, cellBMap.startColumn + cellBMap.cell.__colSpan - 1);
|
148
|
-
let maxRow = Math.max(cellAMap.startRow + cellAMap.cell.__rowSpan - 1, cellBMap.startRow + cellBMap.cell.__rowSpan - 1);
|
149
|
-
let exploredMinColumn = minColumn;
|
150
|
-
let exploredMinRow = minRow;
|
151
|
-
let exploredMaxColumn = minColumn;
|
152
|
-
let exploredMaxRow = minRow;
|
153
|
-
function expandBoundary(mapValue) {
|
154
|
-
const {
|
155
|
-
cell,
|
156
|
-
startColumn: cellStartColumn,
|
157
|
-
startRow: cellStartRow
|
158
|
-
} = mapValue;
|
159
|
-
minColumn = Math.min(minColumn, cellStartColumn);
|
160
|
-
minRow = Math.min(minRow, cellStartRow);
|
161
|
-
maxColumn = Math.max(maxColumn, cellStartColumn + cell.__colSpan - 1);
|
162
|
-
maxRow = Math.max(maxRow, cellStartRow + cell.__rowSpan - 1);
|
163
|
-
}
|
164
|
-
while (minColumn < exploredMinColumn || minRow < exploredMinRow || maxColumn > exploredMaxColumn || maxRow > exploredMaxRow) {
|
165
|
-
if (minColumn < exploredMinColumn) {
|
166
|
-
// Expand on the left
|
167
|
-
const rowDiff = exploredMaxRow - exploredMinRow;
|
168
|
-
const previousColumn = exploredMinColumn - 1;
|
169
|
-
for (let i = 0; i <= rowDiff; i++) {
|
170
|
-
expandBoundary(map[exploredMinRow + i][previousColumn]);
|
171
|
-
}
|
172
|
-
exploredMinColumn = previousColumn;
|
173
|
-
}
|
174
|
-
if (minRow < exploredMinRow) {
|
175
|
-
// Expand on top
|
176
|
-
const columnDiff = exploredMaxColumn - exploredMinColumn;
|
177
|
-
const previousRow = exploredMinRow - 1;
|
178
|
-
for (let i = 0; i <= columnDiff; i++) {
|
179
|
-
expandBoundary(map[previousRow][exploredMinColumn + i]);
|
180
|
-
}
|
181
|
-
exploredMinRow = previousRow;
|
182
|
-
}
|
183
|
-
if (maxColumn > exploredMaxColumn) {
|
184
|
-
// Expand on the right
|
185
|
-
const rowDiff = exploredMaxRow - exploredMinRow;
|
186
|
-
const nextColumn = exploredMaxColumn + 1;
|
187
|
-
for (let i = 0; i <= rowDiff; i++) {
|
188
|
-
expandBoundary(map[exploredMinRow + i][nextColumn]);
|
189
|
-
}
|
190
|
-
exploredMaxColumn = nextColumn;
|
191
|
-
}
|
192
|
-
if (maxRow > exploredMaxRow) {
|
193
|
-
// Expand on the bottom
|
194
|
-
const columnDiff = exploredMaxColumn - exploredMinColumn;
|
195
|
-
const nextRow = exploredMaxRow + 1;
|
196
|
-
for (let i = 0; i <= columnDiff; i++) {
|
197
|
-
expandBoundary(map[nextRow][exploredMinColumn + i]);
|
198
|
-
}
|
199
|
-
exploredMaxRow = nextRow;
|
200
|
-
}
|
201
|
-
}
|
202
|
-
const nodes = [gridNode];
|
203
|
-
let lastRow = null;
|
204
|
-
for (let i = minRow; i <= maxRow; i++) {
|
205
|
-
for (let j = minColumn; j <= maxColumn; j++) {
|
206
|
-
const {
|
207
|
-
cell
|
208
|
-
} = map[i][j];
|
209
|
-
const currentRow = cell.getParent();
|
210
|
-
if (!lexical.DEPRECATED_$isGridRowNode(currentRow)) {
|
211
|
-
throw Error(`Expected GridCellNode parent to be a GridRowNode`);
|
212
|
-
}
|
213
|
-
if (currentRow !== lastRow) {
|
214
|
-
nodes.push(currentRow);
|
215
|
-
}
|
216
|
-
nodes.push(cell, ...$getChildrenRecursively(cell));
|
217
|
-
lastRow = currentRow;
|
218
|
-
}
|
219
|
-
}
|
220
|
-
if (!lexical.isCurrentlyReadOnlyMode()) {
|
221
|
-
this._cachedNodes = nodes;
|
222
|
-
}
|
223
|
-
return nodes;
|
224
|
-
}
|
225
|
-
getTextContent() {
|
226
|
-
const nodes = this.getNodes();
|
227
|
-
let textContent = '';
|
228
|
-
for (let i = 0; i < nodes.length; i++) {
|
229
|
-
textContent += nodes[i].getTextContent();
|
230
|
-
}
|
231
|
-
return textContent;
|
232
|
-
}
|
233
|
-
}
|
234
|
-
function $isGridSelection(x) {
|
235
|
-
return x instanceof GridSelection;
|
236
|
-
}
|
237
|
-
function $createGridSelection() {
|
238
|
-
const anchor = lexical.$createPoint('root', 0, 'element');
|
239
|
-
const focus = lexical.$createPoint('root', 0, 'element');
|
240
|
-
return new GridSelection('root', anchor, focus);
|
241
|
-
}
|
242
|
-
function $getChildrenRecursively(node) {
|
243
|
-
const nodes = [];
|
244
|
-
const stack = [node];
|
245
|
-
while (stack.length > 0) {
|
246
|
-
const currentNode = stack.pop();
|
247
|
-
if (!(currentNode !== undefined)) {
|
248
|
-
throw Error(`Stack.length > 0; can't be undefined`);
|
249
|
-
}
|
250
|
-
if (lexical.$isElementNode(currentNode)) {
|
251
|
-
stack.unshift(...currentNode.getChildren());
|
252
|
-
}
|
253
|
-
if (currentNode !== node) {
|
254
|
-
nodes.push(currentNode);
|
255
|
-
}
|
256
|
-
}
|
257
|
-
return nodes;
|
258
|
-
}
|
10
|
+
var lexical = require('lexical');
|
259
11
|
|
260
12
|
/**
|
261
13
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
@@ -281,7 +33,11 @@ const TableCellHeaderStates = {
|
|
281
33
|
ROW: 1
|
282
34
|
};
|
283
35
|
/** @noInheritDoc */
|
284
|
-
class TableCellNode extends lexical.
|
36
|
+
class TableCellNode extends lexical.ElementNode {
|
37
|
+
/** @internal */
|
38
|
+
|
39
|
+
/** @internal */
|
40
|
+
|
285
41
|
/** @internal */
|
286
42
|
|
287
43
|
/** @internal */
|
@@ -318,7 +74,9 @@ class TableCellNode extends lexical.DEPRECATED_GridCellNode {
|
|
318
74
|
return cellNode;
|
319
75
|
}
|
320
76
|
constructor(headerState = TableCellHeaderStates.NO_STATUS, colSpan = 1, width, key) {
|
321
|
-
super(
|
77
|
+
super(key);
|
78
|
+
this.__colSpan = colSpan;
|
79
|
+
this.__rowSpan = 1;
|
322
80
|
this.__headerState = headerState;
|
323
81
|
this.__width = width;
|
324
82
|
this.__backgroundColor = null;
|
@@ -373,11 +131,27 @@ class TableCellNode extends lexical.DEPRECATED_GridCellNode {
|
|
373
131
|
return {
|
374
132
|
...super.exportJSON(),
|
375
133
|
backgroundColor: this.getBackgroundColor(),
|
134
|
+
colSpan: this.__colSpan,
|
376
135
|
headerState: this.__headerState,
|
136
|
+
rowSpan: this.__rowSpan,
|
377
137
|
type: 'tablecell',
|
378
138
|
width: this.getWidth()
|
379
139
|
};
|
380
140
|
}
|
141
|
+
getColSpan() {
|
142
|
+
return this.__colSpan;
|
143
|
+
}
|
144
|
+
setColSpan(colSpan) {
|
145
|
+
this.getWritable().__colSpan = colSpan;
|
146
|
+
return this;
|
147
|
+
}
|
148
|
+
getRowSpan() {
|
149
|
+
return this.__rowSpan;
|
150
|
+
}
|
151
|
+
setRowSpan(rowSpan) {
|
152
|
+
this.getWritable().__rowSpan = rowSpan;
|
153
|
+
return this;
|
154
|
+
}
|
381
155
|
getTag() {
|
382
156
|
return this.hasHeader() ? 'th' : 'td';
|
383
157
|
}
|
@@ -469,6 +243,15 @@ function $isTableCellNode(node) {
|
|
469
243
|
return node instanceof TableCellNode;
|
470
244
|
}
|
471
245
|
|
246
|
+
/**
|
247
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
248
|
+
*
|
249
|
+
* This source code is licensed under the MIT license found in the
|
250
|
+
* LICENSE file in the root directory of this source tree.
|
251
|
+
*
|
252
|
+
*/
|
253
|
+
const INSERT_TABLE_COMMAND = lexical.createCommand('INSERT_TABLE_COMMAND');
|
254
|
+
|
472
255
|
/**
|
473
256
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
474
257
|
*
|
@@ -477,7 +260,7 @@ function $isTableCellNode(node) {
|
|
477
260
|
*
|
478
261
|
*/
|
479
262
|
/** @noInheritDoc */
|
480
|
-
class TableRowNode extends lexical.
|
263
|
+
class TableRowNode extends lexical.ElementNode {
|
481
264
|
/** @internal */
|
482
265
|
|
483
266
|
static getType() {
|
@@ -571,42 +354,967 @@ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !==
|
|
571
354
|
* LICENSE file in the root directory of this source tree.
|
572
355
|
*
|
573
356
|
*/
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
357
|
+
function $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders = true) {
|
358
|
+
const tableNode = $createTableNode();
|
359
|
+
for (let iRow = 0; iRow < rowCount; iRow++) {
|
360
|
+
const tableRowNode = $createTableRowNode();
|
361
|
+
for (let iColumn = 0; iColumn < columnCount; iColumn++) {
|
362
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
363
|
+
if (typeof includeHeaders === 'object') {
|
364
|
+
if (iRow === 0 && includeHeaders.rows) headerState |= TableCellHeaderStates.ROW;
|
365
|
+
if (iColumn === 0 && includeHeaders.columns) headerState |= TableCellHeaderStates.COLUMN;
|
366
|
+
} else if (includeHeaders) {
|
367
|
+
if (iRow === 0) headerState |= TableCellHeaderStates.ROW;
|
368
|
+
if (iColumn === 0) headerState |= TableCellHeaderStates.COLUMN;
|
369
|
+
}
|
370
|
+
const tableCellNode = $createTableCellNode(headerState);
|
371
|
+
const paragraphNode = lexical.$createParagraphNode();
|
372
|
+
paragraphNode.append(lexical.$createTextNode());
|
373
|
+
tableCellNode.append(paragraphNode);
|
374
|
+
tableRowNode.append(tableCellNode);
|
375
|
+
}
|
376
|
+
tableNode.append(tableRowNode);
|
377
|
+
}
|
378
|
+
return tableNode;
|
379
|
+
}
|
380
|
+
function $getTableCellNodeFromLexicalNode(startingNode) {
|
381
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableCellNode(n));
|
382
|
+
if ($isTableCellNode(node)) {
|
383
|
+
return node;
|
384
|
+
}
|
385
|
+
return null;
|
386
|
+
}
|
387
|
+
function $getTableRowNodeFromTableCellNodeOrThrow(startingNode) {
|
388
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableRowNode(n));
|
389
|
+
if ($isTableRowNode(node)) {
|
390
|
+
return node;
|
391
|
+
}
|
392
|
+
throw new Error('Expected table cell to be inside of table row.');
|
393
|
+
}
|
394
|
+
function $getTableNodeFromLexicalNodeOrThrow(startingNode) {
|
395
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableNode(n));
|
396
|
+
if ($isTableNode(node)) {
|
397
|
+
return node;
|
398
|
+
}
|
399
|
+
throw new Error('Expected table cell to be inside of table.');
|
400
|
+
}
|
401
|
+
function $getTableRowIndexFromTableCellNode(tableCellNode) {
|
402
|
+
const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode);
|
403
|
+
const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableRowNode);
|
404
|
+
return tableNode.getChildren().findIndex(n => n.is(tableRowNode));
|
405
|
+
}
|
406
|
+
function $getTableColumnIndexFromTableCellNode(tableCellNode) {
|
407
|
+
const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode);
|
408
|
+
return tableRowNode.getChildren().findIndex(n => n.is(tableCellNode));
|
409
|
+
}
|
410
|
+
function $getTableCellSiblingsFromTableCellNode(tableCellNode, table) {
|
411
|
+
const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
|
412
|
+
const {
|
413
|
+
x,
|
414
|
+
y
|
415
|
+
} = tableNode.getCordsFromCellNode(tableCellNode, table);
|
416
|
+
return {
|
417
|
+
above: tableNode.getCellNodeFromCords(x, y - 1, table),
|
418
|
+
below: tableNode.getCellNodeFromCords(x, y + 1, table),
|
419
|
+
left: tableNode.getCellNodeFromCords(x - 1, y, table),
|
420
|
+
right: tableNode.getCellNodeFromCords(x + 1, y, table)
|
421
|
+
};
|
422
|
+
}
|
423
|
+
function $removeTableRowAtIndex(tableNode, indexToDelete) {
|
424
|
+
const tableRows = tableNode.getChildren();
|
425
|
+
if (indexToDelete >= tableRows.length || indexToDelete < 0) {
|
426
|
+
throw new Error('Expected table cell to be inside of table row.');
|
427
|
+
}
|
428
|
+
const targetRowNode = tableRows[indexToDelete];
|
429
|
+
targetRowNode.remove();
|
430
|
+
return tableNode;
|
431
|
+
}
|
432
|
+
function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCount, table) {
|
433
|
+
const tableRows = tableNode.getChildren();
|
434
|
+
if (targetIndex >= tableRows.length || targetIndex < 0) {
|
435
|
+
throw new Error('Table row target index out of range');
|
436
|
+
}
|
437
|
+
const targetRowNode = tableRows[targetIndex];
|
438
|
+
if ($isTableRowNode(targetRowNode)) {
|
439
|
+
for (let r = 0; r < rowCount; r++) {
|
440
|
+
const tableRowCells = targetRowNode.getChildren();
|
441
|
+
const tableColumnCount = tableRowCells.length;
|
442
|
+
const newTableRowNode = $createTableRowNode();
|
443
|
+
for (let c = 0; c < tableColumnCount; c++) {
|
444
|
+
const tableCellFromTargetRow = tableRowCells[c];
|
445
|
+
if (!$isTableCellNode(tableCellFromTargetRow)) {
|
446
|
+
throw Error(`Expected table cell`);
|
447
|
+
}
|
448
|
+
const {
|
449
|
+
above,
|
450
|
+
below
|
451
|
+
} = $getTableCellSiblingsFromTableCellNode(tableCellFromTargetRow, table);
|
452
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
453
|
+
const width = above && above.getWidth() || below && below.getWidth() || undefined;
|
454
|
+
if (above && above.hasHeaderState(TableCellHeaderStates.COLUMN) || below && below.hasHeaderState(TableCellHeaderStates.COLUMN)) {
|
455
|
+
headerState |= TableCellHeaderStates.COLUMN;
|
456
|
+
}
|
457
|
+
const tableCellNode = $createTableCellNode(headerState, 1, width);
|
458
|
+
tableCellNode.append(lexical.$createParagraphNode());
|
459
|
+
newTableRowNode.append(tableCellNode);
|
460
|
+
}
|
461
|
+
if (shouldInsertAfter) {
|
462
|
+
targetRowNode.insertAfter(newTableRowNode);
|
463
|
+
} else {
|
464
|
+
targetRowNode.insertBefore(newTableRowNode);
|
465
|
+
}
|
466
|
+
}
|
467
|
+
} else {
|
468
|
+
throw new Error('Row before insertion index does not exist.');
|
469
|
+
}
|
470
|
+
return tableNode;
|
471
|
+
}
|
472
|
+
const getHeaderState = (currentState, possibleState) => {
|
473
|
+
if (currentState === TableCellHeaderStates.BOTH || currentState === possibleState) {
|
474
|
+
return possibleState;
|
475
|
+
}
|
476
|
+
return TableCellHeaderStates.NO_STATUS;
|
477
|
+
};
|
478
|
+
function $insertTableRow__EXPERIMENTAL(insertAfter = true) {
|
479
|
+
const selection = lexical.$getSelection();
|
480
|
+
if (!(lexical.$isRangeSelection(selection) || $isTableSelection(selection))) {
|
481
|
+
throw Error(`Expected a RangeSelection or GridSelection`);
|
482
|
+
}
|
483
|
+
const focus = selection.focus.getNode();
|
484
|
+
const [focusCell,, grid] = $getNodeTriplet(focus);
|
485
|
+
const [gridMap, focusCellMap] = $computeTableMap(grid, focusCell, focusCell);
|
486
|
+
const columnCount = gridMap[0].length;
|
487
|
+
const {
|
488
|
+
startRow: focusStartRow
|
489
|
+
} = focusCellMap;
|
490
|
+
if (insertAfter) {
|
491
|
+
const focusEndRow = focusStartRow + focusCell.__rowSpan - 1;
|
492
|
+
const focusEndRowMap = gridMap[focusEndRow];
|
493
|
+
const newRow = $createTableRowNode();
|
494
|
+
for (let i = 0; i < columnCount; i++) {
|
495
|
+
const {
|
496
|
+
cell,
|
497
|
+
startRow
|
498
|
+
} = focusEndRowMap[i];
|
499
|
+
if (startRow + cell.__rowSpan - 1 <= focusEndRow) {
|
500
|
+
const currentCell = focusEndRowMap[i].cell;
|
501
|
+
const currentCellHeaderState = currentCell.__headerState;
|
502
|
+
const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.COLUMN);
|
503
|
+
newRow.append($createTableCellNode(headerState).append(lexical.$createParagraphNode()));
|
504
|
+
} else {
|
505
|
+
cell.setRowSpan(cell.__rowSpan + 1);
|
506
|
+
}
|
507
|
+
}
|
508
|
+
const focusEndRowNode = grid.getChildAtIndex(focusEndRow);
|
509
|
+
if (!$isTableRowNode(focusEndRowNode)) {
|
510
|
+
throw Error(`focusEndRow is not a TableRowNode`);
|
511
|
+
}
|
512
|
+
focusEndRowNode.insertAfter(newRow);
|
513
|
+
} else {
|
514
|
+
const focusStartRowMap = gridMap[focusStartRow];
|
515
|
+
const newRow = $createTableRowNode();
|
516
|
+
for (let i = 0; i < columnCount; i++) {
|
517
|
+
const {
|
518
|
+
cell,
|
519
|
+
startRow
|
520
|
+
} = focusStartRowMap[i];
|
521
|
+
if (startRow === focusStartRow) {
|
522
|
+
const currentCell = focusStartRowMap[i].cell;
|
523
|
+
const currentCellHeaderState = currentCell.__headerState;
|
524
|
+
const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.COLUMN);
|
525
|
+
newRow.append($createTableCellNode(headerState).append(lexical.$createParagraphNode()));
|
526
|
+
} else {
|
527
|
+
cell.setRowSpan(cell.__rowSpan + 1);
|
528
|
+
}
|
529
|
+
}
|
530
|
+
const focusStartRowNode = grid.getChildAtIndex(focusStartRow);
|
531
|
+
if (!$isTableRowNode(focusStartRowNode)) {
|
532
|
+
throw Error(`focusEndRow is not a TableRowNode`);
|
533
|
+
}
|
534
|
+
focusStartRowNode.insertBefore(newRow);
|
535
|
+
}
|
536
|
+
}
|
537
|
+
function $insertTableColumn(tableNode, targetIndex, shouldInsertAfter = true, columnCount, table) {
|
538
|
+
const tableRows = tableNode.getChildren();
|
539
|
+
const tableCellsToBeInserted = [];
|
540
|
+
for (let r = 0; r < tableRows.length; r++) {
|
541
|
+
const currentTableRowNode = tableRows[r];
|
542
|
+
if ($isTableRowNode(currentTableRowNode)) {
|
543
|
+
for (let c = 0; c < columnCount; c++) {
|
544
|
+
const tableRowChildren = currentTableRowNode.getChildren();
|
545
|
+
if (targetIndex >= tableRowChildren.length || targetIndex < 0) {
|
546
|
+
throw new Error('Table column target index out of range');
|
547
|
+
}
|
548
|
+
const targetCell = tableRowChildren[targetIndex];
|
549
|
+
if (!$isTableCellNode(targetCell)) {
|
550
|
+
throw Error(`Expected table cell`);
|
551
|
+
}
|
552
|
+
const {
|
553
|
+
left,
|
554
|
+
right
|
555
|
+
} = $getTableCellSiblingsFromTableCellNode(targetCell, table);
|
556
|
+
let headerState = TableCellHeaderStates.NO_STATUS;
|
557
|
+
if (left && left.hasHeaderState(TableCellHeaderStates.ROW) || right && right.hasHeaderState(TableCellHeaderStates.ROW)) {
|
558
|
+
headerState |= TableCellHeaderStates.ROW;
|
559
|
+
}
|
560
|
+
const newTableCell = $createTableCellNode(headerState);
|
561
|
+
newTableCell.append(lexical.$createParagraphNode());
|
562
|
+
tableCellsToBeInserted.push({
|
563
|
+
newTableCell,
|
564
|
+
targetCell
|
565
|
+
});
|
566
|
+
}
|
567
|
+
}
|
568
|
+
}
|
569
|
+
tableCellsToBeInserted.forEach(({
|
570
|
+
newTableCell,
|
571
|
+
targetCell
|
572
|
+
}) => {
|
573
|
+
if (shouldInsertAfter) {
|
574
|
+
targetCell.insertAfter(newTableCell);
|
575
|
+
} else {
|
576
|
+
targetCell.insertBefore(newTableCell);
|
577
|
+
}
|
578
|
+
});
|
579
|
+
return tableNode;
|
580
|
+
}
|
581
|
+
function $insertTableColumn__EXPERIMENTAL(insertAfter = true) {
|
582
|
+
const selection = lexical.$getSelection();
|
583
|
+
if (!(lexical.$isRangeSelection(selection) || $isTableSelection(selection))) {
|
584
|
+
throw Error(`Expected a RangeSelection or GridSelection`);
|
585
|
+
}
|
586
|
+
const anchor = selection.anchor.getNode();
|
587
|
+
const focus = selection.focus.getNode();
|
588
|
+
const [anchorCell] = $getNodeTriplet(anchor);
|
589
|
+
const [focusCell,, grid] = $getNodeTriplet(focus);
|
590
|
+
const [gridMap, focusCellMap, anchorCellMap] = $computeTableMap(grid, focusCell, anchorCell);
|
591
|
+
const rowCount = gridMap.length;
|
592
|
+
const startColumn = insertAfter ? Math.max(focusCellMap.startColumn, anchorCellMap.startColumn) : Math.min(focusCellMap.startColumn, anchorCellMap.startColumn);
|
593
|
+
const insertAfterColumn = insertAfter ? startColumn + focusCell.__colSpan - 1 : startColumn - 1;
|
594
|
+
const gridFirstChild = grid.getFirstChild();
|
595
|
+
if (!$isTableRowNode(gridFirstChild)) {
|
596
|
+
throw Error(`Expected firstTable child to be a row`);
|
597
|
+
}
|
598
|
+
let firstInsertedCell = null;
|
599
|
+
function $createTableCellNodeForInsertTableColumn(headerState = TableCellHeaderStates.NO_STATUS) {
|
600
|
+
const cell = $createTableCellNode(headerState).append(lexical.$createParagraphNode());
|
601
|
+
if (firstInsertedCell === null) {
|
602
|
+
firstInsertedCell = cell;
|
603
|
+
}
|
604
|
+
return cell;
|
605
|
+
}
|
606
|
+
let loopRow = gridFirstChild;
|
607
|
+
rowLoop: for (let i = 0; i < rowCount; i++) {
|
608
|
+
if (i !== 0) {
|
609
|
+
const currentRow = loopRow.getNextSibling();
|
610
|
+
if (!$isTableRowNode(currentRow)) {
|
611
|
+
throw Error(`Expected row nextSibling to be a row`);
|
612
|
+
}
|
613
|
+
loopRow = currentRow;
|
614
|
+
}
|
615
|
+
const rowMap = gridMap[i];
|
616
|
+
const currentCellHeaderState = rowMap[insertAfterColumn < 0 ? 0 : insertAfterColumn].cell.__headerState;
|
617
|
+
const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.ROW);
|
618
|
+
if (insertAfterColumn < 0) {
|
619
|
+
$insertFirst(loopRow, $createTableCellNodeForInsertTableColumn(headerState));
|
620
|
+
continue;
|
621
|
+
}
|
622
|
+
const {
|
623
|
+
cell: currentCell,
|
624
|
+
startColumn: currentStartColumn,
|
625
|
+
startRow: currentStartRow
|
626
|
+
} = rowMap[insertAfterColumn];
|
627
|
+
if (currentStartColumn + currentCell.__colSpan - 1 <= insertAfterColumn) {
|
628
|
+
let insertAfterCell = currentCell;
|
629
|
+
let insertAfterCellRowStart = currentStartRow;
|
630
|
+
let prevCellIndex = insertAfterColumn;
|
631
|
+
while (insertAfterCellRowStart !== i && insertAfterCell.__rowSpan > 1) {
|
632
|
+
prevCellIndex -= currentCell.__colSpan;
|
633
|
+
if (prevCellIndex >= 0) {
|
634
|
+
const {
|
635
|
+
cell: cell_,
|
636
|
+
startRow: startRow_
|
637
|
+
} = rowMap[prevCellIndex];
|
638
|
+
insertAfterCell = cell_;
|
639
|
+
insertAfterCellRowStart = startRow_;
|
640
|
+
} else {
|
641
|
+
loopRow.append($createTableCellNodeForInsertTableColumn(headerState));
|
642
|
+
continue rowLoop;
|
643
|
+
}
|
644
|
+
}
|
645
|
+
insertAfterCell.insertAfter($createTableCellNodeForInsertTableColumn(headerState));
|
646
|
+
} else {
|
647
|
+
currentCell.setColSpan(currentCell.__colSpan + 1);
|
648
|
+
}
|
649
|
+
}
|
650
|
+
if (firstInsertedCell !== null) {
|
651
|
+
$moveSelectionToCell(firstInsertedCell);
|
652
|
+
}
|
653
|
+
}
|
654
|
+
function $deleteTableColumn(tableNode, targetIndex) {
|
655
|
+
const tableRows = tableNode.getChildren();
|
656
|
+
for (let i = 0; i < tableRows.length; i++) {
|
657
|
+
const currentTableRowNode = tableRows[i];
|
658
|
+
if ($isTableRowNode(currentTableRowNode)) {
|
659
|
+
const tableRowChildren = currentTableRowNode.getChildren();
|
660
|
+
if (targetIndex >= tableRowChildren.length || targetIndex < 0) {
|
661
|
+
throw new Error('Table column target index out of range');
|
662
|
+
}
|
663
|
+
tableRowChildren[targetIndex].remove();
|
664
|
+
}
|
665
|
+
}
|
666
|
+
return tableNode;
|
667
|
+
}
|
668
|
+
function $deleteTableRow__EXPERIMENTAL() {
|
669
|
+
const selection = lexical.$getSelection();
|
670
|
+
if (!(lexical.$isRangeSelection(selection) || $isTableSelection(selection))) {
|
671
|
+
throw Error(`Expected a RangeSelection or GridSelection`);
|
672
|
+
}
|
673
|
+
const anchor = selection.anchor.getNode();
|
674
|
+
const focus = selection.focus.getNode();
|
675
|
+
const [anchorCell,, grid] = $getNodeTriplet(anchor);
|
676
|
+
const [focusCell] = $getNodeTriplet(focus);
|
677
|
+
const [gridMap, anchorCellMap, focusCellMap] = $computeTableMap(grid, anchorCell, focusCell);
|
678
|
+
const {
|
679
|
+
startRow: anchorStartRow
|
680
|
+
} = anchorCellMap;
|
681
|
+
const {
|
682
|
+
startRow: focusStartRow
|
683
|
+
} = focusCellMap;
|
684
|
+
const focusEndRow = focusStartRow + focusCell.__rowSpan - 1;
|
685
|
+
if (gridMap.length === focusEndRow - anchorStartRow + 1) {
|
686
|
+
// Empty grid
|
687
|
+
grid.remove();
|
688
|
+
return;
|
689
|
+
}
|
690
|
+
const columnCount = gridMap[0].length;
|
691
|
+
const nextRow = gridMap[focusEndRow + 1];
|
692
|
+
const nextRowNode = grid.getChildAtIndex(focusEndRow + 1);
|
693
|
+
for (let row = focusEndRow; row >= anchorStartRow; row--) {
|
694
|
+
for (let column = columnCount - 1; column >= 0; column--) {
|
695
|
+
const {
|
696
|
+
cell,
|
697
|
+
startRow: cellStartRow,
|
698
|
+
startColumn: cellStartColumn
|
699
|
+
} = gridMap[row][column];
|
700
|
+
if (cellStartColumn !== column) {
|
701
|
+
// Don't repeat work for the same Cell
|
702
|
+
continue;
|
703
|
+
}
|
704
|
+
// Rows overflowing top have to be trimmed
|
705
|
+
if (row === anchorStartRow && cellStartRow < anchorStartRow) {
|
706
|
+
cell.setRowSpan(cell.__rowSpan - (cellStartRow - anchorStartRow));
|
707
|
+
}
|
708
|
+
// Rows overflowing bottom have to be trimmed and moved to the next row
|
709
|
+
if (cellStartRow >= anchorStartRow && cellStartRow + cell.__rowSpan - 1 > focusEndRow) {
|
710
|
+
cell.setRowSpan(cell.__rowSpan - (focusEndRow - cellStartRow + 1));
|
711
|
+
if (!(nextRowNode !== null)) {
|
712
|
+
throw Error(`Expected nextRowNode not to be null`);
|
713
|
+
}
|
714
|
+
if (column === 0) {
|
715
|
+
$insertFirst(nextRowNode, cell);
|
716
|
+
} else {
|
717
|
+
const {
|
718
|
+
cell: previousCell
|
719
|
+
} = nextRow[column - 1];
|
720
|
+
previousCell.insertAfter(cell);
|
721
|
+
}
|
722
|
+
}
|
723
|
+
}
|
724
|
+
const rowNode = grid.getChildAtIndex(row);
|
725
|
+
if (!$isTableRowNode(rowNode)) {
|
726
|
+
throw Error(`Expected GridNode childAtIndex(${String(row)}) to be RowNode`);
|
727
|
+
}
|
728
|
+
rowNode.remove();
|
729
|
+
}
|
730
|
+
if (nextRow !== undefined) {
|
731
|
+
const {
|
732
|
+
cell
|
733
|
+
} = nextRow[0];
|
734
|
+
$moveSelectionToCell(cell);
|
735
|
+
} else {
|
736
|
+
const previousRow = gridMap[anchorStartRow - 1];
|
737
|
+
const {
|
738
|
+
cell
|
739
|
+
} = previousRow[0];
|
740
|
+
$moveSelectionToCell(cell);
|
741
|
+
}
|
742
|
+
}
|
743
|
+
function $deleteTableColumn__EXPERIMENTAL() {
|
744
|
+
const selection = lexical.$getSelection();
|
745
|
+
if (!(lexical.$isRangeSelection(selection) || $isTableSelection(selection))) {
|
746
|
+
throw Error(`Expected a RangeSelection or GridSelection`);
|
747
|
+
}
|
748
|
+
const anchor = selection.anchor.getNode();
|
749
|
+
const focus = selection.focus.getNode();
|
750
|
+
const [anchorCell,, grid] = $getNodeTriplet(anchor);
|
751
|
+
const [focusCell] = $getNodeTriplet(focus);
|
752
|
+
const [gridMap, anchorCellMap, focusCellMap] = $computeTableMap(grid, anchorCell, focusCell);
|
753
|
+
const {
|
754
|
+
startColumn: anchorStartColumn
|
755
|
+
} = anchorCellMap;
|
756
|
+
const {
|
757
|
+
startRow: focusStartRow,
|
758
|
+
startColumn: focusStartColumn
|
759
|
+
} = focusCellMap;
|
760
|
+
const startColumn = Math.min(anchorStartColumn, focusStartColumn);
|
761
|
+
const endColumn = Math.max(anchorStartColumn + anchorCell.__colSpan - 1, focusStartColumn + focusCell.__colSpan - 1);
|
762
|
+
const selectedColumnCount = endColumn - startColumn + 1;
|
763
|
+
const columnCount = gridMap[0].length;
|
764
|
+
if (columnCount === endColumn - startColumn + 1) {
|
765
|
+
// Empty grid
|
766
|
+
grid.selectPrevious();
|
767
|
+
grid.remove();
|
768
|
+
return;
|
769
|
+
}
|
770
|
+
const rowCount = gridMap.length;
|
771
|
+
for (let row = 0; row < rowCount; row++) {
|
772
|
+
for (let column = startColumn; column <= endColumn; column++) {
|
773
|
+
const {
|
774
|
+
cell,
|
775
|
+
startColumn: cellStartColumn
|
776
|
+
} = gridMap[row][column];
|
777
|
+
if (cellStartColumn < startColumn) {
|
778
|
+
if (column === startColumn) {
|
779
|
+
const overflowLeft = startColumn - cellStartColumn;
|
780
|
+
// Overflowing left
|
781
|
+
cell.setColSpan(cell.__colSpan -
|
782
|
+
// Possible overflow right too
|
783
|
+
Math.min(selectedColumnCount, cell.__colSpan - overflowLeft));
|
784
|
+
}
|
785
|
+
} else if (cellStartColumn + cell.__colSpan - 1 > endColumn) {
|
786
|
+
if (column === endColumn) {
|
787
|
+
// Overflowing right
|
788
|
+
const inSelectedArea = endColumn - cellStartColumn + 1;
|
789
|
+
cell.setColSpan(cell.__colSpan - inSelectedArea);
|
790
|
+
}
|
791
|
+
} else {
|
792
|
+
cell.remove();
|
793
|
+
}
|
794
|
+
}
|
795
|
+
}
|
796
|
+
const focusRowMap = gridMap[focusStartRow];
|
797
|
+
const nextColumn = focusRowMap[focusStartColumn + focusCell.__colSpan];
|
798
|
+
if (nextColumn !== undefined) {
|
799
|
+
const {
|
800
|
+
cell
|
801
|
+
} = nextColumn;
|
802
|
+
$moveSelectionToCell(cell);
|
803
|
+
} else {
|
804
|
+
const previousRow = focusRowMap[focusStartColumn - 1];
|
805
|
+
const {
|
806
|
+
cell
|
807
|
+
} = previousRow;
|
808
|
+
$moveSelectionToCell(cell);
|
809
|
+
}
|
810
|
+
}
|
811
|
+
function $moveSelectionToCell(cell) {
|
812
|
+
const firstDescendant = cell.getFirstDescendant();
|
813
|
+
if (firstDescendant == null) {
|
814
|
+
cell.selectStart();
|
815
|
+
} else {
|
816
|
+
firstDescendant.getParentOrThrow().selectStart();
|
817
|
+
}
|
818
|
+
}
|
819
|
+
function $insertFirst(parent, node) {
|
820
|
+
const firstChild = parent.getFirstChild();
|
821
|
+
if (firstChild !== null) {
|
822
|
+
firstChild.insertBefore(node);
|
823
|
+
} else {
|
824
|
+
parent.append(node);
|
825
|
+
}
|
826
|
+
}
|
827
|
+
function $unmergeCell() {
|
828
|
+
const selection = lexical.$getSelection();
|
829
|
+
if (!(lexical.$isRangeSelection(selection) || $isTableSelection(selection))) {
|
830
|
+
throw Error(`Expected a RangeSelection or GridSelection`);
|
831
|
+
}
|
832
|
+
const anchor = selection.anchor.getNode();
|
833
|
+
const [cell, row, grid] = $getNodeTriplet(anchor);
|
834
|
+
const colSpan = cell.__colSpan;
|
835
|
+
const rowSpan = cell.__rowSpan;
|
836
|
+
if (colSpan > 1) {
|
837
|
+
for (let i = 1; i < colSpan; i++) {
|
838
|
+
cell.insertAfter($createTableCellNode(TableCellHeaderStates.NO_STATUS));
|
839
|
+
}
|
840
|
+
cell.setColSpan(1);
|
841
|
+
}
|
842
|
+
if (rowSpan > 1) {
|
843
|
+
const [map, cellMap] = $computeTableMap(grid, cell, cell);
|
844
|
+
const {
|
845
|
+
startColumn,
|
846
|
+
startRow
|
847
|
+
} = cellMap;
|
848
|
+
let currentRowNode;
|
849
|
+
for (let i = 1; i < rowSpan; i++) {
|
850
|
+
const currentRow = startRow + i;
|
851
|
+
const currentRowMap = map[currentRow];
|
852
|
+
currentRowNode = (currentRowNode || row).getNextSibling();
|
853
|
+
if (!$isTableRowNode(currentRowNode)) {
|
854
|
+
throw Error(`Expected row next sibling to be a row`);
|
855
|
+
}
|
856
|
+
let insertAfterCell = null;
|
857
|
+
for (let column = 0; column < startColumn; column++) {
|
858
|
+
const currentCellMap = currentRowMap[column];
|
859
|
+
const currentCell = currentCellMap.cell;
|
860
|
+
if (currentCellMap.startRow === currentRow) {
|
861
|
+
insertAfterCell = currentCell;
|
862
|
+
}
|
863
|
+
if (currentCell.__colSpan > 1) {
|
864
|
+
column += currentCell.__colSpan - 1;
|
865
|
+
}
|
866
|
+
}
|
867
|
+
if (insertAfterCell === null) {
|
868
|
+
for (let j = 0; j < colSpan; j++) {
|
869
|
+
$insertFirst(currentRowNode, $createTableCellNode(TableCellHeaderStates.NO_STATUS));
|
870
|
+
}
|
871
|
+
} else {
|
872
|
+
for (let j = 0; j < colSpan; j++) {
|
873
|
+
insertAfterCell.insertAfter($createTableCellNode(TableCellHeaderStates.NO_STATUS));
|
874
|
+
}
|
875
|
+
}
|
876
|
+
}
|
877
|
+
cell.setRowSpan(1);
|
878
|
+
}
|
879
|
+
}
|
880
|
+
function $computeTableMap(grid, cellA, cellB) {
|
881
|
+
const tableMap = [];
|
882
|
+
let cellAValue = null;
|
883
|
+
let cellBValue = null;
|
884
|
+
function write(startRow, startColumn, cell) {
|
885
|
+
const value = {
|
886
|
+
cell,
|
887
|
+
startColumn,
|
888
|
+
startRow
|
889
|
+
};
|
890
|
+
const rowSpan = cell.__rowSpan;
|
891
|
+
const colSpan = cell.__colSpan;
|
892
|
+
for (let i = 0; i < rowSpan; i++) {
|
893
|
+
if (tableMap[startRow + i] === undefined) {
|
894
|
+
tableMap[startRow + i] = [];
|
895
|
+
}
|
896
|
+
for (let j = 0; j < colSpan; j++) {
|
897
|
+
tableMap[startRow + i][startColumn + j] = value;
|
898
|
+
}
|
899
|
+
}
|
900
|
+
if (cellA.is(cell)) {
|
901
|
+
cellAValue = value;
|
902
|
+
}
|
903
|
+
if (cellB.is(cell)) {
|
904
|
+
cellBValue = value;
|
905
|
+
}
|
906
|
+
}
|
907
|
+
function isEmpty(row, column) {
|
908
|
+
return tableMap[row] === undefined || tableMap[row][column] === undefined;
|
909
|
+
}
|
910
|
+
const gridChildren = grid.getChildren();
|
911
|
+
for (let i = 0; i < gridChildren.length; i++) {
|
912
|
+
const row = gridChildren[i];
|
913
|
+
if (!$isTableRowNode(row)) {
|
914
|
+
throw Error(`Expected GridNode children to be TableRowNode`);
|
915
|
+
}
|
916
|
+
const rowChildren = row.getChildren();
|
917
|
+
let j = 0;
|
918
|
+
for (const cell of rowChildren) {
|
919
|
+
if (!$isTableCellNode(cell)) {
|
920
|
+
throw Error(`Expected TableRowNode children to be TableCellNode`);
|
921
|
+
}
|
922
|
+
while (!isEmpty(i, j)) {
|
923
|
+
j++;
|
924
|
+
}
|
925
|
+
write(i, j, cell);
|
926
|
+
j += cell.__colSpan;
|
927
|
+
}
|
928
|
+
}
|
929
|
+
if (!(cellAValue !== null)) {
|
930
|
+
throw Error(`Anchor not found in Grid`);
|
931
|
+
}
|
932
|
+
if (!(cellBValue !== null)) {
|
933
|
+
throw Error(`Focus not found in Grid`);
|
934
|
+
}
|
935
|
+
return [tableMap, cellAValue, cellBValue];
|
936
|
+
}
|
937
|
+
function $getNodeTriplet(source) {
|
938
|
+
let cell;
|
939
|
+
if (source instanceof TableCellNode) {
|
940
|
+
cell = source;
|
941
|
+
} else if ('__type' in source) {
|
942
|
+
const cell_ = utils.$findMatchingParent(source, $isTableCellNode);
|
943
|
+
if (!$isTableCellNode(cell_)) {
|
944
|
+
throw Error(`Expected to find a parent TableCellNode`);
|
945
|
+
}
|
946
|
+
cell = cell_;
|
947
|
+
} else {
|
948
|
+
const cell_ = utils.$findMatchingParent(source.getNode(), $isTableCellNode);
|
949
|
+
if (!$isTableCellNode(cell_)) {
|
950
|
+
throw Error(`Expected to find a parent TableCellNode`);
|
951
|
+
}
|
952
|
+
cell = cell_;
|
953
|
+
}
|
954
|
+
const row = cell.getParent();
|
955
|
+
if (!$isTableRowNode(row)) {
|
956
|
+
throw Error(`Expected TableCellNode to have a parent TableRowNode`);
|
957
|
+
}
|
958
|
+
const grid = row.getParent();
|
959
|
+
if (!$isTableNode(grid)) {
|
960
|
+
throw Error(`Expected TableRowNode to have a parent GridNode`);
|
961
|
+
}
|
962
|
+
return [cell, row, grid];
|
963
|
+
}
|
964
|
+
function $getTableCellNodeRect(tableCellNode) {
|
965
|
+
const [cellNode,, gridNode] = $getNodeTriplet(tableCellNode);
|
966
|
+
const rows = gridNode.getChildren();
|
967
|
+
const rowCount = rows.length;
|
968
|
+
const columnCount = rows[0].getChildren().length;
|
969
|
+
|
970
|
+
// Create a matrix of the same size as the table to track the position of each cell
|
971
|
+
const cellMatrix = new Array(rowCount);
|
972
|
+
for (let i = 0; i < rowCount; i++) {
|
973
|
+
cellMatrix[i] = new Array(columnCount);
|
974
|
+
}
|
975
|
+
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
976
|
+
const row = rows[rowIndex];
|
977
|
+
const cells = row.getChildren();
|
978
|
+
let columnIndex = 0;
|
979
|
+
for (let cellIndex = 0; cellIndex < cells.length; cellIndex++) {
|
980
|
+
// Find the next available position in the matrix, skip the position of merged cells
|
981
|
+
while (cellMatrix[rowIndex][columnIndex]) {
|
982
|
+
columnIndex++;
|
983
|
+
}
|
984
|
+
const cell = cells[cellIndex];
|
985
|
+
const rowSpan = cell.__rowSpan || 1;
|
986
|
+
const colSpan = cell.__colSpan || 1;
|
987
|
+
|
988
|
+
// Put the cell into the corresponding position in the matrix
|
989
|
+
for (let i = 0; i < rowSpan; i++) {
|
990
|
+
for (let j = 0; j < colSpan; j++) {
|
991
|
+
cellMatrix[rowIndex + i][columnIndex + j] = cell;
|
992
|
+
}
|
993
|
+
}
|
994
|
+
|
995
|
+
// Return to the original index, row span and column span of the cell.
|
996
|
+
if (cellNode === cell) {
|
997
|
+
return {
|
998
|
+
colSpan,
|
999
|
+
columnIndex,
|
1000
|
+
rowIndex,
|
1001
|
+
rowSpan
|
1002
|
+
};
|
1003
|
+
}
|
1004
|
+
columnIndex += colSpan;
|
1005
|
+
}
|
1006
|
+
}
|
1007
|
+
return null;
|
1008
|
+
}
|
1009
|
+
|
1010
|
+
/**
|
1011
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
1012
|
+
*
|
1013
|
+
* This source code is licensed under the MIT license found in the
|
1014
|
+
* LICENSE file in the root directory of this source tree.
|
1015
|
+
*
|
1016
|
+
*/
|
1017
|
+
class TableSelection {
|
1018
|
+
constructor(tableKey, anchor, focus) {
|
1019
|
+
this.anchor = anchor;
|
1020
|
+
this.focus = focus;
|
1021
|
+
anchor._selection = this;
|
1022
|
+
focus._selection = this;
|
1023
|
+
this._cachedNodes = null;
|
1024
|
+
this.dirty = false;
|
1025
|
+
this.tableKey = tableKey;
|
1026
|
+
}
|
1027
|
+
getStartEndPoints() {
|
1028
|
+
return [this.anchor, this.focus];
|
1029
|
+
}
|
1030
|
+
|
1031
|
+
/**
|
1032
|
+
* Returns whether the Selection is "backwards", meaning the focus
|
1033
|
+
* logically precedes the anchor in the EditorState.
|
1034
|
+
* @returns true if the Selection is backwards, false otherwise.
|
1035
|
+
*/
|
1036
|
+
isBackward() {
|
1037
|
+
return this.focus.isBefore(this.anchor);
|
1038
|
+
}
|
1039
|
+
getCachedNodes() {
|
1040
|
+
return this._cachedNodes;
|
1041
|
+
}
|
1042
|
+
setCachedNodes(nodes) {
|
1043
|
+
this._cachedNodes = nodes;
|
1044
|
+
}
|
1045
|
+
is(selection) {
|
1046
|
+
if (!$isTableSelection(selection)) {
|
1047
|
+
return false;
|
1048
|
+
}
|
1049
|
+
return this.tableKey === selection.tableKey && this.anchor.is(selection.anchor) && this.focus.is(selection.focus);
|
1050
|
+
}
|
1051
|
+
set(tableKey, anchorCellKey, focusCellKey) {
|
1052
|
+
this.dirty = true;
|
1053
|
+
this.tableKey = tableKey;
|
1054
|
+
this.anchor.key = anchorCellKey;
|
1055
|
+
this.focus.key = focusCellKey;
|
1056
|
+
this._cachedNodes = null;
|
1057
|
+
}
|
1058
|
+
clone() {
|
1059
|
+
return new TableSelection(this.tableKey, this.anchor, this.focus);
|
1060
|
+
}
|
1061
|
+
isCollapsed() {
|
1062
|
+
return false;
|
1063
|
+
}
|
1064
|
+
extract() {
|
1065
|
+
return this.getNodes();
|
1066
|
+
}
|
1067
|
+
insertRawText(text) {
|
1068
|
+
// Do nothing?
|
1069
|
+
}
|
1070
|
+
insertText() {
|
1071
|
+
// Do nothing?
|
1072
|
+
}
|
1073
|
+
insertNodes(nodes) {
|
1074
|
+
const focusNode = this.focus.getNode();
|
1075
|
+
if (!lexical.$isElementNode(focusNode)) {
|
1076
|
+
throw Error(`Expected TableSelection focus to be an ElementNode`);
|
1077
|
+
}
|
1078
|
+
const selection = lexical.$normalizeSelection__EXPERIMENTAL(focusNode.select(0, focusNode.getChildrenSize()));
|
1079
|
+
selection.insertNodes(nodes);
|
1080
|
+
}
|
1081
|
+
|
1082
|
+
// TODO Deprecate this method. It's confusing when used with colspan|rowspan
|
1083
|
+
getShape() {
|
1084
|
+
const anchorCellNode = lexical.$getNodeByKey(this.anchor.key);
|
1085
|
+
if (!$isTableCellNode(anchorCellNode)) {
|
1086
|
+
throw Error(`Expected TableSelection anchor to be (or a child of) TableCellNode`);
|
1087
|
+
}
|
1088
|
+
const anchorCellNodeRect = $getTableCellNodeRect(anchorCellNode);
|
1089
|
+
if (!(anchorCellNodeRect !== null)) {
|
1090
|
+
throw Error(`getCellRect: expected to find AnchorNode`);
|
1091
|
+
}
|
1092
|
+
const focusCellNode = lexical.$getNodeByKey(this.focus.key);
|
1093
|
+
if (!$isTableCellNode(focusCellNode)) {
|
1094
|
+
throw Error(`Expected TableSelection focus to be (or a child of) TableCellNode`);
|
1095
|
+
}
|
1096
|
+
const focusCellNodeRect = $getTableCellNodeRect(focusCellNode);
|
1097
|
+
if (!(focusCellNodeRect !== null)) {
|
1098
|
+
throw Error(`getCellRect: expected to find focusCellNode`);
|
1099
|
+
}
|
1100
|
+
const startX = Math.min(anchorCellNodeRect.columnIndex, focusCellNodeRect.columnIndex);
|
1101
|
+
const stopX = Math.max(anchorCellNodeRect.columnIndex, focusCellNodeRect.columnIndex);
|
1102
|
+
const startY = Math.min(anchorCellNodeRect.rowIndex, focusCellNodeRect.rowIndex);
|
1103
|
+
const stopY = Math.max(anchorCellNodeRect.rowIndex, focusCellNodeRect.rowIndex);
|
1104
|
+
return {
|
1105
|
+
fromX: Math.min(startX, stopX),
|
1106
|
+
fromY: Math.min(startY, stopY),
|
1107
|
+
toX: Math.max(startX, stopX),
|
1108
|
+
toY: Math.max(startY, stopY)
|
1109
|
+
};
|
1110
|
+
}
|
1111
|
+
getNodes() {
|
1112
|
+
const cachedNodes = this._cachedNodes;
|
1113
|
+
if (cachedNodes !== null) {
|
1114
|
+
return cachedNodes;
|
1115
|
+
}
|
1116
|
+
const anchorNode = this.anchor.getNode();
|
1117
|
+
const focusNode = this.focus.getNode();
|
1118
|
+
const anchorCell = utils.$findMatchingParent(anchorNode, $isTableCellNode);
|
1119
|
+
// todo replace with triplet
|
1120
|
+
const focusCell = utils.$findMatchingParent(focusNode, $isTableCellNode);
|
1121
|
+
if (!$isTableCellNode(anchorCell)) {
|
1122
|
+
throw Error(`Expected TableSelection anchor to be (or a child of) TableCellNode`);
|
1123
|
+
}
|
1124
|
+
if (!$isTableCellNode(focusCell)) {
|
1125
|
+
throw Error(`Expected TableSelection focus to be (or a child of) TableCellNode`);
|
1126
|
+
}
|
1127
|
+
const anchorRow = anchorCell.getParent();
|
1128
|
+
if (!$isTableRowNode(anchorRow)) {
|
1129
|
+
throw Error(`Expected anchorCell to have a parent TableRowNode`);
|
1130
|
+
}
|
1131
|
+
const tableNode = anchorRow.getParent();
|
1132
|
+
if (!$isTableNode(tableNode)) {
|
1133
|
+
throw Error(`Expected tableNode to have a parent TableNode`);
|
1134
|
+
}
|
1135
|
+
const focusCellGrid = focusCell.getParents()[1];
|
1136
|
+
if (focusCellGrid !== tableNode) {
|
1137
|
+
if (!tableNode.isParentOf(focusCell)) {
|
1138
|
+
// focus is on higher Grid level than anchor
|
1139
|
+
const gridParent = tableNode.getParent();
|
1140
|
+
if (!(gridParent != null)) {
|
1141
|
+
throw Error(`Expected gridParent to have a parent`);
|
1142
|
+
}
|
1143
|
+
this.set(this.tableKey, gridParent.getKey(), focusCell.getKey());
|
1144
|
+
} else {
|
1145
|
+
// anchor is on higher Grid level than focus
|
1146
|
+
const focusCellParent = focusCellGrid.getParent();
|
1147
|
+
if (!(focusCellParent != null)) {
|
1148
|
+
throw Error(`Expected focusCellParent to have a parent`);
|
1149
|
+
}
|
1150
|
+
this.set(this.tableKey, focusCell.getKey(), focusCellParent.getKey());
|
1151
|
+
}
|
1152
|
+
return this.getNodes();
|
1153
|
+
}
|
1154
|
+
|
1155
|
+
// TODO Mapping the whole Grid every time not efficient. We need to compute the entire state only
|
1156
|
+
// once (on load) and iterate on it as updates occur. However, to do this we need to have the
|
1157
|
+
// ability to store a state. Killing TableSelection and moving the logic to the plugin would make
|
1158
|
+
// this possible.
|
1159
|
+
const [map, cellAMap, cellBMap] = $computeTableMap(tableNode, anchorCell, focusCell);
|
1160
|
+
let minColumn = Math.min(cellAMap.startColumn, cellBMap.startColumn);
|
1161
|
+
let minRow = Math.min(cellAMap.startRow, cellBMap.startRow);
|
1162
|
+
let maxColumn = Math.max(cellAMap.startColumn + cellAMap.cell.__colSpan - 1, cellBMap.startColumn + cellBMap.cell.__colSpan - 1);
|
1163
|
+
let maxRow = Math.max(cellAMap.startRow + cellAMap.cell.__rowSpan - 1, cellBMap.startRow + cellBMap.cell.__rowSpan - 1);
|
1164
|
+
let exploredMinColumn = minColumn;
|
1165
|
+
let exploredMinRow = minRow;
|
1166
|
+
let exploredMaxColumn = minColumn;
|
1167
|
+
let exploredMaxRow = minRow;
|
1168
|
+
function expandBoundary(mapValue) {
|
1169
|
+
const {
|
1170
|
+
cell,
|
1171
|
+
startColumn: cellStartColumn,
|
1172
|
+
startRow: cellStartRow
|
1173
|
+
} = mapValue;
|
1174
|
+
minColumn = Math.min(minColumn, cellStartColumn);
|
1175
|
+
minRow = Math.min(minRow, cellStartRow);
|
1176
|
+
maxColumn = Math.max(maxColumn, cellStartColumn + cell.__colSpan - 1);
|
1177
|
+
maxRow = Math.max(maxRow, cellStartRow + cell.__rowSpan - 1);
|
1178
|
+
}
|
1179
|
+
while (minColumn < exploredMinColumn || minRow < exploredMinRow || maxColumn > exploredMaxColumn || maxRow > exploredMaxRow) {
|
1180
|
+
if (minColumn < exploredMinColumn) {
|
1181
|
+
// Expand on the left
|
1182
|
+
const rowDiff = exploredMaxRow - exploredMinRow;
|
1183
|
+
const previousColumn = exploredMinColumn - 1;
|
1184
|
+
for (let i = 0; i <= rowDiff; i++) {
|
1185
|
+
expandBoundary(map[exploredMinRow + i][previousColumn]);
|
1186
|
+
}
|
1187
|
+
exploredMinColumn = previousColumn;
|
1188
|
+
}
|
1189
|
+
if (minRow < exploredMinRow) {
|
1190
|
+
// Expand on top
|
1191
|
+
const columnDiff = exploredMaxColumn - exploredMinColumn;
|
1192
|
+
const previousRow = exploredMinRow - 1;
|
1193
|
+
for (let i = 0; i <= columnDiff; i++) {
|
1194
|
+
expandBoundary(map[previousRow][exploredMinColumn + i]);
|
1195
|
+
}
|
1196
|
+
exploredMinRow = previousRow;
|
1197
|
+
}
|
1198
|
+
if (maxColumn > exploredMaxColumn) {
|
1199
|
+
// Expand on the right
|
1200
|
+
const rowDiff = exploredMaxRow - exploredMinRow;
|
1201
|
+
const nextColumn = exploredMaxColumn + 1;
|
1202
|
+
for (let i = 0; i <= rowDiff; i++) {
|
1203
|
+
expandBoundary(map[exploredMinRow + i][nextColumn]);
|
1204
|
+
}
|
1205
|
+
exploredMaxColumn = nextColumn;
|
1206
|
+
}
|
1207
|
+
if (maxRow > exploredMaxRow) {
|
1208
|
+
// Expand on the bottom
|
1209
|
+
const columnDiff = exploredMaxColumn - exploredMinColumn;
|
1210
|
+
const nextRow = exploredMaxRow + 1;
|
1211
|
+
for (let i = 0; i <= columnDiff; i++) {
|
1212
|
+
expandBoundary(map[nextRow][exploredMinColumn + i]);
|
1213
|
+
}
|
1214
|
+
exploredMaxRow = nextRow;
|
1215
|
+
}
|
1216
|
+
}
|
1217
|
+
const nodes = [tableNode];
|
1218
|
+
let lastRow = null;
|
1219
|
+
for (let i = minRow; i <= maxRow; i++) {
|
1220
|
+
for (let j = minColumn; j <= maxColumn; j++) {
|
1221
|
+
const {
|
1222
|
+
cell
|
1223
|
+
} = map[i][j];
|
1224
|
+
const currentRow = cell.getParent();
|
1225
|
+
if (!$isTableRowNode(currentRow)) {
|
1226
|
+
throw Error(`Expected TableCellNode parent to be a TableRowNode`);
|
1227
|
+
}
|
1228
|
+
if (currentRow !== lastRow) {
|
1229
|
+
nodes.push(currentRow);
|
1230
|
+
}
|
1231
|
+
nodes.push(cell, ...$getChildrenRecursively(cell));
|
1232
|
+
lastRow = currentRow;
|
1233
|
+
}
|
1234
|
+
}
|
1235
|
+
if (!lexical.isCurrentlyReadOnlyMode()) {
|
1236
|
+
this._cachedNodes = nodes;
|
1237
|
+
}
|
1238
|
+
return nodes;
|
1239
|
+
}
|
1240
|
+
getTextContent() {
|
1241
|
+
const nodes = this.getNodes();
|
1242
|
+
let textContent = '';
|
1243
|
+
for (let i = 0; i < nodes.length; i++) {
|
1244
|
+
textContent += nodes[i].getTextContent();
|
1245
|
+
}
|
1246
|
+
return textContent;
|
1247
|
+
}
|
1248
|
+
}
|
1249
|
+
function $isTableSelection(x) {
|
1250
|
+
return x instanceof TableSelection;
|
1251
|
+
}
|
1252
|
+
function $createTableSelection() {
|
1253
|
+
const anchor = lexical.$createPoint('root', 0, 'element');
|
1254
|
+
const focus = lexical.$createPoint('root', 0, 'element');
|
1255
|
+
return new TableSelection('root', anchor, focus);
|
1256
|
+
}
|
1257
|
+
function $getChildrenRecursively(node) {
|
1258
|
+
const nodes = [];
|
1259
|
+
const stack = [node];
|
1260
|
+
while (stack.length > 0) {
|
1261
|
+
const currentNode = stack.pop();
|
1262
|
+
if (!(currentNode !== undefined)) {
|
1263
|
+
throw Error(`Stack.length > 0; can't be undefined`);
|
1264
|
+
}
|
1265
|
+
if (lexical.$isElementNode(currentNode)) {
|
1266
|
+
stack.unshift(...currentNode.getChildren());
|
1267
|
+
}
|
1268
|
+
if (currentNode !== node) {
|
1269
|
+
nodes.push(currentNode);
|
1270
|
+
}
|
1271
|
+
}
|
1272
|
+
return nodes;
|
1273
|
+
}
|
1274
|
+
|
1275
|
+
/**
|
1276
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
1277
|
+
*
|
1278
|
+
* This source code is licensed under the MIT license found in the
|
1279
|
+
* LICENSE file in the root directory of this source tree.
|
1280
|
+
*
|
1281
|
+
*/
|
1282
|
+
const getDOMSelection = targetWindow => CAN_USE_DOM ? (targetWindow || window).getSelection() : null;
|
1283
|
+
class TableObserver {
|
1284
|
+
constructor(editor, tableNodeKey) {
|
1285
|
+
this.isHighlightingCells = false;
|
1286
|
+
this.anchorX = -1;
|
1287
|
+
this.anchorY = -1;
|
1288
|
+
this.focusX = -1;
|
1289
|
+
this.focusY = -1;
|
1290
|
+
this.listenersToRemove = new Set();
|
1291
|
+
this.tableNodeKey = tableNodeKey;
|
1292
|
+
this.editor = editor;
|
1293
|
+
this.table = {
|
1294
|
+
columns: 0,
|
1295
|
+
domRows: [],
|
1296
|
+
rows: 0
|
1297
|
+
};
|
1298
|
+
this.tableSelection = null;
|
1299
|
+
this.anchorCellNodeKey = null;
|
1300
|
+
this.focusCellNodeKey = null;
|
1301
|
+
this.anchorCell = null;
|
1302
|
+
this.focusCell = null;
|
1303
|
+
this.hasHijackedSelectionStyles = false;
|
1304
|
+
this.trackTable();
|
1305
|
+
}
|
1306
|
+
getTable() {
|
1307
|
+
return this.table;
|
1308
|
+
}
|
1309
|
+
removeListeners() {
|
1310
|
+
Array.from(this.listenersToRemove).forEach(removeListener => removeListener());
|
1311
|
+
}
|
1312
|
+
trackTable() {
|
1313
|
+
const observer = new MutationObserver(records => {
|
1314
|
+
this.editor.update(() => {
|
1315
|
+
let gridNeedsRedraw = false;
|
1316
|
+
for (let i = 0; i < records.length; i++) {
|
1317
|
+
const record = records[i];
|
610
1318
|
const target = record.target;
|
611
1319
|
const nodeName = target.nodeName;
|
612
1320
|
if (nodeName === 'TABLE' || nodeName === 'TR') {
|
@@ -621,7 +1329,7 @@ class TableSelection {
|
|
621
1329
|
if (!tableElement) {
|
622
1330
|
throw new Error('Expected to find TableElement in DOM');
|
623
1331
|
}
|
624
|
-
this.
|
1332
|
+
this.table = getTable(tableElement);
|
625
1333
|
});
|
626
1334
|
});
|
627
1335
|
this.editor.update(() => {
|
@@ -629,7 +1337,7 @@ class TableSelection {
|
|
629
1337
|
if (!tableElement) {
|
630
1338
|
throw new Error('Expected to find TableElement in DOM');
|
631
1339
|
}
|
632
|
-
this.
|
1340
|
+
this.table = getTable(tableElement);
|
633
1341
|
observer.observe(tableElement, {
|
634
1342
|
childList: true,
|
635
1343
|
subtree: true
|
@@ -643,7 +1351,7 @@ class TableSelection {
|
|
643
1351
|
this.anchorY = -1;
|
644
1352
|
this.focusX = -1;
|
645
1353
|
this.focusY = -1;
|
646
|
-
this.
|
1354
|
+
this.tableSelection = null;
|
647
1355
|
this.anchorCellNodeKey = null;
|
648
1356
|
this.focusCellNodeKey = null;
|
649
1357
|
this.anchorCell = null;
|
@@ -659,7 +1367,7 @@ class TableSelection {
|
|
659
1367
|
if (!tableElement) {
|
660
1368
|
throw new Error('Expected to find TableElement in DOM');
|
661
1369
|
}
|
662
|
-
const grid =
|
1370
|
+
const grid = getTable(tableElement);
|
663
1371
|
$updateDOMForSelection(editor, grid, null);
|
664
1372
|
lexical.$setSelection(null);
|
665
1373
|
editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND, undefined);
|
@@ -688,18 +1396,18 @@ class TableSelection {
|
|
688
1396
|
this.hasHijackedSelectionStyles = true;
|
689
1397
|
});
|
690
1398
|
}
|
691
|
-
|
692
|
-
if (selection
|
1399
|
+
updateTableTableSelection(selection) {
|
1400
|
+
if (selection !== null && selection.tableKey === this.tableNodeKey) {
|
693
1401
|
const editor = this.editor;
|
694
|
-
this.
|
1402
|
+
this.tableSelection = selection;
|
695
1403
|
this.isHighlightingCells = true;
|
696
1404
|
this.disableHighlightStyle();
|
697
|
-
$updateDOMForSelection(editor, this.
|
1405
|
+
$updateDOMForSelection(editor, this.table, this.tableSelection);
|
698
1406
|
} else if (selection == null) {
|
699
1407
|
this.clearHighlight();
|
700
1408
|
} else {
|
701
|
-
this.tableNodeKey = selection.
|
702
|
-
this.
|
1409
|
+
this.tableNodeKey = selection.tableKey;
|
1410
|
+
this.updateTableTableSelection(selection);
|
703
1411
|
}
|
704
1412
|
}
|
705
1413
|
setFocusCellForSelection(cell, ignoreStart = false) {
|
@@ -733,14 +1441,14 @@ class TableSelection {
|
|
733
1441
|
this.focusY = cellY;
|
734
1442
|
if (this.isHighlightingCells) {
|
735
1443
|
const focusTableCellNode = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
736
|
-
if (this.
|
1444
|
+
if (this.tableSelection != null && this.anchorCellNodeKey != null && $isTableCellNode(focusTableCellNode)) {
|
737
1445
|
const focusNodeKey = focusTableCellNode.getKey();
|
738
|
-
this.
|
1446
|
+
this.tableSelection = this.tableSelection.clone() || $createTableSelection();
|
739
1447
|
this.focusCellNodeKey = focusNodeKey;
|
740
|
-
this.
|
741
|
-
lexical.$setSelection(this.
|
1448
|
+
this.tableSelection.set(this.tableNodeKey, this.anchorCellNodeKey, this.focusCellNodeKey);
|
1449
|
+
lexical.$setSelection(this.tableSelection);
|
742
1450
|
editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND, undefined);
|
743
|
-
$updateDOMForSelection(editor, this.
|
1451
|
+
$updateDOMForSelection(editor, this.table, this.tableSelection);
|
744
1452
|
}
|
745
1453
|
}
|
746
1454
|
});
|
@@ -754,7 +1462,7 @@ class TableSelection {
|
|
754
1462
|
const anchorTableCellNode = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
755
1463
|
if ($isTableCellNode(anchorTableCellNode)) {
|
756
1464
|
const anchorNodeKey = anchorTableCellNode.getKey();
|
757
|
-
this.
|
1465
|
+
this.tableSelection = this.tableSelection != null ? this.tableSelection.clone() : $createTableSelection();
|
758
1466
|
this.anchorCellNodeKey = anchorNodeKey;
|
759
1467
|
}
|
760
1468
|
});
|
@@ -762,7 +1470,7 @@ class TableSelection {
|
|
762
1470
|
formatCells(type) {
|
763
1471
|
this.editor.update(() => {
|
764
1472
|
const selection = lexical.$getSelection();
|
765
|
-
if (!$
|
1473
|
+
if (!$isTableSelection(selection)) {
|
766
1474
|
{
|
767
1475
|
throw Error(`Expected grid selection`);
|
768
1476
|
}
|
@@ -789,13 +1497,13 @@ class TableSelection {
|
|
789
1497
|
throw new Error('Expected TableNode.');
|
790
1498
|
}
|
791
1499
|
const selection = lexical.$getSelection();
|
792
|
-
if (!$
|
1500
|
+
if (!$isTableSelection(selection)) {
|
793
1501
|
{
|
794
1502
|
throw Error(`Expected grid selection`);
|
795
1503
|
}
|
796
1504
|
}
|
797
1505
|
const selectedNodes = selection.getNodes().filter($isTableCellNode);
|
798
|
-
if (selectedNodes.length === this.
|
1506
|
+
if (selectedNodes.length === this.table.columns * this.table.rows) {
|
799
1507
|
tableNode.selectPrevious();
|
800
1508
|
// Delete entire table
|
801
1509
|
tableNode.remove();
|
@@ -816,7 +1524,7 @@ class TableSelection {
|
|
816
1524
|
});
|
817
1525
|
}
|
818
1526
|
});
|
819
|
-
$updateDOMForSelection(editor, this.
|
1527
|
+
$updateDOMForSelection(editor, this.table, null);
|
820
1528
|
lexical.$setSelection(null);
|
821
1529
|
editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND, undefined);
|
822
1530
|
});
|
@@ -836,9 +1544,9 @@ function applyTableHandlers(tableNode, tableElement, editor, hasTabHandler) {
|
|
836
1544
|
if (rootElement === null) {
|
837
1545
|
throw new Error('No root element.');
|
838
1546
|
}
|
839
|
-
const
|
1547
|
+
const tableObserver = new TableObserver(editor, tableNode.getKey());
|
840
1548
|
const editorWindow = editor._window || window;
|
841
|
-
|
1549
|
+
attachTableObserverToTableElement(tableElement, tableObserver);
|
842
1550
|
tableElement.addEventListener('mousedown', event => {
|
843
1551
|
setTimeout(() => {
|
844
1552
|
if (event.button !== 0) {
|
@@ -847,20 +1555,20 @@ function applyTableHandlers(tableNode, tableElement, editor, hasTabHandler) {
|
|
847
1555
|
if (!editorWindow) {
|
848
1556
|
return;
|
849
1557
|
}
|
850
|
-
const anchorCell =
|
1558
|
+
const anchorCell = getDOMCellFromTarget(event.target);
|
851
1559
|
if (anchorCell !== null) {
|
852
1560
|
stopEvent(event);
|
853
|
-
|
1561
|
+
tableObserver.setAnchorCellForSelection(anchorCell);
|
854
1562
|
}
|
855
1563
|
const onMouseUp = () => {
|
856
1564
|
editorWindow.removeEventListener('mouseup', onMouseUp);
|
857
1565
|
editorWindow.removeEventListener('mousemove', onMouseMove);
|
858
1566
|
};
|
859
1567
|
const onMouseMove = moveEvent => {
|
860
|
-
const focusCell =
|
861
|
-
if (focusCell !== null && (
|
1568
|
+
const focusCell = getDOMCellFromTarget(moveEvent.target);
|
1569
|
+
if (focusCell !== null && (tableObserver.anchorX !== focusCell.x || tableObserver.anchorY !== focusCell.y)) {
|
862
1570
|
moveEvent.preventDefault();
|
863
|
-
|
1571
|
+
tableObserver.setFocusCellForSelection(focusCell);
|
864
1572
|
}
|
865
1573
|
};
|
866
1574
|
editorWindow.addEventListener('mouseup', onMouseUp);
|
@@ -873,1346 +1581,826 @@ function applyTableHandlers(tableNode, tableElement, editor, hasTabHandler) {
|
|
873
1581
|
if (event.button !== 0) {
|
874
1582
|
return;
|
875
1583
|
}
|
876
|
-
editor.update(() => {
|
877
|
-
const selection = lexical.$getSelection();
|
878
|
-
const target = event.target;
|
879
|
-
if ($
|
880
|
-
|
881
|
-
}
|
882
|
-
});
|
883
|
-
};
|
884
|
-
editorWindow.addEventListener('mousedown', mouseDownCallback);
|
885
|
-
tableSelection.listenersToRemove.add(() => editorWindow.removeEventListener('mousedown', mouseDownCallback));
|
886
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_DOWN_COMMAND, event => $handleArrowKey(editor, event, 'down', tableNode, tableSelection), lexical.COMMAND_PRIORITY_HIGH));
|
887
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_UP_COMMAND, event => $handleArrowKey(editor, event, 'up', tableNode, tableSelection), lexical.COMMAND_PRIORITY_HIGH));
|
888
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_LEFT_COMMAND, event => $handleArrowKey(editor, event, 'backward', tableNode, tableSelection), lexical.COMMAND_PRIORITY_HIGH));
|
889
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_RIGHT_COMMAND, event => $handleArrowKey(editor, event, 'forward', tableNode, tableSelection), lexical.COMMAND_PRIORITY_HIGH));
|
890
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_ESCAPE_COMMAND, event => {
|
891
|
-
const selection = lexical.$getSelection();
|
892
|
-
if ($isGridSelection(selection)) {
|
893
|
-
const focusCellNode = utils.$findMatchingParent(selection.focus.getNode(), $isTableCellNode);
|
894
|
-
if ($isTableCellNode(focusCellNode)) {
|
895
|
-
stopEvent(event);
|
896
|
-
focusCellNode.selectEnd();
|
897
|
-
return true;
|
898
|
-
}
|
899
|
-
}
|
900
|
-
return false;
|
901
|
-
}, lexical.COMMAND_PRIORITY_HIGH));
|
902
|
-
const deleteTextHandler = command => () => {
|
903
|
-
const selection = lexical.$getSelection();
|
904
|
-
if (!$isSelectionInTable(selection, tableNode)) {
|
905
|
-
return false;
|
906
|
-
}
|
907
|
-
if ($isGridSelection(selection)) {
|
908
|
-
tableSelection.clearText();
|
909
|
-
return true;
|
910
|
-
} else if (lexical.$isRangeSelection(selection)) {
|
911
|
-
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
912
|
-
if (!$isTableCellNode(tableCellNode)) {
|
913
|
-
return false;
|
914
|
-
}
|
915
|
-
const anchorNode = selection.anchor.getNode();
|
916
|
-
const focusNode = selection.focus.getNode();
|
917
|
-
const isAnchorInside = tableNode.isParentOf(anchorNode);
|
918
|
-
const isFocusInside = tableNode.isParentOf(focusNode);
|
919
|
-
const selectionContainsPartialTable = isAnchorInside && !isFocusInside || isFocusInside && !isAnchorInside;
|
920
|
-
if (selectionContainsPartialTable) {
|
921
|
-
tableSelection.clearText();
|
922
|
-
return true;
|
923
|
-
}
|
924
|
-
const nearestElementNode = utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
925
|
-
const topLevelCellElementNode = nearestElementNode && utils.$findMatchingParent(nearestElementNode, n => lexical.$isElementNode(n) && $isTableCellNode(n.getParent()));
|
926
|
-
if (!lexical.$isElementNode(topLevelCellElementNode) || !lexical.$isElementNode(nearestElementNode)) {
|
927
|
-
return false;
|
928
|
-
}
|
929
|
-
if (command === lexical.DELETE_LINE_COMMAND && topLevelCellElementNode.getPreviousSibling() === null) {
|
930
|
-
// TODO: Fix Delete Line in Table Cells.
|
931
|
-
return true;
|
932
|
-
}
|
933
|
-
if (command === lexical.DELETE_CHARACTER_COMMAND || command === lexical.DELETE_WORD_COMMAND) {
|
934
|
-
if (selection.isCollapsed() && selection.anchor.offset === 0) {
|
935
|
-
if (nearestElementNode !== topLevelCellElementNode) {
|
936
|
-
const children = nearestElementNode.getChildren();
|
937
|
-
const newParagraphNode = lexical.$createParagraphNode();
|
938
|
-
children.forEach(child => newParagraphNode.append(child));
|
939
|
-
nearestElementNode.replace(newParagraphNode);
|
940
|
-
nearestElementNode.getWritable().__parent = tableCellNode.getKey();
|
941
|
-
return true;
|
942
|
-
}
|
943
|
-
}
|
944
|
-
}
|
945
|
-
}
|
946
|
-
return false;
|
947
|
-
};
|
948
|
-
[lexical.DELETE_WORD_COMMAND, lexical.DELETE_LINE_COMMAND, lexical.DELETE_CHARACTER_COMMAND].forEach(command => {
|
949
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(command, deleteTextHandler(command), lexical.COMMAND_PRIORITY_CRITICAL));
|
950
|
-
});
|
951
|
-
const deleteCellHandler = event => {
|
952
|
-
const selection = lexical.$getSelection();
|
953
|
-
if (!$isSelectionInTable(selection, tableNode)) {
|
954
|
-
return false;
|
955
|
-
}
|
956
|
-
if ($isGridSelection(selection)) {
|
957
|
-
event.preventDefault();
|
958
|
-
event.stopPropagation();
|
959
|
-
tableSelection.clearText();
|
960
|
-
return true;
|
961
|
-
} else if (lexical.$isRangeSelection(selection)) {
|
962
|
-
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
963
|
-
if (!$isTableCellNode(tableCellNode)) {
|
964
|
-
return false;
|
1584
|
+
editor.update(() => {
|
1585
|
+
const selection = lexical.$getSelection();
|
1586
|
+
const target = event.target;
|
1587
|
+
if ($isTableSelection(selection) && selection.tableKey === tableObserver.tableNodeKey && rootElement.contains(target)) {
|
1588
|
+
tableObserver.clearHighlight();
|
965
1589
|
}
|
966
|
-
}
|
967
|
-
return false;
|
1590
|
+
});
|
968
1591
|
};
|
969
|
-
|
970
|
-
|
971
|
-
|
1592
|
+
editorWindow.addEventListener('mousedown', mouseDownCallback);
|
1593
|
+
tableObserver.listenersToRemove.add(() => editorWindow.removeEventListener('mousedown', mouseDownCallback));
|
1594
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_DOWN_COMMAND, event => $handleArrowKey(editor, event, 'down', tableNode, tableObserver), lexical.COMMAND_PRIORITY_HIGH));
|
1595
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_UP_COMMAND, event => $handleArrowKey(editor, event, 'up', tableNode, tableObserver), lexical.COMMAND_PRIORITY_HIGH));
|
1596
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_LEFT_COMMAND, event => $handleArrowKey(editor, event, 'backward', tableNode, tableObserver), lexical.COMMAND_PRIORITY_HIGH));
|
1597
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_ARROW_RIGHT_COMMAND, event => $handleArrowKey(editor, event, 'forward', tableNode, tableObserver), lexical.COMMAND_PRIORITY_HIGH));
|
1598
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_ESCAPE_COMMAND, event => {
|
972
1599
|
const selection = lexical.$getSelection();
|
973
|
-
if (
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
} else if (lexical.$isRangeSelection(selection)) {
|
980
|
-
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
981
|
-
if (!$isTableCellNode(tableCellNode)) {
|
982
|
-
return false;
|
1600
|
+
if ($isTableSelection(selection)) {
|
1601
|
+
const focusCellNode = utils.$findMatchingParent(selection.focus.getNode(), $isTableCellNode);
|
1602
|
+
if ($isTableCellNode(focusCellNode)) {
|
1603
|
+
stopEvent(event);
|
1604
|
+
focusCellNode.selectEnd();
|
1605
|
+
return true;
|
983
1606
|
}
|
984
1607
|
}
|
985
1608
|
return false;
|
986
|
-
}, lexical.
|
987
|
-
|
1609
|
+
}, lexical.COMMAND_PRIORITY_HIGH));
|
1610
|
+
const deleteTextHandler = command => () => {
|
988
1611
|
const selection = lexical.$getSelection();
|
989
1612
|
if (!$isSelectionInTable(selection, tableNode)) {
|
990
1613
|
return false;
|
991
1614
|
}
|
992
|
-
if ($
|
993
|
-
|
994
|
-
return
|
1615
|
+
if ($isTableSelection(selection)) {
|
1616
|
+
tableObserver.clearText();
|
1617
|
+
return true;
|
995
1618
|
} else if (lexical.$isRangeSelection(selection)) {
|
996
1619
|
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
997
1620
|
if (!$isTableCellNode(tableCellNode)) {
|
998
1621
|
return false;
|
999
1622
|
}
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
return
|
1008
|
-
}
|
1009
|
-
const tableCellNode = $findCellNode(selection.anchor.getNode());
|
1010
|
-
if (tableCellNode === null) {
|
1011
|
-
return false;
|
1012
|
-
}
|
1013
|
-
stopEvent(event);
|
1014
|
-
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
1015
|
-
selectGridNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, !event.shiftKey ? 'forward' : 'backward');
|
1016
|
-
return true;
|
1017
|
-
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
1018
|
-
}
|
1019
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.FOCUS_COMMAND, payload => {
|
1020
|
-
return tableNode.isSelected();
|
1021
|
-
}, lexical.COMMAND_PRIORITY_HIGH));
|
1022
|
-
function getCellFromCellNode(tableCellNode) {
|
1023
|
-
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
1024
|
-
return tableNode.getCellFromCordsOrThrow(currentCords.x, currentCords.y, tableSelection.grid);
|
1025
|
-
}
|
1026
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, selectionPayload => {
|
1027
|
-
const {
|
1028
|
-
nodes,
|
1029
|
-
selection
|
1030
|
-
} = selectionPayload;
|
1031
|
-
const isPointSelection = lexical.$INTERNAL_isPointSelection(selection);
|
1032
|
-
const isRangeSelection = lexical.$isRangeSelection(selection);
|
1033
|
-
const isSelectionInsideOfGrid = isRangeSelection && utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.DEPRECATED_$isGridCellNode(n)) !== null && utils.$findMatchingParent(selection.focus.getNode(), n => lexical.DEPRECATED_$isGridCellNode(n)) !== null || isPointSelection && !isRangeSelection;
|
1034
|
-
if (nodes.length !== 1 || !lexical.DEPRECATED_$isGridNode(nodes[0]) || !isSelectionInsideOfGrid) {
|
1035
|
-
return false;
|
1036
|
-
}
|
1037
|
-
const {
|
1038
|
-
anchor
|
1039
|
-
} = selection;
|
1040
|
-
const newGrid = nodes[0];
|
1041
|
-
const newGridRows = newGrid.getChildren();
|
1042
|
-
const newColumnCount = newGrid.getFirstChildOrThrow().getChildrenSize();
|
1043
|
-
const newRowCount = newGrid.getChildrenSize();
|
1044
|
-
const gridCellNode = utils.$findMatchingParent(anchor.getNode(), n => lexical.DEPRECATED_$isGridCellNode(n));
|
1045
|
-
const gridRowNode = gridCellNode && utils.$findMatchingParent(gridCellNode, n => lexical.DEPRECATED_$isGridRowNode(n));
|
1046
|
-
const gridNode = gridRowNode && utils.$findMatchingParent(gridRowNode, n => lexical.DEPRECATED_$isGridNode(n));
|
1047
|
-
if (!lexical.DEPRECATED_$isGridCellNode(gridCellNode) || !lexical.DEPRECATED_$isGridRowNode(gridRowNode) || !lexical.DEPRECATED_$isGridNode(gridNode)) {
|
1048
|
-
return false;
|
1049
|
-
}
|
1050
|
-
const startY = gridRowNode.getIndexWithinParent();
|
1051
|
-
const stopY = Math.min(gridNode.getChildrenSize() - 1, startY + newRowCount - 1);
|
1052
|
-
const startX = gridCellNode.getIndexWithinParent();
|
1053
|
-
const stopX = Math.min(gridRowNode.getChildrenSize() - 1, startX + newColumnCount - 1);
|
1054
|
-
const fromX = Math.min(startX, stopX);
|
1055
|
-
const fromY = Math.min(startY, stopY);
|
1056
|
-
const toX = Math.max(startX, stopX);
|
1057
|
-
const toY = Math.max(startY, stopY);
|
1058
|
-
const gridRowNodes = gridNode.getChildren();
|
1059
|
-
let newRowIdx = 0;
|
1060
|
-
let newAnchorCellKey;
|
1061
|
-
let newFocusCellKey;
|
1062
|
-
for (let r = fromY; r <= toY; r++) {
|
1063
|
-
const currentGridRowNode = gridRowNodes[r];
|
1064
|
-
if (!lexical.DEPRECATED_$isGridRowNode(currentGridRowNode)) {
|
1065
|
-
return false;
|
1066
|
-
}
|
1067
|
-
const newGridRowNode = newGridRows[newRowIdx];
|
1068
|
-
if (!lexical.DEPRECATED_$isGridRowNode(newGridRowNode)) {
|
1069
|
-
return false;
|
1070
|
-
}
|
1071
|
-
const gridCellNodes = currentGridRowNode.getChildren();
|
1072
|
-
const newGridCellNodes = newGridRowNode.getChildren();
|
1073
|
-
let newColumnIdx = 0;
|
1074
|
-
for (let c = fromX; c <= toX; c++) {
|
1075
|
-
const currentGridCellNode = gridCellNodes[c];
|
1076
|
-
if (!lexical.DEPRECATED_$isGridCellNode(currentGridCellNode)) {
|
1077
|
-
return false;
|
1078
|
-
}
|
1079
|
-
const newGridCellNode = newGridCellNodes[newColumnIdx];
|
1080
|
-
if (!lexical.DEPRECATED_$isGridCellNode(newGridCellNode)) {
|
1081
|
-
return false;
|
1082
|
-
}
|
1083
|
-
if (r === fromY && c === fromX) {
|
1084
|
-
newAnchorCellKey = currentGridCellNode.getKey();
|
1085
|
-
} else if (r === toY && c === toX) {
|
1086
|
-
newFocusCellKey = currentGridCellNode.getKey();
|
1087
|
-
}
|
1088
|
-
const originalChildren = currentGridCellNode.getChildren();
|
1089
|
-
newGridCellNode.getChildren().forEach(child => {
|
1090
|
-
if (lexical.$isTextNode(child)) {
|
1091
|
-
const paragraphNode = lexical.$createParagraphNode();
|
1092
|
-
paragraphNode.append(child);
|
1093
|
-
currentGridCellNode.append(child);
|
1094
|
-
} else {
|
1095
|
-
currentGridCellNode.append(child);
|
1096
|
-
}
|
1097
|
-
});
|
1098
|
-
originalChildren.forEach(n => n.remove());
|
1099
|
-
newColumnIdx++;
|
1100
|
-
}
|
1101
|
-
newRowIdx++;
|
1102
|
-
}
|
1103
|
-
if (newAnchorCellKey && newFocusCellKey) {
|
1104
|
-
const newGridSelection = $createGridSelection();
|
1105
|
-
newGridSelection.set(nodes[0].getKey(), newAnchorCellKey, newFocusCellKey);
|
1106
|
-
lexical.$setSelection(newGridSelection);
|
1107
|
-
}
|
1108
|
-
return true;
|
1109
|
-
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
1110
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.SELECTION_CHANGE_COMMAND, () => {
|
1111
|
-
const selection = lexical.$getSelection();
|
1112
|
-
const prevSelection = lexical.$getPreviousSelection();
|
1113
|
-
if (lexical.$isRangeSelection(selection)) {
|
1114
|
-
const {
|
1115
|
-
anchor,
|
1116
|
-
focus
|
1117
|
-
} = selection;
|
1118
|
-
const anchorNode = anchor.getNode();
|
1119
|
-
const focusNode = focus.getNode();
|
1120
|
-
// Using explicit comparison with table node to ensure it's not a nested table
|
1121
|
-
// as in that case we'll leave selection resolving to that table
|
1122
|
-
const anchorCellNode = $findCellNode(anchorNode);
|
1123
|
-
const focusCellNode = $findCellNode(focusNode);
|
1124
|
-
const isAnchorInside = anchorCellNode && tableNode.is($findTableNode(anchorCellNode));
|
1125
|
-
const isFocusInside = focusCellNode && tableNode.is($findTableNode(focusCellNode));
|
1126
|
-
const isPartialyWithinTable = isAnchorInside !== isFocusInside;
|
1127
|
-
const isWithinTable = isAnchorInside && isFocusInside;
|
1128
|
-
const isBackward = selection.isBackward();
|
1129
|
-
if (isPartialyWithinTable) {
|
1130
|
-
const newSelection = selection.clone();
|
1131
|
-
newSelection.focus.set(tableNode.getKey(), isBackward ? 0 : tableNode.getChildrenSize(), 'element');
|
1132
|
-
lexical.$setSelection(newSelection);
|
1133
|
-
$addHighlightStyleToTable(editor, tableSelection);
|
1134
|
-
} else if (isWithinTable) {
|
1135
|
-
// Handle case when selection spans across multiple cells but still
|
1136
|
-
// has range selection, then we convert it into grid selection
|
1137
|
-
if (!anchorCellNode.is(focusCellNode)) {
|
1138
|
-
tableSelection.setAnchorCellForSelection(getCellFromCellNode(anchorCellNode));
|
1139
|
-
tableSelection.setFocusCellForSelection(getCellFromCellNode(focusCellNode), true);
|
1140
|
-
}
|
1141
|
-
}
|
1142
|
-
}
|
1143
|
-
if (selection && !selection.is(prevSelection) && ($isGridSelection(selection) || $isGridSelection(prevSelection)) && tableSelection.gridSelection && !tableSelection.gridSelection.is(prevSelection)) {
|
1144
|
-
if ($isGridSelection(selection) && selection.gridKey === tableSelection.tableNodeKey) {
|
1145
|
-
tableSelection.updateTableGridSelection(selection);
|
1146
|
-
} else if (!$isGridSelection(selection) && $isGridSelection(prevSelection) && prevSelection.gridKey === tableSelection.tableNodeKey) {
|
1147
|
-
tableSelection.updateTableGridSelection(null);
|
1148
|
-
}
|
1149
|
-
return false;
|
1150
|
-
}
|
1151
|
-
if (tableSelection.hasHijackedSelectionStyles && !tableNode.isSelected()) {
|
1152
|
-
$removeHighlightStyleToTable(editor, tableSelection);
|
1153
|
-
} else if (!tableSelection.hasHijackedSelectionStyles && tableNode.isSelected()) {
|
1154
|
-
$addHighlightStyleToTable(editor, tableSelection);
|
1155
|
-
}
|
1156
|
-
return false;
|
1157
|
-
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
1158
|
-
return tableSelection;
|
1159
|
-
}
|
1160
|
-
function attachTableSelectionToTableElement(tableElement, tableSelection) {
|
1161
|
-
tableElement[LEXICAL_ELEMENT_KEY] = tableSelection;
|
1162
|
-
}
|
1163
|
-
function getTableSelectionFromTableElement(tableElement) {
|
1164
|
-
return tableElement[LEXICAL_ELEMENT_KEY];
|
1165
|
-
}
|
1166
|
-
function getCellFromTarget(node) {
|
1167
|
-
let currentNode = node;
|
1168
|
-
while (currentNode != null) {
|
1169
|
-
const nodeName = currentNode.nodeName;
|
1170
|
-
if (nodeName === 'TD' || nodeName === 'TH') {
|
1171
|
-
// @ts-expect-error: internal field
|
1172
|
-
const cell = currentNode._cell;
|
1173
|
-
if (cell === undefined) {
|
1174
|
-
return null;
|
1175
|
-
}
|
1176
|
-
return cell;
|
1177
|
-
}
|
1178
|
-
currentNode = currentNode.parentNode;
|
1179
|
-
}
|
1180
|
-
return null;
|
1181
|
-
}
|
1182
|
-
function getTableGrid(tableElement) {
|
1183
|
-
const cells = [];
|
1184
|
-
const grid = {
|
1185
|
-
cells,
|
1186
|
-
columns: 0,
|
1187
|
-
rows: 0
|
1188
|
-
};
|
1189
|
-
let currentNode = tableElement.firstChild;
|
1190
|
-
let x = 0;
|
1191
|
-
let y = 0;
|
1192
|
-
cells.length = 0;
|
1193
|
-
while (currentNode != null) {
|
1194
|
-
const nodeMame = currentNode.nodeName;
|
1195
|
-
if (nodeMame === 'TD' || nodeMame === 'TH') {
|
1196
|
-
const elem = currentNode;
|
1197
|
-
const cell = {
|
1198
|
-
elem,
|
1199
|
-
hasBackgroundColor: elem.style.backgroundColor !== '',
|
1200
|
-
highlighted: false,
|
1201
|
-
x,
|
1202
|
-
y
|
1203
|
-
};
|
1204
|
-
|
1205
|
-
// @ts-expect-error: internal field
|
1206
|
-
currentNode._cell = cell;
|
1207
|
-
let row = cells[y];
|
1208
|
-
if (row === undefined) {
|
1209
|
-
row = cells[y] = [];
|
1210
|
-
}
|
1211
|
-
row[x] = cell;
|
1212
|
-
} else {
|
1213
|
-
const child = currentNode.firstChild;
|
1214
|
-
if (child != null) {
|
1215
|
-
currentNode = child;
|
1216
|
-
continue;
|
1217
|
-
}
|
1218
|
-
}
|
1219
|
-
const sibling = currentNode.nextSibling;
|
1220
|
-
if (sibling != null) {
|
1221
|
-
x++;
|
1222
|
-
currentNode = sibling;
|
1223
|
-
continue;
|
1224
|
-
}
|
1225
|
-
const parent = currentNode.parentNode;
|
1226
|
-
if (parent != null) {
|
1227
|
-
const parentSibling = parent.nextSibling;
|
1228
|
-
if (parentSibling == null) {
|
1229
|
-
break;
|
1230
|
-
}
|
1231
|
-
y++;
|
1232
|
-
x = 0;
|
1233
|
-
currentNode = parentSibling;
|
1234
|
-
}
|
1235
|
-
}
|
1236
|
-
grid.columns = x + 1;
|
1237
|
-
grid.rows = y + 1;
|
1238
|
-
return grid;
|
1239
|
-
}
|
1240
|
-
function $updateDOMForSelection(editor, grid, selection) {
|
1241
|
-
const selectedCellNodes = new Set(selection ? selection.getNodes() : []);
|
1242
|
-
$forEachGridCell(grid, (cell, lexicalNode) => {
|
1243
|
-
const elem = cell.elem;
|
1244
|
-
if (selectedCellNodes.has(lexicalNode)) {
|
1245
|
-
cell.highlighted = true;
|
1246
|
-
$addHighlightToDOM(editor, cell);
|
1247
|
-
} else {
|
1248
|
-
cell.highlighted = false;
|
1249
|
-
$removeHighlightFromDOM(editor, cell);
|
1250
|
-
if (!elem.getAttribute('style')) {
|
1251
|
-
elem.removeAttribute('style');
|
1623
|
+
const anchorNode = selection.anchor.getNode();
|
1624
|
+
const focusNode = selection.focus.getNode();
|
1625
|
+
const isAnchorInside = tableNode.isParentOf(anchorNode);
|
1626
|
+
const isFocusInside = tableNode.isParentOf(focusNode);
|
1627
|
+
const selectionContainsPartialTable = isAnchorInside && !isFocusInside || isFocusInside && !isAnchorInside;
|
1628
|
+
if (selectionContainsPartialTable) {
|
1629
|
+
tableObserver.clearText();
|
1630
|
+
return true;
|
1252
1631
|
}
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
const {
|
1258
|
-
cells
|
1259
|
-
} = grid;
|
1260
|
-
for (let y = 0; y < cells.length; y++) {
|
1261
|
-
const row = cells[y];
|
1262
|
-
if (!row) {
|
1263
|
-
continue;
|
1264
|
-
}
|
1265
|
-
for (let x = 0; x < row.length; x++) {
|
1266
|
-
const cell = row[x];
|
1267
|
-
if (!cell) {
|
1268
|
-
continue;
|
1632
|
+
const nearestElementNode = utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
1633
|
+
const topLevelCellElementNode = nearestElementNode && utils.$findMatchingParent(nearestElementNode, n => lexical.$isElementNode(n) && $isTableCellNode(n.getParent()));
|
1634
|
+
if (!lexical.$isElementNode(topLevelCellElementNode) || !lexical.$isElementNode(nearestElementNode)) {
|
1635
|
+
return false;
|
1269
1636
|
}
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1637
|
+
if (command === lexical.DELETE_LINE_COMMAND && topLevelCellElementNode.getPreviousSibling() === null) {
|
1638
|
+
// TODO: Fix Delete Line in Table Cells.
|
1639
|
+
return true;
|
1640
|
+
}
|
1641
|
+
if (command === lexical.DELETE_CHARACTER_COMMAND || command === lexical.DELETE_WORD_COMMAND) {
|
1642
|
+
if (selection.isCollapsed() && selection.anchor.offset === 0) {
|
1643
|
+
if (nearestElementNode !== topLevelCellElementNode) {
|
1644
|
+
const children = nearestElementNode.getChildren();
|
1645
|
+
const newParagraphNode = lexical.$createParagraphNode();
|
1646
|
+
children.forEach(child => newParagraphNode.append(child));
|
1647
|
+
nearestElementNode.replace(newParagraphNode);
|
1648
|
+
nearestElementNode.getWritable().__parent = tableCellNode.getKey();
|
1649
|
+
return true;
|
1650
|
+
}
|
1651
|
+
}
|
1276
1652
|
}
|
1277
1653
|
}
|
1278
|
-
|
1279
|
-
}
|
1280
|
-
|
1281
|
-
|
1282
|
-
$forEachGridCell(tableSelection.grid, cell => {
|
1283
|
-
cell.highlighted = true;
|
1284
|
-
$addHighlightToDOM(editor, cell);
|
1654
|
+
return false;
|
1655
|
+
};
|
1656
|
+
[lexical.DELETE_WORD_COMMAND, lexical.DELETE_LINE_COMMAND, lexical.DELETE_CHARACTER_COMMAND].forEach(command => {
|
1657
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(command, deleteTextHandler(command), lexical.COMMAND_PRIORITY_CRITICAL));
|
1285
1658
|
});
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
const elem = cell.elem;
|
1291
|
-
cell.highlighted = false;
|
1292
|
-
$removeHighlightFromDOM(editor, cell);
|
1293
|
-
if (!elem.getAttribute('style')) {
|
1294
|
-
elem.removeAttribute('style');
|
1659
|
+
const deleteCellHandler = event => {
|
1660
|
+
const selection = lexical.$getSelection();
|
1661
|
+
if (!$isSelectionInTable(selection, tableNode)) {
|
1662
|
+
return false;
|
1295
1663
|
}
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
switch (direction) {
|
1301
|
-
case 'backward':
|
1302
|
-
case 'forward':
|
1303
|
-
if (x !== (isForward ? tableSelection.grid.columns - 1 : 0)) {
|
1304
|
-
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x + (isForward ? 1 : -1), y, tableSelection.grid), isForward);
|
1305
|
-
} else {
|
1306
|
-
if (y !== (isForward ? tableSelection.grid.rows - 1 : 0)) {
|
1307
|
-
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(isForward ? 0 : tableSelection.grid.columns - 1, y + (isForward ? 1 : -1), tableSelection.grid), isForward);
|
1308
|
-
} else if (!isForward) {
|
1309
|
-
tableNode.selectPrevious();
|
1310
|
-
} else {
|
1311
|
-
tableNode.selectNext();
|
1312
|
-
}
|
1313
|
-
}
|
1664
|
+
if ($isTableSelection(selection)) {
|
1665
|
+
event.preventDefault();
|
1666
|
+
event.stopPropagation();
|
1667
|
+
tableObserver.clearText();
|
1314
1668
|
return true;
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
tableNode.selectPrevious();
|
1669
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
1670
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
1671
|
+
if (!$isTableCellNode(tableCellNode)) {
|
1672
|
+
return false;
|
1320
1673
|
}
|
1674
|
+
}
|
1675
|
+
return false;
|
1676
|
+
};
|
1677
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_BACKSPACE_COMMAND, deleteCellHandler, lexical.COMMAND_PRIORITY_CRITICAL));
|
1678
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_DELETE_COMMAND, deleteCellHandler, lexical.COMMAND_PRIORITY_CRITICAL));
|
1679
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.FORMAT_TEXT_COMMAND, payload => {
|
1680
|
+
const selection = lexical.$getSelection();
|
1681
|
+
if (!$isSelectionInTable(selection, tableNode)) {
|
1682
|
+
return false;
|
1683
|
+
}
|
1684
|
+
if ($isTableSelection(selection)) {
|
1685
|
+
tableObserver.formatCells(payload);
|
1321
1686
|
return true;
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
tableNode.selectNext();
|
1687
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
1688
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
1689
|
+
if (!$isTableCellNode(tableCellNode)) {
|
1690
|
+
return false;
|
1327
1691
|
}
|
1328
|
-
|
1329
|
-
|
1692
|
+
}
|
1693
|
+
return false;
|
1694
|
+
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
1695
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.CONTROLLED_TEXT_INSERTION_COMMAND, payload => {
|
1696
|
+
const selection = lexical.$getSelection();
|
1697
|
+
if (!$isSelectionInTable(selection, tableNode)) {
|
1330
1698
|
return false;
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
tableSelection.setFocusCellForSelection(tableNode.getCellFromCordsOrThrow(x + (isForward ? 1 : -1), y, tableSelection.grid));
|
1699
|
+
}
|
1700
|
+
if ($isTableSelection(selection)) {
|
1701
|
+
tableObserver.clearHighlight();
|
1702
|
+
return false;
|
1703
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
1704
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
1705
|
+
if (!$isTableCellNode(tableCellNode)) {
|
1706
|
+
return false;
|
1340
1707
|
}
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1708
|
+
}
|
1709
|
+
return false;
|
1710
|
+
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
1711
|
+
if (hasTabHandler) {
|
1712
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.KEY_TAB_COMMAND, event => {
|
1713
|
+
const selection = lexical.$getSelection();
|
1714
|
+
if (!lexical.$isRangeSelection(selection) || !selection.isCollapsed() || !$isSelectionInTable(selection, tableNode)) {
|
1347
1715
|
return false;
|
1348
1716
|
}
|
1349
|
-
|
1350
|
-
if (
|
1351
|
-
tableSelection.setFocusCellForSelection(tableNode.getCellFromCordsOrThrow(x, y + 1, tableSelection.grid));
|
1352
|
-
return true;
|
1353
|
-
} else {
|
1717
|
+
const tableCellNode = $findCellNode(selection.anchor.getNode());
|
1718
|
+
if (tableCellNode === null) {
|
1354
1719
|
return false;
|
1355
1720
|
}
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
if (lexical.$isRangeSelection(selection) || $isGridSelection(selection)) {
|
1362
|
-
const isAnchorInside = tableNode.isParentOf(selection.anchor.getNode());
|
1363
|
-
const isFocusInside = tableNode.isParentOf(selection.focus.getNode());
|
1364
|
-
return isAnchorInside && isFocusInside;
|
1365
|
-
}
|
1366
|
-
return false;
|
1367
|
-
}
|
1368
|
-
function selectTableCellNode(tableCell, fromStart) {
|
1369
|
-
if (fromStart) {
|
1370
|
-
tableCell.selectStart();
|
1371
|
-
} else {
|
1372
|
-
tableCell.selectEnd();
|
1373
|
-
}
|
1374
|
-
}
|
1375
|
-
const BROWSER_BLUE_RGB = '172,206,247';
|
1376
|
-
function $addHighlightToDOM(editor, cell) {
|
1377
|
-
const element = cell.elem;
|
1378
|
-
const node = lexical.$getNearestNodeFromDOMNode(element);
|
1379
|
-
if (!$isTableCellNode(node)) {
|
1380
|
-
throw Error(`Expected to find LexicalNode from Table Cell DOMNode`);
|
1381
|
-
}
|
1382
|
-
const backgroundColor = node.getBackgroundColor();
|
1383
|
-
if (backgroundColor === null) {
|
1384
|
-
element.style.setProperty('background-color', `rgb(${BROWSER_BLUE_RGB})`);
|
1385
|
-
} else {
|
1386
|
-
element.style.setProperty('background-image', `linear-gradient(to right, rgba(${BROWSER_BLUE_RGB},0.85), rgba(${BROWSER_BLUE_RGB},0.85))`);
|
1387
|
-
}
|
1388
|
-
element.style.setProperty('caret-color', 'transparent');
|
1389
|
-
}
|
1390
|
-
function $removeHighlightFromDOM(editor, cell) {
|
1391
|
-
const element = cell.elem;
|
1392
|
-
const node = lexical.$getNearestNodeFromDOMNode(element);
|
1393
|
-
if (!$isTableCellNode(node)) {
|
1394
|
-
throw Error(`Expected to find LexicalNode from Table Cell DOMNode`);
|
1395
|
-
}
|
1396
|
-
const backgroundColor = node.getBackgroundColor();
|
1397
|
-
if (backgroundColor === null) {
|
1398
|
-
element.style.removeProperty('background-color');
|
1721
|
+
stopEvent(event);
|
1722
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableObserver.table);
|
1723
|
+
selectTableNodeInDirection(tableObserver, tableNode, currentCords.x, currentCords.y, !event.shiftKey ? 'forward' : 'backward');
|
1724
|
+
return true;
|
1725
|
+
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
1399
1726
|
}
|
1400
|
-
|
1401
|
-
|
1402
|
-
}
|
1403
|
-
function
|
1404
|
-
|
1405
|
-
|
1406
|
-
}
|
1407
|
-
function $findTableNode(node) {
|
1408
|
-
const tableNode = utils.$findMatchingParent(node, $isTableNode);
|
1409
|
-
return $isTableNode(tableNode) ? tableNode : null;
|
1410
|
-
}
|
1411
|
-
function $handleArrowKey(editor, event, direction, tableNode, tableSelection) {
|
1412
|
-
const selection = lexical.$getSelection();
|
1413
|
-
if (!$isSelectionInTable(selection, tableNode)) {
|
1414
|
-
return false;
|
1727
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.FOCUS_COMMAND, payload => {
|
1728
|
+
return tableNode.isSelected();
|
1729
|
+
}, lexical.COMMAND_PRIORITY_HIGH));
|
1730
|
+
function getObserverCellFromCellNode(tableCellNode) {
|
1731
|
+
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableObserver.table);
|
1732
|
+
return tableNode.getDOMCellFromCordsOrThrow(currentCords.x, currentCords.y, tableObserver.table);
|
1415
1733
|
}
|
1416
|
-
|
1417
|
-
// Horizontal move between cels seem to work well without interruption
|
1418
|
-
// so just exit early, and handle vertical moves
|
1419
|
-
if (direction === 'backward' || direction === 'forward') {
|
1420
|
-
return false;
|
1421
|
-
}
|
1734
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, selectionPayload => {
|
1422
1735
|
const {
|
1423
|
-
|
1424
|
-
|
1425
|
-
} =
|
1426
|
-
const
|
1427
|
-
const
|
1428
|
-
|
1736
|
+
nodes,
|
1737
|
+
selection
|
1738
|
+
} = selectionPayload;
|
1739
|
+
const anchorAndFocus = selection.getStartEndPoints();
|
1740
|
+
const isTableSelection = $isTableSelection(selection);
|
1741
|
+
const isRangeSelection = lexical.$isRangeSelection(selection);
|
1742
|
+
const isSelectionInsideOfGrid = isRangeSelection && utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n)) !== null && utils.$findMatchingParent(selection.focus.getNode(), n => $isTableCellNode(n)) !== null || isTableSelection;
|
1743
|
+
if (nodes.length !== 1 || !$isTableNode(nodes[0]) || !isSelectionInsideOfGrid || anchorAndFocus === null) {
|
1429
1744
|
return false;
|
1430
1745
|
}
|
1431
|
-
const
|
1432
|
-
|
1433
|
-
|
1434
|
-
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1440
|
-
const anchorDOM = editor.getElementByKey(anchor.key);
|
1441
|
-
if (anchorDOM == null || anchorCellDom == null) {
|
1746
|
+
const [anchor] = anchorAndFocus;
|
1747
|
+
const newGrid = nodes[0];
|
1748
|
+
const newGridRows = newGrid.getChildren();
|
1749
|
+
const newColumnCount = newGrid.getFirstChildOrThrow().getChildrenSize();
|
1750
|
+
const newRowCount = newGrid.getChildrenSize();
|
1751
|
+
const gridCellNode = utils.$findMatchingParent(anchor.getNode(), n => $isTableCellNode(n));
|
1752
|
+
const gridRowNode = gridCellNode && utils.$findMatchingParent(gridCellNode, n => $isTableRowNode(n));
|
1753
|
+
const gridNode = gridRowNode && utils.$findMatchingParent(gridRowNode, n => $isTableNode(n));
|
1754
|
+
if (!$isTableCellNode(gridCellNode) || !$isTableRowNode(gridRowNode) || !$isTableNode(gridNode)) {
|
1442
1755
|
return false;
|
1443
1756
|
}
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1757
|
+
const startY = gridRowNode.getIndexWithinParent();
|
1758
|
+
const stopY = Math.min(gridNode.getChildrenSize() - 1, startY + newRowCount - 1);
|
1759
|
+
const startX = gridCellNode.getIndexWithinParent();
|
1760
|
+
const stopX = Math.min(gridRowNode.getChildrenSize() - 1, startX + newColumnCount - 1);
|
1761
|
+
const fromX = Math.min(startX, stopX);
|
1762
|
+
const fromY = Math.min(startY, stopY);
|
1763
|
+
const toX = Math.max(startX, stopX);
|
1764
|
+
const toY = Math.max(startY, stopY);
|
1765
|
+
const gridRowNodes = gridNode.getChildren();
|
1766
|
+
let newRowIdx = 0;
|
1767
|
+
let newAnchorCellKey;
|
1768
|
+
let newFocusCellKey;
|
1769
|
+
for (let r = fromY; r <= toY; r++) {
|
1770
|
+
const currentGridRowNode = gridRowNodes[r];
|
1771
|
+
if (!$isTableRowNode(currentGridRowNode)) {
|
1450
1772
|
return false;
|
1451
1773
|
}
|
1452
|
-
const
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1774
|
+
const newGridRowNode = newGridRows[newRowIdx];
|
1775
|
+
if (!$isTableRowNode(newGridRowNode)) {
|
1776
|
+
return false;
|
1777
|
+
}
|
1778
|
+
const gridCellNodes = currentGridRowNode.getChildren();
|
1779
|
+
const newGridCellNodes = newGridRowNode.getChildren();
|
1780
|
+
let newColumnIdx = 0;
|
1781
|
+
for (let c = fromX; c <= toX; c++) {
|
1782
|
+
const currentGridCellNode = gridCellNodes[c];
|
1783
|
+
if (!$isTableCellNode(currentGridCellNode)) {
|
1784
|
+
return false;
|
1785
|
+
}
|
1786
|
+
const newGridCellNode = newGridCellNodes[newColumnIdx];
|
1787
|
+
if (!$isTableCellNode(newGridCellNode)) {
|
1788
|
+
return false;
|
1789
|
+
}
|
1790
|
+
if (r === fromY && c === fromX) {
|
1791
|
+
newAnchorCellKey = currentGridCellNode.getKey();
|
1792
|
+
} else if (r === toY && c === toX) {
|
1793
|
+
newFocusCellKey = currentGridCellNode.getKey();
|
1794
|
+
}
|
1795
|
+
const originalChildren = currentGridCellNode.getChildren();
|
1796
|
+
newGridCellNode.getChildren().forEach(child => {
|
1797
|
+
if (lexical.$isTextNode(child)) {
|
1798
|
+
const paragraphNode = lexical.$createParagraphNode();
|
1799
|
+
paragraphNode.append(child);
|
1800
|
+
currentGridCellNode.append(child);
|
1801
|
+
} else {
|
1802
|
+
currentGridCellNode.append(child);
|
1803
|
+
}
|
1804
|
+
});
|
1805
|
+
originalChildren.forEach(n => n.remove());
|
1806
|
+
newColumnIdx++;
|
1807
|
+
}
|
1808
|
+
newRowIdx++;
|
1458
1809
|
}
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1810
|
+
if (newAnchorCellKey && newFocusCellKey) {
|
1811
|
+
const newTableSelection = $createTableSelection();
|
1812
|
+
newTableSelection.set(nodes[0].getKey(), newAnchorCellKey, newFocusCellKey);
|
1813
|
+
lexical.$setSelection(newTableSelection);
|
1462
1814
|
}
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
}
|
1473
|
-
|
1815
|
+
return true;
|
1816
|
+
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
1817
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.SELECTION_CHANGE_COMMAND, () => {
|
1818
|
+
const selection = lexical.$getSelection();
|
1819
|
+
const prevSelection = lexical.$getPreviousSelection();
|
1820
|
+
if (lexical.$isRangeSelection(selection)) {
|
1821
|
+
const {
|
1822
|
+
anchor,
|
1823
|
+
focus
|
1824
|
+
} = selection;
|
1825
|
+
const anchorNode = anchor.getNode();
|
1826
|
+
const focusNode = focus.getNode();
|
1827
|
+
// Using explicit comparison with table node to ensure it's not a nested table
|
1828
|
+
// as in that case we'll leave selection resolving to that table
|
1829
|
+
const anchorCellNode = $findCellNode(anchorNode);
|
1830
|
+
const focusCellNode = $findCellNode(focusNode);
|
1831
|
+
const isAnchorInside = anchorCellNode && tableNode.is($findTableNode(anchorCellNode));
|
1832
|
+
const isFocusInside = focusCellNode && tableNode.is($findTableNode(focusCellNode));
|
1833
|
+
const isPartialyWithinTable = isAnchorInside !== isFocusInside;
|
1834
|
+
const isWithinTable = isAnchorInside && isFocusInside;
|
1835
|
+
const isBackward = selection.isBackward();
|
1836
|
+
if (isPartialyWithinTable) {
|
1837
|
+
const newSelection = selection.clone();
|
1838
|
+
newSelection.focus.set(tableNode.getKey(), isBackward ? 0 : tableNode.getChildrenSize(), 'element');
|
1839
|
+
lexical.$setSelection(newSelection);
|
1840
|
+
$addHighlightStyleToTable(editor, tableObserver);
|
1841
|
+
} else if (isWithinTable) {
|
1842
|
+
// Handle case when selection spans across multiple cells but still
|
1843
|
+
// has range selection, then we convert it into grid selection
|
1844
|
+
if (!anchorCellNode.is(focusCellNode)) {
|
1845
|
+
tableObserver.setAnchorCellForSelection(getObserverCellFromCellNode(anchorCellNode));
|
1846
|
+
tableObserver.setFocusCellForSelection(getObserverCellFromCellNode(focusCellNode), true);
|
1847
|
+
}
|
1474
1848
|
}
|
1475
|
-
return true;
|
1476
1849
|
}
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
const focusCellNode = utils.$findMatchingParent(focus.getNode(), $isTableCellNode);
|
1484
|
-
const [tableNodeFromSelection] = selection.getNodes();
|
1485
|
-
const tableElement = editor.getElementByKey(tableNodeFromSelection.getKey());
|
1486
|
-
if (!$isTableCellNode(anchorCellNode) || !$isTableCellNode(focusCellNode) || !$isTableNode(tableNodeFromSelection) || tableElement == null) {
|
1850
|
+
if (selection && !selection.is(prevSelection) && ($isTableSelection(selection) || $isTableSelection(prevSelection)) && tableObserver.tableSelection && !tableObserver.tableSelection.is(prevSelection)) {
|
1851
|
+
if ($isTableSelection(selection) && selection.tableKey === tableObserver.tableNodeKey) {
|
1852
|
+
tableObserver.updateTableTableSelection(selection);
|
1853
|
+
} else if (!$isTableSelection(selection) && $isTableSelection(prevSelection) && prevSelection.tableKey === tableObserver.tableNodeKey) {
|
1854
|
+
tableObserver.updateTableTableSelection(null);
|
1855
|
+
}
|
1487
1856
|
return false;
|
1488
1857
|
}
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
tableSelection.setAnchorCellForSelection(anchorCell);
|
1494
|
-
stopEvent(event);
|
1495
|
-
if (event.shiftKey) {
|
1496
|
-
const cords = tableNode.getCordsFromCellNode(focusCellNode, grid);
|
1497
|
-
return adjustFocusNodeInDirection(tableSelection, tableNodeFromSelection, cords.x, cords.y, direction);
|
1498
|
-
} else {
|
1499
|
-
focusCellNode.selectEnd();
|
1858
|
+
if (tableObserver.hasHijackedSelectionStyles && !tableNode.isSelected()) {
|
1859
|
+
$removeHighlightStyleToTable(editor, tableObserver);
|
1860
|
+
} else if (!tableObserver.hasHijackedSelectionStyles && tableNode.isSelected()) {
|
1861
|
+
$addHighlightStyleToTable(editor, tableObserver);
|
1500
1862
|
}
|
1501
|
-
return
|
1502
|
-
}
|
1503
|
-
return
|
1863
|
+
return false;
|
1864
|
+
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
1865
|
+
return tableObserver;
|
1504
1866
|
}
|
1505
|
-
function
|
1506
|
-
|
1507
|
-
event.stopImmediatePropagation();
|
1508
|
-
event.stopPropagation();
|
1867
|
+
function attachTableObserverToTableElement(tableElement, tableObserver) {
|
1868
|
+
tableElement[LEXICAL_ELEMENT_KEY] = tableObserver;
|
1509
1869
|
}
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
static getType() {
|
1523
|
-
return 'table';
|
1524
|
-
}
|
1525
|
-
static clone(node) {
|
1526
|
-
return new TableNode(node.__key);
|
1527
|
-
}
|
1528
|
-
static importDOM() {
|
1529
|
-
return {
|
1530
|
-
table: _node => ({
|
1531
|
-
conversion: convertTableElement,
|
1532
|
-
priority: 1
|
1533
|
-
})
|
1534
|
-
};
|
1535
|
-
}
|
1536
|
-
static importJSON(_serializedNode) {
|
1537
|
-
return $createTableNode();
|
1538
|
-
}
|
1539
|
-
constructor(key) {
|
1540
|
-
super(key);
|
1541
|
-
}
|
1542
|
-
exportJSON() {
|
1543
|
-
return {
|
1544
|
-
...super.exportJSON(),
|
1545
|
-
type: 'table',
|
1546
|
-
version: 1
|
1547
|
-
};
|
1548
|
-
}
|
1549
|
-
createDOM(config, editor) {
|
1550
|
-
const tableElement = document.createElement('table');
|
1551
|
-
utils.addClassNamesToElement(tableElement, config.theme.table);
|
1552
|
-
return tableElement;
|
1553
|
-
}
|
1554
|
-
updateDOM() {
|
1555
|
-
return false;
|
1556
|
-
}
|
1557
|
-
exportDOM(editor) {
|
1558
|
-
return {
|
1559
|
-
...super.exportDOM(editor),
|
1560
|
-
after: tableElement => {
|
1561
|
-
if (tableElement) {
|
1562
|
-
const newElement = tableElement.cloneNode();
|
1563
|
-
const colGroup = document.createElement('colgroup');
|
1564
|
-
const tBody = document.createElement('tbody');
|
1565
|
-
if (utils.isHTMLElement(tableElement)) {
|
1566
|
-
tBody.append(...tableElement.children);
|
1567
|
-
}
|
1568
|
-
const firstRow = this.getFirstChildOrThrow();
|
1569
|
-
if (!$isTableRowNode(firstRow)) {
|
1570
|
-
throw new Error('Expected to find row node.');
|
1571
|
-
}
|
1572
|
-
const colCount = firstRow.getChildrenSize();
|
1573
|
-
for (let i = 0; i < colCount; i++) {
|
1574
|
-
const col = document.createElement('col');
|
1575
|
-
colGroup.append(col);
|
1576
|
-
}
|
1577
|
-
newElement.replaceChildren(colGroup, tBody);
|
1578
|
-
return newElement;
|
1579
|
-
}
|
1870
|
+
function getTableObserverFromTableElement(tableElement) {
|
1871
|
+
return tableElement[LEXICAL_ELEMENT_KEY];
|
1872
|
+
}
|
1873
|
+
function getDOMCellFromTarget(node) {
|
1874
|
+
let currentNode = node;
|
1875
|
+
while (currentNode != null) {
|
1876
|
+
const nodeName = currentNode.nodeName;
|
1877
|
+
if (nodeName === 'TD' || nodeName === 'TH') {
|
1878
|
+
// @ts-expect-error: internal field
|
1879
|
+
const cell = currentNode._cell;
|
1880
|
+
if (cell === undefined) {
|
1881
|
+
return null;
|
1580
1882
|
}
|
1581
|
-
|
1883
|
+
return cell;
|
1884
|
+
}
|
1885
|
+
currentNode = currentNode.parentNode;
|
1582
1886
|
}
|
1887
|
+
return null;
|
1888
|
+
}
|
1889
|
+
function getTable(tableElement) {
|
1890
|
+
const domRows = [];
|
1891
|
+
const grid = {
|
1892
|
+
columns: 0,
|
1893
|
+
domRows,
|
1894
|
+
rows: 0
|
1895
|
+
};
|
1896
|
+
let currentNode = tableElement.firstChild;
|
1897
|
+
let x = 0;
|
1898
|
+
let y = 0;
|
1899
|
+
domRows.length = 0;
|
1900
|
+
while (currentNode != null) {
|
1901
|
+
const nodeMame = currentNode.nodeName;
|
1902
|
+
if (nodeMame === 'TD' || nodeMame === 'TH') {
|
1903
|
+
const elem = currentNode;
|
1904
|
+
const cell = {
|
1905
|
+
elem,
|
1906
|
+
hasBackgroundColor: elem.style.backgroundColor !== '',
|
1907
|
+
highlighted: false,
|
1908
|
+
x,
|
1909
|
+
y
|
1910
|
+
};
|
1583
1911
|
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
return false;
|
1590
|
-
}
|
1591
|
-
isShadowRoot() {
|
1592
|
-
return true;
|
1593
|
-
}
|
1594
|
-
getCordsFromCellNode(tableCellNode, grid) {
|
1595
|
-
const {
|
1596
|
-
rows,
|
1597
|
-
cells
|
1598
|
-
} = grid;
|
1599
|
-
for (let y = 0; y < rows; y++) {
|
1600
|
-
const row = cells[y];
|
1601
|
-
if (row == null) {
|
1602
|
-
continue;
|
1912
|
+
// @ts-expect-error: internal field
|
1913
|
+
currentNode._cell = cell;
|
1914
|
+
let row = domRows[y];
|
1915
|
+
if (row === undefined) {
|
1916
|
+
row = domRows[y] = [];
|
1603
1917
|
}
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
|
1610
|
-
return cellNode === tableCellNode;
|
1611
|
-
});
|
1612
|
-
if (x !== -1) {
|
1613
|
-
return {
|
1614
|
-
x,
|
1615
|
-
y
|
1616
|
-
};
|
1918
|
+
row[x] = cell;
|
1919
|
+
} else {
|
1920
|
+
const child = currentNode.firstChild;
|
1921
|
+
if (child != null) {
|
1922
|
+
currentNode = child;
|
1923
|
+
continue;
|
1617
1924
|
}
|
1618
1925
|
}
|
1619
|
-
|
1620
|
-
|
1621
|
-
|
1622
|
-
|
1623
|
-
|
1624
|
-
} = grid;
|
1625
|
-
const row = cells[y];
|
1626
|
-
if (row == null) {
|
1627
|
-
return null;
|
1628
|
-
}
|
1629
|
-
const cell = row[x];
|
1630
|
-
if (cell == null) {
|
1631
|
-
return null;
|
1926
|
+
const sibling = currentNode.nextSibling;
|
1927
|
+
if (sibling != null) {
|
1928
|
+
x++;
|
1929
|
+
currentNode = sibling;
|
1930
|
+
continue;
|
1632
1931
|
}
|
1633
|
-
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
1637
|
-
|
1638
|
-
|
1932
|
+
const parent = currentNode.parentNode;
|
1933
|
+
if (parent != null) {
|
1934
|
+
const parentSibling = parent.nextSibling;
|
1935
|
+
if (parentSibling == null) {
|
1936
|
+
break;
|
1937
|
+
}
|
1938
|
+
y++;
|
1939
|
+
x = 0;
|
1940
|
+
currentNode = parentSibling;
|
1639
1941
|
}
|
1640
|
-
return cell;
|
1641
1942
|
}
|
1642
|
-
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1943
|
+
grid.columns = x + 1;
|
1944
|
+
grid.rows = y + 1;
|
1945
|
+
return grid;
|
1946
|
+
}
|
1947
|
+
function $updateDOMForSelection(editor, table, selection) {
|
1948
|
+
const selectedCellNodes = new Set(selection ? selection.getNodes() : []);
|
1949
|
+
$forEachTableCell(table, (cell, lexicalNode) => {
|
1950
|
+
const elem = cell.elem;
|
1951
|
+
if (selectedCellNodes.has(lexicalNode)) {
|
1952
|
+
cell.highlighted = true;
|
1953
|
+
$addHighlightToDOM(editor, cell);
|
1954
|
+
} else {
|
1955
|
+
cell.highlighted = false;
|
1956
|
+
$removeHighlightFromDOM(editor, cell);
|
1957
|
+
if (!elem.getAttribute('style')) {
|
1958
|
+
elem.removeAttribute('style');
|
1959
|
+
}
|
1646
1960
|
}
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1961
|
+
});
|
1962
|
+
}
|
1963
|
+
function $forEachTableCell(grid, cb) {
|
1964
|
+
const {
|
1965
|
+
domRows
|
1966
|
+
} = grid;
|
1967
|
+
for (let y = 0; y < domRows.length; y++) {
|
1968
|
+
const row = domRows[y];
|
1969
|
+
if (!row) {
|
1970
|
+
continue;
|
1650
1971
|
}
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
1656
|
-
|
1972
|
+
for (let x = 0; x < row.length; x++) {
|
1973
|
+
const cell = row[x];
|
1974
|
+
if (!cell) {
|
1975
|
+
continue;
|
1976
|
+
}
|
1977
|
+
const lexicalNode = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
1978
|
+
if (lexicalNode !== null) {
|
1979
|
+
cb(cell, lexicalNode, {
|
1980
|
+
x,
|
1981
|
+
y
|
1982
|
+
});
|
1983
|
+
}
|
1657
1984
|
}
|
1658
|
-
return node;
|
1659
|
-
}
|
1660
|
-
canSelectBefore() {
|
1661
|
-
return true;
|
1662
|
-
}
|
1663
|
-
canIndent() {
|
1664
|
-
return false;
|
1665
1985
|
}
|
1666
1986
|
}
|
1667
|
-
function $
|
1668
|
-
|
1669
|
-
|
1670
|
-
|
1671
|
-
|
1672
|
-
|
1673
|
-
}
|
1674
|
-
function convertTableElement(_domNode) {
|
1675
|
-
return {
|
1676
|
-
node: $createTableNode()
|
1677
|
-
};
|
1678
|
-
}
|
1679
|
-
function $createTableNode() {
|
1680
|
-
return lexical.$applyNodeReplacement(new TableNode());
|
1987
|
+
function $addHighlightStyleToTable(editor, tableSelection) {
|
1988
|
+
tableSelection.disableHighlightStyle();
|
1989
|
+
$forEachTableCell(tableSelection.table, cell => {
|
1990
|
+
cell.highlighted = true;
|
1991
|
+
$addHighlightToDOM(editor, cell);
|
1992
|
+
});
|
1681
1993
|
}
|
1682
|
-
function $
|
1683
|
-
|
1994
|
+
function $removeHighlightStyleToTable(editor, tableObserver) {
|
1995
|
+
tableObserver.enableHighlightStyle();
|
1996
|
+
$forEachTableCell(tableObserver.table, cell => {
|
1997
|
+
const elem = cell.elem;
|
1998
|
+
cell.highlighted = false;
|
1999
|
+
$removeHighlightFromDOM(editor, cell);
|
2000
|
+
if (!elem.getAttribute('style')) {
|
2001
|
+
elem.removeAttribute('style');
|
2002
|
+
}
|
2003
|
+
});
|
1684
2004
|
}
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
1688
|
-
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1700
|
-
if (iRow === 0 && includeHeaders.rows) headerState |= TableCellHeaderStates.ROW;
|
1701
|
-
if (iColumn === 0 && includeHeaders.columns) headerState |= TableCellHeaderStates.COLUMN;
|
1702
|
-
} else if (includeHeaders) {
|
1703
|
-
if (iRow === 0) headerState |= TableCellHeaderStates.ROW;
|
1704
|
-
if (iColumn === 0) headerState |= TableCellHeaderStates.COLUMN;
|
2005
|
+
const selectTableNodeInDirection = (tableObserver, tableNode, x, y, direction) => {
|
2006
|
+
const isForward = direction === 'forward';
|
2007
|
+
switch (direction) {
|
2008
|
+
case 'backward':
|
2009
|
+
case 'forward':
|
2010
|
+
if (x !== (isForward ? tableObserver.table.columns - 1 : 0)) {
|
2011
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x + (isForward ? 1 : -1), y, tableObserver.table), isForward);
|
2012
|
+
} else {
|
2013
|
+
if (y !== (isForward ? tableObserver.table.rows - 1 : 0)) {
|
2014
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(isForward ? 0 : tableObserver.table.columns - 1, y + (isForward ? 1 : -1), tableObserver.table), isForward);
|
2015
|
+
} else if (!isForward) {
|
2016
|
+
tableNode.selectPrevious();
|
2017
|
+
} else {
|
2018
|
+
tableNode.selectNext();
|
2019
|
+
}
|
1705
2020
|
}
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
2021
|
+
return true;
|
2022
|
+
case 'up':
|
2023
|
+
if (y !== 0) {
|
2024
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x, y - 1, tableObserver.table), false);
|
2025
|
+
} else {
|
2026
|
+
tableNode.selectPrevious();
|
2027
|
+
}
|
2028
|
+
return true;
|
2029
|
+
case 'down':
|
2030
|
+
if (y !== tableObserver.table.rows - 1) {
|
2031
|
+
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x, y + 1, tableObserver.table), true);
|
2032
|
+
} else {
|
2033
|
+
tableNode.selectNext();
|
2034
|
+
}
|
2035
|
+
return true;
|
2036
|
+
default:
|
2037
|
+
return false;
|
1713
2038
|
}
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
2039
|
+
};
|
2040
|
+
const adjustFocusNodeInDirection = (tableObserver, tableNode, x, y, direction) => {
|
2041
|
+
const isForward = direction === 'forward';
|
2042
|
+
switch (direction) {
|
2043
|
+
case 'backward':
|
2044
|
+
case 'forward':
|
2045
|
+
if (x !== (isForward ? tableObserver.table.columns - 1 : 0)) {
|
2046
|
+
tableObserver.setFocusCellForSelection(tableNode.getDOMCellFromCordsOrThrow(x + (isForward ? 1 : -1), y, tableObserver.table));
|
2047
|
+
}
|
2048
|
+
return true;
|
2049
|
+
case 'up':
|
2050
|
+
if (y !== 0) {
|
2051
|
+
tableObserver.setFocusCellForSelection(tableNode.getDOMCellFromCordsOrThrow(x, y - 1, tableObserver.table));
|
2052
|
+
return true;
|
2053
|
+
} else {
|
2054
|
+
return false;
|
2055
|
+
}
|
2056
|
+
case 'down':
|
2057
|
+
if (y !== tableObserver.table.rows - 1) {
|
2058
|
+
tableObserver.setFocusCellForSelection(tableNode.getDOMCellFromCordsOrThrow(x, y + 1, tableObserver.table));
|
2059
|
+
return true;
|
2060
|
+
} else {
|
2061
|
+
return false;
|
2062
|
+
}
|
2063
|
+
default:
|
2064
|
+
return false;
|
1720
2065
|
}
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1724
|
-
|
1725
|
-
|
1726
|
-
return
|
2066
|
+
};
|
2067
|
+
function $isSelectionInTable(selection, tableNode) {
|
2068
|
+
if (lexical.$isRangeSelection(selection) || $isTableSelection(selection)) {
|
2069
|
+
const isAnchorInside = tableNode.isParentOf(selection.anchor.getNode());
|
2070
|
+
const isFocusInside = tableNode.isParentOf(selection.focus.getNode());
|
2071
|
+
return isAnchorInside && isFocusInside;
|
1727
2072
|
}
|
1728
|
-
|
2073
|
+
return false;
|
1729
2074
|
}
|
1730
|
-
function
|
1731
|
-
|
1732
|
-
|
1733
|
-
|
2075
|
+
function selectTableCellNode(tableCell, fromStart) {
|
2076
|
+
if (fromStart) {
|
2077
|
+
tableCell.selectStart();
|
2078
|
+
} else {
|
2079
|
+
tableCell.selectEnd();
|
1734
2080
|
}
|
1735
|
-
throw new Error('Expected table cell to be inside of table.');
|
1736
2081
|
}
|
1737
|
-
|
1738
|
-
|
1739
|
-
const
|
1740
|
-
|
2082
|
+
const BROWSER_BLUE_RGB = '172,206,247';
|
2083
|
+
function $addHighlightToDOM(editor, cell) {
|
2084
|
+
const element = cell.elem;
|
2085
|
+
const node = lexical.$getNearestNodeFromDOMNode(element);
|
2086
|
+
if (!$isTableCellNode(node)) {
|
2087
|
+
throw Error(`Expected to find LexicalNode from Table Cell DOMNode`);
|
2088
|
+
}
|
2089
|
+
const backgroundColor = node.getBackgroundColor();
|
2090
|
+
if (backgroundColor === null) {
|
2091
|
+
element.style.setProperty('background-color', `rgb(${BROWSER_BLUE_RGB})`);
|
2092
|
+
} else {
|
2093
|
+
element.style.setProperty('background-image', `linear-gradient(to right, rgba(${BROWSER_BLUE_RGB},0.85), rgba(${BROWSER_BLUE_RGB},0.85))`);
|
2094
|
+
}
|
2095
|
+
element.style.setProperty('caret-color', 'transparent');
|
1741
2096
|
}
|
1742
|
-
function $
|
1743
|
-
const
|
1744
|
-
|
2097
|
+
function $removeHighlightFromDOM(editor, cell) {
|
2098
|
+
const element = cell.elem;
|
2099
|
+
const node = lexical.$getNearestNodeFromDOMNode(element);
|
2100
|
+
if (!$isTableCellNode(node)) {
|
2101
|
+
throw Error(`Expected to find LexicalNode from Table Cell DOMNode`);
|
2102
|
+
}
|
2103
|
+
const backgroundColor = node.getBackgroundColor();
|
2104
|
+
if (backgroundColor === null) {
|
2105
|
+
element.style.removeProperty('background-color');
|
2106
|
+
}
|
2107
|
+
element.style.removeProperty('background-image');
|
2108
|
+
element.style.removeProperty('caret-color');
|
1745
2109
|
}
|
1746
|
-
function $
|
1747
|
-
const
|
1748
|
-
|
1749
|
-
x,
|
1750
|
-
y
|
1751
|
-
} = tableNode.getCordsFromCellNode(tableCellNode, grid);
|
1752
|
-
return {
|
1753
|
-
above: tableNode.getCellNodeFromCords(x, y - 1, grid),
|
1754
|
-
below: tableNode.getCellNodeFromCords(x, y + 1, grid),
|
1755
|
-
left: tableNode.getCellNodeFromCords(x - 1, y, grid),
|
1756
|
-
right: tableNode.getCellNodeFromCords(x + 1, y, grid)
|
1757
|
-
};
|
2110
|
+
function $findCellNode(node) {
|
2111
|
+
const cellNode = utils.$findMatchingParent(node, $isTableCellNode);
|
2112
|
+
return $isTableCellNode(cellNode) ? cellNode : null;
|
1758
2113
|
}
|
1759
|
-
function $
|
1760
|
-
const
|
1761
|
-
|
1762
|
-
throw new Error('Expected table cell to be inside of table row.');
|
1763
|
-
}
|
1764
|
-
const targetRowNode = tableRows[indexToDelete];
|
1765
|
-
targetRowNode.remove();
|
1766
|
-
return tableNode;
|
2114
|
+
function $findTableNode(node) {
|
2115
|
+
const tableNode = utils.$findMatchingParent(node, $isTableNode);
|
2116
|
+
return $isTableNode(tableNode) ? tableNode : null;
|
1767
2117
|
}
|
1768
|
-
function $
|
1769
|
-
const
|
1770
|
-
if (
|
1771
|
-
|
2118
|
+
function $handleArrowKey(editor, event, direction, tableNode, tableObserver) {
|
2119
|
+
const selection = lexical.$getSelection();
|
2120
|
+
if (!$isSelectionInTable(selection, tableNode)) {
|
2121
|
+
return false;
|
1772
2122
|
}
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1777
|
-
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
} = $getTableCellSiblingsFromTableCellNode(tableCellFromTargetRow, grid);
|
1788
|
-
let headerState = TableCellHeaderStates.NO_STATUS;
|
1789
|
-
const width = above && above.getWidth() || below && below.getWidth() || undefined;
|
1790
|
-
if (above && above.hasHeaderState(TableCellHeaderStates.COLUMN) || below && below.hasHeaderState(TableCellHeaderStates.COLUMN)) {
|
1791
|
-
headerState |= TableCellHeaderStates.COLUMN;
|
1792
|
-
}
|
1793
|
-
const tableCellNode = $createTableCellNode(headerState, 1, width);
|
1794
|
-
tableCellNode.append(lexical.$createParagraphNode());
|
1795
|
-
newTableRowNode.append(tableCellNode);
|
1796
|
-
}
|
1797
|
-
if (shouldInsertAfter) {
|
1798
|
-
targetRowNode.insertAfter(newTableRowNode);
|
1799
|
-
} else {
|
1800
|
-
targetRowNode.insertBefore(newTableRowNode);
|
1801
|
-
}
|
2123
|
+
if (lexical.$isRangeSelection(selection) && selection.isCollapsed()) {
|
2124
|
+
// Horizontal move between cels seem to work well without interruption
|
2125
|
+
// so just exit early, and handle vertical moves
|
2126
|
+
if (direction === 'backward' || direction === 'forward') {
|
2127
|
+
return false;
|
2128
|
+
}
|
2129
|
+
const {
|
2130
|
+
anchor,
|
2131
|
+
focus
|
2132
|
+
} = selection;
|
2133
|
+
const anchorCellNode = utils.$findMatchingParent(anchor.getNode(), $isTableCellNode);
|
2134
|
+
const focusCellNode = utils.$findMatchingParent(focus.getNode(), $isTableCellNode);
|
2135
|
+
if (!$isTableCellNode(anchorCellNode) || !anchorCellNode.is(focusCellNode)) {
|
2136
|
+
return false;
|
1802
2137
|
}
|
1803
|
-
|
1804
|
-
|
1805
|
-
|
1806
|
-
|
1807
|
-
|
1808
|
-
|
1809
|
-
const selection = lexical.$getSelection();
|
1810
|
-
if (!lexical.$INTERNAL_isPointSelection(selection)) {
|
1811
|
-
throw Error(`Expected a INTERNAL_PointSelection`);
|
1812
|
-
}
|
1813
|
-
const focus = selection.focus.getNode();
|
1814
|
-
const [focusCell,, grid] = lexical.DEPRECATED_$getNodeTriplet(focus);
|
1815
|
-
const [gridMap, focusCellMap] = lexical.DEPRECATED_$computeGridMap(grid, focusCell, focusCell);
|
1816
|
-
const columnCount = gridMap[0].length;
|
1817
|
-
const {
|
1818
|
-
startRow: focusStartRow
|
1819
|
-
} = focusCellMap;
|
1820
|
-
if (insertAfter) {
|
1821
|
-
const focusEndRow = focusStartRow + focusCell.__rowSpan - 1;
|
1822
|
-
const focusEndRowMap = gridMap[focusEndRow];
|
1823
|
-
const newRow = $createTableRowNode();
|
1824
|
-
for (let i = 0; i < columnCount; i++) {
|
1825
|
-
const {
|
1826
|
-
cell,
|
1827
|
-
startRow
|
1828
|
-
} = focusEndRowMap[i];
|
1829
|
-
if (startRow + cell.__rowSpan - 1 <= focusEndRow) {
|
1830
|
-
newRow.append($createTableCellNode(TableCellHeaderStates.NO_STATUS).append(lexical.$createParagraphNode()));
|
1831
|
-
} else {
|
1832
|
-
cell.setRowSpan(cell.__rowSpan + 1);
|
2138
|
+
const anchorCellTable = $findTableNode(anchorCellNode);
|
2139
|
+
if (anchorCellTable !== tableNode && anchorCellTable != null) {
|
2140
|
+
const anchorCellTableElement = editor.getElementByKey(anchorCellTable.getKey());
|
2141
|
+
if (anchorCellTableElement != null) {
|
2142
|
+
tableObserver.table = getTable(anchorCellTableElement);
|
2143
|
+
return $handleArrowKey(editor, event, direction, anchorCellTable, tableObserver);
|
1833
2144
|
}
|
1834
2145
|
}
|
1835
|
-
const
|
1836
|
-
|
1837
|
-
|
2146
|
+
const anchorCellDom = editor.getElementByKey(anchorCellNode.__key);
|
2147
|
+
const anchorDOM = editor.getElementByKey(anchor.key);
|
2148
|
+
if (anchorDOM == null || anchorCellDom == null) {
|
2149
|
+
return false;
|
1838
2150
|
}
|
1839
|
-
|
1840
|
-
|
1841
|
-
|
1842
|
-
|
1843
|
-
|
1844
|
-
|
1845
|
-
|
1846
|
-
startRow
|
1847
|
-
} = focusStartRowMap[i];
|
1848
|
-
if (startRow === focusStartRow) {
|
1849
|
-
newRow.append($createTableCellNode(TableCellHeaderStates.NO_STATUS).append(lexical.$createParagraphNode()));
|
1850
|
-
} else {
|
1851
|
-
cell.setRowSpan(cell.__rowSpan + 1);
|
2151
|
+
let edgeSelectionRect;
|
2152
|
+
if (anchor.type === 'element') {
|
2153
|
+
edgeSelectionRect = anchorDOM.getBoundingClientRect();
|
2154
|
+
} else {
|
2155
|
+
const domSelection = window.getSelection();
|
2156
|
+
if (domSelection === null || domSelection.rangeCount === 0) {
|
2157
|
+
return false;
|
1852
2158
|
}
|
2159
|
+
const range = domSelection.getRangeAt(0);
|
2160
|
+
edgeSelectionRect = range.getBoundingClientRect();
|
1853
2161
|
}
|
1854
|
-
const
|
1855
|
-
if (
|
1856
|
-
|
2162
|
+
const edgeChild = direction === 'up' ? anchorCellNode.getFirstChild() : anchorCellNode.getLastChild();
|
2163
|
+
if (edgeChild == null) {
|
2164
|
+
return false;
|
1857
2165
|
}
|
1858
|
-
|
1859
|
-
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
|
1866
|
-
|
1867
|
-
|
1868
|
-
const
|
1869
|
-
|
1870
|
-
|
1871
|
-
|
1872
|
-
|
1873
|
-
if (!$isTableCellNode(targetCell)) {
|
1874
|
-
throw Error(`Expected table cell`);
|
1875
|
-
}
|
1876
|
-
const {
|
1877
|
-
left,
|
1878
|
-
right
|
1879
|
-
} = $getTableCellSiblingsFromTableCellNode(targetCell, grid);
|
1880
|
-
let headerState = TableCellHeaderStates.NO_STATUS;
|
1881
|
-
if (left && left.hasHeaderState(TableCellHeaderStates.ROW) || right && right.hasHeaderState(TableCellHeaderStates.ROW)) {
|
1882
|
-
headerState |= TableCellHeaderStates.ROW;
|
1883
|
-
}
|
1884
|
-
const newTableCell = $createTableCellNode(headerState);
|
1885
|
-
newTableCell.append(lexical.$createParagraphNode());
|
1886
|
-
tableCellsToBeInserted.push({
|
1887
|
-
newTableCell,
|
1888
|
-
targetCell
|
1889
|
-
});
|
2166
|
+
const edgeChildDOM = editor.getElementByKey(edgeChild.__key);
|
2167
|
+
if (edgeChildDOM == null) {
|
2168
|
+
return false;
|
2169
|
+
}
|
2170
|
+
const edgeRect = edgeChildDOM.getBoundingClientRect();
|
2171
|
+
const isExiting = direction === 'up' ? edgeRect.top > edgeSelectionRect.top - edgeSelectionRect.height : edgeSelectionRect.bottom + edgeSelectionRect.height > edgeRect.bottom;
|
2172
|
+
if (isExiting) {
|
2173
|
+
stopEvent(event);
|
2174
|
+
const cords = tableNode.getCordsFromCellNode(anchorCellNode, tableObserver.table);
|
2175
|
+
if (event.shiftKey) {
|
2176
|
+
const cell = tableNode.getDOMCellFromCordsOrThrow(cords.x, cords.y, tableObserver.table);
|
2177
|
+
tableObserver.setAnchorCellForSelection(cell);
|
2178
|
+
tableObserver.setFocusCellForSelection(cell, true);
|
2179
|
+
} else {
|
2180
|
+
return selectTableNodeInDirection(tableObserver, tableNode, cords.x, cords.y, direction);
|
1890
2181
|
}
|
2182
|
+
return true;
|
1891
2183
|
}
|
1892
|
-
}
|
1893
|
-
|
1894
|
-
|
1895
|
-
|
1896
|
-
|
1897
|
-
|
1898
|
-
|
2184
|
+
} else if ($isTableSelection(selection)) {
|
2185
|
+
const {
|
2186
|
+
anchor,
|
2187
|
+
focus
|
2188
|
+
} = selection;
|
2189
|
+
const anchorCellNode = utils.$findMatchingParent(anchor.getNode(), $isTableCellNode);
|
2190
|
+
const focusCellNode = utils.$findMatchingParent(focus.getNode(), $isTableCellNode);
|
2191
|
+
const [tableNodeFromSelection] = selection.getNodes();
|
2192
|
+
const tableElement = editor.getElementByKey(tableNodeFromSelection.getKey());
|
2193
|
+
if (!$isTableCellNode(anchorCellNode) || !$isTableCellNode(focusCellNode) || !$isTableNode(tableNodeFromSelection) || tableElement == null) {
|
2194
|
+
return false;
|
2195
|
+
}
|
2196
|
+
tableObserver.updateTableTableSelection(selection);
|
2197
|
+
const grid = getTable(tableElement);
|
2198
|
+
const cordsAnchor = tableNode.getCordsFromCellNode(anchorCellNode, grid);
|
2199
|
+
const anchorCell = tableNode.getDOMCellFromCordsOrThrow(cordsAnchor.x, cordsAnchor.y, grid);
|
2200
|
+
tableObserver.setAnchorCellForSelection(anchorCell);
|
2201
|
+
stopEvent(event);
|
2202
|
+
if (event.shiftKey) {
|
2203
|
+
const cords = tableNode.getCordsFromCellNode(focusCellNode, grid);
|
2204
|
+
return adjustFocusNodeInDirection(tableObserver, tableNodeFromSelection, cords.x, cords.y, direction);
|
1899
2205
|
} else {
|
1900
|
-
|
2206
|
+
focusCellNode.selectEnd();
|
1901
2207
|
}
|
1902
|
-
|
1903
|
-
|
2208
|
+
return true;
|
2209
|
+
}
|
2210
|
+
return false;
|
1904
2211
|
}
|
1905
|
-
function
|
1906
|
-
|
1907
|
-
|
1908
|
-
|
2212
|
+
function stopEvent(event) {
|
2213
|
+
event.preventDefault();
|
2214
|
+
event.stopImmediatePropagation();
|
2215
|
+
event.stopPropagation();
|
2216
|
+
}
|
2217
|
+
|
2218
|
+
/**
|
2219
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
2220
|
+
*
|
2221
|
+
* This source code is licensed under the MIT license found in the
|
2222
|
+
* LICENSE file in the root directory of this source tree.
|
2223
|
+
*
|
2224
|
+
*/
|
2225
|
+
/** @noInheritDoc */
|
2226
|
+
class TableNode extends lexical.ElementNode {
|
2227
|
+
static getType() {
|
2228
|
+
return 'table';
|
1909
2229
|
}
|
1910
|
-
|
1911
|
-
|
1912
|
-
const [anchorCell] = lexical.DEPRECATED_$getNodeTriplet(anchor);
|
1913
|
-
const [focusCell,, grid] = lexical.DEPRECATED_$getNodeTriplet(focus);
|
1914
|
-
const [gridMap, focusCellMap, anchorCellMap] = lexical.DEPRECATED_$computeGridMap(grid, focusCell, anchorCell);
|
1915
|
-
const rowCount = gridMap.length;
|
1916
|
-
const startColumn = insertAfter ? Math.max(focusCellMap.startColumn, anchorCellMap.startColumn) : Math.min(focusCellMap.startColumn, anchorCellMap.startColumn);
|
1917
|
-
const insertAfterColumn = insertAfter ? startColumn + focusCell.__colSpan - 1 : startColumn - 1;
|
1918
|
-
const gridFirstChild = grid.getFirstChild();
|
1919
|
-
if (!lexical.DEPRECATED_$isGridRowNode(gridFirstChild)) {
|
1920
|
-
throw Error(`Expected firstTable child to be a row`);
|
2230
|
+
static clone(node) {
|
2231
|
+
return new TableNode(node.__key);
|
1921
2232
|
}
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
1925
|
-
|
1926
|
-
|
1927
|
-
|
1928
|
-
|
2233
|
+
static importDOM() {
|
2234
|
+
return {
|
2235
|
+
table: _node => ({
|
2236
|
+
conversion: convertTableElement,
|
2237
|
+
priority: 1
|
2238
|
+
})
|
2239
|
+
};
|
1929
2240
|
}
|
1930
|
-
|
1931
|
-
|
1932
|
-
if (i !== 0) {
|
1933
|
-
const currentRow = loopRow.getNextSibling();
|
1934
|
-
if (!lexical.DEPRECATED_$isGridRowNode(currentRow)) {
|
1935
|
-
throw Error(`Expected row nextSibling to be a row`);
|
1936
|
-
}
|
1937
|
-
loopRow = currentRow;
|
1938
|
-
}
|
1939
|
-
const rowMap = gridMap[i];
|
1940
|
-
if (insertAfterColumn < 0) {
|
1941
|
-
$insertFirst(loopRow, $createTableCellNodeForInsertTableColumn());
|
1942
|
-
continue;
|
1943
|
-
}
|
1944
|
-
const {
|
1945
|
-
cell: currentCell,
|
1946
|
-
startColumn: currentStartColumn,
|
1947
|
-
startRow: currentStartRow
|
1948
|
-
} = rowMap[insertAfterColumn];
|
1949
|
-
if (currentStartColumn + currentCell.__colSpan - 1 <= insertAfterColumn) {
|
1950
|
-
let insertAfterCell = currentCell;
|
1951
|
-
let insertAfterCellRowStart = currentStartRow;
|
1952
|
-
let prevCellIndex = insertAfterColumn;
|
1953
|
-
while (insertAfterCellRowStart !== i && insertAfterCell.__rowSpan > 1) {
|
1954
|
-
prevCellIndex -= currentCell.__colSpan;
|
1955
|
-
if (prevCellIndex >= 0) {
|
1956
|
-
const {
|
1957
|
-
cell: cell_,
|
1958
|
-
startRow: startRow_
|
1959
|
-
} = rowMap[prevCellIndex];
|
1960
|
-
insertAfterCell = cell_;
|
1961
|
-
insertAfterCellRowStart = startRow_;
|
1962
|
-
} else {
|
1963
|
-
loopRow.append($createTableCellNodeForInsertTableColumn());
|
1964
|
-
continue rowLoop;
|
1965
|
-
}
|
1966
|
-
}
|
1967
|
-
insertAfterCell.insertAfter($createTableCellNodeForInsertTableColumn());
|
1968
|
-
} else {
|
1969
|
-
currentCell.setColSpan(currentCell.__colSpan + 1);
|
1970
|
-
}
|
2241
|
+
static importJSON(_serializedNode) {
|
2242
|
+
return $createTableNode();
|
1971
2243
|
}
|
1972
|
-
|
1973
|
-
|
2244
|
+
constructor(key) {
|
2245
|
+
super(key);
|
1974
2246
|
}
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
2247
|
+
exportJSON() {
|
2248
|
+
return {
|
2249
|
+
...super.exportJSON(),
|
2250
|
+
type: 'table',
|
2251
|
+
version: 1
|
2252
|
+
};
|
2253
|
+
}
|
2254
|
+
createDOM(config, editor) {
|
2255
|
+
const tableElement = document.createElement('table');
|
2256
|
+
utils.addClassNamesToElement(tableElement, config.theme.table);
|
2257
|
+
return tableElement;
|
2258
|
+
}
|
2259
|
+
updateDOM() {
|
2260
|
+
return false;
|
2261
|
+
}
|
2262
|
+
exportDOM(editor) {
|
2263
|
+
return {
|
2264
|
+
...super.exportDOM(editor),
|
2265
|
+
after: tableElement => {
|
2266
|
+
if (tableElement) {
|
2267
|
+
const newElement = tableElement.cloneNode();
|
2268
|
+
const colGroup = document.createElement('colgroup');
|
2269
|
+
const tBody = document.createElement('tbody');
|
2270
|
+
if (utils.isHTMLElement(tableElement)) {
|
2271
|
+
tBody.append(...tableElement.children);
|
2272
|
+
}
|
2273
|
+
const firstRow = this.getFirstChildOrThrow();
|
2274
|
+
if (!$isTableRowNode(firstRow)) {
|
2275
|
+
throw new Error('Expected to find row node.');
|
2276
|
+
}
|
2277
|
+
const colCount = firstRow.getChildrenSize();
|
2278
|
+
for (let i = 0; i < colCount; i++) {
|
2279
|
+
const col = document.createElement('col');
|
2280
|
+
colGroup.append(col);
|
2281
|
+
}
|
2282
|
+
newElement.replaceChildren(colGroup, tBody);
|
2283
|
+
return newElement;
|
2284
|
+
}
|
1984
2285
|
}
|
1985
|
-
|
1986
|
-
}
|
2286
|
+
};
|
1987
2287
|
}
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
|
1992
|
-
if (!lexical.$INTERNAL_isPointSelection(selection)) {
|
1993
|
-
throw Error(`Expected a INTERNAL_PointSelection`);
|
2288
|
+
|
2289
|
+
// TODO 0.10 deprecate
|
2290
|
+
canExtractContents() {
|
2291
|
+
return false;
|
1994
2292
|
}
|
1995
|
-
|
1996
|
-
|
1997
|
-
const [anchorCell,, grid] = lexical.DEPRECATED_$getNodeTriplet(anchor);
|
1998
|
-
const [focusCell] = lexical.DEPRECATED_$getNodeTriplet(focus);
|
1999
|
-
const [gridMap, anchorCellMap, focusCellMap] = lexical.DEPRECATED_$computeGridMap(grid, anchorCell, focusCell);
|
2000
|
-
const {
|
2001
|
-
startRow: anchorStartRow
|
2002
|
-
} = anchorCellMap;
|
2003
|
-
const {
|
2004
|
-
startRow: focusStartRow
|
2005
|
-
} = focusCellMap;
|
2006
|
-
const focusEndRow = focusStartRow + focusCell.__rowSpan - 1;
|
2007
|
-
if (gridMap.length === focusEndRow - anchorStartRow + 1) {
|
2008
|
-
// Empty grid
|
2009
|
-
grid.remove();
|
2010
|
-
return;
|
2293
|
+
canBeEmpty() {
|
2294
|
+
return false;
|
2011
2295
|
}
|
2012
|
-
|
2013
|
-
|
2014
|
-
|
2015
|
-
|
2016
|
-
|
2017
|
-
|
2018
|
-
|
2019
|
-
|
2020
|
-
|
2021
|
-
|
2022
|
-
if (
|
2023
|
-
// Don't repeat work for the same Cell
|
2296
|
+
isShadowRoot() {
|
2297
|
+
return true;
|
2298
|
+
}
|
2299
|
+
getCordsFromCellNode(tableCellNode, table) {
|
2300
|
+
const {
|
2301
|
+
rows,
|
2302
|
+
domRows
|
2303
|
+
} = table;
|
2304
|
+
for (let y = 0; y < rows; y++) {
|
2305
|
+
const row = domRows[y];
|
2306
|
+
if (row == null) {
|
2024
2307
|
continue;
|
2025
2308
|
}
|
2026
|
-
|
2027
|
-
|
2028
|
-
|
2029
|
-
|
2030
|
-
|
2031
|
-
|
2032
|
-
|
2033
|
-
|
2034
|
-
|
2035
|
-
|
2036
|
-
|
2037
|
-
|
2038
|
-
}
|
2039
|
-
const {
|
2040
|
-
cell: previousCell
|
2041
|
-
} = nextRow[column - 1];
|
2042
|
-
previousCell.insertAfter(cell);
|
2043
|
-
}
|
2309
|
+
const x = row.findIndex(cell => {
|
2310
|
+
if (!cell) return;
|
2311
|
+
const {
|
2312
|
+
elem
|
2313
|
+
} = cell;
|
2314
|
+
const cellNode = lexical.$getNearestNodeFromDOMNode(elem);
|
2315
|
+
return cellNode === tableCellNode;
|
2316
|
+
});
|
2317
|
+
if (x !== -1) {
|
2318
|
+
return {
|
2319
|
+
x,
|
2320
|
+
y
|
2321
|
+
};
|
2044
2322
|
}
|
2045
2323
|
}
|
2046
|
-
|
2047
|
-
if (!lexical.DEPRECATED_$isGridRowNode(rowNode)) {
|
2048
|
-
throw Error(`Expected GridNode childAtIndex(${String(row)}) to be RowNode`);
|
2049
|
-
}
|
2050
|
-
rowNode.remove();
|
2324
|
+
throw new Error('Cell not found in table.');
|
2051
2325
|
}
|
2052
|
-
|
2053
|
-
const {
|
2054
|
-
cell
|
2055
|
-
} = nextRow[0];
|
2056
|
-
$moveSelectionToCell(cell);
|
2057
|
-
} else {
|
2058
|
-
const previousRow = gridMap[anchorStartRow - 1];
|
2326
|
+
getDOMCellFromCords(x, y, table) {
|
2059
2327
|
const {
|
2060
|
-
|
2061
|
-
} =
|
2062
|
-
|
2328
|
+
domRows
|
2329
|
+
} = table;
|
2330
|
+
const row = domRows[y];
|
2331
|
+
if (row == null) {
|
2332
|
+
return null;
|
2333
|
+
}
|
2334
|
+
const cell = row[x];
|
2335
|
+
if (cell == null) {
|
2336
|
+
return null;
|
2337
|
+
}
|
2338
|
+
return cell;
|
2063
2339
|
}
|
2064
|
-
|
2065
|
-
|
2066
|
-
|
2067
|
-
|
2068
|
-
|
2340
|
+
getDOMCellFromCordsOrThrow(x, y, table) {
|
2341
|
+
const cell = this.getDOMCellFromCords(x, y, table);
|
2342
|
+
if (!cell) {
|
2343
|
+
throw new Error('Cell not found at cords.');
|
2344
|
+
}
|
2345
|
+
return cell;
|
2069
2346
|
}
|
2070
|
-
|
2071
|
-
|
2072
|
-
|
2073
|
-
|
2074
|
-
|
2075
|
-
|
2076
|
-
|
2077
|
-
|
2078
|
-
|
2079
|
-
|
2080
|
-
startColumn: focusStartColumn
|
2081
|
-
} = focusCellMap;
|
2082
|
-
const startColumn = Math.min(anchorStartColumn, focusStartColumn);
|
2083
|
-
const endColumn = Math.max(anchorStartColumn + anchorCell.__colSpan - 1, focusStartColumn + focusCell.__colSpan - 1);
|
2084
|
-
const selectedColumnCount = endColumn - startColumn + 1;
|
2085
|
-
const columnCount = gridMap[0].length;
|
2086
|
-
if (columnCount === endColumn - startColumn + 1) {
|
2087
|
-
// Empty grid
|
2088
|
-
grid.selectPrevious();
|
2089
|
-
grid.remove();
|
2090
|
-
return;
|
2347
|
+
getCellNodeFromCords(x, y, table) {
|
2348
|
+
const cell = this.getDOMCellFromCords(x, y, table);
|
2349
|
+
if (cell == null) {
|
2350
|
+
return null;
|
2351
|
+
}
|
2352
|
+
const node = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
2353
|
+
if ($isTableCellNode(node)) {
|
2354
|
+
return node;
|
2355
|
+
}
|
2356
|
+
return null;
|
2091
2357
|
}
|
2092
|
-
|
2093
|
-
|
2094
|
-
|
2095
|
-
|
2096
|
-
cell,
|
2097
|
-
startColumn: cellStartColumn
|
2098
|
-
} = gridMap[row][column];
|
2099
|
-
if (cellStartColumn < startColumn) {
|
2100
|
-
if (column === startColumn) {
|
2101
|
-
const overflowLeft = startColumn - cellStartColumn;
|
2102
|
-
// Overflowing left
|
2103
|
-
cell.setColSpan(cell.__colSpan -
|
2104
|
-
// Possible overflow right too
|
2105
|
-
Math.min(selectedColumnCount, cell.__colSpan - overflowLeft));
|
2106
|
-
}
|
2107
|
-
} else if (cellStartColumn + cell.__colSpan - 1 > endColumn) {
|
2108
|
-
if (column === endColumn) {
|
2109
|
-
// Overflowing right
|
2110
|
-
const inSelectedArea = endColumn - cellStartColumn + 1;
|
2111
|
-
cell.setColSpan(cell.__colSpan - inSelectedArea);
|
2112
|
-
}
|
2113
|
-
} else {
|
2114
|
-
cell.remove();
|
2115
|
-
}
|
2358
|
+
getCellNodeFromCordsOrThrow(x, y, table) {
|
2359
|
+
const node = this.getCellNodeFromCords(x, y, table);
|
2360
|
+
if (!node) {
|
2361
|
+
throw new Error('Node at cords not TableCellNode.');
|
2116
2362
|
}
|
2363
|
+
return node;
|
2117
2364
|
}
|
2118
|
-
|
2119
|
-
|
2120
|
-
if (nextColumn !== undefined) {
|
2121
|
-
const {
|
2122
|
-
cell
|
2123
|
-
} = nextColumn;
|
2124
|
-
$moveSelectionToCell(cell);
|
2125
|
-
} else {
|
2126
|
-
const previousRow = focusRowMap[focusStartColumn - 1];
|
2127
|
-
const {
|
2128
|
-
cell
|
2129
|
-
} = previousRow;
|
2130
|
-
$moveSelectionToCell(cell);
|
2365
|
+
canSelectBefore() {
|
2366
|
+
return true;
|
2131
2367
|
}
|
2132
|
-
|
2133
|
-
|
2134
|
-
const firstDescendant = cell.getFirstDescendant();
|
2135
|
-
if (firstDescendant == null) {
|
2136
|
-
cell.selectStart();
|
2137
|
-
} else {
|
2138
|
-
firstDescendant.getParentOrThrow().selectStart();
|
2368
|
+
canIndent() {
|
2369
|
+
return false;
|
2139
2370
|
}
|
2140
2371
|
}
|
2141
|
-
function $
|
2142
|
-
const
|
2143
|
-
if (
|
2144
|
-
|
2145
|
-
} else {
|
2146
|
-
parent.append(node);
|
2372
|
+
function $getElementForTableNode(editor, tableNode) {
|
2373
|
+
const tableElement = editor.getElementByKey(tableNode.getKey());
|
2374
|
+
if (tableElement == null) {
|
2375
|
+
throw new Error('Table Element Not Found');
|
2147
2376
|
}
|
2377
|
+
return getTable(tableElement);
|
2148
2378
|
}
|
2149
|
-
function
|
2150
|
-
|
2151
|
-
|
2152
|
-
|
2153
|
-
|
2154
|
-
|
2155
|
-
|
2156
|
-
|
2157
|
-
|
2158
|
-
|
2159
|
-
for (let i = 1; i < colSpan; i++) {
|
2160
|
-
cell.insertAfter($createTableCellNode(TableCellHeaderStates.NO_STATUS));
|
2161
|
-
}
|
2162
|
-
cell.setColSpan(1);
|
2163
|
-
}
|
2164
|
-
if (rowSpan > 1) {
|
2165
|
-
const [map, cellMap] = lexical.DEPRECATED_$computeGridMap(grid, cell, cell);
|
2166
|
-
const {
|
2167
|
-
startColumn,
|
2168
|
-
startRow
|
2169
|
-
} = cellMap;
|
2170
|
-
let currentRowNode;
|
2171
|
-
for (let i = 1; i < rowSpan; i++) {
|
2172
|
-
const currentRow = startRow + i;
|
2173
|
-
const currentRowMap = map[currentRow];
|
2174
|
-
currentRowNode = (currentRowNode || row).getNextSibling();
|
2175
|
-
if (!lexical.DEPRECATED_$isGridRowNode(currentRowNode)) {
|
2176
|
-
throw Error(`Expected row next sibling to be a row`);
|
2177
|
-
}
|
2178
|
-
let insertAfterCell = null;
|
2179
|
-
for (let column = 0; column < startColumn; column++) {
|
2180
|
-
const currentCellMap = currentRowMap[column];
|
2181
|
-
const currentCell = currentCellMap.cell;
|
2182
|
-
if (currentCellMap.startRow === currentRow) {
|
2183
|
-
insertAfterCell = currentCell;
|
2184
|
-
}
|
2185
|
-
if (currentCell.__colSpan > 1) {
|
2186
|
-
column += currentCell.__colSpan - 1;
|
2187
|
-
}
|
2188
|
-
}
|
2189
|
-
if (insertAfterCell === null) {
|
2190
|
-
for (let j = 0; j < colSpan; j++) {
|
2191
|
-
$insertFirst(currentRowNode, $createTableCellNode(TableCellHeaderStates.NO_STATUS));
|
2192
|
-
}
|
2193
|
-
} else {
|
2194
|
-
for (let j = 0; j < colSpan; j++) {
|
2195
|
-
insertAfterCell.insertAfter($createTableCellNode(TableCellHeaderStates.NO_STATUS));
|
2196
|
-
}
|
2197
|
-
}
|
2198
|
-
}
|
2199
|
-
cell.setRowSpan(1);
|
2200
|
-
}
|
2379
|
+
function convertTableElement(_domNode) {
|
2380
|
+
return {
|
2381
|
+
node: $createTableNode()
|
2382
|
+
};
|
2383
|
+
}
|
2384
|
+
function $createTableNode() {
|
2385
|
+
return lexical.$applyNodeReplacement(new TableNode());
|
2386
|
+
}
|
2387
|
+
function $isTableNode(node) {
|
2388
|
+
return node instanceof TableNode;
|
2201
2389
|
}
|
2202
2390
|
|
2203
|
-
|
2204
|
-
const INSERT_TABLE_COMMAND = lexical.createCommand('INSERT_TABLE_COMMAND');
|
2205
|
-
|
2206
|
-
exports.$createGridSelection = $createGridSelection;
|
2391
|
+
exports.$computeTableMap = $computeTableMap;
|
2207
2392
|
exports.$createTableCellNode = $createTableCellNode;
|
2208
2393
|
exports.$createTableNode = $createTableNode;
|
2209
2394
|
exports.$createTableNodeWithDimensions = $createTableNodeWithDimensions;
|
2210
2395
|
exports.$createTableRowNode = $createTableRowNode;
|
2396
|
+
exports.$createTableSelection = $createTableSelection;
|
2211
2397
|
exports.$deleteTableColumn = $deleteTableColumn;
|
2212
2398
|
exports.$deleteTableColumn__EXPERIMENTAL = $deleteTableColumn__EXPERIMENTAL;
|
2213
2399
|
exports.$deleteTableRow__EXPERIMENTAL = $deleteTableRow__EXPERIMENTAL;
|
2214
|
-
exports.$
|
2400
|
+
exports.$getElementForTableNode = $getElementForTableNode;
|
2401
|
+
exports.$getNodeTriplet = $getNodeTriplet;
|
2215
2402
|
exports.$getTableCellNodeFromLexicalNode = $getTableCellNodeFromLexicalNode;
|
2403
|
+
exports.$getTableCellNodeRect = $getTableCellNodeRect;
|
2216
2404
|
exports.$getTableColumnIndexFromTableCellNode = $getTableColumnIndexFromTableCellNode;
|
2217
2405
|
exports.$getTableNodeFromLexicalNodeOrThrow = $getTableNodeFromLexicalNodeOrThrow;
|
2218
2406
|
exports.$getTableRowIndexFromTableCellNode = $getTableRowIndexFromTableCellNode;
|
@@ -2221,18 +2409,18 @@ exports.$insertTableColumn = $insertTableColumn;
|
|
2221
2409
|
exports.$insertTableColumn__EXPERIMENTAL = $insertTableColumn__EXPERIMENTAL;
|
2222
2410
|
exports.$insertTableRow = $insertTableRow;
|
2223
2411
|
exports.$insertTableRow__EXPERIMENTAL = $insertTableRow__EXPERIMENTAL;
|
2224
|
-
exports.$isGridSelection = $isGridSelection;
|
2225
2412
|
exports.$isTableCellNode = $isTableCellNode;
|
2226
2413
|
exports.$isTableNode = $isTableNode;
|
2227
2414
|
exports.$isTableRowNode = $isTableRowNode;
|
2415
|
+
exports.$isTableSelection = $isTableSelection;
|
2228
2416
|
exports.$removeTableRowAtIndex = $removeTableRowAtIndex;
|
2229
2417
|
exports.$unmergeCell = $unmergeCell;
|
2230
2418
|
exports.INSERT_TABLE_COMMAND = INSERT_TABLE_COMMAND;
|
2231
2419
|
exports.TableCellHeaderStates = TableCellHeaderStates;
|
2232
2420
|
exports.TableCellNode = TableCellNode;
|
2233
2421
|
exports.TableNode = TableNode;
|
2422
|
+
exports.TableObserver = TableObserver;
|
2234
2423
|
exports.TableRowNode = TableRowNode;
|
2235
|
-
exports.TableSelection = TableSelection;
|
2236
2424
|
exports.applyTableHandlers = applyTableHandlers;
|
2237
|
-
exports.
|
2238
|
-
exports.
|
2425
|
+
exports.getDOMCellFromTarget = getDOMCellFromTarget;
|
2426
|
+
exports.getTableObserverFromTableElement = getTableObserverFromTableElement;
|