Compare commits
137 Commits
Author | SHA1 | Date | |
---|---|---|---|
43c199c725 | |||
0e975b3d66 | |||
c6ab47e838 | |||
48c17d51bb | |||
df2315ae4a | |||
e67fd9cb2b | |||
639842332f | |||
2cb7d44a77 | |||
6cd62418a5 | |||
f3ba11b21c | |||
51b1e08a35 | |||
b0d0041ff9 | |||
55c5dd818a | |||
3bebe0ad59 | |||
c5c67fd92a | |||
1486d3de56 | |||
6d8eea40be | |||
0922d49cd3 | |||
f76471f553 | |||
973177676e | |||
5aa878b901 | |||
b99d1fc129 | |||
1590f9ac70 | |||
6c772b956c | |||
9d09ff3518 | |||
d9ad69b7cd | |||
e23d230acb | |||
5ca872cb07 | |||
b179facca2 | |||
db60270e1f | |||
3e2130bc80 | |||
1b336785b4 | |||
6eed0fe0f5 | |||
2f8f69b0c4 | |||
4580a65a84 | |||
661c3e21e4 | |||
32646f8806 | |||
231428852e | |||
46ddf77342 | |||
441afe8c97 | |||
ca9ce01f56 | |||
2b9ce0febd | |||
18760387db | |||
28dabb06cb | |||
50fc9b6274 | |||
367518d504 | |||
efd89f24e6 | |||
4fd2b6f1d3 | |||
5ae541a40d | |||
c9fb9a827d | |||
918faf59c3 | |||
3a9fa49fbb | |||
218a08d793 | |||
416a239708 | |||
d1bdbd397a | |||
a6077b8f16 | |||
83a7f4664d | |||
728aefc4a7 | |||
40730548bb | |||
d6c2c96757 | |||
b22f565dd0 | |||
41eeac1b05 | |||
18a5f22f4c | |||
2a1161d857 | |||
4b6d3c3e3c | |||
14a1d62148 | |||
1f98d9461b | |||
8dc590746b | |||
de5f5c9a77 | |||
788205b14d | |||
ca5f6a56a5 | |||
bf8dfe6604 | |||
b0ee0305fb | |||
8f6984580a | |||
383c6d769f | |||
9f38a4f48a | |||
475a132ce0 | |||
4111413074 | |||
50209bb435 | |||
b37d2c141d | |||
d19cdcae0c | |||
3f652764e9 | |||
7b5cf690e2 | |||
d674523139 | |||
db7f27a88c | |||
677300e34f | |||
9271b2d11a | |||
942c6d028c | |||
f717126145 | |||
abd5ace85c | |||
612c024b1f | |||
12ad545fe8 | |||
6d0f6a61d7 | |||
e3bcad6d3c | |||
f7c372a85c | |||
bb277a4a76 | |||
52b78a583e | |||
20ab36191b | |||
dbfb80e660 | |||
421f4471de | |||
04ea2b2dc9 | |||
93a2404343 | |||
149cda9a3b | |||
b9465b2a20 | |||
ab07f2ecbe | |||
c70c147afe | |||
8db52212ab | |||
d021a3995e | |||
1ea347ed21 | |||
0725e54271 | |||
3b6aca2451 | |||
249e44532f | |||
d3af3663ec | |||
bf18154fcf | |||
5efc9e383b | |||
6505119d3b | |||
600f97de29 | |||
a1c21d2143 | |||
39066fb5f2 | |||
8fd99052fb | |||
4e671eb512 | |||
2677c4a4ec | |||
e19890e27a | |||
28556f277b | |||
50e08f198c | |||
7639b60b15 | |||
765a9686d8 | |||
ff443aa7c4 | |||
28fc328cb3 | |||
083f121683 | |||
2f57d3be84 | |||
7b47dadede | |||
8ad5485347 | |||
8df78e45d9 | |||
39cef5e61d | |||
5552f9d834 | |||
d13795696d |
@ -10,6 +10,7 @@ script:
|
|||||||
- npm run style
|
- npm run style
|
||||||
- npm run build
|
- npm run build
|
||||||
- npm run ts-node -- ./demo/demo1.ts
|
- npm run ts-node -- ./demo/demo1.ts
|
||||||
|
- npm run e2e "My Document.docx"
|
||||||
- npm run ts-node -- ./demo/demo2.ts
|
- npm run ts-node -- ./demo/demo2.ts
|
||||||
- npm run ts-node -- ./demo/demo3.ts
|
- npm run ts-node -- ./demo/demo3.ts
|
||||||
- npm run ts-node -- ./demo/demo4.ts
|
- npm run ts-node -- ./demo/demo4.ts
|
||||||
@ -19,6 +20,7 @@ script:
|
|||||||
- npm run ts-node -- ./demo/demo8.ts
|
- npm run ts-node -- ./demo/demo8.ts
|
||||||
- npm run ts-node -- ./demo/demo9.ts
|
- npm run ts-node -- ./demo/demo9.ts
|
||||||
- npm run ts-node -- ./demo/demo10.ts
|
- npm run ts-node -- ./demo/demo10.ts
|
||||||
|
- npm run e2e "My Document.docx"
|
||||||
- npm run ts-node -- ./demo/demo11.ts
|
- npm run ts-node -- ./demo/demo11.ts
|
||||||
- npm run ts-node -- ./demo/demo12.ts
|
- npm run ts-node -- ./demo/demo12.ts
|
||||||
- npm run ts-node -- ./demo/demo13.ts
|
- npm run ts-node -- ./demo/demo13.ts
|
||||||
@ -41,6 +43,7 @@ script:
|
|||||||
- npm run ts-node -- ./demo/demo30.ts
|
- npm run ts-node -- ./demo/demo30.ts
|
||||||
- npm run ts-node -- ./demo/demo31.ts
|
- npm run ts-node -- ./demo/demo31.ts
|
||||||
- npm run ts-node -- ./demo/demo32.ts
|
- npm run ts-node -- ./demo/demo32.ts
|
||||||
|
# - npm run e2e "My Document.docx" // Need to fix
|
||||||
- npm run ts-node -- ./demo/demo33.ts
|
- npm run ts-node -- ./demo/demo33.ts
|
||||||
- npm run ts-node -- ./demo/demo34.ts
|
- npm run ts-node -- ./demo/demo34.ts
|
||||||
after_failure:
|
after_failure:
|
||||||
|
15
README.md
15
README.md
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
## Browser
|
## Browser
|
||||||
|
|
||||||
Here are examples of `docx` being used with basic `HTML/JS` in a browser environment.
|
Here are examples of `docx` being used with basic `HTML/JS` in a browser environment:
|
||||||
|
|
||||||
* https://codepen.io/anon/pen/dqoVgQ
|
* https://codepen.io/anon/pen/dqoVgQ
|
||||||
* https://jsfiddle.net/3xhezb5w/2
|
* https://jsfiddle.net/3xhezb5w/2
|
||||||
@ -64,8 +64,17 @@ Check the `examples` section in the [documentation](https://docx.js.org/#/exampl
|
|||||||
|
|
||||||
Read the contribution guidelines [here](https://docx.js.org/#/contribution-guidelines).
|
Read the contribution guidelines [here](https://docx.js.org/#/contribution-guidelines).
|
||||||
|
|
||||||
|
# Used by
|
||||||
|
|
||||||
|
[<img src="https://i.imgur.com/zy5qWmI.png" alt="drawing" height="200"/>](https://hfour.com/)
|
||||||
|
[<img src="https://i.imgur.com/OYP5tgS.png" alt="drawing" height="200"/>](https://fuzzproductions.com/)
|
||||||
|
[<img src="https://i.imgur.com/zUDMfZ3.png" alt="drawing" height="200"/>](https://www.mettzer.com/)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
[![patreon][patreon-image]][patreon-url]
|
||||||
|
[![browserstack][browserstack-image]][browserstack-url]
|
||||||
|
|
||||||
Made with 💖
|
Made with 💖
|
||||||
|
|
||||||
[npm-image]: https://badge.fury.io/js/docx.svg
|
[npm-image]: https://badge.fury.io/js/docx.svg
|
||||||
@ -84,3 +93,7 @@ Made with 💖
|
|||||||
[pr-url]: http://makeapullrequest.com
|
[pr-url]: http://makeapullrequest.com
|
||||||
[codecov-image]: https://codecov.io/gh/dolanmiu/docx/branch/master/graph/badge.svg
|
[codecov-image]: https://codecov.io/gh/dolanmiu/docx/branch/master/graph/badge.svg
|
||||||
[codecov-url]: https://codecov.io/gh/dolanmiu/docx
|
[codecov-url]: https://codecov.io/gh/dolanmiu/docx
|
||||||
|
[patreon-image]: https://user-images.githubusercontent.com/2917613/51251459-4e880480-1991-11e9-92bf-38b96675a9e2.png
|
||||||
|
[patreon-url]: https://www.patreon.com/dolanmiu
|
||||||
|
[browserstack-image]: https://user-images.githubusercontent.com/2917613/54233552-128e9d00-4505-11e9-88fb-025a4e04007c.png
|
||||||
|
[browserstack-url]: https://www.browserstack.com
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Add images to header and footer
|
// Generate a CV
|
||||||
// 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, TextRun } from "../build";
|
import { Document, Packer, Paragraph, TextRun } from "../build";
|
||||||
@ -233,7 +233,7 @@ class DocumentCreator {
|
|||||||
|
|
||||||
public createRoleText(roleText: string): Paragraph {
|
public createRoleText(roleText: string): Paragraph {
|
||||||
const paragraph = new Paragraph();
|
const paragraph = new Paragraph();
|
||||||
const role = new TextRun(roleText).italic();
|
const role = new TextRun(roleText).italics();
|
||||||
|
|
||||||
paragraph.addRun(role);
|
paragraph.addRun(role);
|
||||||
|
|
||||||
|
@ -84,8 +84,7 @@ doc.Styles.createParagraphStyle("ListParagraph", "List Paragraph")
|
|||||||
.basedOn("Normal");
|
.basedOn("Normal");
|
||||||
|
|
||||||
doc.createImage(fs.readFileSync("./demo/images/pizza.gif"));
|
doc.createImage(fs.readFileSync("./demo/images/pizza.gif"));
|
||||||
doc
|
doc.createParagraph("HEADING")
|
||||||
.createParagraph("HEADING")
|
|
||||||
.heading1()
|
.heading1()
|
||||||
.center();
|
.center();
|
||||||
|
|
||||||
@ -107,12 +106,15 @@ doc.createParagraph("Sir,").style("normalPara");
|
|||||||
|
|
||||||
doc.createParagraph("BRIEF DESCRIPTION").style("normalPara");
|
doc.createParagraph("BRIEF DESCRIPTION").style("normalPara");
|
||||||
|
|
||||||
const table = new Table(4, 4);
|
const table = new Table({
|
||||||
|
rows: 4,
|
||||||
|
columns: 4,
|
||||||
|
});
|
||||||
table
|
table
|
||||||
.getRow(0)
|
.getRow(0)
|
||||||
.getCell(0)
|
.getCell(0)
|
||||||
.addContent(new Paragraph("Pole No."));
|
.addParagraph(new Paragraph("Pole No."));
|
||||||
// table.Properties.width = 10000;
|
|
||||||
doc.addTable(table);
|
doc.addTable(table);
|
||||||
|
|
||||||
const arrboth = [
|
const arrboth = [
|
||||||
@ -127,10 +129,7 @@ const arrboth = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
arrboth.forEach((item) => {
|
arrboth.forEach((item) => {
|
||||||
const para = doc.createParagraph();
|
doc.createImage(fs.readFileSync(item.image));
|
||||||
para.addImage(doc.createImage(fs.readFileSync(item.image)));
|
|
||||||
// para.Properties.width = 60;
|
|
||||||
// para.Properties.height = 90;
|
|
||||||
doc.createParagraph(item.comment).style("normalPara2");
|
doc.createParagraph(item.comment).style("normalPara2");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Multiple sections and headers
|
// Multiple sections and headers
|
||||||
// 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, PageNumberFormat, PageOrientation, Paragraph } from "../build";
|
import { Document, Packer, PageNumberFormat, PageOrientation, Paragraph, TextRun } from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
@ -41,6 +41,42 @@ doc.addSection({
|
|||||||
|
|
||||||
doc.createParagraph("hello in landscape");
|
doc.createParagraph("hello in landscape");
|
||||||
|
|
||||||
|
const header2 = doc.createHeader();
|
||||||
|
const pageNumber = new TextRun("Page number: ").pageNumber();
|
||||||
|
header2.createParagraph().addRun(pageNumber);
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
headers: {
|
||||||
|
default: header2,
|
||||||
|
},
|
||||||
|
orientation: PageOrientation.PORTRAIT,
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.createParagraph("Page number in the header must be 2, because it continues from the previous section.");
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
headers: {
|
||||||
|
default: header2,
|
||||||
|
},
|
||||||
|
pageNumberFormatType: PageNumberFormat.UPPER_ROMAN,
|
||||||
|
orientation: PageOrientation.PORTRAIT,
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.createParagraph(
|
||||||
|
"Page number in the header must be III, because it continues from the previous section, but is defined as upper roman.",
|
||||||
|
);
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
headers: {
|
||||||
|
default: header2,
|
||||||
|
},
|
||||||
|
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
||||||
|
pageNumberStart: 25,
|
||||||
|
orientation: PageOrientation.PORTRAIT,
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.createParagraph("Page number in the header must be 25, because it is defined to start at 25 and to be decimal in this section.");
|
||||||
|
|
||||||
const packer = new Packer();
|
const packer = new Packer();
|
||||||
|
|
||||||
packer.toBuffer(doc).then((buffer) => {
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
@ -5,11 +5,14 @@ import { BorderStyle, Document, Packer, Paragraph } from "../build";
|
|||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
const table = doc.createTable(4, 4);
|
const table = doc.createTable({
|
||||||
|
rows: 4,
|
||||||
|
columns: 4,
|
||||||
|
});
|
||||||
table
|
table
|
||||||
.getCell(2, 2)
|
.getCell(2, 2)
|
||||||
.addContent(new Paragraph("Hello"))
|
.addParagraph(new Paragraph("Hello"))
|
||||||
.CellProperties.Borders.addTopBorder(BorderStyle.DASH_DOT_STROKED, 3, "red")
|
.Borders.addTopBorder(BorderStyle.DASH_DOT_STROKED, 3, "red")
|
||||||
.addBottomBorder(BorderStyle.DOUBLE, 3, "blue")
|
.addBottomBorder(BorderStyle.DOUBLE, 3, "blue")
|
||||||
.addStartBorder(BorderStyle.DOT_DOT_DASH, 3, "green")
|
.addStartBorder(BorderStyle.DOT_DOT_DASH, 3, "green")
|
||||||
.addEndBorder(BorderStyle.DOT_DOT_DASH, 3, "#ff8000");
|
.addEndBorder(BorderStyle.DOT_DOT_DASH, 3, "#ff8000");
|
||||||
|
@ -16,7 +16,7 @@ paragraph2.addRun(textRun2);
|
|||||||
doc.addParagraph(paragraph2);
|
doc.addParagraph(paragraph2);
|
||||||
|
|
||||||
const paragraph3 = new Paragraph().bidirectional();
|
const paragraph3 = new Paragraph().bidirectional();
|
||||||
const textRun3 = new TextRun("שלום עולם").italic().rightToLeft();
|
const textRun3 = new TextRun("שלום עולם").italics().rightToLeft();
|
||||||
paragraph3.addRun(textRun3);
|
paragraph3.addRun(textRun3);
|
||||||
doc.addParagraph(paragraph3);
|
doc.addParagraph(paragraph3);
|
||||||
|
|
||||||
|
@ -5,11 +5,14 @@ import { Document, Media, Packer, Paragraph } from "../build";
|
|||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
const table = doc.createTable(4, 4);
|
const table = doc.createTable({
|
||||||
table.getCell(2, 2).addContent(new Paragraph("Hello"));
|
rows: 4,
|
||||||
|
columns: 4,
|
||||||
|
});
|
||||||
|
table.getCell(2, 2).addParagraph(new Paragraph("Hello"));
|
||||||
|
|
||||||
const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
|
const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
|
||||||
table.getCell(1, 1).addContent(image.Paragraph);
|
table.getCell(1, 1).addParagraph(image.Paragraph);
|
||||||
|
|
||||||
const packer = new Packer();
|
const packer = new Packer();
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Custom styles using JavaScript configuration
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Document, Packer } from "../build";
|
import { Document, Packer } from "../build";
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Creates two paragraphs, one with a border and one without
|
// Table of contents
|
||||||
// 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 { File, Packer, Paragraph, StyleLevel, TableOfContents } from "../build";
|
import { File, Packer, Paragraph, StyleLevel, TableOfContents } from "../build";
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Numbered lists
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Document, Indent, Numbering, Packer, Paragraph } from "../build";
|
import { Document, Indent, Numbering, Packer, Paragraph } from "../build";
|
||||||
|
|
||||||
@ -15,10 +17,22 @@ const item2 = new Paragraph("line with contextual spacing");
|
|||||||
const item3 = new Paragraph("line without contextual spacing");
|
const item3 = new Paragraph("line without contextual spacing");
|
||||||
const item4 = new Paragraph("line without contextual spacing");
|
const item4 = new Paragraph("line without contextual spacing");
|
||||||
|
|
||||||
item1.setNumbering(concrete, 0).spacing({before: 200}).contextualSpacing(true);
|
item1
|
||||||
item2.setNumbering(concrete, 0).spacing({before: 200}).contextualSpacing(true);
|
.setNumbering(concrete, 0)
|
||||||
item3.setNumbering(concrete, 0).spacing({before: 200}).contextualSpacing(false);
|
.spacing({ before: 200 })
|
||||||
item4.setNumbering(concrete, 0).spacing({before: 200}).contextualSpacing(false);
|
.contextualSpacing(true);
|
||||||
|
item2
|
||||||
|
.setNumbering(concrete, 0)
|
||||||
|
.spacing({ before: 200 })
|
||||||
|
.contextualSpacing(true);
|
||||||
|
item3
|
||||||
|
.setNumbering(concrete, 0)
|
||||||
|
.spacing({ before: 200 })
|
||||||
|
.contextualSpacing(false);
|
||||||
|
item4
|
||||||
|
.setNumbering(concrete, 0)
|
||||||
|
.spacing({ before: 200 })
|
||||||
|
.contextualSpacing(false);
|
||||||
|
|
||||||
doc.addParagraph(item1);
|
doc.addParagraph(item1);
|
||||||
doc.addParagraph(item2);
|
doc.addParagraph(item2);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Example on how to use a template document
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Document, ImportDotx, Packer, Paragraph } from "../build";
|
import { Document, ImportDotx, Packer, Paragraph } from "../build";
|
||||||
|
|
||||||
|
@ -5,15 +5,18 @@ import { Document, Packer, Paragraph, VerticalAlign } from "../build";
|
|||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
const table = doc.createTable(2, 2);
|
const table = doc.createTable({
|
||||||
|
rows: 2,
|
||||||
|
columns: 2,
|
||||||
|
});
|
||||||
table
|
table
|
||||||
.getCell(1, 1)
|
.getCell(1, 1)
|
||||||
.addContent(new Paragraph("This text should be in the middle of the cell"))
|
.addParagraph(new Paragraph("This text should be in the middle of the cell"))
|
||||||
.CellProperties.setVerticalAlign(VerticalAlign.CENTER);
|
.setVerticalAlign(VerticalAlign.CENTER);
|
||||||
|
|
||||||
table
|
table
|
||||||
.getCell(1, 0)
|
.getCell(1, 0)
|
||||||
.addContent(
|
.addParagraph(
|
||||||
new Paragraph(
|
new Paragraph(
|
||||||
"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",
|
||||||
).heading1(),
|
).heading1(),
|
||||||
|
@ -1,33 +1,99 @@
|
|||||||
// Example of how you would create a table and add data to it
|
// Example of how you would merge cells together
|
||||||
// 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 } from "../build";
|
import { Document, Packer, Paragraph, ShadingType, WidthType } from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
let table = doc.createTable(2, 2);
|
let table = doc.createTable({
|
||||||
|
rows: 2,
|
||||||
|
columns: 2,
|
||||||
|
});
|
||||||
|
|
||||||
table.getCell(0, 0).addContent(new Paragraph("Hello"));
|
table.getCell(0, 0).addParagraph(new Paragraph("Hello"));
|
||||||
table.getRow(0).mergeCells(0, 1);
|
table.getRow(0).mergeCells(0, 1);
|
||||||
|
|
||||||
doc.createParagraph("Another table").heading2();
|
doc.createParagraph("Another table").heading2();
|
||||||
|
|
||||||
table = doc.createTable(2, 3);
|
table = doc.createTable({
|
||||||
table.getCell(0, 0).addContent(new Paragraph("World"));
|
rows: 2,
|
||||||
|
columns: 3,
|
||||||
|
width: 100,
|
||||||
|
widthUnitType: WidthType.AUTO,
|
||||||
|
columnWidths: [1000, 1000, 1000],
|
||||||
|
});
|
||||||
|
table
|
||||||
|
.getCell(0, 0)
|
||||||
|
.addParagraph(new Paragraph("World"))
|
||||||
|
.setMargains({
|
||||||
|
top: 1000,
|
||||||
|
bottom: 1000,
|
||||||
|
left: 1000,
|
||||||
|
right: 1000,
|
||||||
|
});
|
||||||
table.getRow(0).mergeCells(0, 2);
|
table.getRow(0).mergeCells(0, 2);
|
||||||
|
|
||||||
doc.createParagraph("Another table").heading2();
|
doc.createParagraph("Another table").heading2();
|
||||||
|
|
||||||
table = doc.createTable(2, 4);
|
table = doc.createTable({
|
||||||
table.getCell(0, 0).addContent(new Paragraph("Foo"));
|
rows: 2,
|
||||||
|
columns: 4,
|
||||||
|
width: 7000,
|
||||||
|
widthUnitType: WidthType.DXA,
|
||||||
|
margains: {
|
||||||
|
top: 400,
|
||||||
|
bottom: 400,
|
||||||
|
right: 400,
|
||||||
|
left: 400,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
table.getCell(0, 0).addParagraph(new Paragraph("Foo"));
|
||||||
|
table.getCell(0, 1).addParagraph(new Paragraph("v"));
|
||||||
|
|
||||||
table.getCell(1, 0).addContent(new Paragraph("Bar1"));
|
table
|
||||||
table.getCell(1, 1).addContent(new Paragraph("Bar2"));
|
.getCell(1, 0)
|
||||||
table.getCell(1, 2).addContent(new Paragraph("Bar3"));
|
.addParagraph(new Paragraph("Bar1"))
|
||||||
table.getCell(1, 3).addContent(new Paragraph("Bar4"));
|
.setShading({
|
||||||
|
fill: "b79c2f",
|
||||||
|
val: ShadingType.REVERSE_DIAGONAL_STRIPE,
|
||||||
|
color: "auto",
|
||||||
|
});
|
||||||
|
table
|
||||||
|
.getCell(1, 1)
|
||||||
|
.addParagraph(new Paragraph("Bar2"))
|
||||||
|
.setShading({
|
||||||
|
fill: "42c5f4",
|
||||||
|
val: ShadingType.PERCENT_95,
|
||||||
|
color: "auto",
|
||||||
|
});
|
||||||
|
table
|
||||||
|
.getCell(1, 2)
|
||||||
|
.addParagraph(new Paragraph("Bar3"))
|
||||||
|
.setShading({
|
||||||
|
fill: "880aa8",
|
||||||
|
val: ShadingType.PERCENT_10,
|
||||||
|
color: "e2df0b",
|
||||||
|
});
|
||||||
|
table
|
||||||
|
.getCell(1, 3)
|
||||||
|
.addParagraph(new Paragraph("Bar4"))
|
||||||
|
.setShading({
|
||||||
|
fill: "FF0000",
|
||||||
|
val: ShadingType.CLEAR,
|
||||||
|
color: "auto",
|
||||||
|
});
|
||||||
|
|
||||||
table.getRow(0).mergeCells(0, 3);
|
table.getRow(0).mergeCells(0, 3);
|
||||||
|
|
||||||
|
doc.createParagraph("hi");
|
||||||
|
|
||||||
|
doc.createTable({
|
||||||
|
rows: 2,
|
||||||
|
columns: 2,
|
||||||
|
width: 100,
|
||||||
|
widthUnitType: WidthType.PERCENTAGE,
|
||||||
|
});
|
||||||
|
|
||||||
const packer = new Packer();
|
const packer = new Packer();
|
||||||
|
|
||||||
packer.toBuffer(doc).then((buffer) => {
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
@ -1,28 +1,25 @@
|
|||||||
// Example of how you would create a table with float positions
|
// Example of how you would create a table with float positions
|
||||||
// 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 {
|
import { Document, Packer, Paragraph, RelativeHorizontalPosition, RelativeVerticalPosition, TableAnchorType, WidthType } from "../build";
|
||||||
Document,
|
|
||||||
Packer,
|
|
||||||
Paragraph,
|
|
||||||
RelativeHorizontalPosition,
|
|
||||||
RelativeVerticalPosition,
|
|
||||||
TableAnchorType,
|
|
||||||
WidthType,
|
|
||||||
} from "../build";
|
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
const table = doc.createTable(2, 2).float({
|
const table = doc.createTable({
|
||||||
|
rows: 2,
|
||||||
|
columns: 2,
|
||||||
|
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,
|
||||||
|
widthUnitType: WidthType.DXA,
|
||||||
});
|
});
|
||||||
table.setFixedWidthLayout();
|
table.setFixedWidthLayout();
|
||||||
table.setWidth(WidthType.DXA, 4535);
|
|
||||||
|
|
||||||
table.getCell(0, 0).addContent(new Paragraph("Hello"));
|
table.getCell(0, 0).addParagraph(new Paragraph("Hello"));
|
||||||
table.getRow(0).mergeCells(0, 1);
|
table.getRow(0).mergeCells(0, 1);
|
||||||
|
|
||||||
const packer = new Packer();
|
const packer = new Packer();
|
||||||
|
18
demo/demo35.ts
Normal file
18
demo/demo35.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Example on how to add hyperlinks to websites
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, Packer, Paragraph } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
const paragraph = new Paragraph();
|
||||||
|
const link = doc.createHyperlink("http://www.example.com", "Hyperlink");
|
||||||
|
|
||||||
|
link.bold();
|
||||||
|
paragraph.addHyperLink(link);
|
||||||
|
doc.addParagraph(paragraph);
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
26
demo/demo36.ts
Normal file
26
demo/demo36.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Add image to table cell
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, Media, Packer, Table } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
|
||||||
|
|
||||||
|
const table = new Table({
|
||||||
|
rows: 2,
|
||||||
|
columns: 2,
|
||||||
|
});
|
||||||
|
table.getCell(1, 1).addParagraph(image.Paragraph);
|
||||||
|
|
||||||
|
// doc.createParagraph("Hello World");
|
||||||
|
doc.addTable(table);
|
||||||
|
|
||||||
|
// doc.Header.createImage(fs.readFileSync("./demo/images/pizza.gif"));
|
||||||
|
doc.Header.addTable(table);
|
||||||
|
// doc.Footer.createImage(fs.readFileSync("./demo/images/pizza.gif"));
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
18
demo/demo37.ts
Normal file
18
demo/demo37.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Add images to header and footer
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, Media, Packer } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
|
||||||
|
doc.createParagraph("Hello World");
|
||||||
|
|
||||||
|
doc.Header.addImage(image);
|
||||||
|
doc.Header.createImage(fs.readFileSync("./demo/images/pizza.gif"));
|
||||||
|
doc.Header.createImage(fs.readFileSync("./demo/images/image1.jpeg"));
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
@ -1,4 +1,4 @@
|
|||||||
// Example of how to add images to the document - You can use Buffers, UInt8Arrays or Base64 strings
|
// Example of how to "wrap" text around an image
|
||||||
// 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 } from "../build";
|
// import { Document, Packer, Paragraph } from "../build";
|
||||||
|
33
demo/demo39.ts
Normal file
33
demo/demo39.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Example how to display page numbers
|
||||||
|
// 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(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
pageNumberStart: 1,
|
||||||
|
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
doc.Header.createParagraph("Foo Bar corp. ")
|
||||||
|
.addRun(new TextRun("Page Number ").pageNumber())
|
||||||
|
.addRun(new TextRun(" to ").numberOfTotalPages());
|
||||||
|
|
||||||
|
doc.Footer.createParagraph("Foo Bar corp. ")
|
||||||
|
.center()
|
||||||
|
.addRun(new TextRun("Page Number: ").pageNumber())
|
||||||
|
.addRun(new TextRun(" to ").numberOfTotalPages());
|
||||||
|
|
||||||
|
doc.createParagraph("Hello World 1").pageBreak();
|
||||||
|
doc.createParagraph("Hello World 2").pageBreak();
|
||||||
|
doc.createParagraph("Hello World 3").pageBreak();
|
||||||
|
doc.createParagraph("Hello World 4").pageBreak();
|
||||||
|
doc.createParagraph("Hello World 5").pageBreak();
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
@ -5,8 +5,11 @@ import { Document, Packer, Paragraph } from "../build";
|
|||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
const table = doc.createTable(4, 4);
|
const table = doc.createTable({
|
||||||
table.getCell(2, 2).addContent(new Paragraph("Hello"));
|
rows: 4,
|
||||||
|
columns: 4,
|
||||||
|
});
|
||||||
|
table.getCell(2, 2).addParagraph(new Paragraph("Hello"));
|
||||||
|
|
||||||
const packer = new Packer();
|
const packer = new Packer();
|
||||||
|
|
||||||
|
51
demo/demo41.ts
Normal file
51
demo/demo41.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Multiple cells merging in the same table
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, Packer, Paragraph } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
|
||||||
|
const table = doc.createTable({
|
||||||
|
rows: 13,
|
||||||
|
columns: 6,
|
||||||
|
});
|
||||||
|
let row = 0;
|
||||||
|
table.getCell(row, 0).addContent(new Paragraph("0,0"));
|
||||||
|
table.getCell(row, 1).addContent(new Paragraph("0,1"));
|
||||||
|
table.getCell(row, 3).addContent(new Paragraph("0,3"));
|
||||||
|
table.getCell(row, 4).addContent(new Paragraph("0,4"));
|
||||||
|
table.getRow(row).mergeCells(4, 5);
|
||||||
|
table.getRow(row).mergeCells(1, 2);
|
||||||
|
row = 1;
|
||||||
|
table.getCell(row, 0).addContent(new Paragraph("1,0"));
|
||||||
|
table.getCell(row, 2).addContent(new Paragraph("1,2"));
|
||||||
|
table.getCell(row, 4).addContent(new Paragraph("1,4"));
|
||||||
|
table.getRow(row).mergeCells(4, 5);
|
||||||
|
table.getRow(row).mergeCells(2, 3);
|
||||||
|
table.getRow(row).mergeCells(0, 1);
|
||||||
|
|
||||||
|
row = 2;
|
||||||
|
table.getCell(row, 0).addContent(new Paragraph("2,0"));
|
||||||
|
table.getCell(row, 1).addContent(new Paragraph("2,1"));
|
||||||
|
table.getCell(row, 2).addContent(new Paragraph("2,2"));
|
||||||
|
table.getCell(row, 3).addContent(new Paragraph("2,3"));
|
||||||
|
table.getCell(row, 4).addContent(new Paragraph("2,4"));
|
||||||
|
table.getRow(row).mergeCells(4, 5);
|
||||||
|
table.getRow(row).mergeCells(1, 2);
|
||||||
|
row = 3;
|
||||||
|
table.getCell(row, 0).addContent(new Paragraph("3,0"));
|
||||||
|
table.getCell(row, 1).addContent(new Paragraph("3,1"));
|
||||||
|
table.getCell(row, 2).addContent(new Paragraph("3,2"));
|
||||||
|
table.getCell(row, 3).addContent(new Paragraph("3,3"));
|
||||||
|
table.getCell(row, 4).addContent(new Paragraph("3,4"));
|
||||||
|
table.getCell(row, 5).addContent(new Paragraph("3,5"));
|
||||||
|
row = 4;
|
||||||
|
table.getCell(row, 0).addContent(new Paragraph("4,0"));
|
||||||
|
table.getCell(row, 5).addContent(new Paragraph("4,5"));
|
||||||
|
table.getRow(row).mergeCells(0, 4);
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
20
demo/demo43.ts
Normal file
20
demo/demo43.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Add image to table cell
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, Packer, Paragraph } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
|
||||||
|
const table = doc.createTable({
|
||||||
|
rows: 4,
|
||||||
|
columns: 4,
|
||||||
|
});
|
||||||
|
table.getCell(2, 2).addParagraph(new Paragraph("Hello"));
|
||||||
|
table.getColumn(3).mergeCells(1, 2);
|
||||||
|
// table.getCell(3, 2).addParagraph(new Paragraph("Hello"));
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
@ -29,6 +29,7 @@ import * as docx from "docx";
|
|||||||
## Basic Usage
|
## Basic Usage
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
var fs = require("fs");
|
||||||
var docx = require("docx");
|
var docx = require("docx");
|
||||||
|
|
||||||
// Create document
|
// Create document
|
||||||
@ -41,11 +42,12 @@ paragraph.addRun(new docx.TextRun("Lorem Ipsum Foo Bar"));
|
|||||||
doc.addParagraph(paragraph);
|
doc.addParagraph(paragraph);
|
||||||
|
|
||||||
// Used to export the file into a .docx file
|
// Used to export the file into a .docx file
|
||||||
var exporter = new docx.LocalPacker(doc);
|
var packer = new docx.Packer();
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My First Document.docx", buffer);
|
||||||
|
});
|
||||||
|
|
||||||
exporter.pack("My First Document");
|
// Done! A file called 'My First Document.docx' will be in your file system.
|
||||||
|
|
||||||
// Done! A file called 'My First Document.docx' will be in your file system if you used LocalPacker
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Honoured Mentions
|
## Honoured Mentions
|
||||||
|
@ -15,8 +15,10 @@
|
|||||||
* [Headers & Footers](usage/headers-and-footers.md)
|
* [Headers & Footers](usage/headers-and-footers.md)
|
||||||
* [Bullet Points](usage/bullet-points.md)
|
* [Bullet Points](usage/bullet-points.md)
|
||||||
* [Numbering](usage/numbering.md)
|
* [Numbering](usage/numbering.md)
|
||||||
|
* [Tables](usage/tables.md)
|
||||||
* [Tab Stops](usage/tab-stops.md)
|
* [Tab Stops](usage/tab-stops.md)
|
||||||
* [Table of Contents](usage/table-of-contents.md)
|
* [Table of Contents](usage/table-of-contents.md)
|
||||||
|
* [Page Numbers](usage/page-numbers.md)
|
||||||
* Styling
|
* Styling
|
||||||
* [Styling with JS](usage/styling-with-js.md)
|
* [Styling with JS](usage/styling-with-js.md)
|
||||||
* [Styling with XML](usage/styling-with-xml.md)
|
* [Styling with XML](usage/styling-with-xml.md)
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
## Always think about the user
|
## Always think about the user
|
||||||
|
|
||||||
The number one pillar for contribution is to **ALWAYS** think about how the user will use the library.
|
The number one pillar for contribution to `docx` is to **ALWAYS** think about how the user will use `docx`.
|
||||||
|
|
||||||
Put yourself in their position, and imagine how they would feel about your feature you wrote.
|
Put yourself in their position, and imagine how they would feel about your feature you wrote.
|
||||||
|
|
||||||
@ -37,13 +37,13 @@ Unesesary coment removed // Make sure to use correct spelling
|
|||||||
|
|
||||||
## No leaky components in API interface
|
## No leaky components in API interface
|
||||||
|
|
||||||
This mainly applies to the API the end user will consume.
|
> This mainly applies to the API the end user will consume.
|
||||||
|
|
||||||
Try to make method parameters accept primatives, or `json` objects, so that child components are created **inside** the component, rather than being **injected** in.
|
Try to make method parameters of the outside API accept primatives, or `json` objects, so that child components are created **inside** the component, rather than being **injected** in.
|
||||||
|
|
||||||
This is so that:
|
This is so that:
|
||||||
|
|
||||||
1. Imports are much cleaner, no need for:
|
1. Imports are much cleaner for the end user, no need for:
|
||||||
```js
|
```js
|
||||||
import { ChildComponent } from "./my-feature/sub-component/deeper/.../my-deep.component";
|
import { ChildComponent } from "./my-feature/sub-component/deeper/.../my-deep.component";
|
||||||
```
|
```
|
||||||
@ -52,17 +52,29 @@ This is so that:
|
|||||||
3. It means the end user does not need to import and create the child component to be injected.
|
3. It means the end user does not need to import and create the child component to be injected.
|
||||||
|
|
||||||
**Do not**
|
**Do not**
|
||||||
`TableFloatProperties` is a class. The outside world would have to construct the object, and inject it in
|
|
||||||
|
`TableFloatProperties` is a class. The outside world would have to `new` up the object, and inject it in like so:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
public float(tableFloatProperties: TableFloatProperties): Table
|
public float(tableFloatProperties: TableFloatProperties): Table
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
table.float(new TableFloatProperties(...));
|
||||||
|
```
|
||||||
|
|
||||||
**Do**
|
**Do**
|
||||||
`ITableFloatOptions` is an interface for a JSON of primatives.
|
|
||||||
|
`ITableFloatOptions` is an interface for a JSON of primatives. The end user would need to pass in a json object and not need to worry about the internals:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
public float(tableFloatOptions: ITableFloatOptions): Table
|
public float(tableFloatOptions: ITableFloatOptions): Table
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
table.float({...});
|
||||||
|
```
|
||||||
|
|
||||||
## Add vs Create
|
## Add vs Create
|
||||||
|
|
||||||
This is just a guideline, and the rules can sometimes be broken.
|
This is just a guideline, and the rules can sometimes be broken.
|
||||||
@ -76,7 +88,8 @@ This is just a guideline, and the rules can sometimes be broken.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
* Use `add` if you add the element into the method as a parameter:
|
* Use `add` if you add the element into the method as a parameter.
|
||||||
|
*Note:* This may look like its breaking the previous guideline, but it has semantically different meanings. The previous one is using data to construct an object, whereas this one is simply adding elements into the document:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
public addParagraph(paragraph: Paragraph) {
|
public addParagraph(paragraph: Paragraph) {
|
||||||
@ -108,6 +121,30 @@ private get _level: string;
|
|||||||
private get level: string;
|
private get level: string;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Temporal Methods
|
||||||
|
|
||||||
|
Some methods are `non-temporal`, which means regardless of when you call the method, it will have the same affect on the document. For example, setting the width of a table at the end of the document will have the same effect as setting the width at the start:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
table.setWidth(1000); // now removed as of version 5.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Whereas some methods are `temporal`, which means depending on the time-frame they are called, it would produce a difference result. For example, moving `createParagraph()` around your code will physically alter the document.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
doc.createParagraph("hello");
|
||||||
|
```
|
||||||
|
|
||||||
|
If a method is `non-temporal`, put it in the objects `constructor`. For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const table = new Table(width: number);
|
||||||
|
```
|
||||||
|
|
||||||
|
`Non-temporal` methods are usually methods which can only be used one time and one time only. For example, `.float()`. It does not make sense to call `.float()` again if its already floating.
|
||||||
|
|
||||||
|
I am not sure what the real term is, but this will do.
|
||||||
|
|
||||||
## Interfaces over type alias
|
## Interfaces over type alias
|
||||||
|
|
||||||
Do not use `type`, but rather use `Interfaces`. `type` cannot be extended, and a class cannot implement it.
|
Do not use `type`, but rather use `Interfaces`. `type` cannot be extended, and a class cannot implement it.
|
||||||
@ -154,7 +191,7 @@ enum WeaponType = {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Spell correctly, full and in American English
|
## Spell correctly, in full and in American English
|
||||||
|
|
||||||
I am not sure where these habits in software development come from, but I do not believe it is beneficial:
|
I am not sure where these habits in software development come from, but I do not believe it is beneficial:
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ This command will run the `demo selector app` in the `/demo` folder. It will pro
|
|||||||
|
|
||||||
A simple hello world of the `docx` library:
|
A simple hello world of the `docx` library:
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo1.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo1.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo1.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo1.ts_
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo1.ts_
|
|||||||
|
|
||||||
This example shows how to customise the look and feel of a document using JS configuration
|
This example shows how to customise the look and feel of a document using JS configuration
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo2.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo2.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo2.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo2.ts_
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo2.ts_
|
|||||||
|
|
||||||
This example shows how to customise the look and feel of a document using XML configuration
|
This example shows how to customise the look and feel of a document using XML configuration
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo13.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo13.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo13.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo13.ts_
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo13.ts_
|
|||||||
|
|
||||||
This example shows many levels of numbering
|
This example shows many levels of numbering
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo3.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo3.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo3.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo3.ts_
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo3.ts_
|
|||||||
|
|
||||||
Example of simple table
|
Example of simple table
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo4.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo4.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo4.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo4.ts_
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo4.ts_
|
|||||||
|
|
||||||
Styling the borders of a table
|
Styling the borders of a table
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo20.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo20.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo20.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo20.ts_
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo20.ts_
|
|||||||
|
|
||||||
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/demo5.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.ts_
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.ts_
|
|||||||
|
|
||||||
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/demo9.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.ts_
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.ts_
|
|||||||
|
|
||||||
Example showing how to scale images
|
Example showing how to scale images
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo12.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo12.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo12.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo12.ts_
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo12.ts_
|
|||||||
|
|
||||||
This is the best way to add an image to a document because you can add the same image in two locations without increasing document size by re-using the same image
|
This is the best way to add an image to a document because you can add the same image in two locations without increasing document size by re-using the same image
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo23.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo23.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo23.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo23.ts_
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo23.ts_
|
|||||||
|
|
||||||
As before, to add an image to a table, you would need to add it to the `Media` object first
|
As before, to add an image to a table, you would need to add it to the `Media` object first
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo24.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo24.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo24.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo24.ts_
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo24.ts_
|
|||||||
|
|
||||||
If you want to use a Base64 image instead
|
If you want to use a Base64 image instead
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo18.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo18.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo18.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo18.ts_
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo18.ts_
|
|||||||
|
|
||||||
Example showing how to set custom margains
|
Example showing how to set custom margains
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo6.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo6.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo6.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo6.ts_
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo6.ts_
|
|||||||
|
|
||||||
Example showing how to set the document to `landscape` or `portrait`
|
Example showing how to set the document to `landscape` or `portrait`
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo7.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo7.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo7.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo7.ts_
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo7.ts_
|
|||||||
|
|
||||||
Example showing how to add headers and footers
|
Example showing how to add headers and footers
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo8.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo8.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo8.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo8.ts_
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ Check out `Sections` for this feature
|
|||||||
|
|
||||||
Example showing how to page break
|
Example showing how to page break
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo14.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo14.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo14.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo14.ts_
|
||||||
|
|
||||||
@ -152,15 +152,16 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo14.ts_
|
|||||||
|
|
||||||
Example showing how to page break before like in Word
|
Example showing how to page break before like in Word
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo15.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo15.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo15.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo15.ts_
|
||||||
|
|
||||||
## Sections
|
## Sections
|
||||||
|
|
||||||
Example of how sections work. Sections allow multiple headers and footers, and `landscape`/`portrait` inside the same document
|
Example of how sections work. Sections allow multiple headers and footers, and `landscape`/`portrait` inside the same document.
|
||||||
|
Also you can have different page number formats and starts for different sections.
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo16.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo16.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo16.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo16.ts_
|
||||||
|
|
||||||
@ -168,7 +169,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo16.ts_
|
|||||||
|
|
||||||
Example of how to add footnotes. Good for references
|
Example of how to add footnotes. Good for references
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo17.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo17.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo17.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo17.ts_
|
||||||
|
|
||||||
@ -178,7 +179,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo17.ts_
|
|||||||
|
|
||||||
Example showing how to use the Buffer packer and then write that buffer to the file system
|
Example showing how to use the Buffer packer and then write that buffer to the file system
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo19.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo19.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo19.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo19.ts_
|
||||||
|
|
||||||
@ -187,7 +188,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo19.ts_
|
|||||||
|
|
||||||
Example showing how to make bookmarks to make internal hyperlinks within the document
|
Example showing how to make bookmarks to make internal hyperlinks within the document
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo21.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo21.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo21.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo21.ts_
|
||||||
|
|
||||||
@ -195,7 +196,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo21.ts_
|
|||||||
|
|
||||||
Example showing how to use bidirectional text for certain languages such as Hebrew
|
Example showing how to use bidirectional text for certain languages such as Hebrew
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo22.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo22.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo22.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo22.ts_
|
||||||
|
|
||||||
@ -205,7 +206,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo22.ts_
|
|||||||
|
|
||||||
Example showing how to add headers and footers
|
Example showing how to add headers and footers
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo10.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo10.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo10.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo10.ts_
|
||||||
|
|
||||||
@ -213,6 +214,6 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo10.ts_
|
|||||||
|
|
||||||
This example shows how to customise the look and feel of a document and add images
|
This example shows how to customise the look and feel of a document and add images
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo11.ts ":include")
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo11.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo11.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo11.ts_
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
|
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
|
||||||
<script src="https://unpkg.com/docsify-copy-code@2"></script>
|
<script src="https://unpkg.com/docsify-copy-code@2"></script>
|
||||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||||
|
<script src="//unpkg.com/prismjs/components/prism-typescript.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
To create a new document, it is very easy:
|
To create a new document, it is very easy:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var doc = new docx.Document();
|
const doc = new docx.Document();
|
||||||
```
|
```
|
||||||
|
|
||||||
## Document properties
|
## Document properties
|
||||||
@ -13,7 +13,7 @@ var doc = new docx.Document();
|
|||||||
You can add properties to the Word document by specifying options, for example:
|
You can add properties to the Word document by specifying options, for example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var doc = new docx.Document({
|
const doc = new docx.Document({
|
||||||
creator: "Dolan Miu",
|
creator: "Dolan Miu",
|
||||||
description: "My extremely interesting document",
|
description: "My extremely interesting document",
|
||||||
title: "My Document",
|
title: "My Document",
|
||||||
@ -22,14 +22,18 @@ var doc = new docx.Document({
|
|||||||
|
|
||||||
### Full list of options:
|
### Full list of options:
|
||||||
|
|
||||||
```
|
|
||||||
creator
|
* creator
|
||||||
description
|
* description
|
||||||
title
|
* title
|
||||||
subject
|
* subject
|
||||||
keywords
|
* keywords
|
||||||
lastModifiedBy
|
* lastModifiedBy
|
||||||
revision
|
* revision
|
||||||
```
|
|
||||||
|
|
||||||
You can mix and match whatever properties you want, or provide no properties.
|
You can mix and match whatever properties you want, or provide no properties.
|
||||||
|
|
||||||
|
### units for positioning
|
||||||
|
|
||||||
|
Various parts of the API require positioning arguments. The units are "20ths of a point" from the [OOXML](http://officeopenxml.com/index.php) specification.
|
||||||
|
See [Lars Corneliussen's blog post](https://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/) for more information and how to convert units.
|
@ -37,8 +37,12 @@ Also all the supported section properties are implemented according to: http://o
|
|||||||
|
|
||||||
// Add new section with another header and footer
|
// Add new section with another header and footer
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
headerId: header.Header.ReferenceId,
|
headers: {
|
||||||
footerId: footer.Footer.ReferenceId,
|
default: header
|
||||||
|
},
|
||||||
|
footers: {
|
||||||
|
default: footer
|
||||||
|
},
|
||||||
pageNumberStart: 1,
|
pageNumberStart: 1,
|
||||||
pageNumberFormatType: docx.PageNumberFormat.DECIMAL,
|
pageNumberFormatType: docx.PageNumberFormat.DECIMAL,
|
||||||
});
|
});
|
||||||
|
@ -210,7 +210,7 @@ doc.createImage(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/demo5.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.ts_
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.ts_
|
|||||||
|
|
||||||
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/demo9.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.ts_
|
||||||
|
|
||||||
@ -226,6 +226,6 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.ts_
|
|||||||
|
|
||||||
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/demo38.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo38.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo38.ts_
|
||||||
|
@ -26,7 +26,7 @@ _levels_ which form a sequence starting at 0 indicating the top-level
|
|||||||
list look and increasing from there to descibe the sublists, then
|
list look and increasing from there to descibe the sublists, then
|
||||||
sub-sublists, etc. Each level includes the following properties:
|
sub-sublists, etc. Each level includes the following properties:
|
||||||
|
|
||||||
* **level**: This its 0-based index in the defintion stack
|
* **level**: This is its 0-based index in the definition stack
|
||||||
* **numberFormat**: This indicates how the bullet or number should be
|
* **numberFormat**: This indicates how the bullet or number should be
|
||||||
generated. Options include `bullet` (meaning don't count), `decimal`
|
generated. Options include `bullet` (meaning don't count), `decimal`
|
||||||
(arabic numerals), `upperRoman`, `lowerRoman`, `hex`, and many
|
(arabic numerals), `upperRoman`, `lowerRoman`, `hex`, and many
|
||||||
@ -64,8 +64,8 @@ styles or numbering of any kind, you'll have to use the
|
|||||||
`docx.Numbering` class.
|
`docx.Numbering` class.
|
||||||
|
|
||||||
First you need to create a new numbering container class and use it to
|
First you need to create a new numbering container class and use it to
|
||||||
create your abstract numbering style, define your levels, and creat
|
create your abstract numbering style, define your levels, and create
|
||||||
your concreate numbering style:
|
your concrete numbering style:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const numbering = new docx.Numbering();
|
const numbering = new docx.Numbering();
|
||||||
@ -78,8 +78,8 @@ abstractNum.createLevel(2, "lowerLetter", "%3)", "start").addParagraphProperty(n
|
|||||||
const concrete = numbering.createConcreteNumbering(abstractNum);
|
const concrete = numbering.createConcreteNumbering(abstractNum);
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then apply your concrete style to paragraphs using their
|
You can then apply your concrete style to paragraphs using the
|
||||||
`#setNumbering` method:
|
`setNumbering` method:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
topLevelP.setNumbering(concrete, 0);
|
topLevelP.setNumbering(concrete, 0);
|
||||||
|
66
docs/usage/page-numbers.md
Normal file
66
docs/usage/page-numbers.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Page Numbers
|
||||||
|
|
||||||
|
> This feature allows you to set page numbers on each page
|
||||||
|
|
||||||
|
?> **Note:** This feature only works on Headers and Footers
|
||||||
|
|
||||||
|
```ts
|
||||||
|
doc.Header.createParagraph().addRun(new TextRun("Page Number: ").pageNumber()).addRun(new TextRun("to ").numberOfTotalPages());
|
||||||
|
```
|
||||||
|
|
||||||
|
## Current page number
|
||||||
|
|
||||||
|
To get the current page number, call the `.pageNumber()` method on a `TextRun`. Then add the newly created `TextRun` into a paragraph
|
||||||
|
|
||||||
|
```ts
|
||||||
|
pageNumber();
|
||||||
|
```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const currentPageRun = new TextRun("Current Page Number: ").pageNumber();
|
||||||
|
paragraph.addRun(currentPageRun);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Total number of pages
|
||||||
|
|
||||||
|
```ts
|
||||||
|
numberOfTotalPages();
|
||||||
|
```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const lastPage = new TextRun("Total Page Number: ").numberOfTotalPages();
|
||||||
|
paragraph.addRun(lastPage);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Both
|
||||||
|
|
||||||
|
You can combine the two to get "Page 2 of 10" effect:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const currentPageRun = new TextRun("Page ").pageNumber();
|
||||||
|
const lastPage = new TextRun("of ").numberOfTotalPages();
|
||||||
|
|
||||||
|
paragraph.addRun(currentPageRun);
|
||||||
|
paragraph.addRun(lastPage);
|
||||||
|
```
|
||||||
|
|
||||||
|
Or:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
doc.Header.createParagraph().addRun(new TextRun("Page ").pageNumber()).addRun(new TextRun("of ").numberOfTotalPages());
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Simple Example
|
||||||
|
|
||||||
|
Adding page numbers to Header and Footer
|
||||||
|
|
||||||
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo39.ts ':include')
|
||||||
|
|
||||||
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo39.ts_
|
@ -14,7 +14,7 @@ const name = new TextRun("Name:")
|
|||||||
## Available methods
|
## Available methods
|
||||||
|
|
||||||
* For run formatting:
|
* For run formatting:
|
||||||
* `.bold()`, `.italic()`, `.smallCaps()`, `.allCaps()`, `.strike()`, `.doubleStrike()`, `.subScript()`, `.superScript()`: Set the formatting property to true
|
* `.bold()`, `.italics()`, `.smallCaps()`, `.allCaps()`, `.strike()`, `.doubleStrike()`, `.subScript()`, `.superScript()`: Set the formatting property to true
|
||||||
* `.underline(style="single", color=null)`: Set the underline style and color
|
* `.underline(style="single", color=null)`: Set the underline style and color
|
||||||
* `.color(color)`: Set the text color, using 6 hex characters for RRGGBB (no leading `#`)
|
* `.color(color)`: Set the text color, using 6 hex characters for RRGGBB (no leading `#`)
|
||||||
* `.size(halfPts)`: Set the font size, measured in half-points
|
* `.size(halfPts)`: Set the font size, measured in half-points
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
> Tab stops are useful, if you are unclear of what they are, [here is a link explaining](https://en.wikipedia.org/wiki/Tab_stop). It enables side by side text which is nicely laid out without the need for tables, or constantly pressing space bar.
|
> Tab stops are useful, if you are unclear of what they are, [here is a link explaining](https://en.wikipedia.org/wiki/Tab_stop). It enables side by side text which is nicely laid out without the need for tables, or constantly pressing space bar.
|
||||||
|
|
||||||
**Note**: At the moment, the unit of measurement for a tab stop is counter intuitive for a human. It is using OpenXMLs own measuring system. For example, 2268 roughly translates to 3cm. Therefore in the future, I may consider changing it to percentages or even cm.
|
!> **Note**: At the moment, the unit of measurement for a tab stop is counter intuitive for a human. It is using OpenXMLs own measuring system. For example, 2268 roughly translates to 3cm. Therefore in the future, I may consider changing it to percentages or even cm.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -71,6 +71,6 @@ doc.addParagraph(new Paragraph("My Spectacular Style #1").style("MySpectacularSt
|
|||||||
|
|
||||||
### 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/demo28.ts ':include')
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo28.ts_
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo28.ts_
|
||||||
|
255
docs/usage/tables.md
Normal file
255
docs/usage/tables.md
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
# Tables
|
||||||
|
|
||||||
|
You can create tables with `docx`. More information can be found [here](http://officeopenxml.com/WPtable.php).
|
||||||
|
|
||||||
|
## Create Table
|
||||||
|
|
||||||
|
To create a table, simply use the `createTable()` method on a `document`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const table = doc.createTable([NUMBER OF ROWS], [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.addTable(table);
|
||||||
|
```
|
||||||
|
|
||||||
|
The snippet below creates a table of 2 rows and 4 columns.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const table = doc.createTable(2, 4);
|
||||||
|
|
||||||
|
// Or
|
||||||
|
|
||||||
|
const table = new Table(2, 4);
|
||||||
|
doc.addTable(table);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rows and Columns
|
||||||
|
|
||||||
|
You can get a row or a column from a table like so, where `index` is a number:
|
||||||
|
|
||||||
|
### Get Row
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const row = doc.getRow(index);
|
||||||
|
```
|
||||||
|
|
||||||
|
With this, you can merge a row by using the `mergeCells()` method, where `startIndex` is the row number you want to merge from, and `endIndex` is where you want it to merge to:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
row.mergeCells(startIndex, endIndex);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can get a cell from a `row` by using the `getCell()` method, where `index` is the row index:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
row.getCell(index);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Column
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const column = doc.getColumn(index);
|
||||||
|
```
|
||||||
|
|
||||||
|
Again, you can merge a row by using the `mergeCells()` method, where `startIndex` is the row number you want to merge from, and `endIndex` is where you want it to merge to:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
column.mergeCells(startIndex, endIndex);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can get a cell from a `column` by using the `getCell()` method, where `index` is the column index:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
column.getCell(index);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cells
|
||||||
|
|
||||||
|
The `createTable()` method created a table with cells. To access the cell, use the `getCell()` method.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const cell = table.getCell([ROW INDEX], [COLUMN INDEX]);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also get a cell from a `column` or a `row` with `getCell()`, mentioned previously.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const cell = table.getCell(0, 2);
|
||||||
|
|
||||||
|
const cell = row.getCell(0);
|
||||||
|
|
||||||
|
const cell = column.getCell(2);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add paragraph to a cell
|
||||||
|
|
||||||
|
Once you have got the cell, you can add data to it with the `addParagraph()` method.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
cell.addParagraph(new Paragraph("Hello"));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Borders
|
||||||
|
|
||||||
|
BorderStyle can be imported from `docx`. Size determines the thickness. HTML color can be a hex code or alias such as `red`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
cell.Borders.addTopBorder([BorderStyle], [SIZE], [HTML COLOR]);
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
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.addStartBorder(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
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { VerticalAlign } from "docx";
|
||||||
|
|
||||||
|
cell.setVerticalAlign([VerticalAlign TYPE]);
|
||||||
|
```
|
||||||
|
|
||||||
|
For example, to center align a cell:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
cell.setVerticalAlign(VerticalAlign.CENTER);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rows
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
table.getRow([ROW INDEX]);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
This will merge 3 cells together starting from index `0`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
table.getRow(0).mergeCells(0, 2);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Merging on a column
|
||||||
|
|
||||||
|
It has not been implemented yet, but it will follow a similar structure as merging a row.
|
||||||
|
|
||||||
|
## Nested Tables
|
||||||
|
|
||||||
|
To have a table within a table
|
||||||
|
|
||||||
|
```ts
|
||||||
|
cell.addTable(new Table(1, 1));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo4.ts ':include')
|
||||||
|
|
||||||
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo4.ts_
|
||||||
|
|
||||||
|
### Custom borders
|
||||||
|
|
||||||
|
Example showing how to add colourful borders to tables
|
||||||
|
|
||||||
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo20.ts ':include')
|
||||||
|
|
||||||
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo20.ts_
|
||||||
|
|
||||||
|
### Adding images
|
||||||
|
|
||||||
|
Example showing how to add images to tables
|
||||||
|
|
||||||
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo24.ts ':include')
|
||||||
|
|
||||||
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo24.ts_
|
||||||
|
|
||||||
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo36.ts ':include')
|
||||||
|
|
||||||
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo36.ts_
|
||||||
|
|
||||||
|
### Alignment of text in a cell
|
||||||
|
|
||||||
|
Example showing how align text in a table cell
|
||||||
|
|
||||||
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo31.ts ':include')
|
||||||
|
|
||||||
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo31.ts_
|
||||||
|
|
||||||
|
### Merging rows
|
||||||
|
|
||||||
|
Example showing merging of `rows`
|
||||||
|
|
||||||
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo32.ts ':include')
|
||||||
|
|
||||||
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo32.ts_
|
||||||
|
|
||||||
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo41.ts ':include')
|
||||||
|
|
||||||
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo41.ts_
|
||||||
|
|
||||||
|
### Merging columns
|
||||||
|
|
||||||
|
Example showing merging of `columns`
|
||||||
|
|
||||||
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo43.ts ':include')
|
||||||
|
|
||||||
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo43.ts_
|
||||||
|
|
||||||
|
### Floating tables
|
||||||
|
|
||||||
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo34.ts ':include')
|
||||||
|
|
||||||
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo34.ts_
|
||||||
|
|
@ -22,7 +22,7 @@ text.bold();
|
|||||||
### Italics
|
### Italics
|
||||||
|
|
||||||
```js
|
```js
|
||||||
text.italic();
|
text.italics();
|
||||||
```
|
```
|
||||||
|
|
||||||
### Underline
|
### Underline
|
||||||
@ -80,5 +80,5 @@ text.break();
|
|||||||
What if you want to create a paragraph which is **_bold_** and **_italic_**?
|
What if you want to create a paragraph which is **_bold_** and **_italic_**?
|
||||||
|
|
||||||
```js
|
```js
|
||||||
paragraph.bold().italic();
|
paragraph.bold().italics();
|
||||||
```
|
```
|
||||||
|
15
package.json
15
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "docx",
|
"name": "docx",
|
||||||
"version": "4.6.0",
|
"version": "5.0.0-rc1",
|
||||||
"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": {
|
||||||
@ -8,7 +8,7 @@
|
|||||||
"test": "mocha-webpack \"src/**/*.ts\"",
|
"test": "mocha-webpack \"src/**/*.ts\"",
|
||||||
"test.coverage": "nyc npm test",
|
"test.coverage": "nyc npm test",
|
||||||
"test.watch": "npm test -- --watch",
|
"test.watch": "npm test -- --watch",
|
||||||
"prepublishOnly": "npm run build",
|
"prepublishOnly": "npm run build --production",
|
||||||
"lint": "tslint --project .",
|
"lint": "tslint --project .",
|
||||||
"build": "npm run webpack && npm run fix-types",
|
"build": "npm run webpack && npm run fix-types",
|
||||||
"tsc": "rimraf ./build && tsc -p .",
|
"tsc": "rimraf ./build && tsc -p .",
|
||||||
@ -17,7 +17,8 @@
|
|||||||
"typedoc": "typedoc src/index.ts",
|
"typedoc": "typedoc src/index.ts",
|
||||||
"style": "prettier -l \"src/**/*.ts\"",
|
"style": "prettier -l \"src/**/*.ts\"",
|
||||||
"style.fix": "npm run style -- --write",
|
"style.fix": "npm run style -- --write",
|
||||||
"fix-types": "node types-absolute-fixer.js",
|
"fix-types": "ts-node scripts/types-absolute-fixer.ts",
|
||||||
|
"e2e": "ts-node scripts/e2e.ts",
|
||||||
"ts-node": "ts-node"
|
"ts-node": "ts-node"
|
||||||
},
|
},
|
||||||
"pre-commit": [
|
"pre-commit": [
|
||||||
@ -47,9 +48,7 @@
|
|||||||
],
|
],
|
||||||
"types": "./build/index.d.ts",
|
"types": "./build/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/image-size": "0.0.29",
|
|
||||||
"@types/jszip": "^3.1.4",
|
"@types/jszip": "^3.1.4",
|
||||||
"image-size": "^0.6.2",
|
|
||||||
"jszip": "^3.1.5",
|
"jszip": "^3.1.5",
|
||||||
"xml": "^1.0.1",
|
"xml": "^1.0.1",
|
||||||
"xml-js": "^1.6.8"
|
"xml-js": "^1.6.8"
|
||||||
@ -63,7 +62,9 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^3.4.35",
|
"@types/chai": "^3.4.35",
|
||||||
"@types/mocha": "^2.2.39",
|
"@types/mocha": "^2.2.39",
|
||||||
|
"@types/request-promise": "^4.1.42",
|
||||||
"@types/sinon": "^4.3.1",
|
"@types/sinon": "^4.3.1",
|
||||||
|
"@types/webpack": "^4.4.24",
|
||||||
"awesome-typescript-loader": "^3.4.1",
|
"awesome-typescript-loader": "^3.4.1",
|
||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
"glob": "^7.1.2",
|
"glob": "^7.1.2",
|
||||||
@ -73,9 +74,11 @@
|
|||||||
"mocha-webpack": "^1.0.1",
|
"mocha-webpack": "^1.0.1",
|
||||||
"nyc": "^13.1.0",
|
"nyc": "^13.1.0",
|
||||||
"pre-commit": "^1.2.2",
|
"pre-commit": "^1.2.2",
|
||||||
"prettier": "^1.12.1",
|
"prettier": "^1.15.2",
|
||||||
"prompt": "^1.0.0",
|
"prompt": "^1.0.0",
|
||||||
"replace-in-file": "^3.1.0",
|
"replace-in-file": "^3.1.0",
|
||||||
|
"request": "^2.88.0",
|
||||||
|
"request-promise": "^4.2.2",
|
||||||
"rimraf": "^2.5.2",
|
"rimraf": "^2.5.2",
|
||||||
"shelljs": "^0.7.7",
|
"shelljs": "^0.7.7",
|
||||||
"sinon": "^5.0.7",
|
"sinon": "^5.0.7",
|
||||||
|
30
scripts/e2e.ts
Normal file
30
scripts/e2e.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// tslint:disable:no-console
|
||||||
|
import * as fs from "fs";
|
||||||
|
import * as request from "request-promise";
|
||||||
|
|
||||||
|
async function e2e(filePath: string): Promise<void> {
|
||||||
|
console.log(`Running e2e for: ${filePath}`);
|
||||||
|
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
console.error("File not found");
|
||||||
|
throw Error("File not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await request.post({
|
||||||
|
url: "https://wt-9017166451e5dc00461b648d19f5e8da-0.sandbox.auth0-extend.com/docx-validator",
|
||||||
|
formData: {
|
||||||
|
document: fs.createReadStream(filePath),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
e2e(process.argv[2])
|
||||||
|
.then(() => {
|
||||||
|
console.log("Success! Document is valid");
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.log("Error! Validation failed");
|
||||||
|
process.exit(1);
|
||||||
|
});
|
@ -1,5 +1,5 @@
|
|||||||
const glob = require("glob");
|
import * as glob from "glob";
|
||||||
const replace = require("replace-in-file");
|
import * as replace from "replace-in-file";
|
||||||
|
|
||||||
const files = glob.sync("build/**/*.d.ts");
|
const files = glob.sync("build/**/*.d.ts");
|
||||||
|
|
17
src/export/packer/image-replacer.ts
Normal file
17
src/export/packer/image-replacer.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { IMediaData, Media } from "file/media";
|
||||||
|
|
||||||
|
export class ImageReplacer {
|
||||||
|
public replace(xmlData: string, mediaData: IMediaData[], offset: number): string {
|
||||||
|
let currentXmlData = xmlData;
|
||||||
|
|
||||||
|
mediaData.forEach((image, i) => {
|
||||||
|
currentXmlData = currentXmlData.replace(`{${image.fileName}}`, (offset + i).toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
return currentXmlData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMediaData(xmlData: string, media: Media): IMediaData[] {
|
||||||
|
return media.Array.filter((image) => xmlData.search(`{${image.fileName}}`) > 0);
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,7 @@ describe("Compiler", () => {
|
|||||||
describe("#compile()", () => {
|
describe("#compile()", () => {
|
||||||
it("should pack all the content", async function() {
|
it("should pack all the content", async function() {
|
||||||
this.timeout(99999999);
|
this.timeout(99999999);
|
||||||
const zipFile = await compiler.compile(file);
|
const zipFile = compiler.compile(file);
|
||||||
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
||||||
|
|
||||||
expect(fileNames).is.an.instanceof(Array);
|
expect(fileNames).is.an.instanceof(Array);
|
||||||
@ -46,7 +46,7 @@ describe("Compiler", () => {
|
|||||||
|
|
||||||
this.timeout(99999999);
|
this.timeout(99999999);
|
||||||
|
|
||||||
const zipFile = await compiler.compile(file);
|
const zipFile = compiler.compile(file);
|
||||||
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
||||||
|
|
||||||
expect(fileNames).is.an.instanceof(Array);
|
expect(fileNames).is.an.instanceof(Array);
|
||||||
|
@ -3,6 +3,7 @@ import * as xml from "xml";
|
|||||||
|
|
||||||
import { File } from "file";
|
import { File } from "file";
|
||||||
import { Formatter } from "../formatter";
|
import { Formatter } from "../formatter";
|
||||||
|
import { ImageReplacer } from "./image-replacer";
|
||||||
|
|
||||||
interface IXmlifyedFile {
|
interface IXmlifyedFile {
|
||||||
readonly data: string;
|
readonly data: string;
|
||||||
@ -28,14 +29,15 @@ interface IXmlifyedFileMapping {
|
|||||||
|
|
||||||
export class Compiler {
|
export class Compiler {
|
||||||
private readonly formatter: Formatter;
|
private readonly formatter: Formatter;
|
||||||
|
private readonly imageReplacer: ImageReplacer;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.formatter = new Formatter();
|
this.formatter = new Formatter();
|
||||||
|
this.imageReplacer = new ImageReplacer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async compile(file: File): Promise<JSZip> {
|
public compile(file: File): JSZip {
|
||||||
const zip = new JSZip();
|
const zip = new JSZip();
|
||||||
|
|
||||||
const xmlifiedFileMapping = this.xmlifyFile(file);
|
const xmlifiedFileMapping = this.xmlifyFile(file);
|
||||||
|
|
||||||
for (const key in xmlifiedFileMapping) {
|
for (const key in xmlifiedFileMapping) {
|
||||||
@ -59,26 +61,39 @@ export class Compiler {
|
|||||||
zip.file(`word/media/${data.fileName}`, mediaData);
|
zip.file(`word/media/${data.fileName}`, mediaData);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const header of file.Headers) {
|
|
||||||
for (const data of header.Media.Array) {
|
|
||||||
zip.file(`word/media/${data.fileName}`, data.stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const footer of file.Footers) {
|
|
||||||
for (const data of footer.Media.Array) {
|
|
||||||
zip.file(`word/media/${data.fileName}`, data.stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return zip;
|
return zip;
|
||||||
}
|
}
|
||||||
|
|
||||||
private xmlifyFile(file: File): IXmlifyedFileMapping {
|
private xmlifyFile(file: File): IXmlifyedFileMapping {
|
||||||
file.verifyUpdateFields();
|
file.verifyUpdateFields();
|
||||||
|
const documentRelationshipCount = file.DocumentRelationships.RelationshipCount + 1;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
Relationships: {
|
||||||
|
data: (() => {
|
||||||
|
const xmlData = xml(this.formatter.format(file.Document));
|
||||||
|
const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media);
|
||||||
|
|
||||||
|
mediaDatas.forEach((mediaData, i) => {
|
||||||
|
file.DocumentRelationships.createRelationship(
|
||||||
|
documentRelationshipCount + i,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||||
|
`media/${mediaData.fileName}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return xml(this.formatter.format(file.DocumentRelationships));
|
||||||
|
})(),
|
||||||
|
path: "word/_rels/document.xml.rels",
|
||||||
|
},
|
||||||
Document: {
|
Document: {
|
||||||
data: xml(this.formatter.format(file.Document), true),
|
data: (() => {
|
||||||
|
const tempXmlData = xml(this.formatter.format(file.Document), true);
|
||||||
|
const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media);
|
||||||
|
const xmlData = this.imageReplacer.replace(tempXmlData, mediaDatas, documentRelationshipCount);
|
||||||
|
|
||||||
|
return xmlData;
|
||||||
|
})(),
|
||||||
path: "word/document.xml",
|
path: "word/document.xml",
|
||||||
},
|
},
|
||||||
Styles: {
|
Styles: {
|
||||||
@ -98,30 +113,66 @@ export class Compiler {
|
|||||||
data: xml(this.formatter.format(file.Numbering)),
|
data: xml(this.formatter.format(file.Numbering)),
|
||||||
path: "word/numbering.xml",
|
path: "word/numbering.xml",
|
||||||
},
|
},
|
||||||
Relationships: {
|
|
||||||
data: xml(this.formatter.format(file.DocumentRelationships)),
|
|
||||||
path: "word/_rels/document.xml.rels",
|
|
||||||
},
|
|
||||||
FileRelationships: {
|
FileRelationships: {
|
||||||
data: xml(this.formatter.format(file.FileRelationships)),
|
data: xml(this.formatter.format(file.FileRelationships)),
|
||||||
path: "_rels/.rels",
|
path: "_rels/.rels",
|
||||||
},
|
},
|
||||||
Headers: file.Headers.map((headerWrapper, index) => ({
|
HeaderRelationships: file.Headers.map((headerWrapper, index) => {
|
||||||
data: xml(this.formatter.format(headerWrapper.Header)),
|
const xmlData = xml(this.formatter.format(headerWrapper.Header));
|
||||||
path: `word/header${index + 1}.xml`,
|
const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media);
|
||||||
})),
|
|
||||||
Footers: file.Footers.map((footerWrapper, index) => ({
|
mediaDatas.forEach((mediaData, i) => {
|
||||||
data: xml(this.formatter.format(footerWrapper.Footer)),
|
headerWrapper.Relationships.createRelationship(
|
||||||
path: `word/footer${index + 1}.xml`,
|
i,
|
||||||
})),
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||||
HeaderRelationships: file.Headers.map((headerWrapper, index) => ({
|
`media/${mediaData.fileName}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
data: xml(this.formatter.format(headerWrapper.Relationships)),
|
data: xml(this.formatter.format(headerWrapper.Relationships)),
|
||||||
path: `word/_rels/header${index + 1}.xml.rels`,
|
path: `word/_rels/header${index + 1}.xml.rels`,
|
||||||
})),
|
};
|
||||||
FooterRelationships: file.Footers.map((footerWrapper, index) => ({
|
}),
|
||||||
|
FooterRelationships: file.Footers.map((footerWrapper, index) => {
|
||||||
|
const xmlData = xml(this.formatter.format(footerWrapper.Footer));
|
||||||
|
const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media);
|
||||||
|
|
||||||
|
mediaDatas.forEach((mediaData, i) => {
|
||||||
|
footerWrapper.Relationships.createRelationship(
|
||||||
|
i,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||||
|
`media/${mediaData.fileName}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
data: xml(this.formatter.format(footerWrapper.Relationships)),
|
data: xml(this.formatter.format(footerWrapper.Relationships)),
|
||||||
path: `word/_rels/footer${index + 1}.xml.rels`,
|
path: `word/_rels/footer${index + 1}.xml.rels`,
|
||||||
})),
|
};
|
||||||
|
}),
|
||||||
|
Headers: file.Headers.map((headerWrapper, index) => {
|
||||||
|
const tempXmlData = xml(this.formatter.format(headerWrapper.Header));
|
||||||
|
const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media);
|
||||||
|
// TODO: 0 needs to be changed when headers get relationships of their own
|
||||||
|
const xmlData = this.imageReplacer.replace(tempXmlData, mediaDatas, 0);
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: xmlData,
|
||||||
|
path: `word/header${index + 1}.xml`,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
Footers: file.Footers.map((footerWrapper, index) => {
|
||||||
|
const tempXmlData = xml(this.formatter.format(footerWrapper.Footer));
|
||||||
|
const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media);
|
||||||
|
// TODO: 0 needs to be changed when headers get relationships of their own
|
||||||
|
const xmlData = this.imageReplacer.replace(tempXmlData, mediaDatas, 0);
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: xmlData,
|
||||||
|
path: `word/footer${index + 1}.xml`,
|
||||||
|
};
|
||||||
|
}),
|
||||||
ContentTypes: {
|
ContentTypes: {
|
||||||
data: xml(this.formatter.format(file.ContentTypes)),
|
data: xml(this.formatter.format(file.ContentTypes)),
|
||||||
path: "[Content_Types].xml",
|
path: "[Content_Types].xml",
|
||||||
|
@ -46,4 +46,24 @@ describe("Packer", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#toBase64String()", () => {
|
||||||
|
it("should create a standard docx file", async function() {
|
||||||
|
this.timeout(99999999);
|
||||||
|
const str = await packer.toBase64String(file);
|
||||||
|
|
||||||
|
assert.isDefined(str);
|
||||||
|
assert.isTrue(str.length > 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle exception if it throws any", () => {
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
const compiler = stub((packer as any).compiler, "compile");
|
||||||
|
|
||||||
|
compiler.throwsException();
|
||||||
|
return packer.toBase64String(file).catch((error) => {
|
||||||
|
assert.isDefined(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,7 @@ export class Packer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async toBuffer(file: File): Promise<Buffer> {
|
public async toBuffer(file: File): Promise<Buffer> {
|
||||||
const zip = await this.compiler.compile(file);
|
const zip = this.compiler.compile(file);
|
||||||
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",
|
||||||
@ -19,7 +19,7 @@ export class Packer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async toBase64String(file: File): Promise<string> {
|
public async toBase64String(file: File): Promise<string> {
|
||||||
const zip = await this.compiler.compile(file);
|
const zip = this.compiler.compile(file);
|
||||||
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",
|
||||||
@ -29,7 +29,7 @@ export class Packer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async toBlob(file: File): Promise<Blob> {
|
public async toBlob(file: File): Promise<Blob> {
|
||||||
const zip = await this.compiler.compile(file);
|
const zip = this.compiler.compile(file);
|
||||||
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",
|
||||||
|
@ -79,6 +79,26 @@ describe("ContentTypes", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
expect(tree["Types"][13]).to.deep.equal({
|
||||||
|
Override: [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml",
|
||||||
|
PartName: "/word/footnotes.xml",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(tree["Types"][14]).to.deep.equal({
|
||||||
|
Override: [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml",
|
||||||
|
PartName: "/word/settings.xml",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -88,7 +108,7 @@ describe("ContentTypes", () => {
|
|||||||
contentTypes.addFooter(102);
|
contentTypes.addFooter(102);
|
||||||
const tree = new Formatter().format(contentTypes);
|
const tree = new Formatter().format(contentTypes);
|
||||||
|
|
||||||
expect(tree["Types"][14]).to.deep.equal({
|
expect(tree["Types"][15]).to.deep.equal({
|
||||||
Override: [
|
Override: [
|
||||||
{
|
{
|
||||||
_attr: {
|
_attr: {
|
||||||
@ -99,7 +119,7 @@ describe("ContentTypes", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree["Types"][15]).to.deep.equal({
|
expect(tree["Types"][16]).to.deep.equal({
|
||||||
Override: [
|
Override: [
|
||||||
{
|
{
|
||||||
_attr: {
|
_attr: {
|
||||||
@ -118,7 +138,7 @@ describe("ContentTypes", () => {
|
|||||||
contentTypes.addHeader(202);
|
contentTypes.addHeader(202);
|
||||||
const tree = new Formatter().format(contentTypes);
|
const tree = new Formatter().format(contentTypes);
|
||||||
|
|
||||||
expect(tree["Types"][14]).to.deep.equal({
|
expect(tree["Types"][15]).to.deep.equal({
|
||||||
Override: [
|
Override: [
|
||||||
{
|
{
|
||||||
_attr: {
|
_attr: {
|
||||||
@ -129,7 +149,7 @@ describe("ContentTypes", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree["Types"][15]).to.deep.equal({
|
expect(tree["Types"][16]).to.deep.equal({
|
||||||
Override: [
|
Override: [
|
||||||
{
|
{
|
||||||
_attr: {
|
_attr: {
|
||||||
|
@ -30,6 +30,7 @@ export class ContentTypes extends XmlComponent {
|
|||||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.extended-properties+xml", "/docProps/app.xml"));
|
this.root.push(new Override("application/vnd.openxmlformats-officedocument.extended-properties+xml", "/docProps/app.xml"));
|
||||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", "/word/numbering.xml"));
|
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", "/word/numbering.xml"));
|
||||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml", "/word/footnotes.xml"));
|
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml", "/word/footnotes.xml"));
|
||||||
|
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml", "/word/settings.xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public addFooter(index: number): void {
|
public addFooter(index: number): void {
|
||||||
|
@ -17,7 +17,7 @@ describe("Body", () => {
|
|||||||
expect(formatted)
|
expect(formatted)
|
||||||
.to.have.property("w:sectPr")
|
.to.have.property("w:sectPr")
|
||||||
.and.to.be.an.instanceof(Array);
|
.and.to.be.an.instanceof(Array);
|
||||||
expect(formatted["w:sectPr"]).to.have.length(5);
|
expect(formatted["w:sectPr"]).to.have.length(4);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -76,7 +76,6 @@ describe("Body", () => {
|
|||||||
},
|
},
|
||||||
{ "w:cols": [{ _attr: { "w:space": 708 } }] },
|
{ "w:cols": [{ _attr: { "w:space": 708 } }] },
|
||||||
{ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] },
|
{ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] },
|
||||||
{ "w:pgNumType": [{ _attr: { "w:fmt": "decimal" } }] },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -104,7 +103,6 @@ describe("Body", () => {
|
|||||||
},
|
},
|
||||||
{ "w:cols": [{ _attr: { "w:space": 708 } }] },
|
{ "w:cols": [{ _attr: { "w:space": 708 } }] },
|
||||||
{ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] },
|
{ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] },
|
||||||
{ "w:pgNumType": [{ _attr: { "w:fmt": "decimal" } }] },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -88,7 +88,6 @@ describe("SectionProperties", () => {
|
|||||||
});
|
});
|
||||||
expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": [{ _attr: { "w:space": 708 } }] });
|
expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": [{ _attr: { "w:space": 708 } }] });
|
||||||
expect(tree["w:sectPr"][3]).to.deep.equal({ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] });
|
expect(tree["w:sectPr"][3]).to.deep.equal({ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] });
|
||||||
expect(tree["w:sectPr"][4]).to.deep.equal({ "w:pgNumType": [{ _attr: { "w:fmt": "decimal" } }] });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create section properties with changed options", () => {
|
it("should create section properties with changed options", () => {
|
||||||
@ -183,5 +182,25 @@ describe("SectionProperties", () => {
|
|||||||
"w:pgBorders": [{ _attr: { "w:offsetFrom": "page" } }],
|
"w:pgBorders": [{ _attr: { "w:offsetFrom": "page" } }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should create section properties with page number type, but without start attribute", () => {
|
||||||
|
const properties = new SectionProperties({
|
||||||
|
pageNumberFormatType: PageNumberFormat.UPPER_ROMAN,
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(properties);
|
||||||
|
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||||
|
const pgNumType = tree["w:sectPr"].find((item) => item["w:pgNumType"] !== undefined);
|
||||||
|
expect(pgNumType).to.deep.equal({
|
||||||
|
"w:pgNumType": [{ _attr: { "w:fmt": "upperRoman" } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create section properties without page number type", () => {
|
||||||
|
const properties = new SectionProperties({});
|
||||||
|
const tree = new Formatter().format(properties);
|
||||||
|
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||||
|
const pgNumType = tree["w:sectPr"].find((item) => item["w:pgNumType"] !== undefined);
|
||||||
|
expect(pgNumType).to.equal(undefined);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -14,7 +14,7 @@ import { HeaderReference } from "./header-reference/header-reference";
|
|||||||
import { IPageBordersOptions, PageBorders } from "./page-border";
|
import { IPageBordersOptions, PageBorders } from "./page-border";
|
||||||
import { PageMargin } from "./page-margin/page-margin";
|
import { PageMargin } from "./page-margin/page-margin";
|
||||||
import { IPageMarginAttributes } from "./page-margin/page-margin-attributes";
|
import { IPageMarginAttributes } from "./page-margin/page-margin-attributes";
|
||||||
import { IPageNumberTypeAttributes, PageNumberFormat, PageNumberType } from "./page-number";
|
import { IPageNumberTypeAttributes, PageNumberType } from "./page-number";
|
||||||
import { PageSize } from "./page-size/page-size";
|
import { PageSize } from "./page-size/page-size";
|
||||||
import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes";
|
import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes";
|
||||||
import { TitlePage } from "./title-page/title-page";
|
import { TitlePage } from "./title-page/title-page";
|
||||||
@ -69,7 +69,7 @@ export class SectionProperties extends XmlComponent {
|
|||||||
orientation = PageOrientation.PORTRAIT,
|
orientation = PageOrientation.PORTRAIT,
|
||||||
headers,
|
headers,
|
||||||
footers,
|
footers,
|
||||||
pageNumberFormatType = PageNumberFormat.DECIMAL,
|
pageNumberFormatType,
|
||||||
pageNumberStart,
|
pageNumberStart,
|
||||||
pageBorders,
|
pageBorders,
|
||||||
pageBorderTop,
|
pageBorderTop,
|
||||||
@ -88,7 +88,9 @@ export class SectionProperties extends XmlComponent {
|
|||||||
this.addHeaders(headers);
|
this.addHeaders(headers);
|
||||||
this.addFooters(footers);
|
this.addFooters(footers);
|
||||||
|
|
||||||
|
if (pageNumberStart || pageNumberFormatType) {
|
||||||
this.root.push(new PageNumberType(pageNumberStart, pageNumberFormatType));
|
this.root.push(new PageNumberType(pageNumberStart, pageNumberFormatType));
|
||||||
|
}
|
||||||
|
|
||||||
if (pageBorders || pageBorderTop || pageBorderRight || pageBorderBottom || pageBorderLeft) {
|
if (pageBorders || pageBorderTop || pageBorderRight || pageBorderBottom || pageBorderLeft) {
|
||||||
this.root.push(
|
this.root.push(
|
||||||
|
@ -59,7 +59,10 @@ describe("Document", () => {
|
|||||||
|
|
||||||
describe("#createTable", () => {
|
describe("#createTable", () => {
|
||||||
it("should create a new table and append it to body", () => {
|
it("should create a new table and append it to body", () => {
|
||||||
const table = document.createTable(2, 3);
|
const table = document.createTable({
|
||||||
|
rows: 2,
|
||||||
|
columns: 3,
|
||||||
|
});
|
||||||
expect(table).to.be.an.instanceof(Table);
|
expect(table).to.be.an.instanceof(Table);
|
||||||
const body = new Formatter().format(document)["w:document"][1]["w:body"];
|
const body = new Formatter().format(document)["w:document"][1]["w:body"];
|
||||||
expect(body)
|
expect(body)
|
||||||
@ -69,7 +72,10 @@ describe("Document", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should create a table with the correct dimensions", () => {
|
it("should create a table with the correct dimensions", () => {
|
||||||
document.createTable(2, 3);
|
document.createTable({
|
||||||
|
rows: 2,
|
||||||
|
columns: 3,
|
||||||
|
});
|
||||||
const body = new Formatter().format(document)["w:document"][1]["w:body"];
|
const body = new Formatter().format(document)["w:document"][1]["w:body"];
|
||||||
expect(body)
|
expect(body)
|
||||||
.to.be.an("array")
|
.to.be.an("array")
|
||||||
@ -78,9 +84,9 @@ describe("Document", () => {
|
|||||||
.to.have.property("w:tbl")
|
.to.have.property("w:tbl")
|
||||||
.which.includes({
|
.which.includes({
|
||||||
"w:tblGrid": [
|
"w:tblGrid": [
|
||||||
{ "w:gridCol": [{ _attr: { "w:w": 1 } }] },
|
{ "w:gridCol": [{ _attr: { "w:w": 100 } }] },
|
||||||
{ "w:gridCol": [{ _attr: { "w:w": 1 } }] },
|
{ "w:gridCol": [{ _attr: { "w:w": 100 } }] },
|
||||||
{ "w:gridCol": [{ _attr: { "w:w": 1 } }] },
|
{ "w:gridCol": [{ _attr: { "w:w": 100 } }] },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
expect(body[0]["w:tbl"].filter((x) => x["w:tr"])).to.have.length(2);
|
expect(body[0]["w:tbl"].filter((x) => x["w:tr"])).to.have.length(2);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// http://officeopenxml.com/WPdocument.php
|
// http://officeopenxml.com/WPdocument.php
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
import { Paragraph } from "../paragraph";
|
import { Paragraph } from "../paragraph";
|
||||||
import { Table } from "../table";
|
import { ITableOptions, Table } from "../table";
|
||||||
import { TableOfContents } from "../table-of-contents";
|
import { TableOfContents } from "../table-of-contents";
|
||||||
import { Body } from "./body";
|
import { Body } from "./body";
|
||||||
import { SectionPropertiesOptions } from "./body/section-properties";
|
import { SectionPropertiesOptions } from "./body/section-properties";
|
||||||
@ -53,12 +53,13 @@ export class Document extends XmlComponent {
|
|||||||
return para;
|
return para;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addTable(table: Table): void {
|
public addTable(table: Table): Document {
|
||||||
this.body.push(table);
|
this.body.push(table);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createTable(rows: number, cols: number): Table {
|
public createTable(options: ITableOptions): Table {
|
||||||
const table = new Table(rows, cols);
|
const table = new Table(options);
|
||||||
this.addTable(table);
|
this.addTable(table);
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,20 @@ import { Anchor } from "./anchor";
|
|||||||
|
|
||||||
function createAnchor(drawingOptions: IDrawingOptions): Anchor {
|
function createAnchor(drawingOptions: IDrawingOptions): Anchor {
|
||||||
return new Anchor(
|
return new Anchor(
|
||||||
1,
|
{
|
||||||
|
fileName: "test.png",
|
||||||
|
stream: new Buffer(""),
|
||||||
|
dimensions: {
|
||||||
|
pixels: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
emus: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
pixels: {
|
pixels: {
|
||||||
x: 100,
|
x: 100,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// http://officeopenxml.com/drwPicFloating.php
|
// http://officeopenxml.com/drwPicFloating.php
|
||||||
import { IMediaDataDimensions } from "file/media";
|
import { IMediaData, IMediaDataDimensions } from "file/media";
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
import { IDrawingOptions } from "../drawing";
|
import { IDrawingOptions } from "../drawing";
|
||||||
import { HorizontalPosition, IFloating, SimplePos, VerticalPosition } from "../floating";
|
import { HorizontalPosition, IFloating, SimplePos, VerticalPosition } from "../floating";
|
||||||
@ -21,7 +21,7 @@ const defaultOptions: IFloating = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export class Anchor extends XmlComponent {
|
export class Anchor extends XmlComponent {
|
||||||
constructor(referenceId: number, dimensions: IMediaDataDimensions, drawingOptions: IDrawingOptions) {
|
constructor(mediaData: IMediaData, dimensions: IMediaDataDimensions, drawingOptions: IDrawingOptions) {
|
||||||
super("wp:anchor");
|
super("wp:anchor");
|
||||||
|
|
||||||
const floating = {
|
const floating = {
|
||||||
@ -77,6 +77,6 @@ export class Anchor extends XmlComponent {
|
|||||||
|
|
||||||
this.root.push(new DocProperties());
|
this.root.push(new DocProperties());
|
||||||
this.root.push(new GraphicFrameProperties());
|
this.root.push(new GraphicFrameProperties());
|
||||||
this.root.push(new Graphic(referenceId, dimensions.emus.x, dimensions.emus.y));
|
this.root.push(new Graphic(mediaData, dimensions.emus.x, dimensions.emus.y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ function createDrawing(drawingOptions?: IDrawingOptions): Drawing {
|
|||||||
return new Drawing(
|
return new Drawing(
|
||||||
{
|
{
|
||||||
fileName: "test.jpg",
|
fileName: "test.jpg",
|
||||||
referenceId: 1,
|
|
||||||
stream: Buffer.from(imageBase64Data, "base64"),
|
stream: Buffer.from(imageBase64Data, "base64"),
|
||||||
path: path,
|
path: path,
|
||||||
dimensions: {
|
dimensions: {
|
||||||
|
@ -21,15 +21,11 @@ export class Drawing extends XmlComponent {
|
|||||||
constructor(imageData: IMediaData, drawingOptions: IDrawingOptions = {}) {
|
constructor(imageData: IMediaData, drawingOptions: IDrawingOptions = {}) {
|
||||||
super("w:drawing");
|
super("w:drawing");
|
||||||
|
|
||||||
if (imageData === undefined) {
|
|
||||||
throw new Error("imageData cannot be undefined");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!drawingOptions.floating) {
|
if (!drawingOptions.floating) {
|
||||||
this.inline = new Inline(imageData.referenceId, imageData.dimensions);
|
this.inline = new Inline(imageData, imageData.dimensions);
|
||||||
this.root.push(this.inline);
|
this.root.push(this.inline);
|
||||||
} else {
|
} else {
|
||||||
this.root.push(new Anchor(imageData.referenceId, imageData.dimensions, drawingOptions));
|
this.root.push(new Anchor(imageData, imageData.dimensions, drawingOptions));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
|
import { IMediaData } from "file/media";
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
import { GraphicDataAttributes } from "./graphic-data-attribute";
|
import { GraphicDataAttributes } from "./graphic-data-attribute";
|
||||||
import { Pic } from "./pic";
|
import { Pic } from "./pic";
|
||||||
|
|
||||||
export class GraphicData extends XmlComponent {
|
export class GraphicData extends XmlComponent {
|
||||||
private readonly pic: Pic;
|
private readonly pic: Pic;
|
||||||
|
|
||||||
constructor(referenceId: number, x: number, y: number) {
|
constructor(mediaData: IMediaData, x: number, y: number) {
|
||||||
super("a:graphicData");
|
super("a:graphicData");
|
||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
@ -14,7 +16,7 @@ export class GraphicData extends XmlComponent {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.pic = new Pic(referenceId, x, y);
|
this.pic = new Pic(mediaData, x, y);
|
||||||
|
|
||||||
this.root.push(this.pic);
|
this.root.push(this.pic);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
|
import { IMediaData } from "file/media";
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
import { Blip } from "./blip";
|
import { Blip } from "./blip";
|
||||||
import { SourceRectangle } from "./source-rectangle";
|
import { SourceRectangle } from "./source-rectangle";
|
||||||
import { Stretch } from "./stretch";
|
import { Stretch } from "./stretch";
|
||||||
|
|
||||||
export class BlipFill extends XmlComponent {
|
export class BlipFill extends XmlComponent {
|
||||||
constructor(referenceId: number) {
|
constructor(mediaData: IMediaData) {
|
||||||
super("pic:blipFill");
|
super("pic:blipFill");
|
||||||
this.root.push(new Blip(referenceId));
|
|
||||||
|
this.root.push(new Blip(mediaData));
|
||||||
this.root.push(new SourceRectangle());
|
this.root.push(new SourceRectangle());
|
||||||
this.root.push(new Stretch());
|
this.root.push(new Stretch());
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { IMediaData } from "file/media";
|
||||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
interface IBlipProperties {
|
interface IBlipProperties {
|
||||||
@ -13,11 +14,11 @@ class BlipAttributes extends XmlAttributeComponent<IBlipProperties> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Blip extends XmlComponent {
|
export class Blip extends XmlComponent {
|
||||||
constructor(referenceId: number) {
|
constructor(mediaData: IMediaData) {
|
||||||
super("a:blip");
|
super("a:blip");
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new BlipAttributes({
|
new BlipAttributes({
|
||||||
embed: `rId${referenceId}`,
|
embed: `rId{${mediaData.fileName}}`,
|
||||||
cstate: "none",
|
cstate: "none",
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// http://officeopenxml.com/drwPic.php
|
// http://officeopenxml.com/drwPic.php
|
||||||
|
import { IMediaData } from "file/media";
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
import { BlipFill } from "./blip/blip-fill";
|
import { BlipFill } from "./blip/blip-fill";
|
||||||
import { NonVisualPicProperties } from "./non-visual-pic-properties/non-visual-pic-properties";
|
import { NonVisualPicProperties } from "./non-visual-pic-properties/non-visual-pic-properties";
|
||||||
import { PicAttributes } from "./pic-attributes";
|
import { PicAttributes } from "./pic-attributes";
|
||||||
@ -8,7 +10,7 @@ import { ShapeProperties } from "./shape-properties/shape-properties";
|
|||||||
export class Pic extends XmlComponent {
|
export class Pic extends XmlComponent {
|
||||||
private readonly shapeProperties: ShapeProperties;
|
private readonly shapeProperties: ShapeProperties;
|
||||||
|
|
||||||
constructor(referenceId: number, x: number, y: number) {
|
constructor(mediaData: IMediaData, x: number, y: number) {
|
||||||
super("pic:pic");
|
super("pic:pic");
|
||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
@ -20,7 +22,7 @@ export class Pic extends XmlComponent {
|
|||||||
this.shapeProperties = new ShapeProperties(x, y);
|
this.shapeProperties = new ShapeProperties(x, y);
|
||||||
|
|
||||||
this.root.push(new NonVisualPicProperties());
|
this.root.push(new NonVisualPicProperties());
|
||||||
this.root.push(new BlipFill(referenceId));
|
this.root.push(new BlipFill(mediaData));
|
||||||
this.root.push(new ShapeProperties(x, y));
|
this.root.push(new ShapeProperties(x, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
|
import { IMediaData } from "file/media";
|
||||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
import { GraphicData } from "./graphic-data";
|
import { GraphicData } from "./graphic-data";
|
||||||
|
|
||||||
interface IGraphicProperties {
|
interface IGraphicProperties {
|
||||||
@ -14,7 +16,7 @@ class GraphicAttributes extends XmlAttributeComponent<IGraphicProperties> {
|
|||||||
export class Graphic extends XmlComponent {
|
export class Graphic extends XmlComponent {
|
||||||
private readonly data: GraphicData;
|
private readonly data: GraphicData;
|
||||||
|
|
||||||
constructor(referenceId: number, x: number, y: number) {
|
constructor(mediaData: IMediaData, x: number, y: number) {
|
||||||
super("a:graphic");
|
super("a:graphic");
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new GraphicAttributes({
|
new GraphicAttributes({
|
||||||
@ -22,7 +24,7 @@ export class Graphic extends XmlComponent {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.data = new GraphicData(referenceId, x, y);
|
this.data = new GraphicData(mediaData, x, y);
|
||||||
|
|
||||||
this.root.push(this.data);
|
this.root.push(this.data);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// http://officeopenxml.com/drwPicInline.php
|
// http://officeopenxml.com/drwPicInline.php
|
||||||
import { IMediaDataDimensions } from "file/media";
|
import { IMediaData, IMediaDataDimensions } from "file/media";
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
import { DocProperties } from "./../doc-properties/doc-properties";
|
import { DocProperties } from "./../doc-properties/doc-properties";
|
||||||
import { EffectExtent } from "./../effect-extent/effect-extent";
|
import { EffectExtent } from "./../effect-extent/effect-extent";
|
||||||
@ -12,7 +12,7 @@ export class Inline extends XmlComponent {
|
|||||||
private readonly extent: Extent;
|
private readonly extent: Extent;
|
||||||
private readonly graphic: Graphic;
|
private readonly graphic: Graphic;
|
||||||
|
|
||||||
constructor(referenceId: number, private readonly dimensions: IMediaDataDimensions) {
|
constructor(readonly mediaData: IMediaData, private readonly dimensions: IMediaDataDimensions) {
|
||||||
super("wp:inline");
|
super("wp:inline");
|
||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
@ -25,7 +25,7 @@ export class Inline extends XmlComponent {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.extent = new Extent(dimensions.emus.x, dimensions.emus.y);
|
this.extent = new Extent(dimensions.emus.x, dimensions.emus.y);
|
||||||
this.graphic = new Graphic(referenceId, dimensions.emus.x, dimensions.emus.y);
|
this.graphic = new Graphic(mediaData, dimensions.emus.x, dimensions.emus.y);
|
||||||
|
|
||||||
this.root.push(this.extent);
|
this.root.push(this.extent);
|
||||||
this.root.push(new EffectExtent());
|
this.root.push(new EffectExtent());
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
import * as sinon from "sinon";
|
||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { File } from "./file";
|
import { File } from "./file";
|
||||||
|
import { Paragraph } from "./paragraph";
|
||||||
|
import { Table } from "./table";
|
||||||
|
|
||||||
describe("File", () => {
|
describe("File", () => {
|
||||||
describe("#constructor", () => {
|
describe("#constructor", () => {
|
||||||
it("should create with correct headers", () => {
|
it("should create with correct headers and footers", () => {
|
||||||
const doc = new File();
|
const doc = new File();
|
||||||
const header = doc.createHeader();
|
const header = doc.createHeader();
|
||||||
const footer = doc.createFooter();
|
const footer = doc.createFooter();
|
||||||
@ -26,6 +29,26 @@ describe("File", () => {
|
|||||||
expect(tree["w:body"][1]["w:sectPr"][5]["w:footerReference"][0]._attr["w:type"]).to.equal("default");
|
expect(tree["w:body"][1]["w:sectPr"][5]["w:footerReference"][0]._attr["w:type"]).to.equal("default");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should create with first headers and footers", () => {
|
||||||
|
const doc = new File();
|
||||||
|
const header = doc.createHeader();
|
||||||
|
const footer = doc.createFooter();
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
headers: {
|
||||||
|
first: header,
|
||||||
|
},
|
||||||
|
footers: {
|
||||||
|
first: footer,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(doc.Document.Body);
|
||||||
|
|
||||||
|
expect(tree["w:body"][1]["w:sectPr"][4]["w:headerReference"][0]._attr["w:type"]).to.equal("first");
|
||||||
|
expect(tree["w:body"][1]["w:sectPr"][5]["w:footerReference"][0]._attr["w:type"]).to.equal("first");
|
||||||
|
});
|
||||||
|
|
||||||
it("should create with correct headers", () => {
|
it("should create with correct headers", () => {
|
||||||
const doc = new File();
|
const doc = new File();
|
||||||
const header = doc.createHeader();
|
const header = doc.createHeader();
|
||||||
@ -55,4 +78,96 @@ describe("File", () => {
|
|||||||
expect(tree["w:body"][1]["w:sectPr"][9]["w:footerReference"][0]._attr["w:type"]).to.equal("even");
|
expect(tree["w:body"][1]["w:sectPr"][9]["w:footerReference"][0]._attr["w:type"]).to.equal("even");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#addParagraph", () => {
|
||||||
|
it("should call the underlying document's addParagraph", () => {
|
||||||
|
const file = new File();
|
||||||
|
const spy = sinon.spy(file.Document, "addParagraph");
|
||||||
|
file.addParagraph(new Paragraph());
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#addTable", () => {
|
||||||
|
it("should call the underlying document's addTable", () => {
|
||||||
|
const wrapper = new File();
|
||||||
|
const spy = sinon.spy(wrapper.Document, "addTable");
|
||||||
|
wrapper.addTable(
|
||||||
|
new Table({
|
||||||
|
rows: 1,
|
||||||
|
columns: 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#createTable", () => {
|
||||||
|
it("should call the underlying document's createTable", () => {
|
||||||
|
const wrapper = new File();
|
||||||
|
const spy = sinon.spy(wrapper.Document, "createTable");
|
||||||
|
wrapper.createTable({
|
||||||
|
rows: 1,
|
||||||
|
columns: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#addTableOfContents", () => {
|
||||||
|
it("should call the underlying document's addTableOfContents", () => {
|
||||||
|
const wrapper = new File();
|
||||||
|
const spy = sinon.spy(wrapper.Document, "addTableOfContents");
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
wrapper.addTableOfContents({} as any);
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#createParagraph", () => {
|
||||||
|
it("should call the underlying document's createParagraph", () => {
|
||||||
|
const wrapper = new File();
|
||||||
|
const spy = sinon.spy(wrapper.Document, "createParagraph");
|
||||||
|
wrapper.createParagraph("test");
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#addImage", () => {
|
||||||
|
it("should call the underlying document's addImage", () => {
|
||||||
|
const wrapper = new File();
|
||||||
|
const spy = sinon.spy(wrapper.Document, "addParagraph");
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
wrapper.addImage({} as any);
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#createImage", () => {
|
||||||
|
it("should call the underlying document's createImage", () => {
|
||||||
|
const wrapper = new File();
|
||||||
|
const spy = sinon.spy(wrapper.Media, "addMedia");
|
||||||
|
const wrapperSpy = sinon.spy(wrapper.Document, "addParagraph");
|
||||||
|
wrapper.createImage("");
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
expect(wrapperSpy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#createFootnote", () => {
|
||||||
|
it("should call the underlying document's createFootnote", () => {
|
||||||
|
const wrapper = new File();
|
||||||
|
const spy = sinon.spy(wrapper.FootNotes, "createFootNote");
|
||||||
|
wrapper.createFootnote(new Paragraph(""));
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -19,11 +19,12 @@ import { Image, Media } from "./media";
|
|||||||
import { Numbering } from "./numbering";
|
import { Numbering } from "./numbering";
|
||||||
import { Bookmark, Hyperlink, Paragraph } from "./paragraph";
|
import { Bookmark, Hyperlink, Paragraph } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
|
import { TargetModeType } from "./relationships/relationship/relationship";
|
||||||
import { Settings } from "./settings";
|
import { Settings } from "./settings";
|
||||||
import { Styles } from "./styles";
|
import { Styles } from "./styles";
|
||||||
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
||||||
import { DefaultStylesFactory } from "./styles/factory";
|
import { DefaultStylesFactory } from "./styles/factory";
|
||||||
import { Table } from "./table";
|
import { ITableOptions, Table } from "./table";
|
||||||
import { TableOfContents } from "./table-of-contents";
|
import { TableOfContents } from "./table-of-contents";
|
||||||
|
|
||||||
export class File {
|
export class File {
|
||||||
@ -57,12 +58,13 @@ export class File {
|
|||||||
this.coreProperties = new CoreProperties(options);
|
this.coreProperties = new CoreProperties(options);
|
||||||
this.numbering = new Numbering();
|
this.numbering = new Numbering();
|
||||||
this.docRelationships = new Relationships();
|
this.docRelationships = new Relationships();
|
||||||
this.media = new Media();
|
|
||||||
this.fileRelationships = new Relationships();
|
this.fileRelationships = new Relationships();
|
||||||
this.appProperties = new AppProperties();
|
this.appProperties = new AppProperties();
|
||||||
this.footNotes = new FootNotes();
|
this.footNotes = new FootNotes();
|
||||||
this.contentTypes = new ContentTypes();
|
this.contentTypes = new ContentTypes();
|
||||||
|
|
||||||
|
this.media = fileProperties.template && fileProperties.template.media ? fileProperties.template.media : new Media();
|
||||||
|
|
||||||
if (fileProperties.template) {
|
if (fileProperties.template) {
|
||||||
this.currentRelationshipId = fileProperties.template.currentRelationshipId + 1;
|
this.currentRelationshipId = fileProperties.template.currentRelationshipId + 1;
|
||||||
}
|
}
|
||||||
@ -72,7 +74,8 @@ export class File {
|
|||||||
throw Error("can not use both template and external styles");
|
throw Error("can not use both template and external styles");
|
||||||
}
|
}
|
||||||
if (fileProperties.template) {
|
if (fileProperties.template) {
|
||||||
this.styles = fileProperties.template.styles;
|
const stylesFactory = new ExternalStylesFactory();
|
||||||
|
this.styles = stylesFactory.newInstance(fileProperties.template.styles);
|
||||||
} else if (options.externalStyles) {
|
} else if (options.externalStyles) {
|
||||||
const stylesFactory = new ExternalStylesFactory();
|
const stylesFactory = new ExternalStylesFactory();
|
||||||
this.styles = stylesFactory.newInstance(options.externalStyles);
|
this.styles = stylesFactory.newInstance(options.externalStyles);
|
||||||
@ -109,8 +112,9 @@ export class File {
|
|||||||
this.settings = new Settings();
|
this.settings = new Settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public addTableOfContents(toc: TableOfContents): void {
|
public addTableOfContents(toc: TableOfContents): File {
|
||||||
this.document.addTableOfContents(toc);
|
this.document.addTableOfContents(toc);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addParagraph(paragraph: Paragraph): File {
|
public addParagraph(paragraph: Paragraph): File {
|
||||||
@ -122,12 +126,13 @@ export class File {
|
|||||||
return this.document.createParagraph(text);
|
return this.document.createParagraph(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addTable(table: Table): void {
|
public addTable(table: Table): File {
|
||||||
return this.document.addTable(table);
|
this.document.addTable(table);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createTable(rows: number, cols: number): Table {
|
public createTable(options: ITableOptions): Table {
|
||||||
return this.document.createTable(rows, cols);
|
return this.document.createTable(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addImage(image: Image): File {
|
public addImage(image: Image): File {
|
||||||
@ -154,7 +159,7 @@ export class File {
|
|||||||
hyperlink.linkId,
|
hyperlink.linkId,
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
||||||
link,
|
link,
|
||||||
"External",
|
TargetModeType.EXTERNAL,
|
||||||
);
|
);
|
||||||
return hyperlink;
|
return hyperlink;
|
||||||
}
|
}
|
||||||
@ -319,6 +324,11 @@ export class File {
|
|||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
|
||||||
"footnotes.xml",
|
"footnotes.xml",
|
||||||
);
|
);
|
||||||
|
this.docRelationships.createRelationship(
|
||||||
|
this.currentRelationshipId++,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings",
|
||||||
|
"settings.xml",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private groupHeaders(headers: IDocumentHeader[], group: IHeaderFooterGroup<HeaderWrapper> = {}): IHeaderFooterGroup<HeaderWrapper> {
|
private groupHeaders(headers: IDocumentHeader[], group: IHeaderFooterGroup<HeaderWrapper> = {}): IHeaderFooterGroup<HeaderWrapper> {
|
||||||
@ -326,12 +336,6 @@ export class File {
|
|||||||
|
|
||||||
for (const header of headers) {
|
for (const header of headers) {
|
||||||
switch (header.type) {
|
switch (header.type) {
|
||||||
case HeaderReferenceType.DEFAULT:
|
|
||||||
newGroup = {
|
|
||||||
...newGroup,
|
|
||||||
default: header.header,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case HeaderReferenceType.FIRST:
|
case HeaderReferenceType.FIRST:
|
||||||
newGroup = {
|
newGroup = {
|
||||||
...newGroup,
|
...newGroup,
|
||||||
@ -344,6 +348,7 @@ export class File {
|
|||||||
even: header.header,
|
even: header.header,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
case HeaderReferenceType.DEFAULT:
|
||||||
default:
|
default:
|
||||||
newGroup = {
|
newGroup = {
|
||||||
...newGroup,
|
...newGroup,
|
||||||
@ -361,12 +366,6 @@ export class File {
|
|||||||
|
|
||||||
for (const footer of footers) {
|
for (const footer of footers) {
|
||||||
switch (footer.type) {
|
switch (footer.type) {
|
||||||
case FooterReferenceType.DEFAULT:
|
|
||||||
newGroup = {
|
|
||||||
...newGroup,
|
|
||||||
default: footer.footer,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case FooterReferenceType.FIRST:
|
case FooterReferenceType.FIRST:
|
||||||
newGroup = {
|
newGroup = {
|
||||||
...newGroup,
|
...newGroup,
|
||||||
@ -379,6 +378,7 @@ export class File {
|
|||||||
even: footer.footer,
|
even: footer.footer,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
case FooterReferenceType.DEFAULT:
|
||||||
default:
|
default:
|
||||||
newGroup = {
|
newGroup = {
|
||||||
...newGroup,
|
...newGroup,
|
||||||
|
88
src/file/footer-wrapper.spec.ts
Normal file
88
src/file/footer-wrapper.spec.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
import * as sinon from "sinon";
|
||||||
|
|
||||||
|
import { FooterWrapper } from "./footer-wrapper";
|
||||||
|
import { Media } from "./media";
|
||||||
|
import { Paragraph } from "./paragraph";
|
||||||
|
import { Table } from "./table";
|
||||||
|
|
||||||
|
describe("FooterWrapper", () => {
|
||||||
|
describe("#addParagraph", () => {
|
||||||
|
it("should call the underlying footer's addParagraph", () => {
|
||||||
|
const file = new FooterWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(file.Footer, "addParagraph");
|
||||||
|
file.addParagraph(new Paragraph());
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#addTable", () => {
|
||||||
|
it("should call the underlying footer's addParagraph", () => {
|
||||||
|
const file = new FooterWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(file.Footer, "addTable");
|
||||||
|
file.addTable(
|
||||||
|
new Table({
|
||||||
|
rows: 1,
|
||||||
|
columns: 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#createTable", () => {
|
||||||
|
it("should call the underlying footer's createTable", () => {
|
||||||
|
const wrapper = new FooterWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(wrapper.Footer, "createTable");
|
||||||
|
wrapper.createTable(1, 1);
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#createParagraph", () => {
|
||||||
|
it("should call the underlying footer's createParagraph", () => {
|
||||||
|
const file = new FooterWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(file.Footer, "addParagraph");
|
||||||
|
file.createParagraph();
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#addImage", () => {
|
||||||
|
it("should call the underlying footer's addImage", () => {
|
||||||
|
const file = new FooterWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(file.Footer, "addParagraph");
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
file.addImage({} as any);
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#createImage", () => {
|
||||||
|
it("should call the underlying footer's createImage", () => {
|
||||||
|
const file = new FooterWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(file.Media, "addMedia");
|
||||||
|
const fileSpy = sinon.spy(file, "addImage");
|
||||||
|
file.createImage("");
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
expect(fileSpy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#addChildElement", () => {
|
||||||
|
it("should call the underlying footer's addChildElement", () => {
|
||||||
|
const file = new FooterWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(file.Footer, "addChildElement");
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
file.addChildElement({} as any);
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -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, IMediaData, Media } from "./media";
|
import { Image, Media } from "./media";
|
||||||
import { ImageParagraph, Paragraph } from "./paragraph";
|
import { ImageParagraph, Paragraph } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
import { Table } from "./table";
|
import { Table } from "./table";
|
||||||
@ -43,29 +43,8 @@ export class FooterWrapper {
|
|||||||
this.footer.addChildElement(childElement);
|
this.footer.addChildElement(childElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addImageRelationship(image: Buffer, refId: number, width?: number, height?: number): IMediaData {
|
|
||||||
const mediaData = this.media.addMedia(image, refId, width, height);
|
|
||||||
this.relationships.createRelationship(
|
|
||||||
mediaData.referenceId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
||||||
`media/${mediaData.fileName}`,
|
|
||||||
);
|
|
||||||
return mediaData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addHyperlinkRelationship(target: string, refId: number, targetMode?: "External" | undefined): void {
|
|
||||||
this.relationships.createRelationship(
|
|
||||||
refId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
|
||||||
target,
|
|
||||||
targetMode,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public createImage(image: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): void {
|
public createImage(image: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): void {
|
||||||
// TODO
|
const mediaData = this.media.addMedia(image, width, height);
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
const mediaData = this.addImageRelationship(image as any, this.relationships.RelationshipCount, width, height);
|
|
||||||
this.addImage(new Image(new ImageParagraph(mediaData)));
|
this.addImage(new Image(new ImageParagraph(mediaData)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,10 @@ export class Footer extends InitializableXmlComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public createTable(rows: number, cols: number): Table {
|
public createTable(rows: number, cols: number): Table {
|
||||||
const table = new Table(rows, cols);
|
const table = new Table({
|
||||||
|
rows: rows,
|
||||||
|
columns: cols,
|
||||||
|
});
|
||||||
this.addTable(table);
|
this.addTable(table);
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
@ -9,19 +9,78 @@ import { Table } from "./table";
|
|||||||
describe("HeaderWrapper", () => {
|
describe("HeaderWrapper", () => {
|
||||||
describe("#addParagraph", () => {
|
describe("#addParagraph", () => {
|
||||||
it("should call the underlying header's addParagraph", () => {
|
it("should call the underlying header's addParagraph", () => {
|
||||||
const file = new HeaderWrapper(new Media(), 1);
|
const wrapper = new HeaderWrapper(new Media(), 1);
|
||||||
const spy = sinon.spy(file.Header, "addParagraph");
|
const spy = sinon.spy(wrapper.Header, "addParagraph");
|
||||||
file.addParagraph(new Paragraph());
|
wrapper.addParagraph(new Paragraph());
|
||||||
|
|
||||||
expect(spy.called).to.equal(true);
|
expect(spy.called).to.equal(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#addTable", () => {
|
describe("#addTable", () => {
|
||||||
it("should call the underlying header's addParagraph", () => {
|
it("should call the underlying header's addTable", () => {
|
||||||
|
const wrapper = new HeaderWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(wrapper.Header, "addTable");
|
||||||
|
wrapper.addTable(
|
||||||
|
new Table({
|
||||||
|
rows: 1,
|
||||||
|
columns: 1,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#createTable", () => {
|
||||||
|
it("should call the underlying header's createTable", () => {
|
||||||
|
const wrapper = new HeaderWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(wrapper.Header, "createTable");
|
||||||
|
wrapper.createTable(1, 1);
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#createParagraph", () => {
|
||||||
|
it("should call the underlying header's createParagraph", () => {
|
||||||
const file = new HeaderWrapper(new Media(), 1);
|
const file = new HeaderWrapper(new Media(), 1);
|
||||||
const spy = sinon.spy(file.Header, "addTable");
|
const spy = sinon.spy(file.Header, "addParagraph");
|
||||||
file.addTable(new Table(1, 1));
|
file.createParagraph();
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#addImage", () => {
|
||||||
|
it("should call the underlying header's addImage", () => {
|
||||||
|
const file = new HeaderWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(file.Header, "addParagraph");
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
file.addImage({} as any);
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#createImage", () => {
|
||||||
|
it("should call the underlying header's createImage", () => {
|
||||||
|
const file = new HeaderWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(file.Media, "addMedia");
|
||||||
|
const fileSpy = sinon.spy(file, "addImage");
|
||||||
|
file.createImage("");
|
||||||
|
|
||||||
|
expect(spy.called).to.equal(true);
|
||||||
|
expect(fileSpy.called).to.equal(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#addChildElement", () => {
|
||||||
|
it("should call the underlying header's addChildElement", () => {
|
||||||
|
const file = new HeaderWrapper(new Media(), 1);
|
||||||
|
const spy = sinon.spy(file.Header, "addChildElement");
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
file.addChildElement({} as any);
|
||||||
|
|
||||||
expect(spy.called).to.equal(true);
|
expect(spy.called).to.equal(true);
|
||||||
});
|
});
|
||||||
|
@ -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, IMediaData, Media } from "./media";
|
import { Image, Media } from "./media";
|
||||||
import { ImageParagraph, Paragraph } from "./paragraph";
|
import { ImageParagraph, Paragraph } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
import { Table } from "./table";
|
import { Table } from "./table";
|
||||||
@ -43,29 +43,8 @@ export class HeaderWrapper {
|
|||||||
this.header.addChildElement(childElement);
|
this.header.addChildElement(childElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addImageRelationship(image: Buffer, refId: number, width?: number, height?: number): IMediaData {
|
|
||||||
const mediaData = this.media.addMedia(image, refId, width, height);
|
|
||||||
this.relationships.createRelationship(
|
|
||||||
mediaData.referenceId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
||||||
`media/${mediaData.fileName}`,
|
|
||||||
);
|
|
||||||
return mediaData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addHyperlinkRelationship(target: string, refId: number, targetMode?: "External" | undefined): void {
|
|
||||||
this.relationships.createRelationship(
|
|
||||||
refId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
|
||||||
target,
|
|
||||||
targetMode,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public createImage(image: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): void {
|
public createImage(image: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): void {
|
||||||
// TODO
|
const mediaData = this.media.addMedia(image, width, height);
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
const mediaData = this.addImageRelationship(image as any, this.relationships.RelationshipCount, width, height);
|
|
||||||
this.addImage(new Image(new ImageParagraph(mediaData)));
|
this.addImage(new Image(new ImageParagraph(mediaData)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,10 @@ export class Header extends InitializableXmlComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public createTable(rows: number, cols: number): Table {
|
public createTable(rows: number, cols: number): Table {
|
||||||
const table = new Table(rows, cols);
|
const table = new Table({
|
||||||
|
rows: rows,
|
||||||
|
columns: cols,
|
||||||
|
});
|
||||||
this.addTable(table);
|
this.addTable(table);
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ export interface IMediaDataDimensions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IMediaData {
|
export interface IMediaData {
|
||||||
readonly referenceId: number;
|
|
||||||
readonly stream: Buffer | Uint8Array | ArrayBuffer;
|
readonly stream: Buffer | Uint8Array | ArrayBuffer;
|
||||||
readonly path?: string;
|
readonly path?: string;
|
||||||
readonly fileName: string;
|
readonly fileName: string;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// tslint:disable:object-literal-key-quotes
|
// tslint:disable:object-literal-key-quotes
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
import { stub } from "sinon";
|
||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
@ -20,16 +21,18 @@ describe("Media", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should ensure the correct relationship id is used when adding image", () => {
|
it("should ensure the correct relationship id is used when adding image", () => {
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
stub(Media as any, "generateId").callsFake(() => "testId");
|
||||||
|
|
||||||
const file = new File();
|
const file = new File();
|
||||||
const image1 = Media.addImage(file, "test");
|
const image1 = Media.addImage(file, "test");
|
||||||
|
|
||||||
const tree = new Formatter().format(image1.Paragraph);
|
const tree = new Formatter().format(image1.Paragraph);
|
||||||
const inlineElements = tree["w:p"][1]["w:r"][1]["w:drawing"][0]["wp:inline"];
|
const inlineElements = tree["w:p"][1]["w:r"][1]["w:drawing"][0]["wp:inline"];
|
||||||
const graphicData = inlineElements.find((x) => x["a:graphic"]);
|
const graphicData = inlineElements.find((x) => x["a:graphic"]);
|
||||||
|
|
||||||
expect(graphicData["a:graphic"][1]["a:graphicData"][1]["pic:pic"][2]["pic:blipFill"][0]["a:blip"][0]).to.deep.equal({
|
expect(graphicData["a:graphic"][1]["a:graphicData"][1]["pic:pic"][2]["pic:blipFill"][0]["a:blip"][0]).to.deep.equal({
|
||||||
_attr: {
|
_attr: {
|
||||||
"r:embed": `rId${file.DocumentRelationships.RelationshipCount}`,
|
"r:embed": `rId{testId.png}`,
|
||||||
cstate: "none",
|
cstate: "none",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -41,7 +44,7 @@ describe("Media", () => {
|
|||||||
|
|
||||||
expect(graphicData2["a:graphic"][1]["a:graphicData"][1]["pic:pic"][2]["pic:blipFill"][0]["a:blip"][0]).to.deep.equal({
|
expect(graphicData2["a:graphic"][1]["a:graphicData"][1]["pic:pic"][2]["pic:blipFill"][0]["a:blip"][0]).to.deep.equal({
|
||||||
_attr: {
|
_attr: {
|
||||||
"r:embed": `rId${file.DocumentRelationships.RelationshipCount}`,
|
"r:embed": `rId{testId.png}`,
|
||||||
cstate: "none",
|
cstate: "none",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -53,9 +56,8 @@ describe("Media", () => {
|
|||||||
// tslint:disable-next-line:no-any
|
// tslint:disable-next-line:no-any
|
||||||
(Media as any).generateId = () => "test";
|
(Media as any).generateId = () => "test";
|
||||||
|
|
||||||
const image = new Media().addMedia("", 1);
|
const image = new Media().addMedia("");
|
||||||
expect(image.fileName).to.equal("test.png");
|
expect(image.fileName).to.equal("test.png");
|
||||||
expect(image.referenceId).to.equal(1);
|
|
||||||
expect(image.dimensions).to.deep.equal({
|
expect(image.dimensions).to.deep.equal({
|
||||||
pixels: {
|
pixels: {
|
||||||
x: 100,
|
x: 100,
|
||||||
@ -74,7 +76,7 @@ describe("Media", () => {
|
|||||||
// tslint:disable-next-line:no-any
|
// tslint:disable-next-line:no-any
|
||||||
(Media as any).generateId = () => "test";
|
(Media as any).generateId = () => "test";
|
||||||
|
|
||||||
const image = new Media().addMedia("", 1);
|
const image = new Media().addMedia("");
|
||||||
expect(image.stream).to.be.an.instanceof(Uint8Array);
|
expect(image.stream).to.be.an.instanceof(Uint8Array);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -85,12 +87,11 @@ describe("Media", () => {
|
|||||||
(Media as any).generateId = () => "test";
|
(Media as any).generateId = () => "test";
|
||||||
|
|
||||||
const media = new Media();
|
const media = new Media();
|
||||||
media.addMedia("", 1);
|
media.addMedia("");
|
||||||
|
|
||||||
const image = media.getMedia("test.png");
|
const image = media.getMedia("test.png");
|
||||||
|
|
||||||
expect(image.fileName).to.equal("test.png");
|
expect(image.fileName).to.equal("test.png");
|
||||||
expect(image.referenceId).to.equal(1);
|
|
||||||
expect(image.dimensions).to.deep.equal({
|
expect(image.dimensions).to.deep.equal({
|
||||||
pixels: {
|
pixels: {
|
||||||
x: 100,
|
x: 100,
|
||||||
@ -116,7 +117,7 @@ describe("Media", () => {
|
|||||||
(Media as any).generateId = () => "test";
|
(Media as any).generateId = () => "test";
|
||||||
|
|
||||||
const media = new Media();
|
const media = new Media();
|
||||||
media.addMedia("", 1);
|
media.addMedia("");
|
||||||
|
|
||||||
const array = media.Array;
|
const array = media.Array;
|
||||||
expect(array).to.be.an.instanceof(Array);
|
expect(array).to.be.an.instanceof(Array);
|
||||||
@ -124,7 +125,6 @@ describe("Media", () => {
|
|||||||
|
|
||||||
const image = array[0];
|
const image = array[0];
|
||||||
expect(image.fileName).to.equal("test.png");
|
expect(image.fileName).to.equal("test.png");
|
||||||
expect(image.referenceId).to.equal(1);
|
|
||||||
expect(image.dimensions).to.deep.equal({
|
expect(image.dimensions).to.deep.equal({
|
||||||
pixels: {
|
pixels: {
|
||||||
x: 100,
|
x: 100,
|
||||||
|
@ -4,11 +4,6 @@ import { ImageParagraph } from "../paragraph";
|
|||||||
import { IMediaData } from "./data";
|
import { IMediaData } from "./data";
|
||||||
import { Image } from "./image";
|
import { Image } from "./image";
|
||||||
|
|
||||||
interface IHackedFile {
|
|
||||||
// tslint:disable-next-line:readonly-keyword
|
|
||||||
currentRelationshipId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Media {
|
export class Media {
|
||||||
public static addImage(
|
public static addImage(
|
||||||
file: File,
|
file: File,
|
||||||
@ -18,14 +13,7 @@ export class Media {
|
|||||||
drawingOptions?: IDrawingOptions,
|
drawingOptions?: IDrawingOptions,
|
||||||
): Image {
|
): Image {
|
||||||
// Workaround to expose id without exposing to API
|
// Workaround to expose id without exposing to API
|
||||||
const exposedFile = (file as {}) as IHackedFile;
|
const mediaData = file.Media.addMedia(buffer, width, height);
|
||||||
const mediaData = file.Media.addMedia(buffer, exposedFile.currentRelationshipId++, width, height);
|
|
||||||
file.DocumentRelationships.createRelationship(
|
|
||||||
mediaData.referenceId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
||||||
`media/${mediaData.fileName}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return new Image(new ImageParagraph(mediaData, drawingOptions));
|
return new Image(new ImageParagraph(mediaData, drawingOptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,17 +45,11 @@ export class Media {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addMedia(
|
public addMedia(buffer: Buffer | string | Uint8Array | ArrayBuffer, width: number = 100, height: number = 100): IMediaData {
|
||||||
buffer: Buffer | string | Uint8Array | ArrayBuffer,
|
|
||||||
referenceId: number,
|
|
||||||
width: number = 100,
|
|
||||||
height: number = 100,
|
|
||||||
): IMediaData {
|
|
||||||
const key = `${Media.generateId()}.png`;
|
const key = `${Media.generateId()}.png`;
|
||||||
|
|
||||||
return this.createMedia(
|
return this.createMedia(
|
||||||
key,
|
key,
|
||||||
referenceId,
|
|
||||||
{
|
{
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
@ -78,7 +60,6 @@ export class Media {
|
|||||||
|
|
||||||
private createMedia(
|
private createMedia(
|
||||||
key: string,
|
key: string,
|
||||||
relationshipsCount: number,
|
|
||||||
dimensions: { readonly width: number; readonly height: number },
|
dimensions: { readonly width: number; readonly height: number },
|
||||||
data: Buffer | string | Uint8Array | ArrayBuffer,
|
data: Buffer | string | Uint8Array | ArrayBuffer,
|
||||||
filePath?: string,
|
filePath?: string,
|
||||||
@ -86,7 +67,6 @@ export class Media {
|
|||||||
const newData = typeof data === "string" ? this.convertDataURIToBinary(data) : data;
|
const newData = typeof data === "string" ? this.convertDataURIToBinary(data) : data;
|
||||||
|
|
||||||
const imageData: IMediaData = {
|
const imageData: IMediaData = {
|
||||||
referenceId: relationshipsCount,
|
|
||||||
stream: newData,
|
stream: newData,
|
||||||
path: filePath,
|
path: filePath,
|
||||||
fileName: key,
|
fileName: key,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export * from "./numbering";
|
export * from "./numbering";
|
||||||
export * from "./abstract-numbering";
|
export * from "./abstract-numbering";
|
||||||
export * from "./level";
|
export * from "./level";
|
||||||
|
export * from "./num";
|
||||||
|
@ -18,9 +18,9 @@ class SpacingAttributes extends XmlAttributeComponent<ISpacingProperties> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Spacing extends XmlComponent {
|
export class Spacing extends XmlComponent {
|
||||||
constructor(opts: ISpacingProperties) {
|
constructor(options: ISpacingProperties) {
|
||||||
super("w:spacing");
|
super("w:spacing");
|
||||||
this.root.push(new SpacingAttributes(opts));
|
this.root.push(new SpacingAttributes(options));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,10 +10,9 @@ describe("Image", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
image = new ImageParagraph({
|
image = new ImageParagraph({
|
||||||
referenceId: 0,
|
|
||||||
stream: new Buffer(""),
|
stream: new Buffer(""),
|
||||||
path: "",
|
path: "",
|
||||||
fileName: "",
|
fileName: "test.png",
|
||||||
dimensions: {
|
dimensions: {
|
||||||
pixels: {
|
pixels: {
|
||||||
x: 10,
|
x: 10,
|
||||||
@ -171,7 +170,7 @@ describe("Image", () => {
|
|||||||
{
|
{
|
||||||
_attr: {
|
_attr: {
|
||||||
cstate: "none",
|
cstate: "none",
|
||||||
"r:embed": "rId0",
|
"r:embed": "rId{test.png}",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -5,6 +5,7 @@ import { HyperlinkAttributes, IHyperlinkAttributesProperties } from "./hyperlink
|
|||||||
|
|
||||||
export class Hyperlink extends XmlComponent {
|
export class Hyperlink extends XmlComponent {
|
||||||
public readonly linkId: number;
|
public readonly linkId: number;
|
||||||
|
private readonly textRun: TextRun;
|
||||||
|
|
||||||
constructor(text: string, relationshipsCount: number, anchor?: string) {
|
constructor(text: string, relationshipsCount: number, anchor?: string) {
|
||||||
super("w:hyperlink");
|
super("w:hyperlink");
|
||||||
@ -19,6 +20,11 @@ export class Hyperlink extends XmlComponent {
|
|||||||
|
|
||||||
const attributes = new HyperlinkAttributes(props);
|
const attributes = new HyperlinkAttributes(props);
|
||||||
this.root.push(attributes);
|
this.root.push(attributes);
|
||||||
this.root.push(new TextRun(text).style("Hyperlink"));
|
this.textRun = new TextRun(text).style("Hyperlink");
|
||||||
|
this.root.push(this.textRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get TextRun(): TextRun {
|
||||||
|
return this.textRun;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
export * from "./hyperlink";
|
export * from "./hyperlink";
|
||||||
export * from "./bookmark";
|
export * from "./bookmark";
|
||||||
|
export * from "./outline-level";
|
||||||
|
23
src/file/paragraph/links/outline-level.spec.ts
Normal file
23
src/file/paragraph/links/outline-level.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { assert } from "chai";
|
||||||
|
|
||||||
|
import { Utility } from "tests/utility";
|
||||||
|
|
||||||
|
import { OutlineLevel } from "./outline-level";
|
||||||
|
|
||||||
|
describe("ParagraphOutlineLevel", () => {
|
||||||
|
let outlineLevel: OutlineLevel;
|
||||||
|
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("should create an outlineLevel with given value", () => {
|
||||||
|
outlineLevel = new OutlineLevel("0");
|
||||||
|
const newJson = Utility.jsonify(outlineLevel);
|
||||||
|
assert.equal(newJson.root[0].root.val, "0");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create an outlineLevel with blank val", () => {
|
||||||
|
outlineLevel = new OutlineLevel("");
|
||||||
|
const newJson = Utility.jsonify(outlineLevel);
|
||||||
|
assert.equal(newJson.root[0].root.val, "");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
16
src/file/paragraph/links/outline-level.ts
Normal file
16
src/file/paragraph/links/outline-level.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// http://officeopenxml.com/WPparagraph.php
|
||||||
|
import { Attributes, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
|
export class OutlineLevel extends XmlComponent {
|
||||||
|
public readonly level: string;
|
||||||
|
|
||||||
|
constructor(level: string) {
|
||||||
|
super("w:outlineLvl");
|
||||||
|
this.level = level;
|
||||||
|
this.root.push(
|
||||||
|
new Attributes({
|
||||||
|
val: level,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import { Formatter } from "export/formatter";
|
|||||||
import * as file from "file";
|
import * as file from "file";
|
||||||
|
|
||||||
import { Numbering } from "../numbering";
|
import { Numbering } from "../numbering";
|
||||||
|
import { LeaderType } from "./formatting";
|
||||||
|
|
||||||
describe("Paragraph", () => {
|
describe("Paragraph", () => {
|
||||||
let paragraph: file.Paragraph;
|
let paragraph: file.Paragraph;
|
||||||
@ -86,6 +87,48 @@ describe("Paragraph", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#heading4()", () => {
|
||||||
|
it("should add heading style to JSON", () => {
|
||||||
|
paragraph.heading4();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:pStyle": [{ _attr: { "w:val": "Heading4" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#heading5()", () => {
|
||||||
|
it("should add heading style to JSON", () => {
|
||||||
|
paragraph.heading5();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:pStyle": [{ _attr: { "w:val": "Heading5" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#heading6()", () => {
|
||||||
|
it("should add heading style to JSON", () => {
|
||||||
|
paragraph.heading6();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:pStyle": [{ _attr: { "w:val": "Heading6" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("#title()", () => {
|
describe("#title()", () => {
|
||||||
it("should add title style to JSON", () => {
|
it("should add title style to JSON", () => {
|
||||||
paragraph.title();
|
paragraph.title();
|
||||||
@ -114,6 +157,235 @@ describe("Paragraph", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#left()", () => {
|
||||||
|
it("should add left alignment to JSON", () => {
|
||||||
|
paragraph.left();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:jc": [{ _attr: { "w:val": "left" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#right()", () => {
|
||||||
|
it("should add right alignment to JSON", () => {
|
||||||
|
paragraph.right();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:jc": [{ _attr: { "w:val": "right" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#start()", () => {
|
||||||
|
it("should add start alignment to JSON", () => {
|
||||||
|
paragraph.start();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:jc": [{ _attr: { "w:val": "start" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#end()", () => {
|
||||||
|
it("should add end alignment to JSON", () => {
|
||||||
|
paragraph.end();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:jc": [{ _attr: { "w:val": "end" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#distribute()", () => {
|
||||||
|
it("should add distribute alignment to JSON", () => {
|
||||||
|
paragraph.distribute();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:jc": [{ _attr: { "w:val": "distribute" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#justified()", () => {
|
||||||
|
it("should add justified alignment to JSON", () => {
|
||||||
|
paragraph.justified();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:jc": [{ _attr: { "w:val": "both" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#maxRightTabStop()", () => {
|
||||||
|
it("should add maxRightTabStop to JSON", () => {
|
||||||
|
paragraph.maxRightTabStop();
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [
|
||||||
|
{
|
||||||
|
"w:tabs": [
|
||||||
|
{
|
||||||
|
"w:tab": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:pos": 9026,
|
||||||
|
"w:val": "right",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#leftTabStop()", () => {
|
||||||
|
it("should add leftTabStop to JSON", () => {
|
||||||
|
paragraph.leftTabStop(100, LeaderType.HYPHEN);
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [
|
||||||
|
{
|
||||||
|
"w:tabs": [
|
||||||
|
{
|
||||||
|
"w:tab": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:pos": 100,
|
||||||
|
"w:val": "left",
|
||||||
|
"w:leader": "hyphen",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#rightTabStop()", () => {
|
||||||
|
it("should add rightTabStop to JSON", () => {
|
||||||
|
paragraph.rightTabStop(100, LeaderType.DOT);
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [
|
||||||
|
{
|
||||||
|
"w:tabs": [
|
||||||
|
{
|
||||||
|
"w:tab": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:pos": 100,
|
||||||
|
"w:val": "right",
|
||||||
|
"w:leader": "dot",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#centerTabStop()", () => {
|
||||||
|
it("should add centerTabStop to JSON", () => {
|
||||||
|
paragraph.centerTabStop(100, LeaderType.MIDDLE_DOT);
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [
|
||||||
|
{
|
||||||
|
"w:tabs": [
|
||||||
|
{
|
||||||
|
"w:tab": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:pos": 100,
|
||||||
|
"w:val": "center",
|
||||||
|
"w:leader": "middleDot",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#contextualSpacing()", () => {
|
||||||
|
it("should add contextualSpacing to JSON, and set 1 if true", () => {
|
||||||
|
paragraph.contextualSpacing(true);
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:contextualSpacing": [{ _attr: { "w:val": 1 } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should add contextualSpacing to JSON, and set 0 if false", () => {
|
||||||
|
paragraph.contextualSpacing(false);
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:contextualSpacing": [{ _attr: { "w:val": 0 } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("#thematicBreak()", () => {
|
describe("#thematicBreak()", () => {
|
||||||
it("should add thematic break to JSON", () => {
|
it("should add thematic break to JSON", () => {
|
||||||
paragraph.thematicBreak();
|
paragraph.thematicBreak();
|
||||||
@ -394,4 +666,18 @@ describe("Paragraph", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#outlineLevel", () => {
|
||||||
|
it("should set paragraph outline level to the given value", () => {
|
||||||
|
paragraph.outlineLevel("0");
|
||||||
|
const tree = new Formatter().format(paragraph);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:p": [
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:outlineLvl": [{ _attr: { "w:val": "0" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -14,7 +14,7 @@ import { ContextualSpacing, ISpacingProperties, Spacing } from "./formatting/spa
|
|||||||
import { Style } from "./formatting/style";
|
import { Style } from "./formatting/style";
|
||||||
import { CenterTabStop, LeaderType, LeftTabStop, MaxRightTabStop, RightTabStop } from "./formatting/tab-stop";
|
import { CenterTabStop, LeaderType, LeftTabStop, MaxRightTabStop, RightTabStop } from "./formatting/tab-stop";
|
||||||
import { NumberProperties } from "./formatting/unordered-list";
|
import { NumberProperties } from "./formatting/unordered-list";
|
||||||
import { Bookmark, Hyperlink } from "./links";
|
import { Bookmark, Hyperlink, OutlineLevel } from "./links";
|
||||||
import { ParagraphProperties } from "./properties";
|
import { ParagraphProperties } from "./properties";
|
||||||
import { PictureRun, Run, SequentialIdentifier, TextRun } from "./run";
|
import { PictureRun, Run, SequentialIdentifier, TextRun } from "./run";
|
||||||
|
|
||||||
@ -241,13 +241,13 @@ export class Paragraph extends XmlComponent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addTabStop(run: Run): Paragraph {
|
|
||||||
this.root.splice(1, 0, run);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addSequentialIdentifier(identifier: string): Paragraph {
|
public addSequentialIdentifier(identifier: string): Paragraph {
|
||||||
this.root.push(new SequentialIdentifier(identifier));
|
this.root.push(new SequentialIdentifier(identifier));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public outlineLevel(level: string): Paragraph {
|
||||||
|
this.properties.push(new OutlineLevel(level));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
23
src/file/paragraph/run/page-number.spec.ts
Normal file
23
src/file/paragraph/run/page-number.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
|
import { NumberOfPages, Page } from "./page-number";
|
||||||
|
|
||||||
|
describe("Page", () => {
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("uses the font name for both ascii and hAnsi", () => {
|
||||||
|
const tree = new Formatter().format(new Page());
|
||||||
|
expect(tree).to.deep.equal({ "w:instrText": [{ _attr: { "xml:space": "preserve" } }, "PAGE"] });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("NumberOfPages", () => {
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("uses the font name for both ascii and hAnsi", () => {
|
||||||
|
const tree = new Formatter().format(new NumberOfPages());
|
||||||
|
expect(tree).to.deep.equal({ "w:instrText": [{ _attr: { "xml:space": "preserve" } }, "NUMPAGES"] });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -12,3 +12,11 @@ export class Page extends XmlComponent {
|
|||||||
this.root.push("PAGE");
|
this.root.push("PAGE");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class NumberOfPages extends XmlComponent {
|
||||||
|
constructor() {
|
||||||
|
super("w:instrText");
|
||||||
|
this.root.push(new TextAttributes({ space: SpaceType.PRESERVE }));
|
||||||
|
this.root.push("NUMPAGES");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,9 +21,9 @@ describe("Run", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#italic()", () => {
|
describe("#italics()", () => {
|
||||||
it("it should add italics to the properties", () => {
|
it("it should add italics to the properties", () => {
|
||||||
run.italic();
|
run.italics();
|
||||||
const newJson = Utility.jsonify(run);
|
const newJson = Utility.jsonify(run);
|
||||||
assert.equal(newJson.root[0].root[0].rootKey, "w:i");
|
assert.equal(newJson.root[0].root[0].rootKey, "w:i");
|
||||||
assert.equal(newJson.root[0].root[1].rootKey, "w:iCs");
|
assert.equal(newJson.root[0].root[1].rootKey, "w:iCs");
|
||||||
@ -156,6 +156,38 @@ describe("Run", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#numberOfTotalPages", () => {
|
||||||
|
it("should set the run to the RTL mode", () => {
|
||||||
|
run.numberOfTotalPages();
|
||||||
|
const tree = new Formatter().format(run);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:r": [
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:fldChar": [{ _attr: { "w:fldCharType": "begin" } }] },
|
||||||
|
{ "w:instrText": [{ _attr: { "xml:space": "preserve" } }, "NUMPAGES"] },
|
||||||
|
{ "w:fldChar": [{ _attr: { "w:fldCharType": "separate" } }] },
|
||||||
|
{ "w:fldChar": [{ _attr: { "w:fldCharType": "end" } }] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#pageNumber", () => {
|
||||||
|
it("should set the run to the RTL mode", () => {
|
||||||
|
run.pageNumber();
|
||||||
|
const tree = new Formatter().format(run);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:r": [
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:fldChar": [{ _attr: { "w:fldCharType": "begin" } }] },
|
||||||
|
{ "w:instrText": [{ _attr: { "xml:space": "preserve" } }, "PAGE"] },
|
||||||
|
{ "w:fldChar": [{ _attr: { "w:fldCharType": "separate" } }] },
|
||||||
|
{ "w:fldChar": [{ _attr: { "w:fldCharType": "end" } }] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("#style", () => {
|
describe("#style", () => {
|
||||||
it("should set the style to the given styleId", () => {
|
it("should set the style to the given styleId", () => {
|
||||||
run.style("myRunStyle");
|
run.style("myRunStyle");
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
SizeComplexScript,
|
SizeComplexScript,
|
||||||
Strike,
|
Strike,
|
||||||
} from "./formatting";
|
} from "./formatting";
|
||||||
import { Page } from "./page-number";
|
import { NumberOfPages, 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";
|
||||||
@ -39,7 +39,7 @@ export class Run extends XmlComponent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public italic(): Run {
|
public italics(): Run {
|
||||||
this.properties.push(new Italics());
|
this.properties.push(new Italics());
|
||||||
this.properties.push(new ItalicsComplexScript());
|
this.properties.push(new ItalicsComplexScript());
|
||||||
return this;
|
return this;
|
||||||
@ -84,6 +84,14 @@ export class Run extends XmlComponent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public numberOfTotalPages(): Run {
|
||||||
|
this.root.push(new Begin());
|
||||||
|
this.root.push(new NumberOfPages());
|
||||||
|
this.root.push(new Separate());
|
||||||
|
this.root.push(new End());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public smallCaps(): Run {
|
public smallCaps(): Run {
|
||||||
this.properties.push(new SmallCaps());
|
this.properties.push(new SmallCaps());
|
||||||
return this;
|
return this;
|
||||||
|
@ -17,7 +17,9 @@ export type RelationshipType =
|
|||||||
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
||||||
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
|
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
|
||||||
|
|
||||||
export type TargetModeType = "External";
|
export enum TargetModeType {
|
||||||
|
EXTERNAL = "External",
|
||||||
|
}
|
||||||
|
|
||||||
export class Relationship extends XmlComponent {
|
export class Relationship extends XmlComponent {
|
||||||
constructor(id: string, type: RelationshipType, target: string, targetMode?: TargetModeType) {
|
constructor(id: string, type: RelationshipType, target: string, targetMode?: TargetModeType) {
|
||||||
|
24
src/file/settings/compatibility.spec.ts
Normal file
24
src/file/settings/compatibility.spec.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
import { Compatibility } from "file/settings/compatibility";
|
||||||
|
|
||||||
|
describe("Compatibility", () => {
|
||||||
|
describe("#constructor", () => {
|
||||||
|
it("creates an initially empty property object", () => {
|
||||||
|
const compatibility = new Compatibility();
|
||||||
|
|
||||||
|
const tree = new Formatter().format(compatibility);
|
||||||
|
expect(tree).to.deep.equal({ "w:compat": [] });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#doNotExpandShiftReturn", () => {
|
||||||
|
it("should create a setting for not justifying lines ending in soft line break", () => {
|
||||||
|
const compatibility = new Compatibility();
|
||||||
|
compatibility.doNotExpandShiftReturn();
|
||||||
|
|
||||||
|
const tree = new Formatter().format(compatibility);
|
||||||
|
expect(tree).to.deep.equal({ "w:compat": [{ "w:doNotExpandShiftReturn": [] }] });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
19
src/file/settings/compatibility.ts
Normal file
19
src/file/settings/compatibility.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
|
class DoNotExpandShiftReturn extends XmlComponent {
|
||||||
|
constructor() {
|
||||||
|
super("w:doNotExpandShiftReturn");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Compatibility extends XmlComponent {
|
||||||
|
constructor() {
|
||||||
|
super("w:compat");
|
||||||
|
}
|
||||||
|
|
||||||
|
public doNotExpandShiftReturn(): Compatibility {
|
||||||
|
this.root.push(new DoNotExpandShiftReturn());
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -60,4 +60,25 @@ describe("Settings", () => {
|
|||||||
assertSettingsWithUpdateFields(settings);
|
assertSettingsWithUpdateFields(settings);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe("#addCompatibility", () => {
|
||||||
|
it("should add an empty Compatibility", () => {
|
||||||
|
const settings = new Settings();
|
||||||
|
settings.addCompatibility();
|
||||||
|
|
||||||
|
const tree = new Formatter().format(settings);
|
||||||
|
let keys: string[] = Object.keys(tree);
|
||||||
|
expect(keys[0]).to.be.equal("w:settings");
|
||||||
|
const rootArray = tree["w:settings"];
|
||||||
|
expect(rootArray).is.an.instanceof(Array);
|
||||||
|
expect(rootArray).has.length(2);
|
||||||
|
keys = Object.keys(rootArray[0]);
|
||||||
|
expect(keys).is.an.instanceof(Array);
|
||||||
|
expect(keys).has.length(1);
|
||||||
|
expect(keys[0]).to.be.equal("_attr");
|
||||||
|
keys = Object.keys(rootArray[1]);
|
||||||
|
expect(keys).is.an.instanceof(Array);
|
||||||
|
expect(keys).has.length(1);
|
||||||
|
expect(keys[0]).to.be.equal("w:compat");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||||
|
import { Compatibility } from "./compatibility";
|
||||||
import { UpdateFields } from "./update-fields";
|
import { UpdateFields } from "./update-fields";
|
||||||
|
|
||||||
export interface ISettingsAttributesProperties {
|
export interface ISettingsAttributesProperties {
|
||||||
readonly wpc?: string;
|
readonly wpc?: string;
|
||||||
readonly mc?: string;
|
readonly mc?: string;
|
||||||
@ -19,6 +21,7 @@ export interface ISettingsAttributesProperties {
|
|||||||
readonly wps?: string;
|
readonly wps?: string;
|
||||||
readonly Ignorable?: string;
|
readonly Ignorable?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SettingsAttributes extends XmlAttributeComponent<ISettingsAttributesProperties> {
|
export class SettingsAttributes extends XmlAttributeComponent<ISettingsAttributesProperties> {
|
||||||
protected readonly xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
wpc: "xmlns:wpc",
|
wpc: "xmlns:wpc",
|
||||||
@ -40,7 +43,10 @@ export class SettingsAttributes extends XmlAttributeComponent<ISettingsAttribute
|
|||||||
Ignorable: "mc:Ignorable",
|
Ignorable: "mc:Ignorable",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Settings extends XmlComponent {
|
export class Settings extends XmlComponent {
|
||||||
|
private readonly compatibility;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super("w:settings");
|
super("w:settings");
|
||||||
this.root.push(
|
this.root.push(
|
||||||
@ -64,10 +70,20 @@ export class Settings extends XmlComponent {
|
|||||||
Ignorable: "w14 w15 wp14",
|
Ignorable: "w14 w15 wp14",
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
this.compatibility = new Compatibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
public addUpdateFields(): void {
|
public addUpdateFields(): void {
|
||||||
if (!this.root.find((child) => child instanceof UpdateFields)) {
|
if (!this.root.find((child) => child instanceof UpdateFields)) {
|
||||||
this.addChildElement(new UpdateFields());
|
this.addChildElement(new UpdateFields());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addCompatibility(): Compatibility {
|
||||||
|
if (!this.root.find((child) => child instanceof Compatibility)) {
|
||||||
|
this.addChildElement(this.compatibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.compatibility;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ describe("External styles factory", () => {
|
|||||||
const importedStyle = new ExternalStylesFactory().newInstance(externalStyles) as any;
|
const importedStyle = new ExternalStylesFactory().newInstance(externalStyles) as any;
|
||||||
|
|
||||||
expect(importedStyle.rootKey).to.equal("w:styles");
|
expect(importedStyle.rootKey).to.equal("w:styles");
|
||||||
expect(importedStyle.root[0]._attr).to.eql({
|
expect(importedStyle.root[0]._attr).to.deep.equal({
|
||||||
"xmlns:mc": "first",
|
"xmlns:mc": "first",
|
||||||
"xmlns:r": "second",
|
"xmlns:r": "second",
|
||||||
});
|
});
|
||||||
@ -61,7 +61,7 @@ describe("External styles factory", () => {
|
|||||||
it("should parse other child elements of w:styles", () => {
|
it("should parse other child elements of w:styles", () => {
|
||||||
// tslint:disable-next-line:no-any
|
// tslint:disable-next-line:no-any
|
||||||
const importedStyle = new ExternalStylesFactory().newInstance(externalStyles) as any;
|
const importedStyle = new ExternalStylesFactory().newInstance(externalStyles) as any;
|
||||||
expect(importedStyle.root[1]).to.eql({
|
expect(importedStyle.root[1]).to.deep.equal({
|
||||||
deleted: false,
|
deleted: false,
|
||||||
root: [
|
root: [
|
||||||
{
|
{
|
||||||
@ -122,7 +122,7 @@ describe("External styles factory", () => {
|
|||||||
],
|
],
|
||||||
rootKey: "w:docDefaults",
|
rootKey: "w:docDefaults",
|
||||||
});
|
});
|
||||||
expect(importedStyle.root[2]).to.eql({
|
expect(importedStyle.root[2]).to.deep.equal({
|
||||||
_attr: {
|
_attr: {
|
||||||
"w:defLockedState": "1",
|
"w:defLockedState": "1",
|
||||||
"w:defUIPriority": "99",
|
"w:defUIPriority": "99",
|
||||||
@ -138,7 +138,7 @@ describe("External styles factory", () => {
|
|||||||
const importedStyle = new ExternalStylesFactory().newInstance(externalStyles) as any;
|
const importedStyle = new ExternalStylesFactory().newInstance(externalStyles) as any;
|
||||||
|
|
||||||
expect(importedStyle.root.length).to.equal(5);
|
expect(importedStyle.root.length).to.equal(5);
|
||||||
expect(importedStyle.root[3]).to.eql({
|
expect(importedStyle.root[3]).to.deep.equal({
|
||||||
_attr: {
|
_attr: {
|
||||||
"w:default": "1",
|
"w:default": "1",
|
||||||
"w:styleId": "Normal",
|
"w:styleId": "Normal",
|
||||||
@ -163,7 +163,7 @@ describe("External styles factory", () => {
|
|||||||
rootKey: "w:style",
|
rootKey: "w:style",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(importedStyle.root[4]).to.eql({
|
expect(importedStyle.root[4]).to.deep.equal({
|
||||||
_attr: {
|
_attr: {
|
||||||
"w:styleId": "Heading1",
|
"w:styleId": "Heading1",
|
||||||
"w:type": "paragraph",
|
"w:type": "paragraph",
|
||||||
|
346
src/file/styles/style/character-style.spec.ts
Normal file
346
src/file/styles/style/character-style.spec.ts
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
|
import { CharacterStyle } from "./character-style";
|
||||||
|
|
||||||
|
describe("CharacterStyle", () => {
|
||||||
|
describe("#constructor", () => {
|
||||||
|
it("should set the style type to character and use the given style id", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the name of the style, if given", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId", "Style Name");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Style Name" } }] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("formatting methods: style attributes", () => {
|
||||||
|
it("#basedOn", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId").basedOn("otherId");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "otherId" } }] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("formatting methods: run properties", () => {
|
||||||
|
it("#size", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId").size(24);
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:sz": [{ _attr: { "w:val": 24 } }] }, { "w:szCs": [{ _attr: { "w:val": 24 } }] }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#underline", () => {
|
||||||
|
it("should set underline to 'single' if no arguments are given", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId").underline();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:u": [{ _attr: { "w:val": "single" } }] }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the style if given", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId").underline("double");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:u": [{ _attr: { "w:val": "double" } }] }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the style and color if given", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId").underline("double", "005599");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:u": [{ _attr: { "w:val": "double", "w:color": "005599" } }] }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#superScript", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId").superScript();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:vertAlign": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "superscript",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#color", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId").color("123456");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:color": [{ _attr: { "w:val": "123456" } }] }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#bold", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId").bold();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:b": [{ _attr: { "w:val": true } }] }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#italics", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId").italics();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:i": [{ _attr: { "w:val": true } }] }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#link", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId").link("MyLink");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
{ "w:link": [{ _attr: { "w:val": "MyLink" } }] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#semiHidden", () => {
|
||||||
|
const style = new CharacterStyle("myStyleId").semiHidden();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ "w:unhideWhenUsed": [] },
|
||||||
|
{ "w:semiHidden": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
61
src/file/styles/style/character-style.ts
Normal file
61
src/file/styles/style/character-style.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import * as formatting from "file/paragraph/run/formatting";
|
||||||
|
import { RunProperties } from "file/paragraph/run/properties";
|
||||||
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
import { BasedOn, Link, SemiHidden, UiPriority, UnhideWhenUsed } from "./components";
|
||||||
|
import { Style } from "./style";
|
||||||
|
|
||||||
|
export class CharacterStyle extends Style {
|
||||||
|
private readonly runProperties: RunProperties;
|
||||||
|
|
||||||
|
constructor(styleId: string, name?: string) {
|
||||||
|
super({ type: "character", styleId: styleId }, name);
|
||||||
|
this.runProperties = new RunProperties();
|
||||||
|
this.root.push(this.runProperties);
|
||||||
|
this.root.push(new UiPriority("99"));
|
||||||
|
this.root.push(new UnhideWhenUsed());
|
||||||
|
}
|
||||||
|
|
||||||
|
public basedOn(parentId: string): CharacterStyle {
|
||||||
|
this.root.push(new BasedOn(parentId));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addRunProperty(property: XmlComponent): CharacterStyle {
|
||||||
|
this.runProperties.push(property);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public color(color: string): CharacterStyle {
|
||||||
|
return this.addRunProperty(new formatting.Color(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bold(): CharacterStyle {
|
||||||
|
return this.addRunProperty(new formatting.Bold());
|
||||||
|
}
|
||||||
|
|
||||||
|
public italics(): CharacterStyle {
|
||||||
|
return this.addRunProperty(new formatting.Italics());
|
||||||
|
}
|
||||||
|
|
||||||
|
public underline(underlineType?: string, color?: string): CharacterStyle {
|
||||||
|
return this.addRunProperty(new formatting.Underline(underlineType, color));
|
||||||
|
}
|
||||||
|
|
||||||
|
public superScript(): CharacterStyle {
|
||||||
|
return this.addRunProperty(new formatting.SuperScript());
|
||||||
|
}
|
||||||
|
|
||||||
|
public size(twips: number): CharacterStyle {
|
||||||
|
return this.addRunProperty(new formatting.Size(twips)).addRunProperty(new formatting.SizeComplexScript(twips));
|
||||||
|
}
|
||||||
|
|
||||||
|
public link(link: string): CharacterStyle {
|
||||||
|
this.root.push(new Link(link));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public semiHidden(): CharacterStyle {
|
||||||
|
this.root.push(new SemiHidden());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
53
src/file/styles/style/components.spec.ts
Normal file
53
src/file/styles/style/components.spec.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
import * as components from "./components";
|
||||||
|
|
||||||
|
describe("Style components", () => {
|
||||||
|
it("Name#constructor", () => {
|
||||||
|
const style = new components.Name("Style Name");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({ "w:name": [{ _attr: { "w:val": "Style Name" } }] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("BasedOn#constructor", () => {
|
||||||
|
const style = new components.BasedOn("otherId");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({ "w:basedOn": [{ _attr: { "w:val": "otherId" } }] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Next#constructor", () => {
|
||||||
|
const style = new components.Next("otherId");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({ "w:next": [{ _attr: { "w:val": "otherId" } }] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Link#constructor", () => {
|
||||||
|
const style = new components.Link("otherId");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({ "w:link": [{ _attr: { "w:val": "otherId" } }] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("UiPriority#constructor", () => {
|
||||||
|
const style = new components.UiPriority("123");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({ "w:uiPriority": [{ _attr: { "w:val": "123" } }] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("UnhideWhenUsed#constructor", () => {
|
||||||
|
const style = new components.UnhideWhenUsed();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({ "w:unhideWhenUsed": [] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("QuickFormat#constructor", () => {
|
||||||
|
const style = new components.QuickFormat();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({ "w:qFormat": [] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("SemiHidden#constructor", () => {
|
||||||
|
const style = new components.SemiHidden();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({ "w:semiHidden": [] });
|
||||||
|
});
|
||||||
|
});
|
331
src/file/styles/style/default-styles.spec.ts
Normal file
331
src/file/styles/style/default-styles.spec.ts
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
import * as defaultStyels from "./default-styles";
|
||||||
|
|
||||||
|
describe("Default Styles", () => {
|
||||||
|
it("HeadingStyle#constructor", () => {
|
||||||
|
const style = new defaultStyels.HeadingStyle("Heading1", "Heading 1");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "Heading1" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Heading 1" } }] },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:next": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:qFormat": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("TitleStyle#constructor", () => {
|
||||||
|
const style = new defaultStyels.TitleStyle();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "Title" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Title" } }] },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:next": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:qFormat": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Heading1Style#constructor", () => {
|
||||||
|
const style = new defaultStyels.Heading1Style();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "Heading1" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Heading 1" } }] },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:next": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:qFormat": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Heading2Style#constructor", () => {
|
||||||
|
const style = new defaultStyels.Heading2Style();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "Heading2" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Heading 2" } }] },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:next": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:qFormat": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Heading3Style#constructor", () => {
|
||||||
|
const style = new defaultStyels.Heading3Style();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "Heading3" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Heading 3" } }] },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:next": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:qFormat": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Heading4Style#constructor", () => {
|
||||||
|
const style = new defaultStyels.Heading4Style();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "Heading4" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Heading 4" } }] },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:next": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:qFormat": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Heading5Style#constructor", () => {
|
||||||
|
const style = new defaultStyels.Heading5Style();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "Heading5" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Heading 5" } }] },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:next": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:qFormat": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Heading6Style#constructor", () => {
|
||||||
|
const style = new defaultStyels.Heading6Style();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "Heading6" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Heading 6" } }] },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:next": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:qFormat": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ListParagraph#constructor", () => {
|
||||||
|
const style = new defaultStyels.ListParagraph();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "ListParagraph" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "List Paragraph" } }] },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:qFormat": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("FootnoteText#constructor", () => {
|
||||||
|
const style = new defaultStyels.FootnoteText();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "FootnoteText" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "footnote text" } }] },
|
||||||
|
{
|
||||||
|
"w:pPr": [
|
||||||
|
{
|
||||||
|
"w:spacing": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:after": 0,
|
||||||
|
"w:line": 240,
|
||||||
|
"w:lineRule": "auto",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:sz": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:szCs": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "Normal" } }] },
|
||||||
|
{ "w:link": [{ _attr: { "w:val": "FootnoteTextChar" } }] },
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:semiHidden": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("FootnoteReferenceStyle#constructor", () => {
|
||||||
|
const style = new defaultStyels.FootnoteReferenceStyle();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "FootnoteReference" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "footnote reference" } }] },
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:vertAlign": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "superscript",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "DefaultParagraphFont" } }] },
|
||||||
|
|
||||||
|
{
|
||||||
|
"w:semiHidden": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("FootnoteTextChar#constructor", () => {
|
||||||
|
const style = new defaultStyels.FootnoteTextChar();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "FootnoteTextChar" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Footnote Text Char" } }] },
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:sz": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:szCs": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "DefaultParagraphFont" } }] },
|
||||||
|
{ "w:link": [{ _attr: { "w:val": "FootnoteText" } }] },
|
||||||
|
{
|
||||||
|
"w:semiHidden": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("HyperlinkStyle#constructor", () => {
|
||||||
|
const style = new defaultStyels.HyperlinkStyle();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "Hyperlink" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Hyperlink" } }] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:color": [{ _attr: { "w:val": "0563C1" } }] }, { "w:u": [{ _attr: { "w:val": "single" } }] }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": [],
|
||||||
|
},
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "DefaultParagraphFont" } }] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
106
src/file/styles/style/default-styles.ts
Normal file
106
src/file/styles/style/default-styles.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { CharacterStyle } from "./character-style";
|
||||||
|
import { ParagraphStyle } from "./paragraph-style";
|
||||||
|
|
||||||
|
export class HeadingStyle extends ParagraphStyle {
|
||||||
|
constructor(styleId: string, name: string) {
|
||||||
|
super(styleId, name);
|
||||||
|
this.basedOn("Normal");
|
||||||
|
this.next("Normal");
|
||||||
|
this.quickFormat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TitleStyle extends HeadingStyle {
|
||||||
|
constructor() {
|
||||||
|
super("Title", "Title");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Heading1Style extends HeadingStyle {
|
||||||
|
constructor() {
|
||||||
|
super("Heading1", "Heading 1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Heading2Style extends HeadingStyle {
|
||||||
|
constructor() {
|
||||||
|
super("Heading2", "Heading 2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Heading3Style extends HeadingStyle {
|
||||||
|
constructor() {
|
||||||
|
super("Heading3", "Heading 3");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Heading4Style extends HeadingStyle {
|
||||||
|
constructor() {
|
||||||
|
super("Heading4", "Heading 4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Heading5Style extends HeadingStyle {
|
||||||
|
constructor() {
|
||||||
|
super("Heading5", "Heading 5");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Heading6Style extends HeadingStyle {
|
||||||
|
constructor() {
|
||||||
|
super("Heading6", "Heading 6");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ListParagraph extends ParagraphStyle {
|
||||||
|
constructor() {
|
||||||
|
super("ListParagraph", "List Paragraph");
|
||||||
|
this.basedOn("Normal");
|
||||||
|
this.quickFormat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FootnoteText extends ParagraphStyle {
|
||||||
|
constructor() {
|
||||||
|
super("FootnoteText", "footnote text");
|
||||||
|
this.basedOn("Normal")
|
||||||
|
.link("FootnoteTextChar")
|
||||||
|
.uiPriority("99")
|
||||||
|
.semiHidden()
|
||||||
|
.unhideWhenUsed()
|
||||||
|
.spacing({
|
||||||
|
after: 0,
|
||||||
|
line: 240,
|
||||||
|
lineRule: "auto",
|
||||||
|
})
|
||||||
|
.size(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FootnoteReferenceStyle extends CharacterStyle {
|
||||||
|
constructor() {
|
||||||
|
super("FootnoteReference", "footnote reference");
|
||||||
|
this.basedOn("DefaultParagraphFont")
|
||||||
|
.semiHidden()
|
||||||
|
.superScript();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FootnoteTextChar extends CharacterStyle {
|
||||||
|
constructor() {
|
||||||
|
super("FootnoteTextChar", "Footnote Text Char");
|
||||||
|
this.basedOn("DefaultParagraphFont")
|
||||||
|
.link("FootnoteText")
|
||||||
|
.semiHidden()
|
||||||
|
.size(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class HyperlinkStyle extends CharacterStyle {
|
||||||
|
constructor() {
|
||||||
|
super("Hyperlink", "Hyperlink");
|
||||||
|
this.basedOn("DefaultParagraphFont")
|
||||||
|
.color("0563C1")
|
||||||
|
.underline("single");
|
||||||
|
}
|
||||||
|
}
|
@ -1,335 +1,4 @@
|
|||||||
import {
|
export * from "./style";
|
||||||
Alignment,
|
export * from "./paragraph-style";
|
||||||
AlignmentOptions,
|
export * from "./character-style";
|
||||||
Indent,
|
export * from "./default-styles";
|
||||||
ISpacingProperties,
|
|
||||||
KeepLines,
|
|
||||||
KeepNext,
|
|
||||||
LeftTabStop,
|
|
||||||
MaxRightTabStop,
|
|
||||||
ParagraphProperties,
|
|
||||||
Spacing,
|
|
||||||
ThematicBreak,
|
|
||||||
} from "file/paragraph";
|
|
||||||
import * as formatting from "file/paragraph/run/formatting";
|
|
||||||
import { RunProperties } from "file/paragraph/run/properties";
|
|
||||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
|
||||||
|
|
||||||
import { BasedOn, Link, Name, Next, QuickFormat, SemiHidden, UiPriority, UnhideWhenUsed } from "./components";
|
|
||||||
|
|
||||||
export interface IStyleAttributes {
|
|
||||||
readonly type?: string;
|
|
||||||
readonly styleId?: string;
|
|
||||||
readonly default?: boolean;
|
|
||||||
readonly customStyle?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
class StyleAttributes extends XmlAttributeComponent<IStyleAttributes> {
|
|
||||||
protected readonly xmlKeys = {
|
|
||||||
type: "w:type",
|
|
||||||
styleId: "w:styleId",
|
|
||||||
default: "w:default",
|
|
||||||
customStyle: "w:customStyle",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Style extends XmlComponent {
|
|
||||||
constructor(attributes: IStyleAttributes, name?: string) {
|
|
||||||
super("w:style");
|
|
||||||
this.root.push(new StyleAttributes(attributes));
|
|
||||||
if (name) {
|
|
||||||
this.root.push(new Name(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public push(styleSegment: XmlComponent): void {
|
|
||||||
this.root.push(styleSegment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ParagraphStyle extends Style {
|
|
||||||
private readonly paragraphProperties: ParagraphProperties;
|
|
||||||
private readonly runProperties: RunProperties;
|
|
||||||
|
|
||||||
constructor(styleId: string, name?: string) {
|
|
||||||
super({ type: "paragraph", styleId: styleId }, name);
|
|
||||||
this.paragraphProperties = new ParagraphProperties();
|
|
||||||
this.runProperties = new RunProperties();
|
|
||||||
this.root.push(this.paragraphProperties);
|
|
||||||
this.root.push(this.runProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
public addParagraphProperty(property: XmlComponent): ParagraphStyle {
|
|
||||||
this.paragraphProperties.push(property);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addRunProperty(property: XmlComponent): ParagraphStyle {
|
|
||||||
this.runProperties.push(property);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public basedOn(parentId: string): ParagraphStyle {
|
|
||||||
this.root.push(new BasedOn(parentId));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public quickFormat(): ParagraphStyle {
|
|
||||||
this.root.push(new QuickFormat());
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public next(nextId: string): ParagraphStyle {
|
|
||||||
this.root.push(new Next(nextId));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------- Run formatting ---------------------- //
|
|
||||||
|
|
||||||
public size(twips: number): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.Size(twips)).addRunProperty(new formatting.SizeComplexScript(twips));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bold(): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.Bold());
|
|
||||||
}
|
|
||||||
|
|
||||||
public italics(): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.Italics());
|
|
||||||
}
|
|
||||||
|
|
||||||
public smallCaps(): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.SmallCaps());
|
|
||||||
}
|
|
||||||
|
|
||||||
public allCaps(): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.Caps());
|
|
||||||
}
|
|
||||||
|
|
||||||
public strike(): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.Strike());
|
|
||||||
}
|
|
||||||
|
|
||||||
public doubleStrike(): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.DoubleStrike());
|
|
||||||
}
|
|
||||||
|
|
||||||
public subScript(): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.SubScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
public superScript(): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.SuperScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
public underline(underlineType?: string, color?: string): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.Underline(underlineType, color));
|
|
||||||
}
|
|
||||||
|
|
||||||
public color(color: string): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.Color(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
public font(fontName: string): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.RunFonts(fontName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public characterSpacing(value: number): ParagraphStyle {
|
|
||||||
return this.addRunProperty(new formatting.CharacterSpacing(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------- Paragraph formatting ------------------------ //
|
|
||||||
|
|
||||||
public center(): ParagraphStyle {
|
|
||||||
return this.addParagraphProperty(new Alignment(AlignmentOptions.CENTER));
|
|
||||||
}
|
|
||||||
|
|
||||||
public left(): ParagraphStyle {
|
|
||||||
return this.addParagraphProperty(new Alignment(AlignmentOptions.LEFT));
|
|
||||||
}
|
|
||||||
|
|
||||||
public right(): ParagraphStyle {
|
|
||||||
return this.addParagraphProperty(new Alignment(AlignmentOptions.RIGHT));
|
|
||||||
}
|
|
||||||
|
|
||||||
public justified(): ParagraphStyle {
|
|
||||||
return this.addParagraphProperty(new Alignment(AlignmentOptions.BOTH));
|
|
||||||
}
|
|
||||||
|
|
||||||
public thematicBreak(): ParagraphStyle {
|
|
||||||
return this.addParagraphProperty(new ThematicBreak());
|
|
||||||
}
|
|
||||||
|
|
||||||
public maxRightTabStop(): ParagraphStyle {
|
|
||||||
return this.addParagraphProperty(new MaxRightTabStop());
|
|
||||||
}
|
|
||||||
|
|
||||||
public leftTabStop(position: number): ParagraphStyle {
|
|
||||||
return this.addParagraphProperty(new LeftTabStop(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
public indent(attrs: object): ParagraphStyle {
|
|
||||||
return this.addParagraphProperty(new Indent(attrs));
|
|
||||||
}
|
|
||||||
|
|
||||||
public spacing(params: ISpacingProperties): ParagraphStyle {
|
|
||||||
return this.addParagraphProperty(new Spacing(params));
|
|
||||||
}
|
|
||||||
|
|
||||||
public keepNext(): ParagraphStyle {
|
|
||||||
return this.addParagraphProperty(new KeepNext());
|
|
||||||
}
|
|
||||||
|
|
||||||
public keepLines(): ParagraphStyle {
|
|
||||||
return this.addParagraphProperty(new KeepLines());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HeadingStyle extends ParagraphStyle {
|
|
||||||
constructor(styleId: string, name: string) {
|
|
||||||
super(styleId, name);
|
|
||||||
this.basedOn("Normal");
|
|
||||||
this.next("Normal");
|
|
||||||
this.quickFormat();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TitleStyle extends HeadingStyle {
|
|
||||||
constructor() {
|
|
||||||
super("Title", "Title");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Heading1Style extends HeadingStyle {
|
|
||||||
constructor() {
|
|
||||||
super("Heading1", "Heading 1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Heading2Style extends HeadingStyle {
|
|
||||||
constructor() {
|
|
||||||
super("Heading2", "Heading 2");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Heading3Style extends HeadingStyle {
|
|
||||||
constructor() {
|
|
||||||
super("Heading3", "Heading 3");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Heading4Style extends HeadingStyle {
|
|
||||||
constructor() {
|
|
||||||
super("Heading4", "Heading 4");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Heading5Style extends HeadingStyle {
|
|
||||||
constructor() {
|
|
||||||
super("Heading5", "Heading 5");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Heading6Style extends HeadingStyle {
|
|
||||||
constructor() {
|
|
||||||
super("Heading6", "Heading 6");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ListParagraph extends ParagraphStyle {
|
|
||||||
constructor() {
|
|
||||||
super("ListParagraph");
|
|
||||||
this.root.push(new Name("List Paragraph"));
|
|
||||||
this.root.push(new BasedOn("Normal"));
|
|
||||||
this.root.push(new QuickFormat());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CharacterStyle extends Style {
|
|
||||||
private readonly runProperties: RunProperties;
|
|
||||||
|
|
||||||
constructor(styleId: string, name?: string) {
|
|
||||||
super({ type: "character", styleId: styleId }, name);
|
|
||||||
this.runProperties = new RunProperties();
|
|
||||||
this.root.push(this.runProperties);
|
|
||||||
this.root.push(new UiPriority("99"));
|
|
||||||
this.root.push(new UnhideWhenUsed());
|
|
||||||
}
|
|
||||||
|
|
||||||
public basedOn(parentId: string): CharacterStyle {
|
|
||||||
this.root.push(new BasedOn(parentId));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addRunProperty(property: XmlComponent): CharacterStyle {
|
|
||||||
this.runProperties.push(property);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public color(color: string): CharacterStyle {
|
|
||||||
return this.addRunProperty(new formatting.Color(color));
|
|
||||||
}
|
|
||||||
|
|
||||||
public underline(underlineType?: string, color?: string): CharacterStyle {
|
|
||||||
return this.addRunProperty(new formatting.Underline(underlineType, color));
|
|
||||||
}
|
|
||||||
|
|
||||||
public size(twips: number): CharacterStyle {
|
|
||||||
return this.addRunProperty(new formatting.Size(twips)).addRunProperty(new formatting.SizeComplexScript(twips));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HyperlinkStyle extends CharacterStyle {
|
|
||||||
constructor() {
|
|
||||||
super("Hyperlink", "Hyperlink");
|
|
||||||
this.basedOn("DefaultParagraphFont")
|
|
||||||
.color("0563C1")
|
|
||||||
.underline("single");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FootnoteReferenceStyle extends Style {
|
|
||||||
private readonly runProperties: RunProperties;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super({ type: "character", styleId: "FootnoteReference" });
|
|
||||||
this.root.push(new Name("footnote reference"));
|
|
||||||
this.root.push(new BasedOn("DefaultParagraphFont"));
|
|
||||||
this.root.push(new UiPriority("99"));
|
|
||||||
this.root.push(new SemiHidden());
|
|
||||||
this.root.push(new UnhideWhenUsed());
|
|
||||||
|
|
||||||
this.runProperties = new RunProperties();
|
|
||||||
this.runProperties.addChildElement(new formatting.SuperScript());
|
|
||||||
this.root.push(this.runProperties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FootnoteText extends ParagraphStyle {
|
|
||||||
constructor() {
|
|
||||||
super("FootnoteText");
|
|
||||||
this.root.push(new Name("footnote text"));
|
|
||||||
this.root.push(new BasedOn("Normal"));
|
|
||||||
this.root.push(new Link("FootnoteTextChar"));
|
|
||||||
this.root.push(new UiPriority("99"));
|
|
||||||
this.root.push(new SemiHidden());
|
|
||||||
this.root.push(new UnhideWhenUsed());
|
|
||||||
this.spacing({
|
|
||||||
after: 0,
|
|
||||||
line: 240,
|
|
||||||
lineRule: "auto",
|
|
||||||
});
|
|
||||||
this.size(20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FootnoteTextChar extends CharacterStyle {
|
|
||||||
constructor() {
|
|
||||||
super("FootnoteTextChar", "Footnote Text Char");
|
|
||||||
this.basedOn("DefaultParagraphFont");
|
|
||||||
this.root.push(new Link("FootnoteText"));
|
|
||||||
this.root.push(new UiPriority("99"));
|
|
||||||
this.root.push(new SemiHidden());
|
|
||||||
this.size(20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
536
src/file/styles/style/paragraph-style.spec.ts
Normal file
536
src/file/styles/style/paragraph-style.spec.ts
Normal file
@ -0,0 +1,536 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
|
import { ParagraphStyle } from "./paragraph-style";
|
||||||
|
|
||||||
|
describe("ParagraphStyle", () => {
|
||||||
|
describe("#constructor", () => {
|
||||||
|
it("should set the style type to paragraph and use the given style id", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:pPr": [] }, { "w:rPr": [] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the name of the style, if given", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId", "Style Name");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:name": [{ _attr: { "w:val": "Style Name" } }] },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("formatting methods: style attributes", () => {
|
||||||
|
it("#basedOn", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").basedOn("otherId");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:basedOn": [{ _attr: { "w:val": "otherId" } }] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#quickFormat", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").quickFormat();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:qFormat": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#next", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").next("otherId");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:next": [{ _attr: { "w:val": "otherId" } }] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("formatting methods: paragraph properties", () => {
|
||||||
|
it("#indent", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").indent({ left: 720 });
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:ind": [{ _attr: { "w:left": 720 } }] }],
|
||||||
|
},
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#spacing", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").spacing({ before: 50, after: 150 });
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:spacing": [{ _attr: { "w:before": 50, "w:after": 150 } }] }],
|
||||||
|
},
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#center", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").center();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:jc": [{ _attr: { "w:val": "center" } }] }],
|
||||||
|
},
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#character spacing", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").characterSpacing(24);
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:spacing": [{ _attr: { "w:val": 24 } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#left", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").left();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:jc": [{ _attr: { "w:val": "left" } }] }],
|
||||||
|
},
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#right", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").right();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:jc": [{ _attr: { "w:val": "right" } }] }],
|
||||||
|
},
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#justified", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").justified();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:pPr": [{ "w:jc": [{ _attr: { "w:val": "both" } }] }],
|
||||||
|
},
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#thematicBreak", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").thematicBreak();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:pPr": [
|
||||||
|
{
|
||||||
|
"w:pBdr": [
|
||||||
|
{
|
||||||
|
"w:bottom": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:color": "auto",
|
||||||
|
"w:space": "1",
|
||||||
|
"w:val": "single",
|
||||||
|
"w:sz": "6",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#leftTabStop", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").leftTabStop(1200);
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:pPr": [
|
||||||
|
{
|
||||||
|
"w:tabs": [{ "w:tab": [{ _attr: { "w:val": "left", "w:pos": 1200 } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#maxRightTabStop", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").maxRightTabStop();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:pPr": [
|
||||||
|
{
|
||||||
|
"w:tabs": [{ "w:tab": [{ _attr: { "w:val": "right", "w:pos": 9026 } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#keepLines", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").keepLines();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [{ "w:keepLines": [] }] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#keepNext", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").keepNext();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [{ "w:keepNext": [] }] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#outlineLevel", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").outlineLevel("1");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [{ "w:outlineLvl": [{ _attr: { "w:val": "1" } }] }] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("formatting methods: run properties", () => {
|
||||||
|
it("#size", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").size(24);
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:sz": [{ _attr: { "w:val": 24 } }] }, { "w:szCs": [{ _attr: { "w:val": 24 } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#smallCaps", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").smallCaps();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:smallCaps": [{ _attr: { "w:val": true } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#allCaps", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").allCaps();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:caps": [{ _attr: { "w:val": true } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#strike", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").strike();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:strike": [{ _attr: { "w:val": true } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#doubleStrike", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").doubleStrike();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:dstrike": [{ _attr: { "w:val": true } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#subScript", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").subScript();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:vertAlign": [{ _attr: { "w:val": "subscript" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#superScript", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").superScript();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:vertAlign": [{ _attr: { "w:val": "superscript" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#font", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").font("Times");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{ "w:rFonts": [{ _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } }] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#bold", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").bold();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:b": [{ _attr: { "w:val": true } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#italics", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").italics();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:i": [{ _attr: { "w:val": true } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#underline", () => {
|
||||||
|
it("should set underline to 'single' if no arguments are given", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").underline();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:u": [{ _attr: { "w:val": "single" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the style if given", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").underline("double");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:u": [{ _attr: { "w:val": "double" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the style and color if given", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").underline("double", "005599");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:u": [{ _attr: { "w:val": "double", "w:color": "005599" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#color", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").color("123456");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:color": [{ _attr: { "w:val": "123456" } }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#link", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").link("MyLink");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:link": [{ _attr: { "w:val": "MyLink" } }] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#semiHidden", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").semiHidden();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:semiHidden": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#uiPriority", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").uiPriority("99");
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{
|
||||||
|
"w:uiPriority": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:val": "99",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("#unhideWhenUsed", () => {
|
||||||
|
const style = new ParagraphStyle("myStyleId").unhideWhenUsed();
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{ "w:rPr": [] },
|
||||||
|
{ "w:unhideWhenUsed": [] },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user