Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
38f2638ea0 | |||
2b874e3f69 | |||
b43ed12c84 | |||
59be381213 | |||
172c333357 | |||
c5eb3d5670 | |||
44b95f2f15 | |||
bd888219fc | |||
2842619196 | |||
b2de74a0e6 | |||
7aa4134e2b | |||
cc36ea7542 | |||
c11af71ed7 | |||
a9d4ebc898 | |||
d2f82052b4 | |||
f88a309d55 | |||
418adca9f3 | |||
993f8f81f7 | |||
99718784f1 | |||
59fc1ed632 | |||
cb74868247 | |||
bd6ae2c0dc | |||
60a599a550 | |||
4ac55a787e | |||
cb52a1ef42 | |||
7827d158d7 | |||
535f2d75b0 | |||
5ecdb48d43 | |||
2502fe7f39 | |||
02487fbb22 | |||
2abff6991f | |||
49e85275c3 | |||
96efdf8b1a | |||
b52a4adaff | |||
a9fc40dad4 | |||
b609a17362 | |||
4b49fdbf8e | |||
fd52c8cf47 |
8
.nycrc
8
.nycrc
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"check-coverage": true,
|
"check-coverage": true,
|
||||||
"lines": 87.54,
|
"lines": 92.34,
|
||||||
"functions": 83.61,
|
"functions": 88.27,
|
||||||
"branches": 72.57,
|
"branches": 84.64,
|
||||||
"statements": 87.32,
|
"statements": 92.15,
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*.ts"
|
"src/**/*.ts"
|
||||||
],
|
],
|
||||||
|
@ -42,7 +42,7 @@ script:
|
|||||||
- npm run ts-node -- ./demo/29-numbered-lists.ts
|
- npm run ts-node -- ./demo/29-numbered-lists.ts
|
||||||
- npm run ts-node -- ./demo/30-template-document.ts
|
- npm run ts-node -- ./demo/30-template-document.ts
|
||||||
- npm run ts-node -- ./demo/31-tables.ts
|
- npm run ts-node -- ./demo/31-tables.ts
|
||||||
- npm run ts-node -- ./demo/32-merge-table-cells.ts
|
- npm run ts-node -- ./demo/32-merge-and-shade-table-cells.ts
|
||||||
# - npm run e2e "My Document.docx" // Need to fix
|
# - npm run e2e "My Document.docx" // Need to fix
|
||||||
- npm run ts-node -- ./demo/33-sequential-captions.ts
|
- npm run ts-node -- ./demo/33-sequential-captions.ts
|
||||||
- npm run ts-node -- ./demo/34-floating-tables.ts
|
- npm run ts-node -- ./demo/34-floating-tables.ts
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Setting styles with JavaScript configuration
|
// Setting styles with JavaScript configuration
|
||||||
// Import from 'docx' rather than '../build' if you install from npm
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { AlignmentType, Document, Footer, HeadingLevel, Media, Packer, Paragraph, Table } from "../build";
|
import { AlignmentType, Document, Footer, HeadingLevel, Media, Packer, Paragraph, Table, TableCell, TableRow } from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
@ -81,13 +81,37 @@ doc.Styles.createParagraphStyle("ListParagraph", "List Paragraph")
|
|||||||
const image = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
|
const image = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 4,
|
rows: [
|
||||||
columns: 4,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Test cell 1.")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Test cell 2.")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Test cell 3.")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Test cell 4.")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
table
|
|
||||||
.getRow(0)
|
|
||||||
.getCell(0)
|
|
||||||
.add(new Paragraph("Pole No."));
|
|
||||||
|
|
||||||
const image1 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
|
const image1 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
|
||||||
const image2 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
|
const image2 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
|
||||||
|
@ -1,23 +1,102 @@
|
|||||||
// Add custom borders to table cell
|
// Add custom borders to table cell
|
||||||
// Import from 'docx' rather than '../build' if you install from npm
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { BorderStyle, Document, Packer, Paragraph, Table } from "../build";
|
import { BorderStyle, Document, Packer, Paragraph, Table, TableCell, TableRow } from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 4,
|
rows: [
|
||||||
columns: 4,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Hello")],
|
||||||
|
borders: {
|
||||||
|
top: {
|
||||||
|
style: BorderStyle.DASH_DOT_STROKED,
|
||||||
|
size: 3,
|
||||||
|
color: "red",
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
style: BorderStyle.DOUBLE,
|
||||||
|
size: 3,
|
||||||
|
color: "blue",
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
style: BorderStyle.DASH_DOT_STROKED,
|
||||||
|
size: 3,
|
||||||
|
color: "green",
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
style: BorderStyle.DASH_DOT_STROKED,
|
||||||
|
size: 3,
|
||||||
|
color: "#ff8000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
doc.addSection({ children: [table] });
|
doc.addSection({ children: [table] });
|
||||||
table
|
|
||||||
.getCell(2, 2)
|
|
||||||
.add(new Paragraph("Hello"))
|
|
||||||
.Borders.addTopBorder(BorderStyle.DASH_DOT_STROKED, 3, "red")
|
|
||||||
.addBottomBorder(BorderStyle.DOUBLE, 3, "blue")
|
|
||||||
.addStartBorder(BorderStyle.DOT_DOT_DASH, 3, "green")
|
|
||||||
.addEndBorder(BorderStyle.DOT_DOT_DASH, 3, "#ff8000");
|
|
||||||
|
|
||||||
Packer.toBuffer(doc).then((buffer) => {
|
Packer.toBuffer(doc).then((buffer) => {
|
||||||
fs.writeFileSync("My Document.docx", buffer);
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
@ -1,24 +1,85 @@
|
|||||||
// Add image to table cell
|
// Add image to table cell
|
||||||
// Import from 'docx' rather than '../build' if you install from npm
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Document, Media, Packer, Paragraph, Table } from "../build";
|
import { Document, Media, Packer, Paragraph, Table, TableCell, TableRow } from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
|
const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 4,
|
rows: [
|
||||||
columns: 4,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph(image)],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Hello")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
children: [table],
|
children: [table],
|
||||||
});
|
});
|
||||||
|
|
||||||
table.getCell(2, 2).add(new Paragraph("Hello"));
|
|
||||||
|
|
||||||
const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
|
|
||||||
table.getCell(1, 1).add(new Paragraph(image));
|
|
||||||
|
|
||||||
Packer.toBuffer(doc).then((buffer) => {
|
Packer.toBuffer(doc).then((buffer) => {
|
||||||
fs.writeFileSync("My Document.docx", buffer);
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
});
|
});
|
||||||
|
@ -10,7 +10,7 @@ const numbering = new Numbering();
|
|||||||
const abstractNum = numbering.createAbstractNumbering();
|
const abstractNum = numbering.createAbstractNumbering();
|
||||||
abstractNum.createLevel(0, "upperRoman", "%1", "start").indent({ left: 720, hanging: 260 });
|
abstractNum.createLevel(0, "upperRoman", "%1", "start").indent({ left: 720, hanging: 260 });
|
||||||
abstractNum.createLevel(1, "decimal", "%2.", "start").indent({ left: 1440, hanging: 980 });
|
abstractNum.createLevel(1, "decimal", "%2.", "start").indent({ left: 1440, hanging: 980 });
|
||||||
abstractNum.createLevel(2, "lowerLetter", "%3)", "start").indent({ left: 14402160, hanging: 1700 });
|
abstractNum.createLevel(2, "lowerLetter", "%3)", "start").indent({ left: 2160, hanging: 1700 });
|
||||||
|
|
||||||
const concrete = numbering.createConcreteNumbering(abstractNum);
|
const concrete = numbering.createConcreteNumbering(abstractNum);
|
||||||
|
|
||||||
|
@ -1,27 +1,47 @@
|
|||||||
// Example of how you would create a table and add data to it
|
// Example of how you would create a table and add data to it
|
||||||
// Import from 'docx' rather than '../build' if you install from npm
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Document, HeadingLevel, Packer, Paragraph, Table, VerticalAlign } from "../build";
|
import { Document, HeadingLevel, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlign } from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 2,
|
rows: [
|
||||||
columns: 2,
|
new TableRow({
|
||||||
});
|
children: [
|
||||||
|
new TableCell({
|
||||||
table
|
children: [new Paragraph({}), new Paragraph({})],
|
||||||
.getCell(1, 1)
|
verticalAlign: VerticalAlign.CENTER,
|
||||||
.add(new Paragraph("This text should be in the middle of the cell"))
|
}),
|
||||||
.setVerticalAlign(VerticalAlign.CENTER);
|
new TableCell({
|
||||||
|
children: [new Paragraph({}), new Paragraph({})],
|
||||||
table.getCell(1, 0).add(
|
verticalAlign: VerticalAlign.CENTER,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [
|
||||||
new Paragraph({
|
new Paragraph({
|
||||||
text:
|
text:
|
||||||
"Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah",
|
"Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah",
|
||||||
heading: HeadingLevel.HEADING_1,
|
heading: HeadingLevel.HEADING_1,
|
||||||
}),
|
}),
|
||||||
);
|
],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [
|
||||||
|
new Paragraph({
|
||||||
|
text: "This text should be in the middle of the cell",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
verticalAlign: VerticalAlign.CENTER,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
children: [table],
|
children: [table],
|
||||||
|
231
demo/32-merge-and-shade-table-cells.ts
Normal file
231
demo/32-merge-and-shade-table-cells.ts
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
// Example of how you would merge cells together (Rows and Columns) and apply shading
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, HeadingLevel, Packer, Paragraph, ShadingType, Table, TableCell, TableRow, WidthType } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
|
||||||
|
const table = new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Hello")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const table2 = new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("World")],
|
||||||
|
margins: {
|
||||||
|
top: 1000,
|
||||||
|
bottom: 1000,
|
||||||
|
left: 1000,
|
||||||
|
right: 1000,
|
||||||
|
},
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
width: {
|
||||||
|
size: 100,
|
||||||
|
type: WidthType.AUTO,
|
||||||
|
},
|
||||||
|
columnWidths: [1000, 1000, 1000],
|
||||||
|
});
|
||||||
|
|
||||||
|
const table3 = new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Foo")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("v")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Bar1")],
|
||||||
|
shading: {
|
||||||
|
fill: "b79c2f",
|
||||||
|
val: ShadingType.REVERSE_DIAGONAL_STRIPE,
|
||||||
|
color: "auto",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Bar2")],
|
||||||
|
shading: {
|
||||||
|
fill: "42c5f4",
|
||||||
|
val: ShadingType.PERCENT_95,
|
||||||
|
color: "auto",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Bar3")],
|
||||||
|
shading: {
|
||||||
|
fill: "880aa8",
|
||||||
|
val: ShadingType.PERCENT_10,
|
||||||
|
color: "e2df0b",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Bar4")],
|
||||||
|
shading: {
|
||||||
|
fill: "FF0000",
|
||||||
|
val: ShadingType.CLEAR,
|
||||||
|
color: "auto",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
width: {
|
||||||
|
size: 7000,
|
||||||
|
type: WidthType.DXA,
|
||||||
|
},
|
||||||
|
margins: {
|
||||||
|
top: 400,
|
||||||
|
bottom: 400,
|
||||||
|
right: 400,
|
||||||
|
left: 400,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const table4 = new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,0")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,1")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,0")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
width: {
|
||||||
|
size: 100,
|
||||||
|
type: WidthType.PERCENTAGE,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const table5 = new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,1")],
|
||||||
|
rowSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,2")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,2")],
|
||||||
|
rowSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
width: {
|
||||||
|
size: 100,
|
||||||
|
type: WidthType.PERCENTAGE,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
children: [
|
||||||
|
table,
|
||||||
|
new Paragraph({
|
||||||
|
text: "Another table",
|
||||||
|
heading: HeadingLevel.HEADING_2,
|
||||||
|
}),
|
||||||
|
table2,
|
||||||
|
new Paragraph({
|
||||||
|
text: "Another table",
|
||||||
|
heading: HeadingLevel.HEADING_2,
|
||||||
|
}),
|
||||||
|
table3,
|
||||||
|
new Paragraph("Merging columns"),
|
||||||
|
table4,
|
||||||
|
new Paragraph("More Merging columns"),
|
||||||
|
table5,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
Packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
@ -1,113 +0,0 @@
|
|||||||
// Example of how you would merge cells together
|
|
||||||
// Import from 'docx' rather than '../build' if you install from npm
|
|
||||||
import * as fs from "fs";
|
|
||||||
import { Document, HeadingLevel, Packer, Paragraph, ShadingType, Table, WidthType } from "../build";
|
|
||||||
|
|
||||||
const doc = new Document();
|
|
||||||
|
|
||||||
const table = new Table({
|
|
||||||
rows: 2,
|
|
||||||
columns: 2,
|
|
||||||
});
|
|
||||||
|
|
||||||
table.getCell(0, 0).add(new Paragraph("Hello"));
|
|
||||||
table.getRow(0).mergeCells(0, 1);
|
|
||||||
|
|
||||||
const table2 = new Table({
|
|
||||||
rows: 2,
|
|
||||||
columns: 3,
|
|
||||||
width: 100,
|
|
||||||
widthUnitType: WidthType.AUTO,
|
|
||||||
columnWidths: [1000, 1000, 1000],
|
|
||||||
});
|
|
||||||
|
|
||||||
table2
|
|
||||||
.getCell(0, 0)
|
|
||||||
.add(new Paragraph("World"))
|
|
||||||
.setMargins({
|
|
||||||
top: 1000,
|
|
||||||
bottom: 1000,
|
|
||||||
left: 1000,
|
|
||||||
right: 1000,
|
|
||||||
});
|
|
||||||
table.getRow(0).mergeCells(0, 2);
|
|
||||||
|
|
||||||
const table3 = new Table({
|
|
||||||
rows: 2,
|
|
||||||
columns: 4,
|
|
||||||
width: 7000,
|
|
||||||
widthUnitType: WidthType.DXA,
|
|
||||||
margins: {
|
|
||||||
top: 400,
|
|
||||||
bottom: 400,
|
|
||||||
right: 400,
|
|
||||||
left: 400,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
table3.getCell(0, 0).add(new Paragraph("Foo"));
|
|
||||||
table3.getCell(0, 1).add(new Paragraph("v"));
|
|
||||||
|
|
||||||
table3
|
|
||||||
.getCell(1, 0)
|
|
||||||
.add(new Paragraph("Bar1"))
|
|
||||||
.setShading({
|
|
||||||
fill: "b79c2f",
|
|
||||||
val: ShadingType.REVERSE_DIAGONAL_STRIPE,
|
|
||||||
color: "auto",
|
|
||||||
});
|
|
||||||
table3
|
|
||||||
.getCell(1, 1)
|
|
||||||
.add(new Paragraph("Bar2"))
|
|
||||||
.setShading({
|
|
||||||
fill: "42c5f4",
|
|
||||||
val: ShadingType.PERCENT_95,
|
|
||||||
color: "auto",
|
|
||||||
});
|
|
||||||
table3
|
|
||||||
.getCell(1, 2)
|
|
||||||
.add(new Paragraph("Bar3"))
|
|
||||||
.setShading({
|
|
||||||
fill: "880aa8",
|
|
||||||
val: ShadingType.PERCENT_10,
|
|
||||||
color: "e2df0b",
|
|
||||||
});
|
|
||||||
table3
|
|
||||||
.getCell(1, 3)
|
|
||||||
.add(new Paragraph("Bar4"))
|
|
||||||
.setShading({
|
|
||||||
fill: "FF0000",
|
|
||||||
val: ShadingType.CLEAR,
|
|
||||||
color: "auto",
|
|
||||||
});
|
|
||||||
|
|
||||||
table3.getRow(0).mergeCells(0, 3);
|
|
||||||
|
|
||||||
const table4 = new Table({
|
|
||||||
rows: 2,
|
|
||||||
columns: 2,
|
|
||||||
width: 100,
|
|
||||||
widthUnitType: WidthType.PERCENTAGE,
|
|
||||||
});
|
|
||||||
|
|
||||||
doc.addSection({
|
|
||||||
children: [
|
|
||||||
table,
|
|
||||||
new Paragraph({
|
|
||||||
text: "Another table",
|
|
||||||
heading: HeadingLevel.HEADING_2,
|
|
||||||
}),
|
|
||||||
table2,
|
|
||||||
new Paragraph({
|
|
||||||
text: "Another table",
|
|
||||||
heading: HeadingLevel.HEADING_2,
|
|
||||||
}),
|
|
||||||
table3,
|
|
||||||
new Paragraph("hi"),
|
|
||||||
table4,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
Packer.toBuffer(doc).then((buffer) => {
|
|
||||||
fs.writeFileSync("My Document.docx", buffer);
|
|
||||||
});
|
|
@ -9,29 +9,48 @@ import {
|
|||||||
RelativeVerticalPosition,
|
RelativeVerticalPosition,
|
||||||
Table,
|
Table,
|
||||||
TableAnchorType,
|
TableAnchorType,
|
||||||
|
TableCell,
|
||||||
TableLayoutType,
|
TableLayoutType,
|
||||||
|
TableRow,
|
||||||
WidthType,
|
WidthType,
|
||||||
} from "../build";
|
} from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 2,
|
rows: [
|
||||||
columns: 2,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Hello")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
float: {
|
float: {
|
||||||
horizontalAnchor: TableAnchorType.MARGIN,
|
horizontalAnchor: TableAnchorType.MARGIN,
|
||||||
verticalAnchor: TableAnchorType.MARGIN,
|
verticalAnchor: TableAnchorType.MARGIN,
|
||||||
relativeHorizontalPosition: RelativeHorizontalPosition.RIGHT,
|
relativeHorizontalPosition: RelativeHorizontalPosition.RIGHT,
|
||||||
relativeVerticalPosition: RelativeVerticalPosition.BOTTOM,
|
relativeVerticalPosition: RelativeVerticalPosition.BOTTOM,
|
||||||
},
|
},
|
||||||
width: 4535,
|
width: {
|
||||||
widthUnitType: WidthType.DXA,
|
size: 4535,
|
||||||
|
type: WidthType.DXA,
|
||||||
|
},
|
||||||
layout: TableLayoutType.FIXED,
|
layout: TableLayoutType.FIXED,
|
||||||
});
|
});
|
||||||
|
|
||||||
table.getCell(0, 0).add(new Paragraph("Hello"));
|
|
||||||
table.getRow(0).mergeCells(0, 1);
|
|
||||||
|
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
children: [table],
|
children: [table],
|
||||||
});
|
});
|
||||||
|
@ -1,16 +1,61 @@
|
|||||||
// Add image to table cell
|
// Add image to table cell in a header and body
|
||||||
// Import from 'docx' rather than '../build' if you install from npm
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Document, Header, Media, Packer, Paragraph, Table } from "../build";
|
import { Document, Header, Media, Packer, Paragraph, Table, TableCell, TableRow } from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
|
const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 2,
|
rows: [
|
||||||
columns: 2,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph(image)],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
table.getCell(1, 1).add(new Paragraph(image));
|
|
||||||
|
|
||||||
// Adding same table in the body and in the header
|
// Adding same table in the body and in the header
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
|
@ -1,17 +1,35 @@
|
|||||||
// Example of how you would create a table and add data to it
|
// Example of how you would create a table and add data to it
|
||||||
// Import from 'docx' rather than '../build' if you install from npm
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Document, Packer, Paragraph, Table } from "../build";
|
import { Document, Packer, Paragraph, Table, TableCell, TableRow } from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 4,
|
rows: [
|
||||||
columns: 4,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Hello")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("World")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
table.getCell(2, 2).add(new Paragraph("Hello"));
|
|
||||||
|
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
children: [table],
|
children: [table],
|
||||||
});
|
});
|
||||||
|
@ -1,52 +1,259 @@
|
|||||||
// Multiple cells merging in the same table
|
// Multiple cells merging in the same table - Rows and Columns
|
||||||
// Import from 'docx' rather than '../build' if you install from npm
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Document, Packer, Paragraph, Table } from "../build";
|
import { Document, Packer, Paragraph, Table, TableCell, TableRow } from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 13,
|
rows: [
|
||||||
columns: 6,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,1")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,3")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,4")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,0")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,2")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,4")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,1")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,3")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,4")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,1")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,2")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,3")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,4")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,5")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("4,0")],
|
||||||
|
columnSpan: 5,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("4,5")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
let row = 0;
|
const table2 = new Table({
|
||||||
table.getCell(row, 0).add(new Paragraph("0,0"));
|
rows: [
|
||||||
table.getCell(row, 1).add(new Paragraph("0,1"));
|
new TableRow({
|
||||||
table.getCell(row, 3).add(new Paragraph("0,3"));
|
children: [
|
||||||
table.getCell(row, 4).add(new Paragraph("0,4"));
|
new TableCell({
|
||||||
table.getRow(row).mergeCells(4, 5);
|
children: [new Paragraph("0,0")],
|
||||||
table.getRow(row).mergeCells(1, 2);
|
}),
|
||||||
row = 1;
|
new TableCell({
|
||||||
table.getCell(row, 0).add(new Paragraph("1,0"));
|
children: [new Paragraph("0,1")],
|
||||||
table.getCell(row, 2).add(new Paragraph("1,2"));
|
rowSpan: 2,
|
||||||
table.getCell(row, 4).add(new Paragraph("1,4"));
|
}),
|
||||||
table.getRow(row).mergeCells(4, 5);
|
new TableCell({
|
||||||
table.getRow(row).mergeCells(2, 3);
|
children: [new Paragraph("0,2")],
|
||||||
table.getRow(row).mergeCells(0, 1);
|
}),
|
||||||
|
new TableCell({
|
||||||
row = 2;
|
children: [new Paragraph("0,3")],
|
||||||
table.getCell(row, 0).add(new Paragraph("2,0"));
|
}),
|
||||||
table.getCell(row, 1).add(new Paragraph("2,1"));
|
new TableCell({
|
||||||
table.getCell(row, 2).add(new Paragraph("2,2"));
|
children: [new Paragraph("0,4")],
|
||||||
table.getCell(row, 3).add(new Paragraph("2,3"));
|
}),
|
||||||
table.getCell(row, 4).add(new Paragraph("2,4"));
|
new TableCell({
|
||||||
table.getRow(row).mergeCells(4, 5);
|
children: [new Paragraph("0,5")],
|
||||||
table.getRow(row).mergeCells(1, 2);
|
}),
|
||||||
row = 3;
|
],
|
||||||
table.getCell(row, 0).add(new Paragraph("3,0"));
|
}),
|
||||||
table.getCell(row, 1).add(new Paragraph("3,1"));
|
new TableRow({
|
||||||
table.getCell(row, 2).add(new Paragraph("3,2"));
|
children: [
|
||||||
table.getCell(row, 3).add(new Paragraph("3,3"));
|
new TableCell({
|
||||||
table.getCell(row, 4).add(new Paragraph("3,4"));
|
children: [new Paragraph("1,0")],
|
||||||
table.getCell(row, 5).add(new Paragraph("3,5"));
|
}),
|
||||||
row = 4;
|
new TableCell({
|
||||||
table.getCell(row, 0).add(new Paragraph("4,0"));
|
children: [new Paragraph("1,2")],
|
||||||
table.getCell(row, 5).add(new Paragraph("4,5"));
|
}),
|
||||||
table.getRow(row).mergeCells(0, 4);
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,3")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,4")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,5")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,1")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,2")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,3")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,4")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,5")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,1")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,2")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,3")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,4")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,5")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("4,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("4,1")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("4,2")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("4,3")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("4,4")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("4,5")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
children: [table],
|
children: [table, new Paragraph(""), table2],
|
||||||
});
|
});
|
||||||
|
|
||||||
Packer.toBuffer(doc).then((buffer) => {
|
Packer.toBuffer(doc).then((buffer) => {
|
||||||
|
@ -1,18 +1,80 @@
|
|||||||
// Add image to table cell
|
// Add image to table cell
|
||||||
// Import from 'docx' rather than '../build' if you install from npm
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Document, Packer, Paragraph, Table } from "../build";
|
import { Document, Packer, Paragraph, Table, TableCell, TableRow } from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 4,
|
rows: [
|
||||||
columns: 4,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
rowSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("Hello")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
table.getCell(2, 2).add(new Paragraph("Hello"));
|
|
||||||
table.getColumn(3).mergeCells(1, 2);
|
|
||||||
|
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
children: [table],
|
children: [table],
|
||||||
});
|
});
|
||||||
|
@ -8,7 +8,7 @@ const doc = new Document();
|
|||||||
doc.addSection({
|
doc.addSection({
|
||||||
properties: {
|
properties: {
|
||||||
column: {
|
column: {
|
||||||
width: 708,
|
space: 708,
|
||||||
count: 2,
|
count: 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -23,7 +23,7 @@ doc.addSection({
|
|||||||
doc.addSection({
|
doc.addSection({
|
||||||
properties: {
|
properties: {
|
||||||
column: {
|
column: {
|
||||||
width: 708,
|
space: 708,
|
||||||
count: 3,
|
count: 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
49
demo/47-number-of-total-pages-section.ts
Normal file
49
demo/47-number-of-total-pages-section.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Multiple sections with total number of pages in each section
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, Packer, PageNumberFormat, TextRun } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
|
||||||
|
|
||||||
|
const header = doc.createHeader();
|
||||||
|
header.createParagraph("Header on another page");
|
||||||
|
const footer = doc.createFooter();
|
||||||
|
footer.createParagraph("Foo Bar corp. ")
|
||||||
|
.center()
|
||||||
|
.addRun(new TextRun("Page Number: ").pageNumber())
|
||||||
|
.addRun(new TextRun(" to ").numberOfTotalPagesSection());
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
headers: {
|
||||||
|
default: header,
|
||||||
|
},
|
||||||
|
footers: {
|
||||||
|
default: footer,
|
||||||
|
},
|
||||||
|
pageNumberStart: 1,
|
||||||
|
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.createParagraph("Section 1").pageBreak();
|
||||||
|
doc.createParagraph("Section 1").pageBreak();
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
headers: {
|
||||||
|
default: header,
|
||||||
|
},
|
||||||
|
footers: {
|
||||||
|
default: footer,
|
||||||
|
},
|
||||||
|
pageNumberStart: 1,
|
||||||
|
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.createParagraph("Section 2").pageBreak();
|
||||||
|
doc.createParagraph("Section 2").pageBreak();
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
@ -5,17 +5,16 @@
|
|||||||
To make a bullet point, simply make a paragraph into a bullet point:
|
To make a bullet point, simply make a paragraph into a bullet point:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const text = new docx.TextRun("Bullet points");
|
const text = new TextRun("Bullet points");
|
||||||
const paragraph = new docx.Paragraph(text).bullet();
|
const paragraph = new Paragraph({
|
||||||
|
text: "Bullet points",
|
||||||
const text2 = new docx.TextRun("Are awesome");
|
bullet: {
|
||||||
const paragraph2 = new docx.Paragraph(text2).bullet();
|
level: 0, // How deep you want the bullet to me
|
||||||
|
},
|
||||||
doc.add(paragraph);
|
});
|
||||||
doc.add(paragraph2);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### This will produce:
|
### This will produce:
|
||||||
|
|
||||||
* Bullet points
|
- Bullet points
|
||||||
* Are awesome
|
- Are awesome
|
||||||
|
@ -2,52 +2,46 @@
|
|||||||
|
|
||||||
!> Headers and Footers requires an understanding of [Sections](usage/sections.md).
|
!> Headers and Footers requires an understanding of [Sections](usage/sections.md).
|
||||||
|
|
||||||
|
Every Section has a sections which you can define its Headers and Footers:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
doc.addSection({
|
||||||
|
headers: {
|
||||||
|
default: new Header({ // The standard default header
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
first: new Header({ // The first header
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
even: new Header({ // The header on every other page
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
footers: {
|
||||||
|
default: new Footer({ // The standard default footer
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
first: new Footer({ // The first footer
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
even: new Footer({ // The footer on every other page
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
children: [],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want more head
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
Creating Headers and footers is simple. Access the `Header` and `Footer` by doing so like this:
|
Example showing basic header and footer
|
||||||
|
|
||||||
```ts
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/8-header-footer.ts ':include')
|
||||||
doc.Header;
|
|
||||||
doc.Footer;
|
|
||||||
```
|
|
||||||
|
|
||||||
You can call the same methods as you would with a `File`:
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/8-header-footer.ts_
|
||||||
|
|
||||||
```ts
|
|
||||||
doc.Header.createParagraph("Header text");
|
|
||||||
doc.Footer.createParagraph("Footer text");
|
|
||||||
```
|
|
||||||
|
|
||||||
Even add images:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
doc.Header.createImage([BUFFER_OF_YOUR_IMAGE]);
|
|
||||||
doc.Footer.createImage([BUFFER_OF_YOUR_IMAGE]);
|
|
||||||
```
|
|
||||||
|
|
||||||
Refer to [`demo8.ts`](https://github.com/dolanmiu/docx/blob/master/demo/demo8.ts) for more information.
|
|
||||||
|
|
||||||
## Multiple Headers and Footers
|
## Multiple Headers and Footers
|
||||||
|
|
||||||
Also all the supported section properties are implemented according to: http://officeopenxml.com/WPsection.php
|
More headers and footers can be accomplished by creating more `Section`. New headers and footers can be set per `Section`
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const header = this.document.createHeader();
|
|
||||||
const footer = this.document.createFooter();
|
|
||||||
|
|
||||||
// Add new section with another header and footer
|
|
||||||
doc.addSection({
|
|
||||||
headers: {
|
|
||||||
default: header
|
|
||||||
},
|
|
||||||
footers: {
|
|
||||||
default: footer
|
|
||||||
},
|
|
||||||
pageNumberStart: 1,
|
|
||||||
pageNumberFormatType: docx.PageNumberFormat.DECIMAL,
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,22 +227,22 @@ Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"), 200, 200, {
|
|||||||
|
|
||||||
Importing Images from file system path
|
Importing Images from file system path
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo5.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/5-images.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/5-images.ts_
|
||||||
|
|
||||||
### Add images to header and footer
|
### Add images to header and footer
|
||||||
|
|
||||||
Example showing how to add image to headers and footers
|
Example showing how to add image to headers and footers
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo9.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/9-images-in-header-and-footer.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/9-images-in-header-and-footer.ts_
|
||||||
|
|
||||||
### Floating images
|
### Floating images
|
||||||
|
|
||||||
Example showing how to float images on top of text and optimally give a `margin`
|
Example showing how to float images on top of text and optimally give a `margin`
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo38.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/38-text-wrapping.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo38.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/38-text-wrapping.ts_
|
||||||
|
@ -86,11 +86,3 @@ topLevelP.setNumbering(concrete, 0);
|
|||||||
subP.setNumbering(concrete, 1);
|
subP.setNumbering(concrete, 1);
|
||||||
subSubP.setNumbering(concrete, 2);
|
subSubP.setNumbering(concrete, 2);
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, you need to let your exporter know about your numbering
|
|
||||||
styles when you're ready to render the document:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const packer = new Packer(doc, undefined, undefined, numbering);
|
|
||||||
packer.pack(myOutput);
|
|
||||||
```
|
|
||||||
|
@ -61,6 +61,6 @@ doc.Header.createParagraph().addRun(new TextRun("Page ").pageNumber()).addRun(ne
|
|||||||
|
|
||||||
Adding page numbers to Header and Footer
|
Adding page numbers to Header and Footer
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo39.ts ':include')
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/39-page-numbers.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo39.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/39-page-numbers.ts_
|
||||||
|
@ -265,7 +265,7 @@ const paragraph = new Paragraph({
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
Example: https://github.com/dolanmiu/docx/blob/master/demo/demo15.ts
|
Example: https://github.com/dolanmiu/docx/blob/master/demo/15-page-break-before.ts
|
||||||
|
|
||||||
## Page break control
|
## Page break control
|
||||||
|
|
||||||
|
@ -44,4 +44,4 @@ doc.add(paragraph);
|
|||||||
doc.createParagraph("Some normal text");
|
doc.createParagraph("Some normal text");
|
||||||
```
|
```
|
||||||
|
|
||||||
Example: https://github.com/dolanmiu/docx/blob/master/demo/demo13.ts
|
Example: https://github.com/dolanmiu/docx/blob/master/demo/13-xml-styles.ts
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
You can generate table of contents with `docx`. More information can be found [here](http://officeopenxml.com/WPtableOfContents.php).
|
You can generate table of contents with `docx`. More information can be found [here](http://officeopenxml.com/WPtableOfContents.php).
|
||||||
|
|
||||||
>Tables of Contents are fields and, by design, it's content is only generated or updated by Word. We can't do it programatically.
|
> Tables of Contents are fields and, by design, it's content is only generated or updated by Word. We can't do it programatically.
|
||||||
>This is why, when you open a the file, Word you will prompt the message "This document contains fields that may refer to other files. Do you want to update the fields in this document?".
|
> This is why, when you open a the file, Word you will prompt the message "This document contains fields that may refer to other files. Do you want to update the fields in this document?".
|
||||||
>You have say yes to Word generate the content of all table of contents.
|
> You have say yes to Word generate the content of all table of contents.
|
||||||
|
|
||||||
The complete documentation can be found [here](https://www.ecma-international.org/publications/standards/Ecma-376.htm) (at Part 1, Page 1251).
|
The complete documentation can be found [here](https://www.ecma-international.org/publications/standards/Ecma-376.htm) (at Part 1, Page 1251).
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ All you need to do is create a `TableOfContents` object and assign it to the doc
|
|||||||
const toc = new TableOfContents("Summary", {
|
const toc = new TableOfContents("Summary", {
|
||||||
hyperlink: true,
|
hyperlink: true,
|
||||||
headingStyleRange: "1-5",
|
headingStyleRange: "1-5",
|
||||||
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)]
|
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)],
|
||||||
});
|
});
|
||||||
|
|
||||||
doc.addTableOfContents(toc);
|
doc.addTableOfContents(toc);
|
||||||
@ -27,23 +27,23 @@ doc.addTableOfContents(toc);
|
|||||||
Here is the list of all options that you can use to generate your tables of contents:
|
Here is the list of all options that you can use to generate your tables of contents:
|
||||||
|
|
||||||
| Option | Type | TOC Field Switch | Description |
|
| Option | Type | TOC Field Switch | Description |
|
||||||
| --- | --- | --- | --- |
|
| ------------------------------- | ------------ | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|captionLabel|string|`\a`|Includes captioned items, but omits caption labels and numbers. The identifier designated by `text` in this switch's field-argument corresponds to the caption label. Use ``\c`` to build a table of captions with labels and numbers.|
|
| captionLabel | string | `\a` | Includes captioned items, but omits caption labels and numbers. The identifier designated by `text` in this switch's field-argument corresponds to the caption label. Use `\c` to build a table of captions with labels and numbers. |
|
||||||
|entriesFromBookmark|string|`\b`|Includes entries only from the portion of the document marked by the bookmark named by `text` in this switch's field-argument.|
|
| entriesFromBookmark | string | `\b` | Includes entries only from the portion of the document marked by the bookmark named by `text` in this switch's field-argument. |
|
||||||
|captionLabelIncludingNumbers|string|`\c`|Includes figures, tables, charts, and other items that are numbered by a SEQ field (§17.16.5.56). The sequence identifier designated by `text` in this switch's field-argument, which corresponds to the caption label, shall match the identifier in the corresponding SEQ field.|
|
| captionLabelIncludingNumbers | string | `\c` | Includes figures, tables, charts, and other items that are numbered by a SEQ field (§17.16.5.56). The sequence identifier designated by `text` in this switch's field-argument, which corresponds to the caption label, shall match the identifier in the corresponding SEQ field. |
|
||||||
|sequenceAndPageNumbersSeparator|string|`\d`|When used with `\s`, the `text` in this switch's field-argument defines the separator between sequence and page numbers. The default separator is a hyphen (-).|
|
| sequenceAndPageNumbersSeparator | string | `\d` | When used with `\s`, the `text` in this switch's field-argument defines the separator between sequence and page numbers. The default separator is a hyphen (-). |
|
||||||
|tcFieldIdentifier|string|`\f`|Includes only those TC fields whose identifier exactly matches the `text` in this switch's field-argument (which is typically a letter).|
|
| tcFieldIdentifier | string | `\f` | Includes only those TC fields whose identifier exactly matches the `text` in this switch's field-argument (which is typically a letter). |
|
||||||
|hyperlink|boolean|`\h`|Makes the table of contents entries hyperlinks.|
|
| hyperlink | boolean | `\h` | Makes the table of contents entries hyperlinks. |
|
||||||
|tcFieldLevelRange|string|`\l`|Includes TC fields that assign entries to one of the levels specified by `text` in this switch's field-argument as a range having the form startLevel-endLevel, where startLevel and endLevel are integers, and startLevel has a value equal-to or less-than endLevel. TC fields that assign entries to lower levels are skipped.|
|
| tcFieldLevelRange | string | `\l` | Includes TC fields that assign entries to one of the levels specified by `text` in this switch's field-argument as a range having the form startLevel-endLevel, where startLevel and endLevel are integers, and startLevel has a value equal-to or less-than endLevel. TC fields that assign entries to lower levels are skipped. |
|
||||||
|pageNumbersEntryLevelsRange|string|`\n`|Without field-argument, omits page numbers from the table of contents. Page numbers are omitted from all levels unless a range of entry levels is specified by `text` in this switch's field-argument. A range is specified as for `\l`.|
|
| pageNumbersEntryLevelsRange | string | `\n` | Without field-argument, omits page numbers from the table of contents. Page numbers are omitted from all levels unless a range of entry levels is specified by `text` in this switch's field-argument. A range is specified as for `\l`. |
|
||||||
|headingStyleRange|string|`\o`|Uses paragraphs formatted with all or the specified range of builtin heading styles. Headings in a style range are specified by `text` in this switch's field-argument using the notation specified as for `\l`, where each integer corresponds to the style with a style ID of HeadingX (e.g. 1 corresponds to Heading1). If no heading range is specified, all heading levels used in the document are listed.|
|
| headingStyleRange | string | `\o` | Uses paragraphs formatted with all or the specified range of builtin heading styles. Headings in a style range are specified by `text` in this switch's field-argument using the notation specified as for `\l`, where each integer corresponds to the style with a style ID of HeadingX (e.g. 1 corresponds to Heading1). If no heading range is specified, all heading levels used in the document are listed. |
|
||||||
|entryAndPageNumberSeparator|string|`\p`|`text` in this switch's field-argument specifies a sequence of characters that separate an entry and its page number. The default is a tab with leader dots.|
|
| entryAndPageNumberSeparator | string | `\p` | `text` in this switch's field-argument specifies a sequence of characters that separate an entry and its page number. The default is a tab with leader dots. |
|
||||||
|seqFieldIdentifierForPrefix|string|`\s`|For entries numbered with a SEQ field (§17.16.5.56), adds a prefix to the page number. The prefix depends on the type of entry. `text` in this switch's field-argument shall match the identifier in the SEQ field.|
|
| seqFieldIdentifierForPrefix | string | `\s` | For entries numbered with a SEQ field (§17.16.5.56), adds a prefix to the page number. The prefix depends on the type of entry. `text` in this switch's field-argument shall match the identifier in the SEQ field. |
|
||||||
|stylesWithLevels|StyleLevel[]|`\t`| Uses paragraphs formatted with styles other than the built-in heading styles. `text` in this switch's field-argument specifies those styles as a set of comma-separated doublets, with each doublet being a comma-separated set of style name and table of content level. `\t` can be combined with `\o`.|
|
| stylesWithLevels | StyleLevel[] | `\t` | Uses paragraphs formatted with styles other than the built-in heading styles. `text` in this switch's field-argument specifies those styles as a set of comma-separated doublets, with each doublet being a comma-separated set of style name and table of content level. `\t` can be combined with `\o`. |
|
||||||
|useAppliedParagraphOutlineLevel|boolean|`\u`|Uses the applied paragraph outline level.|
|
| useAppliedParagraphOutlineLevel | boolean | `\u` | Uses the applied paragraph outline level. |
|
||||||
|preserveTabInEntries|boolean|`\w`|Preserves tab entries within table entries.|
|
| preserveTabInEntries | boolean | `\w` | Preserves tab entries within table entries. |
|
||||||
|preserveNewLineInEntries|boolean|`\x`|Preserves newline characters within table entries.|
|
| preserveNewLineInEntries | boolean | `\x` | Preserves newline characters within table entries. |
|
||||||
|hideTabAndPageNumbersInWebView|boolean|`\z`|Hides tab leader and page numbers in web page view (§17.18.102).|
|
| hideTabAndPageNumbersInWebView | boolean | `\z` | Hides tab leader and page numbers in web page view (§17.18.102). |
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ Here is the list of all options that you can use to generate your tables of cont
|
|||||||
const toc = new TableOfContents("Summary", {
|
const toc = new TableOfContents("Summary", {
|
||||||
hyperlink: true,
|
hyperlink: true,
|
||||||
headingStyleRange: "1-5",
|
headingStyleRange: "1-5",
|
||||||
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)]
|
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)],
|
||||||
});
|
});
|
||||||
|
|
||||||
doc.addTableOfContents(toc);
|
doc.addTableOfContents(toc);
|
||||||
@ -71,6 +71,6 @@ doc.add(new Paragraph("My Spectacular Style #1").style("MySpectacularStyle").pag
|
|||||||
|
|
||||||
### Complete example
|
### Complete example
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo28.ts ':include')
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/28-table-of-contents.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo28.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/28-table-of-contents.ts_
|
||||||
|
@ -1,306 +1,387 @@
|
|||||||
# Tables
|
# Tables
|
||||||
|
|
||||||
You can create tables with `docx`. More information can be found [here](http://officeopenxml.com/WPtable.php).
|
!> Paragraphs requires an understanding of [Sections](usage/sections.md).
|
||||||
|
|
||||||
## Create Table
|
## Intro
|
||||||
|
|
||||||
To create a table, simply create one with `new Table()`, then add it to the document: `doc.add()`.
|
* `Tables` contain a list of `Rows`
|
||||||
|
* `Rows` contain a list of `TableCells`
|
||||||
|
* `TableCells` contain a list of `Parahraphs` and/or `Tables`. You can add `Tables` as tables can be nested inside each other
|
||||||
|
|
||||||
```ts
|
Create a simple table like so:
|
||||||
const table = doc.add(new Table({
|
|
||||||
rows: [NUMBER OF ROWS],
|
|
||||||
columns: [NUMBER OF COLUMNS]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, you can create a table object directly, and then add it in the `document`
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const table = new Table(4, 4);
|
|
||||||
doc.add(table);
|
|
||||||
```
|
|
||||||
|
|
||||||
The snippet below creates a table of 2 rows and 4 columns.
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 2,
|
rows: [Array of `TableRow`s]
|
||||||
columns: 4,
|
|
||||||
});
|
});
|
||||||
doc.add(table);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Rows and Columns
|
Then add the table in the `section`
|
||||||
|
|
||||||
You can get a row or a column from a table like so, where `index` is a number:
|
|
||||||
|
|
||||||
### Get Row
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const row = doc.getRow(index);
|
doc.addSection({
|
||||||
|
children: [table],
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
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:
|
## Table
|
||||||
|
|
||||||
|
### Set Width
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
row.mergeCells(startIndex, endIndex);
|
const table = new Table({
|
||||||
|
...,
|
||||||
|
width: {
|
||||||
|
size: [TABLE_WIDTH],
|
||||||
|
type: WidthType,
|
||||||
|
}
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
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:
|
For example:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const cell = table.getCell(0, 2);
|
|
||||||
|
|
||||||
const cell = row.getCell(0);
|
const table = new Table({
|
||||||
|
...,
|
||||||
|
width: {
|
||||||
|
size: 4535,
|
||||||
|
type: WidthType.DXA,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
const cell = column.getCell(2);
|
### Pagination
|
||||||
|
|
||||||
|
#### Prevent row pagination
|
||||||
|
|
||||||
|
To prevent breaking contents of a row across multiple pages, call `cantSplit`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const table = new Table({
|
||||||
|
rows: [],
|
||||||
|
cantSplit: true,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Table Row
|
||||||
|
|
||||||
|
A table consists of multiple `table rows`. Table rows have a list of `children` which accepts a list of `table cells` explained below. You can create a simple `table row` like so:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const tableRow = new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Or preferably, add the tableRow directly into the `table` without declaring a variable:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const table = new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
Here is a list of options you can add to the `table row`:
|
||||||
|
|
||||||
|
| Property | Type | Notes |
|
||||||
|
| ----------- | ------------------------------------- | -------- |
|
||||||
|
| children | `Array<TableCell>` | Required |
|
||||||
|
| cantSplit | `boolean` | Optional |
|
||||||
|
| tableHeader | `boolean` | Optional |
|
||||||
|
| height | `{ value: number, rule: HeightRule }` | Optional |
|
||||||
|
|
||||||
|
### Repeat row
|
||||||
|
|
||||||
|
If a table is paginated on multiple pages, it is possible to repeat a row at the top of each new page by setting `tableHeader` to `true`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const row = new TableRow({
|
||||||
|
...,
|
||||||
|
tableHeader: true,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Table Cells
|
||||||
|
|
||||||
|
Cells need to be added in the `table row`, you can create a table cell like:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const tableCell = new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Or preferably, add the tableRow directly into the `table row` without declaring a variable:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const tableRow = new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
| Property | Type | Notes |
|
||||||
|
| ------------- | ----------------------------------- | ----------------------------------------------------------- |
|
||||||
|
| children | `Array<Paragraph | Table>` | Required. You can nest tables by adding a table into a cell |
|
||||||
|
| shading | `ITableShadingAttributesProperties` | Optional |
|
||||||
|
| margins | `ITableCellMarginOptions` | Optional |
|
||||||
|
| verticalAlign | `VerticalAlign` | Optional |
|
||||||
|
| columnSpan | `number` | Optional |
|
||||||
|
| rowSpan | `number` | Optional |
|
||||||
|
| borders | `BorderOptions` | Optional |
|
||||||
|
| width | `{ size: number type: WidthType }` | Optional |
|
||||||
|
|
||||||
|
#### Border Options
|
||||||
|
|
||||||
|
| Property | Type | Notes |
|
||||||
|
| -------- | ----------------------------------------------------- | -------- |
|
||||||
|
| top | `{ style: BorderStyle, size: number, color: string }` | Optional |
|
||||||
|
| bottom | `{ style: BorderStyle, size: number, color: string }` | Optional |
|
||||||
|
| left | `{ style: BorderStyle, size: number, color: string }` | Optional |
|
||||||
|
| right | `{ style: BorderStyle, size: number, color: string }` | Optional |
|
||||||
|
|
||||||
|
##### Example
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const cell = new TableCell({
|
||||||
|
...,
|
||||||
|
borders: {
|
||||||
|
top: {
|
||||||
|
style: BorderStyle.DASH_DOT_STROKED,
|
||||||
|
size: 1,
|
||||||
|
color: "red",
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
style: BorderStyle.THICK_THIN_MEDIUM_GAP,
|
||||||
|
size: 5,
|
||||||
|
color: "889900",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Google DOCS
|
||||||
|
|
||||||
|
Google DOCS does not support start and end borders, instead they use left and right borders. So to set left and right borders for Google DOCS you should use:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const cell = new TableCell({
|
||||||
|
...,
|
||||||
|
borders: {
|
||||||
|
top: {
|
||||||
|
style: BorderStyle.DOT_DOT_DASH,
|
||||||
|
size: 3,
|
||||||
|
color: "green",
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
style: BorderStyle.DOT_DOT_DASH,
|
||||||
|
size: 3,
|
||||||
|
color: "ff8000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Add paragraph to a cell
|
### Add paragraph to a cell
|
||||||
|
|
||||||
Once you have got the cell, you can add data to it with the `add()` method.
|
Once you have got the cell, you can add data to it:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
cell.add(new Paragraph("Hello"));
|
const cell = new TableCell({
|
||||||
|
children: [new Paragraph("Hello")],
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set width of a cell
|
### Set width of a cell
|
||||||
|
|
||||||
You can specify the width of a cell using:
|
You can specify the width of a cell using:
|
||||||
|
|
||||||
`cell.Properties.setWidth(width, format)`
|
```ts
|
||||||
|
const cell = new TableCell({
|
||||||
|
...,
|
||||||
|
width: {
|
||||||
|
size: number,
|
||||||
|
type: WidthType,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
format can be:
|
`WidthType` values can be:
|
||||||
|
|
||||||
- WidthType.AUTO
|
| Property | Notes |
|
||||||
- WidthType.DXA: value is in twentieths of a point
|
| -------- | --------------------------------- |
|
||||||
- WidthType.NIL: is considered as zero
|
| AUTO | |
|
||||||
- WidthType.PCT: percent of table width
|
| DXA | value is in twentieths of a point |
|
||||||
|
| NIL | is considered as zero |
|
||||||
|
| PCT | percent of table width |
|
||||||
|
|
||||||
### Example
|
#### Example
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
cell.Properties.setWidth(100, WidthType.DXA);
|
cell.Properties.setWidth(100, WidthType.DXA);
|
||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
### Nested Tables
|
||||||
cell.Properties.setWidth("50%", WidthType.PCT);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Borders
|
To have a table within a table, simply add it in the `children` block of a `table cell`:
|
||||||
|
|
||||||
BorderStyle can be imported from `docx`. Size determines the thickness. HTML color can be a hex code or alias such as `red`.
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
cell.Borders.addTopBorder([BorderStyle], [SIZE], [HTML COLOR]);
|
const cell = new TableCell({
|
||||||
|
children: [new Table(...)],
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
```ts
|
### Vertical Align
|
||||||
cell.Borders.addBottomBorder([BorderStyle], [SIZE], [HTML COLOR]);
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
|
||||||
cell.Borders.addStartBorder([[BorderStyle]], [SIZE], [HTML COLOR]);
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
|
||||||
cell.Borders.addEndBorder([BorderStyle], [SIZE], [HTML COLOR]);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { BorderStyle } from "docx";
|
|
||||||
|
|
||||||
cell.Borders.addStartBorder(BorderStyle.DOT_DOT_DASH, 3, "green");
|
|
||||||
cell.Borders.addEndBorder(BorderStyle.DOT_DOT_DASH, 3, "#ff8000");
|
|
||||||
```
|
|
||||||
|
|
||||||
### Google DOCS
|
|
||||||
|
|
||||||
Google DOCS does not support start and end borders, instead they use left and right borders. So to set left and right borders for Google DOCS you should use:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { BorderStyle } from "docx";
|
|
||||||
|
|
||||||
cell.Borders.addLeftBorder(BorderStyle.DOT_DOT_DASH, 3, "green");
|
|
||||||
cell.Borders.addRightBorder(BorderStyle.DOT_DOT_DASH, 3, "#ff8000");
|
|
||||||
```
|
|
||||||
|
|
||||||
## Set Width
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { WidthType } from "docx";
|
|
||||||
|
|
||||||
table.setWidth([WIDTH], [OPTIONAL WidthType. Defaults to DXA]);
|
|
||||||
```
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
table.setWidth(4535, WidthType.DXA);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Vertical Align
|
|
||||||
|
|
||||||
Sets the vertical alignment of the contents of the cell
|
Sets the vertical alignment of the contents of the cell
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { VerticalAlign } from "docx";
|
const cell = new TableCell({
|
||||||
|
...,
|
||||||
cell.setVerticalAlign([VerticalAlign TYPE]);
|
verticalAlign: VerticalAlign,
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`VerticalAlign` values can be:
|
||||||
|
|
||||||
|
| Property | Notes |
|
||||||
|
| -------- | ------------------------------------------ |
|
||||||
|
| BOTTOM | Align the contents on the bottom |
|
||||||
|
| CENTER | Align the contents on the center |
|
||||||
|
| TOP | Align the contents on the top. The default |
|
||||||
|
|
||||||
For example, to center align a cell:
|
For example, to center align a cell:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
cell.setVerticalAlign(VerticalAlign.CENTER);
|
const cell = new TableCell({
|
||||||
|
verticalAlign: VerticalAlign.CENTER,
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Rows
|
## Merging cells together
|
||||||
|
|
||||||
To get a row, use the `getRow` method on a `table`. There are a handful of methods which you can apply to a row which will be explained below.
|
### Row Merge
|
||||||
|
|
||||||
|
When cell rows are merged, it counts as multiple rows, so be sure to remove excess cells. It is similar to how HTML's `rowspan` works.
|
||||||
|
https://www.w3schools.com/tags/att_td_rowspan.asp
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
table.getRow([ROW INDEX]);
|
const cell = new TableCell({
|
||||||
```
|
...,
|
||||||
|
rowSpan: [NUMBER_OF_CELLS_TO_MERGE],
|
||||||
## Merge cells together
|
});
|
||||||
|
|
||||||
### Merging on a row
|
|
||||||
|
|
||||||
First obtain the row, and call `mergeCells()`. The first argument is where the merge should start. The second argument is where the merge should end.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
table.getRow(0).mergeCells([FROM INDEX], [TO INDEX]);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
This will merge 3 cells together starting from index `0`:
|
The example will merge three rows together.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
table.getRow(0).mergeCells(0, 2);
|
const cell = new TableCell({
|
||||||
|
...,
|
||||||
|
rowSpan: 3,
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Merging on a column
|
### Column Merge
|
||||||
|
|
||||||
It has not been implemented yet, but it will follow a similar structure as merging a row.
|
When cell columns are merged, it counts as multiple columns, so be sure to remove excess cells. It is similar to how HTML's `colspan` works.
|
||||||
|
https://www.w3schools.com/tags/att_td_colspan.asp
|
||||||
## Nested Tables
|
|
||||||
|
|
||||||
To have a table within a table
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
cell.add(new Table(1, 1));
|
const cell = new TableCell({
|
||||||
|
...,
|
||||||
|
columnSpan: [NUMBER_OF_CELLS_TO_MERGE],
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Pagination
|
#### Example
|
||||||
|
|
||||||
###Prevent row pagination
|
The example will merge three columns together.
|
||||||
To prevent breaking contents of a row across multiple pages, call `cantSplit()`:
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
table.getRow(0).setCantSplit();
|
const cell = new TableCell({
|
||||||
```
|
...,
|
||||||
|
columnSpan: 3,
|
||||||
###Repeat row
|
});
|
||||||
If a table is paginated on multiple pages, it is possible to repeat a row at the top of each new page calling `setTableHeader()`:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
table.getRow(0).setTableHeader();
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo4.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/4-basic-table.ts ":include")
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo4.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/4-basic-table.ts_
|
||||||
|
|
||||||
### Custom borders
|
### Custom borders
|
||||||
|
|
||||||
Example showing how to add colourful borders to tables
|
Example showing how to add colourful borders to tables
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo20.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/20-table-cell-borders.ts ":include")
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo20.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/20-table-cell-borders.ts_
|
||||||
|
|
||||||
### Adding images
|
### Adding images
|
||||||
|
|
||||||
Example showing how to add images to tables
|
Example showing how to add images to tables
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo24.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/24-images-to-table-cell.ts ":include")
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo24.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/24-images-to-table-cell.ts_
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo36.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/36-image-to-table-cell.ts ":include")
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo36.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/36-image-to-table-cell.ts_
|
||||||
|
|
||||||
### Alignment of text in a cell
|
### Alignment of text in a cell
|
||||||
|
|
||||||
Example showing how align text in a table cell
|
Example showing how align text in a table cell
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo31.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/31-tables.ts ":include")
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo31.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/31-tables.ts_
|
||||||
|
|
||||||
### Merging rows
|
### Shading
|
||||||
|
|
||||||
Example showing merging of `rows`
|
Example showing merging of columns and rows and shading
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo32.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/32-merge-table-cells.ts ":include")
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo32.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/32-merge-table-cells.ts_
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo41.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/41-merge-table-cells-2.ts ":include")
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo41.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/41-merge-table-cells-2.ts_
|
||||||
|
|
||||||
### Merging columns
|
### Merging columns
|
||||||
|
|
||||||
Example showing merging of `columns`
|
Example showing merging of columns and rows
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo43.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/43-images-to-table-cell-2.ts ":include")
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo43.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/43-images-to-table-cell-2.ts_
|
||||||
|
|
||||||
### Floating tables
|
### Floating tables
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo34.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/34-floating-tables.ts ":include")
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo34.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/34-floating-tables.ts_
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "docx",
|
"name": "docx",
|
||||||
"version": "5.0.0-rc5",
|
"version": "5.0.0-rc6",
|
||||||
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
|
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
|
||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { assert, expect } from "chai";
|
import { assert, expect } from "chai";
|
||||||
|
import * as sinon from "sinon";
|
||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
import * as file from "file";
|
import { Paragraph, TextRun } from "file";
|
||||||
import { CoreProperties } from "file/core-properties";
|
import { CoreProperties } from "file/core-properties";
|
||||||
import { Attributes } from "file/xml-components";
|
import { Attributes } from "file/xml-components";
|
||||||
|
|
||||||
@ -14,22 +15,22 @@ describe("Formatter", () => {
|
|||||||
|
|
||||||
describe("#format()", () => {
|
describe("#format()", () => {
|
||||||
it("should format simple paragraph", () => {
|
it("should format simple paragraph", () => {
|
||||||
const paragraph = new file.Paragraph("");
|
const paragraph = new Paragraph("");
|
||||||
const newJson = formatter.format(paragraph);
|
const newJson = formatter.format(paragraph);
|
||||||
assert.isDefined(newJson["w:p"]);
|
assert.isDefined(newJson["w:p"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should remove xmlKeys", () => {
|
it("should remove xmlKeys", () => {
|
||||||
const paragraph = new file.Paragraph("");
|
const paragraph = new Paragraph("");
|
||||||
const newJson = formatter.format(paragraph);
|
const newJson = formatter.format(paragraph);
|
||||||
const stringifiedJson = JSON.stringify(newJson);
|
const stringifiedJson = JSON.stringify(newJson);
|
||||||
assert(stringifiedJson.indexOf("xmlKeys") < 0);
|
assert(stringifiedJson.indexOf("xmlKeys") < 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should format simple paragraph with bold text", () => {
|
it("should format simple paragraph with bold text", () => {
|
||||||
const paragraph = new file.Paragraph("");
|
const paragraph = new Paragraph("");
|
||||||
paragraph.addRun(
|
paragraph.addRun(
|
||||||
new file.TextRun({
|
new TextRun({
|
||||||
text: "test",
|
text: "test",
|
||||||
bold: true,
|
bold: true,
|
||||||
}),
|
}),
|
||||||
@ -63,7 +64,7 @@ describe("Formatter", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should should change 'p' tag into 'w:p' tag", () => {
|
it("should should change 'p' tag into 'w:p' tag", () => {
|
||||||
const paragraph = new file.Paragraph("");
|
const paragraph = new Paragraph("");
|
||||||
const newJson = formatter.format(paragraph);
|
const newJson = formatter.format(paragraph);
|
||||||
assert.isDefined(newJson["w:p"]);
|
assert.isDefined(newJson["w:p"]);
|
||||||
});
|
});
|
||||||
@ -76,5 +77,13 @@ describe("Formatter", () => {
|
|||||||
const newJson = formatter.format(properties);
|
const newJson = formatter.format(properties);
|
||||||
assert.isDefined(newJson["cp:coreProperties"]);
|
assert.isDefined(newJson["cp:coreProperties"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should call the prep method only once", () => {
|
||||||
|
const paragraph = new Paragraph("");
|
||||||
|
const spy = sinon.spy(paragraph, "prepForXml");
|
||||||
|
|
||||||
|
formatter.format(paragraph);
|
||||||
|
expect(spy.calledOnce).to.equal(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
/* tslint:disable:typedef space-before-function-paren */
|
/* tslint:disable:typedef space-before-function-paren */
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
import * as sinon from "sinon";
|
||||||
|
|
||||||
import { File, Footer, Header } from "file";
|
import { File, Footer, Header, Paragraph } from "file";
|
||||||
|
|
||||||
import { Compiler } from "./next-compiler";
|
import { Compiler } from "./next-compiler";
|
||||||
|
|
||||||
@ -72,5 +73,22 @@ describe("Compiler", () => {
|
|||||||
expect(fileNames).to.include("word/footer2.xml");
|
expect(fileNames).to.include("word/footer2.xml");
|
||||||
expect(fileNames).to.include("word/_rels/footer2.xml.rels");
|
expect(fileNames).to.include("word/_rels/footer2.xml.rels");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should call the format method X times equalling X files to be formatted", () => {
|
||||||
|
// This test is required because before, there was a case where Document was formatted twice, which was inefficient
|
||||||
|
// This also caused issues such as running prepForXml multiple times as format() was ran multiple times.
|
||||||
|
const paragraph = new Paragraph("");
|
||||||
|
const doc = new File();
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
properties: {},
|
||||||
|
children: [paragraph],
|
||||||
|
});
|
||||||
|
// tslint:disable-next-line: no-string-literal
|
||||||
|
const spy = sinon.spy(compiler["formatter"], "format");
|
||||||
|
|
||||||
|
compiler.compile(file);
|
||||||
|
expect(spy.callCount).to.equal(10);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -68,13 +68,13 @@ export class Compiler {
|
|||||||
file.verifyUpdateFields();
|
file.verifyUpdateFields();
|
||||||
const documentRelationshipCount = file.DocumentRelationships.RelationshipCount + 1;
|
const documentRelationshipCount = file.DocumentRelationships.RelationshipCount + 1;
|
||||||
|
|
||||||
|
const documentXmlData = xml(this.formatter.format(file.Document), prettify);
|
||||||
|
const documentMediaDatas = this.imageReplacer.getMediaData(documentXmlData, file.Media);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Relationships: {
|
Relationships: {
|
||||||
data: (() => {
|
data: (() => {
|
||||||
const xmlData = xml(this.formatter.format(file.Document), prettify);
|
documentMediaDatas.forEach((mediaData, i) => {
|
||||||
const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media);
|
|
||||||
|
|
||||||
mediaDatas.forEach((mediaData, i) => {
|
|
||||||
file.DocumentRelationships.createRelationship(
|
file.DocumentRelationships.createRelationship(
|
||||||
documentRelationshipCount + i,
|
documentRelationshipCount + i,
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||||
@ -88,9 +88,7 @@ export class Compiler {
|
|||||||
},
|
},
|
||||||
Document: {
|
Document: {
|
||||||
data: (() => {
|
data: (() => {
|
||||||
const tempXmlData = xml(this.formatter.format(file.Document), prettify);
|
const xmlData = this.imageReplacer.replace(documentXmlData, documentMediaDatas, documentRelationshipCount);
|
||||||
const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media);
|
|
||||||
const xmlData = this.imageReplacer.replace(tempXmlData, mediaDatas, documentRelationshipCount);
|
|
||||||
|
|
||||||
return xmlData;
|
return xmlData;
|
||||||
})(),
|
})(),
|
||||||
|
@ -4,30 +4,33 @@ import { Compiler } from "./next-compiler";
|
|||||||
export class Packer {
|
export class Packer {
|
||||||
public static async toBuffer(file: File, prettify?: boolean): Promise<Buffer> {
|
public static async toBuffer(file: File, prettify?: boolean): Promise<Buffer> {
|
||||||
const zip = this.compiler.compile(file, prettify);
|
const zip = this.compiler.compile(file, prettify);
|
||||||
const zipData = (await zip.generateAsync({
|
const zipData = await zip.generateAsync({
|
||||||
type: "nodebuffer",
|
type: "nodebuffer",
|
||||||
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
})) as Buffer;
|
compression: "DEFLATE",
|
||||||
|
});
|
||||||
|
|
||||||
return zipData;
|
return zipData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async toBase64String(file: File, prettify?: boolean): Promise<string> {
|
public static async toBase64String(file: File, prettify?: boolean): Promise<string> {
|
||||||
const zip = this.compiler.compile(file, prettify);
|
const zip = this.compiler.compile(file, prettify);
|
||||||
const zipData = (await zip.generateAsync({
|
const zipData = await zip.generateAsync({
|
||||||
type: "base64",
|
type: "base64",
|
||||||
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
})) as string;
|
compression: "DEFLATE",
|
||||||
|
});
|
||||||
|
|
||||||
return zipData;
|
return zipData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async toBlob(file: File, prettify?: boolean): Promise<Blob> {
|
public static async toBlob(file: File, prettify?: boolean): Promise<Blob> {
|
||||||
const zip = this.compiler.compile(file, prettify);
|
const zip = this.compiler.compile(file, prettify);
|
||||||
const zipData = (await zip.generateAsync({
|
const zipData = await zip.generateAsync({
|
||||||
type: "blob",
|
type: "blob",
|
||||||
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
})) as Blob;
|
compression: "DEFLATE",
|
||||||
|
});
|
||||||
|
|
||||||
return zipData;
|
return zipData;
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,6 @@ describe("Body", () => {
|
|||||||
|
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:body": [
|
"w:body": [
|
||||||
{
|
|
||||||
"w:p": {},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"w:sectPr": [
|
"w:sectPr": [
|
||||||
{ "w:pgSz": { _attr: { "w:w": 10000, "w:h": 10000, "w:orient": "portrait" } } },
|
{ "w:pgSz": { _attr: { "w:w": 10000, "w:h": 10000, "w:orient": "portrait" } } },
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
||||||
import { Paragraph, ParagraphProperties, TableOfContents } from "../..";
|
import { TableOfContents } from "../..";
|
||||||
import { SectionProperties, SectionPropertiesOptions } from "./section-properties/section-properties";
|
import { SectionProperties, SectionPropertiesOptions } from "./section-properties/section-properties";
|
||||||
|
|
||||||
export class Body extends XmlComponent {
|
export class Body extends XmlComponent {
|
||||||
@ -18,9 +18,6 @@ export class Body extends XmlComponent {
|
|||||||
* @param options new section options
|
* @param options new section options
|
||||||
*/
|
*/
|
||||||
public addSection(options: SectionPropertiesOptions): void {
|
public addSection(options: SectionPropertiesOptions): void {
|
||||||
const currentSection = this.sections.pop() as SectionProperties;
|
|
||||||
this.root.push(this.createSectionParagraph(currentSection));
|
|
||||||
|
|
||||||
this.sections.push(new SectionProperties(options));
|
this.sections.push(new SectionProperties(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,12 +36,4 @@ export class Body extends XmlComponent {
|
|||||||
public getTablesOfContents(): TableOfContents[] {
|
public getTablesOfContents(): TableOfContents[] {
|
||||||
return this.root.filter((child) => child instanceof TableOfContents) as TableOfContents[];
|
return this.root.filter((child) => child instanceof TableOfContents) as TableOfContents[];
|
||||||
}
|
}
|
||||||
|
|
||||||
private createSectionParagraph(section: SectionProperties): Paragraph {
|
|
||||||
const paragraph = new Paragraph({});
|
|
||||||
const properties = new ParagraphProperties({});
|
|
||||||
properties.addChildElement(section);
|
|
||||||
paragraph.addChildElement(properties);
|
|
||||||
return paragraph;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
import { FooterReference } from "./footer-reference";
|
||||||
|
import { FooterReferenceType } from "./footer-reference-attributes";
|
||||||
|
|
||||||
|
describe("footerReference", () => {
|
||||||
|
it("should create", () => {
|
||||||
|
const footer = new FooterReference({
|
||||||
|
footerType: FooterReferenceType.DEFAULT,
|
||||||
|
footerId: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(footer);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:footerReference": {
|
||||||
|
_attr: {
|
||||||
|
"r:id": "rId1",
|
||||||
|
"w:type": "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create without a footer type", () => {
|
||||||
|
const footer = new FooterReference({
|
||||||
|
footerId: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(footer);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:footerReference": {
|
||||||
|
_attr: {
|
||||||
|
"r:id": "rId1",
|
||||||
|
"w:type": "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,42 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
import { HeaderReference } from "./header-reference";
|
||||||
|
import { HeaderReferenceType } from "./header-reference-attributes";
|
||||||
|
|
||||||
|
describe("HeaderReference", () => {
|
||||||
|
it("should create", () => {
|
||||||
|
const footer = new HeaderReference({
|
||||||
|
headerType: HeaderReferenceType.DEFAULT,
|
||||||
|
headerId: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(footer);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:headerReference": {
|
||||||
|
_attr: {
|
||||||
|
"r:id": "rId1",
|
||||||
|
"w:type": "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create without a header type", () => {
|
||||||
|
const footer = new HeaderReference({
|
||||||
|
headerId: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(footer);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:headerReference": {
|
||||||
|
_attr: {
|
||||||
|
"r:id": "rId1",
|
||||||
|
"w:type": "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -38,6 +38,7 @@ describe("SectionProperties", () => {
|
|||||||
},
|
},
|
||||||
pageNumberStart: 10,
|
pageNumberStart: 10,
|
||||||
pageNumberFormatType: PageNumberFormat.CARDINAL_TEXT,
|
pageNumberFormatType: PageNumberFormat.CARDINAL_TEXT,
|
||||||
|
titlePage: true,
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(properties);
|
const tree = new Formatter().format(properties);
|
||||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||||
|
@ -6,7 +6,7 @@ import { Formatter } from "export/formatter";
|
|||||||
import { File } from "./file";
|
import { File } from "./file";
|
||||||
import { Footer, Header } from "./header";
|
import { Footer, Header } from "./header";
|
||||||
import { Paragraph } from "./paragraph";
|
import { Paragraph } from "./paragraph";
|
||||||
import { Table } from "./table";
|
import { Table, TableCell, TableRow } from "./table";
|
||||||
import { TableOfContents } from "./table-of-contents";
|
import { TableOfContents } from "./table-of-contents";
|
||||||
|
|
||||||
describe("File", () => {
|
describe("File", () => {
|
||||||
@ -20,8 +20,8 @@ describe("File", () => {
|
|||||||
|
|
||||||
const tree = new Formatter().format(doc.Document.Body);
|
const tree = new Formatter().format(doc.Document.Body);
|
||||||
|
|
||||||
expect(tree["w:body"][1]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default");
|
expect(tree["w:body"][0]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default");
|
||||||
expect(tree["w:body"][1]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("default");
|
expect(tree["w:body"][0]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("default");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create with correct headers and footers", () => {
|
it("should create with correct headers and footers", () => {
|
||||||
@ -39,8 +39,8 @@ describe("File", () => {
|
|||||||
|
|
||||||
const tree = new Formatter().format(doc.Document.Body);
|
const tree = new Formatter().format(doc.Document.Body);
|
||||||
|
|
||||||
expect(tree["w:body"][1]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default");
|
expect(tree["w:body"][0]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default");
|
||||||
expect(tree["w:body"][1]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("default");
|
expect(tree["w:body"][0]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("default");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create with first headers and footers", () => {
|
it("should create with first headers and footers", () => {
|
||||||
@ -58,8 +58,8 @@ describe("File", () => {
|
|||||||
|
|
||||||
const tree = new Formatter().format(doc.Document.Body);
|
const tree = new Formatter().format(doc.Document.Body);
|
||||||
|
|
||||||
expect(tree["w:body"][1]["w:sectPr"][5]["w:headerReference"]._attr["w:type"]).to.equal("first");
|
expect(tree["w:body"][0]["w:sectPr"][5]["w:headerReference"]._attr["w:type"]).to.equal("first");
|
||||||
expect(tree["w:body"][1]["w:sectPr"][7]["w:footerReference"]._attr["w:type"]).to.equal("first");
|
expect(tree["w:body"][0]["w:sectPr"][7]["w:footerReference"]._attr["w:type"]).to.equal("first");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create with correct headers", () => {
|
it("should create with correct headers", () => {
|
||||||
@ -81,13 +81,13 @@ describe("File", () => {
|
|||||||
|
|
||||||
const tree = new Formatter().format(doc.Document.Body);
|
const tree = new Formatter().format(doc.Document.Body);
|
||||||
|
|
||||||
expect(tree["w:body"][1]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default");
|
expect(tree["w:body"][0]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default");
|
||||||
expect(tree["w:body"][1]["w:sectPr"][5]["w:headerReference"]._attr["w:type"]).to.equal("first");
|
expect(tree["w:body"][0]["w:sectPr"][5]["w:headerReference"]._attr["w:type"]).to.equal("first");
|
||||||
expect(tree["w:body"][1]["w:sectPr"][6]["w:headerReference"]._attr["w:type"]).to.equal("even");
|
expect(tree["w:body"][0]["w:sectPr"][6]["w:headerReference"]._attr["w:type"]).to.equal("even");
|
||||||
|
|
||||||
expect(tree["w:body"][1]["w:sectPr"][7]["w:footerReference"]._attr["w:type"]).to.equal("default");
|
expect(tree["w:body"][0]["w:sectPr"][7]["w:footerReference"]._attr["w:type"]).to.equal("default");
|
||||||
expect(tree["w:body"][1]["w:sectPr"][8]["w:footerReference"]._attr["w:type"]).to.equal("first");
|
expect(tree["w:body"][0]["w:sectPr"][8]["w:footerReference"]._attr["w:type"]).to.equal("first");
|
||||||
expect(tree["w:body"][1]["w:sectPr"][9]["w:footerReference"]._attr["w:type"]).to.equal("even");
|
expect(tree["w:body"][0]["w:sectPr"][9]["w:footerReference"]._attr["w:type"]).to.equal("even");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -108,8 +108,15 @@ describe("File", () => {
|
|||||||
file.addSection({
|
file.addSection({
|
||||||
children: [
|
children: [
|
||||||
new Table({
|
new Table({
|
||||||
rows: 1,
|
rows: [
|
||||||
columns: 1,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,7 @@ import * as sinon from "sinon";
|
|||||||
import { FooterWrapper } from "./footer-wrapper";
|
import { FooterWrapper } from "./footer-wrapper";
|
||||||
import { Media } from "./media";
|
import { Media } from "./media";
|
||||||
import { Paragraph } from "./paragraph";
|
import { Paragraph } from "./paragraph";
|
||||||
import { Table } from "./table";
|
import { Table, TableCell, TableRow } from "./table";
|
||||||
|
|
||||||
describe("FooterWrapper", () => {
|
describe("FooterWrapper", () => {
|
||||||
describe("#add", () => {
|
describe("#add", () => {
|
||||||
@ -21,22 +21,20 @@ describe("FooterWrapper", () => {
|
|||||||
const spy = sinon.spy(file.Footer, "add");
|
const spy = sinon.spy(file.Footer, "add");
|
||||||
file.add(
|
file.add(
|
||||||
new Table({
|
new Table({
|
||||||
rows: 1,
|
rows: [
|
||||||
columns: 1,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(spy.called).to.equal(true);
|
expect(spy.called).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call the underlying footer's addImage", () => {
|
|
||||||
const file = new FooterWrapper(new Media(), 1);
|
|
||||||
const spy = sinon.spy(file.Footer, "add");
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
file.addImage({} as any);
|
|
||||||
|
|
||||||
expect(spy.called).to.equal(true);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#addChildElement", () => {
|
describe("#addChildElement", () => {
|
||||||
|
@ -2,7 +2,7 @@ import { XmlComponent } from "file/xml-components";
|
|||||||
|
|
||||||
import { FooterReferenceType } from "./document";
|
import { FooterReferenceType } from "./document";
|
||||||
import { Footer } from "./footer/footer";
|
import { Footer } from "./footer/footer";
|
||||||
import { Image, Media } from "./media";
|
import { Media } from "./media";
|
||||||
import { Paragraph } from "./paragraph";
|
import { Paragraph } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
import { Table } from "./table";
|
import { Table } from "./table";
|
||||||
@ -25,11 +25,6 @@ export class FooterWrapper {
|
|||||||
this.footer.add(item);
|
this.footer.add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addImage(image: Image): FooterWrapper {
|
|
||||||
this.footer.add(image.Paragraph);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addChildElement(childElement: XmlComponent): void {
|
public addChildElement(childElement: XmlComponent): void {
|
||||||
this.footer.addChildElement(childElement);
|
this.footer.addChildElement(childElement);
|
||||||
}
|
}
|
||||||
|
47
src/file/footer/footer.spec.ts
Normal file
47
src/file/footer/footer.spec.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
|
import { Paragraph } from "../paragraph";
|
||||||
|
import { Footer } from "./footer";
|
||||||
|
|
||||||
|
describe("Footer", () => {
|
||||||
|
it("should create", () => {
|
||||||
|
const footer = new Footer(1);
|
||||||
|
|
||||||
|
const tree = new Formatter().format(footer);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:ftr": {
|
||||||
|
_attr: {
|
||||||
|
"xmlns:m": "http://schemas.openxmlformats.org/officeDocument/2006/math",
|
||||||
|
"xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
||||||
|
"xmlns:o": "urn:schemas-microsoft-com:office:office",
|
||||||
|
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
||||||
|
"xmlns:v": "urn:schemas-microsoft-com:vml",
|
||||||
|
"xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||||
|
"xmlns:w10": "urn:schemas-microsoft-com:office:word",
|
||||||
|
"xmlns:w14": "http://schemas.microsoft.com/office/word/2010/wordml",
|
||||||
|
"xmlns:w15": "http://schemas.microsoft.com/office/word/2012/wordml",
|
||||||
|
"xmlns:wne": "http://schemas.microsoft.com/office/word/2006/wordml",
|
||||||
|
"xmlns:wp": "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
|
||||||
|
"xmlns:wp14": "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
|
||||||
|
"xmlns:wpc": "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
|
||||||
|
"xmlns:wpg": "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
|
||||||
|
"xmlns:wpi": "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
|
||||||
|
"xmlns:wps": "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create with initContent", () => {
|
||||||
|
const header = new Footer(1, new Paragraph({}));
|
||||||
|
|
||||||
|
const tree = new Formatter().format(header);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:ftr": {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -4,7 +4,7 @@ import * as sinon from "sinon";
|
|||||||
import { HeaderWrapper } from "./header-wrapper";
|
import { HeaderWrapper } from "./header-wrapper";
|
||||||
import { Media } from "./media";
|
import { Media } from "./media";
|
||||||
import { Paragraph } from "./paragraph";
|
import { Paragraph } from "./paragraph";
|
||||||
import { Table } from "./table";
|
import { Table, TableCell, TableRow } from "./table";
|
||||||
|
|
||||||
describe("HeaderWrapper", () => {
|
describe("HeaderWrapper", () => {
|
||||||
describe("#add", () => {
|
describe("#add", () => {
|
||||||
@ -21,8 +21,15 @@ describe("HeaderWrapper", () => {
|
|||||||
const spy = sinon.spy(wrapper.Header, "add");
|
const spy = sinon.spy(wrapper.Header, "add");
|
||||||
wrapper.add(
|
wrapper.add(
|
||||||
new Table({
|
new Table({
|
||||||
rows: 1,
|
rows: [
|
||||||
columns: 1,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -30,17 +37,6 @@ describe("HeaderWrapper", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#addImage", () => {
|
|
||||||
it("should call the underlying header's addImage", () => {
|
|
||||||
const file = new HeaderWrapper(new Media(), 1);
|
|
||||||
const spy = sinon.spy(file.Header, "add");
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
file.addImage({} as any);
|
|
||||||
|
|
||||||
expect(spy.called).to.equal(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#addChildElement", () => {
|
describe("#addChildElement", () => {
|
||||||
it("should call the underlying header's addChildElement", () => {
|
it("should call the underlying header's addChildElement", () => {
|
||||||
const file = new HeaderWrapper(new Media(), 1);
|
const file = new HeaderWrapper(new Media(), 1);
|
||||||
|
@ -2,7 +2,7 @@ import { XmlComponent } from "file/xml-components";
|
|||||||
|
|
||||||
import { HeaderReferenceType } from "./document";
|
import { HeaderReferenceType } from "./document";
|
||||||
import { Header } from "./header/header";
|
import { Header } from "./header/header";
|
||||||
import { Image, Media } from "./media";
|
import { Media } from "./media";
|
||||||
import { Paragraph } from "./paragraph";
|
import { Paragraph } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
import { Table } from "./table";
|
import { Table } from "./table";
|
||||||
@ -27,11 +27,6 @@ export class HeaderWrapper {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addImage(image: Image): HeaderWrapper {
|
|
||||||
this.header.add(image.Paragraph);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addChildElement(childElement: XmlComponent | string): void {
|
public addChildElement(childElement: XmlComponent | string): void {
|
||||||
this.header.addChildElement(childElement);
|
this.header.addChildElement(childElement);
|
||||||
}
|
}
|
||||||
|
58
src/file/header/header.spec.ts
Normal file
58
src/file/header/header.spec.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
|
import { Paragraph } from "../paragraph";
|
||||||
|
import { Header } from "./header";
|
||||||
|
|
||||||
|
describe("Header", () => {
|
||||||
|
it("should create", () => {
|
||||||
|
const header = new Header(1);
|
||||||
|
|
||||||
|
const tree = new Formatter().format(header);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:hdr": {
|
||||||
|
_attr: {
|
||||||
|
"xmlns:cx": "http://schemas.microsoft.com/office/drawing/2014/chartex",
|
||||||
|
"xmlns:cx1": "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex",
|
||||||
|
"xmlns:cx2": "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex",
|
||||||
|
"xmlns:cx3": "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex",
|
||||||
|
"xmlns:cx4": "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex",
|
||||||
|
"xmlns:cx5": "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex",
|
||||||
|
"xmlns:cx6": "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex",
|
||||||
|
"xmlns:cx7": "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex",
|
||||||
|
"xmlns:cx8": "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex",
|
||||||
|
"xmlns:m": "http://schemas.openxmlformats.org/officeDocument/2006/math",
|
||||||
|
"xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
||||||
|
"xmlns:o": "urn:schemas-microsoft-com:office:office",
|
||||||
|
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
||||||
|
"xmlns:v": "urn:schemas-microsoft-com:vml",
|
||||||
|
"xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||||
|
"xmlns:w10": "urn:schemas-microsoft-com:office:word",
|
||||||
|
"xmlns:w14": "http://schemas.microsoft.com/office/word/2010/wordml",
|
||||||
|
"xmlns:w15": "http://schemas.microsoft.com/office/word/2012/wordml",
|
||||||
|
"xmlns:w16cid": "http://schemas.microsoft.com/office/word/2016/wordml/cid",
|
||||||
|
"xmlns:w16se": "http://schemas.microsoft.com/office/word/2015/wordml/symex",
|
||||||
|
"xmlns:wne": "http://schemas.microsoft.com/office/word/2006/wordml",
|
||||||
|
"xmlns:wp": "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
|
||||||
|
"xmlns:wp14": "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
|
||||||
|
"xmlns:wpc": "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
|
||||||
|
"xmlns:wpg": "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
|
||||||
|
"xmlns:wpi": "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
|
||||||
|
"xmlns:wps": "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create with initContent", () => {
|
||||||
|
const header = new Header(1, new Paragraph({}));
|
||||||
|
|
||||||
|
const tree = new Formatter().format(header);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:hdr": {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -1,13 +0,0 @@
|
|||||||
import { ImageParagraph, PictureRun } from "../paragraph";
|
|
||||||
|
|
||||||
export class Image {
|
|
||||||
constructor(private readonly paragraph: ImageParagraph) {}
|
|
||||||
|
|
||||||
public get Paragraph(): ImageParagraph {
|
|
||||||
return this.paragraph;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get Run(): PictureRun {
|
|
||||||
return this.paragraph.Run;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,2 @@
|
|||||||
export * from "./media";
|
export * from "./media";
|
||||||
export * from "./data";
|
export * from "./data";
|
||||||
export * from "./image";
|
|
||||||
|
@ -80,6 +80,16 @@ describe("Media", () => {
|
|||||||
const image = new Media().addMedia("");
|
const image = new Media().addMedia("");
|
||||||
expect(image.stream).to.be.an.instanceof(Uint8Array);
|
expect(image.stream).to.be.an.instanceof(Uint8Array);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should use data as is if its not a string", () => {
|
||||||
|
// tslint:disable-next-line
|
||||||
|
((process as any).atob as any) = () => "atob result";
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
(Media as any).generateId = () => "test";
|
||||||
|
|
||||||
|
const image = new Media().addMedia(new Buffer(""));
|
||||||
|
expect(image.stream).to.be.an.instanceof(Uint8Array);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#getMedia", () => {
|
describe("#getMedia", () => {
|
||||||
|
@ -1,11 +1,87 @@
|
|||||||
import { assert, expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { ThematicBreak } from "./border";
|
import { Border, ThematicBreak } from "./border";
|
||||||
|
|
||||||
describe("Border", () => {
|
describe("Border", () => {
|
||||||
// TODO: Need tests here
|
describe("#constructor", () => {
|
||||||
|
it("should create", () => {
|
||||||
|
const border = new Border({
|
||||||
|
top: {
|
||||||
|
color: "red",
|
||||||
|
space: 1,
|
||||||
|
value: "test",
|
||||||
|
size: 2,
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
color: "red",
|
||||||
|
space: 3,
|
||||||
|
value: "test",
|
||||||
|
size: 4,
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
color: "red",
|
||||||
|
space: 5,
|
||||||
|
value: "test",
|
||||||
|
size: 6,
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
color: "red",
|
||||||
|
space: 7,
|
||||||
|
value: "test",
|
||||||
|
size: 8,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(border);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:pBdr": [
|
||||||
|
{
|
||||||
|
"w:top": {
|
||||||
|
_attr: {
|
||||||
|
"w:color": "red",
|
||||||
|
"w:space": 1,
|
||||||
|
"w:sz": 2,
|
||||||
|
"w:val": "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:bottom": {
|
||||||
|
_attr: {
|
||||||
|
"w:color": "red",
|
||||||
|
"w:space": 3,
|
||||||
|
"w:sz": 4,
|
||||||
|
"w:val": "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:left": {
|
||||||
|
_attr: {
|
||||||
|
"w:color": "red",
|
||||||
|
"w:space": 5,
|
||||||
|
"w:sz": 6,
|
||||||
|
"w:val": "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:right": {
|
||||||
|
_attr: {
|
||||||
|
"w:color": "red",
|
||||||
|
"w:space": 7,
|
||||||
|
"w:sz": 8,
|
||||||
|
"w:val": "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("ThematicBreak", () => {
|
describe("ThematicBreak", () => {
|
||||||
@ -16,17 +92,6 @@ describe("ThematicBreak", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create valid JSON", () => {
|
|
||||||
const stringifiedJson = JSON.stringify(thematicBreak);
|
|
||||||
|
|
||||||
try {
|
|
||||||
JSON.parse(stringifiedJson);
|
|
||||||
} catch (e) {
|
|
||||||
assert.isTrue(false);
|
|
||||||
}
|
|
||||||
assert.isTrue(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should create a Thematic Break with correct border properties", () => {
|
it("should create a Thematic Break with correct border properties", () => {
|
||||||
const tree = new Formatter().format(thematicBreak);
|
const tree = new Formatter().format(thematicBreak);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
// tslint:disable:object-literal-key-quotes
|
|
||||||
import { assert } from "chai";
|
|
||||||
|
|
||||||
import { ImageParagraph } from "./image";
|
|
||||||
|
|
||||||
describe("Image", () => {
|
|
||||||
let image: ImageParagraph;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
image = new ImageParagraph({
|
|
||||||
stream: new Buffer(""),
|
|
||||||
path: "",
|
|
||||||
fileName: "test.png",
|
|
||||||
dimensions: {
|
|
||||||
pixels: {
|
|
||||||
x: 10,
|
|
||||||
y: 10,
|
|
||||||
},
|
|
||||||
emus: {
|
|
||||||
x: 10,
|
|
||||||
y: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#constructor()", () => {
|
|
||||||
it("should create valid JSON", () => {
|
|
||||||
const stringifiedJson = JSON.stringify(image);
|
|
||||||
|
|
||||||
try {
|
|
||||||
JSON.parse(stringifiedJson);
|
|
||||||
} catch (e) {
|
|
||||||
assert.isTrue(false);
|
|
||||||
}
|
|
||||||
assert.isTrue(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,18 +0,0 @@
|
|||||||
import { IDrawingOptions } from "../drawing";
|
|
||||||
import { IMediaData } from "../media";
|
|
||||||
import { Paragraph } from "./paragraph";
|
|
||||||
import { PictureRun } from "./run";
|
|
||||||
|
|
||||||
export class ImageParagraph extends Paragraph {
|
|
||||||
private readonly pictureRun: PictureRun;
|
|
||||||
|
|
||||||
constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) {
|
|
||||||
super({});
|
|
||||||
this.pictureRun = new PictureRun(imageData, drawingOptions);
|
|
||||||
this.root.push(this.pictureRun);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get Run(): PictureRun {
|
|
||||||
return this.pictureRun;
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,4 +3,3 @@ export * from "./paragraph";
|
|||||||
export * from "./properties";
|
export * from "./properties";
|
||||||
export * from "./run";
|
export * from "./run";
|
||||||
export * from "./links";
|
export * from "./links";
|
||||||
export * from "./image";
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
// http://officeopenxml.com/WPparagraph.php
|
// http://officeopenxml.com/WPparagraph.php
|
||||||
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
||||||
import { Image } from "file/media";
|
|
||||||
import { Num } from "file/numbering/num";
|
import { Num } from "file/numbering/num";
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
@ -190,13 +189,6 @@ export class Paragraph extends XmlComponent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addImage(image: Image): PictureRun {
|
|
||||||
const run = image.Run;
|
|
||||||
this.addRun(run);
|
|
||||||
|
|
||||||
return run;
|
|
||||||
}
|
|
||||||
|
|
||||||
public pageBreak(): Paragraph {
|
public pageBreak(): Paragraph {
|
||||||
this.root.push(new PageBreak());
|
this.root.push(new PageBreak());
|
||||||
return this;
|
return this;
|
||||||
|
@ -2,7 +2,7 @@ import { expect } from "chai";
|
|||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { NumberOfPages, Page } from "./page-number";
|
import { NumberOfPages, NumberOfPagesSection, Page } from "./page-number";
|
||||||
|
|
||||||
describe("Page", () => {
|
describe("Page", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
@ -21,3 +21,12 @@ describe("NumberOfPages", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("NumberOfPagesSection", () => {
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("uses the font name for both ascii and hAnsi", () => {
|
||||||
|
const tree = new Formatter().format(new NumberOfPagesSection());
|
||||||
|
expect(tree).to.deep.equal({ "w:instrText": [{ _attr: { "xml:space": "preserve" } }, "SECTIONPAGES"] });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -20,3 +20,11 @@ export class NumberOfPages extends XmlComponent {
|
|||||||
this.root.push("NUMPAGES");
|
this.root.push("NUMPAGES");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class NumberOfPagesSection extends XmlComponent {
|
||||||
|
constructor() {
|
||||||
|
super("w:instrText");
|
||||||
|
this.root.push(new TextAttributes({ space: SpaceType.PRESERVE }));
|
||||||
|
this.root.push("SECTIONPAGES");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -284,6 +284,22 @@ describe("Run", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#numberOfTotalPagesSection", () => {
|
||||||
|
it("should set the run to the RTL mode", () => {
|
||||||
|
const run = new Run({});
|
||||||
|
run.numberOfTotalPagesSection();
|
||||||
|
const tree = new Formatter().format(run);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:r": [
|
||||||
|
{ "w:fldChar": { _attr: { "w:fldCharType": "begin" } } },
|
||||||
|
{ "w:instrText": [{ _attr: { "xml:space": "preserve" } }, "SECTIONPAGES"] },
|
||||||
|
{ "w:fldChar": { _attr: { "w:fldCharType": "separate" } } },
|
||||||
|
{ "w:fldChar": { _attr: { "w:fldCharType": "end" } } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("#pageNumber", () => {
|
describe("#pageNumber", () => {
|
||||||
it("should set the run to the RTL mode", () => {
|
it("should set the run to the RTL mode", () => {
|
||||||
const run = new Run({});
|
const run = new Run({});
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
SizeComplexScript,
|
SizeComplexScript,
|
||||||
Strike,
|
Strike,
|
||||||
} from "./formatting";
|
} from "./formatting";
|
||||||
import { NumberOfPages, Page } from "./page-number";
|
import { NumberOfPages, NumberOfPagesSection, Page } from "./page-number";
|
||||||
import { RunProperties } from "./properties";
|
import { RunProperties } from "./properties";
|
||||||
import { RunFonts } from "./run-fonts";
|
import { RunFonts } from "./run-fonts";
|
||||||
import { SubScript, SuperScript } from "./script";
|
import { SubScript, SuperScript } from "./script";
|
||||||
@ -161,4 +161,12 @@ export class Run extends XmlComponent {
|
|||||||
this.root.push(new End());
|
this.root.push(new End());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public numberOfTotalPagesSection(): Run {
|
||||||
|
this.root.push(new Begin());
|
||||||
|
this.root.push(new NumberOfPagesSection());
|
||||||
|
this.root.push(new Separate());
|
||||||
|
this.root.push(new End());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
export class TableGrid extends XmlComponent {
|
export class TableGrid extends XmlComponent {
|
||||||
constructor(cols: number[]) {
|
constructor(widths: number[]) {
|
||||||
super("w:tblGrid");
|
super("w:tblGrid");
|
||||||
cols.forEach((col) => this.root.push(new GridCol(col)));
|
for (const width of widths) {
|
||||||
|
this.root.push(new GridCol(width));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ export class GridSpan extends XmlComponent {
|
|||||||
/**
|
/**
|
||||||
* Vertical merge types.
|
* Vertical merge types.
|
||||||
*/
|
*/
|
||||||
export enum VMergeType {
|
export enum VerticalMergeType {
|
||||||
/**
|
/**
|
||||||
* Cell that is merged with upper one.
|
* Cell that is merged with upper one.
|
||||||
*/
|
*/
|
||||||
@ -114,19 +114,19 @@ export enum VMergeType {
|
|||||||
RESTART = "restart",
|
RESTART = "restart",
|
||||||
}
|
}
|
||||||
|
|
||||||
class VMergeAttributes extends XmlAttributeComponent<{ readonly val: VMergeType }> {
|
class VerticalMergeAttributes extends XmlAttributeComponent<{ readonly val: VerticalMergeType }> {
|
||||||
protected readonly xmlKeys = { val: "w:val" };
|
protected readonly xmlKeys = { val: "w:val" };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vertical merge element. Should be used in a table cell.
|
* Vertical merge element. Should be used in a table cell.
|
||||||
*/
|
*/
|
||||||
export class VMerge extends XmlComponent {
|
export class VerticalMerge extends XmlComponent {
|
||||||
constructor(value: VMergeType) {
|
constructor(value: VerticalMergeType) {
|
||||||
super("w:vMerge");
|
super("w:vMerge");
|
||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new VMergeAttributes({
|
new VerticalMergeAttributes({
|
||||||
val: value,
|
val: value,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -3,7 +3,7 @@ import { expect } from "chai";
|
|||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
import { BorderStyle } from "file/styles";
|
import { BorderStyle } from "file/styles";
|
||||||
|
|
||||||
import { VerticalAlign, VMergeType, WidthType } from "./table-cell-components";
|
import { VerticalAlign, VerticalMergeType, WidthType } from "./table-cell-components";
|
||||||
import { TableCellProperties } from "./table-cell-properties";
|
import { TableCellProperties } from "./table-cell-properties";
|
||||||
|
|
||||||
describe("TableCellProperties", () => {
|
describe("TableCellProperties", () => {
|
||||||
@ -30,7 +30,7 @@ describe("TableCellProperties", () => {
|
|||||||
describe("#addVerticalMerge", () => {
|
describe("#addVerticalMerge", () => {
|
||||||
it("adds vertical merge", () => {
|
it("adds vertical merge", () => {
|
||||||
const properties = new TableCellProperties();
|
const properties = new TableCellProperties();
|
||||||
properties.addVerticalMerge(VMergeType.CONTINUE);
|
properties.addVerticalMerge(VerticalMergeType.CONTINUE);
|
||||||
const tree = new Formatter().format(properties);
|
const tree = new Formatter().format(properties);
|
||||||
expect(tree).to.deep.equal({ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] });
|
expect(tree).to.deep.equal({ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] });
|
||||||
});
|
});
|
||||||
@ -73,6 +73,54 @@ describe("TableCellProperties", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#addMargins", () => {
|
||||||
|
it("sets shading", () => {
|
||||||
|
const properties = new TableCellProperties();
|
||||||
|
properties.addMargins({});
|
||||||
|
const tree = new Formatter().format(properties);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tcPr": [
|
||||||
|
{
|
||||||
|
"w:tcMar": [
|
||||||
|
{
|
||||||
|
"w:top": {
|
||||||
|
_attr: {
|
||||||
|
"w:type": "dxa",
|
||||||
|
"w:w": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:bottom": {
|
||||||
|
_attr: {
|
||||||
|
"w:type": "dxa",
|
||||||
|
"w:w": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:end": {
|
||||||
|
_attr: {
|
||||||
|
"w:type": "dxa",
|
||||||
|
"w:w": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:start": {
|
||||||
|
_attr: {
|
||||||
|
"w:type": "dxa",
|
||||||
|
"w:w": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("#Borders", () => {
|
describe("#Borders", () => {
|
||||||
it("should return the TableCellBorders if Border has borders", () => {
|
it("should return the TableCellBorders if Border has borders", () => {
|
||||||
const properties = new TableCellProperties();
|
const properties = new TableCellProperties();
|
||||||
|
@ -2,7 +2,16 @@ import { IgnoreIfEmptyXmlComponent } from "file/xml-components";
|
|||||||
|
|
||||||
import { ITableShadingAttributesProperties, TableShading } from "../shading";
|
import { ITableShadingAttributesProperties, TableShading } from "../shading";
|
||||||
import { ITableCellMarginOptions, TableCellMargin } from "./cell-margin/table-cell-margins";
|
import { ITableCellMarginOptions, TableCellMargin } from "./cell-margin/table-cell-margins";
|
||||||
import { GridSpan, TableCellBorders, TableCellWidth, VAlign, VerticalAlign, VMerge, VMergeType, WidthType } from "./table-cell-components";
|
import {
|
||||||
|
GridSpan,
|
||||||
|
TableCellBorders,
|
||||||
|
TableCellWidth,
|
||||||
|
VAlign,
|
||||||
|
VerticalAlign,
|
||||||
|
VerticalMerge,
|
||||||
|
VerticalMergeType,
|
||||||
|
WidthType,
|
||||||
|
} from "./table-cell-components";
|
||||||
|
|
||||||
export class TableCellProperties extends IgnoreIfEmptyXmlComponent {
|
export class TableCellProperties extends IgnoreIfEmptyXmlComponent {
|
||||||
private readonly cellBorder: TableCellBorders;
|
private readonly cellBorder: TableCellBorders;
|
||||||
@ -23,8 +32,8 @@ export class TableCellProperties extends IgnoreIfEmptyXmlComponent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addVerticalMerge(type: VMergeType): TableCellProperties {
|
public addVerticalMerge(type: VerticalMergeType): TableCellProperties {
|
||||||
this.root.push(new VMerge(type));
|
this.root.push(new VerticalMerge(type));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@ import { expect } from "chai";
|
|||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
import { BorderStyle } from "file/styles";
|
import { BorderStyle } from "file/styles";
|
||||||
|
|
||||||
import { TableCellBorders, TableCellWidth, WidthType } from "./table-cell-components";
|
import { ShadingType } from "../shading";
|
||||||
|
import { TableCell } from "./table-cell";
|
||||||
|
import { TableCellBorders, TableCellWidth, VerticalAlign, VerticalMergeType, WidthType } from "./table-cell-components";
|
||||||
|
|
||||||
describe("TableCellBorders", () => {
|
describe("TableCellBorders", () => {
|
||||||
describe("#prepForXml", () => {
|
describe("#prepForXml", () => {
|
||||||
@ -222,3 +224,332 @@ describe("TableCellWidth", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("TableCell", () => {
|
||||||
|
describe("#constructor", () => {
|
||||||
|
it("should create", () => {
|
||||||
|
const cell = new TableCell({
|
||||||
|
children: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(cell);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:p": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create with vertical align", () => {
|
||||||
|
const cell = new TableCell({
|
||||||
|
children: [],
|
||||||
|
verticalAlign: VerticalAlign.CENTER,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(cell);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:tcPr": [
|
||||||
|
{
|
||||||
|
"w:vAlign": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": "center",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:p": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create with vertical merge", () => {
|
||||||
|
const cell = new TableCell({
|
||||||
|
children: [],
|
||||||
|
verticalMerge: VerticalMergeType.RESTART,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(cell);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:tcPr": [
|
||||||
|
{
|
||||||
|
"w:vMerge": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": "restart",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:p": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create with margins", () => {
|
||||||
|
const cell = new TableCell({
|
||||||
|
children: [],
|
||||||
|
margins: {
|
||||||
|
top: 1,
|
||||||
|
left: 1,
|
||||||
|
bottom: 1,
|
||||||
|
right: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(cell);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:tcPr": [
|
||||||
|
{
|
||||||
|
"w:tcMar": [
|
||||||
|
{
|
||||||
|
"w:top": {
|
||||||
|
_attr: {
|
||||||
|
"w:type": "dxa",
|
||||||
|
"w:w": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:bottom": {
|
||||||
|
_attr: {
|
||||||
|
"w:type": "dxa",
|
||||||
|
"w:w": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:end": {
|
||||||
|
_attr: {
|
||||||
|
"w:type": "dxa",
|
||||||
|
"w:w": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:start": {
|
||||||
|
_attr: {
|
||||||
|
"w:type": "dxa",
|
||||||
|
"w:w": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:p": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create with shading", () => {
|
||||||
|
const cell = new TableCell({
|
||||||
|
children: [],
|
||||||
|
shading: {
|
||||||
|
fill: "red",
|
||||||
|
color: "blue",
|
||||||
|
val: ShadingType.PERCENT_10,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(cell);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:tcPr": [
|
||||||
|
{
|
||||||
|
"w:shd": {
|
||||||
|
_attr: {
|
||||||
|
"w:color": "blue",
|
||||||
|
"w:fill": "red",
|
||||||
|
"w:val": "pct10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:p": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create with column span", () => {
|
||||||
|
const cell = new TableCell({
|
||||||
|
children: [],
|
||||||
|
columnSpan: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(cell);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:tcPr": [
|
||||||
|
{
|
||||||
|
"w:gridSpan": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:p": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("rowSpan", () => {
|
||||||
|
it("should not create with row span if its less than 1", () => {
|
||||||
|
const cell = new TableCell({
|
||||||
|
children: [],
|
||||||
|
rowSpan: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(cell);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:p": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create with row span if its greater than 1", () => {
|
||||||
|
const cell = new TableCell({
|
||||||
|
children: [],
|
||||||
|
rowSpan: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(cell);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:tcPr": [
|
||||||
|
{
|
||||||
|
"w:vMerge": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": "restart",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:p": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create with borders", () => {
|
||||||
|
const cell = new TableCell({
|
||||||
|
children: [],
|
||||||
|
borders: {
|
||||||
|
top: {
|
||||||
|
style: BorderStyle.DASH_DOT_STROKED,
|
||||||
|
size: 3,
|
||||||
|
color: "red",
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
style: BorderStyle.DOUBLE,
|
||||||
|
size: 3,
|
||||||
|
color: "blue",
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
style: BorderStyle.DASH_DOT_STROKED,
|
||||||
|
size: 3,
|
||||||
|
color: "green",
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
style: BorderStyle.DASH_DOT_STROKED,
|
||||||
|
size: 3,
|
||||||
|
color: "#ff8000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(cell);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:tcPr": [
|
||||||
|
{
|
||||||
|
"w:tcBorders": [
|
||||||
|
{
|
||||||
|
"w:top": {
|
||||||
|
_attr: {
|
||||||
|
"w:color": "red",
|
||||||
|
"w:sz": 3,
|
||||||
|
"w:val": "dashDotStroked",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:bottom": {
|
||||||
|
_attr: {
|
||||||
|
"w:color": "blue",
|
||||||
|
"w:sz": 3,
|
||||||
|
"w:val": "double",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:left": {
|
||||||
|
_attr: {
|
||||||
|
"w:color": "green",
|
||||||
|
"w:sz": 3,
|
||||||
|
"w:val": "dashDotStroked",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:right": {
|
||||||
|
_attr: {
|
||||||
|
"w:color": "#ff8000",
|
||||||
|
"w:sz": 3,
|
||||||
|
"w:val": "dashDotStroked",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:p": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -1,77 +1,112 @@
|
|||||||
// http://officeopenxml.com/WPtableGrid.php
|
// http://officeopenxml.com/WPtableGrid.php
|
||||||
import { Paragraph } from "file/paragraph";
|
import { Paragraph } from "file/paragraph";
|
||||||
|
import { BorderStyle } from "file/styles";
|
||||||
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
import { ITableShadingAttributesProperties } from "../shading";
|
import { ITableShadingAttributesProperties } from "../shading";
|
||||||
import { Table } from "../table";
|
import { Table } from "../table";
|
||||||
import { ITableCellMarginOptions } from "./cell-margin/table-cell-margins";
|
import { ITableCellMarginOptions } from "./cell-margin/table-cell-margins";
|
||||||
import { TableCellBorders, VerticalAlign, VMergeType } from "./table-cell-components";
|
import { VerticalAlign, VerticalMergeType } from "./table-cell-components";
|
||||||
import { TableCellProperties } from "./table-cell-properties";
|
import { TableCellProperties } from "./table-cell-properties";
|
||||||
|
|
||||||
export interface ITableCellOptions {
|
export interface ITableCellOptions {
|
||||||
readonly shading?: ITableShadingAttributesProperties;
|
readonly shading?: ITableShadingAttributesProperties;
|
||||||
|
readonly margins?: ITableCellMarginOptions;
|
||||||
|
readonly verticalAlign?: VerticalAlign;
|
||||||
|
readonly verticalMerge?: VerticalMergeType;
|
||||||
|
readonly columnSpan?: number;
|
||||||
|
readonly rowSpan?: number;
|
||||||
|
readonly borders?: {
|
||||||
|
readonly top?: {
|
||||||
|
readonly style: BorderStyle;
|
||||||
|
readonly size: number;
|
||||||
|
readonly color: string;
|
||||||
|
};
|
||||||
|
readonly bottom?: {
|
||||||
|
readonly style: BorderStyle;
|
||||||
|
readonly size: number;
|
||||||
|
readonly color: string;
|
||||||
|
};
|
||||||
|
readonly left?: {
|
||||||
|
readonly style: BorderStyle;
|
||||||
|
readonly size: number;
|
||||||
|
readonly color: string;
|
||||||
|
};
|
||||||
|
readonly right?: {
|
||||||
|
readonly style: BorderStyle;
|
||||||
|
readonly size: number;
|
||||||
|
readonly color: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
readonly children: Array<Paragraph | Table>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TableCell extends XmlComponent {
|
export class TableCell extends XmlComponent {
|
||||||
private readonly properties: TableCellProperties;
|
private readonly properties: TableCellProperties;
|
||||||
|
|
||||||
constructor() {
|
constructor(readonly options: ITableCellOptions) {
|
||||||
super("w:tc");
|
super("w:tc");
|
||||||
|
|
||||||
this.properties = new TableCellProperties();
|
this.properties = new TableCellProperties();
|
||||||
this.root.push(this.properties);
|
this.root.push(this.properties);
|
||||||
|
|
||||||
|
for (const child of options.children) {
|
||||||
|
this.root.push(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
public add(item: Paragraph | Table): TableCell {
|
if (options.verticalAlign) {
|
||||||
this.root.push(item);
|
this.properties.setVerticalAlign(options.verticalAlign);
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
if (options.verticalMerge) {
|
||||||
|
this.properties.addVerticalMerge(options.verticalMerge);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.margins) {
|
||||||
|
this.properties.addMargins(options.margins);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.shading) {
|
||||||
|
this.properties.setShading(options.shading);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.columnSpan) {
|
||||||
|
this.properties.addGridSpan(options.columnSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.rowSpan && options.rowSpan > 1) {
|
||||||
|
this.properties.addVerticalMerge(VerticalMergeType.RESTART);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.borders) {
|
||||||
|
if (options.borders.top) {
|
||||||
|
this.properties.Borders.addTopBorder(options.borders.top.style, options.borders.top.size, options.borders.top.color);
|
||||||
|
}
|
||||||
|
if (options.borders.bottom) {
|
||||||
|
this.properties.Borders.addBottomBorder(
|
||||||
|
options.borders.bottom.style,
|
||||||
|
options.borders.bottom.size,
|
||||||
|
options.borders.bottom.color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (options.borders.left) {
|
||||||
|
this.properties.Borders.addLeftBorder(options.borders.left.style, options.borders.left.size, options.borders.left.color);
|
||||||
|
}
|
||||||
|
if (options.borders.right) {
|
||||||
|
this.properties.Borders.addRightBorder(
|
||||||
|
options.borders.right.style,
|
||||||
|
options.borders.right.size,
|
||||||
|
options.borders.right.color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public prepForXml(): IXmlableObject | undefined {
|
public prepForXml(): IXmlableObject | undefined {
|
||||||
// Cells must end with a paragraph
|
// Cells must end with a paragraph
|
||||||
if (!(this.root[this.root.length - 1] instanceof Paragraph)) {
|
if (!(this.root[this.root.length - 1] instanceof Paragraph)) {
|
||||||
const para = new Paragraph({});
|
this.root.push(new Paragraph({}));
|
||||||
this.add(para);
|
|
||||||
}
|
}
|
||||||
return super.prepForXml();
|
return super.prepForXml();
|
||||||
}
|
}
|
||||||
|
|
||||||
public setVerticalAlign(type: VerticalAlign): TableCell {
|
|
||||||
this.properties.setVerticalAlign(type);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addGridSpan(cellSpan: number): TableCell {
|
|
||||||
this.properties.addGridSpan(cellSpan);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addVerticalMerge(type: VMergeType): TableCell {
|
|
||||||
this.properties.addVerticalMerge(type);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setMargins(margins: ITableCellMarginOptions): TableCell {
|
|
||||||
this.properties.addMargins(margins);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setShading(attrs: ITableShadingAttributesProperties): TableCell {
|
|
||||||
this.properties.setShading(attrs);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get Borders(): TableCellBorders {
|
|
||||||
return this.properties.Borders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get Properties(): TableCellProperties {
|
|
||||||
return this.properties;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
import { expect } from "chai";
|
|
||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
|
||||||
|
|
||||||
import { TableCell } from "./table-cell";
|
|
||||||
import { TableColumn } from "./table-column";
|
|
||||||
|
|
||||||
import { EMPTY_OBJECT } from "file/xml-components";
|
|
||||||
|
|
||||||
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": EMPTY_OBJECT }],
|
|
||||||
});
|
|
||||||
|
|
||||||
const tree2 = new Formatter().format(cells[1]);
|
|
||||||
expect(tree2).to.deep.equal({
|
|
||||||
"w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": EMPTY_OBJECT }],
|
|
||||||
});
|
|
||||||
|
|
||||||
const tree3 = new Formatter().format(cells[2]);
|
|
||||||
expect(tree3).to.deep.equal({
|
|
||||||
"w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": EMPTY_OBJECT }],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,25 +0,0 @@
|
|||||||
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);
|
|
||||||
|
|
||||||
for (let i = startIndex + 1; i <= endIndex; i++) {
|
|
||||||
this.cells[i].addVerticalMerge(VMergeType.CONTINUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.cells[startIndex];
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,38 +14,66 @@ describe("TableCellMargin", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("#addTopMargin", () => {
|
describe("#addTopMargin", () => {
|
||||||
it("adds a table cell top margin", () => {
|
it("should add a table cell top margin", () => {
|
||||||
const cellMargin = new TableCellMargin();
|
const cellMargin = new TableCellMargin();
|
||||||
cellMargin.addTopMargin(1234, WidthType.DXA);
|
cellMargin.addTopMargin(1234, WidthType.DXA);
|
||||||
const tree = new Formatter().format(cellMargin);
|
const tree = new Formatter().format(cellMargin);
|
||||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:top": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:top": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should add a table cell top margin using default width type", () => {
|
||||||
|
const cellMargin = new TableCellMargin();
|
||||||
|
cellMargin.addTopMargin(1234);
|
||||||
|
const tree = new Formatter().format(cellMargin);
|
||||||
|
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:top": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#addLeftMargin", () => {
|
describe("#addLeftMargin", () => {
|
||||||
it("adds a table cell left margin", () => {
|
it("should add a table cell left margin", () => {
|
||||||
const cellMargin = new TableCellMargin();
|
const cellMargin = new TableCellMargin();
|
||||||
cellMargin.addLeftMargin(1234, WidthType.DXA);
|
cellMargin.addLeftMargin(1234, WidthType.DXA);
|
||||||
const tree = new Formatter().format(cellMargin);
|
const tree = new Formatter().format(cellMargin);
|
||||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:left": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:left": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should add a table cell left margin using default width type", () => {
|
||||||
|
const cellMargin = new TableCellMargin();
|
||||||
|
cellMargin.addLeftMargin(1234);
|
||||||
|
const tree = new Formatter().format(cellMargin);
|
||||||
|
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:left": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#addBottomMargin", () => {
|
describe("#addBottomMargin", () => {
|
||||||
it("adds a table cell bottom margin", () => {
|
it("should add a table cell bottom margin", () => {
|
||||||
const cellMargin = new TableCellMargin();
|
const cellMargin = new TableCellMargin();
|
||||||
cellMargin.addBottomMargin(1234, WidthType.DXA);
|
cellMargin.addBottomMargin(1234, WidthType.DXA);
|
||||||
const tree = new Formatter().format(cellMargin);
|
const tree = new Formatter().format(cellMargin);
|
||||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:bottom": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:bottom": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should add a table cell bottom margin using default width type", () => {
|
||||||
|
const cellMargin = new TableCellMargin();
|
||||||
|
cellMargin.addBottomMargin(1234);
|
||||||
|
const tree = new Formatter().format(cellMargin);
|
||||||
|
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:bottom": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#addRightMargin", () => {
|
describe("#addRightMargin", () => {
|
||||||
it("adds a table cell right margin", () => {
|
it("should add a table cell right margin", () => {
|
||||||
const cellMargin = new TableCellMargin();
|
const cellMargin = new TableCellMargin();
|
||||||
cellMargin.addRightMargin(1234, WidthType.DXA);
|
cellMargin.addRightMargin(1234, WidthType.DXA);
|
||||||
const tree = new Formatter().format(cellMargin);
|
const tree = new Formatter().format(cellMargin);
|
||||||
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:right": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:right": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should add a table cell right margin using default width type", () => {
|
||||||
|
const cellMargin = new TableCellMargin();
|
||||||
|
cellMargin.addRightMargin(1234);
|
||||||
|
const tree = new Formatter().format(cellMargin);
|
||||||
|
expect(tree).to.deep.equal({ "w:tblCellMar": [{ "w:right": { _attr: { "w:type": "dxa", "w:w": 1234 } } }] });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,7 @@ import { expect } from "chai";
|
|||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
|
import { ShadingType } from "../shading";
|
||||||
import { WidthType } from "../table-cell";
|
import { WidthType } from "../table-cell";
|
||||||
import { TableLayoutType } from "./table-layout";
|
import { TableLayoutType } from "./table-layout";
|
||||||
import { TableProperties } from "./table-properties";
|
import { TableProperties } from "./table-properties";
|
||||||
@ -66,4 +67,29 @@ describe("TableProperties", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#setShading", () => {
|
||||||
|
it("sets the shading of the table", () => {
|
||||||
|
const tp = new TableProperties();
|
||||||
|
tp.setShading({
|
||||||
|
fill: "b79c2f",
|
||||||
|
val: ShadingType.REVERSE_DIAGONAL_STRIPE,
|
||||||
|
color: "auto",
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(tp);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tblPr": [
|
||||||
|
{
|
||||||
|
"w:shd": {
|
||||||
|
_attr: {
|
||||||
|
"w:color": "auto",
|
||||||
|
"w:fill": "b79c2f",
|
||||||
|
"w:val": "reverseDiagStripe",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,6 +2,7 @@ import { expect } from "chai";
|
|||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
|
import { Paragraph } from "file/paragraph";
|
||||||
import { HeightRule } from "file/table/table-row/table-row-height";
|
import { HeightRule } from "file/table/table-row/table-row-height";
|
||||||
import { EMPTY_OBJECT } from "file/xml-components";
|
import { EMPTY_OBJECT } from "file/xml-components";
|
||||||
import { TableCell } from "../table-cell";
|
import { TableCell } from "../table-cell";
|
||||||
@ -10,7 +11,9 @@ import { TableRow } from "./table-row";
|
|||||||
describe("TableRow", () => {
|
describe("TableRow", () => {
|
||||||
describe("#constructor", () => {
|
describe("#constructor", () => {
|
||||||
it("should create with no cells", () => {
|
it("should create with no cells", () => {
|
||||||
const tableRow = new TableRow([]);
|
const tableRow = new TableRow({
|
||||||
|
children: [],
|
||||||
|
});
|
||||||
const tree = new Formatter().format(tableRow);
|
const tree = new Formatter().format(tableRow);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:tr": EMPTY_OBJECT,
|
"w:tr": EMPTY_OBJECT,
|
||||||
@ -18,7 +21,13 @@ describe("TableRow", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should create with one cell", () => {
|
it("should create with one cell", () => {
|
||||||
const tableRow = new TableRow([new TableCell()]);
|
const tableRow = new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
const tree = new Formatter().format(tableRow);
|
const tree = new Formatter().format(tableRow);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:tr": [
|
"w:tr": [
|
||||||
@ -32,46 +41,61 @@ describe("TableRow", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should create with cant split", () => {
|
||||||
|
const tableRow = new TableRow({
|
||||||
|
children: [],
|
||||||
|
cantSplit: true,
|
||||||
});
|
});
|
||||||
|
const tree = new Formatter().format(tableRow);
|
||||||
describe("#getCell", () => {
|
expect(tree).to.deep.equal({
|
||||||
it("should get the cell", () => {
|
"w:tr": [
|
||||||
const cell = new TableCell();
|
{
|
||||||
const tableRow = new TableRow([cell]);
|
"w:trPr": [
|
||||||
|
{
|
||||||
expect(tableRow.getCell(0)).to.equal(cell);
|
"w:cantSplit": {
|
||||||
});
|
_attr: {
|
||||||
|
"w:val": true,
|
||||||
it("should throw an error if index is out of bounds", () => {
|
},
|
||||||
const cell = new TableCell();
|
},
|
||||||
const tableRow = new TableRow([cell]);
|
},
|
||||||
|
],
|
||||||
expect(() => tableRow.getCell(1)).to.throw();
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#addGridSpan", () => {
|
it("should create with table header", () => {
|
||||||
it("should merge the cell", () => {
|
const tableRow = new TableRow({
|
||||||
const tableRow = new TableRow([new TableCell(), new TableCell()]);
|
children: [],
|
||||||
|
tableHeader: true,
|
||||||
tableRow.addGridSpan(0, 2);
|
});
|
||||||
expect(() => tableRow.getCell(1)).to.throw();
|
const tree = new Formatter().format(tableRow);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tr": [
|
||||||
|
{
|
||||||
|
"w:trPr": [
|
||||||
|
{
|
||||||
|
"w:tblHeader": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#mergeCells", () => {
|
|
||||||
it("should merge the cell", () => {
|
|
||||||
const tableRow = new TableRow([new TableCell(), new TableCell()]);
|
|
||||||
|
|
||||||
tableRow.mergeCells(0, 1);
|
|
||||||
expect(() => tableRow.getCell(1)).to.throw();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#setHeight", () => {
|
|
||||||
it("should set row height", () => {
|
it("should set row height", () => {
|
||||||
const tableRow = new TableRow([]);
|
const tableRow = new TableRow({
|
||||||
tableRow.setHeight(100, HeightRule.EXACT);
|
children: [],
|
||||||
|
height: {
|
||||||
|
height: 100,
|
||||||
|
rule: HeightRule.EXACT,
|
||||||
|
},
|
||||||
|
});
|
||||||
const tree = new Formatter().format(tableRow);
|
const tree = new Formatter().format(tableRow);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:tr": [
|
"w:tr": [
|
||||||
@ -91,4 +115,71 @@ describe("TableRow", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#addCellToIndex", () => {
|
||||||
|
it("should add cell to correct index with no initial properties", () => {
|
||||||
|
const tableRow = new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
tableHeader: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
tableRow.addCellToIndex(
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
}),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
const tree = new Formatter().format(tableRow);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tr": [
|
||||||
|
{
|
||||||
|
"w:trPr": [
|
||||||
|
{
|
||||||
|
"w:tblHeader": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:p": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:t": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"xml:space": "preserve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"test",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -3,56 +3,51 @@ import { XmlComponent } from "file/xml-components";
|
|||||||
import { TableCell } from "../table-cell";
|
import { TableCell } from "../table-cell";
|
||||||
import { TableRowProperties } from "./table-row-properties";
|
import { TableRowProperties } from "./table-row-properties";
|
||||||
|
|
||||||
|
export interface ITableRowOptions {
|
||||||
|
readonly cantSplit?: boolean;
|
||||||
|
readonly tableHeader?: boolean;
|
||||||
|
readonly height?: {
|
||||||
|
readonly height: number;
|
||||||
|
readonly rule: HeightRule;
|
||||||
|
};
|
||||||
|
readonly children: TableCell[];
|
||||||
|
}
|
||||||
|
|
||||||
export class TableRow extends XmlComponent {
|
export class TableRow extends XmlComponent {
|
||||||
private readonly properties: TableRowProperties;
|
private readonly properties: TableRowProperties;
|
||||||
|
|
||||||
constructor(private readonly cells: TableCell[]) {
|
constructor(private readonly options: ITableRowOptions) {
|
||||||
super("w:tr");
|
super("w:tr");
|
||||||
this.properties = new TableRowProperties();
|
this.properties = new TableRowProperties();
|
||||||
this.root.push(this.properties);
|
this.root.push(this.properties);
|
||||||
cells.forEach((c) => this.root.push(c));
|
|
||||||
|
for (const child of options.children) {
|
||||||
|
this.root.push(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCell(index: number): TableCell {
|
if (options.cantSplit) {
|
||||||
const cell = this.cells[index];
|
|
||||||
|
|
||||||
if (!cell) {
|
|
||||||
throw Error("Index out of bounds when trying to get cell on row");
|
|
||||||
}
|
|
||||||
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addGridSpan(index: number, cellSpan: number): TableCell {
|
|
||||||
const remainCell = this.cells[index];
|
|
||||||
remainCell.addGridSpan(cellSpan);
|
|
||||||
this.cells.splice(index + 1, cellSpan - 1);
|
|
||||||
this.root.splice(index + 2, cellSpan - 1);
|
|
||||||
|
|
||||||
return remainCell;
|
|
||||||
}
|
|
||||||
|
|
||||||
public mergeCells(startIndex: number, endIndex: number): TableCell {
|
|
||||||
const cellSpan = endIndex - startIndex + 1;
|
|
||||||
|
|
||||||
return this.addGridSpan(startIndex, cellSpan);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setCantSplit(): TableRow {
|
|
||||||
this.properties.setCantSplit();
|
this.properties.setCantSplit();
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setTableHeader(): TableRow {
|
if (options.tableHeader) {
|
||||||
this.properties.setTableHeader();
|
this.properties.setTableHeader();
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setHeight(height: number, rule: HeightRule): TableRow {
|
if (options.height) {
|
||||||
this.properties.setHeight(height, rule);
|
this.properties.setHeight(options.height.height, options.height.rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
public get CellCount(): number {
|
||||||
|
return this.options.children.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Children(): TableCell[] {
|
||||||
|
return this.options.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addCellToIndex(cell: TableCell, index: number): void {
|
||||||
|
// Offset because properties is also in root.
|
||||||
|
this.root.splice(index + 1, 0, cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,9 @@ import { Table } from "./table";
|
|||||||
// import { WidthType } from "./table-cell";
|
// import { WidthType } from "./table-cell";
|
||||||
import { RelativeHorizontalPosition, RelativeVerticalPosition, TableAnchorType } from "./table-properties";
|
import { RelativeHorizontalPosition, RelativeVerticalPosition, TableAnchorType } from "./table-properties";
|
||||||
|
|
||||||
import { EMPTY_OBJECT } from "file/xml-components";
|
import { TableCell, WidthType } from "./table-cell";
|
||||||
import { TableLayoutType } from "./table-properties/table-layout";
|
import { TableLayoutType } from "./table-properties/table-layout";
|
||||||
|
import { TableRow } from "./table-row";
|
||||||
|
|
||||||
const DEFAULT_TABLE_PROPERTIES = {
|
const DEFAULT_TABLE_PROPERTIES = {
|
||||||
"w:tblCellMar": [
|
"w:tblCellMar": [
|
||||||
@ -118,11 +119,62 @@ describe("Table", () => {
|
|||||||
describe("#constructor", () => {
|
describe("#constructor", () => {
|
||||||
it("creates a table with the correct number of rows and columns", () => {
|
it("creates a table with the correct number of rows and columns", () => {
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 3,
|
rows: [
|
||||||
columns: 2,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(table);
|
const tree = new Formatter().format(table);
|
||||||
const cell = { "w:tc": [{ "w:p": EMPTY_OBJECT }] };
|
const cell = {
|
||||||
|
"w:tc": [
|
||||||
|
{
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:t": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"xml:space": "preserve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"hello",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:tbl": [
|
"w:tbl": [
|
||||||
{ "w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS] },
|
{ "w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS] },
|
||||||
@ -138,8 +190,15 @@ describe("Table", () => {
|
|||||||
|
|
||||||
it("sets the table to fixed width layout", () => {
|
it("sets the table to fixed width layout", () => {
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 1,
|
rows: [
|
||||||
columns: 1,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
layout: TableLayoutType.FIXED,
|
layout: TableLayoutType.FIXED,
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(table);
|
const tree = new Formatter().format(table);
|
||||||
@ -151,130 +210,60 @@ describe("Table", () => {
|
|||||||
"w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS, { "w:tblLayout": { _attr: { "w:type": "fixed" } } }],
|
"w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS, { "w:tblLayout": { _attr: { "w:type": "fixed" } } }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
describe("#getRow and Row#getCell", () => {
|
it("should set the table to provided width", () => {
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 2,
|
rows: [
|
||||||
columns: 2,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
width: {
|
||||||
|
size: 100,
|
||||||
|
type: WidthType.PERCENTAGE,
|
||||||
|
},
|
||||||
|
layout: TableLayoutType.FIXED,
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return the correct row", () => {
|
|
||||||
table
|
|
||||||
.getRow(0)
|
|
||||||
.getCell(0)
|
|
||||||
.add(new Paragraph("A1"));
|
|
||||||
table
|
|
||||||
.getRow(0)
|
|
||||||
.getCell(1)
|
|
||||||
.add(new Paragraph("B1"));
|
|
||||||
table
|
|
||||||
.getRow(1)
|
|
||||||
.getCell(0)
|
|
||||||
.add(new Paragraph("A2"));
|
|
||||||
table
|
|
||||||
.getRow(1)
|
|
||||||
.getCell(1)
|
|
||||||
.add(new Paragraph("B2"));
|
|
||||||
const tree = new Formatter().format(table);
|
const tree = new Formatter().format(table);
|
||||||
const cell = (c) => ({
|
expect(tree)
|
||||||
"w:tc": [
|
.to.have.property("w:tbl")
|
||||||
|
.which.is.an("array")
|
||||||
|
.with.has.length.at.least(1);
|
||||||
|
expect(tree["w:tbl"][0]).to.deep.equal({
|
||||||
|
"w:tblPr": [
|
||||||
|
DEFAULT_TABLE_PROPERTIES,
|
||||||
|
BORDERS,
|
||||||
{
|
{
|
||||||
"w:p": [{ "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, c] }] }],
|
"w:tblW": {
|
||||||
|
_attr: {
|
||||||
|
"w:type": "pct",
|
||||||
|
"w:w": "100%",
|
||||||
},
|
},
|
||||||
],
|
|
||||||
});
|
|
||||||
expect(tree).to.deep.equal({
|
|
||||||
"w:tbl": [
|
|
||||||
{ "w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS] },
|
|
||||||
{
|
|
||||||
"w:tblGrid": [{ "w:gridCol": { _attr: { "w:w": 100 } } }, { "w:gridCol": { _attr: { "w:w": 100 } } }],
|
|
||||||
},
|
},
|
||||||
{ "w:tr": [cell("A1"), cell("B1")] },
|
|
||||||
{ "w:tr": [cell("A2"), cell("B2")] },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("throws an exception if index is out of bounds", () => {
|
|
||||||
expect(() => table.getCell(9, 9)).to.throw();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("#getColumn", () => {
|
|
||||||
const table = new Table({
|
|
||||||
rows: 2,
|
|
||||||
columns: 2,
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should get correct cell", () => {
|
|
||||||
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("should returns the correct cell", () => {
|
|
||||||
const table = new Table({
|
|
||||||
rows: 2,
|
|
||||||
columns: 2,
|
|
||||||
});
|
|
||||||
table.getCell(0, 0).add(new Paragraph("A1"));
|
|
||||||
table.getCell(0, 1).add(new Paragraph("B1"));
|
|
||||||
table.getCell(1, 0).add(new Paragraph("A2"));
|
|
||||||
table.getCell(1, 1).add(new Paragraph("B2"));
|
|
||||||
const tree = new Formatter().format(table);
|
|
||||||
const cell = (c) => ({
|
|
||||||
"w:tc": [
|
|
||||||
{
|
|
||||||
"w:p": [{ "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, c] }] }],
|
|
||||||
},
|
},
|
||||||
],
|
{ "w:tblLayout": { _attr: { "w:type": "fixed" } } },
|
||||||
});
|
|
||||||
expect(tree).to.deep.equal({
|
|
||||||
"w:tbl": [
|
|
||||||
{ "w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS] },
|
|
||||||
{
|
|
||||||
"w:tblGrid": [{ "w:gridCol": { _attr: { "w:w": 100 } } }, { "w:gridCol": { _attr: { "w:w": 100 } } }],
|
|
||||||
},
|
|
||||||
{ "w:tr": [cell("A1"), cell("B1")] },
|
|
||||||
{ "w:tr": [cell("A2"), cell("B2")] },
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// describe("#setWidth", () => {
|
|
||||||
// it("should set the preferred width on the table", () => {
|
|
||||||
// const table = new Table({rows: 1,columns: 1,}).setWidth(1000, WidthType.PERCENTAGE);
|
|
||||||
// const tree = new Formatter().format(table);
|
|
||||||
// expect(tree)
|
|
||||||
// .to.have.property("w:tbl")
|
|
||||||
// .which.is.an("array")
|
|
||||||
// .with.has.length.at.least(1);
|
|
||||||
// expect(tree["w:tbl"][0]).to.deep.equal({
|
|
||||||
// "w:tblPr": [DEFAULT_TABLE_PROPERTIES, { "w:tblW": { _attr: { "w:type": "pct", "w:w": "1000%" } } }],
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it("sets the preferred width on the table with a default of AUTO", () => {
|
|
||||||
// const table = new Table({rows: 1,columns: 1,}).setWidth(1000);
|
|
||||||
// const tree = new Formatter().format(table);
|
|
||||||
|
|
||||||
// expect(tree["w:tbl"][0]).to.deep.equal({
|
|
||||||
// "w:tblPr": [DEFAULT_TABLE_PROPERTIES, { "w:tblW": { _attr: { "w:type": "auto", "w:w": 1000 } } }],
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
describe("Cell", () => {
|
describe("Cell", () => {
|
||||||
describe("#prepForXml", () => {
|
describe("#prepForXml", () => {
|
||||||
it("inserts a paragraph at the end of the cell if it is empty", () => {
|
it("inserts a paragraph at the end of the cell if it is empty", () => {
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 1,
|
rows: [
|
||||||
columns: 1,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(table);
|
const tree = new Formatter().format(table);
|
||||||
expect(tree)
|
expect(tree)
|
||||||
@ -282,72 +271,119 @@ describe("Table", () => {
|
|||||||
.which.is.an("array");
|
.which.is.an("array");
|
||||||
const row = tree["w:tbl"].find((x) => x["w:tr"]);
|
const row = tree["w:tbl"].find((x) => x["w:tr"]);
|
||||||
expect(row).not.to.be.undefined;
|
expect(row).not.to.be.undefined;
|
||||||
expect(row["w:tr"])
|
|
||||||
.to.be.an("array")
|
|
||||||
.which.has.length.at.least(1);
|
|
||||||
expect(row["w:tr"].find((x) => x["w:tc"])).to.deep.equal({
|
|
||||||
"w:tc": [{ "w:p": EMPTY_OBJECT }],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("inserts a paragraph at the end of the cell even if it has a child table", () => {
|
|
||||||
const parentTable = new Table({
|
|
||||||
rows: 1,
|
|
||||||
columns: 1,
|
|
||||||
});
|
|
||||||
parentTable.getCell(0, 0).add(
|
|
||||||
new Table({
|
|
||||||
rows: 1,
|
|
||||||
columns: 1,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
const tree = new Formatter().format(parentTable);
|
|
||||||
expect(tree)
|
|
||||||
.to.have.property("w:tbl")
|
|
||||||
.which.is.an("array");
|
|
||||||
const row = tree["w:tbl"].find((x) => x["w:tr"]);
|
|
||||||
expect(row).not.to.be.undefined;
|
|
||||||
expect(row["w:tr"])
|
|
||||||
.to.be.an("array")
|
|
||||||
.which.has.length.at.least(1);
|
|
||||||
const cell = row["w:tr"].find((x) => x["w:tc"]);
|
|
||||||
expect(cell).not.to.be.undefined;
|
|
||||||
expect(cell["w:tc"][cell["w:tc"].length - 1]).to.deep.equal({
|
|
||||||
"w:p": EMPTY_OBJECT,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not insert a paragraph if it already ends with one", () => {
|
|
||||||
const parentTable = new Table({
|
|
||||||
rows: 1,
|
|
||||||
columns: 1,
|
|
||||||
});
|
|
||||||
parentTable.getCell(0, 0).add(new Paragraph("Hello"));
|
|
||||||
const tree = new Formatter().format(parentTable);
|
|
||||||
expect(tree)
|
|
||||||
.to.have.property("w:tbl")
|
|
||||||
.which.is.an("array");
|
|
||||||
const row = tree["w:tbl"].find((x) => x["w:tr"]);
|
|
||||||
expect(row).not.to.be.undefined;
|
|
||||||
expect(row["w:tr"])
|
expect(row["w:tr"])
|
||||||
.to.be.an("array")
|
.to.be.an("array")
|
||||||
.which.has.length.at.least(1);
|
.which.has.length.at.least(1);
|
||||||
expect(row["w:tr"].find((x) => x["w:tc"])).to.deep.equal({
|
expect(row["w:tr"].find((x) => x["w:tc"])).to.deep.equal({
|
||||||
"w:tc": [
|
"w:tc": [
|
||||||
{
|
{
|
||||||
"w:p": [{ "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, "Hello"] }] }],
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:t": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"xml:space": "preserve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"hello",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// it("inserts a paragraph at the end of the cell even if it has a child table", () => {
|
||||||
|
// const table = new Table({
|
||||||
|
// rows: [
|
||||||
|
// new TableRow({
|
||||||
|
// children: [
|
||||||
|
// new TableCell({
|
||||||
|
// children: [new Paragraph("hello")],
|
||||||
|
// }),
|
||||||
|
// ],
|
||||||
|
// }),
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
// table.getCell(0, 0).add(
|
||||||
|
// new Table({
|
||||||
|
// rows: [
|
||||||
|
// new TableRow({
|
||||||
|
// children: [
|
||||||
|
// new TableCell({
|
||||||
|
// children: [new Paragraph("hello")],
|
||||||
|
// }),
|
||||||
|
// ],
|
||||||
|
// }),
|
||||||
|
// ],
|
||||||
|
// }),
|
||||||
|
// );
|
||||||
|
// const tree = new Formatter().format(table);
|
||||||
|
// expect(tree)
|
||||||
|
// .to.have.property("w:tbl")
|
||||||
|
// .which.is.an("array");
|
||||||
|
// const row = tree["w:tbl"].find((x) => x["w:tr"]);
|
||||||
|
// expect(row).not.to.be.undefined;
|
||||||
|
// expect(row["w:tr"])
|
||||||
|
// .to.be.an("array")
|
||||||
|
// .which.has.length.at.least(1);
|
||||||
|
// const cell = row["w:tr"].find((x) => x["w:tc"]);
|
||||||
|
// expect(cell).not.to.be.undefined;
|
||||||
|
// expect(cell["w:tc"][cell["w:tc"].length - 1]).to.deep.equal({
|
||||||
|
// "w:p": EMPTY_OBJECT,
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// it("does not insert a paragraph if it already ends with one", () => {
|
||||||
|
// const table = new Table({
|
||||||
|
// rows: [
|
||||||
|
// new TableRow({
|
||||||
|
// children: [
|
||||||
|
// new TableCell({
|
||||||
|
// children: [new Paragraph("hello")],
|
||||||
|
// }),
|
||||||
|
// ],
|
||||||
|
// }),
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
// table.getCell(0, 0).add(new Paragraph("Hello"));
|
||||||
|
// const tree = new Formatter().format(table);
|
||||||
|
// expect(tree)
|
||||||
|
// .to.have.property("w:tbl")
|
||||||
|
// .which.is.an("array");
|
||||||
|
// const row = tree["w:tbl"].find((x) => x["w:tr"]);
|
||||||
|
// expect(row).not.to.be.undefined;
|
||||||
|
// expect(row["w:tr"])
|
||||||
|
// .to.be.an("array")
|
||||||
|
// .which.has.length.at.least(1);
|
||||||
|
// expect(row["w:tr"].find((x) => x["w:tc"])).to.deep.equal({
|
||||||
|
// "w:tc": [
|
||||||
|
// {
|
||||||
|
// "w:p": [{ "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, "Hello"] }] }],
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
// });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#float", () => {
|
describe("#float", () => {
|
||||||
it("sets the table float properties", () => {
|
it("sets the table float properties", () => {
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: 1,
|
rows: [
|
||||||
columns: 1,
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
float: {
|
float: {
|
||||||
horizontalAnchor: TableAnchorType.MARGIN,
|
horizontalAnchor: TableAnchorType.MARGIN,
|
||||||
verticalAnchor: TableAnchorType.PAGE,
|
verticalAnchor: TableAnchorType.PAGE,
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
// http://officeopenxml.com/WPtableGrid.php
|
// http://officeopenxml.com/WPtableGrid.php
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
import { TableGrid } from "./grid";
|
import { TableGrid } from "./grid";
|
||||||
import { TableCell, WidthType } from "./table-cell";
|
import { TableCell, VerticalMergeType, WidthType } from "./table-cell";
|
||||||
import { TableColumn } from "./table-column";
|
|
||||||
import { ITableFloatOptions, TableProperties } from "./table-properties";
|
import { ITableFloatOptions, TableProperties } from "./table-properties";
|
||||||
import { TableLayoutType } from "./table-properties/table-layout";
|
import { TableLayoutType } from "./table-properties/table-layout";
|
||||||
import { TableRow } from "./table-row";
|
import { TableRow } from "./table-row";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
0-width columns don't get rendered correctly, so we need
|
0-width columns don't get rendered correctly, so we need
|
||||||
to give them some value. A reasonable default would be
|
to give them some value. A reasonable default would be
|
||||||
@ -18,10 +17,11 @@ import { TableRow } from "./table-row";
|
|||||||
algorithm will expand columns to fit its content
|
algorithm will expand columns to fit its content
|
||||||
*/
|
*/
|
||||||
export interface ITableOptions {
|
export interface ITableOptions {
|
||||||
readonly rows: number;
|
readonly rows: TableRow[];
|
||||||
readonly columns: number;
|
readonly width?: {
|
||||||
readonly width?: number;
|
readonly size: number;
|
||||||
readonly widthUnitType?: WidthType;
|
readonly type?: WidthType;
|
||||||
|
};
|
||||||
readonly columnWidths?: number[];
|
readonly columnWidths?: number[];
|
||||||
readonly margins?: {
|
readonly margins?: {
|
||||||
readonly marginUnitType?: WidthType;
|
readonly marginUnitType?: WidthType;
|
||||||
@ -36,14 +36,11 @@ export interface ITableOptions {
|
|||||||
|
|
||||||
export class Table extends XmlComponent {
|
export class Table extends XmlComponent {
|
||||||
private readonly properties: TableProperties;
|
private readonly properties: TableProperties;
|
||||||
private readonly rows: TableRow[];
|
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
rows,
|
rows,
|
||||||
columns,
|
width,
|
||||||
width = 100,
|
columnWidths = Array<number>(Math.max(...rows.map((row) => row.CellCount))).fill(100),
|
||||||
widthUnitType = WidthType.AUTO,
|
|
||||||
columnWidths = Array<number>(columns).fill(100),
|
|
||||||
margins: { marginUnitType, top, bottom, right, left } = { marginUnitType: WidthType.AUTO, top: 0, bottom: 0, right: 0, left: 0 },
|
margins: { marginUnitType, top, bottom, right, left } = { marginUnitType: WidthType.AUTO, top: 0, bottom: 0, right: 0, left: 0 },
|
||||||
float,
|
float,
|
||||||
layout,
|
layout,
|
||||||
@ -52,26 +49,45 @@ export class Table extends XmlComponent {
|
|||||||
this.properties = new TableProperties();
|
this.properties = new TableProperties();
|
||||||
this.root.push(this.properties);
|
this.root.push(this.properties);
|
||||||
this.properties.setBorder();
|
this.properties.setBorder();
|
||||||
this.properties.setWidth(width, widthUnitType);
|
|
||||||
|
if (width) {
|
||||||
|
this.properties.setWidth(width.size, width.type);
|
||||||
|
} else {
|
||||||
|
this.properties.setWidth(100);
|
||||||
|
}
|
||||||
|
|
||||||
this.properties.CellMargin.addBottomMargin(bottom || 0, marginUnitType);
|
this.properties.CellMargin.addBottomMargin(bottom || 0, marginUnitType);
|
||||||
this.properties.CellMargin.addTopMargin(top || 0, marginUnitType);
|
this.properties.CellMargin.addTopMargin(top || 0, marginUnitType);
|
||||||
this.properties.CellMargin.addLeftMargin(left || 0, marginUnitType);
|
this.properties.CellMargin.addLeftMargin(left || 0, marginUnitType);
|
||||||
this.properties.CellMargin.addRightMargin(right || 0, marginUnitType);
|
this.properties.CellMargin.addRightMargin(right || 0, marginUnitType);
|
||||||
const grid = new TableGrid(columnWidths);
|
|
||||||
|
|
||||||
this.root.push(grid);
|
this.root.push(new TableGrid(columnWidths));
|
||||||
|
|
||||||
this.rows = Array(rows)
|
for (const row of rows) {
|
||||||
.fill(0)
|
this.root.push(row);
|
||||||
.map(() => {
|
}
|
||||||
const cells = Array(columns)
|
|
||||||
.fill(0)
|
for (const row of rows) {
|
||||||
.map(() => new TableCell());
|
row.Children.forEach((cell, cellIndex) => {
|
||||||
const row = new TableRow(cells);
|
const column = rows.map((r) => r.Children[cellIndex]);
|
||||||
return row;
|
// 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 thisCellsColumnIndex = column.indexOf(cell);
|
||||||
|
const endColumnIndex = thisCellsColumnIndex + (cell.options.rowSpan - 1);
|
||||||
|
|
||||||
|
for (let i = thisCellsColumnIndex + 1; i <= endColumnIndex; i++) {
|
||||||
|
rows[i].addCellToIndex(
|
||||||
|
new TableCell({
|
||||||
|
children: [],
|
||||||
|
verticalMerge: VerticalMergeType.CONTINUE,
|
||||||
|
}),
|
||||||
|
i,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
this.rows.forEach((x) => this.root.push(x));
|
|
||||||
|
|
||||||
if (float) {
|
if (float) {
|
||||||
this.properties.setTableFloatProperties(float);
|
this.properties.setTableFloatProperties(float);
|
||||||
@ -81,24 +97,4 @@ export class Table extends XmlComponent {
|
|||||||
this.properties.setLayout(layout);
|
this.properties.setLayout(layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user