Merge pull request #274 from dolanmiu/feat/vertical-table-merge
Add table column and vertical merging
This commit is contained in:
17
demo/demo43.ts
Normal file
17
demo/demo43.ts
Normal file
@ -0,0 +1,17 @@
|
||||
// Add image to table cell
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Document, Packer, Paragraph } from "../build";
|
||||
|
||||
const doc = new Document();
|
||||
|
||||
const table = doc.createTable(4, 4);
|
||||
table.getCell(2, 2).addParagraph(new Paragraph("Hello"));
|
||||
table.getColumn(3).mergeCells(1, 2);
|
||||
// table.getCell(3, 2).addParagraph(new Paragraph("Hello"));
|
||||
|
||||
const packer = new Packer();
|
||||
|
||||
packer.toBuffer(doc).then((buffer) => {
|
||||
fs.writeFileSync("My Document.docx", buffer);
|
||||
});
|
@ -15,6 +15,7 @@
|
||||
* [Headers & Footers](usage/headers-and-footers.md)
|
||||
* [Bullet Points](usage/bullet-points.md)
|
||||
* [Numbering](usage/numbering.md)
|
||||
* [Tables](usage/tables.md)
|
||||
* [Tab Stops](usage/tab-stops.md)
|
||||
* [Table of Contents](usage/table-of-contents.md)
|
||||
* [Page Numbers](usage/page-numbers.md)
|
||||
|
@ -28,23 +28,69 @@ const table = new Table(2, 4);
|
||||
doc.addTable(table);
|
||||
```
|
||||
|
||||
## Rows and Columns
|
||||
|
||||
You can get a row or a column from a table like so, where `index` is a number:
|
||||
|
||||
### Get Row
|
||||
|
||||
```ts
|
||||
const row = doc.getRow(index);
|
||||
```
|
||||
|
||||
With this, you can merge a row by using the `mergeCells()` method, where `startIndex` is the row number you want to merge from, and `endIndex` is where you want it to merge to:
|
||||
|
||||
```ts
|
||||
row.mergeCells(startIndex, endIndex);
|
||||
```
|
||||
|
||||
You can get a cell from a `row` by using the `getCell()` method, where `index` is the row index:
|
||||
|
||||
```ts
|
||||
row.getCell(index);
|
||||
```
|
||||
|
||||
### Get Column
|
||||
|
||||
```ts
|
||||
const column = doc.getColumn(index);
|
||||
```
|
||||
|
||||
Again, you can merge a row by using the `mergeCells()` method, where `startIndex` is the row number you want to merge from, and `endIndex` is where you want it to merge to:
|
||||
|
||||
```ts
|
||||
column.mergeCells(startIndex, endIndex);
|
||||
```
|
||||
|
||||
You can get a cell from a `column` by using the `getCell()` method, where `index` is the column index:
|
||||
|
||||
```ts
|
||||
column.getCell(index);
|
||||
```
|
||||
|
||||
## Cells
|
||||
|
||||
The above section created a table with cells. To access the cell, use the `getCell` method.
|
||||
The `createTable()` method created a table with cells. To access the cell, use the `getCell()` method.
|
||||
|
||||
```ts
|
||||
const cell = table.getCell([ROW INDEX], [COLUMN INDEX]);
|
||||
```
|
||||
|
||||
You can also get a cell from a `column` or a `row` with `getCell()`, mentioned previously.
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
const cell = table.getCell(0, 2);
|
||||
|
||||
const cell = row.getCell(0);
|
||||
|
||||
const cell = column.getCell(2);
|
||||
```
|
||||
|
||||
### Add paragraph to a cell
|
||||
|
||||
Once you have got the cell, you can add data to it with the `addParagraph` method.
|
||||
Once you have got the cell, you can add data to it with the `addParagraph()` method.
|
||||
|
||||
```ts
|
||||
cell.addParagraph(new Paragraph("Hello"));
|
||||
@ -152,3 +198,58 @@ cell.addTable(new Table(1, 1));
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo4.ts ":include")
|
||||
|
||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo4.ts_
|
||||
|
||||
### Custom borders
|
||||
|
||||
Example showing how to add colourful borders to tables
|
||||
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo20.ts ":include")
|
||||
|
||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo20.ts_
|
||||
|
||||
### Adding images
|
||||
|
||||
Example showing how to add images to tables
|
||||
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo24.ts ":include")
|
||||
|
||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo24.ts_
|
||||
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/36.ts ":include")
|
||||
|
||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/36.ts_
|
||||
|
||||
### Alignment of text in a cell
|
||||
|
||||
Example showing how align text in a table cell
|
||||
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo31.ts ":include")
|
||||
|
||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo31.ts_
|
||||
|
||||
### Merging rows
|
||||
|
||||
Example showing merging of `rows`
|
||||
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo32.ts ":include")
|
||||
|
||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo32.ts_
|
||||
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo41.ts ":include")
|
||||
|
||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo41.ts_
|
||||
|
||||
### Merging columns
|
||||
|
||||
Example showing merging of `columns`
|
||||
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo43.ts ":include")
|
||||
|
||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo43.ts_
|
||||
|
||||
### Floating tables
|
||||
|
||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo34.ts ":include")
|
||||
|
||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo34.ts_
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { Paragraph } from "file/paragraph";
|
||||
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
||||
|
||||
import { Table } from "../table";
|
||||
import { TableCellBorders, VerticalAlign } from "./table-cell-components";
|
||||
import { TableCellBorders, VerticalAlign, VMergeType } from "./table-cell-components";
|
||||
import { TableCellProperties } from "./table-cell-properties";
|
||||
|
||||
export class TableCell extends XmlComponent {
|
||||
@ -58,6 +58,12 @@ export class TableCell extends XmlComponent {
|
||||
return this;
|
||||
}
|
||||
|
||||
public addVerticalMerge(type: VMergeType): TableCell {
|
||||
this.properties.addVerticalMerge(type);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public get Borders(): TableCellBorders {
|
||||
return this.properties.Borders;
|
||||
}
|
||||
|
52
src/file/table/table-column.spec.ts
Normal file
52
src/file/table/table-column.spec.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { TableCell } from "./table-cell";
|
||||
import { TableColumn } from "./table-column";
|
||||
|
||||
describe("TableColumn", () => {
|
||||
let cells: TableCell[];
|
||||
beforeEach(() => {
|
||||
cells = [new TableCell(), new TableCell(), new TableCell()];
|
||||
});
|
||||
|
||||
describe("#getCell", () => {
|
||||
it("should get the correct cell", () => {
|
||||
const tableColumn = new TableColumn(cells);
|
||||
const cell = tableColumn.getCell(0);
|
||||
|
||||
expect(cell).to.deep.equal(cells[0]);
|
||||
|
||||
const cell2 = tableColumn.getCell(1);
|
||||
|
||||
expect(cell2).to.deep.equal(cells[1]);
|
||||
});
|
||||
|
||||
it("should throw an error if index is out of bounds", () => {
|
||||
const tableColumn = new TableColumn(cells);
|
||||
|
||||
expect(() => tableColumn.getCell(9)).to.throw();
|
||||
});
|
||||
});
|
||||
|
||||
describe("#mergeCells", () => {
|
||||
it("should add vMerge to correct cells", () => {
|
||||
const tableColumn = new TableColumn(cells);
|
||||
tableColumn.mergeCells(0, 2);
|
||||
|
||||
const tree = new Formatter().format(cells[0]);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:tc": [{ "w:tcPr": [{ "w:vMerge": [{ _attr: { "w:val": "restart" } }] }] }, { "w:p": [{ "w:pPr": [] }] }],
|
||||
});
|
||||
|
||||
const tree2 = new Formatter().format(cells[1]);
|
||||
expect(tree2).to.deep.equal({ "w:tc": [{ "w:tcPr": [] }, { "w:p": [{ "w:pPr": [] }] }] });
|
||||
|
||||
const tree3 = new Formatter().format(cells[2]);
|
||||
expect(tree3).to.deep.equal({
|
||||
"w:tc": [{ "w:tcPr": [{ "w:vMerge": [{ _attr: { "w:val": "continue" } }] }] }, { "w:p": [{ "w:pPr": [] }] }],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
22
src/file/table/table-column.ts
Normal file
22
src/file/table/table-column.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { TableCell, VMergeType } from "./table-cell";
|
||||
|
||||
export class TableColumn {
|
||||
constructor(private readonly cells: TableCell[]) {}
|
||||
|
||||
public getCell(index: number): TableCell {
|
||||
const cell = this.cells[index];
|
||||
|
||||
if (!cell) {
|
||||
throw Error("Index out of bounds when trying to get cell on column");
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
public mergeCells(startIndex: number, endIndex: number): TableCell {
|
||||
this.cells[startIndex].addVerticalMerge(VMergeType.RESTART);
|
||||
this.cells[endIndex].addVerticalMerge(VMergeType.CONTINUE);
|
||||
|
||||
return this.cells[startIndex];
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ export class TableProperties extends XmlComponent {
|
||||
this.root.push(this.cellMargin);
|
||||
}
|
||||
|
||||
public setWidth(width: number | string, type: WidthType = WidthType.AUTO): TableProperties {
|
||||
public setWidth(width: number, type: WidthType = WidthType.AUTO): TableProperties {
|
||||
this.root.push(new PreferredTableWidth(type, width));
|
||||
return this;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
// http://officeopenxml.com/WPtableWidth.php
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
import { WidthType } from "../table-cell";
|
||||
@ -12,7 +13,7 @@ class TableWidthAttributes extends XmlAttributeComponent<ITableWidth> {
|
||||
}
|
||||
|
||||
export class PreferredTableWidth extends XmlComponent {
|
||||
constructor(type: WidthType, w: number | string) {
|
||||
constructor(type: WidthType, w: number) {
|
||||
super("w:tblW");
|
||||
this.root.push(new TableWidthAttributes({ type, w }));
|
||||
}
|
||||
|
@ -106,8 +106,9 @@ describe("Table", () => {
|
||||
});
|
||||
|
||||
describe("#getRow and Row#getCell", () => {
|
||||
it("returns the correct row", () => {
|
||||
const table = new Table(2, 2);
|
||||
const table = new Table(2, 2);
|
||||
|
||||
it("should return the correct row", () => {
|
||||
table
|
||||
.getRow(0)
|
||||
.getCell(0)
|
||||
@ -144,10 +145,25 @@ describe("Table", () => {
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("throws an exception if index is out of bounds", () => {
|
||||
expect(() => table.getCell(9, 9)).to.throw();
|
||||
});
|
||||
});
|
||||
|
||||
describe("#getColumn", () => {
|
||||
const table = new Table(2, 2);
|
||||
|
||||
it("should get correct row", () => {
|
||||
const column = table.getColumn(0);
|
||||
|
||||
expect(column.getCell(0)).to.equal(table.getCell(0, 0));
|
||||
expect(column.getCell(1)).to.equal(table.getCell(1, 0));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#getCell", () => {
|
||||
it("returns the correct cell", () => {
|
||||
it("should returns the correct cell", () => {
|
||||
const table = new Table(2, 2);
|
||||
table.getCell(0, 0).addParagraph(new Paragraph("A1"));
|
||||
table.getCell(0, 1).addParagraph(new Paragraph("B1"));
|
||||
|
@ -3,6 +3,7 @@ import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { TableGrid } from "./grid";
|
||||
import { TableCell, WidthType } from "./table-cell";
|
||||
import { TableColumn } from "./table-column";
|
||||
import { ITableFloatOptions, TableProperties } from "./table-properties";
|
||||
import { TableRow } from "./table-row";
|
||||
|
||||
@ -51,8 +52,8 @@ export class Table extends XmlComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public getRow(ix: number): TableRow {
|
||||
const row = this.rows[ix];
|
||||
public getRow(index: number): TableRow {
|
||||
const row = this.rows[index];
|
||||
|
||||
if (!row) {
|
||||
throw Error("Index out of bounds when trying to get row on table");
|
||||
@ -61,11 +62,17 @@ export class Table extends XmlComponent {
|
||||
return row;
|
||||
}
|
||||
|
||||
public getColumn(index: number): TableColumn {
|
||||
// This is a convinence method for people who like to work with columns
|
||||
const cells = this.rows.map((row) => row.getCell(index));
|
||||
return new TableColumn(cells);
|
||||
}
|
||||
|
||||
public getCell(row: number, col: number): TableCell {
|
||||
return this.getRow(row).getCell(col);
|
||||
}
|
||||
|
||||
public setWidth(width: number | string, type: WidthType = WidthType.AUTO): Table {
|
||||
public setWidth(width: number, type: WidthType = WidthType.AUTO): Table {
|
||||
this.properties.setWidth(width, type);
|
||||
return this;
|
||||
}
|
||||
|
Reference in New Issue
Block a user