docxml
Version:
TypeScript (component) library for building and parsing a DOCX file
91 lines (90 loc) • 4.43 kB
JavaScript
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _TableGridModel_instances, _TableGridModel_occupancy, _TableGridModel_info, _TableGridModel_getFirstAvailableColumnOnRow;
function coord(x, y) {
return `${x},${y}`;
}
/**
* A conceptual description of the table that makes it easier to reason about it.
*/
export class TableGridModel {
constructor(table) {
_TableGridModel_instances.add(this);
/**
* A map of which col/row coordinates are filled by a cell.
*/
_TableGridModel_occupancy.set(this, new Map());
/**
* The coordinate and size information about a cell.
*/
_TableGridModel_info.set(this, new Map());
table.children.forEach((row, rowIndex) => {
row.children.forEach((cell) => {
const colIndex = __classPrivateFieldGet(this, _TableGridModel_instances, "m", _TableGridModel_getFirstAvailableColumnOnRow).call(this, rowIndex);
for (let y = rowIndex; y < rowIndex + cell.getRowSpan(); y++) {
for (let x = colIndex; x < colIndex + cell.getColSpan(); x++) {
const key = coord(x, y);
if (__classPrivateFieldGet(this, _TableGridModel_occupancy, "f").has(key)) {
// This should never happen so long as the colspans/rowspans make sense.
throw new Error(`Cell ${x},${y} already occupied.`);
}
__classPrivateFieldGet(this, _TableGridModel_occupancy, "f").set(key, cell);
}
}
if (!__classPrivateFieldGet(this, _TableGridModel_info, "f").has(cell)) {
__classPrivateFieldGet(this, _TableGridModel_info, "f").set(cell, {
row: rowIndex,
column: colIndex,
rowspan: cell.getRowSpan(),
colspan: cell.getColSpan(),
});
}
});
});
}
/**
* Return the <td> node belonging to this column/row coordinate, taking all colspans/rowspans
* into account.
*/
getNodeAtCell(column, row) {
return __classPrivateFieldGet(this, _TableGridModel_occupancy, "f").get(coord(column, row)) || null;
}
/**
* Get the number of columns in a row, even if some cells span multiple columns.
*/
getCellsInRow(row) {
// TODO could be simplified if we knew the table is rectangular
return (Array.from(__classPrivateFieldGet(this, _TableGridModel_occupancy, "f").keys())
.filter((key) => key.endsWith(`,${row}`))
.map((key) => key.split(',').map((n) => parseInt(n, 10)))
.sort((a, b) => a[0] - b[0])
// TODO take into accoutn the edge case that .getNodeAtCell returns null
.map(([x, y]) => this.getNodeAtCell(x, y)));
}
/**
* Return the position and spanning of a given <td> node, keeping all colspans/rowspans of other
* cels into account.
*/
getCellInfo(cell) {
const info = __classPrivateFieldGet(this, _TableGridModel_info, "f").get(cell);
if (!info) {
throw new Error(`The given cell does not exist in this table`);
}
return info;
}
}
_TableGridModel_occupancy = new WeakMap(), _TableGridModel_info = new WeakMap(), _TableGridModel_instances = new WeakSet(), _TableGridModel_getFirstAvailableColumnOnRow = function _TableGridModel_getFirstAvailableColumnOnRow(y) {
const columnsOccupied = Array.from(__classPrivateFieldGet(this, _TableGridModel_occupancy, "f").keys())
.filter((key) => key.endsWith(`,${y}`))
.map((key) => parseInt(key.split(',')[0], 10))
.sort((a, b) => a - b);
for (let i = 0; i < columnsOccupied.length; i++) {
if (i !== columnsOccupied[i]) {
return i;
}
}
return columnsOccupied.length;
};