1 import {CustomTableNode} from "../nodes/custom-table";
2 import {$isCustomTableCellNode, CustomTableCellNode} from "../nodes/custom-table-cell";
3 import {$isTableRowNode} from "@lexical/table";
5 export class TableMap {
8 columnCount: number = 0;
10 // Represents an array (rows*columns in length) of cell nodes from top-left to
11 // bottom right. Cells may repeat where merged and covering multiple spaces.
12 cells: CustomTableCellNode[] = [];
14 constructor(table: CustomTableNode) {
15 this.buildCellMap(table);
18 protected buildCellMap(table: CustomTableNode) {
19 const rowsAndCells: CustomTableCellNode[][] = [];
20 const setCell = (x: number, y: number, cell: CustomTableCellNode) => {
21 if (typeof rowsAndCells[y] === 'undefined') {
25 rowsAndCells[y][x] = cell;
27 const cellFilled = (x: number, y: number): boolean => !!(rowsAndCells[y] && rowsAndCells[y][x]);
29 const rowNodes = table.getChildren().filter(r => $isTableRowNode(r));
30 for (let rowIndex = 0; rowIndex < rowNodes.length; rowIndex++) {
31 const rowNode = rowNodes[rowIndex];
32 const cellNodes = rowNode.getChildren().filter(c => $isCustomTableCellNode(c));
33 let targetColIndex: number = 0;
34 for (let cellIndex = 0; cellIndex < cellNodes.length; cellIndex++) {
35 const cellNode = cellNodes[cellIndex];
36 const colspan = cellNode.getColSpan() || 1;
37 const rowSpan = cellNode.getRowSpan() || 1;
38 for (let x = targetColIndex; x < targetColIndex + colspan; x++) {
39 for (let y = rowIndex; y < rowIndex + rowSpan; y++) {
40 while (cellFilled(x, y)) {
45 setCell(x, y, cellNode);
48 targetColIndex += colspan;
52 this.rowCount = rowsAndCells.length;
53 this.columnCount = Math.max(...rowsAndCells.map(r => r.length));
56 let lastCell: CustomTableCellNode = rowsAndCells[0][0];
57 for (let y = 0; y < this.rowCount; y++) {
58 for (let x = 0; x < this.columnCount; x++) {
59 if (!rowsAndCells[y] || !rowsAndCells[y][x]) {
62 cells.push(rowsAndCells[y][x]);
63 lastCell = rowsAndCells[y][x];
71 public getCellAtPosition(x: number, y: number): CustomTableCellNode {
72 const position = (y * this.columnCount) + x;
73 if (position >= this.cells.length) {
74 throw new Error(`TableMap Error: Attempted to get cell ${position+1} of ${this.cells.length}`);
77 return this.cells[position];
80 public getCellsInRange(fromX: number, fromY: number, toX: number, toY: number): CustomTableCellNode[] {
81 const minX = Math.max(Math.min(fromX, toX), 0);
82 const maxX = Math.min(Math.max(fromX, toX), this.columnCount - 1);
83 const minY = Math.max(Math.min(fromY, toY), 0);
84 const maxY = Math.min(Math.max(fromY, toY), this.rowCount - 1);
86 const cells = new Set<CustomTableCellNode>();
88 for (let y = minY; y <= maxY; y++) {
89 for (let x = minX; x <= maxX; x++) {
90 cells.add(this.getCellAtPosition(x, y));
94 return [...cells.values()];