:fix: handle rowSpan
by convert between the virtual column index and the root index
This commit is contained in:
@ -184,7 +184,7 @@ const table5 = new Table({
|
|||||||
new TableRow({
|
new TableRow({
|
||||||
children: [
|
children: [
|
||||||
new TableCell({
|
new TableCell({
|
||||||
children: [],
|
children: [new Paragraph("1,0")],
|
||||||
}),
|
}),
|
||||||
new TableCell({
|
new TableCell({
|
||||||
children: [new Paragraph("1,2")],
|
children: [new Paragraph("1,2")],
|
||||||
@ -195,10 +195,10 @@ const table5 = new Table({
|
|||||||
new TableRow({
|
new TableRow({
|
||||||
children: [
|
children: [
|
||||||
new TableCell({
|
new TableCell({
|
||||||
children: [],
|
children: [new Paragraph("2,0")],
|
||||||
}),
|
}),
|
||||||
new TableCell({
|
new TableCell({
|
||||||
children: [],
|
children: [new Paragraph("2,1")],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@ -238,12 +238,12 @@ const table6 = new Table({
|
|||||||
children: [
|
children: [
|
||||||
new TableCell({
|
new TableCell({
|
||||||
borders,
|
borders,
|
||||||
children: [new Paragraph("11"), new Paragraph("21")],
|
children: [new Paragraph("0,0")],
|
||||||
rowSpan: 2,
|
rowSpan: 2,
|
||||||
}),
|
}),
|
||||||
new TableCell({
|
new TableCell({
|
||||||
borders,
|
borders,
|
||||||
children: [new Paragraph("12")],
|
children: [new Paragraph("0,1")],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@ -251,7 +251,7 @@ const table6 = new Table({
|
|||||||
children: [
|
children: [
|
||||||
new TableCell({
|
new TableCell({
|
||||||
borders,
|
borders,
|
||||||
children: [new Paragraph("22"), new Paragraph("32")],
|
children: [new Paragraph("1,1")],
|
||||||
rowSpan: 2,
|
rowSpan: 2,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@ -260,7 +260,72 @@ const table6 = new Table({
|
|||||||
children: [
|
children: [
|
||||||
new TableCell({
|
new TableCell({
|
||||||
borders,
|
borders,
|
||||||
children: [new Paragraph("31")],
|
children: [new Paragraph("2,0")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
width: {
|
||||||
|
size: 100,
|
||||||
|
type: WidthType.PERCENTAGE,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const table7 = new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,1")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,2")],
|
||||||
|
rowSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,3")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,0")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,3")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,0")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,2")],
|
||||||
|
rowSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,3")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,1")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,3")],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@ -284,12 +349,14 @@ doc.addSection({
|
|||||||
heading: HeadingLevel.HEADING_2,
|
heading: HeadingLevel.HEADING_2,
|
||||||
}),
|
}),
|
||||||
table3,
|
table3,
|
||||||
new Paragraph("Merging columns"),
|
new Paragraph("Merging columns 1"),
|
||||||
table4,
|
table4,
|
||||||
new Paragraph("More Merging columns"),
|
new Paragraph("Merging columns 2"),
|
||||||
table5,
|
table5,
|
||||||
new Paragraph("Another Merging columns"),
|
new Paragraph("Merging columns 3"),
|
||||||
table6,
|
table6,
|
||||||
|
new Paragraph("Merging columns 4"),
|
||||||
|
table7,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -182,4 +182,91 @@ describe("TableRow", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#rootIndexToColumnIndex", () => {
|
||||||
|
it("should get the correct virtual column index by root index", () => {
|
||||||
|
const tableRow = new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tableRow.rootIndexToColumnIndex(1)).to.equal(0);
|
||||||
|
expect(tableRow.rootIndexToColumnIndex(2)).to.equal(3);
|
||||||
|
expect(tableRow.rootIndexToColumnIndex(3)).to.equal(4);
|
||||||
|
expect(tableRow.rootIndexToColumnIndex(4)).to.equal(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#columnIndexToRootIndex", () => {
|
||||||
|
it("should get the correct root index by virtual column index", () => {
|
||||||
|
const tableRow = new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tableRow.columnIndexToRootIndex(0)).to.equal(1);
|
||||||
|
expect(tableRow.columnIndexToRootIndex(1)).to.equal(1);
|
||||||
|
expect(tableRow.columnIndexToRootIndex(2)).to.equal(1);
|
||||||
|
|
||||||
|
expect(tableRow.columnIndexToRootIndex(3)).to.equal(2);
|
||||||
|
expect(tableRow.columnIndexToRootIndex(4)).to.equal(3);
|
||||||
|
|
||||||
|
expect(tableRow.columnIndexToRootIndex(5)).to.equal(4);
|
||||||
|
expect(tableRow.columnIndexToRootIndex(6)).to.equal(4);
|
||||||
|
expect(tableRow.columnIndexToRootIndex(7)).to.equal(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow end new cell index", () => {
|
||||||
|
const tableRow = new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(() => tableRow.columnIndexToRootIndex(8)).to.throw(`cell 'columnIndex' should not great than 7`);
|
||||||
|
expect(tableRow.columnIndexToRootIndex(8, true)).to.equal(5);
|
||||||
|
expect(() => tableRow.columnIndexToRootIndex(9, true)).to.throw(`cell 'columnIndex' should not great than 8`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -54,4 +54,44 @@ export class TableRow extends XmlComponent {
|
|||||||
// Offset because properties is also in root.
|
// Offset because properties is also in root.
|
||||||
this.root.splice(index + 1, 0, cell);
|
this.root.splice(index + 1, 0, cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addCellToColumnIndex(cell: TableCell, columnIndex: number): void {
|
||||||
|
const rootIndex = this.columnIndexToRootIndex(columnIndex, true);
|
||||||
|
this.addCellToIndex(cell, rootIndex - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public rootIndexToColumnIndex(rootIndex: number): number {
|
||||||
|
// convert the root index to the virtual column index
|
||||||
|
if (rootIndex < 1 || rootIndex >= this.root.length) {
|
||||||
|
throw new Error(`cell 'rootIndex' should between 1 to ${this.root.length - 1}`);
|
||||||
|
}
|
||||||
|
let colIdx = 0;
|
||||||
|
// Offset because properties is also in root.
|
||||||
|
for (let rootIdx = 1; rootIdx < rootIndex; rootIdx++) {
|
||||||
|
const cell = this.root[rootIdx] as TableCell;
|
||||||
|
colIdx += cell.options.columnSpan || 1;
|
||||||
|
}
|
||||||
|
return colIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public columnIndexToRootIndex(columnIndex: number, allowEndNewCell: boolean = false): number {
|
||||||
|
// convert the virtual column index to the root index
|
||||||
|
// `allowEndNewCell` for get index to inert new cell
|
||||||
|
if (columnIndex < 0) {
|
||||||
|
throw new Error(`cell 'columnIndex' should not less than zero`);
|
||||||
|
}
|
||||||
|
let colIdx = 0;
|
||||||
|
// Offset because properties is also in root.
|
||||||
|
let rootIdx = 1;
|
||||||
|
const endRootIndex = allowEndNewCell ? this.root.length : this.root.length - 1;
|
||||||
|
while (colIdx <= columnIndex) {
|
||||||
|
if (rootIdx > endRootIndex) {
|
||||||
|
throw new Error(`cell 'columnIndex' should not great than ${colIdx - 1}`);
|
||||||
|
}
|
||||||
|
const cell = this.root[rootIdx] as TableCell;
|
||||||
|
rootIdx += 1;
|
||||||
|
colIdx += (cell && cell.options.columnSpan) || 1;
|
||||||
|
}
|
||||||
|
return rootIdx - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,16 +83,18 @@ export class Table extends XmlComponent {
|
|||||||
// Row Span has to be added in this method and not the constructor because it needs to know information about the column which happens after Table Cell construction
|
// Row Span has to be added in this method and not the constructor because it needs to know information about the column which happens after Table Cell construction
|
||||||
// Row Span of 1 will crash word as it will add RESTART and not a corresponding CONTINUE
|
// Row Span of 1 will crash word as it will add RESTART and not a corresponding CONTINUE
|
||||||
if (cell.options.rowSpan && cell.options.rowSpan > 1) {
|
if (cell.options.rowSpan && cell.options.rowSpan > 1) {
|
||||||
|
const columnIndex = row.rootIndexToColumnIndex(cellIndex + 1);
|
||||||
|
const startRowIndex = rowIndex + 1;
|
||||||
const endRowIndex = rowIndex + (cell.options.rowSpan - 1);
|
const endRowIndex = rowIndex + (cell.options.rowSpan - 1);
|
||||||
for (let i = rowIndex + 1; i <= endRowIndex; i++) {
|
for (let i = startRowIndex; i <= endRowIndex; i++) {
|
||||||
rows[i].addCellToIndex(
|
rows[i].addCellToColumnIndex(
|
||||||
new TableCell({
|
new TableCell({
|
||||||
columnSpan: cell.options.columnSpan,
|
columnSpan: cell.options.columnSpan,
|
||||||
borders: cell.options.borders,
|
borders: cell.options.borders,
|
||||||
children: [],
|
children: [],
|
||||||
verticalMerge: VerticalMergeType.CONTINUE,
|
verticalMerge: VerticalMergeType.CONTINUE,
|
||||||
}),
|
}),
|
||||||
cellIndex,
|
columnIndex,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user