The splitCell
command only works for table cells with colspan greater than one. Is there a way to make this command work for cells with colspan equal to 1? Like in Word, so that the cell is split into smaller ones.
This is an example of a solution that seems to work fine, but could probably be improved. If anyone has any ideas, I would appreciate it.
{
splitSingleCell:
() => ({ state, dispatch, tr }) => {
const getCellType = ({ node }) => {
const nodeTypes = tableNodeTypes(state.schema);
return nodeTypes[node.type.spec.tableRole];
};
// For reference.
// https://github.com/ProseMirror/prosemirror-tables/blob/a99f70855f2b3e2433bc77451fedd884305fda5b/src/commands.ts#L497
const sel = state.selection;
let cellNode;
let cellPos;
if (!(sel instanceof CellSelection)) {
cellNode = cellWrapping(sel.$from);
if (!cellNode) return false;
cellPos = cellAround(sel.$from)?.pos;
} else {
if (sel.$anchorCell.pos != sel.$headCell.pos) return false;
cellNode = sel.$anchorCell.nodeAfter;
cellPos = sel.$anchorCell.pos;
}
if (cellNode == null || cellPos == null) {
return false;
}
if (cellNode.attrs.colspan != 1 || cellNode.attrs.rowspan != 1) {
return false;
}
//
if (dispatch) {
let rect = selectedRect(state);
let currentRow = rect.top;
let currentCol = rect.left;
let baseAttrs = { ...cellNode.attrs };
let currentColWidth = baseAttrs.colwidth;
let newCellWidth = null;
// Get new width for the current and new cells.
if (currentColWidth?.[0]) {
newCellWidth = Math.ceil(currentColWidth[0] / 2);
}
// Update width of the current cell.
if (newCellWidth) {
tr.setNodeMarkup(tr.mapping.map(cellPos, 1), null, { ...baseAttrs, colwidth: [newCellWidth] });
}
// Insert new cell after the current one.
const newCell = getCellType({ node: cellNode }).createAndFill({
...baseAttrs,
colwidth: newCellWidth ? [newCellWidth] : null,
});
tr.insert(tr.mapping.map(cellPos + cellNode.nodeSize, 1), newCell);
// Update colspan and colwidth for cells in other rows.
for (let row = 0; row < rect.map.height; row++) {
if (row === currentRow) continue;
let rowCells = new Set();
for (let col = 0; col < rect.map.width; col++) {
let cellIndex = rect.map.map[row * rect.map.width + col];
if (cellIndex != null) rowCells.add(cellIndex);
}
[...rowCells].forEach((cellIndex) => {
let cellRect = rect.map.findCell(cellIndex);
// If cell covers the column where we added new cell.
if (cellRect.left <= currentCol && cellRect.right > currentCol) {
let cellPos = tr.mapping.map(rect.tableStart + cellIndex, 1);
let cell = tr.doc.nodeAt(cellPos);
if (cell) {
let newColspan = (cell.attrs.colspan || 1) + 1;
let updatedColwidth = cell.attrs.colwidth;
if (updatedColwidth && newCellWidth) {
let originalColIndex = currentCol - cellRect.left;
updatedColwidth = [
...updatedColwidth.slice(0, originalColIndex),
newCellWidth, // current cell width
newCellWidth, // new cell width
...updatedColwidth.slice(originalColIndex + 1)
];
}
tr.setNodeMarkup(cellPos, null, { ...cell.attrs, colspan: newColspan, colwidth: updatedColwidth });
}
}
});
}
}
return true;
},
}
tableNodeTypes
, selectedRect
, cellAround
, cellWrapping
- from ‘prosemirror-tables’.