@lexical/table 0.12.5 → 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 +1809 -1301
- package/LexicalTable.js.flow +125 -40
- package/LexicalTable.prod.js +77 -65
- 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 -40
- package/LexicalTableSelectionHelpers.d.ts +14 -13
- package/LexicalTableUtils.d.ts +14 -4
- package/index.d.ts +9 -16
- package/package.json +3 -3
package/LexicalTable.dev.js
CHANGED
@@ -6,8 +6,8 @@
|
|
6
6
|
*/
|
7
7
|
'use strict';
|
8
8
|
|
9
|
-
var lexical = require('lexical');
|
10
9
|
var utils = require('@lexical/utils');
|
10
|
+
var lexical = require('lexical');
|
11
11
|
|
12
12
|
/**
|
13
13
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
@@ -33,7 +33,11 @@ const TableCellHeaderStates = {
|
|
33
33
|
ROW: 1
|
34
34
|
};
|
35
35
|
/** @noInheritDoc */
|
36
|
-
class TableCellNode extends lexical.
|
36
|
+
class TableCellNode extends lexical.ElementNode {
|
37
|
+
/** @internal */
|
38
|
+
|
39
|
+
/** @internal */
|
40
|
+
|
37
41
|
/** @internal */
|
38
42
|
|
39
43
|
/** @internal */
|
@@ -70,7 +74,9 @@ class TableCellNode extends lexical.DEPRECATED_GridCellNode {
|
|
70
74
|
return cellNode;
|
71
75
|
}
|
72
76
|
constructor(headerState = TableCellHeaderStates.NO_STATUS, colSpan = 1, width, key) {
|
73
|
-
super(
|
77
|
+
super(key);
|
78
|
+
this.__colSpan = colSpan;
|
79
|
+
this.__rowSpan = 1;
|
74
80
|
this.__headerState = headerState;
|
75
81
|
this.__width = width;
|
76
82
|
this.__backgroundColor = null;
|
@@ -125,11 +131,27 @@ class TableCellNode extends lexical.DEPRECATED_GridCellNode {
|
|
125
131
|
return {
|
126
132
|
...super.exportJSON(),
|
127
133
|
backgroundColor: this.getBackgroundColor(),
|
134
|
+
colSpan: this.__colSpan,
|
128
135
|
headerState: this.__headerState,
|
136
|
+
rowSpan: this.__rowSpan,
|
129
137
|
type: 'tablecell',
|
130
138
|
width: this.getWidth()
|
131
139
|
};
|
132
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
|
+
}
|
133
155
|
getTag() {
|
134
156
|
return this.hasHeader() ? 'th' : 'td';
|
135
157
|
}
|
@@ -221,6 +243,15 @@ function $isTableCellNode(node) {
|
|
221
243
|
return node instanceof TableCellNode;
|
222
244
|
}
|
223
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
|
+
|
224
255
|
/**
|
225
256
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
226
257
|
*
|
@@ -229,7 +260,7 @@ function $isTableCellNode(node) {
|
|
229
260
|
*
|
230
261
|
*/
|
231
262
|
/** @noInheritDoc */
|
232
|
-
class TableRowNode extends lexical.
|
263
|
+
class TableRowNode extends lexical.ElementNode {
|
233
264
|
/** @internal */
|
234
265
|
|
235
266
|
static getType() {
|
@@ -323,152 +354,1063 @@ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !==
|
|
323
354
|
* LICENSE file in the root directory of this source tree.
|
324
355
|
*
|
325
356
|
*/
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
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;
|
349
384
|
}
|
350
|
-
|
351
|
-
|
385
|
+
return null;
|
386
|
+
}
|
387
|
+
function $getTableRowNodeFromTableCellNodeOrThrow(startingNode) {
|
388
|
+
const node = utils.$findMatchingParent(startingNode, n => $isTableRowNode(n));
|
389
|
+
if ($isTableRowNode(node)) {
|
390
|
+
return node;
|
352
391
|
}
|
353
|
-
|
354
|
-
|
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;
|
355
398
|
}
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
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`);
|
371
447
|
}
|
372
|
-
const
|
373
|
-
|
374
|
-
|
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;
|
375
456
|
}
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
this.editor.update(() => {
|
380
|
-
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
381
|
-
if (!tableElement) {
|
382
|
-
throw new Error('Expected to find TableElement in DOM');
|
383
|
-
}
|
384
|
-
this.grid = getTableGrid(tableElement);
|
385
|
-
observer.observe(tableElement, {
|
386
|
-
childList: true,
|
387
|
-
subtree: true
|
388
|
-
});
|
389
|
-
});
|
390
|
-
}
|
391
|
-
clearHighlight() {
|
392
|
-
const editor = this.editor;
|
393
|
-
this.isHighlightingCells = false;
|
394
|
-
this.anchorX = -1;
|
395
|
-
this.anchorY = -1;
|
396
|
-
this.focusX = -1;
|
397
|
-
this.focusY = -1;
|
398
|
-
this.gridSelection = null;
|
399
|
-
this.anchorCellNodeKey = null;
|
400
|
-
this.focusCellNodeKey = null;
|
401
|
-
this.anchorCell = null;
|
402
|
-
this.focusCell = null;
|
403
|
-
this.hasHijackedSelectionStyles = false;
|
404
|
-
this.enableHighlightStyle();
|
405
|
-
editor.update(() => {
|
406
|
-
const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
|
407
|
-
if (!$isTableNode(tableNode)) {
|
408
|
-
throw new Error('Expected TableNode.');
|
457
|
+
const tableCellNode = $createTableCellNode(headerState, 1, width);
|
458
|
+
tableCellNode.append(lexical.$createParagraphNode());
|
459
|
+
newTableRowNode.append(tableCellNode);
|
409
460
|
}
|
410
|
-
|
411
|
-
|
412
|
-
|
461
|
+
if (shouldInsertAfter) {
|
462
|
+
targetRowNode.insertAfter(newTableRowNode);
|
463
|
+
} else {
|
464
|
+
targetRowNode.insertBefore(newTableRowNode);
|
413
465
|
}
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND, undefined);
|
418
|
-
});
|
466
|
+
}
|
467
|
+
} else {
|
468
|
+
throw new Error('Row before insertion index does not exist.');
|
419
469
|
}
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
}
|
427
|
-
utils.removeClassNamesFromElement(tableElement, editor._config.theme.tableSelection);
|
428
|
-
tableElement.classList.remove('disable-selection');
|
429
|
-
this.hasHijackedSelectionStyles = false;
|
430
|
-
});
|
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`);
|
431
476
|
}
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
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);
|
438
497
|
}
|
439
|
-
utils.addClassNamesToElement(tableElement, editor._config.theme.tableSelection);
|
440
|
-
this.hasHijackedSelectionStyles = true;
|
441
|
-
});
|
442
|
-
}
|
443
|
-
updateTableGridSelection(selection) {
|
444
|
-
if (selection != null && selection.gridKey === this.tableNodeKey) {
|
445
|
-
const editor = this.editor;
|
446
|
-
this.gridSelection = selection;
|
447
|
-
this.isHighlightingCells = true;
|
448
|
-
this.disableHighlightStyle();
|
449
|
-
$updateDOMForSelection(editor, this.grid, this.gridSelection);
|
450
|
-
} else if (selection == null) {
|
451
|
-
this.clearHighlight();
|
452
|
-
} else {
|
453
|
-
this.tableNodeKey = selection.gridKey;
|
454
|
-
this.updateTableGridSelection(selection);
|
455
498
|
}
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
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];
|
1304
|
+
const target = record.target;
|
1305
|
+
const nodeName = target.nodeName;
|
1306
|
+
if (nodeName === 'TABLE' || nodeName === 'TR') {
|
1307
|
+
gridNeedsRedraw = true;
|
1308
|
+
break;
|
1309
|
+
}
|
1310
|
+
}
|
1311
|
+
if (!gridNeedsRedraw) {
|
1312
|
+
return;
|
1313
|
+
}
|
1314
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
1315
|
+
if (!tableElement) {
|
1316
|
+
throw new Error('Expected to find TableElement in DOM');
|
1317
|
+
}
|
1318
|
+
this.table = getTable(tableElement);
|
1319
|
+
});
|
1320
|
+
});
|
1321
|
+
this.editor.update(() => {
|
1322
|
+
const tableElement = this.editor.getElementByKey(this.tableNodeKey);
|
1323
|
+
if (!tableElement) {
|
1324
|
+
throw new Error('Expected to find TableElement in DOM');
|
1325
|
+
}
|
1326
|
+
this.table = getTable(tableElement);
|
1327
|
+
observer.observe(tableElement, {
|
1328
|
+
childList: true,
|
1329
|
+
subtree: true
|
1330
|
+
});
|
1331
|
+
});
|
1332
|
+
}
|
1333
|
+
clearHighlight() {
|
1334
|
+
const editor = this.editor;
|
1335
|
+
this.isHighlightingCells = false;
|
1336
|
+
this.anchorX = -1;
|
1337
|
+
this.anchorY = -1;
|
1338
|
+
this.focusX = -1;
|
1339
|
+
this.focusY = -1;
|
1340
|
+
this.tableSelection = null;
|
1341
|
+
this.anchorCellNodeKey = null;
|
1342
|
+
this.focusCellNodeKey = null;
|
1343
|
+
this.anchorCell = null;
|
1344
|
+
this.focusCell = null;
|
1345
|
+
this.hasHijackedSelectionStyles = false;
|
1346
|
+
this.enableHighlightStyle();
|
1347
|
+
editor.update(() => {
|
1348
|
+
const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
|
1349
|
+
if (!$isTableNode(tableNode)) {
|
1350
|
+
throw new Error('Expected TableNode.');
|
1351
|
+
}
|
1352
|
+
const tableElement = editor.getElementByKey(this.tableNodeKey);
|
1353
|
+
if (!tableElement) {
|
1354
|
+
throw new Error('Expected to find TableElement in DOM');
|
1355
|
+
}
|
1356
|
+
const grid = getTable(tableElement);
|
1357
|
+
$updateDOMForSelection(editor, grid, null);
|
1358
|
+
lexical.$setSelection(null);
|
1359
|
+
editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND, undefined);
|
1360
|
+
});
|
1361
|
+
}
|
1362
|
+
enableHighlightStyle() {
|
1363
|
+
const editor = this.editor;
|
1364
|
+
editor.update(() => {
|
1365
|
+
const tableElement = editor.getElementByKey(this.tableNodeKey);
|
1366
|
+
if (!tableElement) {
|
1367
|
+
throw new Error('Expected to find TableElement in DOM');
|
1368
|
+
}
|
1369
|
+
utils.removeClassNamesFromElement(tableElement, editor._config.theme.tableSelection);
|
1370
|
+
tableElement.classList.remove('disable-selection');
|
1371
|
+
this.hasHijackedSelectionStyles = false;
|
1372
|
+
});
|
1373
|
+
}
|
1374
|
+
disableHighlightStyle() {
|
1375
|
+
const editor = this.editor;
|
1376
|
+
editor.update(() => {
|
1377
|
+
const tableElement = editor.getElementByKey(this.tableNodeKey);
|
1378
|
+
if (!tableElement) {
|
1379
|
+
throw new Error('Expected to find TableElement in DOM');
|
1380
|
+
}
|
1381
|
+
utils.addClassNamesToElement(tableElement, editor._config.theme.tableSelection);
|
1382
|
+
this.hasHijackedSelectionStyles = true;
|
1383
|
+
});
|
1384
|
+
}
|
1385
|
+
updateTableTableSelection(selection) {
|
1386
|
+
if (selection !== null && selection.tableKey === this.tableNodeKey) {
|
1387
|
+
const editor = this.editor;
|
1388
|
+
this.tableSelection = selection;
|
1389
|
+
this.isHighlightingCells = true;
|
1390
|
+
this.disableHighlightStyle();
|
1391
|
+
$updateDOMForSelection(editor, this.table, this.tableSelection);
|
1392
|
+
} else if (selection == null) {
|
1393
|
+
this.clearHighlight();
|
1394
|
+
} else {
|
1395
|
+
this.tableNodeKey = selection.tableKey;
|
1396
|
+
this.updateTableTableSelection(selection);
|
1397
|
+
}
|
1398
|
+
}
|
1399
|
+
setFocusCellForSelection(cell, ignoreStart = false) {
|
1400
|
+
const editor = this.editor;
|
1401
|
+
editor.update(() => {
|
1402
|
+
const tableNode = lexical.$getNodeByKey(this.tableNodeKey);
|
1403
|
+
if (!$isTableNode(tableNode)) {
|
1404
|
+
throw new Error('Expected TableNode.');
|
1405
|
+
}
|
1406
|
+
const tableElement = editor.getElementByKey(this.tableNodeKey);
|
1407
|
+
if (!tableElement) {
|
1408
|
+
throw new Error('Expected to find TableElement in DOM');
|
1409
|
+
}
|
1410
|
+
const cellX = cell.x;
|
1411
|
+
const cellY = cell.y;
|
1412
|
+
this.focusCell = cell;
|
1413
|
+
if (this.anchorCell !== null) {
|
472
1414
|
const domSelection = getDOMSelection(editor._window);
|
473
1415
|
// Collapse the selection
|
474
1416
|
if (domSelection) {
|
@@ -485,14 +1427,14 @@ class TableSelection {
|
|
485
1427
|
this.focusY = cellY;
|
486
1428
|
if (this.isHighlightingCells) {
|
487
1429
|
const focusTableCellNode = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
488
|
-
if (this.
|
1430
|
+
if (this.tableSelection != null && this.anchorCellNodeKey != null && $isTableCellNode(focusTableCellNode)) {
|
489
1431
|
const focusNodeKey = focusTableCellNode.getKey();
|
490
|
-
this.
|
1432
|
+
this.tableSelection = this.tableSelection.clone() || $createTableSelection();
|
491
1433
|
this.focusCellNodeKey = focusNodeKey;
|
492
|
-
this.
|
493
|
-
lexical.$setSelection(this.
|
1434
|
+
this.tableSelection.set(this.tableNodeKey, this.anchorCellNodeKey, this.focusCellNodeKey);
|
1435
|
+
lexical.$setSelection(this.tableSelection);
|
494
1436
|
editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND, undefined);
|
495
|
-
$updateDOMForSelection(editor, this.
|
1437
|
+
$updateDOMForSelection(editor, this.table, this.tableSelection);
|
496
1438
|
}
|
497
1439
|
}
|
498
1440
|
});
|
@@ -506,7 +1448,7 @@ class TableSelection {
|
|
506
1448
|
const anchorTableCellNode = lexical.$getNearestNodeFromDOMNode(cell.elem);
|
507
1449
|
if ($isTableCellNode(anchorTableCellNode)) {
|
508
1450
|
const anchorNodeKey = anchorTableCellNode.getKey();
|
509
|
-
this.
|
1451
|
+
this.tableSelection = this.tableSelection != null ? this.tableSelection.clone() : $createTableSelection();
|
510
1452
|
this.anchorCellNodeKey = anchorNodeKey;
|
511
1453
|
}
|
512
1454
|
});
|
@@ -514,7 +1456,7 @@ class TableSelection {
|
|
514
1456
|
formatCells(type) {
|
515
1457
|
this.editor.update(() => {
|
516
1458
|
const selection = lexical.$getSelection();
|
517
|
-
if (
|
1459
|
+
if (!$isTableSelection(selection)) {
|
518
1460
|
{
|
519
1461
|
throw Error(`Expected grid selection`);
|
520
1462
|
}
|
@@ -541,13 +1483,13 @@ class TableSelection {
|
|
541
1483
|
throw new Error('Expected TableNode.');
|
542
1484
|
}
|
543
1485
|
const selection = lexical.$getSelection();
|
544
|
-
if (
|
1486
|
+
if (!$isTableSelection(selection)) {
|
545
1487
|
{
|
546
1488
|
throw Error(`Expected grid selection`);
|
547
1489
|
}
|
548
1490
|
}
|
549
1491
|
const selectedNodes = selection.getNodes().filter($isTableCellNode);
|
550
|
-
if (selectedNodes.length === this.
|
1492
|
+
if (selectedNodes.length === this.table.columns * this.table.rows) {
|
551
1493
|
tableNode.selectPrevious();
|
552
1494
|
// Delete entire table
|
553
1495
|
tableNode.remove();
|
@@ -568,7 +1510,7 @@ class TableSelection {
|
|
568
1510
|
});
|
569
1511
|
}
|
570
1512
|
});
|
571
|
-
$updateDOMForSelection(editor, this.
|
1513
|
+
$updateDOMForSelection(editor, this.table, null);
|
572
1514
|
lexical.$setSelection(null);
|
573
1515
|
editor.dispatchCommand(lexical.SELECTION_CHANGE_COMMAND, undefined);
|
574
1516
|
});
|
@@ -588,9 +1530,9 @@ function applyTableHandlers(tableNode, tableElement, editor, hasTabHandler) {
|
|
588
1530
|
if (rootElement === null) {
|
589
1531
|
throw new Error('No root element.');
|
590
1532
|
}
|
591
|
-
const
|
1533
|
+
const tableObserver = new TableObserver(editor, tableNode.getKey());
|
592
1534
|
const editorWindow = editor._window || window;
|
593
|
-
|
1535
|
+
attachTableObserverToTableElement(tableElement, tableObserver);
|
594
1536
|
tableElement.addEventListener('mousedown', event => {
|
595
1537
|
setTimeout(() => {
|
596
1538
|
if (event.button !== 0) {
|
@@ -599,20 +1541,20 @@ function applyTableHandlers(tableNode, tableElement, editor, hasTabHandler) {
|
|
599
1541
|
if (!editorWindow) {
|
600
1542
|
return;
|
601
1543
|
}
|
602
|
-
const anchorCell =
|
1544
|
+
const anchorCell = getDOMCellFromTarget(event.target);
|
603
1545
|
if (anchorCell !== null) {
|
604
1546
|
stopEvent(event);
|
605
|
-
|
1547
|
+
tableObserver.setAnchorCellForSelection(anchorCell);
|
606
1548
|
}
|
607
1549
|
const onMouseUp = () => {
|
608
1550
|
editorWindow.removeEventListener('mouseup', onMouseUp);
|
609
1551
|
editorWindow.removeEventListener('mousemove', onMouseMove);
|
610
1552
|
};
|
611
1553
|
const onMouseMove = moveEvent => {
|
612
|
-
const focusCell =
|
613
|
-
if (focusCell !== null && (
|
1554
|
+
const focusCell = getDOMCellFromTarget(moveEvent.target);
|
1555
|
+
if (focusCell !== null && (tableObserver.anchorX !== focusCell.x || tableObserver.anchorY !== focusCell.y)) {
|
614
1556
|
moveEvent.preventDefault();
|
615
|
-
|
1557
|
+
tableObserver.setFocusCellForSelection(focusCell);
|
616
1558
|
}
|
617
1559
|
};
|
618
1560
|
editorWindow.addEventListener('mouseup', onMouseUp);
|
@@ -626,1260 +1568,825 @@ function applyTableHandlers(tableNode, tableElement, editor, hasTabHandler) {
|
|
626
1568
|
return;
|
627
1569
|
}
|
628
1570
|
editor.update(() => {
|
629
|
-
const selection = lexical.$getSelection();
|
630
|
-
const target = event.target;
|
631
|
-
if (
|
632
|
-
|
633
|
-
}
|
634
|
-
});
|
635
|
-
};
|
636
|
-
editorWindow.addEventListener('mousedown', mouseDownCallback);
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
const selection = lexical.$getSelection();
|
644
|
-
if (
|
645
|
-
const focusCellNode = utils.$findMatchingParent(selection.focus.getNode(), $isTableCellNode);
|
646
|
-
if ($isTableCellNode(focusCellNode)) {
|
647
|
-
stopEvent(event);
|
648
|
-
focusCellNode.selectEnd();
|
649
|
-
return true;
|
650
|
-
}
|
651
|
-
}
|
652
|
-
return false;
|
653
|
-
}, lexical.COMMAND_PRIORITY_HIGH));
|
654
|
-
const deleteTextHandler = command => () => {
|
655
|
-
const selection = lexical.$getSelection();
|
656
|
-
if (!$isSelectionInTable(selection, tableNode)) {
|
657
|
-
return false;
|
658
|
-
}
|
659
|
-
if (lexical.DEPRECATED_$isGridSelection(selection)) {
|
660
|
-
tableSelection.clearText();
|
661
|
-
return true;
|
662
|
-
} else if (lexical.$isRangeSelection(selection)) {
|
663
|
-
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
664
|
-
if (!$isTableCellNode(tableCellNode)) {
|
665
|
-
return false;
|
666
|
-
}
|
667
|
-
const anchorNode = selection.anchor.getNode();
|
668
|
-
const focusNode = selection.focus.getNode();
|
669
|
-
const isAnchorInside = tableNode.isParentOf(anchorNode);
|
670
|
-
const isFocusInside = tableNode.isParentOf(focusNode);
|
671
|
-
const selectionContainsPartialTable = isAnchorInside && !isFocusInside || isFocusInside && !isAnchorInside;
|
672
|
-
if (selectionContainsPartialTable) {
|
673
|
-
tableSelection.clearText();
|
674
|
-
return true;
|
675
|
-
}
|
676
|
-
const nearestElementNode = utils.$findMatchingParent(selection.anchor.getNode(), n => lexical.$isElementNode(n));
|
677
|
-
const topLevelCellElementNode = nearestElementNode && utils.$findMatchingParent(nearestElementNode, n => lexical.$isElementNode(n) && $isTableCellNode(n.getParent()));
|
678
|
-
if (!lexical.$isElementNode(topLevelCellElementNode) || !lexical.$isElementNode(nearestElementNode)) {
|
679
|
-
return false;
|
680
|
-
}
|
681
|
-
if (command === lexical.DELETE_LINE_COMMAND && topLevelCellElementNode.getPreviousSibling() === null) {
|
682
|
-
// TODO: Fix Delete Line in Table Cells.
|
683
|
-
return true;
|
684
|
-
}
|
685
|
-
if (command === lexical.DELETE_CHARACTER_COMMAND || command === lexical.DELETE_WORD_COMMAND) {
|
686
|
-
if (selection.isCollapsed() && selection.anchor.offset === 0) {
|
687
|
-
if (nearestElementNode !== topLevelCellElementNode) {
|
688
|
-
const children = nearestElementNode.getChildren();
|
689
|
-
const newParagraphNode = lexical.$createParagraphNode();
|
690
|
-
children.forEach(child => newParagraphNode.append(child));
|
691
|
-
nearestElementNode.replace(newParagraphNode);
|
692
|
-
nearestElementNode.getWritable().__parent = tableCellNode.getKey();
|
693
|
-
return true;
|
694
|
-
}
|
695
|
-
}
|
696
|
-
}
|
697
|
-
}
|
698
|
-
return false;
|
699
|
-
};
|
700
|
-
[lexical.DELETE_WORD_COMMAND, lexical.DELETE_LINE_COMMAND, lexical.DELETE_CHARACTER_COMMAND].forEach(command => {
|
701
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(command, deleteTextHandler(command), lexical.COMMAND_PRIORITY_CRITICAL));
|
702
|
-
});
|
703
|
-
const deleteCellHandler = event => {
|
704
|
-
const selection = lexical.$getSelection();
|
705
|
-
if (!$isSelectionInTable(selection, tableNode)) {
|
706
|
-
return false;
|
707
|
-
}
|
708
|
-
if (lexical.DEPRECATED_$isGridSelection(selection)) {
|
709
|
-
event.preventDefault();
|
710
|
-
event.stopPropagation();
|
711
|
-
tableSelection.clearText();
|
712
|
-
return true;
|
713
|
-
} else if (lexical.$isRangeSelection(selection)) {
|
714
|
-
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
715
|
-
if (!$isTableCellNode(tableCellNode)) {
|
716
|
-
return false;
|
717
|
-
}
|
718
|
-
}
|
719
|
-
return false;
|
720
|
-
};
|
721
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_BACKSPACE_COMMAND, deleteCellHandler, lexical.COMMAND_PRIORITY_CRITICAL));
|
722
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_DELETE_COMMAND, deleteCellHandler, lexical.COMMAND_PRIORITY_CRITICAL));
|
723
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.FORMAT_TEXT_COMMAND, payload => {
|
724
|
-
const selection = lexical.$getSelection();
|
725
|
-
if (!$isSelectionInTable(selection, tableNode)) {
|
726
|
-
return false;
|
727
|
-
}
|
728
|
-
if (lexical.DEPRECATED_$isGridSelection(selection)) {
|
729
|
-
tableSelection.formatCells(payload);
|
730
|
-
return true;
|
731
|
-
} else if (lexical.$isRangeSelection(selection)) {
|
732
|
-
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
733
|
-
if (!$isTableCellNode(tableCellNode)) {
|
734
|
-
return false;
|
735
|
-
}
|
736
|
-
}
|
737
|
-
return false;
|
738
|
-
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
739
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.CONTROLLED_TEXT_INSERTION_COMMAND, payload => {
|
740
|
-
const selection = lexical.$getSelection();
|
741
|
-
if (!$isSelectionInTable(selection, tableNode)) {
|
742
|
-
return false;
|
743
|
-
}
|
744
|
-
if (lexical.DEPRECATED_$isGridSelection(selection)) {
|
745
|
-
tableSelection.clearHighlight();
|
746
|
-
return false;
|
747
|
-
} else if (lexical.$isRangeSelection(selection)) {
|
748
|
-
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
749
|
-
if (!$isTableCellNode(tableCellNode)) {
|
750
|
-
return false;
|
751
|
-
}
|
752
|
-
}
|
753
|
-
return false;
|
754
|
-
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
755
|
-
if (hasTabHandler) {
|
756
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.KEY_TAB_COMMAND, event => {
|
757
|
-
const selection = lexical.$getSelection();
|
758
|
-
if (!lexical.$isRangeSelection(selection) || !selection.isCollapsed() || !$isSelectionInTable(selection, tableNode)) {
|
759
|
-
return false;
|
760
|
-
}
|
761
|
-
const tableCellNode = $findCellNode(selection.anchor.getNode());
|
762
|
-
if (tableCellNode === null) {
|
763
|
-
return false;
|
764
|
-
}
|
765
|
-
stopEvent(event);
|
766
|
-
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
767
|
-
selectGridNodeInDirection(tableSelection, tableNode, currentCords.x, currentCords.y, !event.shiftKey ? 'forward' : 'backward');
|
768
|
-
return true;
|
769
|
-
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
770
|
-
}
|
771
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.FOCUS_COMMAND, payload => {
|
772
|
-
return tableNode.isSelected();
|
773
|
-
}, lexical.COMMAND_PRIORITY_HIGH));
|
774
|
-
function getCellFromCellNode(tableCellNode) {
|
775
|
-
const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableSelection.grid);
|
776
|
-
return tableNode.getCellFromCordsOrThrow(currentCords.x, currentCords.y, tableSelection.grid);
|
777
|
-
}
|
778
|
-
tableSelection.listenersToRemove.add(editor.registerCommand(lexical.SELECTION_CHANGE_COMMAND, () => {
|
779
|
-
const selection = lexical.$getSelection();
|
780
|
-
const prevSelection = lexical.$getPreviousSelection();
|
781
|
-
if (lexical.$isRangeSelection(selection)) {
|
782
|
-
const {
|
783
|
-
anchor,
|
784
|
-
focus
|
785
|
-
} = selection;
|
786
|
-
const anchorNode = anchor.getNode();
|
787
|
-
const focusNode = focus.getNode();
|
788
|
-
// Using explicit comparison with table node to ensure it's not a nested table
|
789
|
-
// as in that case we'll leave selection resolving to that table
|
790
|
-
const anchorCellNode = $findCellNode(anchorNode);
|
791
|
-
const focusCellNode = $findCellNode(focusNode);
|
792
|
-
const isAnchorInside = anchorCellNode && tableNode.is($findTableNode(anchorCellNode));
|
793
|
-
const isFocusInside = focusCellNode && tableNode.is($findTableNode(focusCellNode));
|
794
|
-
const isPartialyWithinTable = isAnchorInside !== isFocusInside;
|
795
|
-
const isWithinTable = isAnchorInside && isFocusInside;
|
796
|
-
const isBackward = selection.isBackward();
|
797
|
-
if (isPartialyWithinTable) {
|
798
|
-
const newSelection = selection.clone();
|
799
|
-
newSelection.focus.set(tableNode.getKey(), isBackward ? 0 : tableNode.getChildrenSize(), 'element');
|
800
|
-
lexical.$setSelection(newSelection);
|
801
|
-
$addHighlightStyleToTable(editor, tableSelection);
|
802
|
-
} else if (isWithinTable) {
|
803
|
-
// Handle case when selection spans across multiple cells but still
|
804
|
-
// has range selection, then we convert it into grid selection
|
805
|
-
if (!anchorCellNode.is(focusCellNode)) {
|
806
|
-
tableSelection.setAnchorCellForSelection(getCellFromCellNode(anchorCellNode));
|
807
|
-
tableSelection.setFocusCellForSelection(getCellFromCellNode(focusCellNode), true);
|
808
|
-
}
|
809
|
-
}
|
810
|
-
}
|
811
|
-
if (selection && !selection.is(prevSelection) && (lexical.DEPRECATED_$isGridSelection(selection) || lexical.DEPRECATED_$isGridSelection(prevSelection)) && tableSelection.gridSelection && !tableSelection.gridSelection.is(prevSelection)) {
|
812
|
-
if (lexical.DEPRECATED_$isGridSelection(selection) && selection.gridKey === tableSelection.tableNodeKey) {
|
813
|
-
tableSelection.updateTableGridSelection(selection);
|
814
|
-
} else if (!lexical.DEPRECATED_$isGridSelection(selection) && lexical.DEPRECATED_$isGridSelection(prevSelection) && prevSelection.gridKey === tableSelection.tableNodeKey) {
|
815
|
-
tableSelection.updateTableGridSelection(null);
|
816
|
-
}
|
817
|
-
return false;
|
818
|
-
}
|
819
|
-
if (tableSelection.hasHijackedSelectionStyles && !tableNode.isSelected()) {
|
820
|
-
$removeHighlightStyleToTable(editor, tableSelection);
|
821
|
-
} else if (!tableSelection.hasHijackedSelectionStyles && tableNode.isSelected()) {
|
822
|
-
$addHighlightStyleToTable(editor, tableSelection);
|
823
|
-
}
|
824
|
-
return false;
|
825
|
-
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
826
|
-
return tableSelection;
|
827
|
-
}
|
828
|
-
function attachTableSelectionToTableElement(tableElement, tableSelection) {
|
829
|
-
tableElement[LEXICAL_ELEMENT_KEY] = tableSelection;
|
830
|
-
}
|
831
|
-
function getTableSelectionFromTableElement(tableElement) {
|
832
|
-
return tableElement[LEXICAL_ELEMENT_KEY];
|
833
|
-
}
|
834
|
-
function getCellFromTarget(node) {
|
835
|
-
let currentNode = node;
|
836
|
-
while (currentNode != null) {
|
837
|
-
const nodeName = currentNode.nodeName;
|
838
|
-
if (nodeName === 'TD' || nodeName === 'TH') {
|
839
|
-
// @ts-expect-error: internal field
|
840
|
-
const cell = currentNode._cell;
|
841
|
-
if (cell === undefined) {
|
842
|
-
return null;
|
843
|
-
}
|
844
|
-
return cell;
|
845
|
-
}
|
846
|
-
currentNode = currentNode.parentNode;
|
847
|
-
}
|
848
|
-
return null;
|
849
|
-
}
|
850
|
-
function getTableGrid(tableElement) {
|
851
|
-
const cells = [];
|
852
|
-
const grid = {
|
853
|
-
cells,
|
854
|
-
columns: 0,
|
855
|
-
rows: 0
|
856
|
-
};
|
857
|
-
let currentNode = tableElement.firstChild;
|
858
|
-
let x = 0;
|
859
|
-
let y = 0;
|
860
|
-
cells.length = 0;
|
861
|
-
while (currentNode != null) {
|
862
|
-
const nodeMame = currentNode.nodeName;
|
863
|
-
if (nodeMame === 'TD' || nodeMame === 'TH') {
|
864
|
-
const elem = currentNode;
|
865
|
-
const cell = {
|
866
|
-
elem,
|
867
|
-
hasBackgroundColor: elem.style.backgroundColor !== '',
|
868
|
-
highlighted: false,
|
869
|
-
x,
|
870
|
-
y
|
871
|
-
};
|
872
|
-
|
873
|
-
// @ts-expect-error: internal field
|
874
|
-
currentNode._cell = cell;
|
875
|
-
let row = cells[y];
|
876
|
-
if (row === undefined) {
|
877
|
-
row = cells[y] = [];
|
878
|
-
}
|
879
|
-
row[x] = cell;
|
880
|
-
} else {
|
881
|
-
const child = currentNode.firstChild;
|
882
|
-
if (child != null) {
|
883
|
-
currentNode = child;
|
884
|
-
continue;
|
885
|
-
}
|
886
|
-
}
|
887
|
-
const sibling = currentNode.nextSibling;
|
888
|
-
if (sibling != null) {
|
889
|
-
x++;
|
890
|
-
currentNode = sibling;
|
891
|
-
continue;
|
892
|
-
}
|
893
|
-
const parent = currentNode.parentNode;
|
894
|
-
if (parent != null) {
|
895
|
-
const parentSibling = parent.nextSibling;
|
896
|
-
if (parentSibling == null) {
|
897
|
-
break;
|
898
|
-
}
|
899
|
-
y++;
|
900
|
-
x = 0;
|
901
|
-
currentNode = parentSibling;
|
902
|
-
}
|
903
|
-
}
|
904
|
-
grid.columns = x + 1;
|
905
|
-
grid.rows = y + 1;
|
906
|
-
return grid;
|
907
|
-
}
|
908
|
-
function $updateDOMForSelection(editor, grid, selection) {
|
909
|
-
const selectedCellNodes = new Set(selection ? selection.getNodes() : []);
|
910
|
-
$forEachGridCell(grid, (cell, lexicalNode) => {
|
911
|
-
const elem = cell.elem;
|
912
|
-
if (selectedCellNodes.has(lexicalNode)) {
|
913
|
-
cell.highlighted = true;
|
914
|
-
$addHighlightToDOM(editor, cell);
|
915
|
-
} else {
|
916
|
-
cell.highlighted = false;
|
917
|
-
$removeHighlightFromDOM(editor, cell);
|
918
|
-
if (!elem.getAttribute('style')) {
|
919
|
-
elem.removeAttribute('style');
|
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
|
+
});
|
1577
|
+
};
|
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 => {
|
1585
|
+
const selection = lexical.$getSelection();
|
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;
|
920
1592
|
}
|
921
1593
|
}
|
922
|
-
|
923
|
-
}
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
for (let y = 0; y < cells.length; y++) {
|
929
|
-
const row = cells[y];
|
930
|
-
if (!row) {
|
931
|
-
continue;
|
1594
|
+
return false;
|
1595
|
+
}, lexical.COMMAND_PRIORITY_HIGH));
|
1596
|
+
const deleteTextHandler = command => () => {
|
1597
|
+
const selection = lexical.$getSelection();
|
1598
|
+
if (!$isSelectionInTable(selection, tableNode)) {
|
1599
|
+
return false;
|
932
1600
|
}
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
1601
|
+
if ($isTableSelection(selection)) {
|
1602
|
+
tableObserver.clearText();
|
1603
|
+
return true;
|
1604
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
1605
|
+
const tableCellNode = utils.$findMatchingParent(selection.anchor.getNode(), n => $isTableCellNode(n));
|
1606
|
+
if (!$isTableCellNode(tableCellNode)) {
|
1607
|
+
return false;
|
937
1608
|
}
|
938
|
-
const
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
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;
|
1617
|
+
}
|
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)) {
|
1621
|
+
return false;
|
1622
|
+
}
|
1623
|
+
if (command === lexical.DELETE_LINE_COMMAND && topLevelCellElementNode.getPreviousSibling() === null) {
|
1624
|
+
// TODO: Fix Delete Line in Table Cells.
|
1625
|
+
return true;
|
1626
|
+
}
|
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
|
+
}
|
944
1638
|
}
|
945
1639
|
}
|
946
|
-
|
947
|
-
}
|
948
|
-
|
949
|
-
|
950
|
-
$forEachGridCell(tableSelection.grid, cell => {
|
951
|
-
cell.highlighted = true;
|
952
|
-
$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));
|
953
1644
|
});
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
const elem = cell.elem;
|
959
|
-
cell.highlighted = false;
|
960
|
-
$removeHighlightFromDOM(editor, cell);
|
961
|
-
if (!elem.getAttribute('style')) {
|
962
|
-
elem.removeAttribute('style');
|
1645
|
+
const deleteCellHandler = event => {
|
1646
|
+
const selection = lexical.$getSelection();
|
1647
|
+
if (!$isSelectionInTable(selection, tableNode)) {
|
1648
|
+
return false;
|
963
1649
|
}
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
switch (direction) {
|
969
|
-
case 'backward':
|
970
|
-
case 'forward':
|
971
|
-
if (x !== (isForward ? tableSelection.grid.columns - 1 : 0)) {
|
972
|
-
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x + (isForward ? 1 : -1), y, tableSelection.grid), isForward);
|
973
|
-
} else {
|
974
|
-
if (y !== (isForward ? tableSelection.grid.rows - 1 : 0)) {
|
975
|
-
selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(isForward ? 0 : tableSelection.grid.columns - 1, y + (isForward ? 1 : -1), tableSelection.grid), isForward);
|
976
|
-
} else if (!isForward) {
|
977
|
-
tableNode.selectPrevious();
|
978
|
-
} else {
|
979
|
-
tableNode.selectNext();
|
980
|
-
}
|
981
|
-
}
|
1650
|
+
if ($isTableSelection(selection)) {
|
1651
|
+
event.preventDefault();
|
1652
|
+
event.stopPropagation();
|
1653
|
+
tableObserver.clearText();
|
982
1654
|
return true;
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
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;
|
988
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);
|
989
1672
|
return true;
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
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;
|
995
1677
|
}
|
996
|
-
|
997
|
-
|
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)) {
|
998
1684
|
return false;
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
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;
|
1008
1693
|
}
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
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)) {
|
1015
1701
|
return false;
|
1016
1702
|
}
|
1017
|
-
|
1018
|
-
if (
|
1019
|
-
tableSelection.setFocusCellForSelection(tableNode.getCellFromCordsOrThrow(x, y + 1, tableSelection.grid));
|
1020
|
-
return true;
|
1021
|
-
} else {
|
1703
|
+
const tableCellNode = $findCellNode(selection.anchor.getNode());
|
1704
|
+
if (tableCellNode === null) {
|
1022
1705
|
return false;
|
1023
1706
|
}
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
if (lexical.$isRangeSelection(selection) || lexical.DEPRECATED_$isGridSelection(selection)) {
|
1030
|
-
const isAnchorInside = tableNode.isParentOf(selection.anchor.getNode());
|
1031
|
-
const isFocusInside = tableNode.isParentOf(selection.focus.getNode());
|
1032
|
-
return isAnchorInside && isFocusInside;
|
1033
|
-
}
|
1034
|
-
return false;
|
1035
|
-
}
|
1036
|
-
function selectTableCellNode(tableCell, fromStart) {
|
1037
|
-
if (fromStart) {
|
1038
|
-
tableCell.selectStart();
|
1039
|
-
} else {
|
1040
|
-
tableCell.selectEnd();
|
1041
|
-
}
|
1042
|
-
}
|
1043
|
-
const BROWSER_BLUE_RGB = '172,206,247';
|
1044
|
-
function $addHighlightToDOM(editor, cell) {
|
1045
|
-
const element = cell.elem;
|
1046
|
-
const node = lexical.$getNearestNodeFromDOMNode(element);
|
1047
|
-
if (!$isTableCellNode(node)) {
|
1048
|
-
throw Error(`Expected to find LexicalNode from Table Cell DOMNode`);
|
1049
|
-
}
|
1050
|
-
const backgroundColor = node.getBackgroundColor();
|
1051
|
-
if (backgroundColor === null) {
|
1052
|
-
element.style.setProperty('background-color', `rgb(${BROWSER_BLUE_RGB})`);
|
1053
|
-
} else {
|
1054
|
-
element.style.setProperty('background-image', `linear-gradient(to right, rgba(${BROWSER_BLUE_RGB},0.85), rgba(${BROWSER_BLUE_RGB},0.85))`);
|
1055
|
-
}
|
1056
|
-
element.style.setProperty('caret-color', 'transparent');
|
1057
|
-
}
|
1058
|
-
function $removeHighlightFromDOM(editor, cell) {
|
1059
|
-
const element = cell.elem;
|
1060
|
-
const node = lexical.$getNearestNodeFromDOMNode(element);
|
1061
|
-
if (!$isTableCellNode(node)) {
|
1062
|
-
throw Error(`Expected to find LexicalNode from Table Cell DOMNode`);
|
1063
|
-
}
|
1064
|
-
const backgroundColor = node.getBackgroundColor();
|
1065
|
-
if (backgroundColor === null) {
|
1066
|
-
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));
|
1067
1712
|
}
|
1068
|
-
|
1069
|
-
|
1070
|
-
}
|
1071
|
-
function
|
1072
|
-
|
1073
|
-
|
1074
|
-
}
|
1075
|
-
function $findTableNode(node) {
|
1076
|
-
const tableNode = utils.$findMatchingParent(node, $isTableNode);
|
1077
|
-
return $isTableNode(tableNode) ? tableNode : null;
|
1078
|
-
}
|
1079
|
-
function $handleArrowKey(editor, event, direction, tableNode, tableSelection) {
|
1080
|
-
const selection = lexical.$getSelection();
|
1081
|
-
if (!$isSelectionInTable(selection, tableNode)) {
|
1082
|
-
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);
|
1083
1719
|
}
|
1084
|
-
|
1085
|
-
// Horizontal move between cels seem to work well without interruption
|
1086
|
-
// so just exit early, and handle vertical moves
|
1087
|
-
if (direction === 'backward' || direction === 'forward') {
|
1088
|
-
return false;
|
1089
|
-
}
|
1720
|
+
tableObserver.listenersToRemove.add(editor.registerCommand(lexical.SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, selectionPayload => {
|
1090
1721
|
const {
|
1091
|
-
|
1092
|
-
|
1093
|
-
} =
|
1094
|
-
const
|
1095
|
-
const
|
1096
|
-
|
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) {
|
1097
1730
|
return false;
|
1098
1731
|
}
|
1099
|
-
const
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
const anchorDOM = editor.getElementByKey(anchor.key);
|
1109
|
-
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)) {
|
1110
1741
|
return false;
|
1111
1742
|
}
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
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)) {
|
1118
1758
|
return false;
|
1119
1759
|
}
|
1120
|
-
const
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
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++;
|
1126
1795
|
}
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1796
|
+
if (newAnchorCellKey && newFocusCellKey) {
|
1797
|
+
const newTableSelection = $createTableSelection();
|
1798
|
+
newTableSelection.set(nodes[0].getKey(), newAnchorCellKey, newFocusCellKey);
|
1799
|
+
lexical.$setSelection(newTableSelection);
|
1130
1800
|
}
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
}
|
1141
|
-
|
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
|
+
}
|
1142
1834
|
}
|
1143
|
-
return true;
|
1144
1835
|
}
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
const focusCellNode = utils.$findMatchingParent(focus.getNode(), $isTableCellNode);
|
1152
|
-
const [tableNodeFromSelection] = selection.getNodes();
|
1153
|
-
const tableElement = editor.getElementByKey(tableNodeFromSelection.getKey());
|
1154
|
-
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
|
+
}
|
1155
1842
|
return false;
|
1156
1843
|
}
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
tableSelection.setAnchorCellForSelection(anchorCell);
|
1162
|
-
stopEvent(event);
|
1163
|
-
if (event.shiftKey) {
|
1164
|
-
const cords = tableNode.getCordsFromCellNode(focusCellNode, grid);
|
1165
|
-
return adjustFocusNodeInDirection(tableSelection, tableNodeFromSelection, cords.x, cords.y, direction);
|
1166
|
-
} else {
|
1167
|
-
focusCellNode.selectEnd();
|
1844
|
+
if (tableObserver.hasHijackedSelectionStyles && !tableNode.isSelected()) {
|
1845
|
+
$removeHighlightStyleToTable(editor, tableObserver);
|
1846
|
+
} else if (!tableObserver.hasHijackedSelectionStyles && tableNode.isSelected()) {
|
1847
|
+
$addHighlightStyleToTable(editor, tableObserver);
|
1168
1848
|
}
|
1169
|
-
return
|
1170
|
-
}
|
1171
|
-
return
|
1849
|
+
return false;
|
1850
|
+
}, lexical.COMMAND_PRIORITY_CRITICAL));
|
1851
|
+
return tableObserver;
|
1172
1852
|
}
|
1173
|
-
function
|
1174
|
-
|
1175
|
-
event.stopImmediatePropagation();
|
1176
|
-
event.stopPropagation();
|
1853
|
+
function attachTableObserverToTableElement(tableElement, tableObserver) {
|
1854
|
+
tableElement[LEXICAL_ELEMENT_KEY] = tableObserver;
|
1177
1855
|
}
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
static getType() {
|
1191
|
-
return 'table';
|
1192
|
-
}
|
1193
|
-
static clone(node) {
|
1194
|
-
return new TableNode(node.__key);
|
1195
|
-
}
|
1196
|
-
static importDOM() {
|
1197
|
-
return {
|
1198
|
-
table: _node => ({
|
1199
|
-
conversion: convertTableElement,
|
1200
|
-
priority: 1
|
1201
|
-
})
|
1202
|
-
};
|
1203
|
-
}
|
1204
|
-
static importJSON(_serializedNode) {
|
1205
|
-
return $createTableNode();
|
1206
|
-
}
|
1207
|
-
constructor(key) {
|
1208
|
-
super(key);
|
1209
|
-
}
|
1210
|
-
exportJSON() {
|
1211
|
-
return {
|
1212
|
-
...super.exportJSON(),
|
1213
|
-
type: 'table',
|
1214
|
-
version: 1
|
1215
|
-
};
|
1216
|
-
}
|
1217
|
-
createDOM(config, editor) {
|
1218
|
-
const tableElement = document.createElement('table');
|
1219
|
-
utils.addClassNamesToElement(tableElement, config.theme.table);
|
1220
|
-
return tableElement;
|
1221
|
-
}
|
1222
|
-
updateDOM() {
|
1223
|
-
return false;
|
1224
|
-
}
|
1225
|
-
exportDOM(editor) {
|
1226
|
-
return {
|
1227
|
-
...super.exportDOM(editor),
|
1228
|
-
after: tableElement => {
|
1229
|
-
if (tableElement) {
|
1230
|
-
const newElement = tableElement.cloneNode();
|
1231
|
-
const colGroup = document.createElement('colgroup');
|
1232
|
-
const tBody = document.createElement('tbody');
|
1233
|
-
if (utils.isHTMLElement(tableElement)) {
|
1234
|
-
tBody.append(...tableElement.children);
|
1235
|
-
}
|
1236
|
-
const firstRow = this.getFirstChildOrThrow();
|
1237
|
-
if (!$isTableRowNode(firstRow)) {
|
1238
|
-
throw new Error('Expected to find row node.');
|
1239
|
-
}
|
1240
|
-
const colCount = firstRow.getChildrenSize();
|
1241
|
-
for (let i = 0; i < colCount; i++) {
|
1242
|
-
const col = document.createElement('col');
|
1243
|
-
colGroup.append(col);
|
1244
|
-
}
|
1245
|
-
newElement.replaceChildren(colGroup, tBody);
|
1246
|
-
return newElement;
|
1247
|
-
}
|
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;
|
1248
1868
|
}
|
1249
|
-
|
1869
|
+
return cell;
|
1870
|
+
}
|
1871
|
+
currentNode = currentNode.parentNode;
|
1250
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
|
+
};
|
1251
1897
|
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
return false;
|
1258
|
-
}
|
1259
|
-
isShadowRoot() {
|
1260
|
-
return true;
|
1261
|
-
}
|
1262
|
-
getCordsFromCellNode(tableCellNode, grid) {
|
1263
|
-
const {
|
1264
|
-
rows,
|
1265
|
-
cells
|
1266
|
-
} = grid;
|
1267
|
-
for (let y = 0; y < rows; y++) {
|
1268
|
-
const row = cells[y];
|
1269
|
-
if (row == null) {
|
1270
|
-
continue;
|
1898
|
+
// @ts-expect-error: internal field
|
1899
|
+
currentNode._cell = cell;
|
1900
|
+
let row = domRows[y];
|
1901
|
+
if (row === undefined) {
|
1902
|
+
row = domRows[y] = [];
|
1271
1903
|
}
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
return cellNode === tableCellNode;
|
1279
|
-
});
|
1280
|
-
if (x !== -1) {
|
1281
|
-
return {
|
1282
|
-
x,
|
1283
|
-
y
|
1284
|
-
};
|
1904
|
+
row[x] = cell;
|
1905
|
+
} else {
|
1906
|
+
const child = currentNode.firstChild;
|
1907
|
+
if (child != null) {
|
1908
|
+
currentNode = child;
|
1909
|
+
continue;
|
1285
1910
|
}
|
1286
1911
|
}
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
} = grid;
|
1293
|
-
const row = cells[y];
|
1294
|
-
if (row == null) {
|
1295
|
-
return null;
|
1912
|
+
const sibling = currentNode.nextSibling;
|
1913
|
+
if (sibling != null) {
|
1914
|
+
x++;
|
1915
|
+
currentNode = sibling;
|
1916
|
+
continue;
|
1296
1917
|
}
|
1297
|
-
const
|
1298
|
-
if (
|
1299
|
-
|
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;
|
1300
1927
|
}
|
1301
|
-
return cell;
|
1302
1928
|
}
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
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
|
+
}
|
1307
1946
|
}
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
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;
|
1314
1957
|
}
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
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
|
+
}
|
1318
1970
|
}
|
1319
|
-
return null;
|
1320
1971
|
}
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
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');
|
1325
1988
|
}
|
1326
|
-
|
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;
|
1327
2024
|
}
|
1328
|
-
|
1329
|
-
|
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;
|
1330
2051
|
}
|
1331
|
-
|
1332
|
-
|
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;
|
1333
2058
|
}
|
2059
|
+
return false;
|
1334
2060
|
}
|
1335
|
-
function
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
2061
|
+
function selectTableCellNode(tableCell, fromStart) {
|
2062
|
+
if (fromStart) {
|
2063
|
+
tableCell.selectStart();
|
2064
|
+
} else {
|
2065
|
+
tableCell.selectEnd();
|
1339
2066
|
}
|
1340
|
-
return getTableGrid(tableElement);
|
1341
|
-
}
|
1342
|
-
function convertTableElement(_domNode) {
|
1343
|
-
return {
|
1344
|
-
node: $createTableNode()
|
1345
|
-
};
|
1346
|
-
}
|
1347
|
-
function $createTableNode() {
|
1348
|
-
return lexical.$applyNodeReplacement(new TableNode());
|
1349
|
-
}
|
1350
|
-
function $isTableNode(node) {
|
1351
|
-
return node instanceof TableNode;
|
1352
2067
|
}
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
*
|
1360
|
-
*/
|
1361
|
-
function $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders = true) {
|
1362
|
-
const tableNode = $createTableNode();
|
1363
|
-
for (let iRow = 0; iRow < rowCount; iRow++) {
|
1364
|
-
const tableRowNode = $createTableRowNode();
|
1365
|
-
for (let iColumn = 0; iColumn < columnCount; iColumn++) {
|
1366
|
-
let headerState = TableCellHeaderStates.NO_STATUS;
|
1367
|
-
if (typeof includeHeaders === 'object') {
|
1368
|
-
if (iRow === 0 && includeHeaders.rows) headerState |= TableCellHeaderStates.ROW;
|
1369
|
-
if (iColumn === 0 && includeHeaders.columns) headerState |= TableCellHeaderStates.COLUMN;
|
1370
|
-
} else if (includeHeaders) {
|
1371
|
-
if (iRow === 0) headerState |= TableCellHeaderStates.ROW;
|
1372
|
-
if (iColumn === 0) headerState |= TableCellHeaderStates.COLUMN;
|
1373
|
-
}
|
1374
|
-
const tableCellNode = $createTableCellNode(headerState);
|
1375
|
-
const paragraphNode = lexical.$createParagraphNode();
|
1376
|
-
paragraphNode.append(lexical.$createTextNode());
|
1377
|
-
tableCellNode.append(paragraphNode);
|
1378
|
-
tableRowNode.append(tableCellNode);
|
1379
|
-
}
|
1380
|
-
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`);
|
1381
2074
|
}
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
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))`);
|
1388
2080
|
}
|
1389
|
-
|
2081
|
+
element.style.setProperty('caret-color', 'transparent');
|
1390
2082
|
}
|
1391
|
-
function $
|
1392
|
-
const
|
1393
|
-
|
1394
|
-
|
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`);
|
1395
2088
|
}
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
const node = utils.$findMatchingParent(startingNode, n => $isTableNode(n));
|
1400
|
-
if ($isTableNode(node)) {
|
1401
|
-
return node;
|
2089
|
+
const backgroundColor = node.getBackgroundColor();
|
2090
|
+
if (backgroundColor === null) {
|
2091
|
+
element.style.removeProperty('background-color');
|
1402
2092
|
}
|
1403
|
-
|
1404
|
-
|
1405
|
-
function $getTableRowIndexFromTableCellNode(tableCellNode) {
|
1406
|
-
const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode);
|
1407
|
-
const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableRowNode);
|
1408
|
-
return tableNode.getChildren().findIndex(n => n.is(tableRowNode));
|
1409
|
-
}
|
1410
|
-
function $getTableColumnIndexFromTableCellNode(tableCellNode) {
|
1411
|
-
const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode);
|
1412
|
-
return tableRowNode.getChildren().findIndex(n => n.is(tableCellNode));
|
2093
|
+
element.style.removeProperty('background-image');
|
2094
|
+
element.style.removeProperty('caret-color');
|
1413
2095
|
}
|
1414
|
-
function $
|
1415
|
-
const
|
1416
|
-
|
1417
|
-
x,
|
1418
|
-
y
|
1419
|
-
} = tableNode.getCordsFromCellNode(tableCellNode, grid);
|
1420
|
-
return {
|
1421
|
-
above: tableNode.getCellNodeFromCords(x, y - 1, grid),
|
1422
|
-
below: tableNode.getCellNodeFromCords(x, y + 1, grid),
|
1423
|
-
left: tableNode.getCellNodeFromCords(x - 1, y, grid),
|
1424
|
-
right: tableNode.getCellNodeFromCords(x + 1, y, grid)
|
1425
|
-
};
|
2096
|
+
function $findCellNode(node) {
|
2097
|
+
const cellNode = utils.$findMatchingParent(node, $isTableCellNode);
|
2098
|
+
return $isTableCellNode(cellNode) ? cellNode : null;
|
1426
2099
|
}
|
1427
|
-
function $
|
1428
|
-
const
|
1429
|
-
|
1430
|
-
throw new Error('Expected table cell to be inside of table row.');
|
1431
|
-
}
|
1432
|
-
const targetRowNode = tableRows[indexToDelete];
|
1433
|
-
targetRowNode.remove();
|
1434
|
-
return tableNode;
|
2100
|
+
function $findTableNode(node) {
|
2101
|
+
const tableNode = utils.$findMatchingParent(node, $isTableNode);
|
2102
|
+
return $isTableNode(tableNode) ? tableNode : null;
|
1435
2103
|
}
|
1436
|
-
function $
|
1437
|
-
const
|
1438
|
-
if (
|
1439
|
-
|
2104
|
+
function $handleArrowKey(editor, event, direction, tableNode, tableObserver) {
|
2105
|
+
const selection = lexical.$getSelection();
|
2106
|
+
if (!$isSelectionInTable(selection, tableNode)) {
|
2107
|
+
return false;
|
1440
2108
|
}
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
tableCellNode.append(lexical.$createParagraphNode());
|
1463
|
-
newTableRowNode.append(tableCellNode);
|
1464
|
-
}
|
1465
|
-
if (shouldInsertAfter) {
|
1466
|
-
targetRowNode.insertAfter(newTableRowNode);
|
1467
|
-
} else {
|
1468
|
-
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);
|
1469
2130
|
}
|
1470
2131
|
}
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
}
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
const [gridMap, focusCellMap] = lexical.DEPRECATED_$computeGridMap(grid, focusCell, focusCell);
|
1484
|
-
const columnCount = gridMap[0].length;
|
1485
|
-
const {
|
1486
|
-
startRow: focusStartRow
|
1487
|
-
} = focusCellMap;
|
1488
|
-
if (insertAfter) {
|
1489
|
-
const focusEndRow = focusStartRow + focusCell.__rowSpan - 1;
|
1490
|
-
const focusEndRowMap = gridMap[focusEndRow];
|
1491
|
-
const newRow = $createTableRowNode();
|
1492
|
-
for (let i = 0; i < columnCount; i++) {
|
1493
|
-
const {
|
1494
|
-
cell,
|
1495
|
-
startRow
|
1496
|
-
} = focusEndRowMap[i];
|
1497
|
-
if (startRow + cell.__rowSpan - 1 <= focusEndRow) {
|
1498
|
-
newRow.append($createTableCellNode(TableCellHeaderStates.NO_STATUS));
|
1499
|
-
} else {
|
1500
|
-
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;
|
1501
2144
|
}
|
2145
|
+
const range = domSelection.getRangeAt(0);
|
2146
|
+
edgeSelectionRect = range.getBoundingClientRect();
|
1502
2147
|
}
|
1503
|
-
const
|
1504
|
-
if (
|
1505
|
-
|
2148
|
+
const edgeChild = direction === 'up' ? anchorCellNode.getFirstChild() : anchorCellNode.getLastChild();
|
2149
|
+
if (edgeChild == null) {
|
2150
|
+
return false;
|
1506
2151
|
}
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
if (
|
1517
|
-
|
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);
|
1518
2165
|
} else {
|
1519
|
-
|
2166
|
+
return selectTableNodeInDirection(tableObserver, tableNode, cords.x, cords.y, direction);
|
1520
2167
|
}
|
2168
|
+
return true;
|
1521
2169
|
}
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
const currentTableRowNode = tableRows[r];
|
1534
|
-
if ($isTableRowNode(currentTableRowNode)) {
|
1535
|
-
for (let c = 0; c < columnCount; c++) {
|
1536
|
-
const tableRowChildren = currentTableRowNode.getChildren();
|
1537
|
-
if (targetIndex >= tableRowChildren.length || targetIndex < 0) {
|
1538
|
-
throw new Error('Table column target index out of range');
|
1539
|
-
}
|
1540
|
-
const targetCell = tableRowChildren[targetIndex];
|
1541
|
-
if (!$isTableCellNode(targetCell)) {
|
1542
|
-
throw Error(`Expected table cell`);
|
1543
|
-
}
|
1544
|
-
const {
|
1545
|
-
left,
|
1546
|
-
right
|
1547
|
-
} = $getTableCellSiblingsFromTableCellNode(targetCell, grid);
|
1548
|
-
let headerState = TableCellHeaderStates.NO_STATUS;
|
1549
|
-
if (left && left.hasHeaderState(TableCellHeaderStates.ROW) || right && right.hasHeaderState(TableCellHeaderStates.ROW)) {
|
1550
|
-
headerState |= TableCellHeaderStates.ROW;
|
1551
|
-
}
|
1552
|
-
const newTableCell = $createTableCellNode(headerState);
|
1553
|
-
newTableCell.append(lexical.$createParagraphNode());
|
1554
|
-
tableCellsToBeInserted.push({
|
1555
|
-
newTableCell,
|
1556
|
-
targetCell
|
1557
|
-
});
|
1558
|
-
}
|
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;
|
1559
2181
|
}
|
1560
|
-
|
1561
|
-
|
1562
|
-
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
1566
|
-
|
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);
|
1567
2191
|
} else {
|
1568
|
-
|
2192
|
+
focusCellNode.selectEnd();
|
1569
2193
|
}
|
1570
|
-
|
1571
|
-
|
2194
|
+
return true;
|
2195
|
+
}
|
2196
|
+
return false;
|
1572
2197
|
}
|
1573
|
-
function
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
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';
|
1577
2215
|
}
|
1578
|
-
|
1579
|
-
|
1580
|
-
const [anchorCell] = lexical.DEPRECATED_$getNodeTriplet(anchor);
|
1581
|
-
const [focusCell,, grid] = lexical.DEPRECATED_$getNodeTriplet(focus);
|
1582
|
-
const [gridMap, focusCellMap, anchorCellMap] = lexical.DEPRECATED_$computeGridMap(grid, focusCell, anchorCell);
|
1583
|
-
const rowCount = gridMap.length;
|
1584
|
-
const startColumn = insertAfter ? Math.max(focusCellMap.startColumn, anchorCellMap.startColumn) : Math.min(focusCellMap.startColumn, anchorCellMap.startColumn);
|
1585
|
-
const insertAfterColumn = insertAfter ? startColumn + focusCell.__colSpan - 1 : startColumn - 1;
|
1586
|
-
const gridFirstChild = grid.getFirstChild();
|
1587
|
-
if (!lexical.DEPRECATED_$isGridRowNode(gridFirstChild)) {
|
1588
|
-
throw Error(`Expected firstTable child to be a row`);
|
2216
|
+
static clone(node) {
|
2217
|
+
return new TableNode(node.__key);
|
1589
2218
|
}
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
2219
|
+
static importDOM() {
|
2220
|
+
return {
|
2221
|
+
table: _node => ({
|
2222
|
+
conversion: convertTableElement,
|
2223
|
+
priority: 1
|
2224
|
+
})
|
2225
|
+
};
|
1597
2226
|
}
|
1598
|
-
|
1599
|
-
|
1600
|
-
if (i !== 0) {
|
1601
|
-
const currentRow = loopRow.getNextSibling();
|
1602
|
-
if (!lexical.DEPRECATED_$isGridRowNode(currentRow)) {
|
1603
|
-
throw Error(`Expected row nextSibling to be a row`);
|
1604
|
-
}
|
1605
|
-
loopRow = currentRow;
|
1606
|
-
}
|
1607
|
-
const rowMap = gridMap[i];
|
1608
|
-
if (insertAfterColumn < 0) {
|
1609
|
-
$insertFirst(loopRow, $createTableCellNodeForInsertTableColumn());
|
1610
|
-
continue;
|
1611
|
-
}
|
1612
|
-
const {
|
1613
|
-
cell: currentCell,
|
1614
|
-
startColumn: currentStartColumn,
|
1615
|
-
startRow: currentStartRow
|
1616
|
-
} = rowMap[insertAfterColumn];
|
1617
|
-
if (currentStartColumn + currentCell.__colSpan - 1 <= insertAfterColumn) {
|
1618
|
-
let insertAfterCell = currentCell;
|
1619
|
-
let insertAfterCellRowStart = currentStartRow;
|
1620
|
-
let prevCellIndex = insertAfterColumn;
|
1621
|
-
while (insertAfterCellRowStart !== i && insertAfterCell.__rowSpan > 1) {
|
1622
|
-
prevCellIndex -= currentCell.__colSpan;
|
1623
|
-
if (prevCellIndex >= 0) {
|
1624
|
-
const {
|
1625
|
-
cell: cell_,
|
1626
|
-
startRow: startRow_
|
1627
|
-
} = rowMap[prevCellIndex];
|
1628
|
-
insertAfterCell = cell_;
|
1629
|
-
insertAfterCellRowStart = startRow_;
|
1630
|
-
} else {
|
1631
|
-
loopRow.append($createTableCellNodeForInsertTableColumn());
|
1632
|
-
continue rowLoop;
|
1633
|
-
}
|
1634
|
-
}
|
1635
|
-
insertAfterCell.insertAfter($createTableCellNodeForInsertTableColumn());
|
1636
|
-
} else {
|
1637
|
-
currentCell.setColSpan(currentCell.__colSpan + 1);
|
1638
|
-
}
|
2227
|
+
static importJSON(_serializedNode) {
|
2228
|
+
return $createTableNode();
|
1639
2229
|
}
|
1640
|
-
|
1641
|
-
|
2230
|
+
constructor(key) {
|
2231
|
+
super(key);
|
1642
2232
|
}
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
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
|
+
}
|
1652
2271
|
}
|
1653
|
-
|
1654
|
-
}
|
2272
|
+
};
|
1655
2273
|
}
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
1659
|
-
|
1660
|
-
if (!lexical.$INTERNAL_isPointSelection(selection)) {
|
1661
|
-
throw Error(`Expected a INTERNAL_PointSelection`);
|
2274
|
+
|
2275
|
+
// TODO 0.10 deprecate
|
2276
|
+
canExtractContents() {
|
2277
|
+
return false;
|
1662
2278
|
}
|
1663
|
-
|
1664
|
-
|
1665
|
-
const [anchorCell,, grid] = lexical.DEPRECATED_$getNodeTriplet(anchor);
|
1666
|
-
const [focusCell] = lexical.DEPRECATED_$getNodeTriplet(focus);
|
1667
|
-
const [gridMap, anchorCellMap, focusCellMap] = lexical.DEPRECATED_$computeGridMap(grid, anchorCell, focusCell);
|
1668
|
-
const {
|
1669
|
-
startRow: anchorStartRow
|
1670
|
-
} = anchorCellMap;
|
1671
|
-
const {
|
1672
|
-
startRow: focusStartRow
|
1673
|
-
} = focusCellMap;
|
1674
|
-
const focusEndRow = focusStartRow + focusCell.__rowSpan - 1;
|
1675
|
-
if (gridMap.length === focusEndRow - anchorStartRow + 1) {
|
1676
|
-
// Empty grid
|
1677
|
-
grid.remove();
|
1678
|
-
return;
|
2279
|
+
canBeEmpty() {
|
2280
|
+
return false;
|
1679
2281
|
}
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
1688
|
-
|
1689
|
-
|
1690
|
-
if (
|
1691
|
-
// 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) {
|
1692
2293
|
continue;
|
1693
2294
|
}
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
}
|
1707
|
-
const {
|
1708
|
-
cell: previousCell
|
1709
|
-
} = nextRow[column - 1];
|
1710
|
-
previousCell.insertAfter(cell);
|
1711
|
-
}
|
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
|
+
};
|
1712
2308
|
}
|
1713
2309
|
}
|
1714
|
-
|
1715
|
-
if (!lexical.DEPRECATED_$isGridRowNode(rowNode)) {
|
1716
|
-
throw Error(`Expected GridNode childAtIndex(${String(row)}) to be RowNode`);
|
1717
|
-
}
|
1718
|
-
rowNode.remove();
|
2310
|
+
throw new Error('Cell not found in table.');
|
1719
2311
|
}
|
1720
|
-
|
1721
|
-
const {
|
1722
|
-
cell
|
1723
|
-
} = nextRow[0];
|
1724
|
-
$moveSelectionToCell(cell);
|
1725
|
-
} else {
|
1726
|
-
const previousRow = gridMap[anchorStartRow - 1];
|
2312
|
+
getDOMCellFromCords(x, y, table) {
|
1727
2313
|
const {
|
1728
|
-
|
1729
|
-
} =
|
1730
|
-
|
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;
|
1731
2325
|
}
|
1732
|
-
|
1733
|
-
|
1734
|
-
|
1735
|
-
|
1736
|
-
|
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;
|
1737
2332
|
}
|
1738
|
-
|
1739
|
-
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
startColumn: focusStartColumn
|
1749
|
-
} = focusCellMap;
|
1750
|
-
const startColumn = Math.min(anchorStartColumn, focusStartColumn);
|
1751
|
-
const endColumn = Math.max(anchorStartColumn + anchorCell.__colSpan - 1, focusStartColumn + focusCell.__colSpan - 1);
|
1752
|
-
const selectedColumnCount = endColumn - startColumn + 1;
|
1753
|
-
const columnCount = gridMap[0].length;
|
1754
|
-
if (columnCount === endColumn - startColumn + 1) {
|
1755
|
-
// Empty grid
|
1756
|
-
grid.selectPrevious();
|
1757
|
-
grid.remove();
|
1758
|
-
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;
|
1759
2343
|
}
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
cell,
|
1765
|
-
startColumn: cellStartColumn
|
1766
|
-
} = gridMap[row][column];
|
1767
|
-
if (cellStartColumn < startColumn) {
|
1768
|
-
if (column === startColumn) {
|
1769
|
-
const overflowLeft = startColumn - cellStartColumn;
|
1770
|
-
// Overflowing left
|
1771
|
-
cell.setColSpan(cell.__colSpan -
|
1772
|
-
// Possible overflow right too
|
1773
|
-
Math.min(selectedColumnCount, cell.__colSpan - overflowLeft));
|
1774
|
-
}
|
1775
|
-
} else if (cellStartColumn + cell.__colSpan - 1 > endColumn) {
|
1776
|
-
if (column === endColumn) {
|
1777
|
-
// Overflowing right
|
1778
|
-
const inSelectedArea = endColumn - cellStartColumn + 1;
|
1779
|
-
cell.setColSpan(cell.__colSpan - inSelectedArea);
|
1780
|
-
}
|
1781
|
-
} else {
|
1782
|
-
cell.remove();
|
1783
|
-
}
|
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.');
|
1784
2348
|
}
|
2349
|
+
return node;
|
1785
2350
|
}
|
1786
|
-
|
1787
|
-
|
1788
|
-
if (nextColumn !== undefined) {
|
1789
|
-
const {
|
1790
|
-
cell
|
1791
|
-
} = nextColumn;
|
1792
|
-
$moveSelectionToCell(cell);
|
1793
|
-
} else {
|
1794
|
-
const previousRow = focusRowMap[focusStartColumn - 1];
|
1795
|
-
const {
|
1796
|
-
cell
|
1797
|
-
} = previousRow;
|
1798
|
-
$moveSelectionToCell(cell);
|
2351
|
+
canSelectBefore() {
|
2352
|
+
return true;
|
1799
2353
|
}
|
1800
|
-
|
1801
|
-
|
1802
|
-
const firstDescendant = cell.getFirstDescendant();
|
1803
|
-
if (firstDescendant == null) {
|
1804
|
-
cell.selectStart();
|
1805
|
-
} else {
|
1806
|
-
firstDescendant.getParentOrThrow().selectStart();
|
2354
|
+
canIndent() {
|
2355
|
+
return false;
|
1807
2356
|
}
|
1808
2357
|
}
|
1809
|
-
function $
|
1810
|
-
const
|
1811
|
-
if (
|
1812
|
-
|
1813
|
-
} else {
|
1814
|
-
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');
|
1815
2362
|
}
|
2363
|
+
return getTable(tableElement);
|
1816
2364
|
}
|
1817
|
-
function
|
1818
|
-
|
1819
|
-
|
1820
|
-
|
1821
|
-
|
1822
|
-
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
for (let i = 1; i < colSpan; i++) {
|
1828
|
-
cell.insertAfter($createTableCellNode(TableCellHeaderStates.NO_STATUS));
|
1829
|
-
}
|
1830
|
-
cell.setColSpan(1);
|
1831
|
-
}
|
1832
|
-
if (rowSpan > 1) {
|
1833
|
-
const [map, cellMap] = lexical.DEPRECATED_$computeGridMap(grid, cell, cell);
|
1834
|
-
const {
|
1835
|
-
startColumn,
|
1836
|
-
startRow
|
1837
|
-
} = cellMap;
|
1838
|
-
let currentRowNode;
|
1839
|
-
for (let i = 1; i < rowSpan; i++) {
|
1840
|
-
const currentRow = startRow + i;
|
1841
|
-
const currentRowMap = map[currentRow];
|
1842
|
-
currentRowNode = (currentRowNode || row).getNextSibling();
|
1843
|
-
if (!lexical.DEPRECATED_$isGridRowNode(currentRowNode)) {
|
1844
|
-
throw Error(`Expected row next sibling to be a row`);
|
1845
|
-
}
|
1846
|
-
let insertAfterCell = null;
|
1847
|
-
for (let column = 0; column < startColumn; column++) {
|
1848
|
-
const currentCellMap = currentRowMap[column];
|
1849
|
-
const currentCell = currentCellMap.cell;
|
1850
|
-
if (currentCellMap.startRow === currentRow) {
|
1851
|
-
insertAfterCell = currentCell;
|
1852
|
-
}
|
1853
|
-
if (currentCell.__colSpan > 1) {
|
1854
|
-
column += currentCell.__colSpan - 1;
|
1855
|
-
}
|
1856
|
-
}
|
1857
|
-
if (insertAfterCell === null) {
|
1858
|
-
for (let j = 0; j < colSpan; j++) {
|
1859
|
-
$insertFirst(currentRowNode, $createTableCellNode(TableCellHeaderStates.NO_STATUS));
|
1860
|
-
}
|
1861
|
-
} else {
|
1862
|
-
for (let j = 0; j < colSpan; j++) {
|
1863
|
-
insertAfterCell.insertAfter($createTableCellNode(TableCellHeaderStates.NO_STATUS));
|
1864
|
-
}
|
1865
|
-
}
|
1866
|
-
}
|
1867
|
-
cell.setRowSpan(1);
|
1868
|
-
}
|
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;
|
1869
2375
|
}
|
1870
2376
|
|
1871
|
-
|
1872
|
-
const INSERT_TABLE_COMMAND = lexical.createCommand('INSERT_TABLE_COMMAND');
|
1873
|
-
|
2377
|
+
exports.$computeTableMap = $computeTableMap;
|
1874
2378
|
exports.$createTableCellNode = $createTableCellNode;
|
1875
2379
|
exports.$createTableNode = $createTableNode;
|
1876
2380
|
exports.$createTableNodeWithDimensions = $createTableNodeWithDimensions;
|
1877
2381
|
exports.$createTableRowNode = $createTableRowNode;
|
2382
|
+
exports.$createTableSelection = $createTableSelection;
|
1878
2383
|
exports.$deleteTableColumn = $deleteTableColumn;
|
1879
2384
|
exports.$deleteTableColumn__EXPERIMENTAL = $deleteTableColumn__EXPERIMENTAL;
|
1880
2385
|
exports.$deleteTableRow__EXPERIMENTAL = $deleteTableRow__EXPERIMENTAL;
|
1881
|
-
exports.$
|
2386
|
+
exports.$getElementForTableNode = $getElementForTableNode;
|
2387
|
+
exports.$getNodeTriplet = $getNodeTriplet;
|
1882
2388
|
exports.$getTableCellNodeFromLexicalNode = $getTableCellNodeFromLexicalNode;
|
2389
|
+
exports.$getTableCellNodeRect = $getTableCellNodeRect;
|
1883
2390
|
exports.$getTableColumnIndexFromTableCellNode = $getTableColumnIndexFromTableCellNode;
|
1884
2391
|
exports.$getTableNodeFromLexicalNodeOrThrow = $getTableNodeFromLexicalNodeOrThrow;
|
1885
2392
|
exports.$getTableRowIndexFromTableCellNode = $getTableRowIndexFromTableCellNode;
|
@@ -1891,14 +2398,15 @@ exports.$insertTableRow__EXPERIMENTAL = $insertTableRow__EXPERIMENTAL;
|
|
1891
2398
|
exports.$isTableCellNode = $isTableCellNode;
|
1892
2399
|
exports.$isTableNode = $isTableNode;
|
1893
2400
|
exports.$isTableRowNode = $isTableRowNode;
|
2401
|
+
exports.$isTableSelection = $isTableSelection;
|
1894
2402
|
exports.$removeTableRowAtIndex = $removeTableRowAtIndex;
|
1895
2403
|
exports.$unmergeCell = $unmergeCell;
|
1896
2404
|
exports.INSERT_TABLE_COMMAND = INSERT_TABLE_COMMAND;
|
1897
2405
|
exports.TableCellHeaderStates = TableCellHeaderStates;
|
1898
2406
|
exports.TableCellNode = TableCellNode;
|
1899
2407
|
exports.TableNode = TableNode;
|
2408
|
+
exports.TableObserver = TableObserver;
|
1900
2409
|
exports.TableRowNode = TableRowNode;
|
1901
|
-
exports.TableSelection = TableSelection;
|
1902
2410
|
exports.applyTableHandlers = applyTableHandlers;
|
1903
|
-
exports.
|
1904
|
-
exports.
|
2411
|
+
exports.getDOMCellFromTarget = getDOMCellFromTarget;
|
2412
|
+
exports.getTableObserverFromTableElement = getTableObserverFromTableElement;
|