X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/b3d3b14f79552299ce558083383cf05c2f1a7d90..refs/pull/5291/head:/resources/js/wysiwyg/utils/tables.ts diff --git a/resources/js/wysiwyg/utils/tables.ts b/resources/js/wysiwyg/utils/tables.ts index 959c8a423..aa8ec89ba 100644 --- a/resources/js/wysiwyg/utils/tables.ts +++ b/resources/js/wysiwyg/utils/tables.ts @@ -1,10 +1,12 @@ import {BaseSelection, LexicalEditor} from "lexical"; -import {$isTableRowNode, $isTableSelection, TableRowNode} from "@lexical/table"; +import {$isTableRowNode, $isTableSelection, TableRowNode, TableSelection, TableSelectionShape} from "@lexical/table"; import {$isCustomTableNode, CustomTableNode} from "../nodes/custom-table"; -import {$isCustomTableCellNode, CustomTableCellNode} from "../nodes/custom-table-cell-node"; +import {$isCustomTableCellNode, CustomTableCellNode} from "../nodes/custom-table-cell"; import {$getParentOfType} from "./nodes"; import {$getNodeFromSelection} from "./selection"; import {formatSizeValue} from "./dom"; +import {TableMap} from "./table-map"; +import {$isCustomTableRowNode, CustomTableRowNode} from "../nodes/custom-table-row"; function $getTableFromCell(cell: CustomTableCellNode): CustomTableNode|null { return $getParentOfType(cell, $isCustomTableNode) as CustomTableNode|null; @@ -123,6 +125,17 @@ export function $setTableCellColumnWidth(cell: CustomTableCellNode, width: strin } } +export function $getTableCellColumnWidth(editor: LexicalEditor, cell: CustomTableCellNode): string { + const table = $getTableFromCell(cell) + const index = $getCellColumnIndex(cell); + if (!table) { + return ''; + } + + const widths = table.getColWidths(); + return (widths.length > index) ? widths[index] : ''; +} + export function $getTableCellsFromSelection(selection: BaseSelection|null): CustomTableCellNode[] { if ($isTableSelection(selection)) { const nodes = selection.getNodes(); @@ -131,4 +144,174 @@ export function $getTableCellsFromSelection(selection: BaseSelection|null): Cust const cell = $getNodeFromSelection(selection, $isCustomTableCellNode) as CustomTableCellNode; return cell ? [cell] : []; -} \ No newline at end of file +} + +export function $mergeTableCellsInSelection(selection: TableSelection): void { + const selectionShape = selection.getShape(); + const cells = $getTableCellsFromSelection(selection); + if (cells.length === 0) { + return; + } + + const table = $getTableFromCell(cells[0]); + if (!table) { + return; + } + + const tableMap = new TableMap(table); + const headCell = tableMap.getCellAtPosition(selectionShape.toX, selectionShape.toY); + if (!headCell) { + return; + } + + // We have to adjust the shape since it won't take into account spans for the head corner position. + const fixedToX = selectionShape.toX + ((headCell.getColSpan() || 1) - 1); + const fixedToY = selectionShape.toY + ((headCell.getRowSpan() || 1) - 1); + + const mergeCells = tableMap.getCellsInRange({ + fromX: selectionShape.fromX, + fromY: selectionShape.fromY, + toX: fixedToX, + toY: fixedToY, + }); + + if (mergeCells.length === 0) { + return; + } + + const firstCell = mergeCells[0]; + const newWidth = Math.abs(selectionShape.fromX - fixedToX) + 1; + const newHeight = Math.abs(selectionShape.fromY - fixedToY) + 1; + + for (let i = 1; i < mergeCells.length; i++) { + const mergeCell = mergeCells[i]; + firstCell.append(...mergeCell.getChildren()); + mergeCell.remove(); + } + + firstCell.setColSpan(newWidth); + firstCell.setRowSpan(newHeight); +} + +export function $getTableRowsFromSelection(selection: BaseSelection|null): CustomTableRowNode[] { + const cells = $getTableCellsFromSelection(selection); + const rowsByKey: Record = {}; + for (const cell of cells) { + const row = cell.getParent(); + if ($isCustomTableRowNode(row)) { + rowsByKey[row.getKey()] = row; + } + } + + return Object.values(rowsByKey); +} + +export function $getTableFromSelection(selection: BaseSelection|null): CustomTableNode|null { + const cells = $getTableCellsFromSelection(selection); + if (cells.length === 0) { + return null; + } + + const table = $getParentOfType(cells[0], $isCustomTableNode); + if ($isCustomTableNode(table)) { + return table; + } + + return null; +} + +export function $clearTableSizes(table: CustomTableNode): void { + table.setColWidths([]); + + // TODO - Extra form things once table properties and extra things + // are supported + + for (const row of table.getChildren()) { + if (!$isCustomTableRowNode(row)) { + continue; + } + + const rowStyles = row.getStyles(); + rowStyles.delete('height'); + rowStyles.delete('width'); + row.setStyles(rowStyles); + + const cells = row.getChildren().filter(c => $isCustomTableCellNode(c)); + for (const cell of cells) { + const cellStyles = cell.getStyles(); + cellStyles.delete('height'); + cellStyles.delete('width'); + cell.setStyles(cellStyles); + cell.clearWidth(); + } + } +} + +export function $clearTableFormatting(table: CustomTableNode): void { + table.setColWidths([]); + table.setStyles(new Map); + + for (const row of table.getChildren()) { + if (!$isCustomTableRowNode(row)) { + continue; + } + + row.setStyles(new Map); + row.setFormat(''); + + const cells = row.getChildren().filter(c => $isCustomTableCellNode(c)); + for (const cell of cells) { + cell.setStyles(new Map); + cell.clearWidth(); + cell.setFormat(''); + } + } +} + +/** + * Perform the given callback for each cell in the given table. + * Returning false from the callback stops the function early. + */ +export function $forEachTableCell(table: CustomTableNode, callback: (c: CustomTableCellNode) => void|false): void { + outer: for (const row of table.getChildren()) { + if (!$isCustomTableRowNode(row)) { + continue; + } + const cells = row.getChildren(); + for (const cell of cells) { + if (!$isCustomTableCellNode(cell)) { + return; + } + const result = callback(cell); + if (result === false) { + break outer; + } + } + } +} + +export function $getCellPaddingForTable(table: CustomTableNode): string { + let padding: string|null = null; + + $forEachTableCell(table, (cell: CustomTableCellNode) => { + const cellPadding = cell.getStyles().get('padding') || '' + if (padding === null) { + padding = cellPadding; + } + + if (cellPadding !== padding) { + padding = null; + return false; + } + }); + + return padding || ''; +} + + + + + + + +