Compare commits
157 Commits
Author | SHA1 | Date | |
---|---|---|---|
a37ff90bd7 | |||
9998ddfcc9 | |||
12ed54c9fd | |||
3a1a21e498 | |||
e5bfa99b92 | |||
f640f17fa6 | |||
494a32d45d | |||
8040a455be | |||
f091cff7c9 | |||
401ef7336b | |||
18134519be | |||
7980f14efb | |||
40d6a41305 | |||
9cfd835171 | |||
95a9f592eb | |||
61411fd0f3 | |||
a84eb16392 | |||
3355a6f472 | |||
071a8ea9f7 | |||
ea3777d28b | |||
3346b97ee7 | |||
2b834a75a8 | |||
21df53d547 | |||
9143c1c2c1 | |||
83cab7563d | |||
b05fbe7f6e | |||
e6a57738f4 | |||
cc6e35165a | |||
7791ddf76e | |||
4742cf0f3f | |||
8858970491 | |||
f7d18bfead | |||
0ce1b7fa15 | |||
4633592711 | |||
54697ab6b1 | |||
1eed844b9a | |||
dd89fe2463 | |||
9c66db97ff | |||
fea6afdfe4 | |||
6ec2e742ef | |||
3f80b054fc | |||
96d81873d8 | |||
c429ae9920 | |||
6b4e769f48 | |||
b67a9de0e9 | |||
ac9f65a068 | |||
7e8ebb2af2 | |||
f53fe2f881 | |||
6fdd88527a | |||
b6f431e14d | |||
23dee01f06 | |||
5532f91423 | |||
c849d5f3e5 | |||
3f3fd05cb1 | |||
a5bedf9a5b | |||
9d9dd62f00 | |||
a466578467 | |||
3a9420fedf | |||
8ac19a83b2 | |||
9f0b2f7074 | |||
e02ac43c07 | |||
97f76fb62c | |||
3508fd97ec | |||
90f6f68693 | |||
733775d3b9 | |||
f3aa6a9203 | |||
ffdcc7baca | |||
a1e20f4c9a | |||
ccffdad4c0 | |||
2fb5845501 | |||
ddd84a1765 | |||
048ae6a58c | |||
fafa54e4c9 | |||
60dbb32e9e | |||
52b07fd9cb | |||
f6a13aed86 | |||
2da3ba0262 | |||
e08c7cbbfb | |||
a6de5d8a21 | |||
8ec5bc05e0 | |||
6e0c12afb3 | |||
466e880bfc | |||
00a20b7cfc | |||
f27c95191b | |||
c140d2c37c | |||
3a42f2a2f0 | |||
00efedaa09 | |||
72e3d229dc | |||
b12d6ef484 | |||
8ee6fd3e67 | |||
808c5b00a0 | |||
4de6b51e76 | |||
0a8feca6ab | |||
4ca81df401 | |||
8b463b3bb6 | |||
17d696e33a | |||
2f59867db6 | |||
bf1f702e5a | |||
1cff104bae | |||
4805efad2e | |||
12e2ae9e91 | |||
c07b5cf709 | |||
0684738ec2 | |||
f2b50478bf | |||
fc71ebdfef | |||
10114bb12d | |||
7cd8864fb9 | |||
e6d4741955 | |||
4d7387524c | |||
5fe4405d76 | |||
baf0f17bd6 | |||
8e911698a5 | |||
0eb36be053 | |||
79dffc873a | |||
26ee12759c | |||
2e00634bc4 | |||
d63e6bf6b1 | |||
a95366e54e | |||
1c376abeb6 | |||
353d888abd | |||
b6bd532295 | |||
c5b004166d | |||
2f43600daf | |||
b39c7ce323 | |||
5b00279996 | |||
d1d1e01aff | |||
980bc597e2 | |||
a05c5edd49 | |||
985452f5f4 | |||
482674b3b3 | |||
fcbfed9068 | |||
a9167b4809 | |||
f1b176670c | |||
11ce9a5206 | |||
146d0ad9e5 | |||
385ad92331 | |||
571f8b526b | |||
7688aa99f6 | |||
4994bca34c | |||
1a3603dbfb | |||
aedfca377f | |||
7926f6c189 | |||
e9a007d446 | |||
e382dbff84 | |||
e08be3d7a4 | |||
03c4190c2c | |||
12c1f82efe | |||
b1711ae293 | |||
a367951d07 | |||
c55f82c425 | |||
d1044d262e | |||
010fde6258 | |||
8d83219bb6 | |||
a710483918 | |||
4f8ecf631b | |||
a6a8012b39 | |||
d5b6225a90 |
6
.gitignore
vendored
6
.gitignore
vendored
@ -57,3 +57,9 @@ yarn.lock
|
|||||||
|
|
||||||
# Documents
|
# Documents
|
||||||
My Document.docx
|
My Document.docx
|
||||||
|
|
||||||
|
# Temporary folder
|
||||||
|
tmp
|
||||||
|
|
||||||
|
# nyc
|
||||||
|
.nyc_output
|
||||||
|
25
.nycrc
Normal file
25
.nycrc
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"check-coverage": true,
|
||||||
|
"lines": 87.54,
|
||||||
|
"functions": 83.61,
|
||||||
|
"branches": 72.57,
|
||||||
|
"statements": 87.32,
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"src/**/*.spec.ts"
|
||||||
|
],
|
||||||
|
"reporter": [
|
||||||
|
"lcov",
|
||||||
|
"text",
|
||||||
|
"json"
|
||||||
|
],
|
||||||
|
"extension": [
|
||||||
|
".ts"
|
||||||
|
],
|
||||||
|
"cache": true,
|
||||||
|
"all": true,
|
||||||
|
"instrument": false,
|
||||||
|
"sourceMap": true
|
||||||
|
}
|
14
.travis.yml
14
.travis.yml
@ -3,9 +3,10 @@ node_js:
|
|||||||
- 9
|
- 9
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm install
|
||||||
|
- npm install -g codecov
|
||||||
script:
|
script:
|
||||||
- npm run lint
|
- npm run lint
|
||||||
- npm test
|
- npm run test.coverage
|
||||||
- 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
|
||||||
@ -32,12 +33,23 @@ script:
|
|||||||
- npm run ts-node -- ./demo/demo22.ts
|
- npm run ts-node -- ./demo/demo22.ts
|
||||||
- npm run ts-node -- ./demo/demo23.ts
|
- npm run ts-node -- ./demo/demo23.ts
|
||||||
- npm run ts-node -- ./demo/demo24.ts
|
- npm run ts-node -- ./demo/demo24.ts
|
||||||
|
# - npm run ts-node -- ./demo/demo25.ts
|
||||||
|
- npm run ts-node -- ./demo/demo26.ts
|
||||||
|
- npm run ts-node -- ./demo/demo27.ts
|
||||||
|
- npm run ts-node -- ./demo/demo28.ts
|
||||||
|
- npm run ts-node -- ./demo/demo29.ts
|
||||||
|
- npm run ts-node -- ./demo/demo30.ts
|
||||||
|
- npm run ts-node -- ./demo/demo31.ts
|
||||||
|
- npm run ts-node -- ./demo/demo32.ts
|
||||||
|
- npm run ts-node -- ./demo/demo33.ts
|
||||||
|
- npm run ts-node -- ./demo/demo34.ts
|
||||||
after_failure:
|
after_failure:
|
||||||
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
|
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
|
||||||
after_success:
|
after_success:
|
||||||
- npm run typedoc
|
- npm run typedoc
|
||||||
- echo "docx.js.org" > docs/.nojekyll
|
- echo "docx.js.org" > docs/.nojekyll
|
||||||
- echo "docx.js.org" > docs/CNAME
|
- echo "docx.js.org" > docs/CNAME
|
||||||
|
- codecov
|
||||||
deploy:
|
deploy:
|
||||||
provider: pages
|
provider: pages
|
||||||
skip-cleanup: true
|
skip-cleanup: true
|
||||||
|
24
.vscode/tasks.json
vendored
Normal file
24
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "typescript",
|
||||||
|
"tsconfig": "tsconfig.json",
|
||||||
|
"option": "watch",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$tsc-watch"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "ts-node",
|
||||||
|
"problemMatcher": [],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -15,6 +15,7 @@
|
|||||||
[![Known Vulnerabilities][snky-image]][snky-url]
|
[![Known Vulnerabilities][snky-image]][snky-url]
|
||||||
[![Chat on Gitter][gitter-image]][gitter-url]
|
[![Chat on Gitter][gitter-image]][gitter-url]
|
||||||
[![PRs Welcome][pr-image]][pr-url]
|
[![PRs Welcome][pr-image]][pr-url]
|
||||||
|
[![codecov][codecov-image]][codecov-url]
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://i.imgur.com/H5FA1Qy.gif" alt="drawing" width="800"/>
|
<img src="https://i.imgur.com/H5FA1Qy.gif" alt="drawing" width="800"/>
|
||||||
@ -29,6 +30,10 @@ Here are examples of `docx` being used with basic `HTML/JS` in a browser environ
|
|||||||
* https://codepen.io/anon/pen/dqoVgQ
|
* https://codepen.io/anon/pen/dqoVgQ
|
||||||
* https://jsfiddle.net/3xhezb5w/2
|
* https://jsfiddle.net/3xhezb5w/2
|
||||||
|
|
||||||
|
Here is an example of `docx` working in `Angular`:
|
||||||
|
|
||||||
|
* https://stackblitz.com/edit/angular-afvxtz
|
||||||
|
|
||||||
## Node
|
## Node
|
||||||
|
|
||||||
Press `endpoint` on the `RunKit` website:
|
Press `endpoint` on the `RunKit` website:
|
||||||
@ -77,3 +82,5 @@ Made with 💖
|
|||||||
[gitter-url]: https://gitter.im/docx-lib/Lobby
|
[gitter-url]: https://gitter.im/docx-lib/Lobby
|
||||||
[pr-image]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
|
[pr-image]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
|
||||||
[pr-url]: http://makeapullrequest.com
|
[pr-url]: http://makeapullrequest.com
|
||||||
|
[codecov-image]: https://codecov.io/gh/dolanmiu/docx/branch/master/graph/badge.svg
|
||||||
|
[codecov-url]: https://codecov.io/gh/dolanmiu/docx
|
||||||
|
@ -15,8 +15,12 @@ const footer = doc.createFooter();
|
|||||||
footer.createParagraph("Footer on another page");
|
footer.createParagraph("Footer on another page");
|
||||||
|
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
headerId: header.Header.ReferenceId,
|
headers: {
|
||||||
footerId: footer.Footer.ReferenceId,
|
default: header,
|
||||||
|
},
|
||||||
|
footers: {
|
||||||
|
default: footer,
|
||||||
|
},
|
||||||
pageNumberStart: 1,
|
pageNumberStart: 1,
|
||||||
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
||||||
});
|
});
|
||||||
@ -24,8 +28,12 @@ doc.addSection({
|
|||||||
doc.createParagraph("hello");
|
doc.createParagraph("hello");
|
||||||
|
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
headerId: header.Header.ReferenceId,
|
headers: {
|
||||||
footerId: footer.Footer.ReferenceId,
|
default: header,
|
||||||
|
},
|
||||||
|
footers: {
|
||||||
|
default: footer,
|
||||||
|
},
|
||||||
pageNumberStart: 1,
|
pageNumberStart: 1,
|
||||||
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
||||||
orientation: PageOrientation.LANDSCAPE,
|
orientation: PageOrientation.LANDSCAPE,
|
||||||
|
@ -8,11 +8,11 @@ const doc = new Document();
|
|||||||
const paragraph = new Paragraph("Hello World");
|
const paragraph = new Paragraph("Hello World");
|
||||||
doc.addParagraph(paragraph);
|
doc.addParagraph(paragraph);
|
||||||
|
|
||||||
const image = Media.addImage(doc, "./demo/images/image1.jpeg");
|
const image = Media.addImage(doc, fs.readFileSync("./demo/images/image1.jpeg"));
|
||||||
const image2 = Media.addImage(doc, "./demo/images/dog.png");
|
const image2 = Media.addImage(doc, fs.readFileSync("./demo/images/dog.png"));
|
||||||
const image3 = Media.addImage(doc, "./demo/images/cat.jpg");
|
const image3 = Media.addImage(doc, fs.readFileSync("./demo/images/cat.jpg"));
|
||||||
const image4 = Media.addImage(doc, "./demo/images/parrots.bmp");
|
const image4 = Media.addImage(doc, fs.readFileSync("./demo/images/parrots.bmp"));
|
||||||
const image5 = Media.addImage(doc, "./demo/images/pizza.gif");
|
const image5 = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
|
||||||
|
|
||||||
const imageBase64Data = `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`;
|
const imageBase64Data = `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`;
|
||||||
const image6 = Media.addImage(doc, Buffer.from(imageBase64Data, "base64"), 100, 100);
|
const image6 = Media.addImage(doc, Buffer.from(imageBase64Data, "base64"), 100, 100);
|
||||||
|
@ -8,7 +8,7 @@ const doc = new Document();
|
|||||||
const table = doc.createTable(4, 4);
|
const table = doc.createTable(4, 4);
|
||||||
table.getCell(2, 2).addContent(new Paragraph("Hello"));
|
table.getCell(2, 2).addContent(new Paragraph("Hello"));
|
||||||
|
|
||||||
const image = Media.addImage(doc, "./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).addContent(image.Paragraph);
|
||||||
|
|
||||||
const packer = new Packer();
|
const packer = new Packer();
|
||||||
|
@ -30,5 +30,4 @@ const packer = new Packer();
|
|||||||
|
|
||||||
packer.toBuffer(doc).then((buffer) => {
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
fs.writeFileSync("My Document.docx", buffer);
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
console.log("Document created successfully at project root!");
|
|
||||||
});
|
});
|
||||||
|
43
demo/demo28.ts
Normal file
43
demo/demo28.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Creates two paragraphs, one with a border and one without
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { File, Packer, Paragraph, StyleLevel, TableOfContents } from "../build";
|
||||||
|
|
||||||
|
const doc = new File();
|
||||||
|
|
||||||
|
// The first argument is an ID you use to apply the style to paragraphs
|
||||||
|
// The second argument is a human-friendly name to show in the UI
|
||||||
|
doc.Styles.createParagraphStyle("MySpectacularStyle", "My Spectacular Style")
|
||||||
|
.basedOn("Heading1")
|
||||||
|
.next("Heading1")
|
||||||
|
.color("990000")
|
||||||
|
.italics();
|
||||||
|
|
||||||
|
// WordprocessingML docs for TableOfContents can be found here:
|
||||||
|
// http://officeopenxml.com/WPtableOfContents.php
|
||||||
|
|
||||||
|
// Let's define the properties for generate a TOC for heading 1-5 and MySpectacularStyle,
|
||||||
|
// making the entries be hyperlinks for the paragraph
|
||||||
|
const toc = new TableOfContents("Summary", {
|
||||||
|
hyperlink: true,
|
||||||
|
headingStyleRange: "1-5",
|
||||||
|
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)],
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addTableOfContents(toc);
|
||||||
|
|
||||||
|
doc.addParagraph(new Paragraph("Header #1").heading1().pageBreakBefore());
|
||||||
|
doc.addParagraph(new Paragraph("I'm a little text very nicely written.'"));
|
||||||
|
|
||||||
|
doc.addParagraph(new Paragraph("Header #2").heading1().pageBreakBefore());
|
||||||
|
doc.addParagraph(new Paragraph("I'm a other text very nicely written.'"));
|
||||||
|
doc.addParagraph(new Paragraph("Header #2.1").heading2());
|
||||||
|
doc.addParagraph(new Paragraph("I'm a another text very nicely written.'"));
|
||||||
|
|
||||||
|
doc.addParagraph(new Paragraph("My Spectacular Style #1").style("MySpectacularStyle").pageBreakBefore());
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
32
demo/demo29.ts
Normal file
32
demo/demo29.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, Indent, Numbering, Packer, Paragraph } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
|
||||||
|
const numbering = new Numbering();
|
||||||
|
|
||||||
|
const abstractNum = numbering.createAbstractNumbering();
|
||||||
|
abstractNum.createLevel(0, "upperRoman", "%1", "start").addParagraphProperty(new Indent({ left: 720, hanging: 260 }));
|
||||||
|
|
||||||
|
const concrete = numbering.createConcreteNumbering(abstractNum);
|
||||||
|
|
||||||
|
const item1 = new Paragraph("line with contextual spacing");
|
||||||
|
const item2 = new Paragraph("line with contextual spacing");
|
||||||
|
const item3 = new Paragraph("line without contextual spacing");
|
||||||
|
const item4 = new Paragraph("line without contextual spacing");
|
||||||
|
|
||||||
|
item1.setNumbering(concrete, 0).spacing({before: 200}).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(item2);
|
||||||
|
doc.addParagraph(item3);
|
||||||
|
doc.addParagraph(item4);
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
29
demo/demo30.ts
Normal file
29
demo/demo30.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, ImportDotx, Packer, Paragraph } from "../build";
|
||||||
|
|
||||||
|
const importDotx = new ImportDotx();
|
||||||
|
const filePath = "./demo/dotx/template.dotx";
|
||||||
|
|
||||||
|
fs.readFile(filePath, (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
throw new Error(`Failed to read file ${filePath}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
importDotx.extract(data).then((templateDocument) => {
|
||||||
|
// This any needs fixing
|
||||||
|
const sectionProps = {
|
||||||
|
titlePage: templateDocument.titlePageIsDefined,
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const doc = new Document(undefined, sectionProps, {
|
||||||
|
template: templateDocument,
|
||||||
|
});
|
||||||
|
const paragraph = new Paragraph("Hello World");
|
||||||
|
doc.addParagraph(paragraph);
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
26
demo/demo31.ts
Normal file
26
demo/demo31.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Example of how you would create a table and add data to it
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, Packer, Paragraph, VerticalAlign } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
|
||||||
|
const table = doc.createTable(2, 2);
|
||||||
|
table
|
||||||
|
.getCell(1, 1)
|
||||||
|
.addContent(new Paragraph("This text should be in the middle of the cell"))
|
||||||
|
.CellProperties.setVerticalAlign(VerticalAlign.CENTER);
|
||||||
|
|
||||||
|
table
|
||||||
|
.getCell(1, 0)
|
||||||
|
.addContent(
|
||||||
|
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",
|
||||||
|
).heading1(),
|
||||||
|
);
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
35
demo/demo32.ts
Normal file
35
demo/demo32.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Example of how you would create a table and add data to it
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, Packer, Paragraph } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
|
||||||
|
let table = doc.createTable(2, 2);
|
||||||
|
|
||||||
|
table.getCell(0, 0).addContent(new Paragraph("Hello"));
|
||||||
|
table.getRow(0).mergeCells(0, 1);
|
||||||
|
|
||||||
|
doc.createParagraph("Another table").heading2();
|
||||||
|
|
||||||
|
table = doc.createTable(2, 3);
|
||||||
|
table.getCell(0, 0).addContent(new Paragraph("World"));
|
||||||
|
table.getRow(0).mergeCells(0, 2);
|
||||||
|
|
||||||
|
doc.createParagraph("Another table").heading2();
|
||||||
|
|
||||||
|
table = doc.createTable(2, 4);
|
||||||
|
table.getCell(0, 0).addContent(new Paragraph("Foo"));
|
||||||
|
|
||||||
|
table.getCell(1, 0).addContent(new Paragraph("Bar1"));
|
||||||
|
table.getCell(1, 1).addContent(new Paragraph("Bar2"));
|
||||||
|
table.getCell(1, 2).addContent(new Paragraph("Bar3"));
|
||||||
|
table.getCell(1, 3).addContent(new Paragraph("Bar4"));
|
||||||
|
|
||||||
|
table.getRow(0).mergeCells(0, 3);
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
22
demo/demo33.ts
Normal file
22
demo/demo33.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Sequential Captions
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, Packer, Paragraph, TextRun } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
|
||||||
|
const paragraph = new Paragraph("Hello World 1->").addSequentialIdentifier("Caption").addRun(new TextRun(" text after sequencial caption 2->")).addSequentialIdentifier("Caption");
|
||||||
|
const paragraph2 = new Paragraph("Hello World 1->").addSequentialIdentifier("Label").addRun(new TextRun(" text after sequencial caption 2->")).addSequentialIdentifier("Label");
|
||||||
|
const paragraph3 = new Paragraph("Hello World 1->").addSequentialIdentifier("Another").addRun(new TextRun(" text after sequencial caption 3->")).addSequentialIdentifier("Label");
|
||||||
|
const paragraph4 = new Paragraph("Hello World 2->").addSequentialIdentifier("Another").addRun(new TextRun(" text after sequencial caption 4->")).addSequentialIdentifier("Label");
|
||||||
|
|
||||||
|
doc.addParagraph(paragraph);
|
||||||
|
doc.addParagraph(paragraph2);
|
||||||
|
doc.addParagraph(paragraph3);
|
||||||
|
doc.addParagraph(paragraph4);
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
32
demo/demo34.ts
Normal file
32
demo/demo34.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Example of how you would create a table with float positions
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import {
|
||||||
|
Document,
|
||||||
|
Packer,
|
||||||
|
Paragraph,
|
||||||
|
RelativeHorizontalPosition,
|
||||||
|
RelativeVerticalPosition,
|
||||||
|
TableAnchorType,
|
||||||
|
WidthType,
|
||||||
|
} from "../build";
|
||||||
|
|
||||||
|
const doc = new Document();
|
||||||
|
|
||||||
|
const table = doc.createTable(2, 2).float({
|
||||||
|
horizontalAnchor: TableAnchorType.MARGIN,
|
||||||
|
verticalAnchor: TableAnchorType.MARGIN,
|
||||||
|
relativeHorizontalPosition: RelativeHorizontalPosition.RIGHT,
|
||||||
|
relativeVerticalPosition: RelativeVerticalPosition.BOTTOM,
|
||||||
|
});
|
||||||
|
table.setFixedWidthLayout();
|
||||||
|
table.setWidth(WidthType.DXA, 4535);
|
||||||
|
|
||||||
|
table.getCell(0, 0).addContent(new Paragraph("Hello"));
|
||||||
|
table.getRow(0).mergeCells(0, 1);
|
||||||
|
|
||||||
|
const packer = new Packer();
|
||||||
|
|
||||||
|
packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
@ -1,7 +1,8 @@
|
|||||||
// Example of how to add images to the document - You can use Buffers, UInt8Arrays or Base64 strings
|
// Example of how to add images to the document - You can use Buffers, UInt8Arrays or Base64 strings
|
||||||
// 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";
|
||||||
|
import { Document, HorizontalPositionAlign, HorizontalPositionRelativeFrom, Packer, Paragraph, VerticalPositionAlign, VerticalPositionRelativeFrom} from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
@ -13,6 +14,29 @@ doc.createImage(fs.readFileSync("./demo/images/dog.png").toString("base64"));
|
|||||||
doc.createImage(fs.readFileSync("./demo/images/cat.jpg"));
|
doc.createImage(fs.readFileSync("./demo/images/cat.jpg"));
|
||||||
doc.createImage(fs.readFileSync("./demo/images/parrots.bmp"));
|
doc.createImage(fs.readFileSync("./demo/images/parrots.bmp"));
|
||||||
doc.createImage(fs.readFileSync("./demo/images/pizza.gif"));
|
doc.createImage(fs.readFileSync("./demo/images/pizza.gif"));
|
||||||
|
doc.createImage(fs.readFileSync("./demo/images/pizza.gif"), 200, 200, {
|
||||||
|
floating: {
|
||||||
|
horizontalPosition: {
|
||||||
|
offset: 1014400,
|
||||||
|
},
|
||||||
|
verticalPosition: {
|
||||||
|
offset: 1014400,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.createImage(fs.readFileSync("./demo/images/cat.jpg"), 200, 200, {
|
||||||
|
floating: {
|
||||||
|
horizontalPosition: {
|
||||||
|
relative: HorizontalPositionRelativeFrom.PAGE,
|
||||||
|
align: HorizontalPositionAlign.RIGHT,
|
||||||
|
},
|
||||||
|
verticalPosition: {
|
||||||
|
relative: VerticalPositionRelativeFrom.PAGE,
|
||||||
|
align: VerticalPositionAlign.BOTTOM,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const packer = new Packer();
|
const packer = new Packer();
|
||||||
|
|
||||||
|
BIN
demo/dotx/template.dotx
Normal file
BIN
demo/dotx/template.dotx
Normal file
Binary file not shown.
@ -16,6 +16,7 @@
|
|||||||
* [Bullet Points](usage/bullet-points.md)
|
* [Bullet Points](usage/bullet-points.md)
|
||||||
* [Numbering](usage/numbering.md)
|
* [Numbering](usage/numbering.md)
|
||||||
* [Tab Stops](usage/tab-stops.md)
|
* [Tab Stops](usage/tab-stops.md)
|
||||||
|
* [Table of Contents](usage/table-of-contents.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)
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
# Contribution Guidelines
|
# Contribution Guidelines
|
||||||
|
|
||||||
## Writing Code
|
|
||||||
|
|
||||||
* Include documentation reference(s) at the top of each file:
|
* Include documentation reference(s) at the top of each file:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -12,6 +10,59 @@
|
|||||||
|
|
||||||
* Follow the `TSLint` rules
|
* Follow the `TSLint` rules
|
||||||
|
|
||||||
|
## Always think about the user
|
||||||
|
|
||||||
|
The number one pillar for contribution is to **ALWAYS** think about how the user will use the library.
|
||||||
|
|
||||||
|
Put yourself in their position, and imagine how they would feel about your feature you wrote.
|
||||||
|
|
||||||
|
1. Is it easy to use?
|
||||||
|
2. Has it been documented well?
|
||||||
|
3. Is it intuative?
|
||||||
|
4. Is it consistent with the rest of the API?
|
||||||
|
5. Is it fun to use?
|
||||||
|
|
||||||
|
## Good Commit Names
|
||||||
|
|
||||||
|
Please write good commit messages when making a commit: https://chris.beams.io/posts/git-commit/
|
||||||
|
|
||||||
|
**Do not:**
|
||||||
|
```
|
||||||
|
c // What?
|
||||||
|
rtl // Adding acryonyms without explaining anything else is not helpful
|
||||||
|
works! // Glad its working, but the message is not helpful
|
||||||
|
demo updated // Getting better, but capitalize the first letter
|
||||||
|
Unesesary coment removed // Make sure to use correct spelling
|
||||||
|
```
|
||||||
|
|
||||||
|
## No leaky components in API interface
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
This is so that:
|
||||||
|
|
||||||
|
1. Imports are much cleaner, no need for:
|
||||||
|
```js
|
||||||
|
import { ChildComponent } from "./my-feature/sub-component/deeper/.../my-deep.component";
|
||||||
|
```
|
||||||
|
|
||||||
|
2. This is what I consider "leakage". The code is aware of the underlying implementation of the component.
|
||||||
|
3. It means the end user does not need to import and create the child component to be injected.
|
||||||
|
|
||||||
|
**Do not**
|
||||||
|
`TableFloatProperties` is a class. The outside world would have to construct the object, and inject it in
|
||||||
|
```js
|
||||||
|
public float(tableFloatProperties: TableFloatProperties): Table
|
||||||
|
```
|
||||||
|
|
||||||
|
**Do**
|
||||||
|
`ITableFloatOptions` is an interface for a JSON of primatives.
|
||||||
|
```js
|
||||||
|
public float(tableFloatOptions: ITableFloatOptions): Table
|
||||||
|
```
|
||||||
|
|
||||||
## 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.
|
||||||
@ -39,7 +90,7 @@ Getters and Setters are done with a capital letter like so:
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
public get Level() {
|
public get Level() {
|
||||||
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -57,6 +108,86 @@ private get _level: string;
|
|||||||
private get level: string;
|
private get level: string;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Interfaces over type alias
|
||||||
|
|
||||||
|
Do not use `type`, but rather use `Interfaces`. `type` cannot be extended, and a class cannot implement it.
|
||||||
|
|
||||||
|
> "In general, use what you want ( type alias / interface ) just be consistent"
|
||||||
|
> "always use interface for public API's definition when authoring a library or 3rd party ambient type definitions"
|
||||||
|
>
|
||||||
|
> * https://medium.com/@martin_hotell/interface-vs-type-alias-in-typescript-2-7-2a8f1777af4c
|
||||||
|
|
||||||
|
`Interface` is generally preferred over `type`: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types
|
||||||
|
|
||||||
|
**Do not:**
|
||||||
|
|
||||||
|
```js
|
||||||
|
type RelationshipFileInfo = { id: number, target: string };
|
||||||
|
```
|
||||||
|
|
||||||
|
**Do:**
|
||||||
|
|
||||||
|
```js
|
||||||
|
interface IRelationshipFileInfo {
|
||||||
|
id: number;
|
||||||
|
target: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## String enums vs type
|
||||||
|
|
||||||
|
To take full advantage of TypeScript's typing system, its best to use `string enums`:
|
||||||
|
|
||||||
|
**Do not:**
|
||||||
|
|
||||||
|
```js
|
||||||
|
type WeaponType = "bow" | "sword" | "wand";
|
||||||
|
```
|
||||||
|
|
||||||
|
**Do:**
|
||||||
|
|
||||||
|
```js
|
||||||
|
enum WeaponType = {
|
||||||
|
BOW = "bow",
|
||||||
|
SWORD = "sword",
|
||||||
|
WAND = "wand",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Spell correctly, 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:
|
||||||
|
|
||||||
|
**Do not:**
|
||||||
|
```js
|
||||||
|
readdy // misspelling
|
||||||
|
perm // abbreviation
|
||||||
|
conf // abbreviation
|
||||||
|
cnty // abbreviation
|
||||||
|
relationFile // abbreviation
|
||||||
|
colour // U.K. English
|
||||||
|
```
|
||||||
|
|
||||||
|
**Do:**
|
||||||
|
```js
|
||||||
|
ready
|
||||||
|
permission
|
||||||
|
config
|
||||||
|
country
|
||||||
|
relationshipFile
|
||||||
|
color
|
||||||
|
```
|
||||||
|
|
||||||
|
## Keep files small (within reason)
|
||||||
|
|
||||||
|
To minimize merge conflicts, reduce complexity, and improve readability, keep the files small.
|
||||||
|
|
||||||
|
## Name files and folders with `/foo-bar/kebab-case.ts`
|
||||||
|
|
||||||
|
To be consistent and in-line with the project, name files `like-this.ts`.
|
||||||
|
|
||||||
|
https://stackoverflow.com/questions/7273316/what-is-the-javascript-filename-naming-convention
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
Please write a test of every file you make and suffix it with `.spec.ts`.
|
Please write a test of every file you make and suffix it with `.spec.ts`.
|
||||||
@ -78,3 +209,5 @@ describe("ClassName", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Try not to use the `tests/utility.ts` file as this is being deprecated.
|
||||||
|
@ -1,71 +1,135 @@
|
|||||||
# Images
|
# Images
|
||||||
|
|
||||||
## Intro
|
To create a `floating` image on top of text:
|
||||||
|
|
||||||
Adding images is very simple
|
```ts
|
||||||
|
doc.createImage(fs.readFileSync("./demo/images/pizza.gif"), 200, 200, {
|
||||||
Simply call the `createImage` method:
|
|
||||||
|
|
||||||
```js
|
|
||||||
const image = doc.createImage([BUFFER_OF_YOUR_IMAGE]);
|
|
||||||
```
|
|
||||||
|
|
||||||
`docx` supports `jpeg`, `jpg`, `bmp`, `gif` and `png`
|
|
||||||
|
|
||||||
Check `demo5.js` for an example
|
|
||||||
|
|
||||||
## Positioning
|
|
||||||
|
|
||||||
Images can be:
|
|
||||||
|
|
||||||
* floating position of images
|
|
||||||
* Wrapped around the text
|
|
||||||
* Inline
|
|
||||||
|
|
||||||
By default, picture are exported as `INLINE` elements.
|
|
||||||
|
|
||||||
In Word this is found in:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
The `PictureRun` element support various options to define the positioning of the element in the document.
|
|
||||||
|
|
||||||
```js
|
|
||||||
interface DrawingOptions {
|
|
||||||
position?: PlacementPosition;
|
|
||||||
textWrapping?: TextWrapping;
|
|
||||||
floating?: Floating;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
can be passed when creating `PictureRun()` for example:
|
|
||||||
|
|
||||||
```js
|
|
||||||
const imageData = document.createImage(buffer, 903, 1149);
|
|
||||||
|
|
||||||
new docx.PictureRun(imageData, {
|
|
||||||
position: docx.PlacementPosition.FLOATING,
|
|
||||||
floating: {
|
floating: {
|
||||||
horizontalPosition: {
|
horizontalPosition: {
|
||||||
relative: HorizontalPositionRelativeFrom.PAGE,
|
offset: 1014400,
|
||||||
align: HorizontalPositionAlign.LEFT,
|
|
||||||
},
|
},
|
||||||
verticalPosition: {
|
verticalPosition: {
|
||||||
relative: VerticalPositionRelativeFrom.PAGE,
|
offset: 1014400,
|
||||||
align: VerticalPositionAlign.TOP,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
So, the first thing is to define the placement position: `INLINE` or `FLOATING`. Inline is the default one so there is no need to pass drawing options for inline.
|
By default with no arguments, its an `inline` image:
|
||||||
|
|
||||||
When placement position is FLOATING then we can use two options:
|
```ts
|
||||||
|
doc.createImage(fs.readFileSync("./demo/images/parrots.bmp"));
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also create images manually and add them later:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const image = Media.addImage(doc, fs.readFileSync("./demo/images/pizza.gif"));
|
||||||
|
doc.addImage(image);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Intro
|
||||||
|
|
||||||
|
Adding images can be done in two ways:
|
||||||
|
|
||||||
|
1. Call the `createImage` method to add the image directly into the `document`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
doc.createImage([IMAGE_BUFFER], [WIDTH], [HEIGHT], [POSITION_OPTIONS]);
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create an `image` first, then add it into the `document`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const image = Media.addImage(doc, [IMAGE_BUFFER]);
|
||||||
|
doc.addImage(image);
|
||||||
|
```
|
||||||
|
|
||||||
|
`docx` supports `jpeg`, `jpg`, `bmp`, `gif` and `png`
|
||||||
|
|
||||||
|
## Positioning
|
||||||
|
|
||||||
|
> Positioning is the method on how to place the image on the document
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Three types of image positioning is supported:
|
||||||
|
|
||||||
|
- Floating
|
||||||
|
- Wrapped around the text
|
||||||
|
- Inline
|
||||||
|
|
||||||
|
By default, picture are exported as `Inline` elements.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Pass `options` into the `[POSITION_OPTIONS]` metioned in the [Intro above](#Intro).
|
||||||
|
|
||||||
|
### Floating
|
||||||
|
|
||||||
|
To change the position the image to be on top of the text, simply add the `floating` property to the last argument. By default, the offsets are relative to the top left corner of the `page`. Offset units are in [emus](https://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/):
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const imageData = document.createImage(buffer, 903, 1149, {
|
||||||
|
floating: {
|
||||||
|
horizontalPosition: {
|
||||||
|
offset: 1014400, // relative: HorizontalPositionRelativeFrom.PAGE by default
|
||||||
|
},
|
||||||
|
verticalPosition: {
|
||||||
|
offset: 1014400, // relative: VerticalPositionRelativeFrom.PAGE by default
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const imageData = document.createImage(buffer, 903, 1149, {
|
||||||
|
floating: {
|
||||||
|
horizontalPosition: {
|
||||||
|
relative: HorizontalPositionRelativeFrom.RIGHT_MARGIN,
|
||||||
|
offset: 1014400,
|
||||||
|
},
|
||||||
|
verticalPosition: {
|
||||||
|
relative: VerticalPositionRelativeFrom.BOTTOM_MARGIN,
|
||||||
|
offset: 1014400,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
Full options you can pass into `floating` are:
|
||||||
|
|
||||||
|
| Property | Type | Notes |
|
||||||
|
| ------------------ | --------------------------- | -------- |
|
||||||
|
| horizontalPosition | `HorizontalPositionOptions` | Required |
|
||||||
|
| verticalPosition | `VerticalPositionOptions` | Required |
|
||||||
|
| allowOverlap | `boolean` | Optional |
|
||||||
|
| lockAnchor | `boolean` | Optional |
|
||||||
|
| behindDocument | `boolean` | Optional |
|
||||||
|
| layoutInCell | `boolean` | Optional |
|
||||||
|
|
||||||
|
`HorizontalPositionOptions` are:
|
||||||
|
|
||||||
|
| Property | Type | Notes | Possible Values |
|
||||||
|
| -------- | -------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
||||||
|
| relative | `HorizontalPositionRelativeFrom` | Required | `CHARACTER`, `COLUMN`, `INSIDE_MARGIN`, `LEFT_MARGIN`, `MARGIN`, `OUTSIDE_MARGIN`, `PAGE`, `RIGHT_MARGIN` |
|
||||||
|
| align | `HorizontalPositionAlign` | You can either have `align` or `offset`, not both | `CENTER`, `INSIDE`, `LEFT`, `OUTSIDE`, `RIGHT` |
|
||||||
|
| offset | `number` | You can either have `align` or `offset`, not both | `0` to `Infinity` |
|
||||||
|
|
||||||
|
`VerticalPositionOptions` are:
|
||||||
|
|
||||||
|
| Property | Type | Notes | Possible Values |
|
||||||
|
| -------- | ------------------------------ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||||
|
| relative | `VerticalPositionRelativeFrom` | Required | `BOTTOM_MARGIN`, `INSIDE_MARGIN`, `LINE`, `MARGIN`, `OUTSIDE_MARGIN`, `PAGE`, `PARAGRAPH`, `TOP_MARGIN` |
|
||||||
|
| align | `VerticalPositionAlign` | You can either have `align` or `offset`, not both | `BOTTOM`, `CENTER`, `INSIDE`, `OUTSIDE`, `TOP` |
|
||||||
|
| offset | `number` | You can either have `align` or `offset`, not both | `0` to `Infinity` |
|
||||||
|
|
||||||
### Wrap text
|
### Wrap text
|
||||||
|
|
||||||
|
!> **In progress** Documentation may potentially be changing
|
||||||
|
|
||||||
for `drawingOptions.textWrapping` we can define various options. `textWrapping` has the following properties:
|
for `drawingOptions.textWrapping` we can define various options. `textWrapping` has the following properties:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -90,67 +154,20 @@ enum WrapTextOption {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Floating position
|
## Examples
|
||||||
|
|
||||||
When we want to position the image relative or absolute then we need to use option `drawingOptions.floating`:
|
### Add image to the document
|
||||||
|
|
||||||
```js
|
Importing Images from file system path
|
||||||
export interface Floating {
|
|
||||||
horizontalPosition: HorizontalPositionOptions;
|
|
||||||
verticalPosition: VerticalPositionOptions;
|
|
||||||
allowOverlap?: boolean;
|
|
||||||
lockAnchor?: boolean;
|
|
||||||
behindDocument?: boolean;
|
|
||||||
layoutInCell?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface HorizontalPositionOptions {
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo5.ts ":include")
|
||||||
relative: HorizontalPositionRelativeFrom;
|
|
||||||
align?: HorizontalPositionAlign;
|
|
||||||
offset?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface VerticalPositionOptions {
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.ts_
|
||||||
relative: VerticalPositionRelativeFrom;
|
|
||||||
align?: VerticalPositionAlign;
|
|
||||||
offset?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum HorizontalPositionRelativeFrom {
|
### Add images to header and footer
|
||||||
CHARACTER = "character",
|
|
||||||
COLUMN = "column",
|
|
||||||
INSIDE_MARGIN = "insideMargin",
|
|
||||||
LEFT_MARGIN = "leftMargin",
|
|
||||||
MARGIN = "margin",
|
|
||||||
OUTSIDE_MARGIN = "outsideMargin",
|
|
||||||
PAGE = "page",
|
|
||||||
RIGHT_MARGIN = "rightMargin",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum VerticalPositionRelativeFrom {
|
Example showing how to add image to headers and footers
|
||||||
BOTTOM_MARGIN = "bottomMargin",
|
|
||||||
INSIDE_MARGIN = "insideMargin",
|
|
||||||
LINE = "line",
|
|
||||||
MARGIN = "margin",
|
|
||||||
OUTSIDE_MARGIN = "outsideMargin",
|
|
||||||
PAGE = "page",
|
|
||||||
PARAGRAPH = "paragraph",
|
|
||||||
TOP_MARGIN = "topMargin",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum HorizontalPositionAlign {
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo9.ts ":include")
|
||||||
CENTER = "center",
|
|
||||||
INSIDE = "inside",
|
|
||||||
LEFT = "left",
|
|
||||||
OUTSIDE = "outside",
|
|
||||||
RIGHT = "right",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum VerticalPositionAlign {
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.ts_
|
||||||
BOTTOM = "bottom",
|
|
||||||
CENTER = "center",
|
|
||||||
INSIDE = "inside",
|
|
||||||
OUTSIDE = "outside",
|
|
||||||
TOP = "top",
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
@ -75,7 +75,7 @@ abstractNum.createLevel(0, "upperRoman", "%1", "start").addParagraphProperty(new
|
|||||||
abstractNum.createLevel(1, "decimal", "%2.", "start").addParagraphProperty(new Indent(1440, 980));
|
abstractNum.createLevel(1, "decimal", "%2.", "start").addParagraphProperty(new Indent(1440, 980));
|
||||||
abstractNum.createLevel(2, "lowerLetter", "%3)", "start").addParagraphProperty(new Indent(2160, 1700));
|
abstractNum.createLevel(2, "lowerLetter", "%3)", "start").addParagraphProperty(new Indent(2160, 1700));
|
||||||
|
|
||||||
const concrete = numbering.createConcreteNumbering(numberedAbstract);
|
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 their
|
||||||
|
76
docs/usage/table-of-contents.md
Normal file
76
docs/usage/table-of-contents.md
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
You can generate table of contents with `docx`. More information can be found [here](http://officeopenxml.com/WPtableOfContents.php).
|
||||||
|
|
||||||
|
>Tables of Contents are fields and, by design, it's content is only generated or updated by Word. We can't do it programatically.
|
||||||
|
>This is why, when you open a the file, Word you will prompt the message "This document contains fields that may refer to other files. Do you want to update the fields in this document?".
|
||||||
|
>You have say yes to Word generate the content of all table of contents.
|
||||||
|
|
||||||
|
The complete documentation can be found [here](https://www.ecma-international.org/publications/standards/Ecma-376.htm) (at Part 1, Page 1251).
|
||||||
|
|
||||||
|
## How to
|
||||||
|
|
||||||
|
All you need to do is create a `TableOfContents` object and assign it to the document.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const toc = new TableOfContents("Summary", {
|
||||||
|
hyperlink: true,
|
||||||
|
headingStyleRange: "1-5",
|
||||||
|
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)]
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addTableOfContents(toc);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Table of Contents Options
|
||||||
|
|
||||||
|
Here is the list of all options that you can use to generate your tables of contents:
|
||||||
|
|
||||||
|
| Option | Type | TOC Field Switch | Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
|captionLabel|string|`\a`|Includes captioned items, but omits caption labels and numbers. The identifier designated by `text` in this switch's field-argument corresponds to the caption label. Use ``\c`` to build a table of captions with labels and numbers.|
|
||||||
|
|entriesFromBookmark|string|`\b`|Includes entries only from the portion of the document marked by the bookmark named by `text` in this switch's field-argument.|
|
||||||
|
|captionLabelIncludingNumbers|string|`\c`|Includes figures, tables, charts, and other items that are numbered by a SEQ field (§17.16.5.56). The sequence identifier designated by `text` in this switch's field-argument, which corresponds to the caption label, shall match the identifier in the corresponding SEQ field.|
|
||||||
|
|sequenceAndPageNumbersSeparator|string|`\d`|When used with `\s`, the `text` in this switch's field-argument defines the separator between sequence and page numbers. The default separator is a hyphen (-).|
|
||||||
|
|tcFieldIdentifier|string|`\f`|Includes only those TC fields whose identifier exactly matches the `text` in this switch's field-argument (which is typically a letter).|
|
||||||
|
|hyperlink|boolean|`\h`|Makes the table of contents entries hyperlinks.|
|
||||||
|
|tcFieldLevelRange|string|`\l`|Includes TC fields that assign entries to one of the levels specified by `text` in this switch's field-argument as a range having the form startLevel-endLevel, where startLevel and endLevel are integers, and startLevel has a value equal-to or less-than endLevel. TC fields that assign entries to lower levels are skipped.|
|
||||||
|
|pageNumbersEntryLevelsRange|string|`\n`|Without field-argument, omits page numbers from the table of contents. Page numbers are omitted from all levels unless a range of entry levels is specified by `text` in this switch's field-argument. A range is specified as for `\l`.|
|
||||||
|
|headingStyleRange|string|`\o`|Uses paragraphs formatted with all or the specified range of builtin heading styles. Headings in a style range are specified by `text` in this switch's field-argument using the notation specified as for `\l`, where each integer corresponds to the style with a style ID of HeadingX (e.g. 1 corresponds to Heading1). If no heading range is specified, all heading levels used in the document are listed.|
|
||||||
|
|entryAndPageNumberSeparator|string|`\p`|`text` in this switch's field-argument specifies a sequence of characters that separate an entry and its page number. The default is a tab with leader dots.|
|
||||||
|
|seqFieldIdentifierForPrefix|string|`\s`|For entries numbered with a SEQ field (§17.16.5.56), adds a prefix to the page number. The prefix depends on the type of entry. `text` in this switch's field-argument shall match the identifier in the SEQ field.|
|
||||||
|
|stylesWithLevels|StyleLevel[]|`\t`| Uses paragraphs formatted with styles other than the built-in heading styles. `text` in this switch's field-argument specifies those styles as a set of comma-separated doublets, with each doublet being a comma-separated set of style name and table of content level. `\t` can be combined with `\o`.|
|
||||||
|
|useAppliedParagraphOutlineLevel|boolean|`\u`|Uses the applied paragraph outline level.|
|
||||||
|
|preserveTabInEntries|boolean|`\w`|Preserves tab entries within table entries.|
|
||||||
|
|preserveNewLineInEntries|boolean|`\x`|Preserves newline characters within table entries.|
|
||||||
|
|hideTabAndPageNumbersInWebView|boolean|`\z`|Hides tab leader and page numbers in web page view (§17.18.102).|
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Let's define the options for generate a TOC for heading 1-5 and MySpectacularStyle,
|
||||||
|
// making the entries be hyperlinks for the paragraph
|
||||||
|
const toc = new TableOfContents("Summary", {
|
||||||
|
hyperlink: true,
|
||||||
|
headingStyleRange: "1-5",
|
||||||
|
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)]
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addTableOfContents(toc);
|
||||||
|
|
||||||
|
doc.addParagraph(new Paragraph("Header #1").heading1().pageBreakBefore());
|
||||||
|
doc.addParagraph(new Paragraph("I'm a little text, very nicely written.'"));
|
||||||
|
|
||||||
|
doc.addParagraph(new Paragraph("Header #2").heading1().pageBreakBefore());
|
||||||
|
doc.addParagraph(new Paragraph("I'm another text very nicely written.'"));
|
||||||
|
doc.addParagraph(new Paragraph("Header #2.1").heading2());
|
||||||
|
doc.addParagraph(new Paragraph("I'm another text very nicely written.'"));
|
||||||
|
|
||||||
|
doc.addParagraph(new Paragraph("My Spectacular Style #1").style("MySpectacularStyle").pageBreakBefore());
|
||||||
|
```
|
||||||
|
|
||||||
|
### Complete example
|
||||||
|
|
||||||
|
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo28.ts ":include")
|
||||||
|
|
||||||
|
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo28.ts_
|
17
package.json
17
package.json
@ -1,22 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "docx",
|
"name": "docx",
|
||||||
"version": "4.1.0",
|
"version": "4.5.0",
|
||||||
"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": {
|
||||||
"pretest": "rimraf ./build",
|
"pretest": "rimraf ./build",
|
||||||
"test": "mocha-webpack \"src/**/*.ts\"",
|
"test": "mocha-webpack \"src/**/*.ts\"",
|
||||||
"test-watch": "mocha-webpack \"src/**/*.ts\" --watch",
|
"test.coverage": "nyc npm test",
|
||||||
|
"test.watch": "npm test -- --watch",
|
||||||
"prepublishOnly": "npm run build",
|
"prepublishOnly": "npm run build",
|
||||||
"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 .",
|
||||||
"webpack": "rimraf ./build && webpack",
|
"webpack": "rimraf ./build && webpack",
|
||||||
"build.web": "webpack --config webpack.web.config.js",
|
|
||||||
"demo": "npm run build && npm run ts-node ./demo",
|
"demo": "npm run build && npm run ts-node ./demo",
|
||||||
"typedoc": "typedoc src/index.ts",
|
"typedoc": "typedoc src/index.ts",
|
||||||
"style": "prettier -l \"src/**/*.ts\"",
|
"style": "prettier -l \"src/**/*.ts\"",
|
||||||
"style.fix": "prettier \"src/**/*.ts\" --write",
|
"style.fix": "npm run style -- --write",
|
||||||
"fix-types": "node types-absolute-fixer.js",
|
"fix-types": "node types-absolute-fixer.js",
|
||||||
"ts-node": "ts-node"
|
"ts-node": "ts-node"
|
||||||
},
|
},
|
||||||
@ -48,11 +48,11 @@
|
|||||||
"types": "./build/index.d.ts",
|
"types": "./build/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/image-size": "0.0.29",
|
"@types/image-size": "0.0.29",
|
||||||
"@types/jszip": "^3.1.3",
|
"@types/jszip": "^3.1.4",
|
||||||
"fast-xml-parser": "^3.3.6",
|
|
||||||
"image-size": "^0.6.2",
|
"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"
|
||||||
},
|
},
|
||||||
"author": "Dolan Miu",
|
"author": "Dolan Miu",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -67,9 +67,11 @@
|
|||||||
"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",
|
||||||
|
"istanbul-instrumenter-loader": "^3.0.1",
|
||||||
"jszip": "^3.1.5",
|
"jszip": "^3.1.5",
|
||||||
"mocha": "^5.2.0",
|
"mocha": "^5.2.0",
|
||||||
"mocha-webpack": "^1.0.1",
|
"mocha-webpack": "^1.0.1",
|
||||||
|
"nyc": "^13.1.0",
|
||||||
"pre-commit": "^1.2.2",
|
"pre-commit": "^1.2.2",
|
||||||
"prettier": "^1.12.1",
|
"prettier": "^1.12.1",
|
||||||
"prompt": "^1.0.0",
|
"prompt": "^1.0.0",
|
||||||
@ -79,6 +81,7 @@
|
|||||||
"sinon": "^5.0.7",
|
"sinon": "^5.0.7",
|
||||||
"ts-node": "^7.0.1",
|
"ts-node": "^7.0.1",
|
||||||
"tslint": "^5.11.0",
|
"tslint": "^5.11.0",
|
||||||
|
"tslint-immutable": "^4.9.0",
|
||||||
"typedoc": "^0.11.1",
|
"typedoc": "^0.11.1",
|
||||||
"typescript": "2.9.2",
|
"typescript": "2.9.2",
|
||||||
"webpack": "^3.10.0"
|
"webpack": "^3.10.0"
|
||||||
|
@ -2,6 +2,12 @@ import { BaseXmlComponent, IXmlableObject } from "file/xml-components";
|
|||||||
|
|
||||||
export class Formatter {
|
export class Formatter {
|
||||||
public format(input: BaseXmlComponent): IXmlableObject {
|
public format(input: BaseXmlComponent): IXmlableObject {
|
||||||
return input.prepForXml();
|
const output = input.prepForXml();
|
||||||
|
|
||||||
|
if (output) {
|
||||||
|
return output;
|
||||||
|
} else {
|
||||||
|
throw Error("XMLComponent did not format correctly");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
/* tslint:disable:typedef space-before-function-paren */
|
/* tslint:disable:typedef space-before-function-paren */
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { File } from "../../file";
|
|
||||||
|
import { File } from "file";
|
||||||
|
|
||||||
import { Compiler } from "./next-compiler";
|
import { Compiler } from "./next-compiler";
|
||||||
|
|
||||||
describe("Compiler", () => {
|
describe("Compiler", () => {
|
||||||
@ -19,7 +21,7 @@ describe("Compiler", () => {
|
|||||||
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);
|
||||||
expect(fileNames).has.length(17);
|
expect(fileNames).has.length(18);
|
||||||
expect(fileNames).to.include("word/document.xml");
|
expect(fileNames).to.include("word/document.xml");
|
||||||
expect(fileNames).to.include("word/styles.xml");
|
expect(fileNames).to.include("word/styles.xml");
|
||||||
expect(fileNames).to.include("docProps/core.xml");
|
expect(fileNames).to.include("docProps/core.xml");
|
||||||
@ -29,6 +31,7 @@ describe("Compiler", () => {
|
|||||||
expect(fileNames).to.include("word/_rels/header1.xml.rels");
|
expect(fileNames).to.include("word/_rels/header1.xml.rels");
|
||||||
expect(fileNames).to.include("word/footer1.xml");
|
expect(fileNames).to.include("word/footer1.xml");
|
||||||
expect(fileNames).to.include("word/footnotes.xml");
|
expect(fileNames).to.include("word/footnotes.xml");
|
||||||
|
expect(fileNames).to.include("word/settings.xml");
|
||||||
expect(fileNames).to.include("word/_rels/footer1.xml.rels");
|
expect(fileNames).to.include("word/_rels/footer1.xml.rels");
|
||||||
expect(fileNames).to.include("word/_rels/document.xml.rels");
|
expect(fileNames).to.include("word/_rels/document.xml.rels");
|
||||||
expect(fileNames).to.include("[Content_Types].xml");
|
expect(fileNames).to.include("[Content_Types].xml");
|
||||||
@ -47,7 +50,7 @@ describe("Compiler", () => {
|
|||||||
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);
|
||||||
expect(fileNames).has.length(25);
|
expect(fileNames).has.length(26);
|
||||||
|
|
||||||
expect(fileNames).to.include("word/header1.xml");
|
expect(fileNames).to.include("word/header1.xml");
|
||||||
expect(fileNames).to.include("word/_rels/header1.xml.rels");
|
expect(fileNames).to.include("word/_rels/header1.xml.rels");
|
||||||
|
@ -5,24 +5,25 @@ import { File } from "file";
|
|||||||
import { Formatter } from "../formatter";
|
import { Formatter } from "../formatter";
|
||||||
|
|
||||||
interface IXmlifyedFile {
|
interface IXmlifyedFile {
|
||||||
data: string;
|
readonly data: string;
|
||||||
path: string;
|
readonly path: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IXmlifyedFileMapping {
|
interface IXmlifyedFileMapping {
|
||||||
Document: IXmlifyedFile;
|
readonly Document: IXmlifyedFile;
|
||||||
Styles: IXmlifyedFile;
|
readonly Styles: IXmlifyedFile;
|
||||||
Properties: IXmlifyedFile;
|
readonly Properties: IXmlifyedFile;
|
||||||
Numbering: IXmlifyedFile;
|
readonly Numbering: IXmlifyedFile;
|
||||||
Relationships: IXmlifyedFile;
|
readonly Relationships: IXmlifyedFile;
|
||||||
FileRelationships: IXmlifyedFile;
|
readonly FileRelationships: IXmlifyedFile;
|
||||||
Headers: IXmlifyedFile[];
|
readonly Headers: IXmlifyedFile[];
|
||||||
Footers: IXmlifyedFile[];
|
readonly Footers: IXmlifyedFile[];
|
||||||
HeaderRelationships: IXmlifyedFile[];
|
readonly HeaderRelationships: IXmlifyedFile[];
|
||||||
FooterRelationships: IXmlifyedFile[];
|
readonly FooterRelationships: IXmlifyedFile[];
|
||||||
ContentTypes: IXmlifyedFile;
|
readonly ContentTypes: IXmlifyedFile;
|
||||||
AppProperties: IXmlifyedFile;
|
readonly AppProperties: IXmlifyedFile;
|
||||||
FootNotes: IXmlifyedFile;
|
readonly FootNotes: IXmlifyedFile;
|
||||||
|
readonly Settings: IXmlifyedFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Compiler {
|
export class Compiler {
|
||||||
@ -58,10 +59,23 @@ 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();
|
||||||
return {
|
return {
|
||||||
Document: {
|
Document: {
|
||||||
data: xml(this.formatter.format(file.Document), true),
|
data: xml(this.formatter.format(file.Document), true),
|
||||||
@ -120,6 +134,19 @@ export class Compiler {
|
|||||||
data: xml(this.formatter.format(file.FootNotes)),
|
data: xml(this.formatter.format(file.FootNotes)),
|
||||||
path: "word/footnotes.xml",
|
path: "word/footnotes.xml",
|
||||||
},
|
},
|
||||||
|
Settings: {
|
||||||
|
data: xml(this.formatter.format(file.Settings)),
|
||||||
|
path: "word/settings.xml",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* By default docx collapse empty tags. <a></a> -> <a/>. this function mimic it
|
||||||
|
so comparing (diff) original docx file and the library output is easier
|
||||||
|
Currently not used, so commenting out */
|
||||||
|
// private collapseEmptyTags(xmlData: string): string {
|
||||||
|
// const regEx = /<(([^ <>]+)[^<>]*)><\/\2>/g;
|
||||||
|
// const collapsed = xmlData.replace(regEx, "<$1/>");
|
||||||
|
// return collapsed;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
import { assert } from "chai";
|
import { assert } from "chai";
|
||||||
import { stub } from "sinon";
|
import { stub } from "sinon";
|
||||||
|
|
||||||
import { File, Paragraph } from "../../file";
|
import { File, Paragraph } from "file";
|
||||||
|
|
||||||
import { Packer } from "./packer";
|
import { Packer } from "./packer";
|
||||||
|
|
||||||
describe("Packer", () => {
|
describe("Packer", () => {
|
||||||
|
@ -10,21 +10,30 @@ 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 = await this.compiler.compile(file);
|
||||||
const zipData = (await zip.generateAsync({ type: "nodebuffer" })) as Buffer;
|
const zipData = (await zip.generateAsync({
|
||||||
|
type: "nodebuffer",
|
||||||
|
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
})) as Buffer;
|
||||||
|
|
||||||
return zipData;
|
return zipData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async toBase64String(file: File): Promise<string> {
|
public async toBase64String(file: File): Promise<string> {
|
||||||
const zip = await this.compiler.compile(file);
|
const zip = await this.compiler.compile(file);
|
||||||
const zipData = (await zip.generateAsync({ type: "base64" })) as string;
|
const zipData = (await zip.generateAsync({
|
||||||
|
type: "base64",
|
||||||
|
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
})) as string;
|
||||||
|
|
||||||
return zipData;
|
return zipData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async toBlob(file: File): Promise<Blob> {
|
public async toBlob(file: File): Promise<Blob> {
|
||||||
const zip = await this.compiler.compile(file);
|
const zip = await this.compiler.compile(file);
|
||||||
const zipData = (await zip.generateAsync({ type: "blob" })) as Blob;
|
const zipData = (await zip.generateAsync({
|
||||||
|
type: "blob",
|
||||||
|
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
})) as Blob;
|
||||||
|
|
||||||
return zipData;
|
return zipData;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IAppPropertiesAttributes {
|
export interface IAppPropertiesAttributes {
|
||||||
xmlns: string;
|
readonly xmlns: string;
|
||||||
vt: string;
|
readonly vt: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AppPropertiesAttributes extends XmlAttributeComponent<IAppPropertiesAttributes> {
|
export class AppPropertiesAttributes extends XmlAttributeComponent<IAppPropertiesAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
xmlns: "xmlns",
|
xmlns: "xmlns",
|
||||||
vt: "xmlns:vt",
|
vt: "xmlns:vt",
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IContentTypeAttributes {
|
export interface IContentTypeAttributes {
|
||||||
xmlns?: string;
|
readonly xmlns?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ContentTypeAttributes extends XmlAttributeComponent<IContentTypeAttributes> {
|
export class ContentTypeAttributes extends XmlAttributeComponent<IContentTypeAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
xmlns: "xmlns",
|
xmlns: "xmlns",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
// tslint:disable:no-string-literal
|
// tslint:disable:no-string-literal
|
||||||
|
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { Formatter } from "../../export/formatter";
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { ContentTypes } from "./content-types";
|
import { ContentTypes } from "./content-types";
|
||||||
|
|
||||||
describe("ContentTypes", () => {
|
describe("ContentTypes", () => {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IDefaultAttributes {
|
export interface IDefaultAttributes {
|
||||||
contentType: string;
|
readonly contentType: string;
|
||||||
extension?: string;
|
readonly extension?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DefaultAttributes extends XmlAttributeComponent<IDefaultAttributes> {
|
export class DefaultAttributes extends XmlAttributeComponent<IDefaultAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
contentType: "ContentType",
|
contentType: "ContentType",
|
||||||
extension: "Extension",
|
extension: "Extension",
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IOverrideAttributes {
|
export interface IOverrideAttributes {
|
||||||
contentType: string;
|
readonly contentType: string;
|
||||||
partName?: string;
|
readonly partName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OverrideAttributes extends XmlAttributeComponent<IOverrideAttributes> {
|
export class OverrideAttributes extends XmlAttributeComponent<IOverrideAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
contentType: "ContentType",
|
contentType: "ContentType",
|
||||||
partName: "PartName",
|
partName: "PartName",
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { Formatter } from "../../export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { CoreProperties } from "./properties";
|
import { CoreProperties } from "./properties";
|
||||||
|
|
||||||
describe("Properties", () => {
|
describe("Properties", () => {
|
||||||
|
@ -3,14 +3,14 @@ import { DocumentAttributes } from "../document/document-attributes";
|
|||||||
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
|
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
|
||||||
|
|
||||||
export interface IPropertiesOptions {
|
export interface IPropertiesOptions {
|
||||||
title?: string;
|
readonly title?: string;
|
||||||
subject?: string;
|
readonly subject?: string;
|
||||||
creator?: string;
|
readonly creator?: string;
|
||||||
keywords?: string;
|
readonly keywords?: string;
|
||||||
description?: string;
|
readonly description?: string;
|
||||||
lastModifiedBy?: string;
|
readonly lastModifiedBy?: string;
|
||||||
revision?: string;
|
readonly revision?: string;
|
||||||
externalStyles?: string;
|
readonly externalStyles?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CoreProperties extends XmlComponent {
|
export class CoreProperties extends XmlComponent {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { Formatter } from "../../../export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { Body } from "./body";
|
import { Body } from "./body";
|
||||||
|
|
||||||
describe("Body", () => {
|
describe("Body", () => {
|
||||||
@ -16,11 +17,11 @@ 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(7);
|
expect(formatted["w:sectPr"]).to.have.length(5);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("addSection", () => {
|
describe("#addSection", () => {
|
||||||
it("should add section with options", () => {
|
it("should add section with options", () => {
|
||||||
body.addSection({
|
body.addSection({
|
||||||
width: 10000,
|
width: 10000,
|
||||||
@ -38,5 +39,93 @@ describe("Body", () => {
|
|||||||
const newSection = formatted[1]["w:sectPr"];
|
const newSection = formatted[1]["w:sectPr"];
|
||||||
expect(newSection[0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 10000, "w:w": 10000, "w:orient": "portrait" } }] });
|
expect(newSection[0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 10000, "w:w": 10000, "w:orient": "portrait" } }] });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should add section with default parameters", () => {
|
||||||
|
body.addSection({
|
||||||
|
width: 10000,
|
||||||
|
height: 10000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const tree = new Formatter().format(body);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:body": [
|
||||||
|
{
|
||||||
|
"w:p": [
|
||||||
|
{ "w:pPr": [] },
|
||||||
|
{
|
||||||
|
"w:pPr": [
|
||||||
|
{
|
||||||
|
"w:sectPr": [
|
||||||
|
{ "w:pgSz": [{ _attr: { "w:w": 11906, "w:h": 16838, "w:orient": "portrait" } }] },
|
||||||
|
{
|
||||||
|
"w:pgMar": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:top": 1440,
|
||||||
|
"w:right": 1440,
|
||||||
|
"w:bottom": 1440,
|
||||||
|
"w:left": 1440,
|
||||||
|
"w:header": 708,
|
||||||
|
"w:footer": 708,
|
||||||
|
"w:gutter": 0,
|
||||||
|
"w:mirrorMargins": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ "w:cols": [{ _attr: { "w:space": 708 } }] },
|
||||||
|
{ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] },
|
||||||
|
{ "w:pgNumType": [{ _attr: { "w:fmt": "decimal" } }] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:sectPr": [
|
||||||
|
{ "w:pgSz": [{ _attr: { "w:w": 10000, "w:h": 10000, "w:orient": "portrait" } }] },
|
||||||
|
{
|
||||||
|
"w:pgMar": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:top": 1440,
|
||||||
|
"w:right": 1440,
|
||||||
|
"w:bottom": 1440,
|
||||||
|
"w:left": 1440,
|
||||||
|
"w:header": 708,
|
||||||
|
"w:footer": 708,
|
||||||
|
"w:gutter": 0,
|
||||||
|
"w:mirrorMargins": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ "w:cols": [{ _attr: { "w:space": 708 } }] },
|
||||||
|
{ "w:docGrid": [{ _attr: { "w:linePitch": 360 } }] },
|
||||||
|
{ "w:pgNumType": [{ _attr: { "w:fmt": "decimal" } }] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#getParagraphs", () => {
|
||||||
|
it("should get no paragraphs", () => {
|
||||||
|
const paragraphs = body.getParagraphs();
|
||||||
|
|
||||||
|
expect(paragraphs).to.be.an.instanceof(Array);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#DefaultSection", () => {
|
||||||
|
it("should get section", () => {
|
||||||
|
const section = body.DefaultSection;
|
||||||
|
|
||||||
|
const tree = new Formatter().format(section);
|
||||||
|
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
||||||
import { Paragraph, ParagraphProperties } from "../..";
|
import { Paragraph, ParagraphProperties, TableOfContents } from "../..";
|
||||||
import { SectionProperties, SectionPropertiesOptions } from "./section-properties/section-properties";
|
import { SectionProperties, SectionPropertiesOptions } from "./section-properties/section-properties";
|
||||||
|
|
||||||
export class Body extends XmlComponent {
|
export class Body extends XmlComponent {
|
||||||
@ -35,11 +35,9 @@ export class Body extends XmlComponent {
|
|||||||
this.sections.push(new SectionProperties(params));
|
this.sections.push(new SectionProperties(params));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public prepForXml(): IXmlableObject {
|
public prepForXml(): IXmlableObject | undefined {
|
||||||
if (this.sections.length === 1) {
|
if (this.sections.length === 1) {
|
||||||
this.root.push(this.sections[0]);
|
this.root.push(this.sections[0]);
|
||||||
} else if (this.sections.length > 1) {
|
|
||||||
throw new Error("Invalid usage of sections. At the end of the body element there must be ONE section.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.prepForXml();
|
return super.prepForXml();
|
||||||
@ -53,6 +51,14 @@ export class Body extends XmlComponent {
|
|||||||
return this.defaultSection;
|
return this.defaultSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getTablesOfContents(): TableOfContents[] {
|
||||||
|
return this.root.filter((child) => child instanceof TableOfContents) as TableOfContents[];
|
||||||
|
}
|
||||||
|
|
||||||
|
public getParagraphs(): Paragraph[] {
|
||||||
|
return this.root.filter((child) => child instanceof Paragraph) as Paragraph[];
|
||||||
|
}
|
||||||
|
|
||||||
private createSectionParagraph(section: SectionProperties): Paragraph {
|
private createSectionParagraph(section: SectionProperties): Paragraph {
|
||||||
const paragraph = new Paragraph();
|
const paragraph = new Paragraph();
|
||||||
const properties = new ParagraphProperties();
|
const properties = new ParagraphProperties();
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IColumnsAttributes {
|
export interface IColumnsAttributes {
|
||||||
space?: number;
|
readonly space?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ColumnsAttributes extends XmlAttributeComponent<IColumnsAttributes> {
|
export class ColumnsAttributes extends XmlAttributeComponent<IColumnsAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
space: "w:space",
|
space: "w:space",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IDocGridAttributesProperties {
|
export interface IDocGridAttributesProperties {
|
||||||
linePitch?: number;
|
readonly linePitch?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
|
export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
linePitch: "w:linePitch",
|
linePitch: "w:linePitch",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,12 @@ export enum FooterReferenceType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IFooterReferenceAttributes {
|
export interface IFooterReferenceAttributes {
|
||||||
type: string;
|
readonly type: string;
|
||||||
id: string;
|
readonly id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FooterReferenceAttributes extends XmlAttributeComponent<IFooterReferenceAttributes> {
|
export class FooterReferenceAttributes extends XmlAttributeComponent<IFooterReferenceAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
type: "w:type",
|
type: "w:type",
|
||||||
id: "r:id",
|
id: "r:id",
|
||||||
};
|
};
|
||||||
|
@ -2,8 +2,8 @@ import { XmlComponent } from "file/xml-components";
|
|||||||
import { FooterReferenceAttributes, FooterReferenceType } from "./footer-reference-attributes";
|
import { FooterReferenceAttributes, FooterReferenceType } from "./footer-reference-attributes";
|
||||||
|
|
||||||
export interface IFooterOptions {
|
export interface IFooterOptions {
|
||||||
footerType?: FooterReferenceType;
|
readonly footerType?: FooterReferenceType;
|
||||||
footerId?: number;
|
readonly footerId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FooterReference extends XmlComponent {
|
export class FooterReference extends XmlComponent {
|
||||||
|
@ -7,12 +7,12 @@ export enum HeaderReferenceType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IHeaderReferenceAttributes {
|
export interface IHeaderReferenceAttributes {
|
||||||
type: string;
|
readonly type: string;
|
||||||
id: string;
|
readonly id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HeaderReferenceAttributes extends XmlAttributeComponent<IHeaderReferenceAttributes> {
|
export class HeaderReferenceAttributes extends XmlAttributeComponent<IHeaderReferenceAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
type: "w:type",
|
type: "w:type",
|
||||||
id: "r:id",
|
id: "r:id",
|
||||||
};
|
};
|
||||||
|
@ -2,8 +2,8 @@ import { XmlComponent } from "file/xml-components";
|
|||||||
import { HeaderReferenceAttributes, HeaderReferenceType } from "./header-reference-attributes";
|
import { HeaderReferenceAttributes, HeaderReferenceType } from "./header-reference-attributes";
|
||||||
|
|
||||||
export interface IHeaderOptions {
|
export interface IHeaderOptions {
|
||||||
headerType?: HeaderReferenceType;
|
readonly headerType?: HeaderReferenceType;
|
||||||
headerId?: number;
|
readonly headerId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HeaderReference extends XmlComponent {
|
export class HeaderReference extends XmlComponent {
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { Formatter } from "../../../../../export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
import { BorderStyle } from "../../../../styles";
|
import { BorderStyle } from "file/styles";
|
||||||
|
|
||||||
import { PageBorderDisplay, PageBorders, PageBorderZOrder } from "./page-borders";
|
import { PageBorderDisplay, PageBorders, PageBorderZOrder } from "./page-borders";
|
||||||
|
|
||||||
describe("PageBorders", () => {
|
describe("PageBorders", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create empty element when no options are passed", () => {
|
it("should create empty element when no options are passed", () => {
|
||||||
const properties = new PageBorders();
|
const properties = new PageBorders();
|
||||||
const tree = new Formatter().format(properties);
|
expect(() => new Formatter().format(properties)).to.throw();
|
||||||
|
|
||||||
expect(tree).to.equal("");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create page borders with some configuration", () => {
|
it("should create page borders with some configuration", () => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// http://officeopenxml.com/WPsectionBorders.php
|
// http://officeopenxml.com/WPsectionBorders.php
|
||||||
|
import { BorderStyle } from "file/styles";
|
||||||
import { IXmlableObject, XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
import { IXmlableObject, XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||||
import { BorderStyle } from "../../../../styles";
|
|
||||||
|
|
||||||
export enum PageBorderDisplay {
|
export enum PageBorderDisplay {
|
||||||
ALL_PAGES = "allPages",
|
ALL_PAGES = "allPages",
|
||||||
@ -19,28 +19,28 @@ export enum PageBorderZOrder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IPageBorderAttributes {
|
export interface IPageBorderAttributes {
|
||||||
display?: PageBorderDisplay;
|
readonly display?: PageBorderDisplay;
|
||||||
offsetFrom?: PageBorderOffsetFrom;
|
readonly offsetFrom?: PageBorderOffsetFrom;
|
||||||
zOrder?: PageBorderZOrder;
|
readonly zOrder?: PageBorderZOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPageBorderConfiguration {
|
export interface IPageBorderConfiguration {
|
||||||
style?: BorderStyle;
|
readonly style?: BorderStyle;
|
||||||
size?: number;
|
readonly size?: number;
|
||||||
color?: string;
|
readonly color?: string;
|
||||||
space?: number;
|
readonly space?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPageBordersOptions {
|
export interface IPageBordersOptions {
|
||||||
pageBorders?: IPageBorderAttributes;
|
readonly pageBorders?: IPageBorderAttributes;
|
||||||
pageBorderTop?: IPageBorderConfiguration;
|
readonly pageBorderTop?: IPageBorderConfiguration;
|
||||||
pageBorderRight?: IPageBorderConfiguration;
|
readonly pageBorderRight?: IPageBorderConfiguration;
|
||||||
pageBorderBottom?: IPageBorderConfiguration;
|
readonly pageBorderBottom?: IPageBorderConfiguration;
|
||||||
pageBorderLeft?: IPageBorderConfiguration;
|
readonly pageBorderLeft?: IPageBorderConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
class PageBordeAttributes extends XmlAttributeComponent<IPageBorderConfiguration> {
|
class PageBordeAttributes extends XmlAttributeComponent<IPageBorderConfiguration> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
style: "w:val",
|
style: "w:val",
|
||||||
size: "w:size",
|
size: "w:size",
|
||||||
color: "w:color",
|
color: "w:color",
|
||||||
@ -57,7 +57,7 @@ class PageBorder extends XmlComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PageBordersAttributes extends XmlAttributeComponent<IPageBorderAttributes> {
|
class PageBordersAttributes extends XmlAttributeComponent<IPageBorderAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
display: "w:display",
|
display: "w:display",
|
||||||
offsetFrom: "w:offsetFrom",
|
offsetFrom: "w:offsetFrom",
|
||||||
zOrder: "w:zOrder",
|
zOrder: "w:zOrder",
|
||||||
@ -98,7 +98,9 @@ export class PageBorders extends XmlComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public prepForXml(): IXmlableObject {
|
public prepForXml(): IXmlableObject | undefined {
|
||||||
return this.root.length > 0 ? super.prepForXml() : "";
|
if (this.root.length > 0) {
|
||||||
|
return super.prepForXml();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IPageMarginAttributes {
|
export interface IPageMarginAttributes {
|
||||||
top?: number;
|
readonly top?: number;
|
||||||
right?: number;
|
readonly right?: number;
|
||||||
bottom?: number;
|
readonly bottom?: number;
|
||||||
left?: number;
|
readonly left?: number;
|
||||||
header?: number;
|
readonly header?: number;
|
||||||
footer?: number;
|
readonly footer?: number;
|
||||||
gutter?: number;
|
readonly gutter?: number;
|
||||||
mirror?: boolean;
|
readonly mirror?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttributes> {
|
export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
top: "w:top",
|
top: "w:top",
|
||||||
right: "w:right",
|
right: "w:right",
|
||||||
bottom: "w:bottom",
|
bottom: "w:bottom",
|
||||||
|
@ -17,12 +17,12 @@ export enum PageNumberFormat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IPageNumberTypeAttributes {
|
export interface IPageNumberTypeAttributes {
|
||||||
pageNumberStart?: number;
|
readonly pageNumberStart?: number;
|
||||||
pageNumberFormatType?: PageNumberFormat;
|
readonly pageNumberFormatType?: PageNumberFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PageNumberTypeAttributes extends XmlAttributeComponent<IPageNumberTypeAttributes> {
|
export class PageNumberTypeAttributes extends XmlAttributeComponent<IPageNumberTypeAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
pageNumberStart: "w:start",
|
pageNumberStart: "w:start",
|
||||||
pageNumberFormatType: "w:fmt",
|
pageNumberFormatType: "w:fmt",
|
||||||
};
|
};
|
||||||
|
@ -6,13 +6,13 @@ export enum PageOrientation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IPageSizeAttributes {
|
export interface IPageSizeAttributes {
|
||||||
width?: number;
|
readonly width?: number;
|
||||||
height?: number;
|
readonly height?: number;
|
||||||
orientation?: PageOrientation;
|
readonly orientation?: PageOrientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PageSizeAttributes extends XmlAttributeComponent<IPageSizeAttributes> {
|
export class PageSizeAttributes extends XmlAttributeComponent<IPageSizeAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
width: "w:w",
|
width: "w:w",
|
||||||
height: "w:h",
|
height: "w:h",
|
||||||
orientation: "w:orient",
|
orientation: "w:orient",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { Formatter } from "../../../../../export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { PageSize } from "./page-size";
|
import { PageSize } from "./page-size";
|
||||||
import { PageOrientation } from "./page-size-attributes";
|
import { PageOrientation } from "./page-size-attributes";
|
||||||
|
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { Formatter } from "../../../../export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
import { FooterReferenceType, PageBorderOffsetFrom, PageNumberFormat } from "./";
|
import { FooterWrapper } from "file/footer-wrapper";
|
||||||
|
import { HeaderWrapper } from "file/header-wrapper";
|
||||||
|
import { Media } from "file/media";
|
||||||
|
|
||||||
|
import { PageBorderOffsetFrom } from "./page-border";
|
||||||
|
import { PageNumberFormat } from "./page-number";
|
||||||
import { SectionProperties } from "./section-properties";
|
import { SectionProperties } from "./section-properties";
|
||||||
|
|
||||||
describe("SectionProperties", () => {
|
describe("SectionProperties", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create section properties with options", () => {
|
it("should create section properties with options", () => {
|
||||||
|
const media = new Media();
|
||||||
|
|
||||||
const properties = new SectionProperties({
|
const properties = new SectionProperties({
|
||||||
width: 11906,
|
width: 11906,
|
||||||
height: 16838,
|
height: 16838,
|
||||||
@ -20,9 +27,12 @@ describe("SectionProperties", () => {
|
|||||||
mirror: false,
|
mirror: false,
|
||||||
space: 708,
|
space: 708,
|
||||||
linePitch: 360,
|
linePitch: 360,
|
||||||
headerId: 100,
|
headers: {
|
||||||
footerId: 200,
|
default: new HeaderWrapper(media, 100),
|
||||||
footerType: FooterReferenceType.EVEN,
|
},
|
||||||
|
footers: {
|
||||||
|
even: new FooterWrapper(media, 200),
|
||||||
|
},
|
||||||
pageNumberStart: 10,
|
pageNumberStart: 10,
|
||||||
pageNumberFormatType: PageNumberFormat.CARDINAL_TEXT,
|
pageNumberFormatType: PageNumberFormat.CARDINAL_TEXT,
|
||||||
});
|
});
|
||||||
@ -78,9 +88,7 @@ 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:headerReference": [{ _attr: { "r:id": "rId0", "w:type": "default" } }] });
|
expect(tree["w:sectPr"][4]).to.deep.equal({ "w:pgNumType": [{ _attr: { "w:fmt": "decimal" } }] });
|
||||||
expect(tree["w:sectPr"][5]).to.deep.equal({ "w:footerReference": [{ _attr: { "r:id": "rId0", "w:type": "default" } }] });
|
|
||||||
expect(tree["w:sectPr"][6]).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", () => {
|
||||||
@ -170,7 +178,8 @@ describe("SectionProperties", () => {
|
|||||||
});
|
});
|
||||||
const tree = new Formatter().format(properties);
|
const tree = new Formatter().format(properties);
|
||||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||||
expect(tree["w:sectPr"][7]).to.deep.equal({
|
const pgBorders = tree["w:sectPr"].find((item) => item["w:pgBorders"] !== undefined);
|
||||||
|
expect(pgBorders).to.deep.equal({
|
||||||
"w:pgBorders": [{ _attr: { "w:offsetFrom": "page" } }],
|
"w:pgBorders": [{ _attr: { "w:offsetFrom": "page" } }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,115 +1,172 @@
|
|||||||
// http://officeopenxml.com/WPsection.php
|
// http://officeopenxml.com/WPsection.php
|
||||||
|
import { FooterWrapper } from "file/footer-wrapper";
|
||||||
|
import { HeaderWrapper } from "file/header-wrapper";
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
import { FooterReferenceType, IPageBordersOptions, IPageNumberTypeAttributes, PageBorders, PageNumberFormat, PageNumberType } from "./";
|
|
||||||
import { Columns } from "./columns/columns";
|
import { Columns } from "./columns/columns";
|
||||||
import { IColumnsAttributes } from "./columns/columns-attributes";
|
import { IColumnsAttributes } from "./columns/columns-attributes";
|
||||||
import { DocumentGrid } from "./doc-grid/doc-grid";
|
import { DocumentGrid } from "./doc-grid/doc-grid";
|
||||||
import { IDocGridAttributesProperties } from "./doc-grid/doc-grid-attributes";
|
import { IDocGridAttributesProperties } from "./doc-grid/doc-grid-attributes";
|
||||||
import { FooterReference, IFooterOptions } from "./footer-reference/footer-reference";
|
import { FooterReferenceType } from "./footer-reference";
|
||||||
import { HeaderReference, IHeaderOptions } from "./header-reference/header-reference";
|
import { FooterReference } from "./footer-reference/footer-reference";
|
||||||
import { HeaderReferenceType } from "./header-reference/header-reference-attributes";
|
import { HeaderReferenceType } from "./header-reference";
|
||||||
|
import { HeaderReference } from "./header-reference/header-reference";
|
||||||
|
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 { 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";
|
||||||
|
|
||||||
|
export interface IHeaderFooterGroup<T> {
|
||||||
|
readonly default?: T;
|
||||||
|
readonly first?: T;
|
||||||
|
readonly even?: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IHeadersOptions {
|
||||||
|
readonly headers?: IHeaderFooterGroup<HeaderWrapper>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IFootersOptions {
|
||||||
|
readonly footers?: IHeaderFooterGroup<FooterWrapper>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ITitlePageOptions {
|
||||||
|
readonly titlePage?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export type SectionPropertiesOptions = IPageSizeAttributes &
|
export type SectionPropertiesOptions = IPageSizeAttributes &
|
||||||
IPageMarginAttributes &
|
IPageMarginAttributes &
|
||||||
IColumnsAttributes &
|
IColumnsAttributes &
|
||||||
IDocGridAttributesProperties &
|
IDocGridAttributesProperties &
|
||||||
IHeaderOptions &
|
IHeadersOptions &
|
||||||
IFooterOptions &
|
IFootersOptions &
|
||||||
IPageNumberTypeAttributes &
|
IPageNumberTypeAttributes &
|
||||||
IPageBordersOptions;
|
IPageBordersOptions &
|
||||||
|
ITitlePageOptions;
|
||||||
|
|
||||||
export class SectionProperties extends XmlComponent {
|
export class SectionProperties extends XmlComponent {
|
||||||
private readonly options: SectionPropertiesOptions;
|
private readonly options: SectionPropertiesOptions;
|
||||||
|
|
||||||
constructor(options?: SectionPropertiesOptions) {
|
constructor(options: SectionPropertiesOptions = {}) {
|
||||||
super("w:sectPr");
|
super("w:sectPr");
|
||||||
|
|
||||||
const defaultOptions = {
|
const {
|
||||||
width: 11906,
|
width = 11906,
|
||||||
height: 16838,
|
height = 16838,
|
||||||
top: 1440,
|
top = 1440,
|
||||||
right: 1440,
|
right = 1440,
|
||||||
bottom: 1440,
|
bottom = 1440,
|
||||||
left: 1440,
|
left = 1440,
|
||||||
header: 708,
|
header = 708,
|
||||||
footer: 708,
|
footer = 708,
|
||||||
gutter: 0,
|
gutter = 0,
|
||||||
mirror: false,
|
mirror = false,
|
||||||
space: 708,
|
space = 708,
|
||||||
linePitch: 360,
|
linePitch = 360,
|
||||||
orientation: PageOrientation.PORTRAIT,
|
orientation = PageOrientation.PORTRAIT,
|
||||||
headerType: HeaderReferenceType.DEFAULT,
|
headers,
|
||||||
headerId: 0,
|
footers,
|
||||||
footerType: FooterReferenceType.DEFAULT,
|
pageNumberFormatType = PageNumberFormat.DECIMAL,
|
||||||
footerId: 0,
|
pageNumberStart,
|
||||||
pageNumberStart: undefined,
|
pageBorders,
|
||||||
pageNumberFormatType: PageNumberFormat.DECIMAL,
|
pageBorderTop,
|
||||||
pageBorders: undefined,
|
pageBorderRight,
|
||||||
pageBorderTop: undefined,
|
pageBorderBottom,
|
||||||
pageBorderRight: undefined,
|
pageBorderLeft,
|
||||||
pageBorderBottom: undefined,
|
titlePage = false,
|
||||||
pageBorderLeft: undefined,
|
} = options;
|
||||||
};
|
|
||||||
|
|
||||||
const mergedOptions = {
|
this.options = options;
|
||||||
...defaultOptions,
|
this.root.push(new PageSize(width, height, orientation));
|
||||||
...options,
|
this.root.push(new PageMargin(top, right, bottom, left, header, footer, gutter, mirror));
|
||||||
};
|
this.root.push(new Columns(space));
|
||||||
|
this.root.push(new DocumentGrid(linePitch));
|
||||||
|
|
||||||
this.root.push(new PageSize(mergedOptions.width, mergedOptions.height, mergedOptions.orientation));
|
this.addHeaders(headers);
|
||||||
this.root.push(
|
this.addFooters(footers);
|
||||||
new PageMargin(
|
|
||||||
mergedOptions.top,
|
|
||||||
mergedOptions.right,
|
|
||||||
mergedOptions.bottom,
|
|
||||||
mergedOptions.left,
|
|
||||||
mergedOptions.header,
|
|
||||||
mergedOptions.footer,
|
|
||||||
mergedOptions.gutter,
|
|
||||||
mergedOptions.mirror,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
this.root.push(new Columns(mergedOptions.space));
|
|
||||||
this.root.push(new DocumentGrid(mergedOptions.linePitch));
|
|
||||||
|
|
||||||
this.root.push(
|
this.root.push(new PageNumberType(pageNumberStart, pageNumberFormatType));
|
||||||
new HeaderReference({
|
|
||||||
headerType: mergedOptions.headerType,
|
|
||||||
headerId: mergedOptions.headerId,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
this.root.push(
|
|
||||||
new FooterReference({
|
|
||||||
footerType: mergedOptions.footerType,
|
|
||||||
footerId: mergedOptions.footerId,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
this.root.push(new PageNumberType(mergedOptions.pageNumberStart, mergedOptions.pageNumberFormatType));
|
if (pageBorders || pageBorderTop || pageBorderRight || pageBorderBottom || pageBorderLeft) {
|
||||||
|
|
||||||
if (
|
|
||||||
mergedOptions.pageBorders ||
|
|
||||||
mergedOptions.pageBorderTop ||
|
|
||||||
mergedOptions.pageBorderRight ||
|
|
||||||
mergedOptions.pageBorderBottom ||
|
|
||||||
mergedOptions.pageBorderLeft
|
|
||||||
) {
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new PageBorders({
|
new PageBorders({
|
||||||
pageBorders: mergedOptions.pageBorders,
|
pageBorders: pageBorders,
|
||||||
pageBorderTop: mergedOptions.pageBorderTop,
|
pageBorderTop: pageBorderTop,
|
||||||
pageBorderRight: mergedOptions.pageBorderRight,
|
pageBorderRight: pageBorderRight,
|
||||||
pageBorderBottom: mergedOptions.pageBorderBottom,
|
pageBorderBottom: pageBorderBottom,
|
||||||
pageBorderLeft: mergedOptions.pageBorderLeft,
|
pageBorderLeft: pageBorderLeft,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.options = mergedOptions;
|
if (titlePage) {
|
||||||
|
this.root.push(new TitlePage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private addHeaders(headers?: IHeaderFooterGroup<HeaderWrapper>): void {
|
||||||
|
if (headers) {
|
||||||
|
if (headers.default) {
|
||||||
|
this.root.push(
|
||||||
|
new HeaderReference({
|
||||||
|
headerType: HeaderReferenceType.DEFAULT,
|
||||||
|
headerId: headers.default.Header.ReferenceId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headers.first) {
|
||||||
|
this.root.push(
|
||||||
|
new HeaderReference({
|
||||||
|
headerType: HeaderReferenceType.FIRST,
|
||||||
|
headerId: headers.first.Header.ReferenceId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headers.even) {
|
||||||
|
this.root.push(
|
||||||
|
new HeaderReference({
|
||||||
|
headerType: HeaderReferenceType.EVEN,
|
||||||
|
headerId: headers.even.Header.ReferenceId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private addFooters(footers?: IHeaderFooterGroup<FooterWrapper>): void {
|
||||||
|
if (footers) {
|
||||||
|
if (footers.default) {
|
||||||
|
this.root.push(
|
||||||
|
new FooterReference({
|
||||||
|
footerType: FooterReferenceType.DEFAULT,
|
||||||
|
footerId: footers.default.Footer.ReferenceId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (footers.first) {
|
||||||
|
this.root.push(
|
||||||
|
new FooterReference({
|
||||||
|
footerType: FooterReferenceType.FIRST,
|
||||||
|
footerId: footers.first.Footer.ReferenceId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (footers.even) {
|
||||||
|
this.root.push(
|
||||||
|
new FooterReference({
|
||||||
|
footerType: FooterReferenceType.EVEN,
|
||||||
|
footerId: footers.even.Footer.ReferenceId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public get Options(): SectionPropertiesOptions {
|
public get Options(): SectionPropertiesOptions {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IHeaderReferenceAttributes {
|
export interface IHeaderReferenceAttributes {
|
||||||
value: string;
|
readonly value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TitlePageAttributes extends XmlAttributeComponent<IHeaderReferenceAttributes> {
|
export class TitlePageAttributes extends XmlAttributeComponent<IHeaderReferenceAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
value: "w:val",
|
value: "w:val",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { Formatter } from "../../../../../export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { TitlePage } from "./title-page";
|
import { TitlePage } from "./title-page";
|
||||||
|
|
||||||
describe("PageSize", () => {
|
describe("PageSize", () => {
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IDocumentAttributesProperties {
|
export interface IDocumentAttributesProperties {
|
||||||
wpc?: string;
|
readonly wpc?: string;
|
||||||
mc?: string;
|
readonly mc?: string;
|
||||||
o?: string;
|
readonly o?: string;
|
||||||
r?: string;
|
readonly r?: string;
|
||||||
m?: string;
|
readonly m?: string;
|
||||||
v?: string;
|
readonly v?: string;
|
||||||
wp14?: string;
|
readonly wp14?: string;
|
||||||
wp?: string;
|
readonly wp?: string;
|
||||||
w10?: string;
|
readonly w10?: string;
|
||||||
w?: string;
|
readonly w?: string;
|
||||||
w14?: string;
|
readonly w14?: string;
|
||||||
w15?: string;
|
readonly w15?: string;
|
||||||
wpg?: string;
|
readonly wpg?: string;
|
||||||
wpi?: string;
|
readonly wpi?: string;
|
||||||
wne?: string;
|
readonly wne?: string;
|
||||||
wps?: string;
|
readonly wps?: string;
|
||||||
Ignorable?: string;
|
readonly Ignorable?: string;
|
||||||
cp?: string;
|
readonly cp?: string;
|
||||||
dc?: string;
|
readonly dc?: string;
|
||||||
dcterms?: string;
|
readonly dcterms?: string;
|
||||||
dcmitype?: string;
|
readonly dcmitype?: string;
|
||||||
xsi?: string;
|
readonly xsi?: string;
|
||||||
type?: string;
|
readonly type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DocumentAttributes extends XmlAttributeComponent<IDocumentAttributesProperties> {
|
export class DocumentAttributes extends XmlAttributeComponent<IDocumentAttributesProperties> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
wpc: "xmlns:wpc",
|
wpc: "xmlns:wpc",
|
||||||
mc: "xmlns:mc",
|
mc: "xmlns:mc",
|
||||||
o: "xmlns:o",
|
o: "xmlns:o",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { assert, expect } from "chai";
|
import { assert, expect } from "chai";
|
||||||
|
|
||||||
import { Formatter } from "../../export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { Paragraph } from "../paragraph";
|
import { Paragraph } from "../paragraph";
|
||||||
import { Table } from "../table";
|
import { Table } from "../table";
|
||||||
import { Document } from "./document";
|
import { Document } from "./document";
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
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 { Table } from "../table";
|
||||||
|
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";
|
||||||
import { DocumentAttributes } from "./document-attributes";
|
import { DocumentAttributes } from "./document-attributes";
|
||||||
@ -41,6 +42,11 @@ export class Document extends XmlComponent {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addTableOfContents(toc: TableOfContents): Document {
|
||||||
|
this.body.push(toc);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public createParagraph(text?: string): Paragraph {
|
public createParagraph(text?: string): Paragraph {
|
||||||
const para = new Paragraph(text);
|
const para = new Paragraph(text);
|
||||||
this.addParagraph(para);
|
this.addParagraph(para);
|
||||||
@ -60,4 +66,12 @@ export class Document extends XmlComponent {
|
|||||||
public get Body(): Body {
|
public get Body(): Body {
|
||||||
return this.body;
|
return this.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getTablesOfContents(): TableOfContents[] {
|
||||||
|
return this.body.getTablesOfContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getParagraphs(): Paragraph[] {
|
||||||
|
return this.body.getParagraphs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,16 @@ import { XmlAttributeComponent } from "file/xml-components";
|
|||||||
import { IDistance } from "../drawing";
|
import { IDistance } from "../drawing";
|
||||||
|
|
||||||
export interface IAnchorAttributes extends IDistance {
|
export interface IAnchorAttributes extends IDistance {
|
||||||
allowOverlap?: "0" | "1";
|
readonly allowOverlap?: "0" | "1";
|
||||||
behindDoc?: "0" | "1";
|
readonly behindDoc?: "0" | "1";
|
||||||
layoutInCell?: "0" | "1";
|
readonly layoutInCell?: "0" | "1";
|
||||||
locked?: "0" | "1";
|
readonly locked?: "0" | "1";
|
||||||
relativeHeight?: number;
|
readonly relativeHeight?: number;
|
||||||
simplePos?: "0" | "1";
|
readonly simplePos?: "0" | "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AnchorAttributes extends XmlAttributeComponent<IAnchorAttributes> {
|
export class AnchorAttributes extends XmlAttributeComponent<IAnchorAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
distT: "distT",
|
distT: "distT",
|
||||||
distB: "distB",
|
distB: "distB",
|
||||||
distL: "distL",
|
distL: "distL",
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { assert } from "chai";
|
import { assert } from "chai";
|
||||||
|
|
||||||
import { Utility } from "../../../tests/utility";
|
import { Utility } from "tests/utility";
|
||||||
import { IDrawingOptions, TextWrapStyle } from ".././";
|
|
||||||
import { Anchor } from "./";
|
|
||||||
|
|
||||||
function createDrawing(drawingOptions: IDrawingOptions): Anchor {
|
import { IDrawingOptions } from "../drawing";
|
||||||
|
import { TextWrapStyle } from "../text-wrap";
|
||||||
|
import { Anchor } from "./anchor";
|
||||||
|
|
||||||
|
function createAnchor(drawingOptions: IDrawingOptions): Anchor {
|
||||||
return new Anchor(
|
return new Anchor(
|
||||||
1,
|
1,
|
||||||
{
|
{
|
||||||
@ -26,14 +28,32 @@ describe("Anchor", () => {
|
|||||||
|
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a Drawing with correct root key", () => {
|
it("should create a Drawing with correct root key", () => {
|
||||||
anchor = createDrawing({});
|
anchor = createAnchor({
|
||||||
|
floating: {
|
||||||
|
verticalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
horizontalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
const newJson = Utility.jsonify(anchor);
|
const newJson = Utility.jsonify(anchor);
|
||||||
assert.equal(newJson.rootKey, "wp:anchor");
|
assert.equal(newJson.rootKey, "wp:anchor");
|
||||||
assert.equal(newJson.root.length, 10);
|
assert.equal(newJson.root.length, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create a Drawing with all default options", () => {
|
it("should create a Drawing with all default options", () => {
|
||||||
anchor = createDrawing({});
|
anchor = createAnchor({
|
||||||
|
floating: {
|
||||||
|
verticalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
horizontalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
const newJson = Utility.jsonify(anchor);
|
const newJson = Utility.jsonify(anchor);
|
||||||
assert.equal(newJson.root.length, 10);
|
assert.equal(newJson.root.length, 10);
|
||||||
|
|
||||||
@ -58,7 +78,7 @@ describe("Anchor", () => {
|
|||||||
const horizontalPosition = newJson.root[2];
|
const horizontalPosition = newJson.root[2];
|
||||||
assert.equal(horizontalPosition.rootKey, "wp:positionH");
|
assert.equal(horizontalPosition.rootKey, "wp:positionH");
|
||||||
assert.include(horizontalPosition.root[0].root, {
|
assert.include(horizontalPosition.root[0].root, {
|
||||||
relativeFrom: "column",
|
relativeFrom: "page",
|
||||||
});
|
});
|
||||||
assert.equal(horizontalPosition.root[1].rootKey, "wp:posOffset");
|
assert.equal(horizontalPosition.root[1].rootKey, "wp:posOffset");
|
||||||
assert.include(horizontalPosition.root[1].root[0], 0);
|
assert.include(horizontalPosition.root[1].root[0], 0);
|
||||||
@ -67,7 +87,7 @@ describe("Anchor", () => {
|
|||||||
const verticalPosition = newJson.root[3];
|
const verticalPosition = newJson.root[3];
|
||||||
assert.equal(verticalPosition.rootKey, "wp:positionV");
|
assert.equal(verticalPosition.rootKey, "wp:positionV");
|
||||||
assert.include(verticalPosition.root[0].root, {
|
assert.include(verticalPosition.root[0].root, {
|
||||||
relativeFrom: "paragraph",
|
relativeFrom: "page",
|
||||||
});
|
});
|
||||||
assert.equal(verticalPosition.root[1].rootKey, "wp:posOffset");
|
assert.equal(verticalPosition.root[1].rootKey, "wp:posOffset");
|
||||||
assert.include(verticalPosition.root[1].root[0], 0);
|
assert.include(verticalPosition.root[1].root[0], 0);
|
||||||
@ -101,11 +121,19 @@ describe("Anchor", () => {
|
|||||||
assert.equal(graphic.rootKey, "a:graphic");
|
assert.equal(graphic.rootKey, "a:graphic");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create a Drawing with text wrapping", () => {
|
it("should create a Drawing with square text wrapping", () => {
|
||||||
anchor = createDrawing({
|
anchor = createAnchor({
|
||||||
textWrapping: {
|
textWrapping: {
|
||||||
textWrapStyle: TextWrapStyle.SQUARE,
|
textWrapStyle: TextWrapStyle.SQUARE,
|
||||||
},
|
},
|
||||||
|
floating: {
|
||||||
|
verticalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
horizontalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const newJson = Utility.jsonify(anchor);
|
const newJson = Utility.jsonify(anchor);
|
||||||
assert.equal(newJson.root.length, 10);
|
assert.equal(newJson.root.length, 10);
|
||||||
@ -114,5 +142,68 @@ describe("Anchor", () => {
|
|||||||
const textWrap = newJson.root[6];
|
const textWrap = newJson.root[6];
|
||||||
assert.equal(textWrap.rootKey, "wp:wrapSquare");
|
assert.equal(textWrap.rootKey, "wp:wrapSquare");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should create a Drawing with no text wrapping", () => {
|
||||||
|
anchor = createAnchor({
|
||||||
|
textWrapping: {
|
||||||
|
textWrapStyle: TextWrapStyle.NONE,
|
||||||
|
},
|
||||||
|
floating: {
|
||||||
|
verticalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
horizontalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const newJson = Utility.jsonify(anchor);
|
||||||
|
assert.equal(newJson.root.length, 10);
|
||||||
|
|
||||||
|
const textWrap = newJson.root[6];
|
||||||
|
assert.equal(textWrap.rootKey, "wp:wrapNone");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create a Drawing with tight text wrapping", () => {
|
||||||
|
anchor = createAnchor({
|
||||||
|
textWrapping: {
|
||||||
|
textWrapStyle: TextWrapStyle.TIGHT,
|
||||||
|
},
|
||||||
|
floating: {
|
||||||
|
horizontalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
verticalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const newJson = Utility.jsonify(anchor);
|
||||||
|
assert.equal(newJson.root.length, 10);
|
||||||
|
|
||||||
|
const textWrap = newJson.root[6];
|
||||||
|
assert.equal(textWrap.rootKey, "wp:wrapTight");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create a Drawing with tight text wrapping", () => {
|
||||||
|
anchor = createAnchor({
|
||||||
|
textWrapping: {
|
||||||
|
textWrapStyle: TextWrapStyle.TOP_AND_BOTTOM,
|
||||||
|
},
|
||||||
|
floating: {
|
||||||
|
verticalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
horizontalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const newJson = Utility.jsonify(anchor);
|
||||||
|
assert.equal(newJson.root.length, 10);
|
||||||
|
|
||||||
|
const textWrap = newJson.root[6];
|
||||||
|
assert.equal(textWrap.rootKey, "wp:wrapTopAndBottom");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,14 +2,7 @@
|
|||||||
import { IMediaDataDimensions } from "file/media";
|
import { 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 {
|
import { HorizontalPosition, IFloating, SimplePos, VerticalPosition } from "../floating";
|
||||||
HorizontalPosition,
|
|
||||||
HorizontalPositionRelativeFrom,
|
|
||||||
IFloating,
|
|
||||||
SimplePos,
|
|
||||||
VerticalPosition,
|
|
||||||
VerticalPositionRelativeFrom,
|
|
||||||
} from "../floating";
|
|
||||||
import { Graphic } from "../inline/graphic";
|
import { Graphic } from "../inline/graphic";
|
||||||
import { TextWrapStyle, WrapNone, WrapSquare, WrapTight, WrapTopAndBottom } from "../text-wrap";
|
import { TextWrapStyle, WrapNone, WrapSquare, WrapTight, WrapTopAndBottom } from "../text-wrap";
|
||||||
import { DocProperties } from "./../doc-properties/doc-properties";
|
import { DocProperties } from "./../doc-properties/doc-properties";
|
||||||
@ -23,14 +16,8 @@ const defaultOptions: IFloating = {
|
|||||||
behindDocument: false,
|
behindDocument: false,
|
||||||
lockAnchor: false,
|
lockAnchor: false,
|
||||||
layoutInCell: true,
|
layoutInCell: true,
|
||||||
verticalPosition: {
|
verticalPosition: {},
|
||||||
relative: VerticalPositionRelativeFrom.PARAGRAPH,
|
horizontalPosition: {},
|
||||||
offset: 0,
|
|
||||||
},
|
|
||||||
horizontalPosition: {
|
|
||||||
relative: HorizontalPositionRelativeFrom.COLUMN,
|
|
||||||
offset: 0,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Anchor extends XmlComponent {
|
export class Anchor extends XmlComponent {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IDocPropertiesAttributes {
|
export interface IDocPropertiesAttributes {
|
||||||
id?: number;
|
readonly id?: number;
|
||||||
name?: string;
|
readonly name?: string;
|
||||||
descr?: string;
|
readonly descr?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DocPropertiesAttributes extends XmlAttributeComponent<IDocPropertiesAttributes> {
|
export class DocPropertiesAttributes extends XmlAttributeComponent<IDocPropertiesAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
id: "id",
|
id: "id",
|
||||||
name: "name",
|
name: "name",
|
||||||
descr: "descr",
|
descr: "descr",
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { assert } from "chai";
|
import { assert } from "chai";
|
||||||
|
|
||||||
import { Utility } from "../../tests/utility";
|
import { Utility } from "tests/utility";
|
||||||
import { Drawing, IDrawingOptions, PlacementPosition } from "./";
|
|
||||||
|
import { Drawing, IDrawingOptions } from "./drawing";
|
||||||
|
|
||||||
const imageBase64Data = `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`;
|
const imageBase64Data = `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`;
|
||||||
|
|
||||||
@ -46,7 +47,14 @@ describe("Drawing", () => {
|
|||||||
|
|
||||||
it("should create a drawing with anchor element when there options are passed", () => {
|
it("should create a drawing with anchor element when there options are passed", () => {
|
||||||
currentBreak = createDrawing({
|
currentBreak = createDrawing({
|
||||||
position: PlacementPosition.FLOATING,
|
floating: {
|
||||||
|
horizontalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
verticalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const newJson = Utility.jsonify(currentBreak);
|
const newJson = Utility.jsonify(currentBreak);
|
||||||
assert.equal(newJson.root[0].rootKey, "wp:anchor");
|
assert.equal(newJson.root[0].rootKey, "wp:anchor");
|
||||||
|
@ -5,48 +5,33 @@ import { IFloating } from "./floating";
|
|||||||
import { Inline } from "./inline";
|
import { Inline } from "./inline";
|
||||||
import { ITextWrapping } from "./text-wrap";
|
import { ITextWrapping } from "./text-wrap";
|
||||||
|
|
||||||
export enum PlacementPosition {
|
|
||||||
INLINE,
|
|
||||||
FLOATING,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IDistance {
|
export interface IDistance {
|
||||||
distT?: number;
|
readonly distT?: number;
|
||||||
distB?: number;
|
readonly distB?: number;
|
||||||
distL?: number;
|
readonly distL?: number;
|
||||||
distR?: number;
|
readonly distR?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDrawingOptions {
|
export interface IDrawingOptions {
|
||||||
position?: PlacementPosition;
|
readonly textWrapping?: ITextWrapping;
|
||||||
textWrapping?: ITextWrapping;
|
readonly floating?: IFloating;
|
||||||
floating?: IFloating;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultDrawingOptions: IDrawingOptions = {
|
|
||||||
position: PlacementPosition.INLINE,
|
|
||||||
};
|
|
||||||
|
|
||||||
export class Drawing extends XmlComponent {
|
export class Drawing extends XmlComponent {
|
||||||
private readonly inline: Inline;
|
private readonly inline: Inline;
|
||||||
|
|
||||||
constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) {
|
constructor(imageData: IMediaData, drawingOptions: IDrawingOptions = {}) {
|
||||||
super("w:drawing");
|
super("w:drawing");
|
||||||
|
|
||||||
if (imageData === undefined) {
|
if (imageData === undefined) {
|
||||||
throw new Error("imageData cannot be undefined");
|
throw new Error("imageData cannot be undefined");
|
||||||
}
|
}
|
||||||
|
|
||||||
const mergedOptions = {
|
if (!drawingOptions.floating) {
|
||||||
...defaultDrawingOptions,
|
|
||||||
...drawingOptions,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (mergedOptions.position === PlacementPosition.INLINE) {
|
|
||||||
this.inline = new Inline(imageData.referenceId, imageData.dimensions);
|
this.inline = new Inline(imageData.referenceId, imageData.dimensions);
|
||||||
this.root.push(this.inline);
|
this.root.push(this.inline);
|
||||||
} else if (mergedOptions.position === PlacementPosition.FLOATING) {
|
} else {
|
||||||
this.root.push(new Anchor(imageData.referenceId, imageData.dimensions, mergedOptions));
|
this.root.push(new Anchor(imageData.referenceId, imageData.dimensions, drawingOptions));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IEffectExtentAttributes {
|
export interface IEffectExtentAttributes {
|
||||||
b?: number;
|
readonly b?: number;
|
||||||
l?: number;
|
readonly l?: number;
|
||||||
r?: number;
|
readonly r?: number;
|
||||||
t?: number;
|
readonly t?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EffectExtentAttributes extends XmlAttributeComponent<IEffectExtentAttributes> {
|
export class EffectExtentAttributes extends XmlAttributeComponent<IEffectExtentAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
b: "b",
|
b: "b",
|
||||||
l: "l",
|
l: "l",
|
||||||
r: "r",
|
r: "r",
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IExtentAttributes {
|
export interface IExtentAttributes {
|
||||||
cx?: number;
|
readonly cx?: number;
|
||||||
cy?: number;
|
readonly cy?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExtentAttributes extends XmlAttributeComponent<IExtentAttributes> {
|
export class ExtentAttributes extends XmlAttributeComponent<IExtentAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
cx: "cx",
|
cx: "cx",
|
||||||
cy: "cy",
|
cy: "cy",
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
import { ExtentAttributes } from "./extent-attributes";
|
import { ExtentAttributes } from "./extent-attributes";
|
||||||
|
|
||||||
export class Extent extends XmlComponent {
|
export class Extent extends XmlComponent {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { assert } from "chai";
|
import { assert } from "chai";
|
||||||
|
|
||||||
import { VerticalPositionAlign } from ".";
|
import { Utility } from "tests/utility";
|
||||||
import { Utility } from "../../../tests/utility";
|
|
||||||
import { Align } from "./align";
|
import { Align } from "./align";
|
||||||
|
import { VerticalPositionAlign } from "./floating-position";
|
||||||
|
|
||||||
describe("Align", () => {
|
describe("Align", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
|
@ -39,22 +39,22 @@ export enum VerticalPositionAlign {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IHorizontalPositionOptions {
|
export interface IHorizontalPositionOptions {
|
||||||
relative: HorizontalPositionRelativeFrom;
|
readonly relative?: HorizontalPositionRelativeFrom;
|
||||||
align?: HorizontalPositionAlign;
|
readonly align?: HorizontalPositionAlign;
|
||||||
offset?: number;
|
readonly offset?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVerticalPositionOptions {
|
export interface IVerticalPositionOptions {
|
||||||
relative: VerticalPositionRelativeFrom;
|
readonly relative?: VerticalPositionRelativeFrom;
|
||||||
align?: VerticalPositionAlign;
|
readonly align?: VerticalPositionAlign;
|
||||||
offset?: number;
|
readonly offset?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFloating {
|
export interface IFloating {
|
||||||
horizontalPosition: IHorizontalPositionOptions;
|
readonly horizontalPosition: IHorizontalPositionOptions;
|
||||||
verticalPosition: IVerticalPositionOptions;
|
readonly verticalPosition: IVerticalPositionOptions;
|
||||||
allowOverlap?: boolean;
|
readonly allowOverlap?: boolean;
|
||||||
lockAnchor?: boolean;
|
readonly lockAnchor?: boolean;
|
||||||
behindDocument?: boolean;
|
readonly behindDocument?: boolean;
|
||||||
layoutInCell?: boolean;
|
readonly layoutInCell?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { assert } from "chai";
|
import { assert } from "chai";
|
||||||
|
|
||||||
import { HorizontalPositionAlign, HorizontalPositionRelativeFrom } from ".";
|
import { Utility } from "tests/utility";
|
||||||
import { Utility } from "../../../tests/utility";
|
|
||||||
|
import { HorizontalPositionAlign, HorizontalPositionRelativeFrom } from "./floating-position";
|
||||||
import { HorizontalPosition } from "./horizontal-position";
|
import { HorizontalPosition } from "./horizontal-position";
|
||||||
|
|
||||||
describe("HorizontalPosition", () => {
|
describe("HorizontalPosition", () => {
|
||||||
|
@ -5,11 +5,11 @@ import { HorizontalPositionRelativeFrom, IHorizontalPositionOptions } from "./fl
|
|||||||
import { PositionOffset } from "./position-offset";
|
import { PositionOffset } from "./position-offset";
|
||||||
|
|
||||||
interface IHorizontalPositionAttributes {
|
interface IHorizontalPositionAttributes {
|
||||||
relativeFrom: HorizontalPositionRelativeFrom;
|
readonly relativeFrom: HorizontalPositionRelativeFrom;
|
||||||
}
|
}
|
||||||
|
|
||||||
class HorizontalPositionAttributes extends XmlAttributeComponent<IHorizontalPositionAttributes> {
|
class HorizontalPositionAttributes extends XmlAttributeComponent<IHorizontalPositionAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
relativeFrom: "relativeFrom",
|
relativeFrom: "relativeFrom",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -20,7 +20,7 @@ export class HorizontalPosition extends XmlComponent {
|
|||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new HorizontalPositionAttributes({
|
new HorizontalPositionAttributes({
|
||||||
relativeFrom: horizontalPosition.relative,
|
relativeFrom: horizontalPosition.relative || HorizontalPositionRelativeFrom.PAGE,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { assert } from "chai";
|
import { assert } from "chai";
|
||||||
|
|
||||||
import { Utility } from "../../../tests/utility";
|
import { Utility } from "tests/utility";
|
||||||
|
|
||||||
import { PositionOffset } from "./position-offset";
|
import { PositionOffset } from "./position-offset";
|
||||||
|
|
||||||
describe("PositionOffset", () => {
|
describe("PositionOffset", () => {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { assert } from "chai";
|
import { assert } from "chai";
|
||||||
|
|
||||||
import { Utility } from "../../../tests/utility";
|
import { Utility } from "tests/utility";
|
||||||
|
|
||||||
import { SimplePos } from "./simple-pos";
|
import { SimplePos } from "./simple-pos";
|
||||||
|
|
||||||
describe("SimplePos", () => {
|
describe("SimplePos", () => {
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
interface ISimplePosAttributes {
|
interface ISimplePosAttributes {
|
||||||
x: number;
|
readonly x: number;
|
||||||
y: number;
|
readonly y: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SimplePosAttributes extends XmlAttributeComponent<ISimplePosAttributes> {
|
class SimplePosAttributes extends XmlAttributeComponent<ISimplePosAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
x: "x",
|
x: "x",
|
||||||
y: "y",
|
y: "y",
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { assert } from "chai";
|
import { assert } from "chai";
|
||||||
|
|
||||||
import { VerticalPositionAlign, VerticalPositionRelativeFrom } from ".";
|
import { Utility } from "tests/utility";
|
||||||
import { Utility } from "../../../tests/utility";
|
|
||||||
|
import { VerticalPositionAlign, VerticalPositionRelativeFrom } from "./floating-position";
|
||||||
import { VerticalPosition } from "./vertical-position";
|
import { VerticalPosition } from "./vertical-position";
|
||||||
|
|
||||||
describe("VerticalPosition", () => {
|
describe("VerticalPosition", () => {
|
||||||
|
@ -5,11 +5,11 @@ import { IVerticalPositionOptions, VerticalPositionRelativeFrom } from "./floati
|
|||||||
import { PositionOffset } from "./position-offset";
|
import { PositionOffset } from "./position-offset";
|
||||||
|
|
||||||
interface IVerticalPositionAttributes {
|
interface IVerticalPositionAttributes {
|
||||||
relativeFrom: VerticalPositionRelativeFrom;
|
readonly relativeFrom: VerticalPositionRelativeFrom;
|
||||||
}
|
}
|
||||||
|
|
||||||
class VerticalPositionAttributes extends XmlAttributeComponent<IVerticalPositionAttributes> {
|
class VerticalPositionAttributes extends XmlAttributeComponent<IVerticalPositionAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
relativeFrom: "relativeFrom",
|
relativeFrom: "relativeFrom",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -20,7 +20,7 @@ export class VerticalPosition extends XmlComponent {
|
|||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new VerticalPositionAttributes({
|
new VerticalPositionAttributes({
|
||||||
relativeFrom: verticalPosition.relative,
|
relativeFrom: verticalPosition.relative || VerticalPositionRelativeFrom.PAGE,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IGraphicFrameLockAttributes {
|
export interface IGraphicFrameLockAttributes {
|
||||||
xmlns?: string;
|
readonly xmlns?: string;
|
||||||
noChangeAspect?: number;
|
readonly noChangeAspect?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GraphicFrameLockAttributes extends XmlAttributeComponent<IGraphicFrameLockAttributes> {
|
export class GraphicFrameLockAttributes extends XmlAttributeComponent<IGraphicFrameLockAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
xmlns: "xmlns:a",
|
xmlns: "xmlns:a",
|
||||||
noChangeAspect: "noChangeAspect",
|
noChangeAspect: "noChangeAspect",
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IGraphicDataAttributes {
|
export interface IGraphicDataAttributes {
|
||||||
uri?: string;
|
readonly uri?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GraphicDataAttributes extends XmlAttributeComponent<IGraphicDataAttributes> {
|
export class GraphicDataAttributes extends XmlAttributeComponent<IGraphicDataAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
uri: "uri",
|
uri: "uri",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
interface IBlipProperties {
|
interface IBlipProperties {
|
||||||
embed: string;
|
readonly embed: string;
|
||||||
cstate: string;
|
readonly cstate: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class BlipAttributes extends XmlAttributeComponent<IBlipProperties> {
|
class BlipAttributes extends XmlAttributeComponent<IBlipProperties> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
embed: "r:embed",
|
embed: "r:embed",
|
||||||
cstate: "cstate",
|
cstate: "cstate",
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IPicLocksAttributes {
|
export interface IPicLocksAttributes {
|
||||||
noChangeAspect?: number;
|
readonly noChangeAspect?: number;
|
||||||
noChangeArrowheads?: number;
|
readonly noChangeArrowheads?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PicLocksAttributes extends XmlAttributeComponent<IPicLocksAttributes> {
|
export class PicLocksAttributes extends XmlAttributeComponent<IPicLocksAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
noChangeAspect: "noChangeAspect",
|
noChangeAspect: "noChangeAspect",
|
||||||
noChangeArrowheads: "noChangeArrowheads",
|
noChangeArrowheads: "noChangeArrowheads",
|
||||||
};
|
};
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface INonVisualPropertiesAttributes {
|
export interface INonVisualPropertiesAttributes {
|
||||||
id?: number;
|
readonly id?: number;
|
||||||
name?: string;
|
readonly name?: string;
|
||||||
descr?: string;
|
readonly descr?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NonVisualPropertiesAttributes extends XmlAttributeComponent<INonVisualPropertiesAttributes> {
|
export class NonVisualPropertiesAttributes extends XmlAttributeComponent<INonVisualPropertiesAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
id: "id",
|
id: "id",
|
||||||
name: "name",
|
name: "name",
|
||||||
descr: "desc",
|
descr: "desc",
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IPicAttributes {
|
export interface IPicAttributes {
|
||||||
xmlns?: string;
|
readonly xmlns?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PicAttributes extends XmlAttributeComponent<IPicAttributes> {
|
export class PicAttributes extends XmlAttributeComponent<IPicAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
xmlns: "xmlns:pic",
|
xmlns: "xmlns:pic",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IExtentsAttributes {
|
export interface IExtentsAttributes {
|
||||||
cx?: number;
|
readonly cx?: number;
|
||||||
cy?: number;
|
readonly cy?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExtentsAttributes extends XmlAttributeComponent<IExtentsAttributes> {
|
export class ExtentsAttributes extends XmlAttributeComponent<IExtentsAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
cx: "cx",
|
cx: "cx",
|
||||||
cy: "cy",
|
cy: "cy",
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IOffsetAttributes {
|
export interface IOffsetAttributes {
|
||||||
x?: number;
|
readonly x?: number;
|
||||||
y?: number;
|
readonly y?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OffsetAttributes extends XmlAttributeComponent<IOffsetAttributes> {
|
export class OffsetAttributes extends XmlAttributeComponent<IOffsetAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
x: "x",
|
x: "x",
|
||||||
y: "y",
|
y: "y",
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IPresetGeometryAttributes {
|
export interface IPresetGeometryAttributes {
|
||||||
prst?: string;
|
readonly prst?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PresetGeometryAttributes extends XmlAttributeComponent<IPresetGeometryAttributes> {
|
export class PresetGeometryAttributes extends XmlAttributeComponent<IPresetGeometryAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
prst: "prst",
|
prst: "prst",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IShapePropertiesAttributes {
|
export interface IShapePropertiesAttributes {
|
||||||
bwMode?: string;
|
readonly bwMode?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ShapePropertiesAttributes extends XmlAttributeComponent<IShapePropertiesAttributes> {
|
export class ShapePropertiesAttributes extends XmlAttributeComponent<IShapePropertiesAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
bwMode: "bwMode",
|
bwMode: "bwMode",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
|||||||
import { GraphicData } from "./graphic-data";
|
import { GraphicData } from "./graphic-data";
|
||||||
|
|
||||||
interface IGraphicProperties {
|
interface IGraphicProperties {
|
||||||
a: string;
|
readonly a: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class GraphicAttributes extends XmlAttributeComponent<IGraphicProperties> {
|
class GraphicAttributes extends XmlAttributeComponent<IGraphicProperties> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
a: "xmlns:a",
|
a: "xmlns:a",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import { IDistance } from "../drawing";
|
|||||||
export interface IInlineAttributes extends IDistance {}
|
export interface IInlineAttributes extends IDistance {}
|
||||||
|
|
||||||
export class InlineAttributes extends XmlAttributeComponent<IInlineAttributes> {
|
export class InlineAttributes extends XmlAttributeComponent<IInlineAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
distT: "distT",
|
distT: "distT",
|
||||||
distB: "distB",
|
distB: "distB",
|
||||||
distL: "distL",
|
distL: "distL",
|
||||||
|
@ -16,7 +16,7 @@ export enum WrapTextOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ITextWrapping {
|
export interface ITextWrapping {
|
||||||
textWrapStyle: TextWrapStyle;
|
readonly textWrapStyle: TextWrapStyle;
|
||||||
wrapTextOption?: WrapTextOption;
|
readonly wrapTextOption?: WrapTextOption;
|
||||||
distanceFromText?: IDistance;
|
readonly distanceFromText?: IDistance;
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@ import { ITextWrapping, WrapTextOption } from ".";
|
|||||||
import { IDistance } from "../drawing";
|
import { IDistance } from "../drawing";
|
||||||
|
|
||||||
interface IWrapSquareAttributes extends IDistance {
|
interface IWrapSquareAttributes extends IDistance {
|
||||||
wrapText?: WrapTextOption;
|
readonly wrapText?: WrapTextOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
class WrapSquareAttributes extends XmlAttributeComponent<IWrapSquareAttributes> {
|
class WrapSquareAttributes extends XmlAttributeComponent<IWrapSquareAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
distT: "distT",
|
distT: "distT",
|
||||||
distB: "distB",
|
distB: "distB",
|
||||||
distL: "distL",
|
distL: "distL",
|
||||||
|
@ -3,25 +3,25 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
|||||||
import { IDistance } from "../drawing";
|
import { IDistance } from "../drawing";
|
||||||
|
|
||||||
interface IWrapTightAttributes {
|
interface IWrapTightAttributes {
|
||||||
distT?: number;
|
readonly distT?: number;
|
||||||
distB?: number;
|
readonly distB?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
class WrapTightAttributes extends XmlAttributeComponent<IWrapTightAttributes> {
|
class WrapTightAttributes extends XmlAttributeComponent<IWrapTightAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
distT: "distT",
|
distT: "distT",
|
||||||
distB: "distB",
|
distB: "distB",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WrapTight extends XmlComponent {
|
export class WrapTight extends XmlComponent {
|
||||||
constructor(distanceFromText?: IDistance) {
|
constructor(
|
||||||
super("wp:wrapTight");
|
distanceFromText: IDistance = {
|
||||||
|
|
||||||
distanceFromText = distanceFromText || {
|
|
||||||
distT: 0,
|
distT: 0,
|
||||||
distB: 0,
|
distB: 0,
|
||||||
};
|
},
|
||||||
|
) {
|
||||||
|
super("wp:wrapTight");
|
||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new WrapTightAttributes({
|
new WrapTightAttributes({
|
||||||
|
@ -3,25 +3,25 @@ import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
|||||||
import { IDistance } from "../drawing";
|
import { IDistance } from "../drawing";
|
||||||
|
|
||||||
interface IWrapTopAndBottomAttributes {
|
interface IWrapTopAndBottomAttributes {
|
||||||
distT?: number;
|
readonly distT?: number;
|
||||||
distB?: number;
|
readonly distB?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
class WrapTopAndBottomAttributes extends XmlAttributeComponent<IWrapTopAndBottomAttributes> {
|
class WrapTopAndBottomAttributes extends XmlAttributeComponent<IWrapTopAndBottomAttributes> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
distT: "distT",
|
distT: "distT",
|
||||||
distB: "distB",
|
distB: "distB",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WrapTopAndBottom extends XmlComponent {
|
export class WrapTopAndBottom extends XmlComponent {
|
||||||
constructor(distanceFromText?: IDistance) {
|
constructor(
|
||||||
super("wp:wrapTopAndBottom");
|
distanceFromText: IDistance = {
|
||||||
|
|
||||||
distanceFromText = distanceFromText || {
|
|
||||||
distT: 0,
|
distT: 0,
|
||||||
distB: 0,
|
distB: 0,
|
||||||
};
|
},
|
||||||
|
) {
|
||||||
|
super("wp:wrapTopAndBottom");
|
||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new WrapTopAndBottomAttributes({
|
new WrapTopAndBottomAttributes({
|
||||||
|
11
src/file/file-properties.ts
Normal file
11
src/file/file-properties.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { IDocumentTemplate } from "../import-dotx";
|
||||||
|
|
||||||
|
export interface IFileProperties {
|
||||||
|
readonly template?: IDocumentTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
export const WORKAROUND = "";
|
58
src/file/file.spec.ts
Normal file
58
src/file/file.spec.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
|
import { File } from "./file";
|
||||||
|
|
||||||
|
describe("File", () => {
|
||||||
|
describe("#constructor", () => {
|
||||||
|
it("should create with correct headers", () => {
|
||||||
|
const doc = new File();
|
||||||
|
const header = doc.createHeader();
|
||||||
|
const footer = doc.createFooter();
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
headers: {
|
||||||
|
default: header,
|
||||||
|
},
|
||||||
|
footers: {
|
||||||
|
default: 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("default");
|
||||||
|
expect(tree["w:body"][1]["w:sectPr"][5]["w:footerReference"][0]._attr["w:type"]).to.equal("default");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create with correct headers", () => {
|
||||||
|
const doc = new File();
|
||||||
|
const header = doc.createHeader();
|
||||||
|
const footer = doc.createFooter();
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
headers: {
|
||||||
|
default: header,
|
||||||
|
first: header,
|
||||||
|
even: header,
|
||||||
|
},
|
||||||
|
footers: {
|
||||||
|
default: footer,
|
||||||
|
first: footer,
|
||||||
|
even: 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("default");
|
||||||
|
expect(tree["w:body"][1]["w:sectPr"][5]["w:headerReference"][0]._attr["w:type"]).to.equal("first");
|
||||||
|
expect(tree["w:body"][1]["w:sectPr"][6]["w:headerReference"][0]._attr["w:type"]).to.equal("even");
|
||||||
|
|
||||||
|
expect(tree["w:body"][1]["w:sectPr"][7]["w:footerReference"][0]._attr["w:type"]).to.equal("default");
|
||||||
|
expect(tree["w:body"][1]["w:sectPr"][8]["w:footerReference"][0]._attr["w:type"]).to.equal("first");
|
||||||
|
expect(tree["w:body"][1]["w:sectPr"][9]["w:footerReference"][0]._attr["w:type"]).to.equal("even");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
372
src/file/file.ts
372
src/file/file.ts
@ -2,46 +2,77 @@ import { AppProperties } from "./app-properties/app-properties";
|
|||||||
import { ContentTypes } from "./content-types/content-types";
|
import { ContentTypes } from "./content-types/content-types";
|
||||||
import { CoreProperties, IPropertiesOptions } from "./core-properties";
|
import { CoreProperties, IPropertiesOptions } from "./core-properties";
|
||||||
import { Document } from "./document";
|
import { Document } from "./document";
|
||||||
import { FooterReferenceType, HeaderReference, HeaderReferenceType, SectionPropertiesOptions } from "./document/body/section-properties";
|
import {
|
||||||
import { FooterWrapper } from "./footer-wrapper";
|
FooterReferenceType,
|
||||||
|
HeaderReference,
|
||||||
|
HeaderReferenceType,
|
||||||
|
IHeaderFooterGroup,
|
||||||
|
SectionPropertiesOptions,
|
||||||
|
} from "./document/body/section-properties";
|
||||||
|
import { IDrawingOptions } from "./drawing";
|
||||||
|
import { IFileProperties } from "./file-properties";
|
||||||
|
import { FooterWrapper, IDocumentFooter } from "./footer-wrapper";
|
||||||
import { FootNotes } from "./footnotes";
|
import { FootNotes } from "./footnotes";
|
||||||
import { HeaderWrapper } from "./header-wrapper";
|
import { HeaderWrapper, IDocumentHeader } from "./header-wrapper";
|
||||||
import { Image, Media } from "./media";
|
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 { 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 { Table } from "./table";
|
||||||
|
import { TableOfContents } from "./table-of-contents";
|
||||||
|
|
||||||
export class File {
|
export class File {
|
||||||
|
// tslint:disable-next-line:readonly-keyword
|
||||||
|
private currentRelationshipId: number = 1;
|
||||||
|
|
||||||
private readonly document: Document;
|
private readonly document: Document;
|
||||||
private styles: Styles;
|
private readonly headers: IDocumentHeader[] = [];
|
||||||
|
private readonly footers: IDocumentFooter[] = [];
|
||||||
|
private readonly docRelationships: Relationships;
|
||||||
private readonly coreProperties: CoreProperties;
|
private readonly coreProperties: CoreProperties;
|
||||||
private readonly numbering: Numbering;
|
private readonly numbering: Numbering;
|
||||||
private readonly media: Media;
|
private readonly media: Media;
|
||||||
private readonly docRelationships: Relationships;
|
|
||||||
private readonly fileRelationships: Relationships;
|
private readonly fileRelationships: Relationships;
|
||||||
private readonly headerWrapper: HeaderWrapper[] = [];
|
|
||||||
private readonly footerWrapper: FooterWrapper[] = [];
|
|
||||||
private readonly footNotes: FootNotes;
|
private readonly footNotes: FootNotes;
|
||||||
|
private readonly settings: Settings;
|
||||||
private readonly contentTypes: ContentTypes;
|
private readonly contentTypes: ContentTypes;
|
||||||
private readonly appProperties: AppProperties;
|
private readonly appProperties: AppProperties;
|
||||||
|
// tslint:disable-next-line:readonly-keyword
|
||||||
|
private styles: Styles;
|
||||||
|
|
||||||
private currentRelationshipId: number = 1;
|
constructor(
|
||||||
|
options: IPropertiesOptions = {
|
||||||
|
creator: "Un-named",
|
||||||
|
revision: "1",
|
||||||
|
lastModifiedBy: "Un-named",
|
||||||
|
},
|
||||||
|
sectionPropertiesOptions: SectionPropertiesOptions = {},
|
||||||
|
fileProperties: IFileProperties = {},
|
||||||
|
) {
|
||||||
|
this.coreProperties = new CoreProperties(options);
|
||||||
|
this.numbering = new Numbering();
|
||||||
|
this.docRelationships = new Relationships();
|
||||||
|
this.media = new Media();
|
||||||
|
this.fileRelationships = new Relationships();
|
||||||
|
this.appProperties = new AppProperties();
|
||||||
|
this.footNotes = new FootNotes();
|
||||||
|
this.contentTypes = new ContentTypes();
|
||||||
|
|
||||||
constructor(options?: IPropertiesOptions, sectionPropertiesOptions?: SectionPropertiesOptions) {
|
if (fileProperties.template) {
|
||||||
if (!options) {
|
this.currentRelationshipId = fileProperties.template.currentRelationshipId + 1;
|
||||||
options = {
|
|
||||||
creator: "Un-named",
|
|
||||||
revision: "1",
|
|
||||||
lastModifiedBy: "Un-named",
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.externalStyles) {
|
// set up styles
|
||||||
|
if (fileProperties.template && options.externalStyles) {
|
||||||
|
throw Error("can not use both template and external styles");
|
||||||
|
}
|
||||||
|
if (fileProperties.template) {
|
||||||
|
this.styles = fileProperties.template.styles;
|
||||||
|
} else if (options.externalStyles) {
|
||||||
const stylesFactory = new ExternalStylesFactory();
|
const stylesFactory = new ExternalStylesFactory();
|
||||||
this.styles = stylesFactory.newInstance(options.externalStyles);
|
this.styles = stylesFactory.newInstance(options.externalStyles);
|
||||||
} else {
|
} else {
|
||||||
@ -49,66 +80,41 @@ export class File {
|
|||||||
this.styles = stylesFactory.newInstance();
|
this.styles = stylesFactory.newInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.coreProperties = new CoreProperties(options);
|
this.addDefaultRelationships();
|
||||||
this.numbering = new Numbering();
|
|
||||||
this.docRelationships = new Relationships();
|
|
||||||
this.docRelationships.createRelationship(
|
|
||||||
this.currentRelationshipId++,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
|
|
||||||
"styles.xml",
|
|
||||||
);
|
|
||||||
this.docRelationships.createRelationship(
|
|
||||||
this.currentRelationshipId++,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering",
|
|
||||||
"numbering.xml",
|
|
||||||
);
|
|
||||||
this.contentTypes = new ContentTypes();
|
|
||||||
|
|
||||||
this.docRelationships.createRelationship(
|
if (fileProperties.template && fileProperties.template.headers) {
|
||||||
this.currentRelationshipId++,
|
for (const templateHeader of fileProperties.template.headers) {
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
|
this.addHeaderToDocument(templateHeader.header, templateHeader.type);
|
||||||
"footnotes.xml",
|
}
|
||||||
);
|
|
||||||
this.media = new Media();
|
|
||||||
|
|
||||||
const header = this.createHeader();
|
|
||||||
const footer = this.createFooter();
|
|
||||||
|
|
||||||
this.fileRelationships = new Relationships();
|
|
||||||
this.fileRelationships.createRelationship(
|
|
||||||
1,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
|
|
||||||
"word/document.xml",
|
|
||||||
);
|
|
||||||
this.fileRelationships.createRelationship(
|
|
||||||
2,
|
|
||||||
"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
|
|
||||||
"docProps/core.xml",
|
|
||||||
);
|
|
||||||
this.fileRelationships.createRelationship(
|
|
||||||
3,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
|
|
||||||
"docProps/app.xml",
|
|
||||||
);
|
|
||||||
this.appProperties = new AppProperties();
|
|
||||||
|
|
||||||
this.footNotes = new FootNotes();
|
|
||||||
if (!sectionPropertiesOptions) {
|
|
||||||
sectionPropertiesOptions = {
|
|
||||||
footerType: FooterReferenceType.DEFAULT,
|
|
||||||
headerType: HeaderReferenceType.DEFAULT,
|
|
||||||
headerId: header.Header.ReferenceId,
|
|
||||||
footerId: footer.Footer.ReferenceId,
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
sectionPropertiesOptions.headerId = header.Header.ReferenceId;
|
this.createHeader();
|
||||||
sectionPropertiesOptions.footerId = footer.Footer.ReferenceId;
|
|
||||||
}
|
}
|
||||||
this.document = new Document(sectionPropertiesOptions);
|
|
||||||
|
if (fileProperties.template && fileProperties.template.footers) {
|
||||||
|
for (const templateFooter of fileProperties.template.footers) {
|
||||||
|
this.addFooterToDocument(templateFooter.footer, templateFooter.type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.createFooter();
|
||||||
|
}
|
||||||
|
|
||||||
|
const newSectionPropertiesOptions = {
|
||||||
|
...sectionPropertiesOptions,
|
||||||
|
headers: this.groupHeaders(this.headers, sectionPropertiesOptions.headers),
|
||||||
|
footers: this.groupFooters(this.footers, sectionPropertiesOptions.footers),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.document = new Document(newSectionPropertiesOptions);
|
||||||
|
this.settings = new Settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public addParagraph(paragraph: Paragraph): void {
|
public addTableOfContents(toc: TableOfContents): void {
|
||||||
|
this.document.addTableOfContents(toc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addParagraph(paragraph: Paragraph): File {
|
||||||
this.document.addParagraph(paragraph);
|
this.document.addParagraph(paragraph);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createParagraph(text?: string): Paragraph {
|
public createParagraph(text?: string): Paragraph {
|
||||||
@ -128,16 +134,21 @@ export class File {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createImage(buffer: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): Image {
|
public createImage(
|
||||||
const image = Media.addImage(this, buffer, width, height);
|
buffer: Buffer | string | Uint8Array | ArrayBuffer,
|
||||||
|
width?: number,
|
||||||
|
height?: number,
|
||||||
|
drawingOptions?: IDrawingOptions,
|
||||||
|
): Image {
|
||||||
|
const image = Media.addImage(this, buffer, width, height, drawingOptions);
|
||||||
this.document.addParagraph(image.Paragraph);
|
this.document.addParagraph(image.Paragraph);
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createHyperlink(link: string, text?: string): Hyperlink {
|
public createHyperlink(link: string, text?: string): Hyperlink {
|
||||||
text = text === undefined ? link : text;
|
const newText = text === undefined ? link : text;
|
||||||
const hyperlink = new Hyperlink(text, this.docRelationships.RelationshipCount);
|
const hyperlink = new Hyperlink(newText, this.docRelationships.RelationshipCount);
|
||||||
this.docRelationships.createRelationship(
|
this.docRelationships.createRelationship(
|
||||||
hyperlink.linkId,
|
hyperlink.linkId,
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
||||||
@ -148,16 +159,16 @@ export class File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public createInternalHyperLink(anchor: string, text?: string): Hyperlink {
|
public createInternalHyperLink(anchor: string, text?: string): Hyperlink {
|
||||||
text = text === undefined ? anchor : text;
|
const newText = text === undefined ? anchor : text;
|
||||||
const hyperlink = new Hyperlink(text, this.docRelationships.RelationshipCount, anchor);
|
const hyperlink = new Hyperlink(newText, this.docRelationships.RelationshipCount, anchor);
|
||||||
// NOTE: unlike File#createHyperlink(), since the link is to an internal bookmark
|
// NOTE: unlike File#createHyperlink(), since the link is to an internal bookmark
|
||||||
// we don't need to create a new relationship.
|
// we don't need to create a new relationship.
|
||||||
return hyperlink;
|
return hyperlink;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createBookmark(name: string, text?: string): Bookmark {
|
public createBookmark(name: string, text?: string): Bookmark {
|
||||||
text = text === undefined ? name : text;
|
const newText = text === undefined ? name : text;
|
||||||
const bookmark = new Bookmark(name, text, this.docRelationships.RelationshipCount);
|
const bookmark = new Bookmark(name, newText, this.docRelationships.RelationshipCount);
|
||||||
return bookmark;
|
return bookmark;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,25 +182,13 @@ export class File {
|
|||||||
|
|
||||||
public createHeader(): HeaderWrapper {
|
public createHeader(): HeaderWrapper {
|
||||||
const header = new HeaderWrapper(this.media, this.currentRelationshipId++);
|
const header = new HeaderWrapper(this.media, this.currentRelationshipId++);
|
||||||
this.headerWrapper.push(header);
|
this.addHeaderToDocument(header);
|
||||||
this.docRelationships.createRelationship(
|
|
||||||
header.Header.ReferenceId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
|
|
||||||
`header${this.headerWrapper.length}.xml`,
|
|
||||||
);
|
|
||||||
this.contentTypes.addHeader(this.headerWrapper.length);
|
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createFooter(): FooterWrapper {
|
public createFooter(): FooterWrapper {
|
||||||
const footer = new FooterWrapper(this.media, this.currentRelationshipId++);
|
const footer = new FooterWrapper(this.media, this.currentRelationshipId++);
|
||||||
this.footerWrapper.push(footer);
|
this.addFooterToDocument(footer);
|
||||||
this.docRelationships.createRelationship(
|
|
||||||
footer.Footer.ReferenceId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer",
|
|
||||||
`footer${this.footerWrapper.length}.xml`,
|
|
||||||
);
|
|
||||||
this.contentTypes.addFooter(this.footerWrapper.length);
|
|
||||||
return footer;
|
return footer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,6 +205,165 @@ export class File {
|
|||||||
return headerWrapper;
|
return headerWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public createEvenPageHeader(): HeaderWrapper {
|
||||||
|
const headerWrapper = this.createHeader();
|
||||||
|
|
||||||
|
this.document.Body.DefaultSection.addChildElement(
|
||||||
|
new HeaderReference({
|
||||||
|
headerType: HeaderReferenceType.EVEN,
|
||||||
|
headerId: headerWrapper.Header.ReferenceId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return headerWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFooterByReferenceNumber(refId: number): FooterWrapper {
|
||||||
|
const entry = this.footers.map((item) => item.footer).find((h) => h.Footer.ReferenceId === refId);
|
||||||
|
if (entry) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
throw new Error(`There is no footer with given reference id ${refId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getHeaderByReferenceNumber(refId: number): HeaderWrapper {
|
||||||
|
const entry = this.headers.map((item) => item.header).find((h) => h.Header.ReferenceId === refId);
|
||||||
|
if (entry) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
throw new Error(`There is no header with given reference id ${refId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public verifyUpdateFields(): void {
|
||||||
|
if (this.document.getTablesOfContents().length) {
|
||||||
|
this.settings.addUpdateFields();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private addHeaderToDocument(header: HeaderWrapper, type: HeaderReferenceType = HeaderReferenceType.DEFAULT): void {
|
||||||
|
this.headers.push({ header, type });
|
||||||
|
this.docRelationships.createRelationship(
|
||||||
|
header.Header.ReferenceId,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
|
||||||
|
`header${this.headers.length}.xml`,
|
||||||
|
);
|
||||||
|
this.contentTypes.addHeader(this.headers.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private addFooterToDocument(footer: FooterWrapper, type: FooterReferenceType = FooterReferenceType.DEFAULT): void {
|
||||||
|
this.footers.push({ footer, type });
|
||||||
|
this.docRelationships.createRelationship(
|
||||||
|
footer.Footer.ReferenceId,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer",
|
||||||
|
`footer${this.footers.length}.xml`,
|
||||||
|
);
|
||||||
|
this.contentTypes.addFooter(this.footers.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private addDefaultRelationships(): void {
|
||||||
|
this.fileRelationships.createRelationship(
|
||||||
|
1,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
|
||||||
|
"word/document.xml",
|
||||||
|
);
|
||||||
|
this.fileRelationships.createRelationship(
|
||||||
|
2,
|
||||||
|
"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
|
||||||
|
"docProps/core.xml",
|
||||||
|
);
|
||||||
|
this.fileRelationships.createRelationship(
|
||||||
|
3,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
|
||||||
|
"docProps/app.xml",
|
||||||
|
);
|
||||||
|
|
||||||
|
this.docRelationships.createRelationship(
|
||||||
|
this.currentRelationshipId++,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
|
||||||
|
"styles.xml",
|
||||||
|
);
|
||||||
|
this.docRelationships.createRelationship(
|
||||||
|
this.currentRelationshipId++,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering",
|
||||||
|
"numbering.xml",
|
||||||
|
);
|
||||||
|
this.docRelationships.createRelationship(
|
||||||
|
this.currentRelationshipId++,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
|
||||||
|
"footnotes.xml",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private groupHeaders(headers: IDocumentHeader[], group: IHeaderFooterGroup<HeaderWrapper> = {}): IHeaderFooterGroup<HeaderWrapper> {
|
||||||
|
let newGroup = group;
|
||||||
|
|
||||||
|
for (const header of headers) {
|
||||||
|
switch (header.type) {
|
||||||
|
case HeaderReferenceType.DEFAULT:
|
||||||
|
newGroup = {
|
||||||
|
...newGroup,
|
||||||
|
default: header.header,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case HeaderReferenceType.FIRST:
|
||||||
|
newGroup = {
|
||||||
|
...newGroup,
|
||||||
|
first: header.header,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case HeaderReferenceType.EVEN:
|
||||||
|
newGroup = {
|
||||||
|
...newGroup,
|
||||||
|
even: header.header,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
newGroup = {
|
||||||
|
...newGroup,
|
||||||
|
default: header.header,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
private groupFooters(footers: IDocumentFooter[], group: IHeaderFooterGroup<FooterWrapper> = {}): IHeaderFooterGroup<FooterWrapper> {
|
||||||
|
let newGroup = group;
|
||||||
|
|
||||||
|
for (const footer of footers) {
|
||||||
|
switch (footer.type) {
|
||||||
|
case FooterReferenceType.DEFAULT:
|
||||||
|
newGroup = {
|
||||||
|
...newGroup,
|
||||||
|
default: footer.footer,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case FooterReferenceType.FIRST:
|
||||||
|
newGroup = {
|
||||||
|
...newGroup,
|
||||||
|
first: footer.footer,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case FooterReferenceType.EVEN:
|
||||||
|
newGroup = {
|
||||||
|
...newGroup,
|
||||||
|
even: footer.footer,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
newGroup = {
|
||||||
|
...newGroup,
|
||||||
|
default: footer.footer,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newGroup;
|
||||||
|
}
|
||||||
|
|
||||||
public get Document(): Document {
|
public get Document(): Document {
|
||||||
return this.document;
|
return this.document;
|
||||||
}
|
}
|
||||||
@ -239,35 +397,19 @@ export class File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get Header(): HeaderWrapper {
|
public get Header(): HeaderWrapper {
|
||||||
return this.headerWrapper[0];
|
return this.headers[0].header;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get Headers(): HeaderWrapper[] {
|
public get Headers(): HeaderWrapper[] {
|
||||||
return this.headerWrapper;
|
return this.headers.map((item) => item.header);
|
||||||
}
|
|
||||||
|
|
||||||
public HeaderByRefNumber(refId: number): HeaderWrapper {
|
|
||||||
const entry = this.headerWrapper.find((h) => h.Header.ReferenceId === refId);
|
|
||||||
if (entry) {
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
throw new Error(`There is no header with given reference id ${refId}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get Footer(): FooterWrapper {
|
public get Footer(): FooterWrapper {
|
||||||
return this.footerWrapper[0];
|
return this.footers[0].footer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get Footers(): FooterWrapper[] {
|
public get Footers(): FooterWrapper[] {
|
||||||
return this.footerWrapper;
|
return this.footers.map((item) => item.footer);
|
||||||
}
|
|
||||||
|
|
||||||
public FooterByRefNumber(refId: number): FooterWrapper {
|
|
||||||
const entry = this.footerWrapper.find((h) => h.Footer.ReferenceId === refId);
|
|
||||||
if (entry) {
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
throw new Error(`There is no footer with given reference id ${refId}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get ContentTypes(): ContentTypes {
|
public get ContentTypes(): ContentTypes {
|
||||||
@ -281,4 +423,8 @@ export class File {
|
|||||||
public get FootNotes(): FootNotes {
|
public get FootNotes(): FootNotes {
|
||||||
return this.footNotes;
|
return this.footNotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get Settings(): Settings {
|
||||||
|
return this.settings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
|
import { FooterReferenceType } from "./document";
|
||||||
import { Footer } from "./footer/footer";
|
import { Footer } from "./footer/footer";
|
||||||
import { Image, Media } from "./media";
|
import { Image, IMediaData, 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";
|
||||||
|
|
||||||
|
export interface IDocumentFooter {
|
||||||
|
readonly footer: FooterWrapper;
|
||||||
|
readonly type: FooterReferenceType;
|
||||||
|
}
|
||||||
|
|
||||||
export class FooterWrapper {
|
export class FooterWrapper {
|
||||||
private readonly footer: Footer;
|
private readonly footer: Footer;
|
||||||
private readonly relationships: Relationships;
|
private readonly relationships: Relationships;
|
||||||
|
|
||||||
constructor(private readonly media: Media, referenceId: number) {
|
constructor(private readonly media: Media, referenceId: number, initContent?: XmlComponent) {
|
||||||
this.footer = new Footer(referenceId);
|
this.footer = new Footer(referenceId, initContent);
|
||||||
this.relationships = new Relationships();
|
this.relationships = new Relationships();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,17 +39,33 @@ export class FooterWrapper {
|
|||||||
return this.footer.createTable(rows, cols);
|
return this.footer.createTable(rows, cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addChildElement(childElement: XmlComponent | string): void {
|
public addChildElement(childElement: XmlComponent): void {
|
||||||
this.footer.addChildElement(childElement);
|
this.footer.addChildElement(childElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createImage(image: Buffer, width?: number, height?: number): void {
|
public addImageRelationship(image: Buffer, refId: number, width?: number, height?: number): IMediaData {
|
||||||
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height);
|
const mediaData = this.media.addMedia(image, refId, width, height);
|
||||||
this.relationships.createRelationship(
|
this.relationships.createRelationship(
|
||||||
mediaData.referenceId,
|
mediaData.referenceId,
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||||
`media/${mediaData.fileName}`,
|
`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 {
|
||||||
|
// TODO
|
||||||
|
// 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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,4 +81,8 @@ export class FooterWrapper {
|
|||||||
public get Relationships(): Relationships {
|
public get Relationships(): Relationships {
|
||||||
return this.relationships;
|
return this.relationships;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get Media(): Media {
|
||||||
|
return this.media;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,32 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IFooterAttributesProperties {
|
export interface IFooterAttributesProperties {
|
||||||
wpc?: string;
|
readonly wpc?: string;
|
||||||
mc?: string;
|
readonly mc?: string;
|
||||||
o?: string;
|
readonly o?: string;
|
||||||
r?: string;
|
readonly r?: string;
|
||||||
m?: string;
|
readonly m?: string;
|
||||||
v?: string;
|
readonly v?: string;
|
||||||
wp14?: string;
|
readonly wp14?: string;
|
||||||
wp?: string;
|
readonly wp?: string;
|
||||||
w10?: string;
|
readonly w10?: string;
|
||||||
w?: string;
|
readonly w?: string;
|
||||||
w14?: string;
|
readonly w14?: string;
|
||||||
w15?: string;
|
readonly w15?: string;
|
||||||
wpg?: string;
|
readonly wpg?: string;
|
||||||
wpi?: string;
|
readonly wpi?: string;
|
||||||
wne?: string;
|
readonly wne?: string;
|
||||||
wps?: string;
|
readonly wps?: string;
|
||||||
cp?: string;
|
readonly cp?: string;
|
||||||
dc?: string;
|
readonly dc?: string;
|
||||||
dcterms?: string;
|
readonly dcterms?: string;
|
||||||
dcmitype?: string;
|
readonly dcmitype?: string;
|
||||||
xsi?: string;
|
readonly xsi?: string;
|
||||||
type?: string;
|
readonly type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FooterAttributes extends XmlAttributeComponent<IFooterAttributesProperties> {
|
export class FooterAttributes extends XmlAttributeComponent<IFooterAttributesProperties> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
wpc: "xmlns:wpc",
|
wpc: "xmlns:wpc",
|
||||||
mc: "xmlns:mc",
|
mc: "xmlns:mc",
|
||||||
o: "xmlns:o",
|
o: "xmlns:o",
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
// http://officeopenxml.com/WPfooters.php
|
// http://officeopenxml.com/WPfooters.php
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { InitializableXmlComponent, XmlComponent } from "file/xml-components";
|
||||||
import { Paragraph } from "../paragraph";
|
import { Paragraph } from "../paragraph";
|
||||||
import { Table } from "../table";
|
import { Table } from "../table";
|
||||||
import { FooterAttributes } from "./footer-attributes";
|
import { FooterAttributes } from "./footer-attributes";
|
||||||
|
|
||||||
export class Footer extends XmlComponent {
|
export class Footer extends InitializableXmlComponent {
|
||||||
private readonly refId: number;
|
private readonly refId: number;
|
||||||
|
|
||||||
constructor(referenceNumber: number) {
|
constructor(referenceNumber: number, initContent?: XmlComponent) {
|
||||||
super("w:ftr");
|
super("w:ftr", initContent);
|
||||||
this.refId = referenceNumber;
|
this.refId = referenceNumber;
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new FooterAttributes({
|
new FooterAttributes({
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
|
||||||
export interface IFootnoteAttributesProperties {
|
export interface IFootnoteAttributesProperties {
|
||||||
type?: string;
|
readonly type?: string;
|
||||||
id: number;
|
readonly id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FootnoteAttributes extends XmlAttributeComponent<IFootnoteAttributesProperties> {
|
export class FootnoteAttributes extends XmlAttributeComponent<IFootnoteAttributesProperties> {
|
||||||
protected xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
type: "w:type",
|
type: "w:type",
|
||||||
id: "w:id",
|
id: "w:id",
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { Formatter } from "../../../export/formatter";
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { Footnote, FootnoteType } from "./footnote";
|
import { Footnote, FootnoteType } from "./footnote";
|
||||||
|
|
||||||
describe("Footnote", () => {
|
describe("Footnote", () => {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
import { Paragraph } from "file/paragraph";
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
import { Paragraph } from "../../paragraph";
|
|
||||||
import { FootnoteAttributes } from "./footnote-attributes";
|
import { FootnoteAttributes } from "./footnote-attributes";
|
||||||
import { FootnoteRefRun } from "./run/footnote-ref-run";
|
import { FootnoteRefRun } from "./run/footnote-ref-run";
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user