55 lines
1.8 KiB
TypeScript
55 lines
1.8 KiB
TypeScript
export interface SimpleCellRange {
|
|
from: { row: number | null; col: number | null }
|
|
to: { row: number | null; col: number | null }
|
|
}
|
|
|
|
export interface SimpleCell {
|
|
row: number
|
|
col: number
|
|
}
|
|
|
|
/**
|
|
* Expands one or more Handsontable selection ranges (as returned by
|
|
* getSelectedRange()/the context menu callback's selection argument) into
|
|
* every individual (row, col) cell they cover. A whole-row selection (row
|
|
* header click) reports col: -1 (Handsontable.CellRange itself types this
|
|
* as number | null, so null is treated the same way here) on whichever end
|
|
* is the "start" of the range; a whole-column selection reports row: -1
|
|
* the same way - normalized here to the real 0..totalRows-1/0..totalCols-1
|
|
* bounds, since neither -1 nor null is a usable index for anything
|
|
* downstream (comments lookup, setDataAtRowProp, ...). Multiple ranges
|
|
* (ctrl-click) are all expanded, not just the first.
|
|
*/
|
|
export const expandCellRanges = (
|
|
ranges: SimpleCellRange[],
|
|
totalRows: number,
|
|
totalCols: number
|
|
): SimpleCell[] => {
|
|
const cells: SimpleCell[] = []
|
|
|
|
const normalizeRow = (row: number | null) =>
|
|
row === -1 || row === null ? undefined : row
|
|
const normalizeCol = (col: number | null) =>
|
|
col === -1 || col === null ? undefined : col
|
|
|
|
for (const range of ranges) {
|
|
const rowA = normalizeRow(range.from.row) ?? 0
|
|
const rowB = normalizeRow(range.to.row) ?? totalRows - 1
|
|
const colA = normalizeCol(range.from.col) ?? 0
|
|
const colB = normalizeCol(range.to.col) ?? totalCols - 1
|
|
|
|
const startRow = Math.min(rowA, rowB)
|
|
const endRow = Math.max(rowA, rowB)
|
|
const startCol = Math.min(colA, colB)
|
|
const endCol = Math.max(colA, colB)
|
|
|
|
for (let row = startRow; row <= endRow; row++) {
|
|
for (let col = startCol; col <= endCol; col++) {
|
|
cells.push({ row, col })
|
|
}
|
|
}
|
|
}
|
|
|
|
return cells
|
|
}
|