:fix: handle rowSpan by convert between the virtual column index and the root index

This commit is contained in:
wangfengming
2020-06-22 12:25:51 +08:00
parent 11e54b3e2c
commit 8c9b61b37a
4 changed files with 209 additions and 13 deletions

View File

@ -184,7 +184,7 @@ const table5 = new Table({
new TableRow({
children: [
new TableCell({
children: [],
children: [new Paragraph("1,0")],
}),
new TableCell({
children: [new Paragraph("1,2")],
@ -195,10 +195,10 @@ const table5 = new Table({
new TableRow({
children: [
new TableCell({
children: [],
children: [new Paragraph("2,0")],
}),
new TableCell({
children: [],
children: [new Paragraph("2,1")],
}),
],
}),
@ -238,12 +238,12 @@ const table6 = new Table({
children: [
new TableCell({
borders,
children: [new Paragraph("11"), new Paragraph("21")],
children: [new Paragraph("0,0")],
rowSpan: 2,
}),
new TableCell({
borders,
children: [new Paragraph("12")],
children: [new Paragraph("0,1")],
}),
],
}),
@ -251,7 +251,7 @@ const table6 = new Table({
children: [
new TableCell({
borders,
children: [new Paragraph("22"), new Paragraph("32")],
children: [new Paragraph("1,1")],
rowSpan: 2,
}),
],
@ -260,7 +260,72 @@ const table6 = new Table({
children: [
new TableCell({
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,
}),
table3,
new Paragraph("Merging columns"),
new Paragraph("Merging columns 1"),
table4,
new Paragraph("More Merging columns"),
new Paragraph("Merging columns 2"),
table5,
new Paragraph("Another Merging columns"),
new Paragraph("Merging columns 3"),
table6,
new Paragraph("Merging columns 4"),
table7,
],
});

View File

@ -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`);
});
});
});

View File

@ -54,4 +54,44 @@ export class TableRow extends XmlComponent {
// Offset because properties is also in root.
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;
}
}

View File

@ -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 of 1 will crash word as it will add RESTART and not a corresponding CONTINUE
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);
for (let i = rowIndex + 1; i <= endRowIndex; i++) {
rows[i].addCellToIndex(
for (let i = startRowIndex; i <= endRowIndex; i++) {
rows[i].addCellToColumnIndex(
new TableCell({
columnSpan: cell.options.columnSpan,
borders: cell.options.borders,
children: [],
verticalMerge: VerticalMergeType.CONTINUE,
}),
cellIndex,
columnIndex,
);
}
}