Compare commits
393 Commits
Author | SHA1 | Date | |
---|---|---|---|
34da2f4289 | |||
b986403656 | |||
5cba664f70 | |||
9a35029f16 | |||
3c768c5630 | |||
f77ddb4037 | |||
536204e5ef | |||
1f078e0687 | |||
705b1f7cfc | |||
28233075bd | |||
f1627c378d | |||
0aa5510b9c | |||
3d9216e8bf | |||
054ece38ab | |||
951094c6fb | |||
ea01ddb337 | |||
34036bca8f | |||
0256968240 | |||
1f894303d3 | |||
c79e9ded71 | |||
0d72de7e53 | |||
750368ac08 | |||
4394a9b575 | |||
1b758b73e6 | |||
65a0e97c97 | |||
3c33931d99 | |||
e475779ba5 | |||
4c58e3c47d | |||
9fb77d9cee | |||
f315909dc0 | |||
fa9ffec601 | |||
636d114d44 | |||
2140ed63cd | |||
8d0f7d58bf | |||
3c48822cec | |||
547c05b05d | |||
e5ba625820 | |||
45e644ac43 | |||
9b14b9c925 | |||
0bc55208ec | |||
285eb0a85d | |||
d521e20c0e | |||
439f8ff4bc | |||
18791c99f5 | |||
9991700701 | |||
01bc6093dd | |||
5c08b889b1 | |||
7944a7064e | |||
1713358f0c | |||
b6465e15de | |||
5ca97ce96f | |||
5609b11188 | |||
eec084767f | |||
3a795401d1 | |||
23fd3b483f | |||
a2566e92d2 | |||
bf884c8d13 | |||
dae2898496 | |||
9555ddd648 | |||
755895ebef | |||
4283a6c7d9 | |||
dd7439b45c | |||
b4c7ed2347 | |||
9354b99897 | |||
a1fbbde149 | |||
607087d256 | |||
7d50194cbf | |||
ab5c5c0fb7 | |||
bc1bca762e | |||
75290aeaf5 | |||
996594da9b | |||
5018134e35 | |||
da9ebbdb9a | |||
eb5a4f9620 | |||
64cec50b84 | |||
ce2a949176 | |||
ff7756f8c5 | |||
4221b9085a | |||
76e7f40bd2 | |||
dc2f9c3bdc | |||
8eb5d6281e | |||
6d09355174 | |||
4e3a2fd90f | |||
463c282568 | |||
8c0ff0422a | |||
0fe1765b7f | |||
4accf65802 | |||
c6eb11d535 | |||
58cfb427e9 | |||
90bb670de6 | |||
727e741b08 | |||
41f516d64b | |||
366cd2b4b1 | |||
243d73542f | |||
44520bc54b | |||
831ef9a98c | |||
bef9ea28f2 | |||
7fa94b6996 | |||
c1cc211c7f | |||
9efee181ba | |||
631f561441 | |||
94592de477 | |||
ac204a5189 | |||
e48ca53660 | |||
5c2d4f729a | |||
03d6636262 | |||
74b3267294 | |||
83af11aa1b | |||
8cf9b83068 | |||
5dab97241e | |||
3b7394fe74 | |||
31c6f0a8ca | |||
890983c1e1 | |||
e8db8ec669 | |||
dcbe542fb2 | |||
ca695ad122 | |||
60bd9a84dd | |||
ecc3b2ef3f | |||
3e8d816614 | |||
dde54082d5 | |||
6845cd433f | |||
046ef0330a | |||
fcd0427fe4 | |||
4c4e253883 | |||
3a9f09b578 | |||
e9aea8b8a9 | |||
5c9b5e4322 | |||
33d6544aba | |||
3f257bf5a4 | |||
1ff31a2a42 | |||
14013273af | |||
b34127665c | |||
0fcd02aea8 | |||
d773148218 | |||
d52bf7b57d | |||
f378c37b62 | |||
d773972877 | |||
738b36b6a9 | |||
ad7ef22b63 | |||
e73e1f98f9 | |||
738e374bf2 | |||
c5861129c9 | |||
5f4c595a1a | |||
238b8b9a8d | |||
a92f3a7ba1 | |||
2a1685ab82 | |||
0088d58fea | |||
cbf4f828ab | |||
2ccf27162e | |||
5dffda8c7c | |||
e1c777738b | |||
0f531b2a9b | |||
d523b2dae7 | |||
f50c7f20cb | |||
f21fb06467 | |||
2fd4f064ae | |||
36a18c5af3 | |||
75587df420 | |||
43ea0bd406 | |||
ec2ad99e95 | |||
46deaa5a4a | |||
697baa3fd6 | |||
15829b53a6 | |||
56f1e4408a | |||
689d4d07bc | |||
b0049d8221 | |||
152a11d7fc | |||
31171330a2 | |||
3c0032cf68 | |||
0e44af1c06 | |||
39893a984c | |||
b75e194993 | |||
9fb58a5852 | |||
5c578a6bea | |||
3ba197a289 | |||
bbf50c34a0 | |||
6b6f2214f6 | |||
836ffd683f | |||
6c94a1382c | |||
c13cac899a | |||
ec1f9d5ecf | |||
a8115ff964 | |||
da744cbdec | |||
439ab8441e | |||
15b14579e6 | |||
1cb666fd03 | |||
bde4aa4657 | |||
709876a02d | |||
a0b74f24e3 | |||
ed15614023 | |||
c3e97a0aab | |||
b69968a99c | |||
82b12a99b9 | |||
1486519a98 | |||
7e194350d8 | |||
855c47954e | |||
dd3300506b | |||
154c7cb54b | |||
cd75c2e860 | |||
1b0f19d570 | |||
45026eb30e | |||
aeddcc7478 | |||
f88b588b60 | |||
f00844ad1b | |||
8e87437272 | |||
49b011280c | |||
37b94eeedc | |||
4053b5bbc2 | |||
46972a861d | |||
528dab5c10 | |||
d1ffc0bffa | |||
3741dd7ef2 | |||
c6c4b0cbcd | |||
804380f70e | |||
118f60f704 | |||
d556f97dbe | |||
b116b0a268 | |||
99f0297c4f | |||
4543016869 | |||
2b9c15a638 | |||
4ca5ea6046 | |||
2de55a1eb3 | |||
db20efa95b | |||
3822d8139d | |||
3a65f383e4 | |||
d05fef6b93 | |||
f02b6211a3 | |||
4b4f67f9c7 | |||
9f38e33a48 | |||
69ca5d8b0c | |||
809474e9c5 | |||
e5b56c4214 | |||
568a27367a | |||
c6f99fcbe5 | |||
309abbcc47 | |||
de145e0623 | |||
7f24abd104 | |||
edafbdb1ff | |||
034cd187ab | |||
8f04e0da4a | |||
90b8b8140b | |||
0b28bf02c4 | |||
2b169fc63a | |||
e2bb50d6ad | |||
730e33b164 | |||
6603aafa38 | |||
05a6ab77cc | |||
5a52541136 | |||
e4709a7f8d | |||
60b7ce4785 | |||
fd4afea9aa | |||
04d88fa592 | |||
87000d8656 | |||
776132ede0 | |||
b845e4daee | |||
da61a30eb8 | |||
3a02bc087c | |||
b05748da25 | |||
63cea76eac | |||
e198f0752a | |||
22e62ed950 | |||
c3e92c0709 | |||
d0036e64b5 | |||
7bfe8f26f0 | |||
4274c7674c | |||
8505e04e58 | |||
4466145d00 | |||
ce2a0fb864 | |||
a56119e7cd | |||
56eecef1a8 | |||
097c6a5962 | |||
ee105cdb83 | |||
7891402c72 | |||
bde13193d5 | |||
449e1ed963 | |||
dd6d1bc039 | |||
528be93191 | |||
1ea6017483 | |||
08bd2744b6 | |||
54ab55b92c | |||
5155cdaf45 | |||
496fcb55fa | |||
fcc393aca2 | |||
2611e0c74f | |||
acc23be297 | |||
bdc0aa26ea | |||
ff14fcae3a | |||
37d099b457 | |||
0344eb8e27 | |||
403e7a4228 | |||
aa336dc652 | |||
d8fca42eb7 | |||
10d1d15f73 | |||
ac55e0fcb3 | |||
780682a8f7 | |||
b627f0982a | |||
798cbb8628 | |||
15f79abf5e | |||
f5e35603ef | |||
06da596ffb | |||
4593464a15 | |||
30912e7aaf | |||
56b18d3793 | |||
d0a675fde6 | |||
45130bed0b | |||
faefb0d2a8 | |||
c4b7a7094b | |||
d527013451 | |||
bb8ac8b9d8 | |||
cdc97adaeb | |||
72f0ad9fdb | |||
0f55d70a19 | |||
6ac0375400 | |||
9048f8f271 | |||
23eaff2dab | |||
df4a381135 | |||
41dcf363b4 | |||
f143c017cb | |||
7463c0301f | |||
bb24c50bf4 | |||
70538a8062 | |||
085db9350c | |||
eabdefdaf4 | |||
9fc8e50691 | |||
dfc01f2d5a | |||
4e8aec9a0e | |||
c7e0554817 | |||
d77d59836f | |||
a035f4f411 | |||
53b1bba103 | |||
605536ce68 | |||
a9e4c88804 | |||
79c1db9c91 | |||
3b757ad4c8 | |||
ee07ff8282 | |||
85583a3dbd | |||
46daacfbc8 | |||
7acd9e1fde | |||
97e3f8bc78 | |||
ff378d6667 | |||
9930476f64 | |||
3e5223dd5d | |||
e3bb8258e5 | |||
77301a401e | |||
a09882b566 | |||
e72453c19a | |||
bd159b280f | |||
4d3d971a12 | |||
def503c53e | |||
74afae1850 | |||
7db166b19c | |||
0271e4ad40 | |||
2b010dbfec | |||
a8f38a3d01 | |||
bd69779a12 | |||
571ba2e2c3 | |||
7a25165046 | |||
977fdbb9eb | |||
2f05186730 | |||
38695c3c4b | |||
f2152b3da1 | |||
51dc538cdd | |||
c76bb2859a | |||
0b6f040bba | |||
149908ea62 | |||
98f745a3f7 | |||
9b840c0d63 | |||
0085b1d128 | |||
c3ddd576e2 | |||
cf237bcc10 | |||
c6ce7fe3a3 | |||
712e612ab1 | |||
161038cc75 | |||
24aee70b67 | |||
b486bcf372 | |||
97147bc3d7 | |||
6a0b01e05c | |||
e60d9cbbce | |||
594045644b | |||
e36022d044 | |||
2b0acc2980 | |||
2058f72c2e | |||
0788b10106 | |||
7b431e50bc | |||
633487ca16 | |||
43d1f40baa | |||
aec7f09031 | |||
790dfa320e | |||
260482d9d4 | |||
b699481ae3 | |||
0f7260c152 | |||
d43d742875 | |||
fceefcf290 |
40
.github/dependabot.yml
vendored
Normal file
40
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
ignore:
|
||||
- dependency-name: "@types/node"
|
||||
versions:
|
||||
- 14.14.22
|
||||
- 14.14.24
|
||||
- 14.14.25
|
||||
- 14.14.26
|
||||
- 14.14.28
|
||||
- 14.14.29
|
||||
- 14.14.30
|
||||
- 15.0.0
|
||||
- dependency-name: webpack
|
||||
versions:
|
||||
- 5.31.2
|
||||
- 5.35.0
|
||||
- dependency-name: ts-loader
|
||||
versions:
|
||||
- 9.1.0
|
||||
- dependency-name: awesome-typescript-loader
|
||||
versions:
|
||||
- 5.2.1
|
||||
- dependency-name: chai
|
||||
versions:
|
||||
- 4.2.0
|
||||
- 4.3.0
|
||||
- 4.3.1
|
||||
- 4.3.3
|
||||
- dependency-name: replace-in-file
|
||||
versions:
|
||||
- 6.1.0
|
||||
- dependency-name: "@types/chai"
|
||||
versions:
|
||||
- 4.2.14
|
5
.github/workflows/default.yml
vendored
5
.github/workflows/default.yml
vendored
@ -33,6 +33,11 @@ jobs:
|
||||
run: npm ci
|
||||
- name: Test
|
||||
run: npm run test.coverage
|
||||
- name: Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
|
26
.github/workflows/remove-old-artifacts.yml
vendored
Normal file
26
.github/workflows/remove-old-artifacts.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
name: Remove old artifacts
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Every day at 1am
|
||||
- cron: "0 1 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
logLevel:
|
||||
description: "Log level"
|
||||
required: true
|
||||
default: "warning"
|
||||
|
||||
jobs:
|
||||
remove-old-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Remove old artifacts
|
||||
uses: c-hive/gha-remove-artifacts@v1
|
||||
with:
|
||||
age: "1 week"
|
||||
# Optional inputs
|
||||
# skip-tags: true
|
||||
# skip-recent: 5
|
9
.nycrc
9
.nycrc
@ -1,9 +1,9 @@
|
||||
{
|
||||
"check-coverage": true,
|
||||
"lines": 98.86,
|
||||
"functions": 97.86,
|
||||
"branches": 95.86,
|
||||
"statements": 98.86,
|
||||
"lines": 99.31,
|
||||
"functions": 99.09,
|
||||
"branches": 96.17,
|
||||
"statements": 99.31,
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
@ -21,6 +21,5 @@
|
||||
],
|
||||
"cache": true,
|
||||
"all": true,
|
||||
"instrument": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
[![NPM version][npm-image]][npm-url]
|
||||
[![Downloads per month][downloads-image]][downloads-url]
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[![GitHub Action Workflow Status][github-actions-workflow-image]][github-actions-workflow-url]
|
||||
[![Dependency Status][daviddm-image]][daviddm-url]
|
||||
[![Known Vulnerabilities][snky-image]][snky-url]
|
||||
@ -103,8 +102,6 @@ Made with 💖
|
||||
[npm-url]: https://npmjs.org/package/docx
|
||||
[downloads-image]: https://img.shields.io/npm/dm/docx.svg
|
||||
[downloads-url]: https://npmjs.org/package/docx
|
||||
[travis-image]: https://travis-ci.org/dolanmiu/docx.svg?branch=master
|
||||
[travis-url]: https://travis-ci.org/dolanmiu/docx
|
||||
[github-actions-workflow-image]: https://github.com/dolanmiu/docx/workflows/Default/badge.svg
|
||||
[github-actions-workflow-url]: https://github.com/dolanmiu/docx/actions
|
||||
[daviddm-image]: https://david-dm.org/dolanmiu/docx.svg?theme=shields.io
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
TableRow,
|
||||
TabStopPosition,
|
||||
UnderlineType,
|
||||
LevelFormat,
|
||||
} from "../build";
|
||||
|
||||
const table = new Table({
|
||||
@ -51,6 +52,19 @@ const table = new Table({
|
||||
});
|
||||
|
||||
const doc = new Document({
|
||||
numbering:{
|
||||
config:[{
|
||||
reference: 'ref1',
|
||||
levels: [
|
||||
{
|
||||
level: 0,
|
||||
format: LevelFormat.DECIMAL,
|
||||
text: '%1)',
|
||||
start: 50,
|
||||
}
|
||||
],
|
||||
}]
|
||||
},
|
||||
styles: {
|
||||
default: {
|
||||
heading1: {
|
||||
@ -155,6 +169,28 @@ const doc = new Document({
|
||||
spacing: { line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "numberedPara",
|
||||
name: "Numbered Para",
|
||||
basedOn: "Normal",
|
||||
next: "Normal",
|
||||
quickFormat: true,
|
||||
run: {
|
||||
font: "Calibri",
|
||||
size: 26,
|
||||
bold: true,
|
||||
},
|
||||
paragraph: {
|
||||
spacing: { line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 },
|
||||
rightTabStop: TabStopPosition.MAX,
|
||||
leftTabStop: 453.543307087,
|
||||
numbering : {
|
||||
reference: 'ref1',
|
||||
instance: 0,
|
||||
level: 0,
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
sections: [
|
||||
@ -260,6 +296,14 @@ const doc = new Document({
|
||||
text: "Test 2",
|
||||
style: "normalPara2",
|
||||
}),
|
||||
new Paragraph({
|
||||
text: "Numbered paragraph that has numbering attached to custom styles",
|
||||
style: "numberedPara",
|
||||
}),
|
||||
new Paragraph({
|
||||
text: "Numbered para would show up in the styles pane at Word",
|
||||
style: "numberedPara",
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Multiple sections and headers
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Document, Footer, Header, Packer, PageNumber, PageNumberFormat, PageOrientation, Paragraph, TextRun } from "../build";
|
||||
import { Document, Footer, Header, Packer, PageNumber, NumberFormat, PageOrientation, Paragraph, TextRun } from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
@ -13,7 +13,7 @@ const doc = new Document({
|
||||
page: {
|
||||
pageNumbers: {
|
||||
start: 1,
|
||||
formatType: PageNumberFormat.DECIMAL,
|
||||
formatType: NumberFormat.DECIMAL,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -38,7 +38,7 @@ const doc = new Document({
|
||||
},
|
||||
pageNumbers: {
|
||||
start: 1,
|
||||
formatType: PageNumberFormat.DECIMAL,
|
||||
formatType: NumberFormat.DECIMAL,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -85,7 +85,7 @@ const doc = new Document({
|
||||
orientation: PageOrientation.PORTRAIT,
|
||||
},
|
||||
pageNumbers: {
|
||||
formatType: PageNumberFormat.UPPER_ROMAN,
|
||||
formatType: NumberFormat.UPPER_ROMAN,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -116,7 +116,7 @@ const doc = new Document({
|
||||
},
|
||||
pageNumbers: {
|
||||
start: 25,
|
||||
formatType: PageNumberFormat.DECIMAL,
|
||||
formatType: NumberFormat.DECIMAL,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -24,7 +24,7 @@ const doc = new Document({
|
||||
size: 28,
|
||||
bold: true,
|
||||
italics: true,
|
||||
color: "red",
|
||||
color: "FF0000",
|
||||
},
|
||||
paragraph: {
|
||||
spacing: {
|
||||
|
@ -36,17 +36,17 @@ const doc = new Document({
|
||||
top: {
|
||||
style: BorderStyle.DASH_DOT_STROKED,
|
||||
size: 3,
|
||||
color: "red",
|
||||
color: "FF0000",
|
||||
},
|
||||
bottom: {
|
||||
style: BorderStyle.DOUBLE,
|
||||
size: 3,
|
||||
color: "blue",
|
||||
color: "0000FF",
|
||||
},
|
||||
left: {
|
||||
style: BorderStyle.DASH_DOT_STROKED,
|
||||
size: 3,
|
||||
color: "green",
|
||||
color: "00FF00",
|
||||
},
|
||||
right: {
|
||||
style: BorderStyle.DASH_DOT_STROKED,
|
||||
|
@ -1,7 +1,7 @@
|
||||
// This demo shows how to create bookmarks then link to them with internal hyperlinks
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Bookmark, Document, Footer, HeadingLevel, InternalHyperlink, Packer, PageBreak, Paragraph, TextRun } from "../build";
|
||||
import { Bookmark, Document, Footer, HeadingLevel, InternalHyperlink, Packer, PageBreak, Paragraph, TextRun, PageReference } from "../build";
|
||||
|
||||
const LOREM_IPSUM =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mi velit, convallis convallis scelerisque nec, faucibus nec leo. Phasellus at posuere mauris, tempus dignissim velit. Integer et tortor dolor. Duis auctor efficitur mattis. Vivamus ut metus accumsan tellus auctor sollicitudin venenatis et nibh. Cras quis massa ac metus fringilla venenatis. Proin rutrum mauris purus, ut suscipit magna consectetur id. Integer consectetur sollicitudin ante, vitae faucibus neque efficitur in. Praesent ultricies nibh lectus. Mauris pharetra id odio eget iaculis. Duis dictum, risus id pellentesque rutrum, lorem quam malesuada massa, quis ullamcorper turpis urna a diam. Cras vulputate metus vel massa porta ullamcorper. Etiam porta condimentum nulla nec tristique. Sed nulla urna, pharetra non tortor sed, sollicitudin molestie diam. Maecenas enim leo, feugiat eget vehicula id, sollicitudin vitae ante.";
|
||||
@ -18,10 +18,12 @@ const doc = new Document({
|
||||
new Paragraph({
|
||||
children: [
|
||||
new InternalHyperlink({
|
||||
child: new TextRun({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Click here!",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
],
|
||||
anchor: "myAnchorId",
|
||||
}),
|
||||
],
|
||||
@ -47,14 +49,24 @@ const doc = new Document({
|
||||
new Paragraph({
|
||||
children: [
|
||||
new InternalHyperlink({
|
||||
child: new TextRun({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Styled",
|
||||
bold: true,
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
new TextRun({
|
||||
text: " Anchor Text",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
],
|
||||
anchor: "myAnchorId",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [new TextRun("The bookmark can be seen on page "), new PageReference("myAnchorId")],
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -1,7 +1,7 @@
|
||||
// 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 { Document, Packer, Paragraph } from "../build";
|
||||
import { BorderStyle, Document, Packer, Paragraph } from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
@ -14,13 +14,13 @@ const doc = new Document({
|
||||
top: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
value: "single",
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
bottom: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
value: "single",
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
},
|
||||
|
@ -9,6 +9,9 @@ import { File, HeadingLevel, Packer, Paragraph, StyleLevel, TableOfContents } fr
|
||||
// Let's define the properties for generate a TOC for heading 1-5 and MySpectacularStyle,
|
||||
// making the entries be hyperlinks for the paragraph
|
||||
const doc = new File({
|
||||
features: {
|
||||
updateFields: true,
|
||||
},
|
||||
styles: {
|
||||
paragraphStyles: [
|
||||
{
|
||||
|
@ -98,7 +98,7 @@ const table3 = new Table({
|
||||
children: [new Paragraph("Bar1")],
|
||||
shading: {
|
||||
fill: "b79c2f",
|
||||
val: ShadingType.REVERSE_DIAGONAL_STRIPE,
|
||||
type: ShadingType.REVERSE_DIAGONAL_STRIPE,
|
||||
color: "auto",
|
||||
},
|
||||
}),
|
||||
@ -106,7 +106,7 @@ const table3 = new Table({
|
||||
children: [new Paragraph("Bar2")],
|
||||
shading: {
|
||||
fill: "42c5f4",
|
||||
val: ShadingType.PERCENT_95,
|
||||
type: ShadingType.PERCENT_95,
|
||||
color: "auto",
|
||||
},
|
||||
}),
|
||||
@ -114,7 +114,7 @@ const table3 = new Table({
|
||||
children: [new Paragraph("Bar3")],
|
||||
shading: {
|
||||
fill: "880aa8",
|
||||
val: ShadingType.PERCENT_10,
|
||||
type: ShadingType.PERCENT_10,
|
||||
color: "e2df0b",
|
||||
},
|
||||
}),
|
||||
@ -122,7 +122,7 @@ const table3 = new Table({
|
||||
children: [new Paragraph("Bar4")],
|
||||
shading: {
|
||||
fill: "FF0000",
|
||||
val: ShadingType.CLEAR,
|
||||
type: ShadingType.CLEAR,
|
||||
color: "auto",
|
||||
},
|
||||
}),
|
||||
@ -224,22 +224,22 @@ const borders = {
|
||||
top: {
|
||||
style: BorderStyle.DASH_SMALL_GAP,
|
||||
size: 1,
|
||||
color: "red",
|
||||
color: "FF0000",
|
||||
},
|
||||
bottom: {
|
||||
style: BorderStyle.DASH_SMALL_GAP,
|
||||
size: 1,
|
||||
color: "red",
|
||||
color: "FF0000",
|
||||
},
|
||||
left: {
|
||||
style: BorderStyle.DASH_SMALL_GAP,
|
||||
size: 1,
|
||||
color: "red",
|
||||
color: "FF0000",
|
||||
},
|
||||
right: {
|
||||
style: BorderStyle.DASH_SMALL_GAP,
|
||||
size: 1,
|
||||
color: "red",
|
||||
color: "FF0000",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -11,10 +11,12 @@ const doc = new Document({
|
||||
children: [
|
||||
new TextRun("Click here for the "),
|
||||
new ExternalHyperlink({
|
||||
child: new TextRun({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Footnotes external hyperlink",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
],
|
||||
link: "http://www.example.com",
|
||||
}),
|
||||
],
|
||||
@ -31,10 +33,12 @@ const doc = new Document({
|
||||
children: [
|
||||
new TextRun("Click here for the "),
|
||||
new ExternalHyperlink({
|
||||
child: new TextRun({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Footer external hyperlink",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
],
|
||||
link: "http://www.example.com",
|
||||
}),
|
||||
],
|
||||
@ -49,10 +53,12 @@ const doc = new Document({
|
||||
children: [
|
||||
new TextRun("Click here for the "),
|
||||
new ExternalHyperlink({
|
||||
child: new TextRun({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Header external hyperlink",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
],
|
||||
link: "http://www.google.com",
|
||||
}),
|
||||
],
|
||||
@ -64,10 +70,12 @@ const doc = new Document({
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ExternalHyperlink({
|
||||
child: new TextRun({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Anchor Text",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
],
|
||||
link: "http://www.example.com",
|
||||
}),
|
||||
new FootnoteReferenceRun(1),
|
||||
@ -76,24 +84,63 @@ const doc = new Document({
|
||||
new Paragraph({
|
||||
children: [
|
||||
new ExternalHyperlink({
|
||||
child: new ImageRun({
|
||||
children: [
|
||||
new ImageRun({
|
||||
data: fs.readFileSync("./demo/images/image1.jpeg"),
|
||||
transformation: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
}),
|
||||
],
|
||||
link: "http://www.google.com",
|
||||
}),
|
||||
new ExternalHyperlink({
|
||||
child: new TextRun({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "BBC News Link",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
],
|
||||
link: "https://www.bbc.co.uk/news",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "This is a hyperlink with formatting: ",
|
||||
}),
|
||||
new ExternalHyperlink({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "A ",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
new TextRun({
|
||||
text: "single ",
|
||||
bold: true,
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
new TextRun({
|
||||
text: "link",
|
||||
doubleStrike: true,
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
new TextRun({
|
||||
text: "1",
|
||||
superScript: true,
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
new TextRun({
|
||||
text: "!",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
],
|
||||
link: "http://www.example.com",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Example how to display page numbers
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { AlignmentType, Document, Footer, Header, Packer, PageBreak, PageNumber, PageNumberFormat, Paragraph, TextRun } from "../build";
|
||||
import { AlignmentType, Document, Footer, Header, Packer, PageBreak, PageNumber, NumberFormat, Paragraph, TextRun } from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
@ -10,7 +10,7 @@ const doc = new Document({
|
||||
page: {
|
||||
pageNumbers: {
|
||||
start: 1,
|
||||
formatType: PageNumberFormat.DECIMAL,
|
||||
formatType: NumberFormat.DECIMAL,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -14,7 +14,7 @@ const doc = new Document({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Hello World",
|
||||
color: "red",
|
||||
color: "FF0000",
|
||||
bold: true,
|
||||
size: 24,
|
||||
font: {
|
||||
|
@ -14,7 +14,7 @@ const doc = new Document({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "Hello World",
|
||||
color: "red",
|
||||
color: "FF0000",
|
||||
bold: true,
|
||||
size: 24,
|
||||
font: {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Multiple sections with total number of pages in each section
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { AlignmentType, Document, Footer, Header, Packer, PageBreak, PageNumber, PageNumberFormat, Paragraph, TextRun } from "../build";
|
||||
import { AlignmentType, Document, Footer, Header, Packer, PageBreak, PageNumber, NumberFormat, Paragraph, TextRun } from "../build";
|
||||
|
||||
const header = new Header({
|
||||
children: [
|
||||
@ -31,7 +31,7 @@ const doc = new Document({
|
||||
page: {
|
||||
pageNumbers: {
|
||||
start: 1,
|
||||
formatType: PageNumberFormat.DECIMAL,
|
||||
formatType: NumberFormat.DECIMAL,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -52,7 +52,7 @@ const doc = new Document({
|
||||
page: {
|
||||
pageNumbers: {
|
||||
start: 1,
|
||||
formatType: PageNumberFormat.DECIMAL,
|
||||
formatType: NumberFormat.DECIMAL,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1,13 +1,13 @@
|
||||
// Example of making content of section vertically aligned
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Document, Packer, Paragraph, SectionVerticalAlignValue, TextRun } from "../build";
|
||||
import { Document, Packer, Paragraph, VerticalAlign, TextRun } from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
{
|
||||
properties: {
|
||||
verticalAlign: SectionVerticalAlignValue.CENTER,
|
||||
verticalAlign: VerticalAlign.CENTER,
|
||||
},
|
||||
children: [
|
||||
new Paragraph({
|
||||
|
@ -24,22 +24,22 @@ const table = new Table({
|
||||
top: {
|
||||
style: BorderStyle.DASH_SMALL_GAP,
|
||||
size: 1,
|
||||
color: "red",
|
||||
color: "ff0000",
|
||||
},
|
||||
bottom: {
|
||||
style: BorderStyle.DASH_SMALL_GAP,
|
||||
size: 1,
|
||||
color: "red",
|
||||
color: "ff0000",
|
||||
},
|
||||
left: {
|
||||
style: BorderStyle.DASH_SMALL_GAP,
|
||||
size: 1,
|
||||
color: "red",
|
||||
color: "ff0000",
|
||||
},
|
||||
right: {
|
||||
style: BorderStyle.DASH_SMALL_GAP,
|
||||
size: 1,
|
||||
color: "red",
|
||||
color: "ff0000",
|
||||
},
|
||||
},
|
||||
children: [new Paragraph("Hello")],
|
||||
|
@ -20,10 +20,12 @@ import {
|
||||
- https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.insertedrun
|
||||
- https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.deletedrun
|
||||
|
||||
The method `addTrackRevisions()` adds an element `<w:trackRevisions />` to the `settings.xml` file. This specifies that the application shall track *new* revisions made to the existing document.
|
||||
The setting `features: { trackRevisions: true }` adds an element `<w:trackRevisions />` to the `settings.xml` file.
|
||||
This specifies that the application shall track *new* revisions made to the existing document.
|
||||
See also https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.trackrevisions
|
||||
|
||||
Note that this setting enables to track *new changes* after teh file is generated, so this example will still show inserted and deleted text runs when you remove it.
|
||||
Note that this setting enables to track *new changes* after teh file is generated, so this example will still
|
||||
show inserted and deleted text runs when you remove it.
|
||||
*/
|
||||
|
||||
const paragraph = new Paragraph({
|
||||
@ -85,7 +87,7 @@ const doc = new Document({
|
||||
new DeletedTextRun({
|
||||
break: 1,
|
||||
text: "in order",
|
||||
color: "red",
|
||||
color: "ff0000",
|
||||
bold: true,
|
||||
size: 24,
|
||||
font: {
|
||||
|
@ -1,7 +1,16 @@
|
||||
// Text Frame (Text Box) example
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Document, FrameAnchorType, HorizontalPositionAlign, Packer, Paragraph, TextRun, VerticalPositionAlign } from "../build";
|
||||
import {
|
||||
BorderStyle,
|
||||
Document,
|
||||
FrameAnchorType,
|
||||
HorizontalPositionAlign,
|
||||
Packer,
|
||||
Paragraph,
|
||||
TextRun,
|
||||
VerticalPositionAlign,
|
||||
} from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
@ -29,25 +38,25 @@ const doc = new Document({
|
||||
top: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
value: "single",
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
bottom: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
value: "single",
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
left: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
value: "single",
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
right: {
|
||||
color: "auto",
|
||||
space: 1,
|
||||
value: "single",
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 6,
|
||||
},
|
||||
},
|
||||
|
38
demo/65-page-sizes.ts
Normal file
38
demo/65-page-sizes.ts
Normal file
@ -0,0 +1,38 @@
|
||||
// Example of how to set the document page sizes
|
||||
// Reference from https://papersizes.io/a/a3
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { convertMillimetersToTwip, Document, Packer, PageOrientation, Paragraph } from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
{
|
||||
properties: {
|
||||
page: {
|
||||
size: {
|
||||
orientation: PageOrientation.LANDSCAPE,
|
||||
height: convertMillimetersToTwip(210),
|
||||
width: convertMillimetersToTwip(148),
|
||||
},
|
||||
},
|
||||
},
|
||||
children: [new Paragraph("Hello World")],
|
||||
},
|
||||
{
|
||||
properties: {
|
||||
page: {
|
||||
size: {
|
||||
orientation: PageOrientation.PORTRAIT,
|
||||
height: convertMillimetersToTwip(420),
|
||||
width: convertMillimetersToTwip(297),
|
||||
},
|
||||
},
|
||||
},
|
||||
children: [new Paragraph("Hello World")],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Packer.toBuffer(doc).then((buffer) => {
|
||||
fs.writeFileSync("My Document.docx", buffer);
|
||||
});
|
43
demo/66-fields.ts
Normal file
43
demo/66-fields.ts
Normal file
@ -0,0 +1,43 @@
|
||||
// Use fields to include dynamic text
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Bookmark, Document, Packer, Paragraph, SimpleField, TextRun } from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
creator: 'Me',
|
||||
sections: [
|
||||
{
|
||||
properties: {},
|
||||
children: [
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun("This document is called "),
|
||||
new SimpleField("FILENAME", "My Document.docx"),
|
||||
new TextRun(", was created on "),
|
||||
new SimpleField('CREATEDATE \\@ "d MMMM yyyy"'),
|
||||
new TextRun(" by "),
|
||||
new SimpleField("AUTHOR"),
|
||||
],
|
||||
}),
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun("The document has "),
|
||||
new SimpleField("NUMWORDS", "34"),
|
||||
new TextRun(" words and if you'd print it "),
|
||||
new Bookmark({
|
||||
id: "TimesPrinted",
|
||||
children: [new TextRun("42")],
|
||||
}),
|
||||
new TextRun(" times two-sided, you would need "),
|
||||
new SimpleField("=INT((TimesPrinted+1)/2)"),
|
||||
new TextRun(" sheets of paper."),
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Packer.toBuffer(doc).then((buffer) => {
|
||||
fs.writeFileSync("My Document.docx", buffer);
|
||||
});
|
28
demo/67-column-break.ts
Normal file
28
demo/67-column-break.ts
Normal file
@ -0,0 +1,28 @@
|
||||
// Section with 2 columns including a column break
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Document, Packer, Paragraph, ColumnBreak, TextRun } from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
{
|
||||
properties: {
|
||||
column: {
|
||||
space: 708,
|
||||
count: 2,
|
||||
},
|
||||
},
|
||||
children: [
|
||||
new Paragraph({ children: [
|
||||
new TextRun('This text will be in the first column.'),
|
||||
new ColumnBreak(),
|
||||
new TextRun('This text will be in the second column.'),
|
||||
] }),
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Packer.toBuffer(doc).then((buffer) => {
|
||||
fs.writeFileSync("My Document.docx", buffer);
|
||||
});
|
86
demo/68-numbering-instances-and-starting-number.ts
Normal file
86
demo/68-numbering-instances-and-starting-number.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import * as fs from "fs";
|
||||
import { Document, Packer, Paragraph, PageNumberFormat} from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
numbering:{
|
||||
config:[
|
||||
{
|
||||
reference: 'ref1',
|
||||
levels: [
|
||||
{
|
||||
level: 0,
|
||||
format: PageNumberFormat.DECIMAL,
|
||||
text: '%1',
|
||||
start: 10,
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
reference: 'ref2',
|
||||
levels: [
|
||||
{
|
||||
level: 0,
|
||||
format: PageNumberFormat.DECIMAL,
|
||||
text: '%1'
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
sections: [{
|
||||
children: [
|
||||
new Paragraph({
|
||||
text: "REF1 - inst:0 - lvl:0",
|
||||
numbering : {
|
||||
reference: 'ref1',
|
||||
instance: 0,
|
||||
level: 0,
|
||||
}
|
||||
}),
|
||||
new Paragraph({
|
||||
text: "REF1 - inst:0 - lvl:0",
|
||||
numbering : {
|
||||
reference: 'ref1',
|
||||
instance: 0,
|
||||
level: 0,
|
||||
}
|
||||
}),
|
||||
new Paragraph({
|
||||
text: "REF1 - inst:1 - lvl:0",
|
||||
numbering : {
|
||||
reference: 'ref1',
|
||||
instance: 1,
|
||||
level: 0,
|
||||
},
|
||||
}),
|
||||
new Paragraph({
|
||||
text: "REF1 - inst:1 - lvl:0",
|
||||
numbering : {
|
||||
reference: 'ref1',
|
||||
instance: 1,
|
||||
level: 0,
|
||||
}
|
||||
}),
|
||||
new Paragraph({
|
||||
text: "REF2 - inst:0 - lvl:0",
|
||||
numbering : {
|
||||
reference: 'ref2',
|
||||
instance: 1,
|
||||
level: 0,
|
||||
}
|
||||
}),
|
||||
new Paragraph({
|
||||
text: "REF2 - inst:0 - lvl:0",
|
||||
numbering : {
|
||||
reference: 'ref2',
|
||||
instance: 1,
|
||||
level: 0,
|
||||
}
|
||||
})
|
||||
],
|
||||
}]
|
||||
});
|
||||
|
||||
Packer.toBuffer(doc).then((buffer) => {
|
||||
fs.writeFileSync("My Document.docx", buffer);
|
||||
});
|
31
demo/69-different-width-columns.ts
Normal file
31
demo/69-different-width-columns.ts
Normal file
@ -0,0 +1,31 @@
|
||||
// Sections with multiple columns
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Column, Document, Packer, Paragraph } from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
{
|
||||
properties: {
|
||||
column: {
|
||||
count: 2,
|
||||
space: 720,
|
||||
equalWidth: false,
|
||||
children: [new Column({ width: 2880, space: 720 }), new Column({ width: 5760 })],
|
||||
},
|
||||
},
|
||||
children: [
|
||||
new Paragraph(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
|
||||
),
|
||||
new Paragraph(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
|
||||
),
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Packer.toBuffer(doc).then((buffer) => {
|
||||
fs.writeFileSync("My Document.docx", buffer);
|
||||
});
|
37
demo/70-line-numbers-suppression.ts
Normal file
37
demo/70-line-numbers-suppression.ts
Normal file
@ -0,0 +1,37 @@
|
||||
// Example demonstrating line numbers with suppression.
|
||||
// Import from 'docx' rather than '../build' if you install from npm
|
||||
import * as fs from "fs";
|
||||
import { Document, HeadingLevel, LineNumberRestartFormat, Packer, Paragraph } from "../build";
|
||||
|
||||
const doc = new Document({
|
||||
sections: [
|
||||
{
|
||||
properties: {
|
||||
lineNumbers: {
|
||||
countBy: 1,
|
||||
restart: LineNumberRestartFormat.CONTINUOUS,
|
||||
},
|
||||
},
|
||||
children: [
|
||||
new Paragraph({
|
||||
text: "Hello",
|
||||
heading: HeadingLevel.HEADING_1,
|
||||
}),
|
||||
new Paragraph(
|
||||
"Himenaeos duis luctus nullam fermentum lobortis potenti vivamus non dis, sed facilisis ultricies scelerisque aenean risus hac senectus. Adipiscing id venenatis justo ante gravida placerat, ac curabitur dis pellentesque proin bibendum risus, aliquam porta taciti vulputate primis. Tortor ipsum fermentum quam vel convallis primis nisl praesent tincidunt, lobortis quisque felis vitae condimentum class ut sem nam, aenean potenti pretium ac amet lacinia himenaeos mi. Aliquam nisl turpis hendrerit est morbi malesuada, augue interdum mus inceptos curabitur tristique, parturient feugiat sodales nulla facilisi. Aliquam non pulvinar purus nulla ex integer, velit faucibus vitae at bibendum quam, risus elit aenean adipiscing posuere.",
|
||||
),
|
||||
new Paragraph({
|
||||
text: 'Enim mollit nostrud ut dolor eiusmod id sit occaecat dolore culpa amet. Veniam dolor consequat dolor labore ullamco laborum dolore eiusmod qui adipisicing. Elit nulla cupidatat et magna. Id eiusmod tempor non laborum ipsum. Veniam et aliqua excepteur duis officia enim elit excepteur fugiat duis. Sit sunt ullamco non dolor est qui deserunt consequat magna. Esse pariatur esse dolor ut excepteur dolor nisi nisi non est cupidatat mollit.',
|
||||
suppressLineNumbers: true
|
||||
}),
|
||||
new Paragraph(
|
||||
"Sed laoreet id mattis egestas nam mollis elit lacinia convallis dui tincidunt ultricies habitant, pharetra per maximus interdum neque tempor risus efficitur morbi imperdiet senectus. Lectus laoreet senectus finibus inceptos donec potenti fermentum, ultrices eleifend odio suscipit magnis tellus maximus nibh, ac sit nullam eget felis himenaeos. Diam class sem magnis aenean commodo faucibus id proin mi, nullam sodales nec mus parturient ornare ad inceptos velit hendrerit, bibendum placerat eleifend integer facilisis urna dictumst suspendisse.",
|
||||
),
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Packer.toBuffer(doc).then((buffer) => {
|
||||
fs.writeFileSync("My Document.docx", buffer);
|
||||
});
|
@ -12,9 +12,7 @@
|
||||
|
||||
<script>
|
||||
function generate() {
|
||||
const doc = new docx.Document();
|
||||
|
||||
const doc = new Document({
|
||||
const doc = new docx.Document({
|
||||
sections: [
|
||||
{
|
||||
children: [
|
||||
|
@ -44,7 +44,7 @@ const doc = new Document({
|
||||
],
|
||||
}),
|
||||
],
|
||||
}];
|
||||
}],
|
||||
});
|
||||
|
||||
// Used to export the file into a .docx file
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
- Simple, declarative API
|
||||
- 60+ usage examples
|
||||
- Battle tested, mature, 98%+ coverage
|
||||
- Battle tested, mature, 99%+ coverage
|
||||
|
||||
[GitHub](https://github.com/dolanmiu/docx)
|
||||
[Get Started](#Welcome)
|
||||
|
@ -15,6 +15,7 @@
|
||||
* [Image](usage/images.md)
|
||||
* [Headers & Footers](usage/headers-and-footers.md)
|
||||
* [Bullet Points](usage/bullet-points.md)
|
||||
* [Hyperlinks](usage/hyperlinks.md)
|
||||
* [Numbering](usage/numbering.md)
|
||||
* [Tables](usage/tables.md)
|
||||
* [Tab Stops](usage/tab-stops.md)
|
||||
|
@ -37,7 +37,7 @@ const paragraph = new Paragraph({
|
||||
new TextRun("This is a simple demo"),
|
||||
new DeletedTextRun({
|
||||
text: "with a deletion.",
|
||||
color: "red",
|
||||
color: "ff0000",
|
||||
bold: true,
|
||||
size: 24,
|
||||
id: 0,
|
||||
|
73
docs/usage/fields.md
Normal file
73
docs/usage/fields.md
Normal file
@ -0,0 +1,73 @@
|
||||
# Fields
|
||||
|
||||
Fields are pieces of dynamic text that you can include in your document. Often used fields are page numbers or references, but you can also include document properties like the author name or last saved date.
|
||||
|
||||
## Simple fields
|
||||
|
||||
There are very complicated fields like the table of contents, but in many cases the whole field just has the same properties (like formatting). In those cases, you can use simple fields.
|
||||
|
||||
Word uses field codes to identify what the result of the field should be. You can find these field codes by adding a field in a document (`Insert -> Quick Parts -> Field...`) and clicking the 'Field codes'-button. Some examples include:
|
||||
|
||||
Field type | Example | Description
|
||||
----------- | --------------- | ---------------------------------------------------------
|
||||
= (Formula) | `=2*21` | Calculates the result of a formula. You can also use bookmarks as variables, see below.
|
||||
Author | `AUTHOR` | Includes the author mentioned in the document properties.
|
||||
CreateDate | `CREATEDATE` | Date the document was created.
|
||||
Date | `DATE` | Today's date.
|
||||
FileName | `FILENAME \p` | The name of the document. Add `\p` for the complete path.
|
||||
Info | `INFO NumWords` | Data from the document properties, e.g. the number of words in the document.
|
||||
NumPages | `NUMPAGES` | Number of pages in the document.
|
||||
UserName | `USERNAME` | Your user name from the Office personalization settings.
|
||||
|
||||
Fields can be added as a child of a paragraph:
|
||||
|
||||
```ts
|
||||
const paragraph = new Paragraph({
|
||||
children: [new TextRun("This document was created by: "), new SimpleField("AUTHOR")],
|
||||
});
|
||||
```
|
||||
|
||||
Fields can contain a cached value that gives the word processor a text to show without having to calculate all fields. The cached value can be updated by selecting the field and pressing F9. A cached value can be passed in as the second argument to the constructor.
|
||||
|
||||
```ts
|
||||
const paragraph = new Paragraph({
|
||||
children: [new TextRun("This document was created by: "), new SimpleField("AUTHOR", "Richard Brodie")],
|
||||
});
|
||||
```
|
||||
|
||||
### Formulas
|
||||
|
||||
One type of field is the formula that can be used to do some basic calculations. This can be done with static values, e.g. `12 + 34`, but a value from a bookmark can also be used in a calculation. This can be seen in the following example:
|
||||
|
||||
```ts
|
||||
const paragraph = new Paragraph({
|
||||
children: [
|
||||
new TextRun("Value one is: "),
|
||||
new Bookmark({ id: "One", children: [new TextRun("451")]}),
|
||||
new TextRun(". The second value is: "),
|
||||
new Bookmark({ id: "Two", children: [new TextRun("886")]}),
|
||||
new TextRun(". The sum of these values is: "),
|
||||
new SimpleField("=One+Two"),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
### Mail merge fields
|
||||
|
||||
Fields are often used in a mail merge where a template document is created and data from another source (Excel or a database) is inserted in the document.
|
||||
|
||||
A convenience class was added to add these mail merge fields to the document easily. You can add these to a paragraph like any other field and only have to supply the name of the field in your data set:
|
||||
|
||||
```ts
|
||||
const paragraph = new Paragraph({
|
||||
children: [new TextRun("Your score was "), new SimpleMailMergeField("Score"), new TextRun(" of 100 points")],
|
||||
});
|
||||
```
|
||||
|
||||
This code is equivalent to:
|
||||
|
||||
```ts
|
||||
const paragraph = new Paragraph({
|
||||
children: [new TextRun("Your score was "), new SimpleField("MERGEFIELD Score", "«Score»"), new TextRun(" of 100 points")],
|
||||
});
|
||||
```
|
@ -1,47 +1,98 @@
|
||||
# Hyperlinks
|
||||
|
||||
!> Hyperlinks require an understanding of [Paragraphs](usage/paragraph.md) and [Text](usage/text.md).
|
||||
|
||||
There are two types of hyperlinks: internal (pointing to a bookmark inside the document) and external (pointing to an external url).
|
||||
|
||||
## Internal
|
||||
|
||||
To create an internal hyperlink you need first to create a bookmark (the paragraph that will be the destination of the hyperlink) with `doc.createBookmark(anchor, text)`.
|
||||
To create an internal hyperlink you need first to create a `Bookmark`, which contains the content that will be the destination of the hyperlink.
|
||||
|
||||
A bookmark is composed of an anchor (an identifier) and the text displayed. After creating a bookmark just add it to a paragraph with `paragraph.addBookmark(bookmark)`
|
||||
|
||||
For example:
|
||||
A bookmark is composed of an anchor (an identifier) and the text displayed. After creating a bookmark just add it to a paragraph. For example, creating a bookmarked heading:
|
||||
|
||||
```ts
|
||||
const paragraph = this.doc.createParagraph();
|
||||
const bookmark = this.doc.createBookmark('anchorForChapter1', 'This is chapter1');
|
||||
paragraph.addBookmark(bookmark);
|
||||
const chapter1 = new Paragraph({
|
||||
heading: HeadingLevel.HEADING_1,
|
||||
children: [
|
||||
new Bookmark({
|
||||
id: "anchorForChapter1",
|
||||
children: [
|
||||
new TextRun("Chapter 1"),
|
||||
],
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
Then you can create an hyperlink pointing to that bookmark with `doc.createInternalHyperLink(anchor,text)`:
|
||||
Then you can create an hyperlink pointing to that bookmark with an `InternalHyperLink`:
|
||||
|
||||
```ts
|
||||
const paragraph = this.doc.createParagraph();
|
||||
const link = this.doc.createInternalHyperLink('anchorForChapter1', 'This is a link to chapter1');
|
||||
paragraph.addHyperLink(link);
|
||||
const link = new InternalHyperlink({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "See Chapter 1",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
],
|
||||
anchor: "anchorForChapter1",
|
||||
})
|
||||
```
|
||||
|
||||
You can also get the page number of the bookmark by creating a page reference to it:
|
||||
|
||||
```ts
|
||||
const paragraph = new Paragraph({
|
||||
children: [
|
||||
new TextRun("Chapter 1 can be seen on page "),
|
||||
new PageReference("anchorForChapter1"),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## External
|
||||
|
||||
To create an external hyperlink you just need to specify the url and the text of the link, then add it to a paragraph with `doc.createHyperlink(url, text)`:
|
||||
To create an external hyperlink you just need to specify the url and the text of the link, then add it to a paragraph:
|
||||
|
||||
```ts
|
||||
const paragraph = this.doc.createParagraph();
|
||||
const link = this.doc.createHyperlink('https://docx.js.org', 'This is an external link');
|
||||
paragraph.addHyperLink(link);
|
||||
const paragraph = new Paragraph({
|
||||
children: [
|
||||
new ExternalHyperlink({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "This is an external link!",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
],
|
||||
link: "https://docx.js.org",
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Styling an hyperlink
|
||||
## Styling hyperlinks
|
||||
|
||||
It is possible to set the style of the text of an hyperlink. This can be done applying run formatting on `TextRun` property of the hyperlink.
|
||||
It is possible to set the style of the text of both internal and external hyperlinks. This can be done applying run formatting on any of the `TextRun` children of the hyperlink. Use the `style: "Hyperlink"` property to show the default link styles, which can be combined with any other style.
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
const link = this.doc.createHyperlink('https://docx.js.org', 'This is an external link');
|
||||
link.TextRun.bold().italics()
|
||||
const styledLink = new ExternalHyperlink({
|
||||
children: [
|
||||
new TextRun({
|
||||
text: "This is a ",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
new TextRun({
|
||||
text: "bold",
|
||||
bold: true,
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
new TextRun({
|
||||
text: " link!",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
],
|
||||
link: "https://docx.js.org",
|
||||
});
|
||||
```
|
||||
|
@ -5,35 +5,49 @@
|
||||
?> **Note:** This feature only works on Headers and Footers
|
||||
|
||||
```ts
|
||||
doc.Header.createParagraph().addRun(new TextRun("Page Number: ").pageNumber()).addRun(new TextRun("to ").numberOfTotalPages());
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
children: ["Page #: ", PageNumber.CURRENT],
|
||||
})
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
## Current page number
|
||||
|
||||
To get the current page number, call the `.pageNumber()` method on a `TextRun`. Then add the newly created `TextRun` into a paragraph
|
||||
|
||||
```ts
|
||||
pageNumber();
|
||||
PageNumber.CURRENT
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
const currentPageRun = new TextRun("Current Page Number: ").pageNumber();
|
||||
paragraph.addRun(currentPageRun);
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
children: ["Page Number ", PageNumber.CURRENT],
|
||||
})
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
## Total number of pages
|
||||
|
||||
```ts
|
||||
numberOfTotalPages();
|
||||
PageNumber.TOTAL_PAGES
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
const lastPage = new TextRun("Total Page Number: ").numberOfTotalPages();
|
||||
paragraph.addRun(lastPage);
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun({
|
||||
children: ["Total Pages Number: ", PageNumber.TOTAL_PAGES],
|
||||
})
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@ -42,17 +56,14 @@ paragraph.addRun(lastPage);
|
||||
You can combine the two to get "Page 2 of 10" effect:
|
||||
|
||||
```ts
|
||||
const currentPageRun = new TextRun("Page ").pageNumber();
|
||||
const lastPage = new TextRun("of ").numberOfTotalPages();
|
||||
|
||||
paragraph.addRun(currentPageRun);
|
||||
paragraph.addRun(lastPage);
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```ts
|
||||
doc.Header.createParagraph().addRun(new TextRun("Page ").pageNumber()).addRun(new TextRun("of ").numberOfTotalPages());
|
||||
new Paragraph({
|
||||
children: [
|
||||
new TextRun("My awesome text here for my university dissertation. ")
|
||||
new TextRun({
|
||||
children: ["Page ", PageNumber.CURRENT, " of ", PageNumber.TOTAL_PAGES],
|
||||
})
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
> Everything (text, images, graphs etc) in OpenXML is organized in paragraphs.
|
||||
|
||||
!> Paragraphs requires an understanding of [Sections](sections.md).
|
||||
!> Paragraphs requires an understanding of [Sections](usage/sections.md).
|
||||
|
||||
You can create `Paragraphs` in the following ways:
|
||||
|
||||
@ -16,7 +16,7 @@ const paragraph = new Paragraph("Short hand Hello World");
|
||||
|
||||
### Children Method
|
||||
|
||||
This method is useful for adding different [text](text.md) with different styles, [symbols](symbols.md), or adding [images](images.md) inline.
|
||||
This method is useful for adding different [text](usage/text.md) with different styles, [symbols](usage/symbols.md), or adding [images](usage/images.md) inline.
|
||||
|
||||
```ts
|
||||
const paragraph = new Paragraph({
|
||||
@ -180,12 +180,12 @@ Adding spacing between paragraphs
|
||||
|
||||
### ISpacingProperties
|
||||
|
||||
| Property | Type | Notes |
|
||||
| -------- | -------------- | -------- |
|
||||
| after | `number` | Optional |
|
||||
| before | `number` | Optional |
|
||||
| line | `number` | Optional |
|
||||
| lineRule | `LineRuleType` | Optional |
|
||||
| Property | Type | Notes | Possible Values |
|
||||
| -------- | -------------- | -------- | ----------------------------- |
|
||||
| after | `number` | Optional | |
|
||||
| before | `number` | Optional | |
|
||||
| line | `number` | Optional | |
|
||||
| lineRule | `LineRuleType` | Optional | `AT_LEAST`, `EXACTLY`, `AUTO` |
|
||||
|
||||
**Example:**
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
# Symbol Runs
|
||||
|
||||
!> SymbolRuns require an understanding of [Paragraphs](paragraph.md).
|
||||
!> SymbolRuns require an understanding of [Paragraphs](usage/paragraph.md).
|
||||
|
||||
You can add multiple `symbol runs` in `Paragraphs` along with [text runs](text.md) using the Paragraph's `children` property.
|
||||
You can add multiple `symbol runs` in `Paragraphs` along with [text runs](usage/text.md) using the Paragraph's `children` property.
|
||||
|
||||
```ts
|
||||
import { Paragraph, TextRun, SymbolRun } from "docx";
|
||||
@ -50,4 +50,4 @@ const symbol = new SymbolRun({
|
||||
});
|
||||
```
|
||||
|
||||
See the [text run](text.md) documentation for more info.
|
||||
See the [text run](usage/text.md) documentation for more info.
|
||||
|
@ -4,15 +4,15 @@
|
||||
|
||||
!> **Note**: The unit of measurement for a tab stop is in [DXA](https://stackoverflow.com/questions/14360183/default-wordml-unit-measurement-pixel-or-point-or-inches)
|
||||
|
||||

|
||||

|
||||
|
||||
Simply call the relevant methods on the paragraph listed below. Then just add a `tab()` method call to a text object. Adding multiple `tabStops` will mean you would have to chain `tab()` until the desired `tabStop` is selected. Example is shown below.
|
||||
Simply declare the tab stops on the paragraph, as shown below. Use the tab character `\t` to indicate the tab position within the `text` property of a `TextRun`. Adding multiple `tabStops` will mean you can add additional `\t` characters until the desired `tabStop` is selected. Example is shown below.
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
const paragraph = new Paragraph({
|
||||
children: [new TextRun("Hey everyone").bold(), new TextRun(\t"11th November 1999")],
|
||||
children: [new TextRun({ text: "Hey everyone", bold: true}), new TextRun("\t11th November 1999")],
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
@ -26,7 +26,7 @@ The example above will create a left aligned text, and a right aligned text on t
|
||||
|
||||
```ts
|
||||
const paragraph = new Paragraph({
|
||||
children: [new TextRun("Second tab stop here I come!")],
|
||||
children: [new TextRun("\t\tSecond tab stop here I come!")],
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
@ -46,7 +46,7 @@ You can add multiple tab stops of the same `type` too.
|
||||
|
||||
```ts
|
||||
const paragraph = new Paragraph({
|
||||
children: [new TextRun("Multiple tab stops!")],
|
||||
children: [new TextRun("Multiple \ttab \tstops!")],
|
||||
tabStops: [
|
||||
{
|
||||
type: TabStopType.RIGHT,
|
||||
@ -103,7 +103,7 @@ const paragraph = new Paragraph({
|
||||
});
|
||||
```
|
||||
|
||||
2268 is the distance fro0oum the left side.
|
||||
2268 is the distance from the left side.
|
||||
|
||||
## Max Right Tab Stop
|
||||
|
||||
|
@ -12,14 +12,29 @@ The complete documentation can be found [here](https://www.ecma-international.or
|
||||
|
||||
All you need to do is create a `TableOfContents` object and assign it to the document.
|
||||
|
||||
**Note**: updateFields feature must be enabled for TableOfContents to update correctly.
|
||||
|
||||
```ts
|
||||
const toc = new TableOfContents("Summary", {
|
||||
const doc = new Document({
|
||||
features: {
|
||||
updateFields: true,
|
||||
},
|
||||
sections: [
|
||||
{
|
||||
children: [
|
||||
new TableOfContents("Summary", {
|
||||
hyperlink: true,
|
||||
headingStyleRange: "1-5",
|
||||
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)],
|
||||
}),
|
||||
new Paragraph({
|
||||
text: "Header #1",
|
||||
heading: HeadingLevel.HEADING_1,
|
||||
pageBreakBefore: true,
|
||||
}),
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
doc.addTableOfContents(toc);
|
||||
```
|
||||
|
||||
## Table of Contents Options
|
||||
|
@ -53,6 +53,18 @@ const table = new Table({
|
||||
});
|
||||
```
|
||||
|
||||
### Set Indent
|
||||
|
||||
```ts
|
||||
const table = new Table({
|
||||
...,
|
||||
indent: {
|
||||
size: 600,
|
||||
type: WidthType.DXA,
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Table Row
|
||||
|
||||
A table consists of multiple `table rows`. Table rows have a list of `children` which accepts a list of `table cells` explained below. You can create a simple `table row` like so:
|
||||
@ -145,7 +157,7 @@ const tableRow = new TableRow({
|
||||
| Property | Type | Notes |
|
||||
| ------------- | ----------------------------------- | ----------------------------------------------------------- |
|
||||
| children | `Array<Paragraph or Table>` | Required. You can nest tables by adding a table into a cell |
|
||||
| shading | `ITableShadingAttributesProperties` | Optional |
|
||||
| shading | `IShadingAttributesProperties` | Optional |
|
||||
| margins | `ITableCellMarginOptions` | Optional |
|
||||
| verticalAlign | `VerticalAlign` | Optional |
|
||||
| columnSpan | `number` | Optional |
|
||||
@ -171,7 +183,7 @@ const cell = new TableCell({
|
||||
top: {
|
||||
style: BorderStyle.DASH_DOT_STROKED,
|
||||
size: 1,
|
||||
color: "red",
|
||||
color: "ff0000",
|
||||
},
|
||||
bottom: {
|
||||
style: BorderStyle.THICK_THIN_MEDIUM_GAP,
|
||||
@ -190,12 +202,12 @@ Google DOCS does not support start and end borders, instead they use left and ri
|
||||
const cell = new TableCell({
|
||||
...,
|
||||
borders: {
|
||||
top: {
|
||||
left: {
|
||||
style: BorderStyle.DOT_DOT_DASH,
|
||||
size: 3,
|
||||
color: "green",
|
||||
color: "00FF00",
|
||||
},
|
||||
bottom: {
|
||||
right: {
|
||||
style: BorderStyle.DOT_DOT_DASH,
|
||||
size: 3,
|
||||
color: "ff8000",
|
||||
@ -231,17 +243,11 @@ const cell = new TableCell({
|
||||
`WidthType` values can be:
|
||||
|
||||
| Property | Notes |
|
||||
| -------- | --------------------------------- |
|
||||
| ---------- | --------------------------------- |
|
||||
| AUTO | |
|
||||
| DXA | value is in twentieths of a point |
|
||||
| NIL | is considered as zero |
|
||||
| PCT | percent of table width |
|
||||
|
||||
#### Example
|
||||
|
||||
```ts
|
||||
cell.Properties.setWidth(100, WidthType.DXA);
|
||||
```
|
||||
| DXA | Value is in twentieths of a point |
|
||||
| NIL | Is considered as zero |
|
||||
| PERCENTAGE | Percent of table width |
|
||||
|
||||
### Nested Tables
|
||||
|
||||
|
6293
package-lock.json
generated
6293
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
41
package.json
41
package.json
@ -1,26 +1,25 @@
|
||||
{
|
||||
"name": "docx",
|
||||
"version": "6.0.3",
|
||||
"version": "7.1.0",
|
||||
"description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.",
|
||||
"main": "build/index.js",
|
||||
"scripts": {
|
||||
"pretest": "rimraf ./build",
|
||||
"test": "mocha-webpack \"src/**/*.ts\"",
|
||||
"test": "mocha -r ts-node/register -r tsconfig-paths/register \"src/**/*.ts\"",
|
||||
"test.coverage": "nyc npm test",
|
||||
"test.watch": "npm test -- --watch",
|
||||
"prepublishOnly": "npm run build --production",
|
||||
"lint": "tslint --project .",
|
||||
"build": "npm run webpack && npm run fix-types",
|
||||
"tsc": "rimraf ./build && tsc -p .",
|
||||
"webpack": "rimraf ./build && webpack",
|
||||
"demo": "npm run build && npm run ts-node ./demo",
|
||||
"webpack": "rimraf ./build && webpack --config ./webpack.config.ts",
|
||||
"demo": "npm run build && npm run ts-node --skip-project ./demo",
|
||||
"typedoc": "rimraf ./build && typedoc src/index.ts --tsconfig tsconfig.typedoc.json",
|
||||
"style": "prettier -l \"src/**/*.ts\"",
|
||||
"style.fix": "npm run style -- --write",
|
||||
"fix-types": "ts-node scripts/types-absolute-fixer.ts",
|
||||
"e2e": "ts-node scripts/e2e.ts",
|
||||
"serve.docs": "cd docs && docsify serve",
|
||||
"ts-node": "ts-node"
|
||||
"ts-node": "ts-node --skip-project"
|
||||
},
|
||||
"pre-commit": [
|
||||
"style",
|
||||
@ -49,8 +48,7 @@
|
||||
],
|
||||
"types": "./build/index.d.ts",
|
||||
"dependencies": {
|
||||
"@types/jszip": "^3.1.4",
|
||||
"@types/node": "^14.0.5",
|
||||
"@types/node": "^16.0.0",
|
||||
"jszip": "^3.1.5",
|
||||
"nanoid": "^3.1.20",
|
||||
"xml": "^1.0.1",
|
||||
@ -64,34 +62,37 @@
|
||||
"homepage": "https://github.com/dolanmiu/docx#readme",
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.2.15",
|
||||
"@types/mocha": "^8.0.0",
|
||||
"@types/mocha": "^9.0.0",
|
||||
"@types/request-promise": "^4.1.42",
|
||||
"@types/sinon": "^9.0.4",
|
||||
"@types/sinon": "^10.0.0",
|
||||
"@types/webpack": "^5.0.0",
|
||||
"awesome-typescript-loader": "^3.4.1",
|
||||
"buffer": "^6.0.3",
|
||||
"chai": "^3.5.0",
|
||||
"docsify-cli": "^4.3.0",
|
||||
"glob": "^7.1.2",
|
||||
"istanbul-instrumenter-loader": "^3.0.1",
|
||||
"jszip": "^3.1.5",
|
||||
"mocha": "^5.2.0",
|
||||
"mocha-webpack": "^1.0.1",
|
||||
"mocha": "^9.0.2",
|
||||
"nyc": "^15.1.0",
|
||||
"pre-commit": "^1.2.2",
|
||||
"prettier": "^2.1.2",
|
||||
"prettier": "^2.3.1",
|
||||
"process": "^0.11.10",
|
||||
"prompt": "^1.0.0",
|
||||
"replace-in-file": "^3.1.0",
|
||||
"replace-in-file": "^6.2.0",
|
||||
"request": "^2.88.0",
|
||||
"request-promise": "^4.2.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"shelljs": "^0.8.4",
|
||||
"sinon": "^10.0.0",
|
||||
"sinon": "^11.0.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"ts-loader": "^9.0.0",
|
||||
"ts-node": "^9.0.0",
|
||||
"tsconfig-paths": "^3.9.0",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-immutable": "^6.0.1",
|
||||
"typedoc": "^0.20.29",
|
||||
"typescript": "4.2.3",
|
||||
"webpack": "^3.10.0"
|
||||
"typedoc": "^0.22.3",
|
||||
"typescript": "4.4.3",
|
||||
"webpack": "^5.28.0",
|
||||
"webpack-cli": "^4.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
|
@ -1,18 +1,16 @@
|
||||
import * as glob from "glob";
|
||||
import * as replace from "replace-in-file";
|
||||
import { replaceInFile } from "replace-in-file";
|
||||
|
||||
const files = glob.sync("build/**/*.d.ts");
|
||||
|
||||
for (const file of files) {
|
||||
replace({
|
||||
replaceInFile({
|
||||
files: file,
|
||||
from: /"file[a-z/-]*"/gi,
|
||||
to: (match) => {
|
||||
const matchSlug = match.replace(/['"]+/g, "").trim();
|
||||
const levelCount = file.split("/").length - 2;
|
||||
const backLevels = Array(levelCount)
|
||||
.fill("../")
|
||||
.join("");
|
||||
const backLevels = Array(levelCount).fill("../").join("");
|
||||
|
||||
return `"${backLevels}${matchSlug}"`;
|
||||
},
|
||||
|
@ -18,14 +18,14 @@ describe("Utility", () => {
|
||||
});
|
||||
|
||||
describe("#uniqueNumericId", () => {
|
||||
it("should generate a unique ID", () => {
|
||||
it("should generate a unique incrementing ID", () => {
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
expect(uniqueNumericId()).to.not.be.undefined;
|
||||
});
|
||||
});
|
||||
|
||||
describe("#uniqueId", () => {
|
||||
it("should call the underlying header's addChildElement", () => {
|
||||
it("should generate a unique pseudorandom ID", () => {
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
expect(uniqueId()).to.not.be.empty;
|
||||
});
|
||||
|
@ -12,7 +12,7 @@ export const convertInchesToTwip = (inches: number): number => {
|
||||
};
|
||||
|
||||
export const uniqueNumericId = (): number => {
|
||||
return currentCount++;
|
||||
return ++currentCount;
|
||||
};
|
||||
|
||||
export const uniqueId = (): string => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { assert, expect } from "chai";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { Formatter } from "@export/formatter";
|
||||
import { Paragraph, TextRun } from "file";
|
||||
import { CoreProperties } from "file/core-properties";
|
||||
import { Attributes } from "file/xml-components";
|
||||
@ -45,18 +45,10 @@ describe("Formatter", () => {
|
||||
{
|
||||
"w:rPr": [
|
||||
{
|
||||
"w:b": {
|
||||
_attr: {
|
||||
"w:val": true,
|
||||
},
|
||||
},
|
||||
"w:b": {},
|
||||
},
|
||||
{
|
||||
"w:bCs": {
|
||||
_attr: {
|
||||
"w:val": true,
|
||||
},
|
||||
},
|
||||
"w:bCs": {},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -36,7 +36,7 @@ describe("ImageReplacer", () => {
|
||||
describe("#getMediaData()", () => {
|
||||
it("should get media data", () => {
|
||||
const imageReplacer = new ImageReplacer();
|
||||
const result = imageReplacer.getMediaData("test {test-image} test", ({
|
||||
const result = imageReplacer.getMediaData("test {test-image} test", {
|
||||
Array: [
|
||||
{
|
||||
stream: Buffer.from(""),
|
||||
@ -53,7 +53,7 @@ describe("ImageReplacer", () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
} as unknown) as Media);
|
||||
} as unknown as Media);
|
||||
|
||||
expect(result).to.have.length(1);
|
||||
});
|
||||
|
@ -70,7 +70,6 @@ export class Compiler {
|
||||
}
|
||||
|
||||
private xmlifyFile(file: File, prettify?: boolean): IXmlifyedFileMapping {
|
||||
file.verifyUpdateFields();
|
||||
const documentRelationshipCount = file.Document.Relationships.RelationshipCount + 1;
|
||||
|
||||
const documentXmlData = xml(
|
||||
@ -78,7 +77,13 @@ export class Compiler {
|
||||
viewWrapper: file.Document,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
standalone: "yes",
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
);
|
||||
const documentMediaDatas = this.imageReplacer.getMediaData(documentXmlData, file.Media);
|
||||
|
||||
@ -98,7 +103,12 @@ export class Compiler {
|
||||
viewWrapper: file.Document,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
);
|
||||
})(),
|
||||
path: "word/_rels/document.xml.rels",
|
||||
@ -113,13 +123,23 @@ export class Compiler {
|
||||
path: "word/document.xml",
|
||||
},
|
||||
Styles: {
|
||||
data: xml(
|
||||
data: (() => {
|
||||
const xmlStyles = xml(
|
||||
this.formatter.format(file.Styles, {
|
||||
viewWrapper: file.Document,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
),
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
standalone: "yes",
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
);
|
||||
const referencedXmlStyles = this.numberingReplacer.replace(xmlStyles, file.Numbering.ConcreteNumbering);
|
||||
return referencedXmlStyles;
|
||||
})(),
|
||||
path: "word/styles.xml",
|
||||
},
|
||||
Properties: {
|
||||
@ -129,6 +149,7 @@ export class Compiler {
|
||||
file,
|
||||
}),
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
standalone: "yes",
|
||||
encoding: "UTF-8",
|
||||
@ -143,7 +164,13 @@ export class Compiler {
|
||||
viewWrapper: file.Document,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
standalone: "yes",
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
),
|
||||
path: "word/numbering.xml",
|
||||
},
|
||||
@ -153,7 +180,12 @@ export class Compiler {
|
||||
viewWrapper: file.Document,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
),
|
||||
path: "_rels/.rels",
|
||||
},
|
||||
@ -163,7 +195,12 @@ export class Compiler {
|
||||
viewWrapper: headerWrapper,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
);
|
||||
const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media);
|
||||
|
||||
@ -181,7 +218,12 @@ export class Compiler {
|
||||
viewWrapper: headerWrapper,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
),
|
||||
path: `word/_rels/header${index + 1}.xml.rels`,
|
||||
};
|
||||
@ -192,7 +234,12 @@ export class Compiler {
|
||||
viewWrapper: footerWrapper,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
);
|
||||
const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media);
|
||||
|
||||
@ -210,7 +257,12 @@ export class Compiler {
|
||||
viewWrapper: footerWrapper,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
),
|
||||
path: `word/_rels/footer${index + 1}.xml.rels`,
|
||||
};
|
||||
@ -221,7 +273,12 @@ export class Compiler {
|
||||
viewWrapper: headerWrapper,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
);
|
||||
const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media);
|
||||
// TODO: 0 needs to be changed when headers get relationships of their own
|
||||
@ -238,7 +295,12 @@ export class Compiler {
|
||||
viewWrapper: footerWrapper,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
);
|
||||
const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media);
|
||||
// TODO: 0 needs to be changed when headers get relationships of their own
|
||||
@ -255,7 +317,12 @@ export class Compiler {
|
||||
viewWrapper: file.Document,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
),
|
||||
path: "[Content_Types].xml",
|
||||
},
|
||||
@ -265,7 +332,13 @@ export class Compiler {
|
||||
viewWrapper: file.Document,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
standalone: "yes",
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
),
|
||||
path: "docProps/custom.xml",
|
||||
},
|
||||
@ -275,7 +348,13 @@ export class Compiler {
|
||||
viewWrapper: file.Document,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
standalone: "yes",
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
),
|
||||
path: "docProps/app.xml",
|
||||
},
|
||||
@ -285,7 +364,12 @@ export class Compiler {
|
||||
viewWrapper: file.FootNotes,
|
||||
file: file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
),
|
||||
path: "word/footnotes.xml",
|
||||
},
|
||||
@ -295,7 +379,12 @@ export class Compiler {
|
||||
viewWrapper: file.FootNotes,
|
||||
file: file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
),
|
||||
path: "word/_rels/footnotes.xml.rels",
|
||||
},
|
||||
@ -305,7 +394,13 @@ export class Compiler {
|
||||
viewWrapper: file.Document,
|
||||
file,
|
||||
}),
|
||||
prettify,
|
||||
{
|
||||
indent: prettify,
|
||||
declaration: {
|
||||
standalone: "yes",
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
},
|
||||
),
|
||||
path: "word/settings.xml",
|
||||
},
|
||||
|
54
src/file/border/border.spec.ts
Normal file
54
src/file/border/border.spec.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { BorderStyle } from "file/border";
|
||||
|
||||
import { BorderElement } from "./border";
|
||||
|
||||
describe("BorderElement", () => {
|
||||
describe("#constructor", () => {
|
||||
it("should create a simple border element", () => {
|
||||
const border = new BorderElement("w:top", {
|
||||
style: BorderStyle.SINGLE,
|
||||
});
|
||||
const tree = new Formatter().format(border);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:top": {
|
||||
_attr: {
|
||||
"w:val": "single",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
it("should create a simple border element with a size", () => {
|
||||
const border = new BorderElement("w:top", {
|
||||
style: BorderStyle.SINGLE,
|
||||
size: 22,
|
||||
});
|
||||
const tree = new Formatter().format(border);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:top": {
|
||||
_attr: {
|
||||
"w:val": "single",
|
||||
"w:sz": 22,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
it("should create a simple border element with space", () => {
|
||||
const border = new BorderElement("w:top", {
|
||||
style: BorderStyle.SINGLE,
|
||||
space: 22,
|
||||
});
|
||||
const tree = new Formatter().format(border);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:top": {
|
||||
_attr: {
|
||||
"w:val": "single",
|
||||
"w:space": 22,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
86
src/file/border/border.ts
Normal file
86
src/file/border/border.ts
Normal file
@ -0,0 +1,86 @@
|
||||
// Note that the border type is identical in all places,
|
||||
// regardless of where it's used like paragraph/table/etc.
|
||||
// PageBorders are a superset, but we're not using any of those extras.
|
||||
//
|
||||
// http://officeopenxml.com/WPborders.php
|
||||
// http://officeopenxml.com/WPtableBorders.php
|
||||
// http://officeopenxml.com/WPtableCellProperties-Borders.php
|
||||
// http://officeopenxml.com/WPsectionBorders.php
|
||||
//
|
||||
// This describes the CT_Border type.
|
||||
// <xsd:complexType name="CT_Border">
|
||||
// <xsd:attribute name="val" type="ST_Border" use="required"/>
|
||||
// <xsd:attribute name="color" type="ST_HexColor" use="optional" default="auto"/>
|
||||
// <xsd:attribute name="themeColor" type="ST_ThemeColor" use="optional"/>
|
||||
// <xsd:attribute name="themeTint" type="ST_UcharHexNumber" use="optional"/>
|
||||
// <xsd:attribute name="themeShade" type="ST_UcharHexNumber" use="optional"/>
|
||||
// <xsd:attribute name="sz" type="ST_EighthPointMeasure" use="optional"/>
|
||||
// <xsd:attribute name="space" type="ST_PointMeasure" use="optional" default="0"/>
|
||||
// <xsd:attribute name="shadow" type="s:ST_OnOff" use="optional"/>
|
||||
// <xsd:attribute name="frame" type="s:ST_OnOff" use="optional"/>
|
||||
// </xsd:complexType>
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
import { eighthPointMeasureValue, hexColorValue, pointMeasureValue } from "../values";
|
||||
|
||||
export interface IBorderOptions {
|
||||
readonly style: BorderStyle;
|
||||
/** Border color, in hex (eg 'FF00AA') */
|
||||
readonly color?: string;
|
||||
/** Size of the border in 1/8 pt */
|
||||
readonly size?: number;
|
||||
/** Spacing offset. Values are specified in pt */
|
||||
readonly space?: number;
|
||||
}
|
||||
|
||||
export class BorderElement extends XmlComponent {
|
||||
constructor(elementName: string, { color, size, space, style }: IBorderOptions) {
|
||||
super(elementName);
|
||||
this.root.push(
|
||||
new BordersAttributes({
|
||||
style,
|
||||
color: color === undefined ? undefined : hexColorValue(color),
|
||||
size: size === undefined ? undefined : eighthPointMeasureValue(size),
|
||||
space: space === undefined ? undefined : pointMeasureValue(space),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BordersAttributes extends XmlAttributeComponent<IBorderOptions> {
|
||||
protected readonly xmlKeys = {
|
||||
style: "w:val",
|
||||
color: "w:color",
|
||||
size: "w:sz",
|
||||
space: "w:space",
|
||||
};
|
||||
}
|
||||
|
||||
export enum BorderStyle {
|
||||
SINGLE = "single",
|
||||
DASH_DOT_STROKED = "dashDotStroked",
|
||||
DASHED = "dashed",
|
||||
DASH_SMALL_GAP = "dashSmallGap",
|
||||
DOT_DASH = "dotDash",
|
||||
DOT_DOT_DASH = "dotDotDash",
|
||||
DOTTED = "dotted",
|
||||
DOUBLE = "double",
|
||||
DOUBLE_WAVE = "doubleWave",
|
||||
INSET = "inset",
|
||||
NIL = "nil",
|
||||
NONE = "none",
|
||||
OUTSET = "outset",
|
||||
THICK = "thick",
|
||||
THICK_THIN_LARGE_GAP = "thickThinLargeGap",
|
||||
THICK_THIN_MEDIUM_GAP = "thickThinMediumGap",
|
||||
THICK_THIN_SMALL_GAP = "thickThinSmallGap",
|
||||
THIN_THICK_LARGE_GAP = "thinThickLargeGap",
|
||||
THIN_THICK_MEDIUM_GAP = "thinThickMediumGap",
|
||||
THIN_THICK_SMALL_GAP = "thinThickSmallGap",
|
||||
THIN_THICK_THIN_LARGE_GAP = "thinThickThinLargeGap",
|
||||
THIN_THICK_THIN_MEDIUM_GAP = "thinThickThinMediumGap",
|
||||
THIN_THICK_THIN_SMALL_GAP = "thinThickThinSmallGap",
|
||||
THREE_D_EMBOSS = "threeDEmboss",
|
||||
THREE_D_ENGRAVE = "threeDEngrave",
|
||||
TRIPLE = "triple",
|
||||
WAVE = "wave",
|
||||
}
|
1
src/file/border/index.ts
Normal file
1
src/file/border/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./border";
|
@ -1,89 +0,0 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { DocumentAttributes } from "../document/document-attributes";
|
||||
|
||||
export class Title extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("dc:title");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Subject extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("dc:subject");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Creator extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("dc:creator");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Keywords extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("cp:keywords");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Description extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("dc:description");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class LastModifiedBy extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("cp:lastModifiedBy");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Revision extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("cp:revision");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class DateComponent extends XmlComponent {
|
||||
protected getCurrentDate(): string {
|
||||
const date = new Date();
|
||||
const year = date.getFullYear();
|
||||
const month = ("0" + (date.getMonth() + 1)).slice(-2);
|
||||
const day = ("0" + date.getDate()).slice(-2);
|
||||
const hours = ("0" + date.getHours()).slice(-2);
|
||||
const minutes = ("0" + date.getMinutes()).slice(-2);
|
||||
const seconds = ("0" + date.getSeconds()).slice(-2);
|
||||
|
||||
return year + "-" + month + "-" + day + "T" + hours + ":" + minutes + ":" + seconds + "Z";
|
||||
}
|
||||
}
|
||||
|
||||
export class Created extends DateComponent {
|
||||
constructor() {
|
||||
super("dcterms:created");
|
||||
this.root.push(
|
||||
new DocumentAttributes({
|
||||
type: "dcterms:W3CDTF",
|
||||
}),
|
||||
);
|
||||
this.root.push(this.getCurrentDate());
|
||||
}
|
||||
}
|
||||
|
||||
export class Modified extends DateComponent {
|
||||
constructor() {
|
||||
super("dcterms:modified");
|
||||
this.root.push(
|
||||
new DocumentAttributes({
|
||||
type: "dcterms:W3CDTF",
|
||||
}),
|
||||
);
|
||||
this.root.push(this.getCurrentDate());
|
||||
}
|
||||
}
|
@ -27,8 +27,7 @@ describe("Properties", () => {
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["cp:coreProperties"]);
|
||||
expect(tree["cp:coreProperties"]).to.be.an.instanceof(Array);
|
||||
expect(Object.keys(tree["cp:coreProperties"][0])).to.deep.equal(["_attr"]);
|
||||
expect(tree["cp:coreProperties"][1]).to.deep.equal({ "dc:title": ["test document"] });
|
||||
expect(tree["cp:coreProperties"]).to.deep.include({ "dc:title": ["test document"] });
|
||||
});
|
||||
|
||||
it("should create properties with all the attributes given", () => {
|
||||
@ -44,9 +43,9 @@ describe("Properties", () => {
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["cp:coreProperties"]);
|
||||
expect(tree["cp:coreProperties"]).to.be.an.instanceof(Array);
|
||||
|
||||
const key = (obj) => Object.keys(obj)[0];
|
||||
const props = tree["cp:coreProperties"].map(key).sort();
|
||||
expect(props).to.deep.equal([
|
||||
expect(tree["cp:coreProperties"].map(key)).to.include.members([
|
||||
"_attr",
|
||||
"cp:keywords",
|
||||
"cp:lastModifiedBy",
|
||||
@ -58,7 +57,7 @@ describe("Properties", () => {
|
||||
"dcterms:created",
|
||||
"dcterms:modified",
|
||||
]);
|
||||
expect(tree["cp:coreProperties"].slice(1, -2).sort((a, b) => (key(a) < key(b) ? -1 : 1))).to.deep.equal([
|
||||
expect(tree["cp:coreProperties"]).to.deep.include.members([
|
||||
{ "cp:keywords": ["test docx"] },
|
||||
{ "cp:lastModifiedBy": ["the author"] },
|
||||
{ "cp:revision": ["123"] },
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { StringContainer, XmlComponent } from "file/xml-components";
|
||||
import { ICustomPropertyOptions } from "../custom-properties";
|
||||
import { IDocumentBackgroundOptions } from "../document";
|
||||
|
||||
@ -7,7 +7,7 @@ import { ISectionOptions } from "../file";
|
||||
import { INumberingOptions } from "../numbering";
|
||||
import { Paragraph } from "../paragraph";
|
||||
import { IStylesOptions } from "../styles";
|
||||
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
|
||||
import { dateTimeValue } from "../values";
|
||||
|
||||
export interface IPropertiesOptions {
|
||||
readonly sections: ISectionOptions[];
|
||||
@ -29,12 +29,35 @@ export interface IPropertiesOptions {
|
||||
readonly background?: IDocumentBackgroundOptions;
|
||||
readonly features?: {
|
||||
readonly trackRevisions?: boolean;
|
||||
readonly updateFields?: boolean;
|
||||
};
|
||||
readonly compatabilityModeVersion?: number;
|
||||
readonly customProperties?: ICustomPropertyOptions[];
|
||||
readonly evenAndOddHeaderAndFooters?: boolean;
|
||||
}
|
||||
|
||||
// <xs:element name="coreProperties" type="CT_CoreProperties"/>
|
||||
|
||||
// <xs:complexType name="CT_CoreProperties">
|
||||
// <xs:all>
|
||||
// <xs:element name="category" minOccurs="0" maxOccurs="1" type="xs:string"/>
|
||||
// <xs:element name="contentStatus" minOccurs="0" maxOccurs="1" type="xs:string"/>
|
||||
// <xs:element ref="dcterms:created" minOccurs="0" maxOccurs="1"/>
|
||||
// <xs:element ref="dc:creator" minOccurs="0" maxOccurs="1"/>
|
||||
// <xs:element ref="dc:description" minOccurs="0" maxOccurs="1"/>
|
||||
// <xs:element ref="dc:identifier" minOccurs="0" maxOccurs="1"/>
|
||||
// <xs:element name="keywords" minOccurs="0" maxOccurs="1" type="CT_Keywords"/>
|
||||
// <xs:element ref="dc:language" minOccurs="0" maxOccurs="1"/>
|
||||
// <xs:element name="lastModifiedBy" minOccurs="0" maxOccurs="1" type="xs:string"/>
|
||||
// <xs:element name="lastPrinted" minOccurs="0" maxOccurs="1" type="xs:dateTime"/>
|
||||
// <xs:element ref="dcterms:modified" minOccurs="0" maxOccurs="1"/>
|
||||
// <xs:element name="revision" minOccurs="0" maxOccurs="1" type="xs:string"/>
|
||||
// <xs:element ref="dc:subject" minOccurs="0" maxOccurs="1"/>
|
||||
// <xs:element ref="dc:title" minOccurs="0" maxOccurs="1"/>
|
||||
// <xs:element name="version" minOccurs="0" maxOccurs="1" type="xs:string"/>
|
||||
// </xs:all>
|
||||
// </xs:complexType>
|
||||
|
||||
export class CoreProperties extends XmlComponent {
|
||||
constructor(options: Omit<IPropertiesOptions, "sections">) {
|
||||
super("cp:coreProperties");
|
||||
@ -48,27 +71,39 @@ export class CoreProperties extends XmlComponent {
|
||||
}),
|
||||
);
|
||||
if (options.title) {
|
||||
this.root.push(new Title(options.title));
|
||||
this.root.push(new StringContainer("dc:title", options.title));
|
||||
}
|
||||
if (options.subject) {
|
||||
this.root.push(new Subject(options.subject));
|
||||
this.root.push(new StringContainer("dc:subject", options.subject));
|
||||
}
|
||||
if (options.creator) {
|
||||
this.root.push(new Creator(options.creator));
|
||||
this.root.push(new StringContainer("dc:creator", options.creator));
|
||||
}
|
||||
if (options.keywords) {
|
||||
this.root.push(new Keywords(options.keywords));
|
||||
this.root.push(new StringContainer("cp:keywords", options.keywords));
|
||||
}
|
||||
if (options.description) {
|
||||
this.root.push(new Description(options.description));
|
||||
this.root.push(new StringContainer("dc:description", options.description));
|
||||
}
|
||||
if (options.lastModifiedBy) {
|
||||
this.root.push(new LastModifiedBy(options.lastModifiedBy));
|
||||
this.root.push(new StringContainer("cp:lastModifiedBy", options.lastModifiedBy));
|
||||
}
|
||||
if (options.revision) {
|
||||
this.root.push(new Revision(options.revision));
|
||||
this.root.push(new StringContainer("cp:revision", options.revision));
|
||||
}
|
||||
this.root.push(new Created());
|
||||
this.root.push(new Modified());
|
||||
this.root.push(new TimestampElement("dcterms:created"));
|
||||
this.root.push(new TimestampElement("dcterms:modified"));
|
||||
}
|
||||
}
|
||||
|
||||
class TimestampElement extends XmlComponent {
|
||||
constructor(name: string) {
|
||||
super(name);
|
||||
this.root.push(
|
||||
new DocumentAttributes({
|
||||
type: "dcterms:W3CDTF",
|
||||
}),
|
||||
);
|
||||
this.root.push(dateTimeValue(new Date()));
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { expect } from "chai";
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { Body } from "./body";
|
||||
import { sectionMarginDefaults } from "./section-properties";
|
||||
|
||||
describe("Body", () => {
|
||||
let body: Body;
|
||||
@ -32,24 +33,23 @@ describe("Body", () => {
|
||||
{
|
||||
"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:top": sectionMarginDefaults.TOP,
|
||||
"w:right": sectionMarginDefaults.RIGHT,
|
||||
"w:bottom": sectionMarginDefaults.BOTTOM,
|
||||
"w:left": sectionMarginDefaults.LEFT,
|
||||
"w:header": sectionMarginDefaults.HEADER,
|
||||
"w:footer": sectionMarginDefaults.FOOTER,
|
||||
"w:gutter": sectionMarginDefaults.GUTTER,
|
||||
},
|
||||
},
|
||||
},
|
||||
{ "w:cols": { _attr: { "w:space": 708, "w:sep": false, "w:num": 1 } } },
|
||||
{ "w:docGrid": { _attr: { "w:linePitch": 360 } } },
|
||||
{
|
||||
"w:pgNumType": {
|
||||
_attr: {},
|
||||
},
|
||||
},
|
||||
// { "w:cols": { _attr: { "w:space": 708, "w:sep": false, "w:num": 1 } } },
|
||||
{ "w:docGrid": { _attr: { "w:linePitch": 360 } } },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { IContext, IXmlableObject, XmlComponent } from "file/xml-components";
|
||||
|
||||
import { Paragraph, ParagraphProperties, TableOfContents } from "../..";
|
||||
import { Paragraph, ParagraphProperties } from "../..";
|
||||
import { ISectionPropertiesOptions, SectionProperties } from "./section-properties/section-properties";
|
||||
|
||||
export class Body extends XmlComponent {
|
||||
@ -38,10 +38,6 @@ export class Body extends XmlComponent {
|
||||
this.root.push(component);
|
||||
}
|
||||
|
||||
public getTablesOfContents(): TableOfContents[] {
|
||||
return this.root.filter((child) => child instanceof TableOfContents) as TableOfContents[];
|
||||
}
|
||||
|
||||
private createSectionParagraph(section: SectionProperties): Paragraph {
|
||||
const paragraph = new Paragraph({});
|
||||
const properties = new ParagraphProperties({});
|
||||
|
@ -1,13 +0,0 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export class ColumnsAttributes extends XmlAttributeComponent<{
|
||||
readonly space?: number;
|
||||
readonly num?: number;
|
||||
readonly separate?: boolean;
|
||||
}> {
|
||||
protected readonly xmlKeys = {
|
||||
space: "w:space",
|
||||
num: "w:num",
|
||||
separate: "w:sep",
|
||||
};
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { ColumnsAttributes } from "./columns-attributes";
|
||||
|
||||
export class Columns extends XmlComponent {
|
||||
constructor(space: number, num: number, separate: boolean) {
|
||||
super("w:cols");
|
||||
this.root.push(
|
||||
new ColumnsAttributes({
|
||||
space: space,
|
||||
num: num,
|
||||
separate: separate,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IDocGridAttributesProperties {
|
||||
readonly linePitch?: number;
|
||||
}
|
||||
|
||||
export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
|
||||
protected readonly xmlKeys = {
|
||||
linePitch: "w:linePitch",
|
||||
};
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { DocGridAttributes } from "./doc-grid-attributes";
|
||||
|
||||
export class DocumentGrid extends XmlComponent {
|
||||
constructor(linePitch: number) {
|
||||
super("w:docGrid");
|
||||
this.root.push(
|
||||
new DocGridAttributes({
|
||||
linePitch: linePitch,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export enum FooterReferenceType {
|
||||
DEFAULT = "default",
|
||||
FIRST = "first",
|
||||
EVEN = "even",
|
||||
}
|
||||
|
||||
export class FooterReferenceAttributes extends XmlAttributeComponent<{
|
||||
readonly type: string;
|
||||
readonly id: string;
|
||||
}> {
|
||||
protected readonly xmlKeys = {
|
||||
type: "w:type",
|
||||
id: "r:id",
|
||||
};
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { FooterReference } from "./footer-reference";
|
||||
import { FooterReferenceType } from "./footer-reference-attributes";
|
||||
|
||||
describe("footerReference", () => {
|
||||
it("should create", () => {
|
||||
const footer = new FooterReference({
|
||||
footerType: FooterReferenceType.DEFAULT,
|
||||
footerId: 1,
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(footer);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:footerReference": {
|
||||
_attr: {
|
||||
"r:id": "rId1",
|
||||
"w:type": "default",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should create without a footer type", () => {
|
||||
const footer = new FooterReference({
|
||||
footerId: 1,
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(footer);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:footerReference": {
|
||||
_attr: {
|
||||
"r:id": "rId1",
|
||||
"w:type": "default",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
@ -1,20 +0,0 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { FooterReferenceAttributes, FooterReferenceType } from "./footer-reference-attributes";
|
||||
|
||||
export interface IFooterOptions {
|
||||
readonly footerType?: FooterReferenceType;
|
||||
readonly footerId?: number;
|
||||
}
|
||||
|
||||
export class FooterReference extends XmlComponent {
|
||||
constructor(options: IFooterOptions) {
|
||||
super("w:footerReference");
|
||||
|
||||
this.root.push(
|
||||
new FooterReferenceAttributes({
|
||||
type: options.footerType || FooterReferenceType.DEFAULT,
|
||||
id: `rId${options.footerId}`,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export * from "./footer-reference";
|
||||
export * from "./footer-reference-attributes";
|
@ -1,17 +0,0 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export enum HeaderReferenceType {
|
||||
DEFAULT = "default",
|
||||
FIRST = "first",
|
||||
EVEN = "even",
|
||||
}
|
||||
|
||||
export class HeaderReferenceAttributes extends XmlAttributeComponent<{
|
||||
readonly type: string;
|
||||
readonly id: string;
|
||||
}> {
|
||||
protected readonly xmlKeys = {
|
||||
type: "w:type",
|
||||
id: "r:id",
|
||||
};
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { HeaderReference } from "./header-reference";
|
||||
import { HeaderReferenceType } from "./header-reference-attributes";
|
||||
|
||||
describe("HeaderReference", () => {
|
||||
it("should create", () => {
|
||||
const footer = new HeaderReference({
|
||||
headerType: HeaderReferenceType.DEFAULT,
|
||||
headerId: 1,
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(footer);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:headerReference": {
|
||||
_attr: {
|
||||
"r:id": "rId1",
|
||||
"w:type": "default",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should create without a header type", () => {
|
||||
const footer = new HeaderReference({
|
||||
headerId: 1,
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(footer);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:headerReference": {
|
||||
_attr: {
|
||||
"r:id": "rId1",
|
||||
"w:type": "default",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
@ -1,19 +0,0 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { HeaderReferenceAttributes, HeaderReferenceType } from "./header-reference-attributes";
|
||||
|
||||
export interface IHeaderReferenceOptions {
|
||||
readonly headerType?: HeaderReferenceType;
|
||||
readonly headerId?: number;
|
||||
}
|
||||
|
||||
export class HeaderReference extends XmlComponent {
|
||||
constructor(options: IHeaderReferenceOptions) {
|
||||
super("w:headerReference");
|
||||
this.root.push(
|
||||
new HeaderReferenceAttributes({
|
||||
type: options.headerType || HeaderReferenceType.DEFAULT,
|
||||
id: `rId${options.headerId}`,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export * from "./header-reference";
|
||||
export * from "./header-reference-attributes";
|
@ -1,9 +1,2 @@
|
||||
export * from "./section-properties";
|
||||
export * from "./footer-reference";
|
||||
export * from "./header-reference";
|
||||
export * from "./page-size";
|
||||
export * from "./page-number";
|
||||
export * from "./page-border";
|
||||
export * from "./line-number";
|
||||
export * from "./vertical-align";
|
||||
export * from "./type";
|
||||
export * from "./properties";
|
||||
|
@ -1 +0,0 @@
|
||||
export * from "./line-number";
|
@ -1,38 +0,0 @@
|
||||
// http://officeopenxml.com/WPsectionLineNumbering.php
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
export enum LineNumberRestartFormat {
|
||||
CONTINUOUS = "continuous",
|
||||
NEW_SECTION = "newSection",
|
||||
NEW_PAGE = "newPage",
|
||||
}
|
||||
|
||||
export interface ILineNumberAttributes {
|
||||
readonly countBy?: number;
|
||||
readonly start?: number;
|
||||
readonly restart?: LineNumberRestartFormat;
|
||||
readonly distance?: number;
|
||||
}
|
||||
|
||||
export class LineNumberAttributes extends XmlAttributeComponent<ILineNumberAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
countBy: "w:countBy",
|
||||
start: "w:start",
|
||||
restart: "w:restart",
|
||||
distance: "w:distance",
|
||||
};
|
||||
}
|
||||
|
||||
export class LineNumberType extends XmlComponent {
|
||||
constructor(countBy?: number, start?: number, restart?: LineNumberRestartFormat, dist?: number) {
|
||||
super("w:lnNumType");
|
||||
this.root.push(
|
||||
new LineNumberAttributes({
|
||||
countBy: countBy,
|
||||
start: start,
|
||||
restart: restart,
|
||||
distance: dist,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from "./page-borders";
|
@ -1,100 +0,0 @@
|
||||
// http://officeopenxml.com/WPsectionBorders.php
|
||||
import { BorderStyle } from "file/styles";
|
||||
import { IgnoreIfEmptyXmlComponent, XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
export enum PageBorderDisplay {
|
||||
ALL_PAGES = "allPages",
|
||||
FIRST_PAGE = "firstPage",
|
||||
NOT_FIRST_PAGE = "notFirstPage",
|
||||
}
|
||||
|
||||
export enum PageBorderOffsetFrom {
|
||||
PAGE = "page",
|
||||
TEXT = "text",
|
||||
}
|
||||
|
||||
export enum PageBorderZOrder {
|
||||
BACK = "back",
|
||||
FRONT = "front",
|
||||
}
|
||||
|
||||
export interface IPageBorderAttributes {
|
||||
readonly display?: PageBorderDisplay;
|
||||
readonly offsetFrom?: PageBorderOffsetFrom;
|
||||
readonly zOrder?: PageBorderZOrder;
|
||||
}
|
||||
|
||||
export interface IPageBorderConfiguration {
|
||||
readonly style?: BorderStyle;
|
||||
readonly size?: number;
|
||||
readonly color?: string;
|
||||
readonly space?: number;
|
||||
}
|
||||
|
||||
export interface IPageBordersOptions {
|
||||
readonly pageBorders?: IPageBorderAttributes;
|
||||
readonly pageBorderTop?: IPageBorderConfiguration;
|
||||
readonly pageBorderRight?: IPageBorderConfiguration;
|
||||
readonly pageBorderBottom?: IPageBorderConfiguration;
|
||||
readonly pageBorderLeft?: IPageBorderConfiguration;
|
||||
}
|
||||
|
||||
class PageBordeAttributes extends XmlAttributeComponent<IPageBorderConfiguration> {
|
||||
protected readonly xmlKeys = {
|
||||
style: "w:val",
|
||||
size: "w:size",
|
||||
color: "w:color",
|
||||
space: "w:space",
|
||||
};
|
||||
}
|
||||
|
||||
class PageBorder extends XmlComponent {
|
||||
constructor(key: string, options: IPageBorderConfiguration) {
|
||||
super(key);
|
||||
|
||||
this.root.push(new PageBordeAttributes(options));
|
||||
}
|
||||
}
|
||||
|
||||
class PageBordersAttributes extends XmlAttributeComponent<IPageBorderAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
display: "w:display",
|
||||
offsetFrom: "w:offsetFrom",
|
||||
zOrder: "w:zOrder",
|
||||
};
|
||||
}
|
||||
|
||||
export class PageBorders extends IgnoreIfEmptyXmlComponent {
|
||||
constructor(options?: IPageBordersOptions) {
|
||||
super("w:pgBorders");
|
||||
|
||||
if (!options) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.pageBorders) {
|
||||
this.root.push(
|
||||
new PageBordersAttributes({
|
||||
display: options.pageBorders.display,
|
||||
offsetFrom: options.pageBorders.offsetFrom,
|
||||
zOrder: options.pageBorders.zOrder,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
this.root.push(new PageBordersAttributes({}));
|
||||
}
|
||||
|
||||
if (options.pageBorderTop) {
|
||||
this.root.push(new PageBorder("w:top", options.pageBorderTop));
|
||||
}
|
||||
if (options.pageBorderRight) {
|
||||
this.root.push(new PageBorder("w:right", options.pageBorderRight));
|
||||
}
|
||||
if (options.pageBorderBottom) {
|
||||
this.root.push(new PageBorder("w:bottom", options.pageBorderBottom));
|
||||
}
|
||||
if (options.pageBorderLeft) {
|
||||
this.root.push(new PageBorder("w:left", options.pageBorderLeft));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IPageMarginAttributes {
|
||||
readonly top?: number;
|
||||
readonly right?: number;
|
||||
readonly bottom?: number;
|
||||
readonly left?: number;
|
||||
readonly header?: number;
|
||||
readonly footer?: number;
|
||||
readonly gutter?: number;
|
||||
readonly mirror?: boolean;
|
||||
}
|
||||
|
||||
export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
top: "w:top",
|
||||
right: "w:right",
|
||||
bottom: "w:bottom",
|
||||
left: "w:left",
|
||||
header: "w:header",
|
||||
footer: "w:footer",
|
||||
gutter: "w:gutter",
|
||||
mirror: "w:mirrorMargins",
|
||||
};
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { PageMarginAttributes } from "./page-margin-attributes";
|
||||
|
||||
export class PageMargin extends XmlComponent {
|
||||
constructor(top: number, right: number, bottom: number, left: number, header: number, footer: number, gutter: number, mirror: boolean) {
|
||||
super("w:pgMar");
|
||||
this.root.push(
|
||||
new PageMarginAttributes({
|
||||
top: top,
|
||||
right: right,
|
||||
bottom: bottom,
|
||||
left: left,
|
||||
header: header,
|
||||
footer: footer,
|
||||
gutter: gutter,
|
||||
mirror: mirror,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from "./page-number";
|
@ -1,53 +0,0 @@
|
||||
// http://officeopenxml.com/WPSectionPgNumType.php
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
export enum PageNumberFormat {
|
||||
CARDINAL_TEXT = "cardinalText",
|
||||
DECIMAL = "decimal",
|
||||
DECIMAL_ENCLOSED_CIRCLE = "decimalEnclosedCircle",
|
||||
DECIMAL_ENCLOSED_FULL_STOP = "decimalEnclosedFullstop",
|
||||
DECIMAL_ENCLOSED_PAREN = "decimalEnclosedParen",
|
||||
DECIMAL_ZERO = "decimalZero",
|
||||
LOWER_LETTER = "lowerLetter",
|
||||
LOWER_ROMAN = "lowerRoman",
|
||||
NONE = "none",
|
||||
ORDINAL_TEXT = "ordinalText",
|
||||
UPPER_LETTER = "upperLetter",
|
||||
UPPER_ROMAN = "upperRoman",
|
||||
DECIMAL_FULL_WIDTH = "decimalFullWidth",
|
||||
}
|
||||
|
||||
export enum PageNumberSeparator {
|
||||
COLON = "colon",
|
||||
EM_DASH = "emDash",
|
||||
EN_DASH = "endash",
|
||||
HYPHEN = "hyphen",
|
||||
PERIOD = "period",
|
||||
}
|
||||
|
||||
export interface IPageNumberTypeAttributes {
|
||||
readonly start?: number;
|
||||
readonly formatType?: PageNumberFormat;
|
||||
readonly separator?: PageNumberSeparator;
|
||||
}
|
||||
|
||||
export class PageNumberTypeAttributes extends XmlAttributeComponent<IPageNumberTypeAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
start: "w:start",
|
||||
formatType: "w:fmt",
|
||||
separator: "w:chapSep",
|
||||
};
|
||||
}
|
||||
|
||||
export class PageNumberType extends XmlComponent {
|
||||
constructor(start?: number, numberFormat?: PageNumberFormat, separator?: PageNumberSeparator) {
|
||||
super("w:pgNumType");
|
||||
this.root.push(
|
||||
new PageNumberTypeAttributes({
|
||||
start: start,
|
||||
formatType: numberFormat,
|
||||
separator: separator,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export * from "./page-size";
|
||||
export * from "./page-size-attributes";
|
@ -1,20 +0,0 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export enum PageOrientation {
|
||||
PORTRAIT = "portrait",
|
||||
LANDSCAPE = "landscape",
|
||||
}
|
||||
|
||||
export interface IPageSizeAttributes {
|
||||
readonly width?: number;
|
||||
readonly height?: number;
|
||||
readonly orientation?: PageOrientation;
|
||||
}
|
||||
|
||||
export class PageSizeAttributes extends XmlAttributeComponent<IPageSizeAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
width: "w:w",
|
||||
height: "w:h",
|
||||
orientation: "w:orient",
|
||||
};
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { PageOrientation, PageSizeAttributes } from "./page-size-attributes";
|
||||
|
||||
export class PageSize extends XmlComponent {
|
||||
constructor(width: number, height: number, orientation: PageOrientation) {
|
||||
super("w:pgSz");
|
||||
|
||||
const flip = orientation === PageOrientation.LANDSCAPE;
|
||||
|
||||
this.root.push(
|
||||
new PageSizeAttributes({
|
||||
width: flip ? height : width,
|
||||
height: flip ? width : height,
|
||||
orientation: orientation,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import { twipsMeasureValue } from "file/values";
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
export interface IColumnAttributes {
|
||||
readonly width: number | string;
|
||||
readonly space?: number | string;
|
||||
}
|
||||
|
||||
export class ColumnAttributes extends XmlAttributeComponent<IColumnAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
width: "w:w",
|
||||
space: "w:space",
|
||||
};
|
||||
}
|
||||
|
||||
export class Column extends XmlComponent {
|
||||
constructor({ width, space }: IColumnAttributes) {
|
||||
super("w:col");
|
||||
this.root.push(
|
||||
new ColumnAttributes({
|
||||
width: twipsMeasureValue(width),
|
||||
space: space === undefined ? undefined : twipsMeasureValue(space),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { Column, Columns } from ".";
|
||||
|
||||
describe("Columns", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create columns of equal width if equalWidth is true", () => {
|
||||
const columns = new Columns({ count: 3, space: 720 });
|
||||
const tree = new Formatter().format(columns);
|
||||
|
||||
expect(tree["w:cols"]).to.deep.equal({ _attr: { "w:num": 3, "w:space": 720 } });
|
||||
});
|
||||
|
||||
it("should ignore individual column attributes if equalWidth is true", () => {
|
||||
const unequalColumns = [new Column({ width: 1000, space: 400 }), new Column({ width: 2000 })];
|
||||
const columns = new Columns({ count: 3, space: 720, equalWidth: true, children: unequalColumns });
|
||||
const tree = new Formatter().format(columns);
|
||||
|
||||
expect(tree).to.deep.equal({ "w:cols": { _attr: { "w:num": 3, "w:space": 720, "w:equalWidth": true } } });
|
||||
});
|
||||
|
||||
it("should have column children if equalWidth is false and individual columns are provided", () => {
|
||||
const unequalColumns = [new Column({ width: 1000, space: 400 }), new Column({ width: 2000 })];
|
||||
const columns = new Columns({ count: 3, space: 720, equalWidth: false, children: unequalColumns });
|
||||
const tree = new Formatter().format(columns);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:cols": [
|
||||
{ _attr: { "w:num": 3, "w:space": 720, "w:equalWidth": false } },
|
||||
{ "w:col": { _attr: { "w:space": 400, "w:w": 1000 } } },
|
||||
{ "w:col": { _attr: { "w:w": 2000 } } },
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,47 @@
|
||||
import { decimalNumber, twipsMeasureValue } from "file/values";
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
import { Column } from "./column";
|
||||
|
||||
// <xsd:complexType name="CT_Columns">
|
||||
// <xsd:sequence minOccurs="0">
|
||||
// <xsd:element name="col" type="CT_Column" maxOccurs="45"/>
|
||||
// </xsd:sequence>
|
||||
// <xsd:attribute name="equalWidth" type="s:ST_OnOff" use="optional"/>
|
||||
// <xsd:attribute name="space" type="s:ST_TwipsMeasure" use="optional" default="720"/>
|
||||
// <xsd:attribute name="num" type="ST_DecimalNumber" use="optional" default="1"/>
|
||||
// <xsd:attribute name="sep" type="s:ST_OnOff" use="optional"/>
|
||||
// </xsd:complexType>
|
||||
export interface IColumnsAttributes {
|
||||
readonly space?: number | string;
|
||||
readonly count?: number;
|
||||
readonly separate?: boolean;
|
||||
readonly equalWidth?: boolean;
|
||||
readonly children?: Column[];
|
||||
}
|
||||
|
||||
export class ColumnsAttributes extends XmlAttributeComponent<IColumnsAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
space: "w:space",
|
||||
count: "w:num",
|
||||
separate: "w:sep",
|
||||
equalWidth: "w:equalWidth",
|
||||
};
|
||||
}
|
||||
|
||||
export class Columns extends XmlComponent {
|
||||
constructor({ space, count, separate, equalWidth, children }: IColumnsAttributes) {
|
||||
super("w:cols");
|
||||
this.root.push(
|
||||
new ColumnsAttributes({
|
||||
space: space === undefined ? undefined : twipsMeasureValue(space),
|
||||
count: count === undefined ? undefined : decimalNumber(count),
|
||||
separate,
|
||||
equalWidth,
|
||||
}),
|
||||
);
|
||||
|
||||
if (!equalWidth && children) {
|
||||
children.forEach((column) => this.addChildElement(column));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
import { decimalNumber } from "file/values";
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
// not implemented
|
||||
// <xsd:simpleType name="ST_DocGrid">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="default"/>
|
||||
// <xsd:enumeration value="lines"/>
|
||||
// <xsd:enumeration value="linesAndChars"/>
|
||||
// <xsd:enumeration value="snapToChars"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
|
||||
// <xsd:complexType name="CT_DocGrid">
|
||||
// <xsd:attribute name="type" type="ST_DocGrid"/>
|
||||
// <xsd:attribute name="linePitch" type="ST_DecimalNumber"/>
|
||||
// <xsd:attribute name="charSpace" type="ST_DecimalNumber"/>
|
||||
// </xsd:complexType>
|
||||
export interface IDocGridAttributesProperties {
|
||||
readonly linePitch?: number;
|
||||
}
|
||||
|
||||
export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
|
||||
protected readonly xmlKeys = {
|
||||
linePitch: "w:linePitch",
|
||||
};
|
||||
}
|
||||
|
||||
export class DocumentGrid extends XmlComponent {
|
||||
constructor(linePitch: number) {
|
||||
super("w:docGrid");
|
||||
this.root.push(
|
||||
new DocGridAttributes({
|
||||
linePitch: decimalNumber(linePitch),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./header-footer-reference";
|
||||
|
||||
describe("HeaderFooterReference", () => {
|
||||
it("#constructor (footer)", () => {
|
||||
const footer = new HeaderFooterReference(HeaderFooterType.FOOTER, {
|
||||
type: HeaderFooterReferenceType.DEFAULT,
|
||||
id: 1,
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(footer);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:footerReference": {
|
||||
_attr: {
|
||||
"r:id": "rId1",
|
||||
"w:type": "default",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("#constructor (header)", () => {
|
||||
const header = new HeaderFooterReference(HeaderFooterType.HEADER, {
|
||||
type: HeaderFooterReferenceType.DEFAULT,
|
||||
id: 1,
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(header);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:headerReference": {
|
||||
_attr: {
|
||||
"r:id": "rId1",
|
||||
"w:type": "default",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should create without a type", () => {
|
||||
const footer = new HeaderFooterReference(HeaderFooterType.FOOTER, {
|
||||
id: 1,
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(footer);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:footerReference": {
|
||||
_attr: {
|
||||
"r:id": "rId1",
|
||||
"w:type": "default",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,65 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
// <xsd:simpleType name="ST_HdrFtr">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="even"/>
|
||||
// <xsd:enumeration value="default"/>
|
||||
// <xsd:enumeration value="first"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export enum HeaderFooterReferenceType {
|
||||
DEFAULT = "default",
|
||||
FIRST = "first",
|
||||
EVEN = "even",
|
||||
}
|
||||
|
||||
// </xsd:complexType>
|
||||
// <xsd:group name="EG_HdrFtrReferences">
|
||||
// <xsd:choice>
|
||||
// <xsd:element name="headerReference" type="CT_HdrFtrRef" minOccurs="0"/>
|
||||
// <xsd:element name="footerReference" type="CT_HdrFtrRef" minOccurs="0"/>
|
||||
// </xsd:choice>
|
||||
// </xsd:group>
|
||||
|
||||
// <xsd:complexType name="CT_HdrFtrRef">
|
||||
// <xsd:complexContent>
|
||||
// <xsd:extension base="CT_Rel">
|
||||
// <xsd:attribute name="type" type="ST_HdrFtr" use="required"/>
|
||||
// </xsd:extension>
|
||||
// </xsd:complexContent>
|
||||
|
||||
// <xsd:complexType name="CT_Rel">
|
||||
// <xsd:attribute ref="r:id" use="required"/>
|
||||
// </xsd:complexType>
|
||||
|
||||
export interface IHeaderFooterOptions {
|
||||
readonly type?: HeaderFooterReferenceType;
|
||||
readonly id?: number;
|
||||
}
|
||||
|
||||
class FooterReferenceAttributes extends XmlAttributeComponent<{
|
||||
readonly type: HeaderFooterReferenceType;
|
||||
readonly id: string;
|
||||
}> {
|
||||
protected readonly xmlKeys = {
|
||||
type: "w:type",
|
||||
id: "r:id",
|
||||
};
|
||||
}
|
||||
|
||||
export enum HeaderFooterType {
|
||||
HEADER = "w:headerReference",
|
||||
FOOTER = "w:footerReference",
|
||||
}
|
||||
export class HeaderFooterReference extends XmlComponent {
|
||||
constructor(type: HeaderFooterType, options: IHeaderFooterOptions) {
|
||||
super(type);
|
||||
|
||||
this.root.push(
|
||||
new FooterReferenceAttributes({
|
||||
type: options.type || HeaderFooterReferenceType.DEFAULT,
|
||||
id: `rId${options.id}`,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
export * from "./column";
|
||||
export * from "./columns";
|
||||
export * from "./doc-grid";
|
||||
// export * from "./header-reference";
|
||||
export * from "./page-size";
|
||||
export * from "./page-number";
|
||||
export * from "./page-borders";
|
||||
export * from "./page-margin";
|
||||
export * from "./page-borders";
|
||||
export * from "./line-number";
|
||||
export * from "./section-type";
|
||||
export * from "./header-footer-reference";
|
@ -0,0 +1,53 @@
|
||||
// http://officeopenxml.com/WPsectionLineNumbering.php
|
||||
import { decimalNumber, twipsMeasureValue } from "file/values";
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
// <xsd:simpleType name="ST_LineNumberRestart">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="newPage"/>
|
||||
// <xsd:enumeration value="newSection"/>
|
||||
// <xsd:enumeration value="continuous"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export enum LineNumberRestartFormat {
|
||||
NEW_PAGE = "newPage",
|
||||
NEW_SECTION = "newSection",
|
||||
CONTINUOUS = "continuous",
|
||||
}
|
||||
|
||||
// <xsd:complexType name="CT_LineNumber">
|
||||
// <xsd:attribute name="countBy" type="ST_DecimalNumber" use="optional"/>
|
||||
// <xsd:attribute name="start" type="ST_DecimalNumber" use="optional" default="1"/>
|
||||
// <xsd:attribute name="distance" type="s:ST_TwipsMeasure" use="optional"/>
|
||||
// <xsd:attribute name="restart" type="ST_LineNumberRestart" use="optional" default="newPage"/>
|
||||
// </xsd:complexType>
|
||||
|
||||
export interface ILineNumberAttributes {
|
||||
readonly countBy?: number;
|
||||
readonly start?: number;
|
||||
readonly restart?: LineNumberRestartFormat;
|
||||
readonly distance?: number | string;
|
||||
}
|
||||
|
||||
export class LineNumberAttributes extends XmlAttributeComponent<ILineNumberAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
countBy: "w:countBy",
|
||||
start: "w:start",
|
||||
restart: "w:restart",
|
||||
distance: "w:distance",
|
||||
};
|
||||
}
|
||||
|
||||
export class LineNumberType extends XmlComponent {
|
||||
constructor({ countBy, start, restart, distance }: ILineNumberAttributes) {
|
||||
super("w:lnNumType");
|
||||
this.root.push(
|
||||
new LineNumberAttributes({
|
||||
countBy: countBy === undefined ? undefined : decimalNumber(countBy),
|
||||
start: start === undefined ? undefined : decimalNumber(start),
|
||||
restart,
|
||||
distance: distance === undefined ? undefined : twipsMeasureValue(distance),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { BorderStyle } from "file/styles";
|
||||
import { BorderStyle } from "file/border";
|
||||
|
||||
import { PageBorderDisplay, PageBorders, PageBorderZOrder } from "./page-borders";
|
||||
|
||||
@ -70,22 +70,22 @@ describe("PageBorders", () => {
|
||||
expect(tree["w:pgBorders"][0]).to.deep.equal({ _attr: { "w:display": "firstPage", "w:zOrder": "back" } });
|
||||
expect(tree["w:pgBorders"][1]).to.deep.equal({
|
||||
"w:top": {
|
||||
_attr: { "w:color": "001122", "w:size": 10, "w:val": "doubleWave" },
|
||||
_attr: { "w:color": "001122", "w:sz": 10, "w:val": "doubleWave" },
|
||||
},
|
||||
});
|
||||
expect(tree["w:pgBorders"][2]).to.deep.equal({
|
||||
"w:right": {
|
||||
_attr: { "w:color": "223344", "w:size": 20, "w:val": "double" },
|
||||
"w:left": {
|
||||
_attr: { "w:color": "889900", "w:sz": 40, "w:val": "dotted" },
|
||||
},
|
||||
});
|
||||
expect(tree["w:pgBorders"][3]).to.deep.equal({
|
||||
"w:bottom": {
|
||||
_attr: { "w:color": "556677", "w:size": 30, "w:val": "single" },
|
||||
_attr: { "w:color": "556677", "w:sz": 30, "w:val": "single" },
|
||||
},
|
||||
});
|
||||
expect(tree["w:pgBorders"][4]).to.deep.equal({
|
||||
"w:left": {
|
||||
_attr: { "w:color": "889900", "w:size": 40, "w:val": "dotted" },
|
||||
"w:right": {
|
||||
_attr: { "w:color": "223344", "w:sz": 20, "w:val": "double" },
|
||||
},
|
||||
});
|
||||
});
|
@ -0,0 +1,106 @@
|
||||
// http://officeopenxml.com/WPsectionBorders.php
|
||||
import { BorderElement, IBorderOptions } from "file/border";
|
||||
import { IgnoreIfEmptyXmlComponent, XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
// <xsd:simpleType name="ST_PageBorderDisplay">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="allPages"/>
|
||||
// <xsd:enumeration value="firstPage"/>
|
||||
// <xsd:enumeration value="notFirstPage"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export enum PageBorderDisplay {
|
||||
ALL_PAGES = "allPages",
|
||||
FIRST_PAGE = "firstPage",
|
||||
NOT_FIRST_PAGE = "notFirstPage",
|
||||
}
|
||||
|
||||
// <xsd:simpleType name="ST_PageBorderOffset">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="page"/>
|
||||
// <xsd:enumeration value="text"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export enum PageBorderOffsetFrom {
|
||||
PAGE = "page",
|
||||
TEXT = "text",
|
||||
}
|
||||
|
||||
// <xsd:simpleType name="ST_PageBorderZOrder">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="front"/>
|
||||
// <xsd:enumeration value="back"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export enum PageBorderZOrder {
|
||||
BACK = "back",
|
||||
FRONT = "front",
|
||||
}
|
||||
|
||||
export interface IPageBorderAttributes {
|
||||
readonly display?: PageBorderDisplay;
|
||||
readonly offsetFrom?: PageBorderOffsetFrom;
|
||||
readonly zOrder?: PageBorderZOrder;
|
||||
}
|
||||
|
||||
export interface IPageBordersOptions {
|
||||
readonly pageBorders?: IPageBorderAttributes;
|
||||
readonly pageBorderTop?: IBorderOptions;
|
||||
readonly pageBorderRight?: IBorderOptions;
|
||||
readonly pageBorderBottom?: IBorderOptions;
|
||||
readonly pageBorderLeft?: IBorderOptions;
|
||||
}
|
||||
|
||||
class PageBordersAttributes extends XmlAttributeComponent<IPageBorderAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
display: "w:display",
|
||||
offsetFrom: "w:offsetFrom",
|
||||
zOrder: "w:zOrder",
|
||||
};
|
||||
}
|
||||
|
||||
// <xsd:complexType name="CT_PageBorders">
|
||||
// <xsd:sequence>
|
||||
// <xsd:element name="top" type="CT_TopPageBorder" minOccurs="0"/>
|
||||
// <xsd:element name="left" type="CT_PageBorder" minOccurs="0"/>
|
||||
// <xsd:element name="bottom" type="CT_BottomPageBorder" minOccurs="0"/>
|
||||
// <xsd:element name="right" type="CT_PageBorder" minOccurs="0"/>
|
||||
// </xsd:sequence>
|
||||
// <xsd:attribute name="zOrder" type="ST_PageBorderZOrder" use="optional" default="front"/>
|
||||
// <xsd:attribute name="display" type="ST_PageBorderDisplay" use="optional"/>
|
||||
// <xsd:attribute name="offsetFrom" type="ST_PageBorderOffset" use="optional" default="text"/>
|
||||
// </xsd:complexType>
|
||||
export class PageBorders extends IgnoreIfEmptyXmlComponent {
|
||||
constructor(options?: IPageBordersOptions) {
|
||||
super("w:pgBorders");
|
||||
|
||||
if (!options) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.pageBorders) {
|
||||
this.root.push(
|
||||
new PageBordersAttributes({
|
||||
display: options.pageBorders.display,
|
||||
offsetFrom: options.pageBorders.offsetFrom,
|
||||
zOrder: options.pageBorders.zOrder,
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
this.root.push(new PageBordersAttributes({}));
|
||||
}
|
||||
|
||||
if (options.pageBorderTop) {
|
||||
this.root.push(new BorderElement("w:top", options.pageBorderTop));
|
||||
}
|
||||
if (options.pageBorderLeft) {
|
||||
this.root.push(new BorderElement("w:left", options.pageBorderLeft));
|
||||
}
|
||||
if (options.pageBorderBottom) {
|
||||
this.root.push(new BorderElement("w:bottom", options.pageBorderBottom));
|
||||
}
|
||||
if (options.pageBorderRight) {
|
||||
this.root.push(new BorderElement("w:right", options.pageBorderRight));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
import { signedTwipsMeasureValue, twipsMeasureValue } from "file/values";
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
// <xsd:complexType name="CT_PageMar">
|
||||
// <xsd:attribute name="top" type="ST_SignedTwipsMeasure" use="required"/>
|
||||
// <xsd:attribute name="right" type="s:ST_TwipsMeasure" use="required"/>
|
||||
// <xsd:attribute name="bottom" type="ST_SignedTwipsMeasure" use="required"/>
|
||||
// <xsd:attribute name="left" type="s:ST_TwipsMeasure" use="required"/>
|
||||
// <xsd:attribute name="header" type="s:ST_TwipsMeasure" use="required"/>
|
||||
// <xsd:attribute name="footer" type="s:ST_TwipsMeasure" use="required"/>
|
||||
// <xsd:attribute name="gutter" type="s:ST_TwipsMeasure" use="required"/>
|
||||
// </xsd:complexType>
|
||||
export interface IPageMarginAttributes {
|
||||
readonly top?: number | string;
|
||||
readonly right?: number | string;
|
||||
readonly bottom?: number | string;
|
||||
readonly left?: number | string;
|
||||
readonly header?: number | string;
|
||||
readonly footer?: number | string;
|
||||
readonly gutter?: number | string;
|
||||
}
|
||||
|
||||
export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
top: "w:top",
|
||||
right: "w:right",
|
||||
bottom: "w:bottom",
|
||||
left: "w:left",
|
||||
header: "w:header",
|
||||
footer: "w:footer",
|
||||
gutter: "w:gutter",
|
||||
};
|
||||
}
|
||||
|
||||
export class PageMargin extends XmlComponent {
|
||||
constructor(
|
||||
top: number | string,
|
||||
right: number | string,
|
||||
bottom: number | string,
|
||||
left: number | string,
|
||||
header: number | string,
|
||||
footer: number | string,
|
||||
gutter: number | string,
|
||||
) {
|
||||
super("w:pgMar");
|
||||
this.root.push(
|
||||
new PageMarginAttributes({
|
||||
top: signedTwipsMeasureValue(top),
|
||||
right: twipsMeasureValue(right),
|
||||
bottom: signedTwipsMeasureValue(bottom),
|
||||
left: twipsMeasureValue(left),
|
||||
header: twipsMeasureValue(header),
|
||||
footer: twipsMeasureValue(footer),
|
||||
gutter: twipsMeasureValue(gutter),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
// http://officeopenxml.com/WPSectionPgNumType.php
|
||||
import { NumberFormat } from "file/shared/number-format";
|
||||
import { decimalNumber } from "file/values";
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
// <xsd:simpleType name="ST_ChapterSep">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="hyphen"/>
|
||||
// <xsd:enumeration value="period"/>
|
||||
// <xsd:enumeration value="colon"/>
|
||||
// <xsd:enumeration value="emDash"/>
|
||||
// <xsd:enumeration value="enDash"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export enum PageNumberSeparator {
|
||||
HYPHEN = "hyphen",
|
||||
PERIOD = "period",
|
||||
COLON = "colon",
|
||||
EM_DASH = "emDash",
|
||||
EN_DASH = "endash",
|
||||
}
|
||||
|
||||
export interface IPageNumberTypeAttributes {
|
||||
readonly start?: number;
|
||||
readonly formatType?: NumberFormat;
|
||||
readonly separator?: PageNumberSeparator;
|
||||
}
|
||||
|
||||
// <xsd:complexType name="CT_PageNumber">
|
||||
// <xsd:attribute name="fmt" type="ST_NumberFormat" use="optional" default="decimal"/>
|
||||
// <xsd:attribute name="start" type="ST_DecimalNumber" use="optional"/>
|
||||
// <xsd:attribute name="chapStyle" type="ST_DecimalNumber" use="optional"/>
|
||||
// <xsd:attribute name="chapSep" type="ST_ChapterSep" use="optional" default="hyphen"/>
|
||||
// </xsd:complexType>
|
||||
|
||||
export class PageNumberTypeAttributes extends XmlAttributeComponent<IPageNumberTypeAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
start: "w:start",
|
||||
formatType: "w:fmt",
|
||||
separator: "w:chapSep",
|
||||
};
|
||||
}
|
||||
export class PageNumberType extends XmlComponent {
|
||||
constructor({ start, formatType, separator }: IPageNumberTypeAttributes) {
|
||||
super("w:pgNumType");
|
||||
this.root.push(
|
||||
new PageNumberTypeAttributes({
|
||||
start: start === undefined ? undefined : decimalNumber(start),
|
||||
formatType,
|
||||
separator,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -2,8 +2,7 @@ import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { PageSize } from "./page-size";
|
||||
import { PageOrientation } from "./page-size-attributes";
|
||||
import { PageOrientation, PageSize } from "./page-size";
|
||||
|
||||
describe("PageSize", () => {
|
||||
describe("#constructor()", () => {
|
@ -0,0 +1,52 @@
|
||||
import { twipsMeasureValue } from "file/values";
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
// <xsd:simpleType name="ST_PageOrientation">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="portrait"/>
|
||||
// <xsd:enumeration value="landscape"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export enum PageOrientation {
|
||||
PORTRAIT = "portrait",
|
||||
LANDSCAPE = "landscape",
|
||||
}
|
||||
|
||||
// <xsd:complexType name="CT_PageSz">
|
||||
// <xsd:attribute name="w" type="s:ST_TwipsMeasure"/>
|
||||
// <xsd:attribute name="h" type="s:ST_TwipsMeasure"/>
|
||||
// <xsd:attribute name="orient" type="ST_PageOrientation" use="optional"/>
|
||||
// <xsd:attribute name="code" type="ST_DecimalNumber" use="optional"/>
|
||||
// </xsd:complexType>
|
||||
export interface IPageSizeAttributes {
|
||||
readonly width?: number | string;
|
||||
readonly height?: number | string;
|
||||
readonly orientation?: PageOrientation;
|
||||
}
|
||||
|
||||
export class PageSizeAttributes extends XmlAttributeComponent<IPageSizeAttributes> {
|
||||
protected readonly xmlKeys = {
|
||||
width: "w:w",
|
||||
height: "w:h",
|
||||
orientation: "w:orient",
|
||||
};
|
||||
}
|
||||
|
||||
export class PageSize extends XmlComponent {
|
||||
constructor(width: number | string, height: number | string, orientation: PageOrientation) {
|
||||
super("w:pgSz");
|
||||
|
||||
const flip = orientation === PageOrientation.LANDSCAPE;
|
||||
|
||||
const widthTwips = twipsMeasureValue(width);
|
||||
const heightTwips = twipsMeasureValue(height);
|
||||
|
||||
this.root.push(
|
||||
new PageSizeAttributes({
|
||||
width: flip ? heightTwips : widthTwips,
|
||||
height: flip ? widthTwips : heightTwips,
|
||||
orientation: orientation,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { Type } from "./section-type";
|
||||
import { SectionType } from "./section-type-attributes";
|
||||
import { SectionType, Type } from "./section-type";
|
||||
|
||||
describe("Type", () => {
|
||||
it("should create with even page section type", () => {
|
@ -0,0 +1,37 @@
|
||||
// http://officeopenxml.com/WPsection.php
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
// <xsd:simpleType name="ST_SectionMark">
|
||||
// <xsd:restriction base="xsd:string">
|
||||
// <xsd:enumeration value="nextPage"/>
|
||||
// <xsd:enumeration value="nextColumn"/>
|
||||
// <xsd:enumeration value="continuous"/>
|
||||
// <xsd:enumeration value="evenPage"/>
|
||||
// <xsd:enumeration value="oddPage"/>
|
||||
// </xsd:restriction>
|
||||
// </xsd:simpleType>
|
||||
export enum SectionType {
|
||||
NEXT_PAGE = "nextPage",
|
||||
NEXT_COLUMN = "nextColumn",
|
||||
CONTINUOUS = "continuous",
|
||||
EVEN_PAGE = "evenPage",
|
||||
ODD_PAGE = "oddPage",
|
||||
}
|
||||
|
||||
// <xsd:complexType name="CT_SectType">
|
||||
// <xsd:attribute name="val" type="ST_SectionMark"/>
|
||||
// </xsd:complexType>
|
||||
export class SectionTypeAttributes extends XmlAttributeComponent<{
|
||||
readonly val: SectionType;
|
||||
}> {
|
||||
protected readonly xmlKeys = {
|
||||
val: "w:val",
|
||||
};
|
||||
}
|
||||
|
||||
export class Type extends XmlComponent {
|
||||
constructor(value: SectionType) {
|
||||
super("w:type");
|
||||
this.root.push(new SectionTypeAttributes({ val: value }));
|
||||
}
|
||||
}
|
@ -5,13 +5,30 @@ import { Formatter } from "export/formatter";
|
||||
import { FooterWrapper } from "file/footer-wrapper";
|
||||
import { HeaderWrapper } from "file/header-wrapper";
|
||||
import { Media } from "file/media";
|
||||
import { LineNumberRestartFormat } from "./line-number";
|
||||
import { NumberFormat } from "file/shared/number-format";
|
||||
import { VerticalAlign } from "file/vertical-align";
|
||||
|
||||
import { PageBorderOffsetFrom } from "./page-border";
|
||||
import { PageNumberFormat } from "./page-number";
|
||||
import { SectionProperties } from "./section-properties";
|
||||
import { SectionType } from "./type/section-type-attributes";
|
||||
import { SectionVerticalAlignValue } from "./vertical-align";
|
||||
import { PageOrientation } from "./properties";
|
||||
import { LineNumberRestartFormat } from "./properties/line-number";
|
||||
import { PageBorderOffsetFrom } from "./properties/page-borders";
|
||||
import { SectionType } from "./properties/section-type";
|
||||
import { sectionMarginDefaults, sectionPageSizeDefaults, SectionProperties } from "./section-properties";
|
||||
|
||||
const DEFAULT_MARGINS = {
|
||||
"w:bottom": sectionMarginDefaults.BOTTOM,
|
||||
"w:footer": sectionMarginDefaults.FOOTER,
|
||||
"w:top": sectionMarginDefaults.TOP,
|
||||
"w:right": sectionMarginDefaults.RIGHT,
|
||||
"w:left": sectionMarginDefaults.LEFT,
|
||||
"w:header": sectionMarginDefaults.HEADER,
|
||||
"w:gutter": sectionMarginDefaults.GUTTER,
|
||||
};
|
||||
|
||||
const PAGE_SIZE_DEFAULTS = {
|
||||
"w:h": sectionPageSizeDefaults.HEIGHT,
|
||||
"w:orient": sectionPageSizeDefaults.ORIENTATION,
|
||||
"w:w": sectionPageSizeDefaults.WIDTH,
|
||||
};
|
||||
|
||||
describe("SectionProperties", () => {
|
||||
describe("#constructor()", () => {
|
||||
@ -21,27 +38,27 @@ describe("SectionProperties", () => {
|
||||
const properties = new SectionProperties({
|
||||
page: {
|
||||
size: {
|
||||
width: 11906,
|
||||
height: 16838,
|
||||
width: 1190,
|
||||
height: 1680,
|
||||
orientation: PageOrientation.PORTRAIT,
|
||||
},
|
||||
margin: {
|
||||
top: convertInchesToTwip(1),
|
||||
right: convertInchesToTwip(1),
|
||||
bottom: convertInchesToTwip(1),
|
||||
left: convertInchesToTwip(1),
|
||||
header: 708,
|
||||
footer: 708,
|
||||
gutter: 0,
|
||||
mirror: false,
|
||||
top: "2in",
|
||||
right: "2in",
|
||||
bottom: "2in",
|
||||
left: "2in",
|
||||
header: 808,
|
||||
footer: 808,
|
||||
gutter: 10,
|
||||
},
|
||||
pageNumbers: {
|
||||
start: 10,
|
||||
formatType: PageNumberFormat.CARDINAL_TEXT,
|
||||
formatType: NumberFormat.CARDINAL_TEXT,
|
||||
},
|
||||
},
|
||||
column: {
|
||||
space: 708,
|
||||
count: 1,
|
||||
space: 208,
|
||||
count: 2,
|
||||
separate: true,
|
||||
},
|
||||
grid: {
|
||||
@ -54,34 +71,35 @@ describe("SectionProperties", () => {
|
||||
even: new FooterWrapper(media, 200),
|
||||
},
|
||||
titlePage: true,
|
||||
verticalAlign: SectionVerticalAlignValue.TOP,
|
||||
verticalAlign: VerticalAlign.TOP,
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(properties);
|
||||
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } } });
|
||||
expect(tree["w:sectPr"][1]).to.deep.equal({
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:headerReference": { _attr: { "r:id": "rId100", "w:type": "default" } } });
|
||||
expect(tree["w:sectPr"][1]).to.deep.equal({ "w:footerReference": { _attr: { "r:id": "rId200", "w:type": "even" } } });
|
||||
expect(tree["w:sectPr"][2]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 1680, "w:w": 1190, "w:orient": "portrait" } } });
|
||||
expect(tree["w:sectPr"][3]).to.deep.equal({
|
||||
"w:pgMar": {
|
||||
_attr: {
|
||||
"w:bottom": 1440,
|
||||
"w:footer": 708,
|
||||
"w:top": 1440,
|
||||
"w:right": 1440,
|
||||
"w:left": 1440,
|
||||
"w:header": 708,
|
||||
"w:gutter": 0,
|
||||
"w:mirrorMargins": false,
|
||||
"w:bottom": "2in",
|
||||
"w:footer": 808,
|
||||
"w:top": "2in",
|
||||
"w:right": "2in",
|
||||
"w:left": "2in",
|
||||
"w:header": 808,
|
||||
"w:gutter": 10,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:sep": true, "w:num": 1 } } });
|
||||
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": "rId100", "w:type": "default" } } });
|
||||
expect(tree["w:sectPr"][5]).to.deep.equal({ "w:footerReference": { _attr: { "r:id": "rId200", "w:type": "even" } } });
|
||||
expect(tree["w:sectPr"][6]).to.deep.equal({ "w:pgNumType": { _attr: { "w:fmt": "cardinalText", "w:start": 10 } } });
|
||||
expect(tree["w:sectPr"][4]).to.deep.equal({ "w:pgNumType": { _attr: { "w:fmt": "cardinalText", "w:start": 10 } } });
|
||||
expect(tree["w:sectPr"][5]).to.deep.equal({ "w:cols": { _attr: { "w:space": 208, "w:sep": true, "w:num": 2 } } });
|
||||
expect(tree["w:sectPr"][6]).to.deep.equal({ "w:vAlign": { _attr: { "w:val": "top" } } });
|
||||
expect(tree["w:sectPr"][7]).to.deep.equal({ "w:titlePg": {} });
|
||||
expect(tree["w:sectPr"][8]).to.deep.equal({ "w:docGrid": { _attr: { "w:linePitch": 360 } } });
|
||||
});
|
||||
|
||||
it("should create section properties with no options", () => {
|
||||
@ -89,22 +107,11 @@ describe("SectionProperties", () => {
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } } });
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: PAGE_SIZE_DEFAULTS } });
|
||||
expect(tree["w:sectPr"][1]).to.deep.equal({
|
||||
"w:pgMar": {
|
||||
_attr: {
|
||||
"w:bottom": 1440,
|
||||
"w:footer": 708,
|
||||
"w:top": 1440,
|
||||
"w:right": 1440,
|
||||
"w:left": 1440,
|
||||
"w:header": 708,
|
||||
"w:gutter": 0,
|
||||
"w:mirrorMargins": false,
|
||||
},
|
||||
},
|
||||
"w:pgMar": { _attr: DEFAULT_MARGINS },
|
||||
});
|
||||
expect(tree["w:sectPr"][2]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:sep": false, "w:num": 1 } } });
|
||||
// expect(tree["w:sectPr"][3]).to.deep.equal({ "w:cols": { _attr: { "w:space": 708, "w:sep": false, "w:num": 1 } } });
|
||||
expect(tree["w:sectPr"][3]).to.deep.equal({ "w:docGrid": { _attr: { "w:linePitch": 360 } } });
|
||||
});
|
||||
|
||||
@ -119,18 +126,12 @@ describe("SectionProperties", () => {
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } } });
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: PAGE_SIZE_DEFAULTS } });
|
||||
expect(tree["w:sectPr"][1]).to.deep.equal({
|
||||
"w:pgMar": {
|
||||
_attr: {
|
||||
"w:bottom": 1440,
|
||||
"w:footer": 708,
|
||||
...DEFAULT_MARGINS,
|
||||
"w:top": 0,
|
||||
"w:right": 1440,
|
||||
"w:left": 1440,
|
||||
"w:header": 708,
|
||||
"w:gutter": 0,
|
||||
"w:mirrorMargins": false,
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -147,18 +148,12 @@ describe("SectionProperties", () => {
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } } });
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: PAGE_SIZE_DEFAULTS } });
|
||||
expect(tree["w:sectPr"][1]).to.deep.equal({
|
||||
"w:pgMar": {
|
||||
_attr: {
|
||||
...DEFAULT_MARGINS,
|
||||
"w:bottom": 0,
|
||||
"w:footer": 708,
|
||||
"w:top": 1440,
|
||||
"w:right": 1440,
|
||||
"w:left": 1440,
|
||||
"w:header": 708,
|
||||
"w:gutter": 0,
|
||||
"w:mirrorMargins": false,
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -170,25 +165,25 @@ describe("SectionProperties", () => {
|
||||
size: {
|
||||
width: 0,
|
||||
height: 0,
|
||||
orientation: PageOrientation.LANDSCAPE,
|
||||
},
|
||||
},
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 0, "w:w": 0, "w:orient": "portrait" } } });
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({
|
||||
"w:pgSz": {
|
||||
_attr: {
|
||||
"w:h": 0,
|
||||
"w:orient": PageOrientation.LANDSCAPE,
|
||||
"w:w": 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(tree["w:sectPr"][1]).to.deep.equal({
|
||||
"w:pgMar": {
|
||||
_attr: {
|
||||
"w:bottom": 1440,
|
||||
"w:footer": 708,
|
||||
"w:top": 1440,
|
||||
"w:right": 1440,
|
||||
"w:left": 1440,
|
||||
"w:header": 708,
|
||||
"w:gutter": 0,
|
||||
"w:mirrorMargins": false,
|
||||
},
|
||||
_attr: DEFAULT_MARGINS,
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -215,7 +210,7 @@ describe("SectionProperties", () => {
|
||||
const properties = new SectionProperties({
|
||||
page: {
|
||||
pageNumbers: {
|
||||
formatType: PageNumberFormat.UPPER_ROMAN,
|
||||
formatType: NumberFormat.UPPER_ROMAN,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -1,29 +1,21 @@
|
||||
// http://officeopenxml.com/WPsection.php
|
||||
// tslint:disable: no-unnecessary-initializer
|
||||
|
||||
import { convertInchesToTwip } from "convenience-functions";
|
||||
import { FooterWrapper } from "file/footer-wrapper";
|
||||
import { HeaderWrapper } from "file/header-wrapper";
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { VerticalAlign, VerticalAlignElement } from "file/vertical-align";
|
||||
import { OnOffElement, XmlComponent } from "file/xml-components";
|
||||
|
||||
import { Columns } from "./columns/columns";
|
||||
import { DocumentGrid } from "./doc-grid/doc-grid";
|
||||
import { IDocGridAttributesProperties } from "./doc-grid/doc-grid-attributes";
|
||||
import { FooterReferenceType } from "./footer-reference";
|
||||
import { FooterReference } from "./footer-reference/footer-reference";
|
||||
import { HeaderReferenceType } from "./header-reference";
|
||||
import { HeaderReference } from "./header-reference/header-reference";
|
||||
import { ILineNumberAttributes, LineNumberType } from "./line-number";
|
||||
import { IPageBordersOptions, PageBorders } from "./page-border";
|
||||
import { PageMargin } from "./page-margin/page-margin";
|
||||
import { IPageMarginAttributes } from "./page-margin/page-margin-attributes";
|
||||
import { IPageNumberTypeAttributes, PageNumberType } from "./page-number";
|
||||
import { PageSize } from "./page-size/page-size";
|
||||
import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes";
|
||||
import { TitlePage } from "./title-page/title-page";
|
||||
import { Type } from "./type/section-type";
|
||||
import { SectionType } from "./type/section-type-attributes";
|
||||
import { SectionVerticalAlign, SectionVerticalAlignValue } from "./vertical-align";
|
||||
import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./properties/header-footer-reference";
|
||||
|
||||
import { Columns, IColumnsAttributes } from "./properties/columns";
|
||||
import { DocumentGrid, IDocGridAttributesProperties } from "./properties/doc-grid";
|
||||
import { ILineNumberAttributes, LineNumberType } from "./properties/line-number";
|
||||
import { IPageBordersOptions, PageBorders } from "./properties/page-borders";
|
||||
import { IPageMarginAttributes, PageMargin } from "./properties/page-margin";
|
||||
import { IPageNumberTypeAttributes, PageNumberType } from "./properties/page-number";
|
||||
import { IPageSizeAttributes, PageOrientation, PageSize } from "./properties/page-size";
|
||||
import { SectionType, Type } from "./properties/section-type";
|
||||
|
||||
export interface IHeaderFooterGroup<T> {
|
||||
readonly default?: T;
|
||||
@ -43,144 +35,153 @@ export interface ISectionPropertiesOptions {
|
||||
readonly footerWrapperGroup?: IHeaderFooterGroup<FooterWrapper>;
|
||||
readonly lineNumbers?: ILineNumberAttributes;
|
||||
readonly titlePage?: boolean;
|
||||
readonly verticalAlign?: SectionVerticalAlignValue;
|
||||
readonly column?: {
|
||||
readonly space?: number;
|
||||
readonly count?: number;
|
||||
readonly separate?: boolean;
|
||||
};
|
||||
readonly verticalAlign?: VerticalAlign;
|
||||
readonly column?: IColumnsAttributes;
|
||||
readonly type?: SectionType;
|
||||
}
|
||||
|
||||
// <xsd:complexType name="CT_SectPr">
|
||||
// <xsd:sequence>
|
||||
// <xsd:group ref="EG_HdrFtrReferences" minOccurs="0" maxOccurs="6"/>
|
||||
// <xsd:group ref="EG_SectPrContents" minOccurs="0"/>
|
||||
// <xsd:element name="sectPrChange" type="CT_SectPrChange" minOccurs="0"/>
|
||||
// </xsd:sequence>
|
||||
// <xsd:attributeGroup ref="AG_SectPrAttributes"/>
|
||||
// </xsd:complexType>
|
||||
|
||||
// <xsd:group name="EG_SectPrContents">
|
||||
// <xsd:sequence>
|
||||
// <xsd:element name="footnotePr" type="CT_FtnProps" minOccurs="0"/>
|
||||
// <xsd:element name="endnotePr" type="CT_EdnProps" minOccurs="0"/>
|
||||
// <xsd:element name="type" type="CT_SectType" minOccurs="0"/>
|
||||
// <xsd:element name="pgSz" type="CT_PageSz" minOccurs="0"/>
|
||||
// <xsd:element name="pgMar" type="CT_PageMar" minOccurs="0"/>
|
||||
// <xsd:element name="paperSrc" type="CT_PaperSource" minOccurs="0"/>
|
||||
// <xsd:element name="pgBorders" type="CT_PageBorders" minOccurs="0"/>
|
||||
// <xsd:element name="lnNumType" type="CT_LineNumber" minOccurs="0"/>
|
||||
// <xsd:element name="pgNumType" type="CT_PageNumber" minOccurs="0"/>
|
||||
// <xsd:element name="cols" type="CT_Columns" minOccurs="0"/>
|
||||
// <xsd:element name="formProt" type="CT_OnOff" minOccurs="0"/>
|
||||
// <xsd:element name="vAlign" type="CT_VerticalJc" minOccurs="0"/>
|
||||
// <xsd:element name="noEndnote" type="CT_OnOff" minOccurs="0"/>
|
||||
// <xsd:element name="titlePg" type="CT_OnOff" minOccurs="0"/>
|
||||
// <xsd:element name="textDirection" type="CT_TextDirection" minOccurs="0"/>
|
||||
// <xsd:element name="bidi" type="CT_OnOff" minOccurs="0"/>
|
||||
// <xsd:element name="rtlGutter" type="CT_OnOff" minOccurs="0"/>
|
||||
// <xsd:element name="docGrid" type="CT_DocGrid" minOccurs="0"/>
|
||||
// <xsd:element name="printerSettings" type="CT_Rel" minOccurs="0"/>
|
||||
// </xsd:sequence>
|
||||
// </xsd:group>
|
||||
|
||||
export const sectionMarginDefaults = {
|
||||
TOP: "1in",
|
||||
RIGHT: "1in",
|
||||
BOTTOM: "1in",
|
||||
LEFT: "1in",
|
||||
HEADER: 708,
|
||||
FOOTER: 708,
|
||||
GUTTER: 0,
|
||||
};
|
||||
|
||||
export const sectionPageSizeDefaults = {
|
||||
WIDTH: 11906,
|
||||
HEIGHT: 16838,
|
||||
ORIENTATION: PageOrientation.PORTRAIT,
|
||||
};
|
||||
|
||||
export class SectionProperties extends XmlComponent {
|
||||
constructor({
|
||||
page: {
|
||||
size: { width = 11906, height = 16838, orientation = PageOrientation.PORTRAIT } = {},
|
||||
size: {
|
||||
width = sectionPageSizeDefaults.WIDTH,
|
||||
height = sectionPageSizeDefaults.HEIGHT,
|
||||
orientation = sectionPageSizeDefaults.ORIENTATION,
|
||||
} = {},
|
||||
margin: {
|
||||
top = convertInchesToTwip(1),
|
||||
right = convertInchesToTwip(1),
|
||||
bottom = convertInchesToTwip(1),
|
||||
left = convertInchesToTwip(1),
|
||||
header = 708,
|
||||
footer = 708,
|
||||
gutter = 0,
|
||||
mirror = false,
|
||||
} = {},
|
||||
pageNumbers: {
|
||||
start: pageNumberStart = undefined,
|
||||
formatType: pageNumberFormatType = undefined,
|
||||
separator: pageNumberSeparator = undefined,
|
||||
} = {},
|
||||
borders: {
|
||||
pageBorders = undefined,
|
||||
pageBorderTop = undefined,
|
||||
pageBorderRight = undefined,
|
||||
pageBorderBottom = undefined,
|
||||
pageBorderLeft = undefined,
|
||||
top = sectionMarginDefaults.TOP,
|
||||
right = sectionMarginDefaults.RIGHT,
|
||||
bottom = sectionMarginDefaults.BOTTOM,
|
||||
left = sectionMarginDefaults.LEFT,
|
||||
header = sectionMarginDefaults.HEADER,
|
||||
footer = sectionMarginDefaults.FOOTER,
|
||||
gutter = sectionMarginDefaults.GUTTER,
|
||||
} = {},
|
||||
pageNumbers = {},
|
||||
borders,
|
||||
} = {},
|
||||
grid: { linePitch = 360 } = {},
|
||||
headerWrapperGroup = {},
|
||||
footerWrapperGroup = {},
|
||||
lineNumbers: { countBy: lineNumberCountBy, start: lineNumberStart, restart: lineNumberRestart, distance: lineNumberDistance } = {},
|
||||
titlePage = false,
|
||||
lineNumbers,
|
||||
titlePage,
|
||||
verticalAlign,
|
||||
column: { space = 708, count = 1, separate = false } = {},
|
||||
column,
|
||||
type,
|
||||
}: ISectionPropertiesOptions = {}) {
|
||||
super("w:sectPr");
|
||||
|
||||
this.root.push(new PageSize(width, height, orientation));
|
||||
this.root.push(new PageMargin(top, right, bottom, left, header, footer, gutter, mirror));
|
||||
this.root.push(new Columns(space, count, separate));
|
||||
this.root.push(new DocumentGrid(linePitch));
|
||||
|
||||
this.addHeaders(headerWrapperGroup);
|
||||
this.addFooters(footerWrapperGroup);
|
||||
|
||||
this.root.push(new PageNumberType(pageNumberStart, pageNumberFormatType, pageNumberSeparator));
|
||||
|
||||
if (lineNumberCountBy || lineNumberStart || lineNumberRestart || lineNumberDistance) {
|
||||
this.root.push(new LineNumberType(lineNumberCountBy, lineNumberStart, lineNumberRestart, lineNumberDistance));
|
||||
}
|
||||
|
||||
if (pageBorders || pageBorderTop || pageBorderRight || pageBorderBottom || pageBorderLeft) {
|
||||
this.root.push(
|
||||
new PageBorders({
|
||||
pageBorders: pageBorders,
|
||||
pageBorderTop: pageBorderTop,
|
||||
pageBorderRight: pageBorderRight,
|
||||
pageBorderBottom: pageBorderBottom,
|
||||
pageBorderLeft: pageBorderLeft,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (titlePage) {
|
||||
this.root.push(new TitlePage());
|
||||
}
|
||||
|
||||
if (verticalAlign) {
|
||||
this.root.push(new SectionVerticalAlign(verticalAlign));
|
||||
}
|
||||
this.addHeaderFooterGroup(HeaderFooterType.HEADER, headerWrapperGroup);
|
||||
this.addHeaderFooterGroup(HeaderFooterType.FOOTER, footerWrapperGroup);
|
||||
|
||||
if (type) {
|
||||
this.root.push(new Type(type));
|
||||
}
|
||||
|
||||
this.root.push(new PageSize(width, height, orientation));
|
||||
this.root.push(new PageMargin(top, right, bottom, left, header, footer, gutter));
|
||||
|
||||
if (borders) {
|
||||
this.root.push(new PageBorders(borders));
|
||||
}
|
||||
|
||||
private addHeaders(headers: IHeaderFooterGroup<HeaderWrapper>): void {
|
||||
if (headers.default) {
|
||||
if (lineNumbers) {
|
||||
this.root.push(new LineNumberType(lineNumbers));
|
||||
}
|
||||
|
||||
this.root.push(new PageNumberType(pageNumbers));
|
||||
|
||||
if (column) {
|
||||
this.root.push(new Columns(column));
|
||||
}
|
||||
|
||||
if (verticalAlign) {
|
||||
this.root.push(new VerticalAlignElement(verticalAlign));
|
||||
}
|
||||
|
||||
if (titlePage !== undefined) {
|
||||
this.root.push(new OnOffElement("w:titlePg", titlePage));
|
||||
}
|
||||
|
||||
this.root.push(new DocumentGrid(linePitch));
|
||||
}
|
||||
|
||||
private addHeaderFooterGroup(
|
||||
type: HeaderFooterType,
|
||||
group: IHeaderFooterGroup<HeaderWrapper> | IHeaderFooterGroup<FooterWrapper>,
|
||||
): void {
|
||||
if (group.default) {
|
||||
this.root.push(
|
||||
new HeaderReference({
|
||||
headerType: HeaderReferenceType.DEFAULT,
|
||||
headerId: headers.default.View.ReferenceId,
|
||||
new HeaderFooterReference(type, {
|
||||
type: HeaderFooterReferenceType.DEFAULT,
|
||||
id: group.default.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (headers.first) {
|
||||
if (group.first) {
|
||||
this.root.push(
|
||||
new HeaderReference({
|
||||
headerType: HeaderReferenceType.FIRST,
|
||||
headerId: headers.first.View.ReferenceId,
|
||||
new HeaderFooterReference(type, {
|
||||
type: HeaderFooterReferenceType.FIRST,
|
||||
id: group.first.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (headers.even) {
|
||||
if (group.even) {
|
||||
this.root.push(
|
||||
new HeaderReference({
|
||||
headerType: HeaderReferenceType.EVEN,
|
||||
headerId: headers.even.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private addFooters(footers: IHeaderFooterGroup<FooterWrapper>): void {
|
||||
if (footers.default) {
|
||||
this.root.push(
|
||||
new FooterReference({
|
||||
footerType: FooterReferenceType.DEFAULT,
|
||||
footerId: footers.default.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (footers.first) {
|
||||
this.root.push(
|
||||
new FooterReference({
|
||||
footerType: FooterReferenceType.FIRST,
|
||||
footerId: footers.first.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (footers.even) {
|
||||
this.root.push(
|
||||
new FooterReference({
|
||||
footerType: FooterReferenceType.EVEN,
|
||||
footerId: footers.even.View.ReferenceId,
|
||||
new HeaderFooterReference(type, {
|
||||
type: HeaderFooterReferenceType.EVEN,
|
||||
id: group.even.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export class TitlePageAttributes extends XmlAttributeComponent<{
|
||||
readonly value: string;
|
||||
}> {
|
||||
protected readonly xmlKeys = {
|
||||
value: "w:val",
|
||||
};
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user