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