Compare commits
83 Commits
Author | SHA1 | Date | |
---|---|---|---|
26a3fa6946 | |||
ee1a7818b6 | |||
8e455f1097 | |||
827c46cf47 | |||
61cbee829d | |||
f0ad1e9194 | |||
bbd339f0e4 | |||
858af64dc3 | |||
01e34c1b28 | |||
41acb475a9 | |||
20978f8c24 | |||
265a3dbe21 | |||
627f5b4bf0 | |||
1538c1aaeb | |||
839661e5f8 | |||
fff6244597 | |||
b2280f64a1 | |||
21d53c41d0 | |||
6e94bbb5e5 | |||
7d655cd3f7 | |||
00821677c8 | |||
784de3e430 | |||
3213c4838d | |||
1b9bc8eb1d | |||
bf58d0b864 | |||
28ca8392ed | |||
5238c55bc2 | |||
901f10c387 | |||
defa22ffe5 | |||
84919c0cc0 | |||
1e8ca123b0 | |||
3ae7c6aedf | |||
6a3ed4bbf8 | |||
e632d323c9 | |||
d2b35ab8f2 | |||
e60f39df41 | |||
076431e04d | |||
75ab44403c | |||
e2d6097819 | |||
ab12ff1257 | |||
25a0212f4e | |||
a8993f14d6 | |||
1834cd86da | |||
437de27ed8 | |||
96f08482da | |||
edec2eca7a | |||
9202524d83 | |||
0461907533 | |||
445a2896d2 | |||
e2d8f1b6b1 | |||
7baa696a76 | |||
3f7ca6bbff | |||
36e1c5fe6a | |||
75a03f1576 | |||
437e83ab78 | |||
b8232f7a02 | |||
49eadb0efc | |||
40dc90e585 | |||
0de302d192 | |||
80bab95f6c | |||
ba3d551c9f | |||
d14fe31f97 | |||
057f41e355 | |||
8c9b61b37a | |||
11e54b3e2c | |||
fa7cb0bef1 | |||
3977c8ab3b | |||
e8f92efe05 | |||
994df8531b | |||
3cdf96ee0c | |||
e2f55d52e9 | |||
d6fa33035a | |||
f11bca728f | |||
596761d78d | |||
8a3c8d4664 | |||
fdfce79e87 | |||
88340aa336 | |||
d0f53fdd4b | |||
d657f61e11 | |||
3ea106bd22 | |||
538264dec5 | |||
6bcd1c2c24 | |||
120c3a7bbe |
11
.nycrc
11
.nycrc
@ -1,14 +1,15 @@
|
|||||||
{
|
{
|
||||||
"check-coverage": true,
|
"check-coverage": true,
|
||||||
"lines": 93.53,
|
"lines": 96.81,
|
||||||
"functions": 89.63,
|
"functions": 93.80,
|
||||||
"branches": 88.57,
|
"branches": 92.63,
|
||||||
"statements": 93.34,
|
"statements": 96.80,
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*.ts"
|
"src/**/*.ts"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"src/**/*.spec.ts"
|
"src/**/*.spec.ts",
|
||||||
|
"src/import-dotx/import-dotx.ts"
|
||||||
],
|
],
|
||||||
"reporter": [
|
"reporter": [
|
||||||
"lcov",
|
"lcov",
|
||||||
|
11
README.md
11
README.md
@ -34,6 +34,15 @@ Here is an example of `docx` working in `Angular`:
|
|||||||
|
|
||||||
* https://stackblitz.com/edit/angular-afvxtz
|
* https://stackblitz.com/edit/angular-afvxtz
|
||||||
|
|
||||||
|
Here is an example of `docx` working in `React`:
|
||||||
|
|
||||||
|
* https://stackblitz.com/edit/react-ts-qq25sp
|
||||||
|
* https://stackblitz.com/edit/react-ts-qdqu7z (adding images to Word Document)
|
||||||
|
|
||||||
|
Here is an example of `docx` working in `Vue.js`:
|
||||||
|
|
||||||
|
* https://stackblitz.com/edit/vuejs-docx
|
||||||
|
|
||||||
## Node
|
## Node
|
||||||
|
|
||||||
Press `endpoint` on the `RunKit` website:
|
Press `endpoint` on the `RunKit` website:
|
||||||
@ -50,7 +59,7 @@ Press `endpoint` on the `RunKit` website:
|
|||||||
* https://runkit.com/dolanmiu/docx-demo8 - Header and Footer
|
* https://runkit.com/dolanmiu/docx-demo8 - Header and Footer
|
||||||
* https://runkit.com/dolanmiu/docx-demo10 - **My CV generated with docx**
|
* https://runkit.com/dolanmiu/docx-demo10 - **My CV generated with docx**
|
||||||
|
|
||||||
More [here](https://docx.js.org/#/examples) and [here](https://github.com/dolanmiu/docx/tree/master/demo)
|
More [here](https://github.com/dolanmiu/docx/tree/master/demo)
|
||||||
|
|
||||||
# How to use & Documentation
|
# How to use & Documentation
|
||||||
|
|
||||||
|
@ -161,6 +161,10 @@ doc.addSection({
|
|||||||
text: "and then underlined ",
|
text: "and then underlined ",
|
||||||
underline: {},
|
underline: {},
|
||||||
}),
|
}),
|
||||||
|
new TextRun({
|
||||||
|
text: "and then emphasis-mark ",
|
||||||
|
emphasisMark: {},
|
||||||
|
}),
|
||||||
new TextRun({
|
new TextRun({
|
||||||
text: "and back to normal.",
|
text: "and back to normal.",
|
||||||
}),
|
}),
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// Also includes an example on how to center tables
|
// Also includes an example on how to center tables
|
||||||
// Import from 'docx' rather than '../build' if you install from npm
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { AlignmentType, Document, HeadingLevel, Packer, Paragraph, ShadingType, Table, TableCell, TableRow, WidthType } from "../build";
|
import { AlignmentType, BorderStyle, Document, HeadingLevel, Packer, Paragraph, ShadingType, Table, TableCell, TableRow, WidthType } from "../build";
|
||||||
|
|
||||||
const doc = new Document();
|
const doc = new Document();
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ const table5 = new Table({
|
|||||||
new TableRow({
|
new TableRow({
|
||||||
children: [
|
children: [
|
||||||
new TableCell({
|
new TableCell({
|
||||||
children: [],
|
children: [new Paragraph("1,0")],
|
||||||
}),
|
}),
|
||||||
new TableCell({
|
new TableCell({
|
||||||
children: [new Paragraph("1,2")],
|
children: [new Paragraph("1,2")],
|
||||||
@ -195,10 +195,10 @@ const table5 = new Table({
|
|||||||
new TableRow({
|
new TableRow({
|
||||||
children: [
|
children: [
|
||||||
new TableCell({
|
new TableCell({
|
||||||
children: [],
|
children: [new Paragraph("2,0")],
|
||||||
}),
|
}),
|
||||||
new TableCell({
|
new TableCell({
|
||||||
children: [],
|
children: [new Paragraph("2,1")],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@ -209,6 +209,163 @@ const table5 = new Table({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const borders = {
|
||||||
|
top: {
|
||||||
|
style: BorderStyle.DASH_SMALL_GAP,
|
||||||
|
size: 1,
|
||||||
|
color: "red",
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
style: BorderStyle.DASH_SMALL_GAP,
|
||||||
|
size: 1,
|
||||||
|
color: "red",
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
style: BorderStyle.DASH_SMALL_GAP,
|
||||||
|
size: 1,
|
||||||
|
color: "red",
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
style: BorderStyle.DASH_SMALL_GAP,
|
||||||
|
size: 1,
|
||||||
|
color: "red",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const table6 = new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
borders,
|
||||||
|
children: [new Paragraph("0,0")],
|
||||||
|
rowSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
borders,
|
||||||
|
children: [new Paragraph("0,1")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
borders,
|
||||||
|
children: [new Paragraph("1,1")],
|
||||||
|
rowSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
borders,
|
||||||
|
children: [new Paragraph("2,0")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
width: {
|
||||||
|
size: 100,
|
||||||
|
type: WidthType.PERCENTAGE,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const table7 = new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,1")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,2")],
|
||||||
|
rowSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("0,3")],
|
||||||
|
rowSpan: 3,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("1,0")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,0")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("2,2")],
|
||||||
|
rowSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,0")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,1")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("3,3")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
width: {
|
||||||
|
size: 100,
|
||||||
|
type: WidthType.PERCENTAGE,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const table8 = new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({ children: [new Paragraph("1,1")] }),
|
||||||
|
new TableCell({ children: [new Paragraph("1,2")] }),
|
||||||
|
new TableCell({ children: [new Paragraph("1,3")] }),
|
||||||
|
new TableCell({ children: [new Paragraph("1,4")], rowSpan: 4, borders }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({ children: [new Paragraph("2,1")] }),
|
||||||
|
new TableCell({ children: [new Paragraph("2,2")] }),
|
||||||
|
new TableCell({ children: [new Paragraph("2,3")], rowSpan: 3 }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({ children: [new Paragraph("3,1")] }),
|
||||||
|
new TableCell({ children: [new Paragraph("3,2")], rowSpan: 2 }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({ children: [new Paragraph("4,1")] }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
width: {
|
||||||
|
size: 100,
|
||||||
|
type: WidthType.PERCENTAGE,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
doc.addSection({
|
doc.addSection({
|
||||||
children: [
|
children: [
|
||||||
table,
|
table,
|
||||||
@ -222,10 +379,16 @@ doc.addSection({
|
|||||||
heading: HeadingLevel.HEADING_2,
|
heading: HeadingLevel.HEADING_2,
|
||||||
}),
|
}),
|
||||||
table3,
|
table3,
|
||||||
new Paragraph("Merging columns"),
|
new Paragraph("Merging columns 1"),
|
||||||
table4,
|
table4,
|
||||||
new Paragraph("More Merging columns"),
|
new Paragraph("Merging columns 2"),
|
||||||
table5,
|
table5,
|
||||||
|
new Paragraph("Merging columns 3"),
|
||||||
|
table6,
|
||||||
|
new Paragraph("Merging columns 4"),
|
||||||
|
table7,
|
||||||
|
new Paragraph("Merging columns 5"),
|
||||||
|
table8,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
55
demo/53-chinese.ts
Normal file
55
demo/53-chinese.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Chinese text - Chinese text need to use a Chinese font. And ascii text need to use a ascii font.
|
||||||
|
// Different from the `52-japanese.ts`.
|
||||||
|
// `52-japanese.ts` will set all characters to use Japanese font.
|
||||||
|
// `53-chinese.ts` will set Chinese characters to use Chinese font, and set ascii characters to use ascii font.
|
||||||
|
|
||||||
|
// Note that if the OS have not install `KaiTi` font, this demo doesn't work.
|
||||||
|
|
||||||
|
// Import from 'docx' rather than '../build' if you install from npm
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { Document, HeadingLevel, Packer, Paragraph, TextRun } from "../build";
|
||||||
|
|
||||||
|
const doc = new Document({
|
||||||
|
styles: {
|
||||||
|
paragraphStyles: [
|
||||||
|
{
|
||||||
|
id: "Normal",
|
||||||
|
name: "Normal",
|
||||||
|
basedOn: "Normal",
|
||||||
|
next: "Normal",
|
||||||
|
quickFormat: true,
|
||||||
|
run: {
|
||||||
|
font: {
|
||||||
|
ascii: "Times",
|
||||||
|
eastAsia: "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addSection({
|
||||||
|
children: [
|
||||||
|
new Paragraph({
|
||||||
|
text: "中文和英文 Chinese and English",
|
||||||
|
heading: HeadingLevel.HEADING_1,
|
||||||
|
}),
|
||||||
|
new Paragraph({
|
||||||
|
text: "中文和英文 Chinese and English",
|
||||||
|
}),
|
||||||
|
new Paragraph({
|
||||||
|
children: [
|
||||||
|
new TextRun({
|
||||||
|
text: "中文和英文 Chinese and English",
|
||||||
|
font: { eastAsia: "SimSun" }, // set eastAsia to "SimSun".
|
||||||
|
// The ascii characters will use the default font ("Times") specified in paragraphStyles
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
Packer.toBuffer(doc).then((buffer) => {
|
||||||
|
fs.writeFileSync("My Document.docx", buffer);
|
||||||
|
});
|
@ -1,13 +1,3 @@
|
|||||||
<p align="center">
|
|
||||||
<img alt="clippy the assistant" src="https://i.imgur.com/37uBGhO.gif">
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
Easily generate .docx files with JS/TS. Works for Node and on the Browser. :100:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Welcome
|
# Welcome
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
@ -66,12 +56,6 @@ Packer.toBuffer(doc).then((buffer) => {
|
|||||||
// Done! A file called 'My First Document.docx' will be in your file system.
|
// Done! A file called 'My First Document.docx' will be in your file system.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Honoured Mentions
|
|
||||||
|
|
||||||
[@felipeochoa](https://github.com/felipeochoa)
|
|
||||||
|
|
||||||
[@h4buli](https://github.com/h4buli)
|
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img alt="clippy the assistant" src="http://i60.tinypic.com/339pvtt.png">
|
<img alt="clippy the assistant" src="http://i60.tinypic.com/339pvtt.png">
|
||||||
</p>
|
</p>
|
||||||
|
10
docs/_coverpage.md
Normal file
10
docs/_coverpage.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<img src="https://i.imgur.com/37uBGhO.gif" alt="drawing" style="width:200px;"/>
|
||||||
|
|
||||||
|
> Easily generate .docx files with JS/TS. Works for Node and on the Browser. :100:
|
||||||
|
|
||||||
|
- Simple, declarative API
|
||||||
|
- 50+ usage examples
|
||||||
|
- Battle tested, mature, 95%+ coverage
|
||||||
|
|
||||||
|
[GitHub](https://github.com/dolanmiu/docx)
|
||||||
|
[Get Started](#Welcome)
|
@ -1,6 +1,6 @@
|
|||||||
* [Getting Started](/)
|
* [Getting Started](/)
|
||||||
|
|
||||||
* [Examples](examples.md)
|
* [Examples](https://github.com/dolanmiu/docx/tree/master/demo)
|
||||||
|
|
||||||
* API
|
* API
|
||||||
|
|
||||||
|
@ -1,25 +1,23 @@
|
|||||||
# Contribution Guidelines
|
# Contribution Guidelines
|
||||||
|
|
||||||
* Include documentation reference(s) at the top of each file:
|
- Include documentation reference(s) at the top of each file:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// http://officeopenxml.com/WPdocument.php
|
// http://officeopenxml.com/WPdocument.php
|
||||||
```
|
```
|
||||||
|
|
||||||
* Follow Prettier standards, and consider using the [Prettier VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) plugin.
|
- Follow Prettier standards, and consider using the [Prettier VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) plugin.
|
||||||
|
|
||||||
* Follow the `TSLint` rules
|
- Follow the `TSLint` rules
|
||||||
|
|
||||||
## Always think about the user
|
## Always think about the user
|
||||||
|
|
||||||
The number one pillar for contribution to `docx` is to **ALWAYS** think about how the user will use `docx`.
|
|
||||||
|
|
||||||
Put yourself in their position, and imagine how they would feel about your feature you wrote.
|
Put yourself in their position, and imagine how they would feel about your feature you wrote.
|
||||||
|
|
||||||
1. Is it easy to use?
|
1. Is it easy to use?
|
||||||
2. Has it been documented well?
|
2. Has it been documented well?
|
||||||
3. Is it intuitive?
|
3. Is it intuitive?
|
||||||
4. Is it consistent with the rest of the API?
|
4. Is it declarative?
|
||||||
5. Is it fun to use?
|
5. Is it fun to use?
|
||||||
|
|
||||||
## Good Commit Names
|
## Good Commit Names
|
||||||
@ -27,6 +25,7 @@ Put yourself in their position, and imagine how they would feel about your featu
|
|||||||
Please write good commit messages when making a commit: https://chris.beams.io/posts/git-commit/
|
Please write good commit messages when making a commit: https://chris.beams.io/posts/git-commit/
|
||||||
|
|
||||||
**Do not:**
|
**Do not:**
|
||||||
|
|
||||||
```
|
```
|
||||||
c // What?
|
c // What?
|
||||||
rtl // Adding acryonyms without explaining anything else is not helpful
|
rtl // Adding acryonyms without explaining anything else is not helpful
|
||||||
@ -35,34 +34,6 @@ demo updated // Getting better, but capitalize the first letter
|
|||||||
Unesesary coment removed // Make sure to use correct spelling
|
Unesesary coment removed // Make sure to use correct spelling
|
||||||
```
|
```
|
||||||
|
|
||||||
## No leaky components in API interface
|
|
||||||
|
|
||||||
> This mainly applies to the API the end user will consume.
|
|
||||||
|
|
||||||
Try to make method parameters of the outside API accept primitives, or `json` objects, so that child components are created **inside** the component, rather than being **injected** in.
|
|
||||||
|
|
||||||
This is so that:
|
|
||||||
|
|
||||||
1. Imports are much cleaner for the end user, no need for:
|
|
||||||
```ts
|
|
||||||
import { ChildComponent } from "./my-feature/sub-component/deeper/.../my-deep.component";
|
|
||||||
```
|
|
||||||
|
|
||||||
2. This is what I consider "leakage". The code is aware of the underlying implementation of the component.
|
|
||||||
3. It means the end user does not need to import and create the child component to be injected.
|
|
||||||
|
|
||||||
**Do not**
|
|
||||||
|
|
||||||
`TableFloatProperties` is a class. The outside world would have to `new` up the object, and inject it in like so:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
public float(tableFloatProperties: TableFloatProperties): Table
|
|
||||||
```
|
|
||||||
|
|
||||||
```ts
|
|
||||||
table.float(new TableFloatProperties(...));
|
|
||||||
```
|
|
||||||
|
|
||||||
**Do**
|
**Do**
|
||||||
|
|
||||||
`ITableFloatOptions` is an interface for a JSON of primitives. The end user would need to pass in a json object and not need to worry about the internals:
|
`ITableFloatOptions` is an interface for a JSON of primitives. The end user would need to pass in a json object and not need to worry about the internals:
|
||||||
@ -71,30 +42,28 @@ This is so that:
|
|||||||
public float(tableFloatOptions: ITableFloatOptions): Table
|
public float(tableFloatOptions: ITableFloatOptions): Table
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Delcariative API
|
||||||
|
|
||||||
|
Make sure the API is declarative, so no _method calling_ or _mutation_. This is a design decision, consistent with the rest of the project. There are benefits to delcariative code over other styles of code, explained here: https://dzone.com/articles/why-declarative-coding-makes-you-a-better-programm
|
||||||
|
|
||||||
|
**Do not:**
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
table.float({...});
|
const paragraph = doc.createParagraph();
|
||||||
|
const text = paragraph.createText();
|
||||||
|
text.contents = "Hello World";
|
||||||
```
|
```
|
||||||
|
|
||||||
## Add vs Create
|
**Do**
|
||||||
|
|
||||||
This is just a guideline, and the rules can sometimes be broken.
|
|
||||||
|
|
||||||
* Use `create` if the method `new`'s up an element inside:
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
public createParagraph() {
|
doc.addSection({
|
||||||
const paragraph = new Paragraph();
|
children: [
|
||||||
this.root.push(paragraph);
|
new Paragraph({
|
||||||
}
|
children: [new TextRun("Hello World")],
|
||||||
```
|
}),
|
||||||
|
],
|
||||||
* Use `add` if you add the element into the method as a parameter.
|
});
|
||||||
*Note:* This may look like its breaking the previous guideline, but it has semantically different meanings. The previous one is using data to construct an object, whereas this one is simply adding elements into the document:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
public add(paragraph: Paragraph) {
|
|
||||||
this.root.push(paragraph);
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Getters and Setters
|
## Getters and Setters
|
||||||
@ -107,7 +76,7 @@ public get Level() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
There is no performance advantage by doing this. It means we don't need to prefix all private variables with the ugly `_`:
|
This is the convention of this project. There is no performance advantage by doing this. It means we don't need to prefix all private variables with `_`:
|
||||||
|
|
||||||
**Do not:**
|
**Do not:**
|
||||||
|
|
||||||
@ -121,30 +90,6 @@ private get _level: string;
|
|||||||
private get level: string;
|
private get level: string;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Temporal Methods
|
|
||||||
|
|
||||||
Some methods are `non-temporal`, which means regardless of when you call the method, it will have the same affect on the document. For example, setting the width of a table at the end of the document will have the same effect as setting the width at the start:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
table.setWidth(1000); // now removed as of version 5.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
Whereas some methods are `temporal`, which means depending on the time-frame they are called, it would produce a difference result. For example, moving `createParagraph()` around your code will physically alter the document.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
doc.createParagraph("hello");
|
|
||||||
```
|
|
||||||
|
|
||||||
If a method is `non-temporal`, put it in the objects `constructor`. For example:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const table = new Table(width: number);
|
|
||||||
```
|
|
||||||
|
|
||||||
`Non-temporal` methods are usually methods which can only be used one time and one time only. For example, `.float()`. It does not make sense to call `.float()` again if its already floating.
|
|
||||||
|
|
||||||
I am not sure what the real term is, but this will do.
|
|
||||||
|
|
||||||
## Interfaces over type alias
|
## Interfaces over type alias
|
||||||
|
|
||||||
Do not use `type`, but rather use `Interfaces`. `type` cannot be extended, and a class cannot implement it.
|
Do not use `type`, but rather use `Interfaces`. `type` cannot be extended, and a class cannot implement it.
|
||||||
@ -152,14 +97,14 @@ Do not use `type`, but rather use `Interfaces`. `type` cannot be extended, and a
|
|||||||
> "In general, use what you want ( type alias / interface ) just be consistent"
|
> "In general, use what you want ( type alias / interface ) just be consistent"
|
||||||
> "always use interface for public API's definition when authoring a library or 3rd party ambient type definitions"
|
> "always use interface for public API's definition when authoring a library or 3rd party ambient type definitions"
|
||||||
>
|
>
|
||||||
> * https://medium.com/@martin_hotell/interface-vs-type-alias-in-typescript-2-7-2a8f1777af4c
|
> - https://medium.com/@martin_hotell/interface-vs-type-alias-in-typescript-2-7-2a8f1777af4c
|
||||||
|
|
||||||
`Interface` is generally preferred over `type`: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types
|
`Interface` is generally preferred over `type`: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types
|
||||||
|
|
||||||
**Do not:**
|
**Do not:**
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type RelationshipFileInfo = { id: number, target: string };
|
type RelationshipFileInfo = { id: number; target: string };
|
||||||
```
|
```
|
||||||
|
|
||||||
**Do:**
|
**Do:**
|
||||||
@ -193,26 +138,26 @@ enum WeaponType = {
|
|||||||
|
|
||||||
## Spell correctly, in full and in American English
|
## Spell correctly, in full and in American English
|
||||||
|
|
||||||
I am not sure where these habits in software development come from, but I do not believe it is beneficial:
|
|
||||||
|
|
||||||
**Do not:**
|
**Do not:**
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
readdy // misspelling
|
readdy; // misspelling
|
||||||
perm // abbreviation
|
perm; // abbreviation
|
||||||
conf // abbreviation
|
conf; // abbreviation
|
||||||
cnty // abbreviation
|
cnty; // abbreviation
|
||||||
relationFile // abbreviation
|
relationFile; // abbreviation
|
||||||
colour // U.K. English
|
colour; // U.K. English
|
||||||
```
|
```
|
||||||
|
|
||||||
**Do:**
|
**Do:**
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
ready
|
ready;
|
||||||
permission
|
permission;
|
||||||
config
|
config;
|
||||||
country
|
country;
|
||||||
relationshipFile
|
relationshipFile;
|
||||||
color
|
color;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Keep files small (within reason)
|
## Keep files small (within reason)
|
||||||
|
219
docs/examples.md
219
docs/examples.md
@ -1,219 +0,0 @@
|
|||||||
# Examples
|
|
||||||
|
|
||||||
> All examples can run independently and can be found in the `/demo` folder of the project
|
|
||||||
|
|
||||||
All the examples below can be ran locally, to do so, run the following command:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run demo
|
|
||||||
```
|
|
||||||
|
|
||||||
This command will run the `demo selector app` in the `/demo` folder. It will prompt you to select a demo number, which will run a demo from that folder.
|
|
||||||
|
|
||||||
## Simple
|
|
||||||
|
|
||||||
A simple hello world of the `docx` library:
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo1.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo1.ts_
|
|
||||||
|
|
||||||
## Styles
|
|
||||||
|
|
||||||
### Styling with JS
|
|
||||||
|
|
||||||
This example shows how to customise the look and feel of a document using JS configuration
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo2.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo2.ts_
|
|
||||||
|
|
||||||
### Styling with XML
|
|
||||||
|
|
||||||
This example shows how to customise the look and feel of a document using XML configuration
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo13.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo13.ts_
|
|
||||||
|
|
||||||
## Numbering
|
|
||||||
|
|
||||||
This example shows many levels of numbering
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo3.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo3.ts_
|
|
||||||
|
|
||||||
## Table
|
|
||||||
|
|
||||||
Example of simple table
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo4.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo4.ts_
|
|
||||||
|
|
||||||
### Styling table borders
|
|
||||||
|
|
||||||
Styling the borders of a table
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo20.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo20.ts_
|
|
||||||
|
|
||||||
## Images
|
|
||||||
|
|
||||||
### Add image to the document
|
|
||||||
|
|
||||||
Importing Images from file system path
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo5.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.ts_
|
|
||||||
|
|
||||||
### Add images to header and footer
|
|
||||||
|
|
||||||
Example showing how to add image to headers and footers
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo9.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.ts_
|
|
||||||
|
|
||||||
### Scaling images
|
|
||||||
|
|
||||||
Example showing how to scale images
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo12.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo12.ts_
|
|
||||||
|
|
||||||
### Add Image to media before adding to document
|
|
||||||
|
|
||||||
This is the best way to add an image to a document because you can add the same image in two locations without increasing document size by re-using the same image
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo23.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo23.ts_
|
|
||||||
|
|
||||||
### Add image to table
|
|
||||||
|
|
||||||
As before, to add an image to a table, you would need to add it to the `Media` object first
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo24.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo24.ts_
|
|
||||||
|
|
||||||
### Images using Base64 URI
|
|
||||||
|
|
||||||
If you want to use a Base64 image instead
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo18.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo18.ts_
|
|
||||||
|
|
||||||
## Margins
|
|
||||||
|
|
||||||
Example showing how to set custom margins
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo6.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo6.ts_
|
|
||||||
|
|
||||||
## Orientation
|
|
||||||
|
|
||||||
Example showing how to set the document to `landscape` or `portrait`
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo7.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo7.ts_
|
|
||||||
|
|
||||||
## Headers & Footers
|
|
||||||
|
|
||||||
Example showing how to add headers and footers
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo8.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo8.ts_
|
|
||||||
|
|
||||||
## Multiple headers and footers
|
|
||||||
|
|
||||||
Check out `Sections` for this feature
|
|
||||||
|
|
||||||
## Page Breaks
|
|
||||||
|
|
||||||
### Normal page breaks
|
|
||||||
|
|
||||||
Example showing how to page break
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo14.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo14.ts_
|
|
||||||
|
|
||||||
### Page break before
|
|
||||||
|
|
||||||
Example showing how to page break before like in Word
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo15.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo15.ts_
|
|
||||||
|
|
||||||
## Sections
|
|
||||||
|
|
||||||
Example of how sections work. Sections allow multiple headers and footers, and `landscape`/`portrait` inside the same document.
|
|
||||||
Also you can have different page number formats and starts for different sections.
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo16.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo16.ts_
|
|
||||||
|
|
||||||
## Footnotes
|
|
||||||
|
|
||||||
Example of how to add footnotes. Good for references
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo17.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo17.ts_
|
|
||||||
|
|
||||||
## Packers
|
|
||||||
|
|
||||||
## Buffer output
|
|
||||||
|
|
||||||
Example showing how to use the Buffer packer and then write that buffer to the file system
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo19.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo19.ts_
|
|
||||||
|
|
||||||
|
|
||||||
## Bookmarks
|
|
||||||
|
|
||||||
Example showing how to make bookmarks to make internal hyperlinks within the document
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo21.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo21.ts_
|
|
||||||
|
|
||||||
## Bidirectional text
|
|
||||||
|
|
||||||
Example showing how to use bidirectional text for certain languages such as Hebrew
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo22.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo22.ts_
|
|
||||||
|
|
||||||
## Showcase
|
|
||||||
|
|
||||||
### My CV
|
|
||||||
|
|
||||||
Example showing how to add headers and footers
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo10.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo10.ts_
|
|
||||||
|
|
||||||
### Style and Images
|
|
||||||
|
|
||||||
This example shows how to customise the look and feel of a document and add images
|
|
||||||
|
|
||||||
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo11.ts ':include')
|
|
||||||
|
|
||||||
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo11.ts_
|
|
@ -1,12 +1,11 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<title>docx - Generate .docx documents with JavaScript</title>
|
<title>docx - Generate .docx documents with JavaScript</title>
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
<meta name="description" content="Generate .docx documents with JavaScript">
|
<meta name="description" content="Generate .docx documents with JavaScript" />
|
||||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="//cdn.jsdelivr.net/npm/docsify-darklight-theme@latest/dist/style.min.css"
|
href="//cdn.jsdelivr.net/npm/docsify-darklight-theme@latest/dist/style.min.css"
|
||||||
@ -19,22 +18,19 @@
|
|||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script>
|
<script>
|
||||||
window.$docsify = {
|
window.$docsify = {
|
||||||
name: 'docx',
|
name: "docx",
|
||||||
repo: 'https://github.com/dolanmiu/docx',
|
repo: "https://github.com/dolanmiu/docx",
|
||||||
loadSidebar: true,
|
loadSidebar: true,
|
||||||
subMaxLevel: 2,
|
subMaxLevel: 2,
|
||||||
search: 'auto',
|
search: "auto",
|
||||||
}
|
coverpage: true,
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||||
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
|
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
|
||||||
<script src="https://unpkg.com/docsify-copy-code@2"></script>
|
<script src="https://unpkg.com/docsify-copy-code@2"></script>
|
||||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||||
<script src="//unpkg.com/prismjs/components/prism-typescript.min.js"></script>
|
<script src="//unpkg.com/prismjs/components/prism-typescript.min.js"></script>
|
||||||
<script
|
<script src="//cdn.jsdelivr.net/npm/docsify-darklight-theme@latest/dist/index.min.js" type="text/javascript"></script>
|
||||||
src="//cdn.jsdelivr.net/npm/docsify-darklight-theme@latest/dist/index.min.js"
|
|
||||||
type="text/javascript">
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
@ -2,11 +2,7 @@
|
|||||||
|
|
||||||
> Packers are the way in which `docx` turns your code into `.docx` format. It is completely decoupled from the `docx.Document`.
|
> Packers are the way in which `docx` turns your code into `.docx` format. It is completely decoupled from the `docx.Document`.
|
||||||
|
|
||||||
Packers in `version 4` and above are now one single `Packer`. It works in both a node and browser environment (Angular etc). Now, the packer returns a `Buffer`, `Blob` or `base64 string`. It is up to you to take that and persist it with node's `fs`, send it down as a downloadable file, or anything else you wish. As of version 4, this library will not have options to export to PDF.
|
Packers works in both a node and browser environment (Angular etc). Now, the packer returns a `Buffer`, `Blob` or `base64 string`. It is up to you to take that and persist it with node's `fs`, send it down as a downloadable file, or anything else you wish. As of `version 4+`, this library will not have options to export to PDF.
|
||||||
|
|
||||||
## Version 5
|
|
||||||
|
|
||||||
Packers in `version 5` and above are now static methods on `Packer`.
|
|
||||||
|
|
||||||
### Export as Buffer
|
### Export as Buffer
|
||||||
|
|
||||||
@ -36,117 +32,3 @@ Packer.toBlob(doc).then((blob) => {
|
|||||||
saveAs(blob, "example.docx");
|
saveAs(blob, "example.docx");
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Version 4
|
|
||||||
|
|
||||||
The `Packer` in `version 4` requires an instance of `Packer`, so be sure to `new` it.
|
|
||||||
|
|
||||||
### Export as Buffer
|
|
||||||
|
|
||||||
This will return a NodeJS `Buffer`. If this is used in the browser, it will return a `UInt8Array` instead.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const packer = new docx.Packer();
|
|
||||||
|
|
||||||
packer.toBuffer(doc).then((buffer) => {
|
|
||||||
fs.writeFileSync("My Document.docx", buffer);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Export as a `base64` string
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const packer = new docx.Packer();
|
|
||||||
|
|
||||||
packer.toBase64String(doc).then((string) => {
|
|
||||||
console.log(string);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Export as Blob
|
|
||||||
|
|
||||||
This is useful if you want to send it as an downloadable in a browser environment.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const packer = new docx.Packer();
|
|
||||||
|
|
||||||
packer.toBlob(doc).then((blob) => {
|
|
||||||
// saveAs from FileSaver will download the file
|
|
||||||
saveAs(blob, "example.docx");
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Version 3 and below
|
|
||||||
|
|
||||||
### File System Packer
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const docx = require("docx");
|
|
||||||
|
|
||||||
const doc = new docx.Document();
|
|
||||||
const exporter = new docx.LocalPacker(doc);
|
|
||||||
exporter.pack("My Document");
|
|
||||||
// Word Document is in file system
|
|
||||||
```
|
|
||||||
|
|
||||||
### Buffer Packer
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const docx = require("docx");
|
|
||||||
|
|
||||||
const doc = new docx.Document();
|
|
||||||
const exporter = new docx.BufferPacker(doc);
|
|
||||||
const buffer = exporter.pack();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Stream Packer
|
|
||||||
|
|
||||||
Creates a `node` `Readable` stream
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const docx = require("docx");
|
|
||||||
|
|
||||||
const doc = new docx.Document();
|
|
||||||
const exporter = new docx.StreamPacker(doc);
|
|
||||||
const stream = exporter.pack();
|
|
||||||
```
|
|
||||||
|
|
||||||
### Express Packer
|
|
||||||
|
|
||||||
The old express packer is now deprecated and may disappear soon, so you should upgrade.
|
|
||||||
|
|
||||||
The reason for this is because it means this project needs to know about and use `express`, which for a Word document generator, does not sound right. Seperation of concerns.
|
|
||||||
|
|
||||||
It will still be usable (for now), but it is ill advised.
|
|
||||||
|
|
||||||
I used the express exporter in my [website](http://www.dolan.bio).
|
|
||||||
|
|
||||||
The recommended way is to use the `StreamPacker` and handle the `express` magic outside of the library:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const docx = require("docx");
|
|
||||||
|
|
||||||
const doc = new docx.Document();
|
|
||||||
const exporter = new docx.StreamPacker(doc);
|
|
||||||
|
|
||||||
const stream = exporter.pack();
|
|
||||||
|
|
||||||
// Express' response object
|
|
||||||
res.attachment("yourfile.xlsx");
|
|
||||||
stream.pipe(res);
|
|
||||||
```
|
|
||||||
|
|
||||||
where `res` is the response object obtained through the Express router. It is that simple. The file will begin downloading in the browser.
|
|
||||||
|
|
||||||
### PDF Exporting
|
|
||||||
|
|
||||||
You can export your word document as a PDF file like so:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const exporter = new docx.LocalPacker(doc);
|
|
||||||
exporter.packPdf("My Document");
|
|
||||||
|
|
||||||
// Express
|
|
||||||
const exporter = new docx.ExpressPacker(doc, res);
|
|
||||||
exporter.packPdf("My Document");
|
|
||||||
```
|
|
||||||
|
@ -22,10 +22,11 @@ const name = new TextRun({
|
|||||||
### Run formatting
|
### Run formatting
|
||||||
|
|
||||||
- `bold`, `italics`, `smallCaps`, `allCaps`, `strike`, `doubleStrike`, `subScript`, `superScript`: Set the formatting property to true
|
- `bold`, `italics`, `smallCaps`, `allCaps`, `strike`, `doubleStrike`, `subScript`, `superScript`: Set the formatting property to true
|
||||||
- `underline(style="single", color=null)`: Set the underline style and color
|
- `underline({type="single", color=null})`: Set the underline style and color
|
||||||
|
- `emphasisMark({type="dot"})`: Set the emphasis mark style
|
||||||
- `color(color)`: Set the text color, using 6 hex characters for RRGGBB (no leading `#`)
|
- `color(color)`: Set the text color, using 6 hex characters for RRGGBB (no leading `#`)
|
||||||
- `size(halfPts)`: Set the font size, measured in half-points
|
- `size(halfPts)`: Set the font size, measured in half-points
|
||||||
- `font(name)`: Set the run's font
|
- `font(name)` or `font({ascii, cs, eastAsia, hAnsi, hint})`: Set the run's font
|
||||||
- `style(name)`: Apply a named run style
|
- `style(name)`: Apply a named run style
|
||||||
- `characterSpacing(value)`: Set the character spacing adjustment (in TWIPs)
|
- `characterSpacing(value)`: Set the character spacing adjustment (in TWIPs)
|
||||||
|
|
||||||
|
@ -68,6 +68,15 @@ const text = new TextRun({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Emphasis Mark
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const text = new TextRun({
|
||||||
|
text: "and then emphasis mark",
|
||||||
|
emphasisMark: {},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
### Strike through
|
### Strike through
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
3136
package-lock.json
generated
3136
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "docx",
|
"name": "docx",
|
||||||
"version": "5.1.1",
|
"version": "5.2.2",
|
||||||
"description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.",
|
"description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.",
|
||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -50,7 +50,7 @@
|
|||||||
"types": "./build/index.d.ts",
|
"types": "./build/index.d.ts",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/jszip": "^3.1.4",
|
"@types/jszip": "^3.1.4",
|
||||||
"@types/node": "^13.1.6",
|
"@types/node": "^14.0.5",
|
||||||
"jszip": "^3.1.5",
|
"jszip": "^3.1.5",
|
||||||
"shortid": "^2.2.15",
|
"shortid": "^2.2.15",
|
||||||
"xml": "^1.0.1",
|
"xml": "^1.0.1",
|
||||||
@ -64,10 +64,10 @@
|
|||||||
"homepage": "https://github.com/dolanmiu/docx#readme",
|
"homepage": "https://github.com/dolanmiu/docx#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/chai": "^3.4.35",
|
"@types/chai": "^3.4.35",
|
||||||
"@types/mocha": "^2.2.39",
|
"@types/mocha": "^8.0.0",
|
||||||
"@types/request-promise": "^4.1.42",
|
"@types/request-promise": "^4.1.42",
|
||||||
"@types/shortid": "0.0.29",
|
"@types/shortid": "0.0.29",
|
||||||
"@types/sinon": "^4.3.1",
|
"@types/sinon": "^9.0.4",
|
||||||
"@types/webpack": "^4.4.24",
|
"@types/webpack": "^4.4.24",
|
||||||
"awesome-typescript-loader": "^3.4.1",
|
"awesome-typescript-loader": "^3.4.1",
|
||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
@ -77,7 +77,7 @@
|
|||||||
"jszip": "^3.1.5",
|
"jszip": "^3.1.5",
|
||||||
"mocha": "^5.2.0",
|
"mocha": "^5.2.0",
|
||||||
"mocha-webpack": "^1.0.1",
|
"mocha-webpack": "^1.0.1",
|
||||||
"nyc": "^14.1.1",
|
"nyc": "^15.1.0",
|
||||||
"pre-commit": "^1.2.2",
|
"pre-commit": "^1.2.2",
|
||||||
"prettier": "^1.15.2",
|
"prettier": "^1.15.2",
|
||||||
"prompt": "^1.0.0",
|
"prompt": "^1.0.0",
|
||||||
@ -85,12 +85,12 @@
|
|||||||
"request": "^2.88.0",
|
"request": "^2.88.0",
|
||||||
"request-promise": "^4.2.2",
|
"request-promise": "^4.2.2",
|
||||||
"rimraf": "^2.5.2",
|
"rimraf": "^2.5.2",
|
||||||
"shelljs": "^0.7.7",
|
"shelljs": "^0.8.4",
|
||||||
"sinon": "^5.0.7",
|
"sinon": "^9.0.2",
|
||||||
"ts-node": "^7.0.1",
|
"ts-node": "^8.10.2",
|
||||||
"tslint": "^5.11.0",
|
"tslint": "^5.11.0",
|
||||||
"tslint-immutable": "^4.9.0",
|
"tslint-immutable": "^4.9.0",
|
||||||
"typedoc": "^0.11.1",
|
"typedoc": "^0.16.11",
|
||||||
"typescript": "2.9.2",
|
"typescript": "2.9.2",
|
||||||
"webpack": "^3.10.0"
|
"webpack": "^3.10.0"
|
||||||
},
|
},
|
||||||
|
@ -45,7 +45,7 @@ export class Body extends XmlComponent {
|
|||||||
private createSectionParagraph(section: SectionProperties): Paragraph {
|
private createSectionParagraph(section: SectionProperties): Paragraph {
|
||||||
const paragraph = new Paragraph({});
|
const paragraph = new Paragraph({});
|
||||||
const properties = new ParagraphProperties({});
|
const properties = new ParagraphProperties({});
|
||||||
properties.addChildElement(section);
|
properties.push(section);
|
||||||
paragraph.addChildElement(properties);
|
paragraph.addChildElement(properties);
|
||||||
return paragraph;
|
return paragraph;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ export enum PageNumberFormat {
|
|||||||
ORDINAL_TEXT = "ordinalText",
|
ORDINAL_TEXT = "ordinalText",
|
||||||
UPPER_LETTER = "upperLetter",
|
UPPER_LETTER = "upperLetter",
|
||||||
UPPER_ROMAN = "upperRoman",
|
UPPER_ROMAN = "upperRoman",
|
||||||
|
DECIMAL_FULL_WIDTH = "decimalFullWidth",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPageNumberTypeAttributes {
|
export interface IPageNumberTypeAttributes {
|
||||||
|
@ -3,10 +3,11 @@ import { expect } from "chai";
|
|||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
import { EMPTY_OBJECT } from "file/xml-components";
|
import { EMPTY_OBJECT } from "file/xml-components";
|
||||||
|
|
||||||
import { AlignmentType, TabStopPosition } from "../paragraph";
|
import { AlignmentType, EmphasisMarkType, TabStopPosition } from "../paragraph";
|
||||||
import { UnderlineType } from "../paragraph/run/underline";
|
import { UnderlineType } from "../paragraph/run/underline";
|
||||||
import { ShadingType } from "../table";
|
import { ShadingType } from "../table";
|
||||||
import { AbstractNumbering } from "./abstract-numbering";
|
import { AbstractNumbering } from "./abstract-numbering";
|
||||||
|
import { LevelSuffix } from "./level";
|
||||||
|
|
||||||
describe("AbstractNumbering", () => {
|
describe("AbstractNumbering", () => {
|
||||||
it("stores its ID at its .id property", () => {
|
it("stores its ID at its .id property", () => {
|
||||||
@ -48,6 +49,20 @@ describe("AbstractNumbering", () => {
|
|||||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:lvlText": { _attr: { "w:val": "%1)" } } });
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:lvlText": { _attr: { "w:val": "%1)" } } });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("has suffix", () => {
|
||||||
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
|
{
|
||||||
|
level: 3,
|
||||||
|
format: "lowerLetter",
|
||||||
|
text: "%1)",
|
||||||
|
alignment: AlignmentType.END,
|
||||||
|
suffix: LevelSuffix.SPACE,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const tree = new Formatter().format(abstractNumbering);
|
||||||
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:suff": { _attr: { "w:val": "space" } } });
|
||||||
|
});
|
||||||
|
|
||||||
describe("formatting methods: paragraph properties", () => {
|
describe("formatting methods: paragraph properties", () => {
|
||||||
it("#indent", () => {
|
it("#indent", () => {
|
||||||
const abstractNumbering = new AbstractNumbering(1, [
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
@ -283,22 +298,41 @@ describe("AbstractNumbering", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("formatting methods: run properties", () => {
|
describe("formatting methods: run properties", () => {
|
||||||
it("#size", () => {
|
const sizeTests = [
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
sizeComplexScript: true,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
sizeComplexScript: false,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
sizeComplexScript: 26,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 26 } } }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
sizeTests.forEach(({ size, sizeComplexScript, expected }) => {
|
||||||
|
it(`#size ${size} cs ${sizeComplexScript}`, () => {
|
||||||
const abstractNumbering = new AbstractNumbering(1, [
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
{
|
{
|
||||||
level: 0,
|
level: 0,
|
||||||
format: "lowerRoman",
|
format: "lowerRoman",
|
||||||
text: "%0.",
|
text: "%0.",
|
||||||
style: {
|
style: {
|
||||||
run: {
|
run: { size, sizeComplexScript },
|
||||||
size: 24,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const tree = new Formatter().format(abstractNumbering);
|
const tree = new Formatter().format(abstractNumbering);
|
||||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:rPr": expected });
|
||||||
"w:rPr": [{ "w:sz": { _attr: { "w:val": 24 } } }],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -417,7 +451,7 @@ describe("AbstractNumbering", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#font", () => {
|
it("#font by name", () => {
|
||||||
const abstractNumbering = new AbstractNumbering(1, [
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
{
|
{
|
||||||
level: 0,
|
level: 0,
|
||||||
@ -433,12 +467,21 @@ describe("AbstractNumbering", () => {
|
|||||||
const tree = new Formatter().format(abstractNumbering);
|
const tree = new Formatter().format(abstractNumbering);
|
||||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({
|
||||||
"w:rPr": [
|
"w:rPr": [
|
||||||
{ "w:rFonts": { _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } } },
|
{
|
||||||
|
"w:rFonts": {
|
||||||
|
_attr: {
|
||||||
|
"w:ascii": "Times",
|
||||||
|
"w:cs": "Times",
|
||||||
|
"w:eastAsia": "Times",
|
||||||
|
"w:hAnsi": "Times",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#bold", () => {
|
it("#font for ascii and eastAsia", () => {
|
||||||
const abstractNumbering = new AbstractNumbering(1, [
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
{
|
{
|
||||||
level: 0,
|
level: 0,
|
||||||
@ -446,75 +489,208 @@ describe("AbstractNumbering", () => {
|
|||||||
text: "%0.",
|
text: "%0.",
|
||||||
style: {
|
style: {
|
||||||
run: {
|
run: {
|
||||||
|
font: {
|
||||||
|
ascii: "Times",
|
||||||
|
eastAsia: "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const tree = new Formatter().format(abstractNumbering);
|
||||||
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:rFonts": {
|
||||||
|
_attr: {
|
||||||
|
"w:ascii": "Times",
|
||||||
|
"w:eastAsia": "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const boldTests = [
|
||||||
|
{
|
||||||
bold: true,
|
bold: true,
|
||||||
|
expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
bold: true,
|
||||||
|
boldComplexScript: true,
|
||||||
|
expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
bold: true,
|
||||||
|
boldComplexScript: false,
|
||||||
|
expected: [{ "w:b": { _attr: { "w:val": true } } }],
|
||||||
},
|
},
|
||||||
]);
|
];
|
||||||
const tree = new Formatter().format(abstractNumbering);
|
boldTests.forEach(({ bold, boldComplexScript, expected }) => {
|
||||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({
|
it(`#bold ${bold} cs ${boldComplexScript}`, () => {
|
||||||
"w:rPr": [{ "w:b": { _attr: { "w:val": true } } }],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("#italics", () => {
|
|
||||||
const abstractNumbering = new AbstractNumbering(1, [
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
{
|
{
|
||||||
level: 0,
|
level: 0,
|
||||||
format: "lowerRoman",
|
format: "lowerRoman",
|
||||||
text: "%0.",
|
text: "%0.",
|
||||||
style: {
|
style: {
|
||||||
run: {
|
run: { bold, boldComplexScript },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const tree = new Formatter().format(abstractNumbering);
|
||||||
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:rPr": expected });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const italicsTests = [
|
||||||
|
{
|
||||||
italics: true,
|
italics: true,
|
||||||
|
expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
italics: true,
|
||||||
|
italicsComplexScript: true,
|
||||||
|
expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
italics: true,
|
||||||
|
italicsComplexScript: false,
|
||||||
|
expected: [{ "w:i": { _attr: { "w:val": true } } }],
|
||||||
},
|
},
|
||||||
]);
|
];
|
||||||
const tree = new Formatter().format(abstractNumbering);
|
italicsTests.forEach(({ italics, italicsComplexScript, expected }) => {
|
||||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({
|
it(`#italics ${italics} cs ${italicsComplexScript}`, () => {
|
||||||
"w:rPr": [{ "w:i": { _attr: { "w:val": true } } }],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("#highlight", () => {
|
|
||||||
const abstractNumbering = new AbstractNumbering(1, [
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
{
|
{
|
||||||
level: 0,
|
level: 0,
|
||||||
format: "lowerRoman",
|
format: "lowerRoman",
|
||||||
text: "%0.",
|
text: "%0.",
|
||||||
style: {
|
style: {
|
||||||
run: {
|
run: { italics, italicsComplexScript },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const tree = new Formatter().format(abstractNumbering);
|
||||||
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:rPr": expected });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const highlightTests = [
|
||||||
|
{
|
||||||
highlight: "005599",
|
highlight: "005599",
|
||||||
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
highlight: "005599",
|
||||||
|
highlightComplexScript: true,
|
||||||
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
highlight: "005599",
|
||||||
|
highlightComplexScript: false,
|
||||||
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }],
|
||||||
},
|
},
|
||||||
]);
|
{
|
||||||
const tree = new Formatter().format(abstractNumbering);
|
highlight: "005599",
|
||||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({
|
highlightComplexScript: "550099",
|
||||||
"w:rPr": [{ "w:highlight": { _attr: { "w:val": "005599" } } }],
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "550099" } } }],
|
||||||
});
|
},
|
||||||
});
|
];
|
||||||
|
highlightTests.forEach(({ highlight, highlightComplexScript, expected }) => {
|
||||||
it("#shadow", () => {
|
it(`#highlight ${highlight} cs ${highlightComplexScript}`, () => {
|
||||||
const abstractNumbering = new AbstractNumbering(1, [
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
{
|
{
|
||||||
level: 0,
|
level: 0,
|
||||||
format: "lowerRoman",
|
format: "lowerRoman",
|
||||||
text: "%0.",
|
text: "%0.",
|
||||||
style: {
|
style: {
|
||||||
run: {
|
run: { highlight, highlightComplexScript },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const tree = new Formatter().format(abstractNumbering);
|
||||||
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:rPr": expected });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const shadingTests = [
|
||||||
|
{
|
||||||
shadow: {
|
shadow: {
|
||||||
type: ShadingType.PERCENT_10,
|
type: ShadingType.PERCENT_10,
|
||||||
fill: "00FFFF",
|
fill: "00FFFF",
|
||||||
color: "FF0000",
|
color: "FF0000",
|
||||||
},
|
},
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
shadingComplexScript: true,
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
shadingComplexScript: false,
|
||||||
|
expected: [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
shadingComplexScript: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "00FF00",
|
||||||
|
},
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "00FF00" } } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
shadingTests.forEach(({ shadow, shading, shadingComplexScript, expected }) => {
|
||||||
|
it("#shadow correctly", () => {
|
||||||
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
|
{
|
||||||
|
level: 0,
|
||||||
|
format: "lowerRoman",
|
||||||
|
text: "%0.",
|
||||||
|
style: {
|
||||||
|
run: { shadow, shading, shadingComplexScript },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
const tree = new Formatter().format(abstractNumbering);
|
const tree = new Formatter().format(abstractNumbering);
|
||||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:rPr": expected });
|
||||||
"w:rPr": [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -582,6 +758,48 @@ describe("AbstractNumbering", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#emphasisMark", () => {
|
||||||
|
it("should set emphasisMark to 'dot' if no arguments are given", () => {
|
||||||
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
|
{
|
||||||
|
level: 0,
|
||||||
|
format: "lowerRoman",
|
||||||
|
text: "%0.",
|
||||||
|
style: {
|
||||||
|
run: {
|
||||||
|
emphasisMark: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const tree = new Formatter().format(abstractNumbering);
|
||||||
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({
|
||||||
|
"w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the style if given", () => {
|
||||||
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
|
{
|
||||||
|
level: 0,
|
||||||
|
format: "lowerRoman",
|
||||||
|
text: "%0.",
|
||||||
|
style: {
|
||||||
|
run: {
|
||||||
|
emphasisMark: {
|
||||||
|
type: EmphasisMarkType.DOT,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const tree = new Formatter().format(abstractNumbering);
|
||||||
|
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({
|
||||||
|
"w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("#color", () => {
|
it("#color", () => {
|
||||||
const abstractNumbering = new AbstractNumbering(1, [
|
const abstractNumbering = new AbstractNumbering(1, [
|
||||||
{
|
{
|
||||||
|
@ -1,19 +1,7 @@
|
|||||||
import { Attributes, XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
import { Attributes, XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||||
import {
|
import { AlignmentType } from "../paragraph/formatting";
|
||||||
Alignment,
|
import { IParagraphStylePropertiesOptions, ParagraphProperties } from "../paragraph/properties";
|
||||||
AlignmentType,
|
import { IRunStylePropertiesOptions, RunProperties } from "../paragraph/run/properties";
|
||||||
Indent,
|
|
||||||
KeepLines,
|
|
||||||
KeepNext,
|
|
||||||
Spacing,
|
|
||||||
TabStop,
|
|
||||||
TabStopType,
|
|
||||||
ThematicBreak,
|
|
||||||
} from "../paragraph/formatting";
|
|
||||||
import { ParagraphProperties } from "../paragraph/properties";
|
|
||||||
import * as formatting from "../paragraph/run/formatting";
|
|
||||||
import { RunProperties } from "../paragraph/run/properties";
|
|
||||||
import { IParagraphStyleOptions2, IRunStyleOptions } from "../styles/style-options";
|
|
||||||
|
|
||||||
interface ILevelAttributesProperties {
|
interface ILevelAttributesProperties {
|
||||||
readonly ilvl?: number;
|
readonly ilvl?: number;
|
||||||
@ -85,8 +73,8 @@ export interface ILevelsOptions {
|
|||||||
readonly start?: number;
|
readonly start?: number;
|
||||||
readonly suffix?: LevelSuffix;
|
readonly suffix?: LevelSuffix;
|
||||||
readonly style?: {
|
readonly style?: {
|
||||||
readonly run?: IRunStyleOptions;
|
readonly run?: IRunStylePropertiesOptions;
|
||||||
readonly paragraph?: IParagraphStyleOptions2;
|
readonly paragraph?: IParagraphStylePropertiesOptions;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,8 +113,8 @@ export class LevelBase extends XmlComponent {
|
|||||||
this.root.push(new LevelText(text));
|
this.root.push(new LevelText(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.paragraphProperties = new ParagraphProperties({});
|
this.paragraphProperties = new ParagraphProperties(style && style.paragraph);
|
||||||
this.runProperties = new RunProperties();
|
this.runProperties = new RunProperties(style && style.run);
|
||||||
|
|
||||||
this.root.push(this.paragraphProperties);
|
this.root.push(this.paragraphProperties);
|
||||||
this.root.push(this.runProperties);
|
this.root.push(this.runProperties);
|
||||||
@ -134,100 +122,6 @@ export class LevelBase extends XmlComponent {
|
|||||||
if (suffix) {
|
if (suffix) {
|
||||||
this.root.push(new Suffix(suffix));
|
this.root.push(new Suffix(suffix));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style) {
|
|
||||||
if (style.run) {
|
|
||||||
if (style.run.size) {
|
|
||||||
this.runProperties.push(new formatting.Size(style.run.size));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.bold) {
|
|
||||||
this.runProperties.push(new formatting.Bold());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.italics) {
|
|
||||||
this.runProperties.push(new formatting.Italics());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.smallCaps) {
|
|
||||||
this.runProperties.push(new formatting.SmallCaps());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.allCaps) {
|
|
||||||
this.runProperties.push(new formatting.Caps());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.strike) {
|
|
||||||
this.runProperties.push(new formatting.Strike());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.doubleStrike) {
|
|
||||||
this.runProperties.push(new formatting.DoubleStrike());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.subScript) {
|
|
||||||
this.runProperties.push(new formatting.SubScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.superScript) {
|
|
||||||
this.runProperties.push(new formatting.SuperScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.underline) {
|
|
||||||
this.runProperties.push(new formatting.Underline(style.run.underline.type, style.run.underline.color));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.color) {
|
|
||||||
this.runProperties.push(new formatting.Color(style.run.color));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.font) {
|
|
||||||
this.runProperties.push(new formatting.RunFonts(style.run.font));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.highlight) {
|
|
||||||
this.runProperties.push(new formatting.Highlight(style.run.highlight));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.run.shadow) {
|
|
||||||
this.runProperties.push(new formatting.Shading(style.run.shadow.type, style.run.shadow.fill, style.run.shadow.color));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.paragraph) {
|
|
||||||
if (style.paragraph.alignment) {
|
|
||||||
this.paragraphProperties.push(new Alignment(style.paragraph.alignment));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.paragraph.thematicBreak) {
|
|
||||||
this.paragraphProperties.push(new ThematicBreak());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.paragraph.rightTabStop) {
|
|
||||||
this.paragraphProperties.push(new TabStop(TabStopType.RIGHT, style.paragraph.rightTabStop));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.paragraph.leftTabStop) {
|
|
||||||
this.paragraphProperties.push(new TabStop(TabStopType.LEFT, style.paragraph.leftTabStop));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.paragraph.indent) {
|
|
||||||
this.paragraphProperties.push(new Indent(style.paragraph.indent));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.paragraph.spacing) {
|
|
||||||
this.paragraphProperties.push(new Spacing(style.paragraph.spacing));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.paragraph.keepNext) {
|
|
||||||
this.paragraphProperties.push(new KeepNext());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.paragraph.keepLines) {
|
|
||||||
this.paragraphProperties.push(new KeepLines());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,48 +3,13 @@ import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run"
|
|||||||
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
import { File } from "../file";
|
import { File } from "../file";
|
||||||
import { Alignment, AlignmentType } from "./formatting/alignment";
|
import { PageBreak } from "./formatting/page-break";
|
||||||
import { Bidirectional } from "./formatting/bidirectional";
|
import { Bookmark, HyperlinkRef } from "./links";
|
||||||
import { IBorderOptions, ThematicBreak } from "./formatting/border";
|
import { IParagraphPropertiesOptions, ParagraphProperties } from "./properties";
|
||||||
import { IIndentAttributesProperties, Indent } from "./formatting/indent";
|
|
||||||
import { KeepLines, KeepNext } from "./formatting/keep";
|
|
||||||
import { PageBreak, PageBreakBefore } from "./formatting/page-break";
|
|
||||||
import { ContextualSpacing, ISpacingProperties, Spacing } from "./formatting/spacing";
|
|
||||||
import { HeadingLevel, Style } from "./formatting/style";
|
|
||||||
import { LeaderType, TabStop, TabStopPosition, TabStopType } from "./formatting/tab-stop";
|
|
||||||
import { NumberProperties } from "./formatting/unordered-list";
|
|
||||||
import { Bookmark, HyperlinkRef, OutlineLevel } from "./links";
|
|
||||||
import { ParagraphProperties } from "./properties";
|
|
||||||
import { PictureRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run";
|
import { PictureRun, Run, SequentialIdentifier, SymbolRun, TextRun } from "./run";
|
||||||
|
|
||||||
export interface IParagraphOptions {
|
export interface IParagraphOptions extends IParagraphPropertiesOptions {
|
||||||
readonly text?: string;
|
readonly text?: string;
|
||||||
readonly border?: IBorderOptions;
|
|
||||||
readonly spacing?: ISpacingProperties;
|
|
||||||
readonly outlineLevel?: number;
|
|
||||||
readonly alignment?: AlignmentType;
|
|
||||||
readonly heading?: HeadingLevel;
|
|
||||||
readonly bidirectional?: boolean;
|
|
||||||
readonly thematicBreak?: boolean;
|
|
||||||
readonly pageBreakBefore?: boolean;
|
|
||||||
readonly contextualSpacing?: boolean;
|
|
||||||
readonly indent?: IIndentAttributesProperties;
|
|
||||||
readonly keepLines?: boolean;
|
|
||||||
readonly keepNext?: boolean;
|
|
||||||
readonly tabStops?: Array<{
|
|
||||||
readonly position: number | TabStopPosition;
|
|
||||||
readonly type: TabStopType;
|
|
||||||
readonly leader?: LeaderType;
|
|
||||||
}>;
|
|
||||||
readonly style?: string;
|
|
||||||
readonly bullet?: {
|
|
||||||
readonly level: number;
|
|
||||||
};
|
|
||||||
readonly numbering?: {
|
|
||||||
readonly reference: string;
|
|
||||||
readonly level: number;
|
|
||||||
readonly custom?: boolean;
|
|
||||||
};
|
|
||||||
readonly children?: Array<
|
readonly children?: Array<
|
||||||
TextRun | PictureRun | SymbolRun | Bookmark | PageBreak | SequentialIdentifier | FootnoteReferenceRun | HyperlinkRef
|
TextRun | PictureRun | SymbolRun | Bookmark | PageBreak | SequentialIdentifier | FootnoteReferenceRun | HyperlinkRef
|
||||||
>;
|
>;
|
||||||
@ -70,9 +35,7 @@ export class Paragraph extends XmlComponent {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.properties = new ParagraphProperties({
|
this.properties = new ParagraphProperties(options);
|
||||||
border: options.border,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.root.push(this.properties);
|
this.root.push(this.properties);
|
||||||
|
|
||||||
@ -80,72 +43,6 @@ export class Paragraph extends XmlComponent {
|
|||||||
this.root.push(new TextRun(options.text));
|
this.root.push(new TextRun(options.text));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.spacing) {
|
|
||||||
this.properties.push(new Spacing(options.spacing));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.outlineLevel !== undefined) {
|
|
||||||
this.properties.push(new OutlineLevel(options.outlineLevel));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.alignment) {
|
|
||||||
this.properties.push(new Alignment(options.alignment));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.heading) {
|
|
||||||
this.properties.push(new Style(options.heading));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.bidirectional) {
|
|
||||||
this.properties.push(new Bidirectional());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.thematicBreak) {
|
|
||||||
this.properties.push(new ThematicBreak());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.pageBreakBefore) {
|
|
||||||
this.properties.push(new PageBreakBefore());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.contextualSpacing) {
|
|
||||||
this.properties.push(new ContextualSpacing(options.contextualSpacing));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.indent) {
|
|
||||||
this.properties.push(new Indent(options.indent));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.keepLines) {
|
|
||||||
this.properties.push(new KeepLines());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.keepNext) {
|
|
||||||
this.properties.push(new KeepNext());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.tabStops) {
|
|
||||||
for (const tabStop of options.tabStops) {
|
|
||||||
this.properties.push(new TabStop(tabStop.type, tabStop.position, tabStop.leader));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.style) {
|
|
||||||
this.properties.push(new Style(options.style));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.bullet) {
|
|
||||||
this.properties.push(new Style("ListParagraph"));
|
|
||||||
this.properties.push(new NumberProperties(1, options.bullet.level));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.numbering) {
|
|
||||||
if (!options.numbering.custom) {
|
|
||||||
this.properties.push(new Style("ListParagraph"));
|
|
||||||
}
|
|
||||||
this.properties.push(new NumberProperties(options.numbering.reference, options.numbering.level));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.children) {
|
if (options.children) {
|
||||||
for (const child of options.children) {
|
for (const child of options.children) {
|
||||||
if (child instanceof Bookmark) {
|
if (child instanceof Bookmark) {
|
||||||
|
@ -1,19 +1,136 @@
|
|||||||
// http://officeopenxml.com/WPparagraphProperties.php
|
// http://officeopenxml.com/WPparagraphProperties.php
|
||||||
import { IgnoreIfEmptyXmlComponent, XmlComponent } from "file/xml-components";
|
import { IgnoreIfEmptyXmlComponent, XmlComponent } from "file/xml-components";
|
||||||
|
import { Alignment, AlignmentType } from "./formatting/alignment";
|
||||||
|
import { Bidirectional } from "./formatting/bidirectional";
|
||||||
|
import { Border, IBorderOptions, ThematicBreak } from "./formatting/border";
|
||||||
|
import { IIndentAttributesProperties, Indent } from "./formatting/indent";
|
||||||
|
import { KeepLines, KeepNext } from "./formatting/keep";
|
||||||
|
import { PageBreakBefore } from "./formatting/page-break";
|
||||||
|
import { ContextualSpacing, ISpacingProperties, Spacing } from "./formatting/spacing";
|
||||||
|
import { HeadingLevel, Style } from "./formatting/style";
|
||||||
|
import { LeaderType, TabStop, TabStopPosition, TabStopType } from "./formatting/tab-stop";
|
||||||
|
import { NumberProperties } from "./formatting/unordered-list";
|
||||||
|
import { OutlineLevel } from "./links";
|
||||||
|
|
||||||
import { Border, IBorderOptions } from "./formatting/border";
|
export interface IParagraphStylePropertiesOptions {
|
||||||
|
readonly alignment?: AlignmentType;
|
||||||
|
readonly thematicBreak?: boolean;
|
||||||
|
readonly contextualSpacing?: boolean;
|
||||||
|
readonly rightTabStop?: number;
|
||||||
|
readonly leftTabStop?: number;
|
||||||
|
readonly indent?: IIndentAttributesProperties;
|
||||||
|
readonly spacing?: ISpacingProperties;
|
||||||
|
readonly keepNext?: boolean;
|
||||||
|
readonly keepLines?: boolean;
|
||||||
|
readonly outlineLevel?: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface IParagraphPropertiesOptions {
|
export interface IParagraphPropertiesOptions extends IParagraphStylePropertiesOptions {
|
||||||
readonly border?: IBorderOptions;
|
readonly border?: IBorderOptions;
|
||||||
|
readonly heading?: HeadingLevel;
|
||||||
|
readonly bidirectional?: boolean;
|
||||||
|
readonly pageBreakBefore?: boolean;
|
||||||
|
readonly tabStops?: Array<{
|
||||||
|
readonly position: number | TabStopPosition;
|
||||||
|
readonly type: TabStopType;
|
||||||
|
readonly leader?: LeaderType;
|
||||||
|
}>;
|
||||||
|
readonly style?: string;
|
||||||
|
readonly bullet?: {
|
||||||
|
readonly level: number;
|
||||||
|
};
|
||||||
|
readonly numbering?: {
|
||||||
|
readonly reference: string;
|
||||||
|
readonly level: number;
|
||||||
|
readonly custom?: boolean;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ParagraphProperties extends IgnoreIfEmptyXmlComponent {
|
export class ParagraphProperties extends IgnoreIfEmptyXmlComponent {
|
||||||
constructor(options: IParagraphPropertiesOptions) {
|
constructor(options?: IParagraphPropertiesOptions) {
|
||||||
super("w:pPr");
|
super("w:pPr");
|
||||||
|
|
||||||
|
if (!options) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.border) {
|
if (options.border) {
|
||||||
this.push(new Border(options.border));
|
this.push(new Border(options.border));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.spacing) {
|
||||||
|
this.push(new Spacing(options.spacing));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.outlineLevel !== undefined) {
|
||||||
|
this.push(new OutlineLevel(options.outlineLevel));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.alignment) {
|
||||||
|
this.push(new Alignment(options.alignment));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.heading) {
|
||||||
|
this.push(new Style(options.heading));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.bidirectional) {
|
||||||
|
this.push(new Bidirectional());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.thematicBreak) {
|
||||||
|
this.push(new ThematicBreak());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.pageBreakBefore) {
|
||||||
|
this.push(new PageBreakBefore());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.contextualSpacing) {
|
||||||
|
this.push(new ContextualSpacing(options.contextualSpacing));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.indent) {
|
||||||
|
this.push(new Indent(options.indent));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.keepLines) {
|
||||||
|
this.push(new KeepLines());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.keepNext) {
|
||||||
|
this.push(new KeepNext());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.tabStops) {
|
||||||
|
for (const tabStop of options.tabStops) {
|
||||||
|
this.push(new TabStop(tabStop.type, tabStop.position, tabStop.leader));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.style) {
|
||||||
|
this.push(new Style(options.style));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.bullet) {
|
||||||
|
this.push(new Style("ListParagraph"));
|
||||||
|
this.push(new NumberProperties(1, options.bullet.level));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.numbering) {
|
||||||
|
if (!options.numbering.custom) {
|
||||||
|
this.push(new Style("ListParagraph"));
|
||||||
|
}
|
||||||
|
this.push(new NumberProperties(options.numbering.reference, options.numbering.level));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.rightTabStop) {
|
||||||
|
this.push(new TabStop(TabStopType.RIGHT, options.rightTabStop));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.leftTabStop) {
|
||||||
|
this.push(new TabStop(TabStopType.LEFT, options.leftTabStop));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public push(item: XmlComponent): void {
|
public push(item: XmlComponent): void {
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
import { XmlComponent } from "file/xml-components";
|
|
||||||
|
|
||||||
export class SmallCaps extends XmlComponent {
|
|
||||||
constructor() {
|
|
||||||
super("w:smallCaps");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Caps extends XmlComponent {
|
|
||||||
constructor() {
|
|
||||||
super("w:caps");
|
|
||||||
}
|
|
||||||
}
|
|
29
src/file/paragraph/run/emphasis-mark.spec.ts
Normal file
29
src/file/paragraph/run/emphasis-mark.spec.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
|
import * as em from "./emphasis-mark";
|
||||||
|
|
||||||
|
describe("EmphasisMark", () => {
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("should create a new EmphasisMark object with w:em as the rootKey", () => {
|
||||||
|
const emphasisMark = new em.EmphasisMark();
|
||||||
|
const tree = new Formatter().format(emphasisMark);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:em": { _attr: { "w:val": "dot" } },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("DotEmphasisMark", () => {
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("should put value in attribute", () => {
|
||||||
|
const emphasisMark = new em.DotEmphasisMark();
|
||||||
|
const tree = new Formatter().format(emphasisMark);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:em": { _attr: { "w:val": "dot" } },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
28
src/file/paragraph/run/emphasis-mark.ts
Normal file
28
src/file/paragraph/run/emphasis-mark.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Attributes, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
|
export enum EmphasisMarkType {
|
||||||
|
DOT = "dot",
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class BaseEmphasisMark extends XmlComponent {
|
||||||
|
protected constructor(emphasisMarkType: EmphasisMarkType) {
|
||||||
|
super("w:em");
|
||||||
|
this.root.push(
|
||||||
|
new Attributes({
|
||||||
|
val: emphasisMarkType,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EmphasisMark extends BaseEmphasisMark {
|
||||||
|
constructor(emphasisMarkType: EmphasisMarkType = EmphasisMarkType.DOT) {
|
||||||
|
super(emphasisMarkType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DotEmphasisMark extends BaseEmphasisMark {
|
||||||
|
constructor() {
|
||||||
|
super(EmphasisMarkType.DOT);
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
import { Attributes, XmlComponent } from "file/xml-components";
|
import { Attributes, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
export { Underline } from "./underline";
|
export { Underline } from "./underline";
|
||||||
|
export { EmphasisMark } from "./emphasis-mark";
|
||||||
export { SubScript, SuperScript } from "./script";
|
export { SubScript, SuperScript } from "./script";
|
||||||
export { RunFonts } from "./run-fonts";
|
export { RunFonts, IFontAttributesProperties } from "./run-fonts";
|
||||||
|
|
||||||
export class Bold extends XmlComponent {
|
export class Bold extends XmlComponent {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -113,17 +115,6 @@ export class Imprint extends XmlComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* export class Shadow extends XmlComponent {
|
|
||||||
constructor() {
|
|
||||||
super("w:shadow");
|
|
||||||
this.root.push(
|
|
||||||
new Attributes({
|
|
||||||
val: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
export class SmallCaps extends XmlComponent {
|
export class SmallCaps extends XmlComponent {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("w:smallCaps");
|
super("w:smallCaps");
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
export * from "./run";
|
export * from "./run";
|
||||||
|
export * from "./properties";
|
||||||
export * from "./text-run";
|
export * from "./text-run";
|
||||||
export * from "./symbol-run";
|
export * from "./symbol-run";
|
||||||
export * from "./picture-run";
|
export * from "./picture-run";
|
||||||
export * from "./run-fonts";
|
export * from "./run-fonts";
|
||||||
export * from "./sequential-identifier";
|
export * from "./sequential-identifier";
|
||||||
export * from "./underline";
|
export * from "./underline";
|
||||||
|
export * from "./emphasis-mark";
|
||||||
export * from "./tab";
|
export * from "./tab";
|
||||||
|
@ -1,8 +1,183 @@
|
|||||||
|
import { ShadingType } from "file/table";
|
||||||
import { IgnoreIfEmptyXmlComponent, XmlComponent } from "file/xml-components";
|
import { IgnoreIfEmptyXmlComponent, XmlComponent } from "file/xml-components";
|
||||||
|
import { EmphasisMark, EmphasisMarkType } from "./emphasis-mark";
|
||||||
|
import {
|
||||||
|
Bold,
|
||||||
|
BoldComplexScript,
|
||||||
|
Caps,
|
||||||
|
CharacterSpacing,
|
||||||
|
Color,
|
||||||
|
DoubleStrike,
|
||||||
|
Highlight,
|
||||||
|
HighlightComplexScript,
|
||||||
|
Italics,
|
||||||
|
ItalicsComplexScript,
|
||||||
|
RightToLeft,
|
||||||
|
Shading,
|
||||||
|
ShadowComplexScript,
|
||||||
|
Size,
|
||||||
|
SizeComplexScript,
|
||||||
|
SmallCaps,
|
||||||
|
Strike,
|
||||||
|
} from "./formatting";
|
||||||
|
import { IFontAttributesProperties, RunFonts } from "./run-fonts";
|
||||||
|
import { SubScript, SuperScript } from "./script";
|
||||||
|
import { Style } from "./style";
|
||||||
|
import { Underline, UnderlineType } from "./underline";
|
||||||
|
|
||||||
|
interface IFontOptions {
|
||||||
|
readonly name: string;
|
||||||
|
readonly hint?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRunStylePropertiesOptions {
|
||||||
|
readonly bold?: boolean;
|
||||||
|
readonly boldComplexScript?: boolean;
|
||||||
|
readonly italics?: boolean;
|
||||||
|
readonly italicsComplexScript?: boolean;
|
||||||
|
readonly underline?: {
|
||||||
|
readonly color?: string;
|
||||||
|
readonly type?: UnderlineType;
|
||||||
|
};
|
||||||
|
readonly emphasisMark?: {
|
||||||
|
readonly type?: EmphasisMarkType;
|
||||||
|
};
|
||||||
|
readonly color?: string;
|
||||||
|
readonly size?: number;
|
||||||
|
readonly sizeComplexScript?: boolean | number;
|
||||||
|
readonly rightToLeft?: boolean;
|
||||||
|
readonly smallCaps?: boolean;
|
||||||
|
readonly allCaps?: boolean;
|
||||||
|
readonly strike?: boolean;
|
||||||
|
readonly doubleStrike?: boolean;
|
||||||
|
readonly subScript?: boolean;
|
||||||
|
readonly superScript?: boolean;
|
||||||
|
readonly font?: string | IFontOptions | IFontAttributesProperties;
|
||||||
|
readonly highlight?: string;
|
||||||
|
readonly highlightComplexScript?: boolean | string;
|
||||||
|
readonly characterSpacing?: number;
|
||||||
|
readonly shading?: {
|
||||||
|
readonly type: ShadingType;
|
||||||
|
readonly fill: string;
|
||||||
|
readonly color: string;
|
||||||
|
};
|
||||||
|
readonly shadingComplexScript?: boolean | IRunStylePropertiesOptions["shading"];
|
||||||
|
readonly shadow?: IRunStylePropertiesOptions["shading"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRunPropertiesOptions extends IRunStylePropertiesOptions {
|
||||||
|
readonly style?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class RunProperties extends IgnoreIfEmptyXmlComponent {
|
export class RunProperties extends IgnoreIfEmptyXmlComponent {
|
||||||
constructor() {
|
constructor(options?: IRunPropertiesOptions) {
|
||||||
super("w:rPr");
|
super("w:rPr");
|
||||||
|
|
||||||
|
if (!options) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.bold) {
|
||||||
|
this.push(new Bold());
|
||||||
|
}
|
||||||
|
if ((options.boldComplexScript === undefined && options.bold) || options.boldComplexScript) {
|
||||||
|
this.push(new BoldComplexScript());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.italics) {
|
||||||
|
this.push(new Italics());
|
||||||
|
}
|
||||||
|
if ((options.italicsComplexScript === undefined && options.italics) || options.italicsComplexScript) {
|
||||||
|
this.push(new ItalicsComplexScript());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.underline) {
|
||||||
|
this.push(new Underline(options.underline.type, options.underline.color));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.emphasisMark) {
|
||||||
|
this.push(new EmphasisMark(options.emphasisMark.type));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.color) {
|
||||||
|
this.push(new Color(options.color));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.size) {
|
||||||
|
this.push(new Size(options.size));
|
||||||
|
}
|
||||||
|
const szCs =
|
||||||
|
options.sizeComplexScript === undefined || options.sizeComplexScript === true ? options.size : options.sizeComplexScript;
|
||||||
|
if (szCs) {
|
||||||
|
this.push(new SizeComplexScript(szCs));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.rightToLeft) {
|
||||||
|
this.push(new RightToLeft());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.smallCaps) {
|
||||||
|
this.push(new SmallCaps());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.allCaps) {
|
||||||
|
this.push(new Caps());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.strike) {
|
||||||
|
this.push(new Strike());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.doubleStrike) {
|
||||||
|
this.push(new DoubleStrike());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.subScript) {
|
||||||
|
this.push(new SubScript());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.superScript) {
|
||||||
|
this.push(new SuperScript());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.style) {
|
||||||
|
this.push(new Style(options.style));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.font) {
|
||||||
|
if (typeof options.font === "string") {
|
||||||
|
this.push(new RunFonts(options.font));
|
||||||
|
} else if ("name" in options.font) {
|
||||||
|
this.push(new RunFonts(options.font.name, options.font.hint));
|
||||||
|
} else {
|
||||||
|
this.push(new RunFonts(options.font));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.highlight) {
|
||||||
|
this.push(new Highlight(options.highlight));
|
||||||
|
}
|
||||||
|
const highlightCs =
|
||||||
|
options.highlightComplexScript === undefined || options.highlightComplexScript === true
|
||||||
|
? options.highlight
|
||||||
|
: options.highlightComplexScript;
|
||||||
|
if (highlightCs) {
|
||||||
|
this.push(new HighlightComplexScript(highlightCs));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.characterSpacing) {
|
||||||
|
this.push(new CharacterSpacing(options.characterSpacing));
|
||||||
|
}
|
||||||
|
|
||||||
|
const shading = options.shading || options.shadow;
|
||||||
|
if (shading) {
|
||||||
|
this.push(new Shading(shading.type, shading.fill, shading.color));
|
||||||
|
}
|
||||||
|
const shdCs =
|
||||||
|
options.shadingComplexScript === undefined || options.shadingComplexScript === true ? shading : options.shadingComplexScript;
|
||||||
|
if (shdCs) {
|
||||||
|
this.push(new ShadowComplexScript(shdCs.type, shdCs.fill, shdCs.color));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public push(item: XmlComponent): void {
|
public push(item: XmlComponent): void {
|
||||||
|
@ -21,5 +21,12 @@ describe("RunFonts", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses the font attrs for ascii and eastAsia", () => {
|
||||||
|
const tree = new Formatter().format(new RunFonts({ ascii: "Times", eastAsia: "KaiTi" }));
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:rFonts": { _attr: { "w:ascii": "Times", "w:eastAsia": "KaiTi" } },
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
interface IRunFontAttributesProperties {
|
export interface IFontAttributesProperties {
|
||||||
readonly ascii: string;
|
readonly ascii?: string;
|
||||||
readonly cs: string;
|
readonly cs?: string;
|
||||||
readonly eastAsia: string;
|
readonly eastAsia?: string;
|
||||||
readonly hAnsi: string;
|
readonly hAnsi?: string;
|
||||||
readonly hint?: string;
|
readonly hint?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RunFontAttributes extends XmlAttributeComponent<IRunFontAttributesProperties> {
|
class RunFontAttributes extends XmlAttributeComponent<IFontAttributesProperties> {
|
||||||
protected readonly xmlKeys = {
|
protected readonly xmlKeys = {
|
||||||
ascii: "w:ascii",
|
ascii: "w:ascii",
|
||||||
cs: "w:cs",
|
cs: "w:cs",
|
||||||
@ -19,16 +19,26 @@ class RunFontAttributes extends XmlAttributeComponent<IRunFontAttributesProperti
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class RunFonts extends XmlComponent {
|
export class RunFonts extends XmlComponent {
|
||||||
constructor(ascii: string, hint?: string) {
|
constructor(name: string, hint?: string);
|
||||||
|
constructor(attrs: string | IFontAttributesProperties);
|
||||||
|
constructor(nameOrAttrs: string | IFontAttributesProperties, hint?: string) {
|
||||||
super("w:rFonts");
|
super("w:rFonts");
|
||||||
|
if (typeof nameOrAttrs === "string") {
|
||||||
|
// use constructor(name: string, hint?: string);
|
||||||
|
const name = nameOrAttrs;
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new RunFontAttributes({
|
new RunFontAttributes({
|
||||||
ascii: ascii,
|
ascii: name,
|
||||||
cs: ascii,
|
cs: name,
|
||||||
eastAsia: ascii,
|
eastAsia: name,
|
||||||
hAnsi: ascii,
|
hAnsi: name,
|
||||||
hint: hint,
|
hint: hint,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
// use constructor(attrs: IRunFontAttributesProperties);
|
||||||
|
const attrs = nameOrAttrs;
|
||||||
|
this.root.push(new RunFontAttributes(attrs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { Formatter } from "export/formatter";
|
|||||||
import { ShadingType } from "file/table";
|
import { ShadingType } from "file/table";
|
||||||
|
|
||||||
import { Run } from "./";
|
import { Run } from "./";
|
||||||
|
import { EmphasisMarkType } from "./emphasis-mark";
|
||||||
import { PageNumber } from "./run";
|
import { PageNumber } from "./run";
|
||||||
import { UnderlineType } from "./underline";
|
import { UnderlineType } from "./underline";
|
||||||
|
|
||||||
@ -84,6 +85,30 @@ describe("Run", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#emphasisMark()", () => {
|
||||||
|
it("should default to 'dot'", () => {
|
||||||
|
const run = new Run({
|
||||||
|
emphasisMark: {},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(run);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:r": [{ "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the style type if given", () => {
|
||||||
|
const run = new Run({
|
||||||
|
emphasisMark: {
|
||||||
|
type: EmphasisMarkType.DOT,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(run);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:r": [{ "w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }] }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("#smallCaps()", () => {
|
describe("#smallCaps()", () => {
|
||||||
it("it should add smallCaps to the properties", () => {
|
it("it should add smallCaps to the properties", () => {
|
||||||
const run = new Run({
|
const run = new Run({
|
||||||
@ -91,7 +116,7 @@ describe("Run", () => {
|
|||||||
});
|
});
|
||||||
const tree = new Formatter().format(run);
|
const tree = new Formatter().format(run);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:r": [{ "w:rPr": [{ "w:smallCaps": {} }] }],
|
"w:r": [{ "w:rPr": [{ "w:smallCaps": { _attr: { "w:val": true } } }] }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -103,7 +128,7 @@ describe("Run", () => {
|
|||||||
});
|
});
|
||||||
const tree = new Formatter().format(run);
|
const tree = new Formatter().format(run);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:r": [{ "w:rPr": [{ "w:caps": {} }] }],
|
"w:r": [{ "w:rPr": [{ "w:caps": { _attr: { "w:val": true } } }] }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -235,7 +260,42 @@ describe("Run", () => {
|
|||||||
"w:r": [
|
"w:r": [
|
||||||
{
|
{
|
||||||
"w:rPr": [
|
"w:rPr": [
|
||||||
{ "w:rFonts": { _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } } },
|
{
|
||||||
|
"w:rFonts": {
|
||||||
|
_attr: {
|
||||||
|
"w:ascii": "Times",
|
||||||
|
"w:cs": "Times",
|
||||||
|
"w:eastAsia": "Times",
|
||||||
|
"w:hAnsi": "Times",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the font for ascii and eastAsia", () => {
|
||||||
|
const run = new Run({
|
||||||
|
font: {
|
||||||
|
ascii: "Times",
|
||||||
|
eastAsia: "KaiTi",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(run);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:rFonts": {
|
||||||
|
_attr: {
|
||||||
|
"w:ascii": "Times",
|
||||||
|
"w:eastAsia": "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -1,63 +1,15 @@
|
|||||||
// http://officeopenxml.com/WPtext.php
|
// http://officeopenxml.com/WPtext.php
|
||||||
import { ShadingType } from "file/table";
|
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
||||||
import { FieldInstruction } from "file/table-of-contents/field-instruction";
|
import { FieldInstruction } from "file/table-of-contents/field-instruction";
|
||||||
import { Break } from "./break";
|
import { Break } from "./break";
|
||||||
import { Caps, SmallCaps } from "./caps";
|
|
||||||
import { Begin, End, Separate } from "./field";
|
import { Begin, End, Separate } from "./field";
|
||||||
import {
|
|
||||||
Bold,
|
|
||||||
BoldComplexScript,
|
|
||||||
Color,
|
|
||||||
DoubleStrike,
|
|
||||||
Highlight,
|
|
||||||
HighlightComplexScript,
|
|
||||||
Italics,
|
|
||||||
ItalicsComplexScript,
|
|
||||||
RightToLeft,
|
|
||||||
Shading,
|
|
||||||
ShadowComplexScript,
|
|
||||||
Size,
|
|
||||||
SizeComplexScript,
|
|
||||||
Strike,
|
|
||||||
} from "./formatting";
|
|
||||||
import { NumberOfPages, NumberOfPagesSection, Page } from "./page-number";
|
import { NumberOfPages, NumberOfPagesSection, Page } from "./page-number";
|
||||||
import { RunProperties } from "./properties";
|
import { IRunPropertiesOptions, RunProperties } from "./properties";
|
||||||
import { Text } from "./run-components/text";
|
import { Text } from "./run-components/text";
|
||||||
import { RunFonts } from "./run-fonts";
|
|
||||||
import { SubScript, SuperScript } from "./script";
|
|
||||||
import { Style } from "./style";
|
|
||||||
import { Underline, UnderlineType } from "./underline";
|
|
||||||
|
|
||||||
export interface IRunOptions {
|
export interface IRunOptions extends IRunPropertiesOptions {
|
||||||
readonly bold?: true;
|
|
||||||
readonly italics?: true;
|
|
||||||
readonly underline?: {
|
|
||||||
readonly color?: string;
|
|
||||||
readonly type?: UnderlineType;
|
|
||||||
};
|
|
||||||
readonly color?: string;
|
|
||||||
readonly size?: number;
|
|
||||||
readonly rightToLeft?: boolean;
|
|
||||||
readonly smallCaps?: boolean;
|
|
||||||
readonly allCaps?: boolean;
|
|
||||||
readonly strike?: boolean;
|
|
||||||
readonly doubleStrike?: boolean;
|
|
||||||
readonly subScript?: boolean;
|
|
||||||
readonly superScript?: boolean;
|
|
||||||
readonly style?: string;
|
|
||||||
readonly font?: {
|
|
||||||
readonly name: string;
|
|
||||||
readonly hint?: string;
|
|
||||||
};
|
|
||||||
readonly highlight?: string;
|
|
||||||
readonly shading?: {
|
|
||||||
readonly type: ShadingType;
|
|
||||||
readonly fill: string;
|
|
||||||
readonly color: string;
|
|
||||||
};
|
|
||||||
readonly children?: Array<Begin | FieldInstruction | Separate | End | PageNumber | FootnoteReferenceRun | string>;
|
readonly children?: Array<Begin | FieldInstruction | Separate | End | PageNumber | FootnoteReferenceRun | string>;
|
||||||
readonly text?: string;
|
readonly text?: string;
|
||||||
}
|
}
|
||||||
@ -73,78 +25,9 @@ export class Run extends XmlComponent {
|
|||||||
|
|
||||||
constructor(options: IRunOptions) {
|
constructor(options: IRunOptions) {
|
||||||
super("w:r");
|
super("w:r");
|
||||||
this.properties = new RunProperties();
|
this.properties = new RunProperties(options);
|
||||||
this.root.push(this.properties);
|
this.root.push(this.properties);
|
||||||
|
|
||||||
if (options.bold) {
|
|
||||||
this.properties.push(new Bold());
|
|
||||||
this.properties.push(new BoldComplexScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.italics) {
|
|
||||||
this.properties.push(new Italics());
|
|
||||||
this.properties.push(new ItalicsComplexScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.underline) {
|
|
||||||
this.properties.push(new Underline(options.underline.type, options.underline.color));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.color) {
|
|
||||||
this.properties.push(new Color(options.color));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.size) {
|
|
||||||
this.properties.push(new Size(options.size));
|
|
||||||
this.properties.push(new SizeComplexScript(options.size));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.rightToLeft) {
|
|
||||||
this.properties.push(new RightToLeft());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.smallCaps) {
|
|
||||||
this.properties.push(new SmallCaps());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.allCaps) {
|
|
||||||
this.properties.push(new Caps());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.strike) {
|
|
||||||
this.properties.push(new Strike());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.doubleStrike) {
|
|
||||||
this.properties.push(new DoubleStrike());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.subScript) {
|
|
||||||
this.properties.push(new SubScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.superScript) {
|
|
||||||
this.properties.push(new SuperScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.style) {
|
|
||||||
this.properties.push(new Style(options.style));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.font) {
|
|
||||||
this.properties.push(new RunFonts(options.font.name, options.font.hint));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.highlight) {
|
|
||||||
this.properties.push(new Highlight(options.highlight));
|
|
||||||
this.properties.push(new HighlightComplexScript(options.highlight));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.shading) {
|
|
||||||
this.properties.push(new Shading(options.shading.type, options.shading.fill, options.shading.color));
|
|
||||||
this.properties.push(new ShadowComplexScript(options.shading.type, options.shading.fill, options.shading.color));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.children) {
|
if (options.children) {
|
||||||
for (const child of options.children) {
|
for (const child of options.children) {
|
||||||
if (typeof child === "string") {
|
if (typeof child === "string") {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { EmphasisMarkType } from "./emphasis-mark";
|
||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
import { UnderlineType } from "./underline";
|
import { UnderlineType } from "./underline";
|
||||||
@ -44,6 +46,9 @@ describe("SymbolRun", () => {
|
|||||||
color: "red",
|
color: "red",
|
||||||
type: UnderlineType.DOUBLE,
|
type: UnderlineType.DOUBLE,
|
||||||
},
|
},
|
||||||
|
emphasisMark: {
|
||||||
|
type: EmphasisMarkType.DOT,
|
||||||
|
},
|
||||||
color: "green",
|
color: "green",
|
||||||
size: 40,
|
size: 40,
|
||||||
highlight: "yellow",
|
highlight: "yellow",
|
||||||
@ -59,6 +64,7 @@ describe("SymbolRun", () => {
|
|||||||
{ "w:i": { _attr: { "w:val": true } } },
|
{ "w:i": { _attr: { "w:val": true } } },
|
||||||
{ "w:iCs": { _attr: { "w:val": true } } },
|
{ "w:iCs": { _attr: { "w:val": true } } },
|
||||||
{ "w:u": { _attr: { "w:val": "double", "w:color": "red" } } },
|
{ "w:u": { _attr: { "w:val": "double", "w:color": "red" } } },
|
||||||
|
{ "w:em": { _attr: { "w:val": "dot" } } },
|
||||||
{ "w:color": { _attr: { "w:val": "green" } } },
|
{ "w:color": { _attr: { "w:val": "green" } } },
|
||||||
{ "w:sz": { _attr: { "w:val": 40 } } },
|
{ "w:sz": { _attr: { "w:val": 40 } } },
|
||||||
{ "w:szCs": { _attr: { "w:val": 40 } } },
|
{ "w:szCs": { _attr: { "w:val": 40 } } },
|
||||||
|
45
src/file/styles/defaults/document-defaults.spec.ts
Normal file
45
src/file/styles/defaults/document-defaults.spec.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { DocumentDefaults } from "./document-defaults";
|
||||||
|
|
||||||
|
import { Formatter } from "export/formatter";
|
||||||
|
|
||||||
|
describe("DocumentDefaults", () => {
|
||||||
|
it("#constructor", () => {
|
||||||
|
const defaults = new DocumentDefaults({
|
||||||
|
paragraph: { spacing: { line: 240 } },
|
||||||
|
run: { color: "808080" },
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(defaults);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:docDefaults": [
|
||||||
|
{
|
||||||
|
"w:rPrDefault": [
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:color": { _attr: { "w:val": "808080" } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:pPrDefault": [
|
||||||
|
{
|
||||||
|
"w:pPr": [
|
||||||
|
{
|
||||||
|
"w:spacing": {
|
||||||
|
_attr: {
|
||||||
|
"w:line": 240,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
25
src/file/styles/defaults/document-defaults.ts
Normal file
25
src/file/styles/defaults/document-defaults.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { IParagraphStylePropertiesOptions } from "file/paragraph/properties";
|
||||||
|
import { IRunStylePropertiesOptions } from "file/paragraph/run/properties";
|
||||||
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
import { ParagraphPropertiesDefaults } from "./paragraph-properties";
|
||||||
|
import { RunPropertiesDefaults } from "./run-properties";
|
||||||
|
|
||||||
|
export interface IDocumentDefaultsOptions {
|
||||||
|
readonly paragraph?: IParagraphStylePropertiesOptions;
|
||||||
|
readonly run?: IRunStylePropertiesOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DocumentDefaults extends XmlComponent {
|
||||||
|
private readonly runPropertiesDefaults: RunPropertiesDefaults;
|
||||||
|
private readonly paragraphPropertiesDefaults: ParagraphPropertiesDefaults;
|
||||||
|
|
||||||
|
constructor(options?: IDocumentDefaultsOptions) {
|
||||||
|
super("w:docDefaults");
|
||||||
|
|
||||||
|
this.runPropertiesDefaults = new RunPropertiesDefaults(options && options.run);
|
||||||
|
this.paragraphPropertiesDefaults = new ParagraphPropertiesDefaults(options && options.paragraph);
|
||||||
|
|
||||||
|
this.root.push(this.runPropertiesDefaults);
|
||||||
|
this.root.push(this.paragraphPropertiesDefaults);
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,3 @@
|
|||||||
import { XmlComponent } from "file/xml-components";
|
export * from "./paragraph-properties";
|
||||||
import { ParagraphPropertiesDefaults } from "./paragraph-properties";
|
export * from "./run-properties";
|
||||||
import { RunPropertiesDefaults } from "./run-properties";
|
export * from "./document-defaults";
|
||||||
|
|
||||||
export class DocumentDefaults extends XmlComponent {
|
|
||||||
private readonly runPropertiesDefaults: RunPropertiesDefaults;
|
|
||||||
private readonly paragraphPropertiesDefaults: ParagraphPropertiesDefaults;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super("w:docDefaults");
|
|
||||||
this.runPropertiesDefaults = new RunPropertiesDefaults();
|
|
||||||
this.paragraphPropertiesDefaults = new ParagraphPropertiesDefaults();
|
|
||||||
this.root.push(this.runPropertiesDefaults);
|
|
||||||
this.root.push(this.paragraphPropertiesDefaults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { ParagraphProperties } from "file/paragraph/properties";
|
import { IParagraphStylePropertiesOptions, ParagraphProperties } from "file/paragraph/properties";
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
export class ParagraphPropertiesDefaults extends XmlComponent {
|
export class ParagraphPropertiesDefaults extends XmlComponent {
|
||||||
constructor() {
|
constructor(options?: IParagraphStylePropertiesOptions) {
|
||||||
super("w:pPrDefault");
|
super("w:pPrDefault");
|
||||||
this.root.push(new ParagraphProperties({}));
|
this.root.push(new ParagraphProperties(options));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,12 @@
|
|||||||
import { Size, SizeComplexScript } from "file/paragraph/run/formatting";
|
import { IRunStylePropertiesOptions, RunProperties } from "file/paragraph/run/properties";
|
||||||
import { RunProperties } from "file/paragraph/run/properties";
|
|
||||||
import { RunFonts } from "file/paragraph/run/run-fonts";
|
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
export class RunPropertiesDefaults extends XmlComponent {
|
export class RunPropertiesDefaults extends XmlComponent {
|
||||||
private readonly properties: RunProperties;
|
private readonly properties: RunProperties;
|
||||||
|
|
||||||
constructor() {
|
constructor(options?: IRunStylePropertiesOptions) {
|
||||||
super("w:rPrDefault");
|
super("w:rPrDefault");
|
||||||
this.properties = new RunProperties();
|
this.properties = new RunProperties(options);
|
||||||
this.root.push(this.properties);
|
this.root.push(this.properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
public size(size: number): RunPropertiesDefaults {
|
|
||||||
this.properties.push(new Size(size));
|
|
||||||
this.properties.push(new SizeComplexScript(size));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public font(fontName: string): RunPropertiesDefaults {
|
|
||||||
this.properties.push(new RunFonts(fontName));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export * from "./styles";
|
export * from "./styles";
|
||||||
export * from "./style/character-style";
|
export * from "./style/character-style";
|
||||||
export * from "./style/paragraph-style";
|
export * from "./style/paragraph-style";
|
||||||
export * from "./style-options";
|
export * from "./defaults";
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
import { AlignmentType, IIndentAttributesProperties, ISpacingProperties, UnderlineType } from "../paragraph";
|
|
||||||
import { ShadingType } from "../table";
|
|
||||||
|
|
||||||
export interface IRunStyleOptions {
|
|
||||||
readonly size?: number;
|
|
||||||
readonly bold?: boolean;
|
|
||||||
readonly italics?: boolean;
|
|
||||||
readonly smallCaps?: boolean;
|
|
||||||
readonly allCaps?: boolean;
|
|
||||||
readonly strike?: boolean;
|
|
||||||
readonly doubleStrike?: boolean;
|
|
||||||
readonly subScript?: boolean;
|
|
||||||
readonly superScript?: boolean;
|
|
||||||
readonly underline?: {
|
|
||||||
readonly type?: UnderlineType;
|
|
||||||
readonly color?: string;
|
|
||||||
};
|
|
||||||
readonly color?: string;
|
|
||||||
readonly font?: string;
|
|
||||||
readonly characterSpacing?: number;
|
|
||||||
readonly highlight?: string;
|
|
||||||
readonly shadow?: {
|
|
||||||
readonly type: ShadingType;
|
|
||||||
readonly fill: string;
|
|
||||||
readonly color: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IParagraphStyleOptions2 {
|
|
||||||
readonly alignment?: AlignmentType;
|
|
||||||
readonly thematicBreak?: boolean;
|
|
||||||
readonly contextualSpacing?: boolean;
|
|
||||||
readonly rightTabStop?: number;
|
|
||||||
readonly leftTabStop?: number;
|
|
||||||
readonly indent?: IIndentAttributesProperties;
|
|
||||||
readonly spacing?: ISpacingProperties;
|
|
||||||
readonly keepNext?: boolean;
|
|
||||||
readonly keepLines?: boolean;
|
|
||||||
readonly outlineLevel?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432
|
|
||||||
/**
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
export const WORKAROUND4 = "";
|
|
@ -1,6 +1,7 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
|
import { EmphasisMarkType } from "file/paragraph/run/emphasis-mark";
|
||||||
import { UnderlineType } from "file/paragraph/run/underline";
|
import { UnderlineType } from "file/paragraph/run/underline";
|
||||||
import { ShadingType } from "file/table";
|
import { ShadingType } from "file/table";
|
||||||
import { EMPTY_OBJECT } from "file/xml-components";
|
import { EMPTY_OBJECT } from "file/xml-components";
|
||||||
@ -201,7 +202,7 @@ describe("CharacterStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should add font", () => {
|
it("should add font by name", () => {
|
||||||
const style = new CharacterStyle({
|
const style = new CharacterStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
run: {
|
run: {
|
||||||
@ -240,6 +241,46 @@ describe("CharacterStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should add font for ascii and eastAsia", () => {
|
||||||
|
const style = new CharacterStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: {
|
||||||
|
font: {
|
||||||
|
ascii: "test font ascii",
|
||||||
|
eastAsia: "test font eastAsia",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:rFonts": {
|
||||||
|
_attr: {
|
||||||
|
"w:ascii": "test font ascii",
|
||||||
|
"w:eastAsia": "test font eastAsia",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": 99,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("should add character spacing", () => {
|
it("should add character spacing", () => {
|
||||||
const style = new CharacterStyle({
|
const style = new CharacterStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
@ -293,19 +334,39 @@ describe("CharacterStyle", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("formatting methods: run properties", () => {
|
describe("formatting methods: run properties", () => {
|
||||||
it("#size", () => {
|
const sizeTests = [
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
sizeComplexScript: true,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
sizeComplexScript: false,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
sizeComplexScript: 26,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 26 } } }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
sizeTests.forEach(({ size, sizeComplexScript, expected }) => {
|
||||||
|
it(`#size ${size} cs ${sizeComplexScript}`, () => {
|
||||||
const style = new CharacterStyle({
|
const style = new CharacterStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
run: {
|
run: { size, sizeComplexScript },
|
||||||
size: 24,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [
|
"w:style": [
|
||||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
{
|
{
|
||||||
"w:rPr": [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }],
|
"w:rPr": expected,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"w:uiPriority": {
|
"w:uiPriority": {
|
||||||
@ -320,6 +381,7 @@ describe("CharacterStyle", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("#underline", () => {
|
describe("#underline", () => {
|
||||||
it("should set underline to 'single' if no arguments are given", () => {
|
it("should set underline to 'single' if no arguments are given", () => {
|
||||||
@ -412,6 +474,66 @@ describe("CharacterStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#emphasisMark", () => {
|
||||||
|
it("should set emphasisMark to 'dot' if no arguments are given", () => {
|
||||||
|
const style = new CharacterStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: {
|
||||||
|
emphasisMark: {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": 99,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the style if given", () => {
|
||||||
|
const style = new CharacterStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: {
|
||||||
|
emphasisMark: {
|
||||||
|
type: EmphasisMarkType.DOT,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:uiPriority": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": 99,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:unhideWhenUsed": EMPTY_OBJECT,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("#superScript", () => {
|
it("#superScript", () => {
|
||||||
const style = new CharacterStyle({
|
const style = new CharacterStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
@ -476,19 +598,34 @@ describe("CharacterStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#bold", () => {
|
const boldTests = [
|
||||||
|
{
|
||||||
|
bold: true,
|
||||||
|
expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bold: true,
|
||||||
|
boldComplexScript: true,
|
||||||
|
expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bold: true,
|
||||||
|
boldComplexScript: false,
|
||||||
|
expected: [{ "w:b": { _attr: { "w:val": true } } }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
boldTests.forEach(({ bold, boldComplexScript, expected }) => {
|
||||||
|
it(`#bold ${bold} cs ${boldComplexScript}`, () => {
|
||||||
const style = new CharacterStyle({
|
const style = new CharacterStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
run: {
|
run: { bold, boldComplexScript },
|
||||||
bold: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [
|
"w:style": [
|
||||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
{
|
{
|
||||||
"w:rPr": [{ "w:b": { _attr: { "w:val": true } } }],
|
"w:rPr": expected,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"w:uiPriority": {
|
"w:uiPriority": {
|
||||||
@ -503,20 +640,36 @@ describe("CharacterStyle", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("#italics", () => {
|
const italicsTests = [
|
||||||
|
{
|
||||||
|
italics: true,
|
||||||
|
expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
italics: true,
|
||||||
|
italicsComplexScript: true,
|
||||||
|
expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
italics: true,
|
||||||
|
italicsComplexScript: false,
|
||||||
|
expected: [{ "w:i": { _attr: { "w:val": true } } }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
italicsTests.forEach(({ italics, italicsComplexScript, expected }) => {
|
||||||
|
it(`#italics ${italics} cs ${italicsComplexScript}`, () => {
|
||||||
const style = new CharacterStyle({
|
const style = new CharacterStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
run: {
|
run: { italics, italicsComplexScript },
|
||||||
italics: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [
|
"w:style": [
|
||||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
{
|
{
|
||||||
"w:rPr": [{ "w:i": { _attr: { "w:val": true } } }],
|
"w:rPr": expected,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"w:uiPriority": {
|
"w:uiPriority": {
|
||||||
@ -531,6 +684,7 @@ describe("CharacterStyle", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("#link", () => {
|
it("#link", () => {
|
||||||
const style = new CharacterStyle({ id: "myStyleId", link: "MyLink" });
|
const style = new CharacterStyle({ id: "myStyleId", link: "MyLink" });
|
||||||
@ -572,19 +726,39 @@ describe("CharacterStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#highlight", () => {
|
const highlightTests = [
|
||||||
|
{
|
||||||
|
highlight: "005599",
|
||||||
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
highlight: "005599",
|
||||||
|
highlightComplexScript: true,
|
||||||
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
highlight: "005599",
|
||||||
|
highlightComplexScript: false,
|
||||||
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
highlight: "005599",
|
||||||
|
highlightComplexScript: "550099",
|
||||||
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "550099" } } }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
highlightTests.forEach(({ highlight, highlightComplexScript, expected }) => {
|
||||||
|
it(`#highlight ${highlight} cs ${highlightComplexScript}`, () => {
|
||||||
const style = new CharacterStyle({
|
const style = new CharacterStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
run: {
|
run: { highlight, highlightComplexScript },
|
||||||
highlight: "005599",
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [
|
"w:style": [
|
||||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
{
|
{
|
||||||
"w:rPr": [{ "w:highlight": { _attr: { "w:val": "005599" } } }],
|
"w:rPr": expected,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"w:uiPriority": {
|
"w:uiPriority": {
|
||||||
@ -599,24 +773,81 @@ describe("CharacterStyle", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("#shadow", () => {
|
const shadingTests = [
|
||||||
const style = new CharacterStyle({
|
{
|
||||||
id: "myStyleId",
|
|
||||||
run: {
|
|
||||||
shadow: {
|
shadow: {
|
||||||
type: ShadingType.PERCENT_10,
|
type: ShadingType.PERCENT_10,
|
||||||
fill: "00FFFF",
|
fill: "00FFFF",
|
||||||
color: "FF0000",
|
color: "FF0000",
|
||||||
},
|
},
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
shadingComplexScript: true,
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
shadingComplexScript: false,
|
||||||
|
expected: [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
shadingComplexScript: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "00FF00",
|
||||||
|
},
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "00FF00" } } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
shadingTests.forEach(({ shadow, shading, shadingComplexScript, expected }) => {
|
||||||
|
it("#shadow correctly", () => {
|
||||||
|
const style = new CharacterStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: { shadow, shading, shadingComplexScript },
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [
|
"w:style": [
|
||||||
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
{ _attr: { "w:type": "character", "w:styleId": "myStyleId" } },
|
||||||
{
|
{
|
||||||
"w:rPr": [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }],
|
"w:rPr": expected,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"w:uiPriority": {
|
"w:uiPriority": {
|
||||||
@ -633,3 +864,4 @@ describe("CharacterStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import * as formatting from "file/paragraph/run/formatting";
|
import { IRunStylePropertiesOptions, RunProperties } from "file/paragraph/run/properties";
|
||||||
import { RunProperties } from "file/paragraph/run/properties";
|
|
||||||
import { UnderlineType } from "file/paragraph/run/underline";
|
|
||||||
|
|
||||||
import { BasedOn, Link, SemiHidden, UiPriority, UnhideWhenUsed } from "./components";
|
import { BasedOn, Link, SemiHidden, UiPriority, UnhideWhenUsed } from "./components";
|
||||||
import { Style } from "./style";
|
import { Style } from "./style";
|
||||||
@ -9,30 +7,7 @@ export interface IBaseCharacterStyleOptions {
|
|||||||
readonly basedOn?: string;
|
readonly basedOn?: string;
|
||||||
readonly link?: string;
|
readonly link?: string;
|
||||||
readonly semiHidden?: boolean;
|
readonly semiHidden?: boolean;
|
||||||
readonly run?: {
|
readonly run?: IRunStylePropertiesOptions;
|
||||||
readonly size?: number;
|
|
||||||
readonly bold?: boolean;
|
|
||||||
readonly italics?: boolean;
|
|
||||||
readonly smallCaps?: boolean;
|
|
||||||
readonly allCaps?: boolean;
|
|
||||||
readonly strike?: boolean;
|
|
||||||
readonly doubleStrike?: boolean;
|
|
||||||
readonly subScript?: boolean;
|
|
||||||
readonly superScript?: boolean;
|
|
||||||
readonly underline?: {
|
|
||||||
readonly type?: UnderlineType;
|
|
||||||
readonly color?: string;
|
|
||||||
};
|
|
||||||
readonly color?: string;
|
|
||||||
readonly font?: string;
|
|
||||||
readonly characterSpacing?: number;
|
|
||||||
readonly highlight?: string;
|
|
||||||
readonly shadow?: {
|
|
||||||
readonly type: string;
|
|
||||||
readonly fill: string;
|
|
||||||
readonly color: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICharacterStyleOptions extends IBaseCharacterStyleOptions {
|
export interface ICharacterStyleOptions extends IBaseCharacterStyleOptions {
|
||||||
@ -45,7 +20,9 @@ export class CharacterStyle extends Style {
|
|||||||
|
|
||||||
constructor(options: ICharacterStyleOptions) {
|
constructor(options: ICharacterStyleOptions) {
|
||||||
super({ type: "character", styleId: options.id }, options.name);
|
super({ type: "character", styleId: options.id }, options.name);
|
||||||
this.runProperties = new RunProperties();
|
|
||||||
|
this.runProperties = new RunProperties(options.run);
|
||||||
|
|
||||||
this.root.push(this.runProperties);
|
this.root.push(this.runProperties);
|
||||||
this.root.push(new UiPriority(99));
|
this.root.push(new UiPriority(99));
|
||||||
this.root.push(new UnhideWhenUsed());
|
this.root.push(new UnhideWhenUsed());
|
||||||
@ -61,68 +38,5 @@ export class CharacterStyle extends Style {
|
|||||||
if (options.semiHidden) {
|
if (options.semiHidden) {
|
||||||
this.root.push(new SemiHidden());
|
this.root.push(new SemiHidden());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.run) {
|
|
||||||
if (options.run.size) {
|
|
||||||
this.runProperties.push(new formatting.Size(options.run.size));
|
|
||||||
this.runProperties.push(new formatting.SizeComplexScript(options.run.size));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.bold) {
|
|
||||||
this.runProperties.push(new formatting.Bold());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.italics) {
|
|
||||||
this.runProperties.push(new formatting.Italics());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.smallCaps) {
|
|
||||||
this.runProperties.push(new formatting.SmallCaps());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.allCaps) {
|
|
||||||
this.runProperties.push(new formatting.Caps());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.strike) {
|
|
||||||
this.runProperties.push(new formatting.Strike());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.doubleStrike) {
|
|
||||||
this.runProperties.push(new formatting.DoubleStrike());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.subScript) {
|
|
||||||
this.runProperties.push(new formatting.SubScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.superScript) {
|
|
||||||
this.runProperties.push(new formatting.SuperScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.underline) {
|
|
||||||
this.runProperties.push(new formatting.Underline(options.run.underline.type, options.run.underline.color));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.color) {
|
|
||||||
this.runProperties.push(new formatting.Color(options.run.color));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.font) {
|
|
||||||
this.runProperties.push(new formatting.RunFonts(options.run.font));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.characterSpacing) {
|
|
||||||
this.runProperties.push(new formatting.CharacterSpacing(options.run.characterSpacing));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.highlight) {
|
|
||||||
this.runProperties.push(new formatting.Highlight(options.run.highlight));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.shadow) {
|
|
||||||
this.runProperties.push(new formatting.Shading(options.run.shadow.type, options.run.shadow.fill, options.run.shadow.color));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { Formatter } from "export/formatter";
|
import { Formatter } from "export/formatter";
|
||||||
import { AlignmentType, TabStopPosition } from "file/paragraph";
|
import { AlignmentType, EmphasisMarkType, TabStopPosition } from "file/paragraph";
|
||||||
import { UnderlineType } from "file/paragraph/run/underline";
|
import { UnderlineType } from "file/paragraph/run/underline";
|
||||||
import { ShadingType } from "file/table";
|
import { ShadingType } from "file/table";
|
||||||
import { EMPTY_OBJECT } from "file/xml-components";
|
import { EMPTY_OBJECT } from "file/xml-components";
|
||||||
@ -49,7 +49,15 @@ describe("ParagraphStyle", () => {
|
|||||||
const style = new ParagraphStyle({ id: "myStyleId", quickFormat: true });
|
const style = new ParagraphStyle({ id: "myStyleId", quickFormat: true });
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:qFormat": EMPTY_OBJECT }],
|
"w:style": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:type": "paragraph",
|
||||||
|
"w:styleId": "myStyleId",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ "w:qFormat": EMPTY_OBJECT },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -299,7 +307,15 @@ describe("ParagraphStyle", () => {
|
|||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:pPr": [{ "w:keepLines": EMPTY_OBJECT }] }],
|
"w:style": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:type": "paragraph",
|
||||||
|
"w:styleId": "myStyleId",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ "w:pPr": [{ "w:keepLines": EMPTY_OBJECT }] },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -312,7 +328,15 @@ describe("ParagraphStyle", () => {
|
|||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:pPr": [{ "w:keepNext": EMPTY_OBJECT }] }],
|
"w:style": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:type": "paragraph",
|
||||||
|
"w:styleId": "myStyleId",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ "w:pPr": [{ "w:keepNext": EMPTY_OBJECT }] },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -334,21 +358,37 @@ describe("ParagraphStyle", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("formatting methods: run properties", () => {
|
describe("formatting methods: run properties", () => {
|
||||||
it("#size", () => {
|
const sizeTests = [
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
sizeComplexScript: true,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
sizeComplexScript: false,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: 24,
|
||||||
|
sizeComplexScript: 26,
|
||||||
|
expected: [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 26 } } }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
sizeTests.forEach(({ size, sizeComplexScript, expected }) => {
|
||||||
|
it(`#size ${size} cs ${sizeComplexScript}`, () => {
|
||||||
const style = new ParagraphStyle({
|
const style = new ParagraphStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
run: {
|
run: { size, sizeComplexScript },
|
||||||
size: 24,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [
|
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:rPr": expected }],
|
||||||
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
});
|
||||||
{
|
|
||||||
"w:rPr": [{ "w:sz": { _attr: { "w:val": 24 } } }, { "w:szCs": { _attr: { "w:val": 24 } } }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -460,7 +500,7 @@ describe("ParagraphStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#font", () => {
|
it("#font by name", () => {
|
||||||
const style = new ParagraphStyle({
|
const style = new ParagraphStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
run: {
|
run: {
|
||||||
@ -473,86 +513,215 @@ describe("ParagraphStyle", () => {
|
|||||||
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
{
|
{
|
||||||
"w:rPr": [
|
"w:rPr": [
|
||||||
{ "w:rFonts": { _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } } },
|
{
|
||||||
|
"w:rFonts": {
|
||||||
|
_attr: {
|
||||||
|
"w:ascii": "Times",
|
||||||
|
"w:cs": "Times",
|
||||||
|
"w:eastAsia": "Times",
|
||||||
|
"w:hAnsi": "Times",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#bold", () => {
|
it("#font for ascii and eastAsia", () => {
|
||||||
const style = new ParagraphStyle({
|
const style = new ParagraphStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
run: {
|
run: {
|
||||||
|
font: {
|
||||||
|
ascii: "Times",
|
||||||
|
eastAsia: "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [
|
||||||
|
{
|
||||||
|
"w:rFonts": {
|
||||||
|
_attr: {
|
||||||
|
"w:ascii": "Times",
|
||||||
|
"w:eastAsia": "KaiTi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const boldTests = [
|
||||||
|
{
|
||||||
bold: true,
|
bold: true,
|
||||||
|
expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
bold: true,
|
||||||
|
boldComplexScript: true,
|
||||||
|
expected: [{ "w:b": { _attr: { "w:val": true } } }, { "w:bCs": { _attr: { "w:val": true } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bold: true,
|
||||||
|
boldComplexScript: false,
|
||||||
|
expected: [{ "w:b": { _attr: { "w:val": true } } }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
boldTests.forEach(({ bold, boldComplexScript, expected }) => {
|
||||||
|
it(`#bold ${bold} cs ${boldComplexScript}`, () => {
|
||||||
|
const style = new ParagraphStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: { bold, boldComplexScript },
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [
|
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:rPr": expected }],
|
||||||
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
});
|
||||||
{
|
|
||||||
"w:rPr": [{ "w:b": { _attr: { "w:val": true } } }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#italics", () => {
|
const italicsTests = [
|
||||||
const style = new ParagraphStyle({
|
{
|
||||||
id: "myStyleId",
|
|
||||||
run: {
|
|
||||||
italics: true,
|
italics: true,
|
||||||
|
expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
italics: true,
|
||||||
|
italicsComplexScript: true,
|
||||||
|
expected: [{ "w:i": { _attr: { "w:val": true } } }, { "w:iCs": { _attr: { "w:val": true } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
italics: true,
|
||||||
|
italicsComplexScript: false,
|
||||||
|
expected: [{ "w:i": { _attr: { "w:val": true } } }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
italicsTests.forEach(({ italics, italicsComplexScript, expected }) => {
|
||||||
|
it(`#italics ${italics} cs ${italicsComplexScript}`, () => {
|
||||||
|
const style = new ParagraphStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: { italics, italicsComplexScript },
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [
|
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:rPr": expected }],
|
||||||
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
});
|
||||||
{
|
|
||||||
"w:rPr": [{ "w:i": { _attr: { "w:val": true } } }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#highlight", () => {
|
const highlightTests = [
|
||||||
const style = new ParagraphStyle({
|
{
|
||||||
id: "myStyleId",
|
|
||||||
run: {
|
|
||||||
highlight: "005599",
|
highlight: "005599",
|
||||||
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
highlight: "005599",
|
||||||
|
highlightComplexScript: true,
|
||||||
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "005599" } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
highlight: "005599",
|
||||||
|
highlightComplexScript: false,
|
||||||
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
highlight: "005599",
|
||||||
|
highlightComplexScript: "550099",
|
||||||
|
expected: [{ "w:highlight": { _attr: { "w:val": "005599" } } }, { "w:highlightCs": { _attr: { "w:val": "550099" } } }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
highlightTests.forEach(({ highlight, highlightComplexScript, expected }) => {
|
||||||
|
it(`#highlight ${highlight} cs ${highlightComplexScript}`, () => {
|
||||||
|
const style = new ParagraphStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: { highlight, highlightComplexScript },
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [
|
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:rPr": expected }],
|
||||||
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
});
|
||||||
{
|
|
||||||
"w:rPr": [{ "w:highlight": { _attr: { "w:val": "005599" } } }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("#shadow", () => {
|
const shadingTests = [
|
||||||
const style = new ParagraphStyle({
|
{
|
||||||
id: "myStyleId",
|
|
||||||
run: {
|
|
||||||
shadow: {
|
shadow: {
|
||||||
type: ShadingType.PERCENT_10,
|
type: ShadingType.PERCENT_10,
|
||||||
fill: "00FFFF",
|
fill: "00FFFF",
|
||||||
color: "FF0000",
|
color: "FF0000",
|
||||||
},
|
},
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
shadingComplexScript: true,
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
shadingComplexScript: false,
|
||||||
|
expected: [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shading: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "FF0000",
|
||||||
|
},
|
||||||
|
shadingComplexScript: {
|
||||||
|
type: ShadingType.PERCENT_10,
|
||||||
|
fill: "00FFFF",
|
||||||
|
color: "00FF00",
|
||||||
|
},
|
||||||
|
expected: [
|
||||||
|
{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } },
|
||||||
|
{ "w:shdCs": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "00FF00" } } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
shadingTests.forEach(({ shadow, shading, shadingComplexScript, expected }) => {
|
||||||
|
it("#shadow correctly", () => {
|
||||||
|
const style = new ParagraphStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: { shadow, shading, shadingComplexScript },
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [
|
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:rPr": expected }],
|
||||||
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
});
|
||||||
{
|
|
||||||
"w:rPr": [{ "w:shd": { _attr: { "w:val": "pct10", "w:fill": "00FFFF", "w:color": "FF0000" } } }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -617,6 +786,46 @@ describe("ParagraphStyle", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#emphasisMark", () => {
|
||||||
|
it("should set emphasisMark to 'dot' if no arguments are given", () => {
|
||||||
|
const style = new ParagraphStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: {
|
||||||
|
emphasisMark: {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the style if given", () => {
|
||||||
|
const style = new ParagraphStyle({
|
||||||
|
id: "myStyleId",
|
||||||
|
run: {
|
||||||
|
emphasisMark: {
|
||||||
|
type: EmphasisMarkType.DOT,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(style);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:style": [
|
||||||
|
{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
|
||||||
|
{
|
||||||
|
"w:rPr": [{ "w:em": { _attr: { "w:val": "dot" } } }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("#color", () => {
|
it("#color", () => {
|
||||||
const style = new ParagraphStyle({
|
const style = new ParagraphStyle({
|
||||||
id: "myStyleId",
|
id: "myStyleId",
|
||||||
@ -639,7 +848,15 @@ describe("ParagraphStyle", () => {
|
|||||||
const style = new ParagraphStyle({ id: "myStyleId", link: "MyLink" });
|
const style = new ParagraphStyle({ id: "myStyleId", link: "MyLink" });
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:link": { _attr: { "w:val": "MyLink" } } }],
|
"w:style": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:type": "paragraph",
|
||||||
|
"w:styleId": "myStyleId",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ "w:link": { _attr: { "w:val": "MyLink" } } },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -647,7 +864,15 @@ describe("ParagraphStyle", () => {
|
|||||||
const style = new ParagraphStyle({ id: "myStyleId", semiHidden: true });
|
const style = new ParagraphStyle({ id: "myStyleId", semiHidden: true });
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:semiHidden": EMPTY_OBJECT }],
|
"w:style": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:type": "paragraph",
|
||||||
|
"w:styleId": "myStyleId",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ "w:semiHidden": EMPTY_OBJECT },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -672,7 +897,15 @@ describe("ParagraphStyle", () => {
|
|||||||
const style = new ParagraphStyle({ id: "myStyleId", unhideWhenUsed: true });
|
const style = new ParagraphStyle({ id: "myStyleId", unhideWhenUsed: true });
|
||||||
const tree = new Formatter().format(style);
|
const tree = new Formatter().format(style);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:style": [{ _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } }, { "w:unhideWhenUsed": EMPTY_OBJECT }],
|
"w:style": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:type": "paragraph",
|
||||||
|
"w:styleId": "myStyleId",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ "w:unhideWhenUsed": EMPTY_OBJECT },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,19 +1,6 @@
|
|||||||
import {
|
import { IParagraphStylePropertiesOptions, IRunStylePropertiesOptions, ParagraphProperties } from "file/paragraph";
|
||||||
Alignment,
|
|
||||||
ContextualSpacing,
|
|
||||||
Indent,
|
|
||||||
KeepLines,
|
|
||||||
KeepNext,
|
|
||||||
OutlineLevel,
|
|
||||||
ParagraphProperties,
|
|
||||||
Spacing,
|
|
||||||
ThematicBreak,
|
|
||||||
} from "file/paragraph";
|
|
||||||
import { TabStop, TabStopType } from "file/paragraph/formatting";
|
|
||||||
import * as formatting from "file/paragraph/run/formatting";
|
|
||||||
import { RunProperties } from "file/paragraph/run/properties";
|
import { RunProperties } from "file/paragraph/run/properties";
|
||||||
|
|
||||||
import { IParagraphStyleOptions2, IRunStyleOptions } from "../style-options";
|
|
||||||
import { BasedOn, Link, Next, QuickFormat, SemiHidden, UiPriority, UnhideWhenUsed } from "./components";
|
import { BasedOn, Link, Next, QuickFormat, SemiHidden, UiPriority, UnhideWhenUsed } from "./components";
|
||||||
import { Style } from "./style";
|
import { Style } from "./style";
|
||||||
|
|
||||||
@ -25,22 +12,25 @@ export interface IBaseParagraphStyleOptions {
|
|||||||
readonly semiHidden?: boolean;
|
readonly semiHidden?: boolean;
|
||||||
readonly uiPriority?: number;
|
readonly uiPriority?: number;
|
||||||
readonly unhideWhenUsed?: boolean;
|
readonly unhideWhenUsed?: boolean;
|
||||||
readonly run?: IRunStyleOptions;
|
readonly paragraph?: IParagraphStylePropertiesOptions;
|
||||||
readonly paragraph?: IParagraphStyleOptions2;
|
readonly run?: IRunStylePropertiesOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IParagraphStyleOptions extends IBaseParagraphStyleOptions {
|
export interface IParagraphStyleOptions extends IBaseParagraphStyleOptions {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly name?: string;
|
readonly name?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ParagraphStyle extends Style {
|
export class ParagraphStyle extends Style {
|
||||||
private readonly paragraphProperties: ParagraphProperties;
|
private readonly paragraphProperties: ParagraphProperties;
|
||||||
private readonly runProperties: RunProperties;
|
private readonly runProperties: RunProperties;
|
||||||
|
|
||||||
constructor(options: IParagraphStyleOptions) {
|
constructor(options: IParagraphStyleOptions) {
|
||||||
super({ type: "paragraph", styleId: options.id }, options.name);
|
super({ type: "paragraph", styleId: options.id }, options.name);
|
||||||
this.paragraphProperties = new ParagraphProperties({});
|
|
||||||
this.runProperties = new RunProperties();
|
this.paragraphProperties = new ParagraphProperties(options.paragraph);
|
||||||
|
this.runProperties = new RunProperties(options.run);
|
||||||
|
|
||||||
this.root.push(this.paragraphProperties);
|
this.root.push(this.paragraphProperties);
|
||||||
this.root.push(this.runProperties);
|
this.root.push(this.runProperties);
|
||||||
|
|
||||||
@ -71,110 +61,5 @@ export class ParagraphStyle extends Style {
|
|||||||
if (options.unhideWhenUsed) {
|
if (options.unhideWhenUsed) {
|
||||||
this.root.push(new UnhideWhenUsed());
|
this.root.push(new UnhideWhenUsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.run) {
|
|
||||||
if (options.run.size) {
|
|
||||||
this.runProperties.push(new formatting.Size(options.run.size));
|
|
||||||
this.runProperties.push(new formatting.SizeComplexScript(options.run.size));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.bold) {
|
|
||||||
this.runProperties.push(new formatting.Bold());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.italics) {
|
|
||||||
this.runProperties.push(new formatting.Italics());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.smallCaps) {
|
|
||||||
this.runProperties.push(new formatting.SmallCaps());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.allCaps) {
|
|
||||||
this.runProperties.push(new formatting.Caps());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.strike) {
|
|
||||||
this.runProperties.push(new formatting.Strike());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.doubleStrike) {
|
|
||||||
this.runProperties.push(new formatting.DoubleStrike());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.subScript) {
|
|
||||||
this.runProperties.push(new formatting.SubScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.superScript) {
|
|
||||||
this.runProperties.push(new formatting.SuperScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.underline) {
|
|
||||||
this.runProperties.push(new formatting.Underline(options.run.underline.type, options.run.underline.color));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.color) {
|
|
||||||
this.runProperties.push(new formatting.Color(options.run.color));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.font) {
|
|
||||||
this.runProperties.push(new formatting.RunFonts(options.run.font));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.characterSpacing) {
|
|
||||||
this.runProperties.push(new formatting.CharacterSpacing(options.run.characterSpacing));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.highlight) {
|
|
||||||
this.runProperties.push(new formatting.Highlight(options.run.highlight));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.run.shadow) {
|
|
||||||
this.runProperties.push(new formatting.Shading(options.run.shadow.type, options.run.shadow.fill, options.run.shadow.color));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.paragraph) {
|
|
||||||
if (options.paragraph.alignment) {
|
|
||||||
this.paragraphProperties.push(new Alignment(options.paragraph.alignment));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.paragraph.thematicBreak) {
|
|
||||||
this.paragraphProperties.push(new ThematicBreak());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.paragraph.contextualSpacing) {
|
|
||||||
this.paragraphProperties.push(new ContextualSpacing(options.paragraph.contextualSpacing));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.paragraph.rightTabStop) {
|
|
||||||
this.paragraphProperties.push(new TabStop(TabStopType.RIGHT, options.paragraph.rightTabStop));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.paragraph.leftTabStop) {
|
|
||||||
this.paragraphProperties.push(new TabStop(TabStopType.LEFT, options.paragraph.leftTabStop));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.paragraph.indent) {
|
|
||||||
this.paragraphProperties.push(new Indent(options.paragraph.indent));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.paragraph.spacing) {
|
|
||||||
this.paragraphProperties.push(new Spacing(options.paragraph.spacing));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.paragraph.keepNext) {
|
|
||||||
this.paragraphProperties.push(new KeepNext());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.paragraph.keepLines) {
|
|
||||||
this.paragraphProperties.push(new KeepLines());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.paragraph.outlineLevel) {
|
|
||||||
this.paragraphProperties.push(new OutlineLevel(options.paragraph.outlineLevel));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,9 @@ export class TableCell extends XmlComponent {
|
|||||||
|
|
||||||
if (options.verticalMerge) {
|
if (options.verticalMerge) {
|
||||||
this.properties.addVerticalMerge(options.verticalMerge);
|
this.properties.addVerticalMerge(options.verticalMerge);
|
||||||
|
} else if (options.rowSpan && options.rowSpan > 1) {
|
||||||
|
// if cell already have a `verticalMerge`, don't handle `rowSpan`
|
||||||
|
this.properties.addVerticalMerge(VerticalMergeType.RESTART);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.margins) {
|
if (options.margins) {
|
||||||
@ -84,10 +87,6 @@ export class TableCell extends XmlComponent {
|
|||||||
this.properties.addGridSpan(options.columnSpan);
|
this.properties.addGridSpan(options.columnSpan);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.rowSpan && options.rowSpan > 1) {
|
|
||||||
this.properties.addVerticalMerge(VerticalMergeType.RESTART);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.width) {
|
if (options.width) {
|
||||||
this.properties.setWidth(options.width.size, options.width.type);
|
this.properties.setWidth(options.width.size, options.width.type);
|
||||||
}
|
}
|
||||||
|
@ -182,4 +182,97 @@ describe("TableRow", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#rootIndexToColumnIndex", () => {
|
||||||
|
it("should get the correct virtual column index by root index", () => {
|
||||||
|
const tableRow = new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tableRow.rootIndexToColumnIndex(1)).to.equal(0);
|
||||||
|
expect(tableRow.rootIndexToColumnIndex(2)).to.equal(3);
|
||||||
|
expect(tableRow.rootIndexToColumnIndex(3)).to.equal(4);
|
||||||
|
expect(tableRow.rootIndexToColumnIndex(4)).to.equal(5);
|
||||||
|
|
||||||
|
expect(() => tableRow.rootIndexToColumnIndex(0)).to.throw(`cell 'rootIndex' should between 1 to 4`);
|
||||||
|
expect(() => tableRow.rootIndexToColumnIndex(5)).to.throw(`cell 'rootIndex' should between 1 to 4`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#columnIndexToRootIndex", () => {
|
||||||
|
it("should get the correct root index by virtual column index", () => {
|
||||||
|
const tableRow = new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tableRow.columnIndexToRootIndex(0)).to.equal(1);
|
||||||
|
expect(tableRow.columnIndexToRootIndex(1)).to.equal(1);
|
||||||
|
expect(tableRow.columnIndexToRootIndex(2)).to.equal(1);
|
||||||
|
|
||||||
|
expect(tableRow.columnIndexToRootIndex(3)).to.equal(2);
|
||||||
|
expect(tableRow.columnIndexToRootIndex(4)).to.equal(3);
|
||||||
|
|
||||||
|
expect(tableRow.columnIndexToRootIndex(5)).to.equal(4);
|
||||||
|
expect(tableRow.columnIndexToRootIndex(6)).to.equal(4);
|
||||||
|
expect(tableRow.columnIndexToRootIndex(7)).to.equal(4);
|
||||||
|
|
||||||
|
expect(() => tableRow.columnIndexToRootIndex(-1)).to.throw(`cell 'columnIndex' should not less than zero`);
|
||||||
|
expect(() => tableRow.columnIndexToRootIndex(8)).to.throw(`cell 'columnIndex' should not great than 7`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow end new cell index", () => {
|
||||||
|
const tableRow = new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("test")],
|
||||||
|
columnSpan: 3,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tableRow.columnIndexToRootIndex(8, true)).to.equal(5);
|
||||||
|
// for column 10, just place the new cell at the end of row
|
||||||
|
expect(tableRow.columnIndexToRootIndex(10, true)).to.equal(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -46,8 +46,56 @@ export class TableRow extends XmlComponent {
|
|||||||
return this.options.children;
|
return this.options.children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get cells(): TableCell[] {
|
||||||
|
return this.root.filter((xmlComponent) => xmlComponent instanceof TableCell);
|
||||||
|
}
|
||||||
|
|
||||||
public addCellToIndex(cell: TableCell, index: number): void {
|
public addCellToIndex(cell: TableCell, index: number): void {
|
||||||
// Offset because properties is also in root.
|
// Offset because properties is also in root.
|
||||||
this.root.splice(index + 1, 0, cell);
|
this.root.splice(index + 1, 0, cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addCellToColumnIndex(cell: TableCell, columnIndex: number): void {
|
||||||
|
const rootIndex = this.columnIndexToRootIndex(columnIndex, true);
|
||||||
|
this.addCellToIndex(cell, rootIndex - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public rootIndexToColumnIndex(rootIndex: number): number {
|
||||||
|
// convert the root index to the virtual column index
|
||||||
|
if (rootIndex < 1 || rootIndex >= this.root.length) {
|
||||||
|
throw new Error(`cell 'rootIndex' should between 1 to ${this.root.length - 1}`);
|
||||||
|
}
|
||||||
|
let colIdx = 0;
|
||||||
|
// Offset because properties is also in root.
|
||||||
|
for (let rootIdx = 1; rootIdx < rootIndex; rootIdx++) {
|
||||||
|
const cell = this.root[rootIdx] as TableCell;
|
||||||
|
colIdx += cell.options.columnSpan || 1;
|
||||||
|
}
|
||||||
|
return colIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public columnIndexToRootIndex(columnIndex: number, allowEndNewCell: boolean = false): number {
|
||||||
|
// convert the virtual column index to the root index
|
||||||
|
// `allowEndNewCell` for get index to inert new cell
|
||||||
|
if (columnIndex < 0) {
|
||||||
|
throw new Error(`cell 'columnIndex' should not less than zero`);
|
||||||
|
}
|
||||||
|
let colIdx = 0;
|
||||||
|
// Offset because properties is also in root.
|
||||||
|
let rootIdx = 1;
|
||||||
|
while (colIdx <= columnIndex) {
|
||||||
|
if (rootIdx >= this.root.length) {
|
||||||
|
if (allowEndNewCell) {
|
||||||
|
// for inserting verticalMerge CONTINUE cell at end of row
|
||||||
|
return this.root.length;
|
||||||
|
} else {
|
||||||
|
throw new Error(`cell 'columnIndex' should not great than ${colIdx - 1}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const cell = this.root[rootIdx] as TableCell;
|
||||||
|
rootIdx += 1;
|
||||||
|
colIdx += (cell && cell.options.columnSpan) || 1;
|
||||||
|
}
|
||||||
|
return rootIdx - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,6 +188,72 @@ describe("Table", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("creates a table with the correct columnSpan and rowSpan", () => {
|
||||||
|
const table = new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
columnSpan: 2,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
rowSpan: 2,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph("hello")],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(table);
|
||||||
|
const cellP = { "w:p": [{ "w:r": [{ "w:t": [{ _attr: { "xml:space": "preserve" } }, "hello"] }] }] };
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tbl": [
|
||||||
|
{ "w:tblPr": [DEFAULT_TABLE_PROPERTIES, BORDERS, WIDTHS] },
|
||||||
|
{
|
||||||
|
"w:tblGrid": [{ "w:gridCol": { _attr: { "w:w": 100 } } }, { "w:gridCol": { _attr: { "w:w": 100 } } }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:tr": [
|
||||||
|
{
|
||||||
|
"w:tc": [{ "w:tcPr": [{ "w:gridSpan": { _attr: { "w:val": 2 } } }] }, cellP],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:tr": [
|
||||||
|
{
|
||||||
|
"w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "restart" } } }] }, cellP],
|
||||||
|
},
|
||||||
|
{ "w:tc": [cellP] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:tr": [
|
||||||
|
{
|
||||||
|
"w:tc": [{ "w:tcPr": [{ "w:vMerge": { _attr: { "w:val": "continue" } } }] }, { "w:p": {} }],
|
||||||
|
},
|
||||||
|
{ "w:tc": [cellP] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("sets the table to fixed width layout", () => {
|
it("sets the table to fixed width layout", () => {
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
rows: [
|
rows: [
|
||||||
|
@ -78,27 +78,29 @@ export class Table extends XmlComponent {
|
|||||||
this.root.push(row);
|
this.root.push(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const row of rows) {
|
rows.forEach((row, rowIndex) => {
|
||||||
row.Children.forEach((cell, cellIndex) => {
|
if (rowIndex === rows.length - 1) {
|
||||||
const column = rows.map((r) => r.Children[cellIndex]);
|
// don't process the end row
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let columnIndex = 0;
|
||||||
|
row.cells.forEach((cell) => {
|
||||||
// Row Span has to be added in this method and not the constructor because it needs to know information about the column which happens after Table Cell construction
|
// Row Span has to be added in this method and not the constructor because it needs to know information about the column which happens after Table Cell construction
|
||||||
// Row Span of 1 will crash word as it will add RESTART and not a corresponding CONTINUE
|
// Row Span of 1 will crash word as it will add RESTART and not a corresponding CONTINUE
|
||||||
if (cell.options.rowSpan && cell.options.rowSpan > 1) {
|
if (cell.options.rowSpan && cell.options.rowSpan > 1) {
|
||||||
const thisCellsColumnIndex = column.indexOf(cell);
|
const continueCell = new TableCell({
|
||||||
const endColumnIndex = thisCellsColumnIndex + (cell.options.rowSpan - 1);
|
// the inserted CONTINUE cell has rowSpan, and will be handled when process the next row
|
||||||
|
rowSpan: cell.options.rowSpan - 1,
|
||||||
for (let i = thisCellsColumnIndex + 1; i <= endColumnIndex; i++) {
|
columnSpan: cell.options.columnSpan,
|
||||||
rows[i].addCellToIndex(
|
borders: cell.options.borders,
|
||||||
new TableCell({
|
|
||||||
children: [],
|
children: [],
|
||||||
verticalMerge: VerticalMergeType.CONTINUE,
|
verticalMerge: VerticalMergeType.CONTINUE,
|
||||||
}),
|
|
||||||
i,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
rows[rowIndex + 1].addCellToColumnIndex(continueCell, columnIndex);
|
||||||
}
|
}
|
||||||
|
columnIndex += cell.options.columnSpan || 1;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (float) {
|
if (float) {
|
||||||
this.properties.setTableFloatProperties(float);
|
this.properties.setTableFloatProperties(float);
|
||||||
|
Reference in New Issue
Block a user