Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
44ed2d6943 | |||
fe7a75b754 | |||
d30cd546ab | |||
03d47658d6 | |||
1403ac664b | |||
ba0a502d27 | |||
44d4b93d06 | |||
72abd4b7ac | |||
a473a98f17 | |||
f649dac62c | |||
ba7f937a7a | |||
1c8e6ae1db | |||
e09e201c45 | |||
409ea028cb | |||
fc86e1842d | |||
b614b74a2a | |||
e7eb415376 | |||
77c5a736dd | |||
a241a51cfd | |||
4e0468d978 | |||
cfe5970e54 | |||
27977edf82 | |||
7405a19ae8 | |||
ce32375d47 | |||
b33b7d2ebd | |||
b2b23bdc1c | |||
7f26badbc9 | |||
b19025881b | |||
5af1045a59 | |||
4d1a351649 | |||
8ba9a448d3 | |||
a708475539 | |||
9c60cfcbc7 | |||
a5454edc61 | |||
7152abfe48 | |||
075eeb7e3c | |||
f0acb3f3fb | |||
ae048833a1 | |||
ebae72004c | |||
13744abff5 | |||
492ef29d7f | |||
a6e6463a36 | |||
2ef596543b | |||
85005c3c07 | |||
0d2b433446 | |||
b1f67652e9 | |||
4e2befb7ef |
@ -14,6 +14,7 @@
|
|||||||
[![Known Vulnerabilities][snky-image]][snky-url]
|
[![Known Vulnerabilities][snky-image]][snky-url]
|
||||||
[![PRs Welcome][pr-image]][pr-url]
|
[![PRs Welcome][pr-image]][pr-url]
|
||||||
[![codecov][codecov-image]][codecov-url]
|
[![codecov][codecov-image]][codecov-url]
|
||||||
|
[![Docx.js Editor][docxjs-editor-image]][docxjs-editor-url]
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://i.imgur.com/QeL1HuU.png" alt="drawing"/>
|
<img src="https://i.imgur.com/QeL1HuU.png" alt="drawing"/>
|
||||||
@ -64,6 +65,10 @@ More [here](https://github.com/dolanmiu/docx/tree/master/demo)
|
|||||||
|
|
||||||
Please refer to the [documentation at https://docx.js.org/](https://docx.js.org/) for details on how to use this library, examples and much more!
|
Please refer to the [documentation at https://docx.js.org/](https://docx.js.org/) for details on how to use this library, examples and much more!
|
||||||
|
|
||||||
|
# Playground
|
||||||
|
|
||||||
|
Experience `docx` in action through [Docx.js Editor][docxjs-editor-url], an interactive playground where you can code and preview the results in real-time.
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
Check the [demo folder](https://github.com/dolanmiu/docx/tree/master/demo) for examples.
|
Check the [demo folder](https://github.com/dolanmiu/docx/tree/master/demo) for examples.
|
||||||
@ -115,3 +120,5 @@ Made with 💖
|
|||||||
[patreon-url]: https://www.patreon.com/dolanmiu
|
[patreon-url]: https://www.patreon.com/dolanmiu
|
||||||
[browserstack-image]: https://user-images.githubusercontent.com/2917613/54233552-128e9d00-4505-11e9-88fb-025a4e04007c.png
|
[browserstack-image]: https://user-images.githubusercontent.com/2917613/54233552-128e9d00-4505-11e9-88fb-025a4e04007c.png
|
||||||
[browserstack-url]: https://www.browserstack.com
|
[browserstack-url]: https://www.browserstack.com
|
||||||
|
[docxjs-editor-image]: https://img.shields.io/badge/Docx.js%20Editor-2b579a.svg?style=flat&logo=javascript&logoColor=white
|
||||||
|
[docxjs-editor-url]: https://docxjs-editor.vercel.app/
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Example demonstrating page borders with style, colors and size
|
// Example demonstrating page borders with style, colors and size
|
||||||
|
|
||||||
|
import { BorderStyle, Document, Packer, PageBorderDisplay, PageBorderOffsetFrom, PageBorderZOrder, Paragraph, TextRun } from "docx";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Document, Packer, TextRun, Paragraph, BorderStyle, PageBorderDisplay, PageBorderOffsetFrom, PageBorderZOrder } from "docx";
|
|
||||||
|
|
||||||
const doc = new Document({
|
const doc = new Document({
|
||||||
sections: [
|
sections: [
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Simple example to add comments to a document
|
// Simple example to add comments to a document
|
||||||
|
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import { Document, Packer, Paragraph, TextRun, CommentRangeStart, CommentRangeEnd, CommentReference } from "docx";
|
import { Document, Packer, Paragraph, TextRun, CommentRangeStart, CommentRangeEnd, CommentReference, ImageRun } from "docx";
|
||||||
|
|
||||||
const doc = new Document({
|
const doc = new Document({
|
||||||
comments: {
|
comments: {
|
||||||
@ -20,6 +20,14 @@ const doc = new Document({
|
|||||||
}),
|
}),
|
||||||
new Paragraph({
|
new Paragraph({
|
||||||
children: [
|
children: [
|
||||||
|
new ImageRun({
|
||||||
|
type: "jpg",
|
||||||
|
data: fs.readFileSync("./demo/images/cat.jpg"),
|
||||||
|
transformation: {
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
},
|
||||||
|
}),
|
||||||
new TextRun({
|
new TextRun({
|
||||||
text: "comment text content",
|
text: "comment text content",
|
||||||
}),
|
}),
|
||||||
|
168
demo/96-template-document.ts
Normal file
168
demo/96-template-document.ts
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// Patch a document with patches
|
||||||
|
|
||||||
|
import * as fs from "fs";
|
||||||
|
import {
|
||||||
|
ExternalHyperlink,
|
||||||
|
HeadingLevel,
|
||||||
|
ImageRun,
|
||||||
|
Paragraph,
|
||||||
|
patchDocument,
|
||||||
|
PatchType,
|
||||||
|
Table,
|
||||||
|
TableCell,
|
||||||
|
TableRow,
|
||||||
|
TextDirection,
|
||||||
|
TextRun,
|
||||||
|
VerticalAlign,
|
||||||
|
} from "docx";
|
||||||
|
|
||||||
|
patchDocument({
|
||||||
|
outputType: "nodebuffer",
|
||||||
|
data: fs.readFileSync("demo/assets/simple-template-4.docx"),
|
||||||
|
patches: {
|
||||||
|
name: {
|
||||||
|
type: PatchType.PARAGRAPH,
|
||||||
|
children: [new TextRun("Sir. "), new TextRun("John Doe"), new TextRun("(The Conqueror)")],
|
||||||
|
},
|
||||||
|
table_heading_1: {
|
||||||
|
type: PatchType.PARAGRAPH,
|
||||||
|
children: [new TextRun("Heading wow!")],
|
||||||
|
},
|
||||||
|
item_1: {
|
||||||
|
type: PatchType.PARAGRAPH,
|
||||||
|
children: [
|
||||||
|
new TextRun("#657"),
|
||||||
|
new ExternalHyperlink({
|
||||||
|
children: [
|
||||||
|
new TextRun({
|
||||||
|
text: "BBC News Link",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
link: "https://www.bbc.co.uk/news",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
paragraph_replace: {
|
||||||
|
type: PatchType.DOCUMENT,
|
||||||
|
children: [
|
||||||
|
new Paragraph("Lorem ipsum paragraph"),
|
||||||
|
new Paragraph("Another paragraph"),
|
||||||
|
new Paragraph({
|
||||||
|
children: [
|
||||||
|
new TextRun("This is a "),
|
||||||
|
new ExternalHyperlink({
|
||||||
|
children: [
|
||||||
|
new TextRun({
|
||||||
|
text: "Google Link",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
link: "https://www.google.co.uk",
|
||||||
|
}),
|
||||||
|
new ImageRun({
|
||||||
|
type: "png",
|
||||||
|
data: fs.readFileSync("./demo/images/dog.png"),
|
||||||
|
transformation: { width: 100, height: 100 },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
header_adjective: {
|
||||||
|
type: PatchType.PARAGRAPH,
|
||||||
|
children: [new TextRun("Delightful Header")],
|
||||||
|
},
|
||||||
|
footer_text: {
|
||||||
|
type: PatchType.PARAGRAPH,
|
||||||
|
children: [
|
||||||
|
new TextRun("replaced just as"),
|
||||||
|
new TextRun(" well"),
|
||||||
|
new ExternalHyperlink({
|
||||||
|
children: [
|
||||||
|
new TextRun({
|
||||||
|
text: "BBC News Link",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
link: "https://www.bbc.co.uk/news",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
image_test: {
|
||||||
|
type: PatchType.PARAGRAPH,
|
||||||
|
children: [
|
||||||
|
new ImageRun({
|
||||||
|
type: "jpg",
|
||||||
|
data: fs.readFileSync("./demo/images/image1.jpeg"),
|
||||||
|
transformation: { width: 100, height: 100 },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
type: PatchType.DOCUMENT,
|
||||||
|
children: [
|
||||||
|
new Table({
|
||||||
|
rows: [
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph({}), new Paragraph({})],
|
||||||
|
verticalAlign: VerticalAlign.CENTER,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph({}), new Paragraph({})],
|
||||||
|
verticalAlign: VerticalAlign.CENTER,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph({ text: "bottom to top" }), new Paragraph({})],
|
||||||
|
textDirection: TextDirection.BOTTOM_TO_TOP_LEFT_TO_RIGHT,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [new Paragraph({ text: "top to bottom" }), new Paragraph({})],
|
||||||
|
textDirection: TextDirection.TOP_TO_BOTTOM_RIGHT_TO_LEFT,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableRow({
|
||||||
|
children: [
|
||||||
|
new TableCell({
|
||||||
|
children: [
|
||||||
|
new Paragraph({
|
||||||
|
text: "Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah",
|
||||||
|
heading: HeadingLevel.HEADING_1,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [
|
||||||
|
new Paragraph({
|
||||||
|
text: "This text should be in the middle of the cell",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
verticalAlign: VerticalAlign.CENTER,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [
|
||||||
|
new Paragraph({
|
||||||
|
text: "Text above should be vertical from bottom to top",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
verticalAlign: VerticalAlign.CENTER,
|
||||||
|
}),
|
||||||
|
new TableCell({
|
||||||
|
children: [
|
||||||
|
new Paragraph({
|
||||||
|
text: "Text above should be vertical from top to bottom",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
verticalAlign: VerticalAlign.CENTER,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
placeholderDelimiters: { start: "<<", end: ">>" },
|
||||||
|
}).then((doc) => {
|
||||||
|
fs.writeFileSync("My Document.docx", doc);
|
||||||
|
});
|
BIN
demo/assets/simple-template-4.docx
Normal file
BIN
demo/assets/simple-template-4.docx
Normal file
Binary file not shown.
@ -1,24 +1,25 @@
|
|||||||
# Contribution Guidelines
|
# Contribution Guidelines
|
||||||
|
|
||||||
- Include documentation reference(s) at the top of each file as a comment. For example:
|
- Include documentation reference(s) at the top of each file as a comment. For example:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// http://officeopenxml.com/WPdocument.php
|
// http://officeopenxml.com/WPdocument.php
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- cSpell:ignore datypic -->
|
<!-- cSpell:ignore datypic -->
|
||||||
|
|
||||||
It can be a link to `officeopenxml.com` or `datypic.com` etc.
|
It can be a link to `officeopenxml.com` or `datypic.com` etc.
|
||||||
It could also be a reference to the official ECMA-376 standard: https://www.ecma-international.org/publications-and-standards/standards/ecma-376/
|
It could also be a reference to the official ECMA-376 standard: https://www.ecma-international.org/publications-and-standards/standards/ecma-376/
|
||||||
|
|
||||||
- Include a portion of the schema as a comment for cross reference. For example:
|
- Include a portion of the schema as a comment for cross reference. For example:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// <xsd:element name="tbl" type="CT_Tbl" minOccurs="0" maxOccurs="1"/>
|
// <xsd:element name="tbl" type="CT_Tbl" minOccurs="0" maxOccurs="1"/>
|
||||||
```
|
```
|
||||||
|
|
||||||
- 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 `ESLint` rules
|
- Follow the `ESLint` rules
|
||||||
|
|
||||||
## Always think about the user
|
## Always think about the user
|
||||||
|
|
||||||
@ -37,6 +38,7 @@ Please write good commit messages when making a commit: https://chris.beams.io/p
|
|||||||
**Do not:**
|
**Do not:**
|
||||||
|
|
||||||
<!-- cspell:disable -->
|
<!-- cspell:disable -->
|
||||||
|
|
||||||
```
|
```
|
||||||
c // What?
|
c // What?
|
||||||
rtl // Adding acronyms without explaining anything else is not helpful
|
rtl // Adding acronyms without explaining anything else is not helpful
|
||||||
@ -44,6 +46,7 @@ works! // Glad its working, but the message is not helpful
|
|||||||
demo updated // Getting better, but capitalize the first letter
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
<!-- cspell:enable -->
|
<!-- cspell:enable -->
|
||||||
|
|
||||||
**Do**
|
**Do**
|
||||||
@ -104,25 +107,28 @@ private get _level: string;
|
|||||||
private get level: string;
|
private get level: string;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Interfaces over type alias
|
## Types over interfaces
|
||||||
|
|
||||||
Do not use `type`, but rather use `Interfaces`. `type` cannot be extended, and a class cannot implement it.
|
Using `type` aliases in TypeScript offers several advantages over `interfaces`:
|
||||||
|
|
||||||
> "In general, use what you want ( type alias / interface ) just be consistent"
|
- **Flexibility with Complex Types**: `type` supports defining unions, intersections, and other complex type constructs that `interfaces` cannot handle. For example:
|
||||||
> "always use interface for public API's definition when authoring a library or 3rd party ambient type definitions"
|
|
||||||
>
|
|
||||||
> - https://medium.com/@martin_hotell/interface-vs-type-alias-in-typescript-2-7-2a8f1777af4c
|
|
||||||
|
|
||||||
`Interface` is generally preferred over `type`: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types
|
```typescript
|
||||||
|
type StringOrNumber = string | number;
|
||||||
|
type Combined = TypeA & TypeB;
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Support for Primitive Types**: `type` can alias primitive types (e.g., `type ID = string`), while `interfaces` are limited to object shapes.
|
||||||
|
- **Tuple and Array Types**: `type` allows defining tuples and specific array types easily (e.g., `type Point = [number, number]`), which `interfaces` cannot represent.
|
||||||
|
- **Utility Types Compatibility**: `type` works seamlessly with TypeScript's utility types (e.g., `Partial<T>`, `Pick<T, K>`), enabling more expressive type transformations.
|
||||||
|
- **Functional Programming**: `type` is ideal for functional programming patterns, such as defining function signatures or mapped types, due to its versatility.
|
||||||
|
- **No Declaration Merging**: Unlike `interfaces`, type does not support declaration merging, which can prevent accidental type extensions and ensure predictable type definitions.
|
||||||
|
- **Consistent Pattern**: This project uses `type` for all type definitions, so using `type` for all type definitions maintains consistency and readability across the codebase.
|
||||||
|
|
||||||
|
Detailed discussion: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types
|
||||||
|
|
||||||
**Do not:**
|
**Do not:**
|
||||||
|
|
||||||
```ts
|
|
||||||
type RelationshipFileInfo = { id: number; target: string };
|
|
||||||
```
|
|
||||||
|
|
||||||
**Do:**
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
interface IRelationshipFileInfo {
|
interface IRelationshipFileInfo {
|
||||||
id: number;
|
id: number;
|
||||||
@ -130,6 +136,12 @@ interface IRelationshipFileInfo {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Do:**
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type RelationshipFileInfo = { id: number; target: string };
|
||||||
|
```
|
||||||
|
|
||||||
## String enums vs type
|
## String enums vs type
|
||||||
|
|
||||||
To take full advantage of TypeScript's typing system, its best to use `string enums`:
|
To take full advantage of TypeScript's typing system, its best to use `string enums`:
|
||||||
|
@ -16,12 +16,10 @@ const chapter1 = new Paragraph({
|
|||||||
children: [
|
children: [
|
||||||
new Bookmark({
|
new Bookmark({
|
||||||
id: "anchorForChapter1",
|
id: "anchorForChapter1",
|
||||||
children: [
|
children: [new TextRun("Chapter 1")],
|
||||||
new TextRun("Chapter 1"),
|
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
})
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Then you can create an hyperlink pointing to that bookmark with an `InternalHyperLink`:
|
Then you can create an hyperlink pointing to that bookmark with an `InternalHyperLink`:
|
||||||
@ -35,20 +33,32 @@ const link = new InternalHyperlink({
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
anchor: "anchorForChapter1",
|
anchor: "anchorForChapter1",
|
||||||
})
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Page reference
|
||||||
|
|
||||||
You can also get the page number of the bookmark by creating a page reference to it:
|
You can also get the page number of the bookmark by creating a page reference to it:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const paragraph = new Paragraph({
|
const paragraph = new Paragraph({
|
||||||
children: [
|
children: [new TextRun("Chapter 1 can be seen on page "), new PageReference("anchorForChapter1")],
|
||||||
new TextRun("Chapter 1 can be seen on page "),
|
|
||||||
new PageReference("anchorForChapter1"),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Numbered item reference
|
||||||
|
|
||||||
|
You can also create cross references for numbered items with `NumberedItemReference`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const paragraph = new Paragraph({
|
||||||
|
children: [new TextRun("See Paragraph "), new NumberedItemReference("anchorForParagraph1", "1.1")],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> The `NumberedItemReference` currently needs a cached value (in this case `1.1`)
|
||||||
|
|
||||||
## External
|
## External
|
||||||
|
|
||||||
To create an external hyperlink you just need to specify the url and the text of the link, then add it to a paragraph:
|
To create an external hyperlink you just need to specify the url and the text of the link, then add it to a paragraph:
|
||||||
@ -69,7 +79,6 @@ const paragraph = new Paragraph({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Styling hyperlinks
|
## Styling hyperlinks
|
||||||
|
|
||||||
It is possible to set the style of the text of both internal and external hyperlinks. This can be done applying run formatting on any of the `TextRun` children of the hyperlink. Use the `style: "Hyperlink"` property to show the default link styles, which can be combined with any other style.
|
It is possible to set the style of the text of both internal and external hyperlinks. This can be done applying run formatting on any of the `TextRun` children of the hyperlink. Use the `style: "Hyperlink"` property to show the default link styles, which can be combined with any other style.
|
||||||
|
@ -2,7 +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 works in both a node and browser environment (Angular etc). Now, the packer returns a `Buffer`, `Blob`, `string`, `base64 string`, or `Stream`. 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`, `string`, `base64 string`, `ArrayBuffer`, or `Stream`. 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.
|
||||||
|
|
||||||
### Export as Buffer
|
### Export as Buffer
|
||||||
|
|
||||||
@ -41,6 +41,16 @@ Packer.toBlob(doc).then((blob) => {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Export as ArrayBuffer
|
||||||
|
|
||||||
|
This may be useful when working in a Node.js worker.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
Packer.toArrayBuffer(doc).then((arrayBuffer) => {
|
||||||
|
port.postMessage(arrayBuffer, [arrayBuffer]);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
### Export as a Stream
|
### Export as a Stream
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
@ -63,3 +73,13 @@ Packer.toString(doc, true, overrides).then((string) => {
|
|||||||
console.log(string);
|
console.log(string);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Export to arbitrary formats
|
||||||
|
|
||||||
|
You can also use the lower-level `Packer.pack` method to export to any specified type.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
Packer.pack(doc, 'string').then((string) => {
|
||||||
|
console.log(string);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
9423
package-lock.json
generated
9423
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "docx",
|
"name": "docx",
|
||||||
"version": "9.2.0",
|
"version": "9.4.1",
|
||||||
"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.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.umd.cjs",
|
"main": "dist/index.umd.cjs",
|
||||||
@ -61,7 +61,7 @@
|
|||||||
"@types/node": "^22.7.5",
|
"@types/node": "^22.7.5",
|
||||||
"hash.js": "^1.1.7",
|
"hash.js": "^1.1.7",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"nanoid": "^5.0.4",
|
"nanoid": "^5.1.3",
|
||||||
"xml": "^1.0.1",
|
"xml": "^1.0.1",
|
||||||
"xml-js": "^1.6.8"
|
"xml-js": "^1.6.8"
|
||||||
},
|
},
|
||||||
@ -79,36 +79,36 @@
|
|||||||
"@types/xml": "^1.0.8",
|
"@types/xml": "^1.0.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.8.1",
|
"@typescript-eslint/eslint-plugin": "^8.8.1",
|
||||||
"@typescript-eslint/parser": "^8.8.1",
|
"@typescript-eslint/parser": "^8.8.1",
|
||||||
"@vitest/coverage-v8": "^2.1.8",
|
"@vitest/coverage-v8": "^3.0.8",
|
||||||
"@vitest/ui": "^2.1.2",
|
"@vitest/ui": "^3.0.8",
|
||||||
"cspell": "^8.2.3",
|
"cspell": "^8.2.3",
|
||||||
"docsify-cli": "^4.3.0",
|
"docsify-cli": "^4.3.0",
|
||||||
"eslint": "^9.13.0",
|
"eslint": "^9.13.0",
|
||||||
"eslint-import-resolver-typescript": "^3.6.3",
|
"eslint-import-resolver-typescript": "^4.3.2",
|
||||||
"eslint-plugin-functional": "^7.0.2",
|
"eslint-plugin-functional": "^7.0.2",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-jsdoc": "^50.3.1",
|
"eslint-plugin-jsdoc": "^50.3.1",
|
||||||
"eslint-plugin-no-null": "^1.0.2",
|
"eslint-plugin-no-null": "^1.0.2",
|
||||||
"eslint-plugin-prefer-arrow": "^1.2.3",
|
"eslint-plugin-prefer-arrow": "^1.2.3",
|
||||||
"eslint-plugin-unicorn": "^56.0.0",
|
"eslint-plugin-unicorn": "^58.0.0",
|
||||||
"execa": "^9.4.0",
|
"execa": "^9.4.0",
|
||||||
"glob": "^11.0.0",
|
"glob": "^11.0.0",
|
||||||
"inquirer": "^12.0.0",
|
"inquirer": "^12.0.0",
|
||||||
"jiti": "^2.3.3",
|
"jiti": "^2.3.3",
|
||||||
"jsdom": "^25.0.1",
|
"jsdom": "^26.0.0",
|
||||||
"pre-commit": "^1.2.2",
|
"pre-commit": "^1.2.2",
|
||||||
"prettier": "^3.1.1",
|
"prettier": "^3.1.1",
|
||||||
"tsconfig-paths": "^4.0.0",
|
"tsconfig-paths": "^4.0.0",
|
||||||
"tsx": "^4.7.0",
|
"tsx": "^4.7.0",
|
||||||
"typedoc": "^0.27.3",
|
"typedoc": "^0.28.2",
|
||||||
"typescript": "5.3.3",
|
"typescript": "5.3.3",
|
||||||
"typescript-eslint": "^8.10.0",
|
"typescript-eslint": "^8.10.0",
|
||||||
"unzipper": "^0.12.3",
|
"unzipper": "^0.12.3",
|
||||||
"vite": "^6.0.1",
|
"vite": "^6.0.1",
|
||||||
"vite-plugin-dts": "^4.2.4",
|
"vite-plugin-dts": "^4.2.4",
|
||||||
"vite-plugin-node-polyfills": "^0.22.0",
|
"vite-plugin-node-polyfills": "^0.23.0",
|
||||||
"vite-tsconfig-paths": "^5.0.1",
|
"vite-tsconfig-paths": "^5.0.1",
|
||||||
"vitest": "^2.1.8"
|
"vitest": "^3.0.8"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
|
@ -36,7 +36,7 @@ describe("Compiler", () => {
|
|||||||
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
||||||
|
|
||||||
expect(fileNames).is.an.instanceof(Array);
|
expect(fileNames).is.an.instanceof(Array);
|
||||||
expect(fileNames).has.length(19);
|
expect(fileNames).has.length(20);
|
||||||
expect(fileNames).to.include("word/document.xml");
|
expect(fileNames).to.include("word/document.xml");
|
||||||
expect(fileNames).to.include("word/styles.xml");
|
expect(fileNames).to.include("word/styles.xml");
|
||||||
expect(fileNames).to.include("docProps/core.xml");
|
expect(fileNames).to.include("docProps/core.xml");
|
||||||
@ -96,7 +96,7 @@ describe("Compiler", () => {
|
|||||||
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
||||||
|
|
||||||
expect(fileNames).is.an.instanceof(Array);
|
expect(fileNames).is.an.instanceof(Array);
|
||||||
expect(fileNames).has.length(27);
|
expect(fileNames).has.length(28);
|
||||||
|
|
||||||
expect(fileNames).to.include("word/header1.xml");
|
expect(fileNames).to.include("word/header1.xml");
|
||||||
expect(fileNames).to.include("word/_rels/header1.xml.rels");
|
expect(fileNames).to.include("word/_rels/header1.xml.rels");
|
||||||
@ -131,7 +131,7 @@ describe("Compiler", () => {
|
|||||||
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
|
||||||
|
|
||||||
expect(fileNames).is.an.instanceof(Array);
|
expect(fileNames).is.an.instanceof(Array);
|
||||||
expect(fileNames).has.length(20);
|
expect(fileNames).has.length(21);
|
||||||
|
|
||||||
expect(fileNames).to.include("word/comments.xml");
|
expect(fileNames).to.include("word/comments.xml");
|
||||||
expect(fileNames).to.include("word/commentsExtended.xml");
|
expect(fileNames).to.include("word/commentsExtended.xml");
|
||||||
@ -163,7 +163,7 @@ describe("Compiler", () => {
|
|||||||
const spy = vi.spyOn(compiler["formatter"], "format");
|
const spy = vi.spyOn(compiler["formatter"], "format");
|
||||||
|
|
||||||
compiler.compile(file);
|
compiler.compile(file);
|
||||||
expect(spy).toBeCalledTimes(15);
|
expect(spy).toBeCalledTimes(16);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should work with media datas", () => {
|
it("should work with media datas", () => {
|
||||||
|
@ -32,6 +32,7 @@ type IXmlifyedFileMapping = {
|
|||||||
readonly FootNotesRelationships: IXmlifyedFile;
|
readonly FootNotesRelationships: IXmlifyedFile;
|
||||||
readonly Settings: IXmlifyedFile;
|
readonly Settings: IXmlifyedFile;
|
||||||
readonly Comments?: IXmlifyedFile;
|
readonly Comments?: IXmlifyedFile;
|
||||||
|
readonly CommentsRelationships?: IXmlifyedFile;
|
||||||
readonly FontTable?: IXmlifyedFile;
|
readonly FontTable?: IXmlifyedFile;
|
||||||
readonly FontTableRelationships?: IXmlifyedFile;
|
readonly FontTableRelationships?: IXmlifyedFile;
|
||||||
};
|
};
|
||||||
@ -104,7 +105,28 @@ export class Compiler {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const commentRelationshipCount = file.Comments.Relationships.RelationshipCount + 1;
|
||||||
|
const commentXmlData = xml(
|
||||||
|
this.formatter.format(file.Comments, {
|
||||||
|
viewWrapper: {
|
||||||
|
View: file.Comments,
|
||||||
|
Relationships: file.Comments.Relationships,
|
||||||
|
},
|
||||||
|
file,
|
||||||
|
stack: [],
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
indent: prettify,
|
||||||
|
declaration: {
|
||||||
|
standalone: "yes",
|
||||||
|
encoding: "UTF-8",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const documentMediaDatas = this.imageReplacer.getMediaData(documentXmlData, file.Media);
|
const documentMediaDatas = this.imageReplacer.getMediaData(documentXmlData, file.Media);
|
||||||
|
const commentMediaDatas = this.imageReplacer.getMediaData(commentXmlData, file.Media);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Relationships: {
|
Relationships: {
|
||||||
@ -450,22 +472,41 @@ export class Compiler {
|
|||||||
path: "word/settings.xml",
|
path: "word/settings.xml",
|
||||||
},
|
},
|
||||||
Comments: {
|
Comments: {
|
||||||
data: xml(
|
data: (() => {
|
||||||
this.formatter.format(file.Comments, {
|
const xmlData = this.imageReplacer.replace(commentXmlData, commentMediaDatas, commentRelationshipCount);
|
||||||
viewWrapper: file.Document,
|
const referenedXmlData = this.numberingReplacer.replace(xmlData, file.Numbering.ConcreteNumbering);
|
||||||
file,
|
return referenedXmlData;
|
||||||
stack: [],
|
})(),
|
||||||
}),
|
|
||||||
{
|
|
||||||
indent: prettify,
|
|
||||||
declaration: {
|
|
||||||
standalone: "yes",
|
|
||||||
encoding: "UTF-8",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
),
|
|
||||||
path: "word/comments.xml",
|
path: "word/comments.xml",
|
||||||
},
|
},
|
||||||
|
CommentsRelationships: {
|
||||||
|
data: (() => {
|
||||||
|
commentMediaDatas.forEach((mediaData, i) => {
|
||||||
|
file.Comments.Relationships.createRelationship(
|
||||||
|
commentRelationshipCount + i,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||||
|
`media/${mediaData.fileName}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return xml(
|
||||||
|
this.formatter.format(file.Comments.Relationships, {
|
||||||
|
viewWrapper: {
|
||||||
|
View: file.Comments,
|
||||||
|
Relationships: file.Comments.Relationships,
|
||||||
|
},
|
||||||
|
file,
|
||||||
|
stack: [],
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
indent: prettify,
|
||||||
|
declaration: {
|
||||||
|
encoding: "UTF-8",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
})(),
|
||||||
|
path: "word/_rels/comments.xml.rels",
|
||||||
|
},
|
||||||
FontTable: {
|
FontTable: {
|
||||||
data: xml(
|
data: xml(
|
||||||
this.formatter.format(file.FontTable.View, {
|
this.formatter.format(file.FontTable.View, {
|
||||||
|
@ -55,32 +55,101 @@ class BordersAttributes extends XmlAttributeComponent<IBorderOptions> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table borders are defined with the <w:tblBorders> element. Child elements of this element specify the kinds of `border`:
|
||||||
|
*
|
||||||
|
* `bottom`, `end` (`right` in the previous version of the standard), `insideH`, `insideV`, `start` (`left` in the previous version of the standard), and `top`.
|
||||||
|
*
|
||||||
|
* Reference: http://officeopenxml.com/WPtableBorders.php
|
||||||
|
*
|
||||||
|
* ## XSD Schema
|
||||||
|
* ```xml
|
||||||
|
* <xsd:simpleType name="ST_Border">
|
||||||
|
* <xsd:restriction base="xsd:string">
|
||||||
|
* <xsd:enumeration value="single"/>
|
||||||
|
* <xsd:enumeration value="dashDotStroked"/>
|
||||||
|
* <xsd:enumeration value="dashed"/>
|
||||||
|
* <xsd:enumeration value="dashSmallGap"/>
|
||||||
|
* <xsd:enumeration value="dotDash"/>
|
||||||
|
* <xsd:enumeration value="dotDotDash"/>
|
||||||
|
* <xsd:enumeration value="dotted"/>
|
||||||
|
* <xsd:enumeration value="double"/>
|
||||||
|
* <xsd:enumeration value="doubleWave"/>
|
||||||
|
* <xsd:enumeration value="inset"/>
|
||||||
|
* <xsd:enumeration value="nil"/>
|
||||||
|
* <xsd:enumeration value="none"/>
|
||||||
|
* <xsd:enumeration value="outset"/>
|
||||||
|
* <xsd:enumeration value="thick"/>
|
||||||
|
* <xsd:enumeration value="thickThinLargeGap"/>
|
||||||
|
* <xsd:enumeration value="thickThinMediumGap"/>
|
||||||
|
* <xsd:enumeration value="thickThinSmallGap"/>
|
||||||
|
* <xsd:enumeration value="thinThickLargeGap"/>
|
||||||
|
* <xsd:enumeration value="thinThickMediumGap"/>
|
||||||
|
* <xsd:enumeration value="thinThickSmallGap"/>
|
||||||
|
* <xsd:enumeration value="thinThickThinLargeGap"/>
|
||||||
|
* <xsd:enumeration value="thinThickThinMediumGap"/>
|
||||||
|
* <xsd:enumeration value="thinThickThinSmallGap"/>
|
||||||
|
* <xsd:enumeration value="threeDEmboss"/>
|
||||||
|
* <xsd:enumeration value="threeDEngrave"/>
|
||||||
|
* <xsd:enumeration value="triple"/>
|
||||||
|
* <xsd:enumeration value="wave"/>
|
||||||
|
* </xsd:restriction>
|
||||||
|
* </xsd:simpleType>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export const BorderStyle = {
|
export const BorderStyle = {
|
||||||
|
/** a single line */
|
||||||
SINGLE: "single",
|
SINGLE: "single",
|
||||||
|
/** a line with a series of alternating thin and thick strokes */
|
||||||
DASH_DOT_STROKED: "dashDotStroked",
|
DASH_DOT_STROKED: "dashDotStroked",
|
||||||
|
/** a dashed line */
|
||||||
DASHED: "dashed",
|
DASHED: "dashed",
|
||||||
|
/** a dashed line with small gaps */
|
||||||
DASH_SMALL_GAP: "dashSmallGap",
|
DASH_SMALL_GAP: "dashSmallGap",
|
||||||
|
/** a line with alternating dots and dashes */
|
||||||
DOT_DASH: "dotDash",
|
DOT_DASH: "dotDash",
|
||||||
|
/** a line with a repeating dot - dot - dash sequence */
|
||||||
DOT_DOT_DASH: "dotDotDash",
|
DOT_DOT_DASH: "dotDotDash",
|
||||||
|
/** a dotted line */
|
||||||
DOTTED: "dotted",
|
DOTTED: "dotted",
|
||||||
|
/** a double line */
|
||||||
DOUBLE: "double",
|
DOUBLE: "double",
|
||||||
|
/** a double wavy line */
|
||||||
DOUBLE_WAVE: "doubleWave",
|
DOUBLE_WAVE: "doubleWave",
|
||||||
|
/** an inset set of lines */
|
||||||
INSET: "inset",
|
INSET: "inset",
|
||||||
|
/** no border */
|
||||||
NIL: "nil",
|
NIL: "nil",
|
||||||
|
/** no border */
|
||||||
NONE: "none",
|
NONE: "none",
|
||||||
|
/** an outset set of lines */
|
||||||
OUTSET: "outset",
|
OUTSET: "outset",
|
||||||
|
/** a single line */
|
||||||
THICK: "thick",
|
THICK: "thick",
|
||||||
|
/** a thick line contained within a thin line with a large-sized intermediate gap */
|
||||||
THICK_THIN_LARGE_GAP: "thickThinLargeGap",
|
THICK_THIN_LARGE_GAP: "thickThinLargeGap",
|
||||||
|
/** a thick line contained within a thin line with a medium-sized intermediate gap */
|
||||||
THICK_THIN_MEDIUM_GAP: "thickThinMediumGap",
|
THICK_THIN_MEDIUM_GAP: "thickThinMediumGap",
|
||||||
|
/** a thick line contained within a thin line with a small intermediate gap */
|
||||||
THICK_THIN_SMALL_GAP: "thickThinSmallGap",
|
THICK_THIN_SMALL_GAP: "thickThinSmallGap",
|
||||||
|
/** a thin line contained within a thick line with a large-sized intermediate gap */
|
||||||
THIN_THICK_LARGE_GAP: "thinThickLargeGap",
|
THIN_THICK_LARGE_GAP: "thinThickLargeGap",
|
||||||
|
/** a thick line contained within a thin line with a medium-sized intermediate gap */
|
||||||
THIN_THICK_MEDIUM_GAP: "thinThickMediumGap",
|
THIN_THICK_MEDIUM_GAP: "thinThickMediumGap",
|
||||||
|
/** a thick line contained within a thin line with a small intermediate gap */
|
||||||
THIN_THICK_SMALL_GAP: "thinThickSmallGap",
|
THIN_THICK_SMALL_GAP: "thinThickSmallGap",
|
||||||
|
/** a thin-thick-thin line with a large gap */
|
||||||
THIN_THICK_THIN_LARGE_GAP: "thinThickThinLargeGap",
|
THIN_THICK_THIN_LARGE_GAP: "thinThickThinLargeGap",
|
||||||
|
/** a thin-thick-thin line with a medium gap */
|
||||||
THIN_THICK_THIN_MEDIUM_GAP: "thinThickThinMediumGap",
|
THIN_THICK_THIN_MEDIUM_GAP: "thinThickThinMediumGap",
|
||||||
|
/** a thin-thick-thin line with a small gap */
|
||||||
THIN_THICK_THIN_SMALL_GAP: "thinThickThinSmallGap",
|
THIN_THICK_THIN_SMALL_GAP: "thinThickThinSmallGap",
|
||||||
|
/** a three-staged gradient line, getting darker towards the paragraph */
|
||||||
THREE_D_EMBOSS: "threeDEmboss",
|
THREE_D_EMBOSS: "threeDEmboss",
|
||||||
|
/** a three-staged gradient like, getting darker away from the paragraph */
|
||||||
THREE_D_ENGRAVE: "threeDEngrave",
|
THREE_D_ENGRAVE: "threeDEngrave",
|
||||||
|
/** a triple line */
|
||||||
TRIPLE: "triple",
|
TRIPLE: "triple",
|
||||||
|
/** a wavy line */
|
||||||
WAVE: "wave",
|
WAVE: "wave",
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -2,26 +2,26 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { DocumentGrid, DocumentGridType } from ".";
|
import { DocumentGridType, createDocumentGrid } from ".";
|
||||||
|
|
||||||
describe("DocumentGrid", () => {
|
describe("createDocumentGrid", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create documentGrid with specified linePitch", () => {
|
it("should create documentGrid with specified linePitch", () => {
|
||||||
const docGrid = new DocumentGrid(360);
|
const docGrid = createDocumentGrid({ linePitch: 360 });
|
||||||
const tree = new Formatter().format(docGrid);
|
const tree = new Formatter().format(docGrid);
|
||||||
|
|
||||||
expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 360 } });
|
expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 360 } });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create documentGrid with specified linePitch and type", () => {
|
it("should create documentGrid with specified linePitch and type", () => {
|
||||||
const docGrid = new DocumentGrid(360, undefined, DocumentGridType.LINES);
|
const docGrid = createDocumentGrid({ linePitch: 360, type: DocumentGridType.LINES });
|
||||||
const tree = new Formatter().format(docGrid);
|
const tree = new Formatter().format(docGrid);
|
||||||
|
|
||||||
expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 360, "w:type": "lines" } });
|
expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 360, "w:type": "lines" } });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create documentGrid with specified linePitch,charSpace and type", () => {
|
it("should create documentGrid with specified linePitch,charSpace and type", () => {
|
||||||
const docGrid = new DocumentGrid(346, -1541, DocumentGridType.LINES_AND_CHARS);
|
const docGrid = createDocumentGrid({ linePitch: 346, charSpace: -1541, type: DocumentGridType.LINES_AND_CHARS });
|
||||||
const tree = new Formatter().format(docGrid);
|
const tree = new Formatter().format(docGrid);
|
||||||
|
|
||||||
expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 346, "w:charSpace": -1541, "w:type": "linesAndChars" } });
|
expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 346, "w:charSpace": -1541, "w:type": "linesAndChars" } });
|
||||||
|
@ -1,53 +1,113 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
import { decimalNumber } from "@util/values";
|
import { decimalNumber } from "@util/values";
|
||||||
|
|
||||||
// not implemented
|
/**
|
||||||
// <xsd:simpleType name="ST_DocGrid">
|
* Specifies the type of the current document grid, which defines the grid behavior.
|
||||||
// <xsd:restriction base="xsd:string">
|
*
|
||||||
// <xsd:enumeration value="default"/>
|
* The grid can define a grid which snaps all East Asian characters to grid positions, but leaves Latin text with its default spacing; a grid which adds the specified character pitch to all characters on each row; or a grid which affects only the line pitch for the current section.
|
||||||
// <xsd:enumeration value="lines"/>
|
*
|
||||||
// <xsd:enumeration value="linesAndChars"/>
|
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_DocGrid_topic_ID0ELYP2.html
|
||||||
// <xsd:enumeration value="snapToChars"/>
|
*
|
||||||
// </xsd:restriction>
|
* ## XSD Schema
|
||||||
// </xsd:simpleType>
|
* ```xml
|
||||||
|
* <xsd:simpleType name="ST_DocGrid">
|
||||||
// <xsd:complexType name="CT_DocGrid">
|
* <xsd:restriction base="xsd:string">
|
||||||
// <xsd:attribute name="type" type="ST_DocGrid"/>
|
* <xsd:enumeration value="default"/>
|
||||||
// <xsd:attribute name="linePitch" type="ST_DecimalNumber"/>
|
* <xsd:enumeration value="lines"/>
|
||||||
// <xsd:attribute name="charSpace" type="ST_DecimalNumber"/>
|
* <xsd:enumeration value="linesAndChars"/>
|
||||||
// </xsd:complexType>
|
* <xsd:enumeration value="snapToChars"/>
|
||||||
|
* </xsd:restriction>
|
||||||
|
* </xsd:simpleType>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export const DocumentGridType = {
|
export const DocumentGridType = {
|
||||||
|
/**
|
||||||
|
* Specifies that no document grid shall be applied to the contents of the current section in the document.
|
||||||
|
*/
|
||||||
DEFAULT: "default",
|
DEFAULT: "default",
|
||||||
|
/**
|
||||||
|
* Specifies that the parent section shall have additional line pitch added to each line within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain the specified number of lines per page.
|
||||||
|
*/
|
||||||
LINES: "lines",
|
LINES: "lines",
|
||||||
|
/**
|
||||||
|
* Specifies that the parent section shall have both the additional line pitch and character pitch added to each line and character within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain a specific number of lines per page and characters per line.
|
||||||
|
*
|
||||||
|
* When this value is set, the input specified via the user interface may be allowed in exact number of line/character pitch units. */
|
||||||
LINES_AND_CHARS: "linesAndChars",
|
LINES_AND_CHARS: "linesAndChars",
|
||||||
|
/**
|
||||||
|
* Specifies that the parent section shall have both the additional line pitch and character pitch added to each line and character within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain a specific number of lines per page and characters per line.
|
||||||
|
*
|
||||||
|
* When this value is set, the input specified via the user interface may be restricted to the number of lines per page and characters per line, with the consumer or producer translating this information based on the current font data to get the resulting line and character pitch values
|
||||||
|
*/
|
||||||
SNAP_TO_CHARS: "snapToChars",
|
SNAP_TO_CHARS: "snapToChars",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type IDocGridAttributesProperties = {
|
export type IDocGridAttributesProperties = {
|
||||||
|
/**
|
||||||
|
* Specifies the type of the current document grid, which defines the grid behavior.
|
||||||
|
*
|
||||||
|
* The grid can define a grid which snaps all East Asian characters to grid positions, but leaves Latin text with its default spacing; a grid which adds the specified character pitch to each character on each row; or a grid which affects only the line pitch for the current section.
|
||||||
|
*/
|
||||||
readonly type?: (typeof DocumentGridType)[keyof typeof DocumentGridType];
|
readonly type?: (typeof DocumentGridType)[keyof typeof DocumentGridType];
|
||||||
readonly linePitch?: number;
|
/**
|
||||||
|
* Specifies the number of lines to be allowed on the document grid for the current page assuming all lines have equal line pitch applied to them. This line pitch shall not be added to any line which appears within a table cell unless the <adjustLineHeightInTable> element (§2.15.3.1) is present in the document's compatibility settings.
|
||||||
|
*
|
||||||
|
* This attribute is specified in twentieths of a point, and defines the pitch for each line of text on this page such that the desired number of single spaced lines of text fits on the current page.
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <w:docGrid w:linePitch="684" …/>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The `linePitch` attribute specifies that 34.2 points is to the amount of pitch allowed for each line on this page in order to maintain the specific document grid. ]
|
||||||
|
*
|
||||||
|
* Individual paragraphs can override the line pitch information specified for the document grid by either:
|
||||||
|
*
|
||||||
|
* Specifying an exact line spacing value using the `lineRule` attribute of value exact on the <spacing> element (§2.3.1.33).
|
||||||
|
*
|
||||||
|
* Specifying that the paragraph text shall not snap to the document grid via the <snapToGrid> element (§2.3.1.32).
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the ST_DecimalNumber simple type (§2.18.16).
|
||||||
|
*/
|
||||||
|
readonly linePitch: number;
|
||||||
|
/**
|
||||||
|
* Specifies the number of characters to be allowed on the document grid for each line in this section.
|
||||||
|
*
|
||||||
|
* This attribute's value shall be specified by multiplying the difference between the desired character pitch and the character pitch for that character in the font size of the Normal font by 4096.
|
||||||
|
*
|
||||||
|
* This value shall then be used to add the character pitch for the specified point size to each character in the section [: This results in text in the Normal style having a specific number of characters per line. ]
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <w:docGrid w:charSize="40960" …/>
|
||||||
|
* ```
|
||||||
|
* The `charSpace` attribute specifies a value of 40960, which means that the delta between the character pitch of each character in the grid and the Normal font is 10 points, resulting in a character pitch of 11+10 = 21 points for all characters in this section. ]
|
||||||
|
*
|
||||||
|
* Individual runs of text can override the line pitch information specified for the document grid by specifying that the run text shall not snap to the document grid via the <snapToGrid> element (§2.3.2.32).
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the `ST_DecimalNumber` simple type (§2.18.16).
|
||||||
|
*/
|
||||||
readonly charSpace?: number;
|
readonly charSpace?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
|
/**
|
||||||
protected readonly xmlKeys = {
|
* This element specifies the settings for the document grid, which enables precise layout of full-width East Asian language characters within a document by specifying the desired number of characters per line and lines per page for all East Asian text content in this section.
|
||||||
type: "w:type",
|
*
|
||||||
linePitch: "w:linePitch",
|
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_docGrid_topic_ID0EHU5S.html
|
||||||
charSpace: "w:charSpace",
|
*
|
||||||
};
|
* ```xml
|
||||||
}
|
* <xsd:complexType name="CT_DocGrid">
|
||||||
|
* <xsd:attribute name="type" type="ST_DocGrid"/>
|
||||||
export class DocumentGrid extends XmlComponent {
|
* <xsd:attribute name="linePitch" type="ST_DecimalNumber"/>
|
||||||
public constructor(linePitch: number, charSpace?: number, type?: (typeof DocumentGridType)[keyof typeof DocumentGridType]) {
|
* <xsd:attribute name="charSpace" type="ST_DecimalNumber"/>
|
||||||
super("w:docGrid");
|
* </xsd:complexType>
|
||||||
|
* ```
|
||||||
this.root.push(
|
* @returns
|
||||||
new DocGridAttributes({
|
*/
|
||||||
type: type,
|
export const createDocumentGrid = ({ type, linePitch, charSpace }: IDocGridAttributesProperties): XmlComponent =>
|
||||||
linePitch: decimalNumber(linePitch),
|
new BuilderElement<IDocGridAttributesProperties>({
|
||||||
charSpace: charSpace ? decimalNumber(charSpace) : undefined,
|
name: "w:docGrid",
|
||||||
}),
|
attributes: {
|
||||||
);
|
type: { key: "w:type", value: type },
|
||||||
}
|
linePitch: { key: "w:linePitch", value: decimalNumber(linePitch) },
|
||||||
}
|
charSpace: { key: "w:charSpace", value: charSpace ? decimalNumber(charSpace) : undefined },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
@ -1,19 +1,30 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
// <xsd:simpleType name="ST_HdrFtr">
|
/**
|
||||||
// <xsd:restriction base="xsd:string">
|
* This simple type specifies the possible types of headers and footers which may be specified for a given header or footer reference in a document. This value determines the page(s) on which the current header or footer shall be displayed.
|
||||||
// <xsd:enumeration value="even"/>
|
*
|
||||||
// <xsd:enumeration value="default"/>
|
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_HdrFtr_topic_ID0E2UW2.html
|
||||||
// <xsd:enumeration value="first"/>
|
*
|
||||||
// </xsd:restriction>
|
* ## XSD Schema
|
||||||
// </xsd:simpleType>
|
* ```xml
|
||||||
|
* <xsd:simpleType name="ST_HdrFtr">
|
||||||
|
* <xsd:restriction base="xsd:string">
|
||||||
|
* <xsd:enumeration value="even"/>
|
||||||
|
* <xsd:enumeration value="default"/>
|
||||||
|
* <xsd:enumeration value="first"/>
|
||||||
|
* </xsd:restriction>
|
||||||
|
* </xsd:simpleType>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export const HeaderFooterReferenceType = {
|
export const HeaderFooterReferenceType = {
|
||||||
|
/** Specifies that this header or footer shall appear on every page in this section which is not overridden with a specific `even` or `first` page header/footer. In a section with all three types specified, this type shall be used on all odd numbered pages (counting from the `first` page in the section, not the section numbering). */
|
||||||
DEFAULT: "default",
|
DEFAULT: "default",
|
||||||
|
/** Specifies that this header or footer shall appear on the first page in this section. The appearance of this header or footer is contingent on the setting of the `titlePg` element (§2.10.6). */
|
||||||
FIRST: "first",
|
FIRST: "first",
|
||||||
|
/** Specifies that this header or footer shall appear on all even numbered pages in this section (counting from the first page in the section, not the section numbering). The appearance of this header or footer is contingent on the setting of the `evenAndOddHeaders` element (§2.10.1). */
|
||||||
EVEN: "even",
|
EVEN: "even",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// </xsd:complexType>
|
|
||||||
// <xsd:group name="EG_HdrFtrReferences">
|
// <xsd:group name="EG_HdrFtrReferences">
|
||||||
// <xsd:choice>
|
// <xsd:choice>
|
||||||
// <xsd:element name="headerReference" type="CT_HdrFtrRef" minOccurs="0"/>
|
// <xsd:element name="headerReference" type="CT_HdrFtrRef" minOccurs="0"/>
|
||||||
|
@ -1,35 +1,128 @@
|
|||||||
// http://officeopenxml.com/WPsectionLineNumbering.php
|
|
||||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
import { PositiveUniversalMeasure, decimalNumber, twipsMeasureValue } from "@util/values";
|
import { PositiveUniversalMeasure, decimalNumber, twipsMeasureValue } from "@util/values";
|
||||||
|
|
||||||
// <xsd:simpleType name="ST_LineNumberRestart">
|
/**
|
||||||
// <xsd:restriction base="xsd:string">
|
* This simple type specifies when the line numbering in the parent section shall be reset to its restart value. The line numbering increments for each line (even if the line number itself is not displayed) until it reaches the restart point specified by this element.
|
||||||
// <xsd:enumeration value="newPage"/>
|
*
|
||||||
// <xsd:enumeration value="newSection"/>
|
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_LineNumberRestart_topic_ID0EUS42.html
|
||||||
// <xsd:enumeration value="continuous"/>
|
*
|
||||||
// </xsd:restriction>
|
* ## XSD Schema
|
||||||
// </xsd:simpleType>
|
*
|
||||||
|
* ```xml
|
||||||
|
* <xsd:simpleType name="ST_LineNumberRestart">
|
||||||
|
* <xsd:restriction base="xsd:string">
|
||||||
|
* <xsd:enumeration value="newPage"/>
|
||||||
|
* <xsd:enumeration value="newSection"/>
|
||||||
|
* <xsd:enumeration value="continuous"/>
|
||||||
|
* </xsd:restriction>
|
||||||
|
* </xsd:simpleType>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export const LineNumberRestartFormat = {
|
export const LineNumberRestartFormat = {
|
||||||
|
/**
|
||||||
|
* ## Restart Line Numbering on Each Page
|
||||||
|
*
|
||||||
|
* Specifies that line numbering for the parent section shall restart to the starting value whenever a new page is displayed.
|
||||||
|
*/
|
||||||
NEW_PAGE: "newPage",
|
NEW_PAGE: "newPage",
|
||||||
|
/**
|
||||||
|
* ## Restart Line Numbering for Each Section
|
||||||
|
*
|
||||||
|
* Specifies that line numbering for the parent section shall restart to the starting value whenever the parent begins.
|
||||||
|
*/
|
||||||
NEW_SECTION: "newSection",
|
NEW_SECTION: "newSection",
|
||||||
|
/**
|
||||||
|
* ## Continue Line Numbering From Previous Section
|
||||||
|
*
|
||||||
|
* Specifies that line numbering for the parent section shall continue from the line numbering from the end of the previous section, if any.
|
||||||
|
*/
|
||||||
CONTINUOUS: "continuous",
|
CONTINUOUS: "continuous",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// <xsd:complexType name="CT_LineNumber">
|
|
||||||
// <xsd:attribute name="countBy" type="ST_DecimalNumber" use="optional"/>
|
|
||||||
// <xsd:attribute name="start" type="ST_DecimalNumber" use="optional" default="1"/>
|
|
||||||
// <xsd:attribute name="distance" type="s:ST_TwipsMeasure" use="optional"/>
|
|
||||||
// <xsd:attribute name="restart" type="ST_LineNumberRestart" use="optional" default="newPage"/>
|
|
||||||
// </xsd:complexType>
|
|
||||||
|
|
||||||
export type ILineNumberAttributes = {
|
export type ILineNumberAttributes = {
|
||||||
|
/**
|
||||||
|
* Specifies the line number increments to be displayed in the current document.
|
||||||
|
*
|
||||||
|
* Although each line has an associated line number, only lines which are an even multiple of this value shall be displayed.
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <w:lnNumType … w:countBy="5"/>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This setting ensures that only lines whose number is a multiple of (e.g. 5, 10, and 15) will have a line number displayed. ]
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the ST_DecimalNumber simple type (§2.18.16).
|
||||||
|
*/
|
||||||
readonly countBy?: number;
|
readonly countBy?: number;
|
||||||
|
/**
|
||||||
|
* ## Line Numbering Starting Value
|
||||||
|
*
|
||||||
|
* Specifies the starting value used for the first line whenever the line numbering is restarted by use of the `restart` attribute.
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <w:lnNumType w:start="3" w:countBy="5"/>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The `start` attribute specifies that line numbers shall be counted starting from the number 3.
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the ST_DecimalNumber simple type (§2.18.16).
|
||||||
|
*/
|
||||||
readonly start?: number;
|
readonly start?: number;
|
||||||
|
/**
|
||||||
|
* ## Line Numbering Restart Setting
|
||||||
|
*
|
||||||
|
* Specifies when the line numbering in this section shall be reset to the line number specified by the `start` attribute's value.
|
||||||
|
*
|
||||||
|
* The line numbering increments for each line (even if it is not displayed) until it reaches the restart point specified by this element.
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <w:sectPr>
|
||||||
|
* ...
|
||||||
|
* <w:lnNumType w:restart="newPage" ... />
|
||||||
|
* </w:sectPr>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The value of `newPage` specifies that the line numbers shall restart at the top of each page to the value specified by the `start` attribute. In this case, `newPage` is the default, so this value could have been omitted entirely.
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the ST_LineNumberRestart simple type (§2.18.54).
|
||||||
|
*/
|
||||||
readonly restart?: (typeof LineNumberRestartFormat)[keyof typeof LineNumberRestartFormat];
|
readonly restart?: (typeof LineNumberRestartFormat)[keyof typeof LineNumberRestartFormat];
|
||||||
|
/**
|
||||||
|
* Specifies the distance between the text margin and the edge of any line numbers appearing in that section.
|
||||||
|
*
|
||||||
|
* ```.xml
|
||||||
|
* <w:lnNumType ... w:distance="720"/>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the ST_TwipsMeasure simple type (§2.18.105).
|
||||||
|
*/
|
||||||
readonly distance?: number | PositiveUniversalMeasure;
|
readonly distance?: number | PositiveUniversalMeasure;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This element specifies the settings for line numbering to be displayed before each column of text in this section in the document.
|
||||||
|
*
|
||||||
|
* References:
|
||||||
|
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_lnNumType_topic_ID0EVRAT.html
|
||||||
|
* - http://officeopenxml.com/WPsectionLineNumbering.php
|
||||||
|
*
|
||||||
|
* ## XSD Schema
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <xsd:complexType name="CT_LineNumber">
|
||||||
|
* <xsd:attribute name="countBy" type="ST_DecimalNumber" use="optional"/>
|
||||||
|
* <xsd:attribute name="start" type="ST_DecimalNumber" use="optional" default="1"/>
|
||||||
|
* <xsd:attribute name="distance" type="s:ST_TwipsMeasure" use="optional"/>
|
||||||
|
* <xsd:attribute name="restart" type="ST_LineNumberRestart" use="optional" default="newPage"/>
|
||||||
|
* </xsd:complexType>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export const createLineNumberType = ({ countBy, start, restart, distance }: ILineNumberAttributes): XmlComponent =>
|
export const createLineNumberType = ({ countBy, start, restart, distance }: ILineNumberAttributes): XmlComponent =>
|
||||||
new BuilderElement<ILineNumberAttributes>({
|
new BuilderElement<ILineNumberAttributes>({
|
||||||
name: "w:lnNumType",
|
name: "w:lnNumType",
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { PageOrientation, PageSize } from "./page-size";
|
import { PageOrientation, createPageSize } from "./page-size";
|
||||||
|
|
||||||
describe("PageSize", () => {
|
describe("PageSize", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create page size with portrait", () => {
|
it("should create page size with portrait", () => {
|
||||||
const properties = new PageSize(100, 200, PageOrientation.PORTRAIT);
|
const properties = createPageSize({ width: 100, height: 200, orientation: PageOrientation.PORTRAIT });
|
||||||
const tree = new Formatter().format(properties);
|
const tree = new Formatter().format(properties);
|
||||||
|
|
||||||
expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]);
|
expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]);
|
||||||
@ -15,7 +15,7 @@ describe("PageSize", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should create page size with horizontal and invert the lengths", () => {
|
it("should create page size with horizontal and invert the lengths", () => {
|
||||||
const properties = new PageSize(100, 200, PageOrientation.LANDSCAPE);
|
const properties = createPageSize({ width: 100, height: 200, orientation: PageOrientation.LANDSCAPE });
|
||||||
const tree = new Formatter().format(properties);
|
const tree = new Formatter().format(properties);
|
||||||
|
|
||||||
expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]);
|
expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]);
|
||||||
|
@ -1,48 +1,132 @@
|
|||||||
import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
import { PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
|
import { PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
|
||||||
|
|
||||||
// <xsd:simpleType name="ST_PageOrientation">
|
/**
|
||||||
// <xsd:restriction base="xsd:string">
|
* This simple type specifies the orientation of all pages in the parent section. This information is used to determine the actual paper size to use when printing the file.
|
||||||
// <xsd:enumeration value="portrait"/>
|
*
|
||||||
// <xsd:enumeration value="landscape"/>
|
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_PageOrientation_topic_ID0EKBK3.html
|
||||||
// </xsd:restriction>
|
*
|
||||||
// </xsd:simpleType>
|
* ## XSD Schema
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <xsd:simpleType name="ST_PageOrientation">
|
||||||
|
* <xsd:restriction base="xsd:string">
|
||||||
|
* <xsd:enumeration value="portrait"/>
|
||||||
|
* <xsd:enumeration value="landscape"/>
|
||||||
|
* </xsd:restriction>
|
||||||
|
* </xsd:simpleType>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export const PageOrientation = {
|
export const PageOrientation = {
|
||||||
|
/**
|
||||||
|
* ## Portrait Mode
|
||||||
|
*
|
||||||
|
* Specifies that pages in this section shall be printed in portrait mode.
|
||||||
|
*/
|
||||||
PORTRAIT: "portrait",
|
PORTRAIT: "portrait",
|
||||||
|
/**
|
||||||
|
* ## Landscape Mode
|
||||||
|
*
|
||||||
|
* Specifies that pages in this section shall be printed in landscape mode, which prints the page contents with a 90 degree rotation with respect to the normal page orientation.
|
||||||
|
*/
|
||||||
LANDSCAPE: "landscape",
|
LANDSCAPE: "landscape",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// <xsd:complexType name="CT_PageSz">
|
|
||||||
// <xsd:attribute name="w" type="s:ST_TwipsMeasure"/>
|
|
||||||
// <xsd:attribute name="h" type="s:ST_TwipsMeasure"/>
|
|
||||||
// <xsd:attribute name="orient" type="ST_PageOrientation" use="optional"/>
|
|
||||||
// <xsd:attribute name="code" type="ST_DecimalNumber" use="optional"/>
|
|
||||||
// </xsd:complexType>
|
|
||||||
export type IPageSizeAttributes = {
|
export type IPageSizeAttributes = {
|
||||||
readonly width?: number | PositiveUniversalMeasure;
|
/**
|
||||||
readonly height?: number | PositiveUniversalMeasure;
|
* ## Page Width
|
||||||
|
*
|
||||||
|
* This attribute indicates the width (in twentieths of a point) for all pages in the current section.
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <w:pgSz w:w="15840" w:h="12240" />
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* All pages in this section are displayed on a page that is 15840 twentieths of a point (11") wide.
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the ST_TwipsMeasure simple type (§2.18.105).
|
||||||
|
*/
|
||||||
|
readonly width: number | PositiveUniversalMeasure;
|
||||||
|
/**
|
||||||
|
* ## Page Height
|
||||||
|
*
|
||||||
|
* Specifies the height (in twentieths of a point) for all pages in the current section.
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <w:pgSz w:w="15840" w:h="12240" />
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* All pages in this section are displayed on a page that is `12240` twentieths of a point (`8.5"`) tall.
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the `ST_TwipsMeasure` simple type (§2.18.105).
|
||||||
|
*/
|
||||||
|
readonly height: number | PositiveUniversalMeasure;
|
||||||
|
/**
|
||||||
|
* ## Page Orientation
|
||||||
|
*
|
||||||
|
* Specifies the orientation of all pages in this section.
|
||||||
|
*
|
||||||
|
* This information is used to determine the actual paper size to use on the printer.
|
||||||
|
*
|
||||||
|
* This implies that the actual paper size width and height are reversed for pages in this section. If this attribute is omitted, then portrait shall be implied.
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <w:pgSz w:w="15840" w:h="12240" w:orient="landscape" />
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Although the page width is 11", and page height is 8.5", according to the `w` and `h` attributes, because the `orient` attribute is set to landscape, pages in this section are printed on 8.5x11" paper in landscape mode.
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the `ST_PageOrientation` simple type (§2.18.71).
|
||||||
|
*/
|
||||||
readonly orientation?: (typeof PageOrientation)[keyof typeof PageOrientation];
|
readonly orientation?: (typeof PageOrientation)[keyof typeof PageOrientation];
|
||||||
|
/**
|
||||||
|
* ## Printer Paper Code
|
||||||
|
*
|
||||||
|
* Specifies a printer-specific paper code for the paper type, which shall be used by the printer for pages in this section.
|
||||||
|
*
|
||||||
|
* This code is stored to ensure the proper paper type is chosen if the specified paper size matches the sizes of multiple paper types supported by the current printer.
|
||||||
|
*
|
||||||
|
* It will be sent to the printer and used by the printer to determine the appropriate paper type to use when printing.
|
||||||
|
*
|
||||||
|
* This value is not interpreted or modified other than storing it as specified by the printer.
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the `ST_DecimalNumber` simple type (§2.18.16).
|
||||||
|
*/
|
||||||
|
readonly code?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class PageSize extends XmlComponent {
|
/**
|
||||||
public constructor(
|
* This element specifies the properties (size and orientation) for all pages in the current section.
|
||||||
width: number | PositiveUniversalMeasure,
|
*
|
||||||
height: number | PositiveUniversalMeasure,
|
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_pgSz_topic_ID0ENEDT.html?hl=pgsz%2Cpage%2Csize
|
||||||
orientation: (typeof PageOrientation)[keyof typeof PageOrientation],
|
*
|
||||||
) {
|
* ## XSD Schema
|
||||||
super("w:pgSz");
|
*
|
||||||
|
* ```xml
|
||||||
const flip = orientation === PageOrientation.LANDSCAPE;
|
* <xsd:complexType name="CT_PageSz">
|
||||||
|
* <xsd:attribute name="w" type="s:ST_TwipsMeasure"/>
|
||||||
const widthTwips = twipsMeasureValue(width);
|
* <xsd:attribute name="h" type="s:ST_TwipsMeasure"/>
|
||||||
const heightTwips = twipsMeasureValue(height);
|
* <xsd:attribute name="orient" type="ST_PageOrientation" use="optional"/>
|
||||||
|
* <xsd:attribute name="code" type="ST_DecimalNumber" use="optional"/>
|
||||||
this.root.push(
|
* </xsd:complexType>
|
||||||
new NextAttributeComponent<IPageSizeAttributes>({
|
* ```
|
||||||
width: { key: "w:w", value: flip ? heightTwips : widthTwips },
|
*/
|
||||||
height: { key: "w:h", value: flip ? widthTwips : heightTwips },
|
export const createPageSize = ({ width, height, orientation, code }: IPageSizeAttributes): XmlComponent => {
|
||||||
orientation: { key: "w:orient", value: orientation },
|
const widthTwips = twipsMeasureValue(width);
|
||||||
}),
|
const heightTwips = twipsMeasureValue(height);
|
||||||
);
|
return new BuilderElement<IPageSizeAttributes>({
|
||||||
}
|
name: "w:pgSz",
|
||||||
}
|
attributes: {
|
||||||
|
width: { key: "w:w", value: orientation === PageOrientation.LANDSCAPE ? heightTwips : widthTwips },
|
||||||
|
height: { key: "w:h", value: orientation === PageOrientation.LANDSCAPE ? widthTwips : heightTwips },
|
||||||
|
orientation: { key: "w:orient", value: orientation },
|
||||||
|
code: { key: "w:code", value: code },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -6,13 +6,13 @@ import { VerticalAlign, VerticalAlignElement } from "@file/vertical-align";
|
|||||||
import { OnOffElement, XmlComponent } from "@file/xml-components";
|
import { OnOffElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { Columns, IColumnsAttributes } from "./properties/columns";
|
import { Columns, IColumnsAttributes } from "./properties/columns";
|
||||||
import { DocumentGrid, IDocGridAttributesProperties } from "./properties/doc-grid";
|
import { IDocGridAttributesProperties, createDocumentGrid } from "./properties/doc-grid";
|
||||||
import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./properties/header-footer-reference";
|
import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./properties/header-footer-reference";
|
||||||
import { ILineNumberAttributes, createLineNumberType } from "./properties/line-number";
|
import { ILineNumberAttributes, createLineNumberType } from "./properties/line-number";
|
||||||
import { IPageBordersOptions, PageBorders } from "./properties/page-borders";
|
import { IPageBordersOptions, PageBorders } from "./properties/page-borders";
|
||||||
import { IPageMarginAttributes, PageMargin } from "./properties/page-margin";
|
import { IPageMarginAttributes, PageMargin } from "./properties/page-margin";
|
||||||
import { IPageNumberTypeAttributes, PageNumberType } from "./properties/page-number";
|
import { IPageNumberTypeAttributes, PageNumberType } from "./properties/page-number";
|
||||||
import { IPageSizeAttributes, PageOrientation, PageSize } from "./properties/page-size";
|
import { IPageSizeAttributes, PageOrientation, createPageSize } from "./properties/page-size";
|
||||||
import { PageTextDirection, PageTextDirectionType } from "./properties/page-text-direction";
|
import { PageTextDirection, PageTextDirectionType } from "./properties/page-text-direction";
|
||||||
import { SectionType, Type } from "./properties/section-type";
|
import { SectionType, Type } from "./properties/section-type";
|
||||||
|
|
||||||
@ -24,13 +24,13 @@ export type IHeaderFooterGroup<T> = {
|
|||||||
|
|
||||||
export type ISectionPropertiesOptions = {
|
export type ISectionPropertiesOptions = {
|
||||||
readonly page?: {
|
readonly page?: {
|
||||||
readonly size?: IPageSizeAttributes;
|
readonly size?: Partial<IPageSizeAttributes>;
|
||||||
readonly margin?: IPageMarginAttributes;
|
readonly margin?: IPageMarginAttributes;
|
||||||
readonly pageNumbers?: IPageNumberTypeAttributes;
|
readonly pageNumbers?: IPageNumberTypeAttributes;
|
||||||
readonly borders?: IPageBordersOptions;
|
readonly borders?: IPageBordersOptions;
|
||||||
readonly textDirection?: (typeof PageTextDirectionType)[keyof typeof PageTextDirectionType];
|
readonly textDirection?: (typeof PageTextDirectionType)[keyof typeof PageTextDirectionType];
|
||||||
};
|
};
|
||||||
readonly grid?: IDocGridAttributesProperties;
|
readonly grid?: Partial<IDocGridAttributesProperties>;
|
||||||
readonly headerWrapperGroup?: IHeaderFooterGroup<HeaderWrapper>;
|
readonly headerWrapperGroup?: IHeaderFooterGroup<HeaderWrapper>;
|
||||||
readonly footerWrapperGroup?: IHeaderFooterGroup<FooterWrapper>;
|
readonly footerWrapperGroup?: IHeaderFooterGroup<FooterWrapper>;
|
||||||
readonly lineNumbers?: ILineNumberAttributes;
|
readonly lineNumbers?: ILineNumberAttributes;
|
||||||
@ -128,7 +128,7 @@ export class SectionProperties extends XmlComponent {
|
|||||||
this.root.push(new Type(type));
|
this.root.push(new Type(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.push(new PageSize(width, height, orientation));
|
this.root.push(createPageSize({ width, height, orientation }));
|
||||||
this.root.push(new PageMargin(top, right, bottom, left, header, footer, gutter));
|
this.root.push(new PageMargin(top, right, bottom, left, header, footer, gutter));
|
||||||
|
|
||||||
if (borders) {
|
if (borders) {
|
||||||
@ -157,7 +157,7 @@ export class SectionProperties extends XmlComponent {
|
|||||||
this.root.push(new PageTextDirection(textDirection));
|
this.root.push(new PageTextDirection(textDirection));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.push(new DocumentGrid(linePitch, charSpace, gridType));
|
this.root.push(createDocumentGrid({ linePitch, charSpace, type: gridType }));
|
||||||
}
|
}
|
||||||
|
|
||||||
private addHeaderFooterGroup(
|
private addHeaderFooterGroup(
|
||||||
|
@ -91,28 +91,20 @@ describe("Anchor", () => {
|
|||||||
// 2: horizontal position
|
// 2: horizontal position
|
||||||
const horizontalPosition = newJson.root[2];
|
const horizontalPosition = newJson.root[2];
|
||||||
assert.equal(horizontalPosition.rootKey, "wp:positionH");
|
assert.equal(horizontalPosition.rootKey, "wp:positionH");
|
||||||
assert.include(horizontalPosition.root[0].root, {
|
|
||||||
relativeFrom: "page",
|
|
||||||
});
|
|
||||||
assert.equal(horizontalPosition.root[1].rootKey, "wp:posOffset");
|
assert.equal(horizontalPosition.root[1].rootKey, "wp:posOffset");
|
||||||
assert.include(horizontalPosition.root[1].root[0], 0);
|
assert.include(horizontalPosition.root[1].root[0], 0);
|
||||||
|
|
||||||
// 3: vertical position
|
// 3: vertical position
|
||||||
const verticalPosition = newJson.root[3];
|
const verticalPosition = newJson.root[3];
|
||||||
assert.equal(verticalPosition.rootKey, "wp:positionV");
|
assert.equal(verticalPosition.rootKey, "wp:positionV");
|
||||||
assert.include(verticalPosition.root[0].root, {
|
|
||||||
relativeFrom: "page",
|
|
||||||
});
|
|
||||||
assert.equal(verticalPosition.root[1].rootKey, "wp:posOffset");
|
assert.equal(verticalPosition.root[1].rootKey, "wp:posOffset");
|
||||||
assert.include(verticalPosition.root[1].root[0], 0);
|
assert.include(verticalPosition.root[1].root[0], 0);
|
||||||
|
|
||||||
// 4: extent
|
// 4: extent
|
||||||
const extent = newJson.root[4];
|
const extent = newJson.root[4];
|
||||||
assert.equal(extent.rootKey, "wp:extent");
|
assert.equal(extent.rootKey, "wp:extent");
|
||||||
assert.include(extent.root[0].root, {
|
|
||||||
cx: 952500,
|
|
||||||
cy: 952500,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 5: effect extent
|
// 5: effect extent
|
||||||
const effectExtent = newJson.root[5];
|
const effectExtent = newJson.root[5];
|
||||||
|
@ -3,13 +3,13 @@ import { IMediaData, IMediaDataTransformation } from "@file/media";
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { IDrawingOptions } from "../drawing";
|
import { IDrawingOptions } from "../drawing";
|
||||||
import { HorizontalPosition, IFloating, SimplePos, VerticalPosition } from "../floating";
|
import { IFloating, createHorizontalPosition, createSimplePos, createVerticalPosition } from "../floating";
|
||||||
import { Graphic } from "../inline/graphic";
|
import { Graphic } from "../inline/graphic";
|
||||||
import { TextWrappingType, WrapNone, WrapSquare, WrapTight, WrapTopAndBottom } from "../text-wrap";
|
import { TextWrappingType, WrapNone, WrapSquare, WrapTight, WrapTopAndBottom } from "../text-wrap";
|
||||||
import { DocProperties } from "./../doc-properties/doc-properties";
|
import { DocProperties } from "./../doc-properties/doc-properties";
|
||||||
import { createEffectExtent } from "./../effect-extent/effect-extent";
|
import { createEffectExtent } from "./../effect-extent/effect-extent";
|
||||||
import { Extent } from "./../extent/extent";
|
import { createExtent } from "./../extent/extent";
|
||||||
import { GraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties";
|
import { createGraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties";
|
||||||
import { AnchorAttributes } from "./anchor-attributes";
|
import { AnchorAttributes } from "./anchor-attributes";
|
||||||
|
|
||||||
// <xsd:complexType name="CT_Anchor">
|
// <xsd:complexType name="CT_Anchor">
|
||||||
@ -74,10 +74,10 @@ export class Anchor extends XmlComponent {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.root.push(new SimplePos());
|
this.root.push(createSimplePos());
|
||||||
this.root.push(new HorizontalPosition(floating.horizontalPosition));
|
this.root.push(createHorizontalPosition(floating.horizontalPosition));
|
||||||
this.root.push(new VerticalPosition(floating.verticalPosition));
|
this.root.push(createVerticalPosition(floating.verticalPosition));
|
||||||
this.root.push(new Extent(transform.emus.x, transform.emus.y));
|
this.root.push(createExtent({ x: transform.emus.x, y: transform.emus.y }));
|
||||||
this.root.push(createEffectExtent({ top: 0, right: 0, bottom: 0, left: 0 }));
|
this.root.push(createEffectExtent({ top: 0, right: 0, bottom: 0, left: 0 }));
|
||||||
|
|
||||||
if (drawingOptions.floating !== undefined && drawingOptions.floating.wrap !== undefined) {
|
if (drawingOptions.floating !== undefined && drawingOptions.floating.wrap !== undefined) {
|
||||||
@ -100,7 +100,7 @@ export class Anchor extends XmlComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.root.push(new DocProperties(drawingOptions.docProperties));
|
this.root.push(new DocProperties(drawingOptions.docProperties));
|
||||||
this.root.push(new GraphicFrameProperties());
|
this.root.push(createGraphicFrameProperties());
|
||||||
this.root.push(new Graphic({ mediaData, transform, outline: drawingOptions.outline }));
|
this.root.push(new Graphic({ mediaData, transform, outline: drawingOptions.outline }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,50 @@
|
|||||||
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
export type EffectExtentAttributes = {
|
export type EffectExtentAttributes = {
|
||||||
|
/**
|
||||||
|
* ## Additional Extent on Top Edge
|
||||||
|
*
|
||||||
|
* Specifies the additional length, in EMUs, which shall be added to the top edge of the DrawingML object to determine its actual top edge including effects.
|
||||||
|
*/
|
||||||
readonly top: number;
|
readonly top: number;
|
||||||
|
/**
|
||||||
|
* ## Additional Extent on Right Edge
|
||||||
|
*
|
||||||
|
* Specifies the additional length, in EMUs, which shall be added to the right edge of the DrawingML object to determine its actual right edge including effects.
|
||||||
|
*/
|
||||||
readonly right: number;
|
readonly right: number;
|
||||||
|
/**
|
||||||
|
* ## Additional Extent on Bottom Edge
|
||||||
|
*
|
||||||
|
* Specifies the additional length, in EMUs, which shall be added to the bottom edge of the DrawingML object to determine its actual bottom edge including effects.
|
||||||
|
*/
|
||||||
readonly bottom: number;
|
readonly bottom: number;
|
||||||
|
/**
|
||||||
|
* ## Additional Extent on Left Edge
|
||||||
|
*
|
||||||
|
* Specifies the additional length, in EMUs, which shall be added to the left edge of the DrawingML object to determine its actual left edge including effects.
|
||||||
|
*/
|
||||||
readonly left: number;
|
readonly left: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
// <xsd:complexType name="CT_EffectExtent">
|
/**
|
||||||
// <xsd:attribute name="l" type="a:ST_Coordinate" use="required"/>
|
* This element specifies the additional extent which shall be added to each edge of the image (top, bottom, left, right) in order to compensate for any drawing effects applied to the DrawingML object.
|
||||||
// <xsd:attribute name="t" type="a:ST_Coordinate" use="required"/>
|
*
|
||||||
// <xsd:attribute name="r" type="a:ST_Coordinate" use="required"/>
|
* The `<extent>` element (§5.5.2.7) specifies the size of the actual DrawingML object; however, an object may have effects applied which change its overall size
|
||||||
// <xsd:attribute name="b" type="a:ST_Coordinate" use="required"/>
|
*
|
||||||
// </xsd:complexType>
|
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_effectExtent_topic_ID0E5O3OB.html
|
||||||
|
*
|
||||||
|
* ## XSD Schema
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <xsd:complexType name="CT_EffectExtent">
|
||||||
|
* <xsd:attribute name="l" type="a:ST_Coordinate" use="required"/>
|
||||||
|
* <xsd:attribute name="t" type="a:ST_Coordinate" use="required"/>
|
||||||
|
* <xsd:attribute name="r" type="a:ST_Coordinate" use="required"/>
|
||||||
|
* <xsd:attribute name="b" type="a:ST_Coordinate" use="required"/>
|
||||||
|
* </xsd:complexType>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
export const createEffectExtent = ({ top, right, bottom, left }: EffectExtentAttributes): XmlComponent =>
|
export const createEffectExtent = ({ top, right, bottom, left }: EffectExtentAttributes): XmlComponent =>
|
||||||
new BuilderElement<EffectExtentAttributes>({
|
new BuilderElement<EffectExtentAttributes>({
|
||||||
name: "wp:effectExtent",
|
name: "wp:effectExtent",
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
import { XmlAttributeComponent } from "@file/xml-components";
|
|
||||||
|
|
||||||
export class ExtentAttributes extends XmlAttributeComponent<{
|
|
||||||
readonly cx?: number;
|
|
||||||
readonly cy?: number;
|
|
||||||
}> {
|
|
||||||
protected readonly xmlKeys = {
|
|
||||||
cx: "cx",
|
|
||||||
cy: "cy",
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,18 +1,60 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { ExtentAttributes } from "./extent-attributes";
|
type ExtentAttributes = {
|
||||||
|
/**
|
||||||
|
* ## Extent Length
|
||||||
|
*
|
||||||
|
* Specifies the length of the extents rectangle in EMUs. This rectangle shall dictate the size of the object as displayed (the result of any scaling to the original object).
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <... cx="1828800" cy="200000"/>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The `cx` attributes specifies that this object has a height of `1828800` EMUs (English Metric Units).
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the `ST_PositiveCoordinate` simple type (§5.1.12.42).
|
||||||
|
*/
|
||||||
|
readonly x?: number;
|
||||||
|
/**
|
||||||
|
* ## Extent Width
|
||||||
|
*
|
||||||
|
* Specifies the width of the extents rectangle in EMUs. This rectangle shall dictate the size of the object as displayed (the result of any scaling to the original object).
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <... cx="1828800" cy="200000"/>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The `cy` attribute specifies that this object has a width of `200000` EMUs (English Metric Units).
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the `ST_PositiveCoordinate` simple type (§5.1.12.42).
|
||||||
|
*/
|
||||||
|
readonly y?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export class Extent extends XmlComponent {
|
/**
|
||||||
private readonly attributes: ExtentAttributes;
|
* This element specifies the extents of the parent `DrawingML` object within the document (i.e. its final height and width).
|
||||||
|
*
|
||||||
public constructor(x: number, y: number) {
|
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_extent_topic_ID0EQB4OB.html
|
||||||
super("wp:extent");
|
*
|
||||||
|
* ## XSD Schema
|
||||||
this.attributes = new ExtentAttributes({
|
*
|
||||||
cx: x,
|
* ```xml
|
||||||
cy: y,
|
* <complexType name="CT_PositiveSize2D">
|
||||||
});
|
* <attribute name="cx" type="ST_PositiveCoordinate" use="required"/>
|
||||||
|
* <attribute name="cy" type="ST_PositiveCoordinate" use="required"/>
|
||||||
this.root.push(this.attributes);
|
* </complexType>
|
||||||
}
|
* ```
|
||||||
}
|
*/
|
||||||
|
export const createExtent = ({ x, y }: ExtentAttributes): XmlComponent =>
|
||||||
|
new BuilderElement<ExtentAttributes>({
|
||||||
|
name: "wp:extent",
|
||||||
|
attributes: {
|
||||||
|
x: { key: "cx", value: x },
|
||||||
|
y: { key: "cy", value: y },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
@ -3,12 +3,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
import { VerticalPositionAlign } from "@file/shared/alignment";
|
import { VerticalPositionAlign } from "@file/shared/alignment";
|
||||||
|
|
||||||
import { Align } from "./align";
|
import { createAlign } from "./align";
|
||||||
|
|
||||||
describe("Align", () => {
|
describe("Align", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a element with correct root key", () => {
|
it("should create a element with correct root key", () => {
|
||||||
const tree = new Formatter().format(new Align(VerticalPositionAlign.CENTER));
|
const tree = new Formatter().format(createAlign(VerticalPositionAlign.CENTER));
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"wp:align": ["center"],
|
"wp:align": ["center"],
|
||||||
});
|
});
|
||||||
|
@ -1,14 +1,23 @@
|
|||||||
// http://officeopenxml.com/drwPicFloating-position.php
|
|
||||||
import { HorizontalPositionAlign, VerticalPositionAlign } from "@file/shared/alignment";
|
import { HorizontalPositionAlign, VerticalPositionAlign } from "@file/shared/alignment";
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
export class Align extends XmlComponent {
|
/**
|
||||||
public constructor(
|
* # Relative Horizontal/Vertical Alignment
|
||||||
value:
|
*
|
||||||
| (typeof HorizontalPositionAlign)[keyof typeof HorizontalPositionAlign]
|
* This element specifies how a DrawingML object shall be horizontally/vertically aligned relative to the horizontal/vertical alignment base defined by the parent element. Once an alignment base is defined, this element shall determine how the DrawingML object shall be aligned relative to that location.
|
||||||
| (typeof VerticalPositionAlign)[keyof typeof VerticalPositionAlign],
|
*
|
||||||
) {
|
* References:
|
||||||
super("wp:align");
|
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_align_topic_ID0EYZZOB.html
|
||||||
this.root.push(value);
|
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_align_topic_ID0ET4ZOB.html
|
||||||
}
|
* - http://officeopenxml.com/drwPicFloating-position.php
|
||||||
}
|
*/
|
||||||
|
export const createAlign = (
|
||||||
|
value:
|
||||||
|
| (typeof HorizontalPositionAlign)[keyof typeof HorizontalPositionAlign]
|
||||||
|
| (typeof VerticalPositionAlign)[keyof typeof VerticalPositionAlign],
|
||||||
|
): XmlComponent =>
|
||||||
|
new BuilderElement({
|
||||||
|
name: "wp:align",
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
children: [value as any],
|
||||||
|
});
|
||||||
|
@ -4,25 +4,115 @@ import { HorizontalPositionAlign, VerticalPositionAlign } from "@file/shared/ali
|
|||||||
|
|
||||||
import { ITextWrapping } from "../text-wrap";
|
import { ITextWrapping } from "../text-wrap";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Horizontal Relative Positioning
|
||||||
|
*
|
||||||
|
* Reference: https://www.datypic.com/sc/ooxml/t-wp_ST_RelFromH.html
|
||||||
|
*/
|
||||||
export const HorizontalPositionRelativeFrom = {
|
export const HorizontalPositionRelativeFrom = {
|
||||||
|
/**
|
||||||
|
* ## Character
|
||||||
|
*
|
||||||
|
* Specifies that the horizontal positioning shall be relative to the position of the anchor within its run content.
|
||||||
|
*/
|
||||||
CHARACTER: "character",
|
CHARACTER: "character",
|
||||||
|
/**
|
||||||
|
* ## Column
|
||||||
|
*
|
||||||
|
* Specifies that the horizontal positioning shall be relative to the extents of the column which contains its anchor.
|
||||||
|
*/
|
||||||
COLUMN: "column",
|
COLUMN: "column",
|
||||||
|
/**
|
||||||
|
* ## Inside Margin
|
||||||
|
*
|
||||||
|
* Specifies that the horizontal positioning shall be relative to the inside margin of the current page (the left margin on odd pages, right on even pages).
|
||||||
|
*/
|
||||||
INSIDE_MARGIN: "insideMargin",
|
INSIDE_MARGIN: "insideMargin",
|
||||||
|
/**
|
||||||
|
* ## Left Margin
|
||||||
|
*
|
||||||
|
* Specifies that the horizontal positioning shall be relative to the left margin of the page.
|
||||||
|
*/
|
||||||
LEFT_MARGIN: "leftMargin",
|
LEFT_MARGIN: "leftMargin",
|
||||||
|
/**
|
||||||
|
* ## Page Margin
|
||||||
|
*
|
||||||
|
* Specifies that the horizontal positioning shall be relative to the page margins.
|
||||||
|
*/
|
||||||
MARGIN: "margin",
|
MARGIN: "margin",
|
||||||
|
/**
|
||||||
|
* ## Outside Margin
|
||||||
|
*
|
||||||
|
* Specifies that the horizontal positioning shall be relative to the outside margin of the current page (the right margin on odd pages, left on even pages).
|
||||||
|
*/
|
||||||
OUTSIDE_MARGIN: "outsideMargin",
|
OUTSIDE_MARGIN: "outsideMargin",
|
||||||
|
/**
|
||||||
|
* ## Page Edge
|
||||||
|
*
|
||||||
|
* Specifies that the horizontal positioning shall be relative to the edge of the page.
|
||||||
|
*/
|
||||||
PAGE: "page",
|
PAGE: "page",
|
||||||
|
/**
|
||||||
|
* ## Right Margin
|
||||||
|
*
|
||||||
|
* Specifies that the horizontal positioning shall be relative to the right margin of the page.
|
||||||
|
*/
|
||||||
RIGHT_MARGIN: "rightMargin",
|
RIGHT_MARGIN: "rightMargin",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vertical Relative Positioning
|
||||||
|
*
|
||||||
|
* Reference: https://www.datypic.com/sc/ooxml/t-wp_ST_RelFromV.html
|
||||||
|
*/
|
||||||
export const VerticalPositionRelativeFrom = {
|
export const VerticalPositionRelativeFrom = {
|
||||||
|
/**
|
||||||
|
* ## Bottom Margin
|
||||||
|
*
|
||||||
|
* Specifies that the vertical positioning shall be relative to the bottom margin of the current page.
|
||||||
|
*/
|
||||||
BOTTOM_MARGIN: "bottomMargin",
|
BOTTOM_MARGIN: "bottomMargin",
|
||||||
|
/**
|
||||||
|
* ## Inside Margin
|
||||||
|
*
|
||||||
|
* Specifies that the vertical positioning shall be relative to the inside margin of the current page.
|
||||||
|
*/
|
||||||
INSIDE_MARGIN: "insideMargin",
|
INSIDE_MARGIN: "insideMargin",
|
||||||
|
/**
|
||||||
|
* ## Line
|
||||||
|
*
|
||||||
|
* Specifies that the vertical positioning shall be relative to the line containing the anchor character.
|
||||||
|
*/
|
||||||
LINE: "line",
|
LINE: "line",
|
||||||
|
/**
|
||||||
|
* ## Page Margin
|
||||||
|
*
|
||||||
|
* Specifies that the vertical positioning shall be relative to the page margins.
|
||||||
|
*/
|
||||||
MARGIN: "margin",
|
MARGIN: "margin",
|
||||||
|
/**
|
||||||
|
* ## Outside Margin
|
||||||
|
*
|
||||||
|
* Specifies that the vertical positioning shall be relative to the outside margin of the current page.
|
||||||
|
*/
|
||||||
OUTSIDE_MARGIN: "outsideMargin",
|
OUTSIDE_MARGIN: "outsideMargin",
|
||||||
|
/**
|
||||||
|
* ## Page Edge
|
||||||
|
*
|
||||||
|
* Specifies that the vertical positioning shall be relative to the edge of the page.
|
||||||
|
*/
|
||||||
PAGE: "page",
|
PAGE: "page",
|
||||||
|
/**
|
||||||
|
* ## Paragraph
|
||||||
|
*
|
||||||
|
* Specifies that the vertical positioning shall be relative to the paragraph which contains the drawing anchor.
|
||||||
|
*/
|
||||||
PARAGRAPH: "paragraph",
|
PARAGRAPH: "paragraph",
|
||||||
|
/**
|
||||||
|
* ## Top Margin
|
||||||
|
*
|
||||||
|
* Specifies that the vertical positioning shall be relative to the top margin of the current page.
|
||||||
|
*/
|
||||||
TOP_MARGIN: "topMargin",
|
TOP_MARGIN: "topMargin",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@ import { Formatter } from "@export/formatter";
|
|||||||
import { HorizontalPositionAlign } from "@file/shared/alignment";
|
import { HorizontalPositionAlign } from "@file/shared/alignment";
|
||||||
|
|
||||||
import { HorizontalPositionRelativeFrom } from "./floating-position";
|
import { HorizontalPositionRelativeFrom } from "./floating-position";
|
||||||
import { HorizontalPosition } from "./horizontal-position";
|
import { createHorizontalPosition } from "./horizontal-position";
|
||||||
|
|
||||||
describe("HorizontalPosition", () => {
|
describe("HorizontalPosition", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a element with position align", () => {
|
it("should create a element with position align", () => {
|
||||||
const tree = new Formatter().format(
|
const tree = new Formatter().format(
|
||||||
new HorizontalPosition({
|
createHorizontalPosition({
|
||||||
relative: HorizontalPositionRelativeFrom.MARGIN,
|
relative: HorizontalPositionRelativeFrom.MARGIN,
|
||||||
align: HorizontalPositionAlign.CENTER,
|
align: HorizontalPositionAlign.CENTER,
|
||||||
}),
|
}),
|
||||||
@ -31,7 +31,7 @@ describe("HorizontalPosition", () => {
|
|||||||
|
|
||||||
it("should create a element with offset", () => {
|
it("should create a element with offset", () => {
|
||||||
const tree = new Formatter().format(
|
const tree = new Formatter().format(
|
||||||
new HorizontalPosition({
|
createHorizontalPosition({
|
||||||
relative: HorizontalPositionRelativeFrom.MARGIN,
|
relative: HorizontalPositionRelativeFrom.MARGIN,
|
||||||
offset: 40,
|
offset: 40,
|
||||||
}),
|
}),
|
||||||
@ -51,7 +51,7 @@ describe("HorizontalPosition", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should require one of align or offset", () => {
|
it("should require one of align or offset", () => {
|
||||||
expect(() => new HorizontalPosition({})).to.throw();
|
expect(() => createHorizontalPosition({})).to.throw();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,34 +1,33 @@
|
|||||||
// http://officeopenxml.com/drwPicFloating-position.php
|
// http://officeopenxml.com/drwPicFloating-position.php
|
||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { Align } from "./align";
|
import { createAlign } from "./align";
|
||||||
import { HorizontalPositionRelativeFrom, IHorizontalPositionOptions } from "./floating-position";
|
import { HorizontalPositionRelativeFrom, IHorizontalPositionOptions } from "./floating-position";
|
||||||
import { PositionOffset } from "./position-offset";
|
import { createPositionOffset } from "./position-offset";
|
||||||
|
|
||||||
class HorizontalPositionAttributes extends XmlAttributeComponent<{
|
/**
|
||||||
readonly relativeFrom: (typeof HorizontalPositionRelativeFrom)[keyof typeof HorizontalPositionRelativeFrom];
|
* Horizontal Positioning
|
||||||
}> {
|
*
|
||||||
protected readonly xmlKeys = {
|
* Reference: https://www.datypic.com/sc/ooxml/e-wp_positionH-1.html
|
||||||
relativeFrom: "relativeFrom",
|
*/
|
||||||
};
|
export const createHorizontalPosition = ({ relative, align, offset }: IHorizontalPositionOptions): XmlComponent =>
|
||||||
}
|
new BuilderElement<{
|
||||||
|
/** Horizontal Position Relative Base */
|
||||||
export class HorizontalPosition extends XmlComponent {
|
readonly relativeFrom: (typeof HorizontalPositionRelativeFrom)[keyof typeof HorizontalPositionRelativeFrom];
|
||||||
public constructor(horizontalPosition: IHorizontalPositionOptions) {
|
}>({
|
||||||
super("wp:positionH");
|
name: "wp:positionH",
|
||||||
|
attributes: {
|
||||||
this.root.push(
|
relativeFrom: { key: "relativeFrom", value: relative ?? HorizontalPositionRelativeFrom.PAGE },
|
||||||
new HorizontalPositionAttributes({
|
},
|
||||||
relativeFrom: horizontalPosition.relative || HorizontalPositionRelativeFrom.PAGE,
|
children: [
|
||||||
}),
|
(() => {
|
||||||
);
|
if (align) {
|
||||||
|
return createAlign(align);
|
||||||
if (horizontalPosition.align) {
|
} else if (offset !== undefined) {
|
||||||
this.root.push(new Align(horizontalPosition.align));
|
return createPositionOffset(offset);
|
||||||
} else if (horizontalPosition.offset !== undefined) {
|
} else {
|
||||||
this.root.push(new PositionOffset(horizontalPosition.offset));
|
throw new Error("There is no configuration provided for floating position (Align or offset)");
|
||||||
} else {
|
}
|
||||||
throw new Error("There is no configuration provided for floating position (Align or offset)");
|
})(),
|
||||||
}
|
],
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { PositionOffset } from "./position-offset";
|
import { createPositionOffset } from "./position-offset";
|
||||||
|
|
||||||
describe("PositionOffset", () => {
|
describe("createPositionOffset", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a element with correct root key", () => {
|
it("should create a element with correct root key", () => {
|
||||||
const tree = new Formatter().format(new PositionOffset(50));
|
const tree = new Formatter().format(createPositionOffset(50));
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"wp:posOffset": ["50"],
|
"wp:posOffset": ["50"],
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
// http://officeopenxml.com/drwPicFloating-position.php
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
import { XmlComponent } from "@file/xml-components";
|
|
||||||
|
|
||||||
export class PositionOffset extends XmlComponent {
|
/**
|
||||||
public constructor(offsetValue: number) {
|
* # Absolute Position Offset
|
||||||
super("wp:posOffset");
|
*
|
||||||
this.root.push(offsetValue.toString());
|
* This element specifies an absolute measurement for the positioning of a floating DrawingML object within a WordprocessingML document. This measurement shall be calculated relative to the top left edge of the positioning base specified by the parent element's `relativeFrom` attribute.
|
||||||
}
|
*
|
||||||
}
|
* References:
|
||||||
|
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_posOffset_topic_ID0EMG6OB.html
|
||||||
|
* - http://officeopenxml.com/drwPicFloating-position.php
|
||||||
|
*/
|
||||||
|
export const createPositionOffset = (offsetValue: number): XmlComponent =>
|
||||||
|
new BuilderElement({
|
||||||
|
name: "wp:posOffset",
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
children: [offsetValue.toString() as any],
|
||||||
|
});
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { SimplePos } from "./simple-pos";
|
import { createSimplePos } from "./simple-pos";
|
||||||
|
|
||||||
describe("SimplePos", () => {
|
describe("createSimplePos", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a element with correct root key", () => {
|
it("should create a element with correct root key", () => {
|
||||||
const tree = new Formatter().format(new SimplePos());
|
const tree = new Formatter().format(createSimplePos());
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"wp:simplePos": {
|
"wp:simplePos": {
|
||||||
_attr: {
|
_attr: {
|
||||||
|
@ -1,26 +1,62 @@
|
|||||||
// http://officeopenxml.com/drwPicFloating-position.php
|
// http://officeopenxml.com/drwPicFloating-position.php
|
||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
class SimplePosAttributes extends XmlAttributeComponent<{
|
|
||||||
readonly x: number;
|
|
||||||
readonly y: number;
|
|
||||||
}> {
|
|
||||||
protected readonly xmlKeys = {
|
|
||||||
x: "x",
|
|
||||||
y: "y",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SimplePos extends XmlComponent {
|
|
||||||
public constructor() {
|
|
||||||
super("wp:simplePos");
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* # Simple Positioning Coordinates
|
||||||
|
*
|
||||||
|
* This element specifies the coordinates at which a DrawingML object shall be positioned relative to the top-left edge of its page, when the `simplePos` attribute is specified on the <anchor> element (§5.5.2.3).
|
||||||
|
*
|
||||||
|
* References:
|
||||||
|
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_simplePos_topic_ID0E5K6OB.html
|
||||||
|
* - http://officeopenxml.com/drwPicFloating-position.php
|
||||||
|
*
|
||||||
|
* ## XSD Schema
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <xsd:complexType name="CT_Point2D">
|
||||||
|
* <xsd:attribute name="x" type="ST_Coordinate" use="required"/>
|
||||||
|
* <xsd:attribute name="y" type="ST_Coordinate" use="required"/>
|
||||||
|
* </xsd:complexType>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const createSimplePos = (): XmlComponent =>
|
||||||
|
new BuilderElement<{
|
||||||
|
/**
|
||||||
|
* ## X-Axis Coordinate
|
||||||
|
*
|
||||||
|
* Specifies a coordinate on the x-axis. The origin point for this coordinate shall be specified by the parent XML element.
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <wp:... x="0" y="100" />
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The `x` attribute defines an x-coordinate of 0.
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the `ST_Coordinate` simple type (§5.1.12.16).
|
||||||
|
*/
|
||||||
|
readonly x: number;
|
||||||
|
/**
|
||||||
|
* ## Y-Axis Coordinate
|
||||||
|
*
|
||||||
|
* Specifies a coordinate on the x-axis. The origin point for this coordinate shall be specified by the parent XML element.
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
* ```xml
|
||||||
|
* <wp:... x="0" y="100" />
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The `y` attribute defines a y-coordinate of 100.
|
||||||
|
*
|
||||||
|
* The possible values for this attribute are defined by the `ST_Coordinate` simple type (§5.1.12.16).
|
||||||
|
*/
|
||||||
|
readonly y: number;
|
||||||
|
}>({
|
||||||
|
name: "wp:simplePos",
|
||||||
// NOTE: It's not fully supported in Microsoft Word, but this element is needed anyway
|
// NOTE: It's not fully supported in Microsoft Word, but this element is needed anyway
|
||||||
this.root.push(
|
attributes: {
|
||||||
new SimplePosAttributes({
|
x: { key: "x", value: 0 },
|
||||||
x: 0,
|
y: { key: "y", value: 0 },
|
||||||
y: 0,
|
},
|
||||||
}),
|
});
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -4,13 +4,13 @@ import { Formatter } from "@export/formatter";
|
|||||||
import { VerticalPositionAlign } from "@file/shared/alignment";
|
import { VerticalPositionAlign } from "@file/shared/alignment";
|
||||||
|
|
||||||
import { VerticalPositionRelativeFrom } from "./floating-position";
|
import { VerticalPositionRelativeFrom } from "./floating-position";
|
||||||
import { VerticalPosition } from "./vertical-position";
|
import { createVerticalPosition } from "./vertical-position";
|
||||||
|
|
||||||
describe("VerticalPosition", () => {
|
describe("VerticalPosition", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a element with position align", () => {
|
it("should create a element with position align", () => {
|
||||||
const tree = new Formatter().format(
|
const tree = new Formatter().format(
|
||||||
new VerticalPosition({
|
createVerticalPosition({
|
||||||
relative: VerticalPositionRelativeFrom.MARGIN,
|
relative: VerticalPositionRelativeFrom.MARGIN,
|
||||||
align: VerticalPositionAlign.INSIDE,
|
align: VerticalPositionAlign.INSIDE,
|
||||||
}),
|
}),
|
||||||
@ -31,7 +31,7 @@ describe("VerticalPosition", () => {
|
|||||||
|
|
||||||
it("should create a element with offset", () => {
|
it("should create a element with offset", () => {
|
||||||
const tree = new Formatter().format(
|
const tree = new Formatter().format(
|
||||||
new VerticalPosition({
|
createVerticalPosition({
|
||||||
relative: VerticalPositionRelativeFrom.MARGIN,
|
relative: VerticalPositionRelativeFrom.MARGIN,
|
||||||
offset: 40,
|
offset: 40,
|
||||||
}),
|
}),
|
||||||
@ -51,7 +51,7 @@ describe("VerticalPosition", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should require one of align or offset", () => {
|
it("should require one of align or offset", () => {
|
||||||
expect(() => new VerticalPosition({})).to.throw();
|
expect(() => createVerticalPosition({})).to.throw();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,34 +1,35 @@
|
|||||||
// http://officeopenxml.com/drwPicFloating-position.php
|
// http://officeopenxml.com/drwPicFloating-position.php
|
||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { Align } from "./align";
|
import { createAlign } from "./align";
|
||||||
import { IVerticalPositionOptions, VerticalPositionRelativeFrom } from "./floating-position";
|
import { IVerticalPositionOptions, VerticalPositionRelativeFrom } from "./floating-position";
|
||||||
import { PositionOffset } from "./position-offset";
|
import { createPositionOffset } from "./position-offset";
|
||||||
|
|
||||||
class VerticalPositionAttributes extends XmlAttributeComponent<{
|
/**
|
||||||
readonly relativeFrom: (typeof VerticalPositionRelativeFrom)[keyof typeof VerticalPositionRelativeFrom];
|
* Vertical Positioning
|
||||||
}> {
|
*
|
||||||
protected readonly xmlKeys = {
|
* This simple type specifies the possible values for the base from which the relative vertical positioning of an object shall be calculated.
|
||||||
relativeFrom: "relativeFrom",
|
*
|
||||||
};
|
* Reference: https://www.datypic.com/sc/ooxml/e-wp_positionV-1.html
|
||||||
}
|
*/
|
||||||
|
export const createVerticalPosition = ({ relative, align, offset }: IVerticalPositionOptions): XmlComponent =>
|
||||||
export class VerticalPosition extends XmlComponent {
|
new BuilderElement<{
|
||||||
public constructor(verticalPosition: IVerticalPositionOptions) {
|
/** Vertical Position Relative Base */
|
||||||
super("wp:positionV");
|
readonly relativeFrom: (typeof VerticalPositionRelativeFrom)[keyof typeof VerticalPositionRelativeFrom];
|
||||||
|
}>({
|
||||||
this.root.push(
|
name: "wp:positionV",
|
||||||
new VerticalPositionAttributes({
|
attributes: {
|
||||||
relativeFrom: verticalPosition.relative || VerticalPositionRelativeFrom.PAGE,
|
relativeFrom: { key: "relativeFrom", value: relative ?? VerticalPositionRelativeFrom.PAGE },
|
||||||
}),
|
},
|
||||||
);
|
children: [
|
||||||
|
(() => {
|
||||||
if (verticalPosition.align) {
|
if (align) {
|
||||||
this.root.push(new Align(verticalPosition.align));
|
return createAlign(align);
|
||||||
} else if (verticalPosition.offset !== undefined) {
|
} else if (offset !== undefined) {
|
||||||
this.root.push(new PositionOffset(verticalPosition.offset));
|
return createPositionOffset(offset);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("There is no configuration provided for floating position (Align or offset)");
|
throw new Error("There is no configuration provided for floating position (Align or offset)");
|
||||||
}
|
}
|
||||||
}
|
})(),
|
||||||
}
|
],
|
||||||
|
});
|
||||||
|
@ -1,11 +1,28 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { GraphicFrameLocks } from "./graphic-frame-locks/graphic-frame-locks";
|
import { GraphicFrameLocks } from "./graphic-frame-locks/graphic-frame-locks";
|
||||||
|
|
||||||
export class GraphicFrameProperties extends XmlComponent {
|
/**
|
||||||
public constructor() {
|
* # Common DrawingML Non-Visual Properties
|
||||||
super("wp:cNvGraphicFramePr");
|
*
|
||||||
|
* This element specifies common non-visual DrawingML object properties for the parent DrawingML object. These properties are specified as child elements of this element.
|
||||||
this.root.push(new GraphicFrameLocks());
|
*
|
||||||
}
|
* References:
|
||||||
}
|
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_cNvGraphicFramePr_topic_ID0E6U2OB.html
|
||||||
|
*
|
||||||
|
* ## XSD Schema
|
||||||
|
*
|
||||||
|
* ```xml
|
||||||
|
* <xsd:complexType name="CT_NonVisualGraphicFrameProperties">
|
||||||
|
* <xsd:sequence>
|
||||||
|
* <xsd:element name="graphicFrameLocks" type="CT_GraphicalObjectFrameLocking" minOccurs="0" maxOccurs="1"/>
|
||||||
|
* <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
* </xsd:sequence>
|
||||||
|
* </xsd:complexType>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const createGraphicFrameProperties = (): XmlComponent =>
|
||||||
|
new BuilderElement({
|
||||||
|
name: "wp:cNvGraphicFramePr",
|
||||||
|
children: [new GraphicFrameLocks()],
|
||||||
|
});
|
||||||
|
@ -4,8 +4,8 @@ import { BuilderElement, XmlComponent } from "@file/xml-components";
|
|||||||
|
|
||||||
import { DocProperties, DocPropertiesOptions } from "./../doc-properties/doc-properties";
|
import { DocProperties, DocPropertiesOptions } from "./../doc-properties/doc-properties";
|
||||||
import { createEffectExtent } from "./../effect-extent/effect-extent";
|
import { createEffectExtent } from "./../effect-extent/effect-extent";
|
||||||
import { Extent } from "./../extent/extent";
|
import { createExtent } from "./../extent/extent";
|
||||||
import { GraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties";
|
import { createGraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties";
|
||||||
import { Graphic } from "./../inline/graphic";
|
import { Graphic } from "./../inline/graphic";
|
||||||
import { OutlineOptions } from "./graphic/graphic-data/pic/shape-properties/outline/outline";
|
import { OutlineOptions } from "./graphic/graphic-data/pic/shape-properties/outline/outline";
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ export const createInline = ({ mediaData, transform, docProperties, outline }: I
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
new Extent(transform.emus.x, transform.emus.y),
|
createExtent({ x: transform.emus.x, y: transform.emus.y }),
|
||||||
createEffectExtent(
|
createEffectExtent(
|
||||||
outline
|
outline
|
||||||
? {
|
? {
|
||||||
@ -64,7 +64,7 @@ export const createInline = ({ mediaData, transform, docProperties, outline }: I
|
|||||||
: { top: 0, right: 0, bottom: 0, left: 0 },
|
: { top: 0, right: 0, bottom: 0, left: 0 },
|
||||||
),
|
),
|
||||||
new DocProperties(docProperties),
|
new DocProperties(docProperties),
|
||||||
new GraphicFrameProperties(),
|
createGraphicFrameProperties(),
|
||||||
new Graphic({ mediaData, transform, outline }),
|
new Graphic({ mediaData, transform, outline }),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -21,3 +21,4 @@ export * from "./vertical-align";
|
|||||||
export * from "./checkbox";
|
export * from "./checkbox";
|
||||||
export * from "./fonts";
|
export * from "./fonts";
|
||||||
export * from "./textbox";
|
export * from "./textbox";
|
||||||
|
export { type IPropertiesOptions } from "./core-properties";
|
||||||
|
@ -24,7 +24,7 @@ class SpacingAttributes extends XmlAttributeComponent<ISpacingProperties> {
|
|||||||
line: "w:line",
|
line: "w:line",
|
||||||
lineRule: "w:lineRule",
|
lineRule: "w:lineRule",
|
||||||
beforeAutoSpacing: "w:beforeAutospacing",
|
beforeAutoSpacing: "w:beforeAutospacing",
|
||||||
afterAutoSpacing: "w:afterAutoSpacing",
|
afterAutoSpacing: "w:afterAutospacing",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
133
src/file/paragraph/links/numbered-item-ref.spec.ts
Normal file
133
src/file/paragraph/links/numbered-item-ref.spec.ts
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
|
import { NumberedItemReference, NumberedItemReferenceFormat } from "./numbered-item-ref";
|
||||||
|
|
||||||
|
describe("NumberedItemReference", () => {
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("should create a numbered item ref without options", () => {
|
||||||
|
const ref = new NumberedItemReference("some_bookmark");
|
||||||
|
const tree = new Formatter().format(ref);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:fldSimple": {
|
||||||
|
_attr: {
|
||||||
|
"w:instr": "REF some_bookmark \\h \\w",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create a numbered item ref with hyperlink option disabled", () => {
|
||||||
|
const ref = new NumberedItemReference("some_bookmark", "1", { hyperlink: false });
|
||||||
|
const tree = new Formatter().format(ref);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:fldSimple": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:instr": "REF some_bookmark \\w",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:t": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"xml:space": "preserve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"1",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create a numbered item ref with referenceFormat option", () => {
|
||||||
|
const ref = new NumberedItemReference("some_bookmark", "1", { referenceFormat: NumberedItemReferenceFormat.RELATIVE });
|
||||||
|
const tree = new Formatter().format(ref);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:fldSimple": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:instr": "REF some_bookmark \\h \\r",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:t": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"xml:space": "preserve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"1",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be possible to use the none referenceFormat option", () => {
|
||||||
|
const ref = new NumberedItemReference("some_bookmark", "1", { referenceFormat: NumberedItemReferenceFormat.NONE });
|
||||||
|
const tree = new Formatter().format(ref);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:fldSimple": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:instr": "REF some_bookmark \\h",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:t": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"xml:space": "preserve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"1",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be possible to use the NO_CONTEXT referenceFormat option", () => {
|
||||||
|
const ref = new NumberedItemReference("some_bookmark", "1", { referenceFormat: NumberedItemReferenceFormat.NO_CONTEXT });
|
||||||
|
const tree = new Formatter().format(ref);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:fldSimple": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"w:instr": "REF some_bookmark \\h \\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"w:r": [
|
||||||
|
{
|
||||||
|
"w:t": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"xml:space": "preserve",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"1",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
66
src/file/paragraph/links/numbered-item-ref.ts
Normal file
66
src/file/paragraph/links/numbered-item-ref.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { SimpleField } from "../run";
|
||||||
|
|
||||||
|
// https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oi29500/7088a8ce-e784-49d4-94b8-cba6ef8fce78
|
||||||
|
export enum NumberedItemReferenceFormat {
|
||||||
|
NONE = "none",
|
||||||
|
/**
|
||||||
|
* \r option - inserts the paragraph number of the bookmarked paragraph in relative context, or relative to its position in the numbering scheme
|
||||||
|
*/
|
||||||
|
RELATIVE = "relative",
|
||||||
|
/**
|
||||||
|
* \n option - causes the field result to be the paragraph number without trailing periods. No information about prior numbered levels is displayed unless it is included as part of the current level.
|
||||||
|
*/
|
||||||
|
NO_CONTEXT = "no_context",
|
||||||
|
/**
|
||||||
|
* \w option - causes the field result to be the entire paragraph number without trailing periods, regardless of the location of the REF field.
|
||||||
|
*/
|
||||||
|
FULL_CONTEXT = "full_context",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type INumberedItemReferenceOptions = {
|
||||||
|
/**
|
||||||
|
* \h option - Creates a hyperlink to the bookmarked paragraph.
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
readonly hyperlink?: boolean;
|
||||||
|
/**
|
||||||
|
* which switch to use for the reference format
|
||||||
|
* @default NumberedItemReferenceFormat.FULL_CONTEXT
|
||||||
|
*/
|
||||||
|
readonly referenceFormat?: NumberedItemReferenceFormat;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Switch = "\\h" | "\\r" | "\\n" | "\\w";
|
||||||
|
|
||||||
|
const SWITCH_MAP: Record<NumberedItemReferenceFormat, Switch | undefined> = {
|
||||||
|
[NumberedItemReferenceFormat.RELATIVE]: "\\r",
|
||||||
|
[NumberedItemReferenceFormat.NO_CONTEXT]: "\\n",
|
||||||
|
[NumberedItemReferenceFormat.FULL_CONTEXT]: "\\w",
|
||||||
|
[NumberedItemReferenceFormat.NONE]: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a field/cross reference to a numbered item in the document.
|
||||||
|
*/
|
||||||
|
export class NumberedItemReference extends SimpleField {
|
||||||
|
public constructor(
|
||||||
|
bookmarkId: string,
|
||||||
|
// TODO: It would be nice if the cached value could be automatically generated
|
||||||
|
/**
|
||||||
|
* The cached value of the field. This is used to display the field result in the document.
|
||||||
|
*/
|
||||||
|
cachedValue?: string,
|
||||||
|
options: INumberedItemReferenceOptions = {},
|
||||||
|
) {
|
||||||
|
const { hyperlink = true, referenceFormat = NumberedItemReferenceFormat.FULL_CONTEXT } = options;
|
||||||
|
const baseInstruction = `REF ${bookmarkId}`;
|
||||||
|
|
||||||
|
// TODO: Requires TypeScript 5.5 update for it to understand `filter`
|
||||||
|
// @ts-expect-error TS2322
|
||||||
|
const switches: readonly Switch[] = [...(hyperlink ? (["\\h"] as const) : []), ...[SWITCH_MAP[referenceFormat]].filter((a) => !!a)];
|
||||||
|
|
||||||
|
const instruction = `${baseInstruction} ${switches.join(" ")}`;
|
||||||
|
|
||||||
|
super(instruction, cachedValue);
|
||||||
|
}
|
||||||
|
}
|
2
src/file/paragraph/math/bar/index.ts
Normal file
2
src/file/paragraph/math/bar/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./math-bar";
|
||||||
|
export * from "./math-bar-properties";
|
12
src/file/paragraph/math/bar/math-bar-pos.ts
Normal file
12
src/file/paragraph/math/bar/math-bar-pos.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// https://www.datypic.com/sc/ooxml/e-m_pos-1.html
|
||||||
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
|
type MathBarPosOptions = { readonly val: string };
|
||||||
|
|
||||||
|
export const createMathBarPos = ({ val }: MathBarPosOptions): XmlComponent =>
|
||||||
|
new BuilderElement<MathBarPosOptions>({
|
||||||
|
name: "m:pos",
|
||||||
|
attributes: {
|
||||||
|
val: { key: "w:val", value: val },
|
||||||
|
},
|
||||||
|
});
|
44
src/file/paragraph/math/bar/math-bar-properties.spec.ts
Normal file
44
src/file/paragraph/math/bar/math-bar-properties.spec.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
|
import { createMathBarProperties } from "./math-bar-properties";
|
||||||
|
|
||||||
|
describe("MathBarProperties", () => {
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("should create a MathBarProperties with top key", () => {
|
||||||
|
const mathBarProperties = createMathBarProperties({ type: "top" });
|
||||||
|
|
||||||
|
const tree = new Formatter().format(mathBarProperties);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"m:barPr": [
|
||||||
|
{
|
||||||
|
"m:pos": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": "top",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("should create a MathBarProperties with bottom key", () => {
|
||||||
|
const mathBarProperties = createMathBarProperties({ type: "bot" });
|
||||||
|
|
||||||
|
const tree = new Formatter().format(mathBarProperties);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"m:barPr": [
|
||||||
|
{
|
||||||
|
"m:pos": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": "bot",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
10
src/file/paragraph/math/bar/math-bar-properties.ts
Normal file
10
src/file/paragraph/math/bar/math-bar-properties.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// https://www.datypic.com/sc/ooxml/e-m_barPr-1.html
|
||||||
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
|
import { createMathBarPos } from "./math-bar-pos";
|
||||||
|
|
||||||
|
export const createMathBarProperties = ({ type }: { readonly type: string }): XmlComponent =>
|
||||||
|
new BuilderElement({
|
||||||
|
name: "m:barPr",
|
||||||
|
children: [createMathBarPos({ val: type })],
|
||||||
|
});
|
38
src/file/paragraph/math/bar/math-bar.spec.ts
Normal file
38
src/file/paragraph/math/bar/math-bar.spec.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
|
import { MathRun } from "../math-run";
|
||||||
|
import { createMathBar } from "./math-bar";
|
||||||
|
|
||||||
|
describe("MathBar", () => {
|
||||||
|
describe("#constructor()", () => {
|
||||||
|
it("should create a MathBar with correct root key", () => {
|
||||||
|
const mathBar = createMathBar({ type: "top", children: [new MathRun("text")] });
|
||||||
|
const tree = new Formatter().format(mathBar);
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"m:bar": [
|
||||||
|
{
|
||||||
|
"m:barPr": [
|
||||||
|
{
|
||||||
|
"m:pos": {
|
||||||
|
_attr: {
|
||||||
|
"w:val": "top",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"m:e": [
|
||||||
|
{
|
||||||
|
"m:r": [{ "m:t": ["text"] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
17
src/file/paragraph/math/bar/math-bar.ts
Normal file
17
src/file/paragraph/math/bar/math-bar.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// https://www.datypic.com/sc/ooxml/e-m_bar-1.html
|
||||||
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
|
import type { MathComponent } from "../math-component";
|
||||||
|
import { createMathBase } from "../n-ary";
|
||||||
|
import { createMathBarProperties } from "./math-bar-properties";
|
||||||
|
|
||||||
|
type MathBarOptions = {
|
||||||
|
readonly type: "top" | "bot";
|
||||||
|
readonly children: readonly MathComponent[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createMathBar = ({ type, children }: MathBarOptions): XmlComponent =>
|
||||||
|
new BuilderElement({
|
||||||
|
name: "m:bar",
|
||||||
|
children: [createMathBarProperties({ type }), createMathBase({ children })],
|
||||||
|
});
|
@ -2,19 +2,23 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
import { MathBase } from "../n-ary";
|
import { createMathBase } from "../n-ary";
|
||||||
import { MathBracketProperties } from "./math-bracket-properties";
|
import { createMathBracketProperties } from "./math-bracket-properties";
|
||||||
|
|
||||||
|
type MathAngledBracketsOptions = { readonly children: readonly MathComponent[] };
|
||||||
|
|
||||||
export class MathAngledBrackets extends XmlComponent {
|
export class MathAngledBrackets extends XmlComponent {
|
||||||
public constructor(options: { readonly children: readonly MathComponent[] }) {
|
public constructor(options: MathAngledBracketsOptions) {
|
||||||
super("m:d");
|
super("m:d");
|
||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new MathBracketProperties({
|
createMathBracketProperties({
|
||||||
beginningCharacter: "〈",
|
characters: {
|
||||||
endingCharacter: "〉",
|
beginningCharacter: "〈",
|
||||||
|
endingCharacter: "〉",
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathBeginningCharacter } from "./math-beginning-character";
|
import { createMathBeginningCharacter } from "./math-beginning-character";
|
||||||
|
|
||||||
describe("MathBeginningCharacter", () => {
|
describe("createMathBeginningCharacter", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathBeginningCharacter with correct root key", () => {
|
it("should create a MathBeginningCharacter with correct root key", () => {
|
||||||
const mathBeginningCharacter = new MathBeginningCharacter("[");
|
const mathBeginningCharacter = createMathBeginningCharacter({ character: "[" });
|
||||||
|
|
||||||
const tree = new Formatter().format(mathBeginningCharacter);
|
const tree = new Formatter().format(mathBeginningCharacter);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_begChr-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_begChr-1.html
|
||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
class MathBeginningCharacterAttributes extends XmlAttributeComponent<{ readonly character: string }> {
|
type MathBeginningCharacterOptions = { readonly character: string };
|
||||||
protected readonly xmlKeys = { character: "m:val" };
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MathBeginningCharacter extends XmlComponent {
|
export const createMathBeginningCharacter = ({ character }: MathBeginningCharacterOptions): XmlComponent =>
|
||||||
public constructor(character: string) {
|
new BuilderElement<MathBeginningCharacterOptions>({
|
||||||
super("m:begChr");
|
name: "m:begChr",
|
||||||
|
attributes: {
|
||||||
this.root.push(new MathBeginningCharacterAttributes({ character }));
|
character: { key: "m:val", value: character },
|
||||||
}
|
},
|
||||||
}
|
});
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathBracketProperties } from "./math-bracket-properties";
|
import { createMathBracketProperties } from "./math-bracket-properties";
|
||||||
|
|
||||||
describe("MathBracketProperties", () => {
|
describe("createMathBracketProperties", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathBracketProperties with correct root key", () => {
|
it("should create a MathBracketProperties with correct root key", () => {
|
||||||
const mathBracketProperties = new MathBracketProperties();
|
const mathBracketProperties = createMathBracketProperties({});
|
||||||
|
|
||||||
const tree = new Formatter().format(mathBracketProperties);
|
const tree = new Formatter().format(mathBracketProperties);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
@ -16,9 +16,11 @@ describe("MathBracketProperties", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should create a MathBracketProperties with correct root key and add brackets", () => {
|
it("should create a MathBracketProperties with correct root key and add brackets", () => {
|
||||||
const mathBracketProperties = new MathBracketProperties({
|
const mathBracketProperties = createMathBracketProperties({
|
||||||
beginningCharacter: "[",
|
characters: {
|
||||||
endingCharacter: "]",
|
beginningCharacter: "[",
|
||||||
|
endingCharacter: "]",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const tree = new Formatter().format(mathBracketProperties);
|
const tree = new Formatter().format(mathBracketProperties);
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_dPr-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_dPr-1.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathBeginningCharacter } from "./math-beginning-character";
|
import { createMathBeginningCharacter } from "./math-beginning-character";
|
||||||
import { MathEndingCharacter } from "./math-ending-char";
|
import { createMathEndingCharacter } from "./math-ending-char";
|
||||||
|
|
||||||
export class MathBracketProperties extends XmlComponent {
|
type MathBracketPropertiesOptions = { readonly characters?: { readonly beginningCharacter: string; readonly endingCharacter: string } };
|
||||||
public constructor(options?: { readonly beginningCharacter: string; readonly endingCharacter: string }) {
|
|
||||||
super("m:dPr");
|
|
||||||
|
|
||||||
if (!!options) {
|
export const createMathBracketProperties = ({ characters }: MathBracketPropertiesOptions): XmlComponent =>
|
||||||
this.root.push(new MathBeginningCharacter(options.beginningCharacter));
|
new BuilderElement({
|
||||||
this.root.push(new MathEndingCharacter(options.endingCharacter));
|
name: "m:dPr",
|
||||||
}
|
children: !!characters
|
||||||
}
|
? [
|
||||||
}
|
createMathBeginningCharacter({ character: characters.beginningCharacter }),
|
||||||
|
createMathEndingCharacter({ character: characters.endingCharacter }),
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
});
|
||||||
|
@ -2,19 +2,21 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
import { MathBase } from "../n-ary";
|
import { createMathBase } from "../n-ary";
|
||||||
import { MathBracketProperties } from "./math-bracket-properties";
|
import { createMathBracketProperties } from "./math-bracket-properties";
|
||||||
|
|
||||||
export class MathCurlyBrackets extends XmlComponent {
|
export class MathCurlyBrackets extends XmlComponent {
|
||||||
public constructor(options: { readonly children: readonly MathComponent[] }) {
|
public constructor(options: { readonly children: readonly MathComponent[] }) {
|
||||||
super("m:d");
|
super("m:d");
|
||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new MathBracketProperties({
|
createMathBracketProperties({
|
||||||
beginningCharacter: "{",
|
characters: {
|
||||||
endingCharacter: "}",
|
beginningCharacter: "{",
|
||||||
|
endingCharacter: "}",
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_endChr-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_endChr-1.html
|
||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
class MathEndingCharacterAttributes extends XmlAttributeComponent<{ readonly character: string }> {
|
type MathEndingCharacterOptions = { readonly character: string };
|
||||||
protected readonly xmlKeys = { character: "m:val" };
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MathEndingCharacter extends XmlComponent {
|
export const createMathEndingCharacter = ({ character }: MathEndingCharacterOptions): XmlComponent =>
|
||||||
public constructor(character: string) {
|
new BuilderElement<MathEndingCharacterOptions>({
|
||||||
super("m:endChr");
|
name: "m:endChr",
|
||||||
|
attributes: {
|
||||||
this.root.push(new MathEndingCharacterAttributes({ character }));
|
character: { key: "m:val", value: character },
|
||||||
}
|
},
|
||||||
}
|
});
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathEndingCharacter } from "./math-ending-char";
|
import { createMathEndingCharacter } from "./math-ending-char";
|
||||||
|
|
||||||
describe("MathEndingCharacter", () => {
|
describe("createMathEndingCharacter", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathEndingCharacter with correct root key", () => {
|
it("should create a MathEndingCharacter with correct root key", () => {
|
||||||
const mathEndingCharacter = new MathEndingCharacter("]");
|
const mathEndingCharacter = createMathEndingCharacter({ character: "]" });
|
||||||
|
|
||||||
const tree = new Formatter().format(mathEndingCharacter);
|
const tree = new Formatter().format(mathEndingCharacter);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
import { MathBase } from "../n-ary";
|
import { createMathBase } from "../n-ary";
|
||||||
import { MathBracketProperties } from "./math-bracket-properties";
|
import { createMathBracketProperties } from "./math-bracket-properties";
|
||||||
|
|
||||||
export class MathRoundBrackets extends XmlComponent {
|
export class MathRoundBrackets extends XmlComponent {
|
||||||
public constructor(options: { readonly children: readonly MathComponent[] }) {
|
public constructor(options: { readonly children: readonly MathComponent[] }) {
|
||||||
super("m:d");
|
super("m:d");
|
||||||
|
|
||||||
this.root.push(new MathBracketProperties());
|
this.root.push(createMathBracketProperties({}));
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,19 +2,21 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
import { MathBase } from "../n-ary";
|
import { createMathBase } from "../n-ary";
|
||||||
import { MathBracketProperties } from "./math-bracket-properties";
|
import { createMathBracketProperties } from "./math-bracket-properties";
|
||||||
|
|
||||||
export class MathSquareBrackets extends XmlComponent {
|
export class MathSquareBrackets extends XmlComponent {
|
||||||
public constructor(options: { readonly children: readonly MathComponent[] }) {
|
public constructor(options: { readonly children: readonly MathComponent[] }) {
|
||||||
super("m:d");
|
super("m:d");
|
||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new MathBracketProperties({
|
createMathBracketProperties({
|
||||||
beginningCharacter: "[",
|
characters: {
|
||||||
endingCharacter: "]",
|
beginningCharacter: "[",
|
||||||
|
endingCharacter: "]",
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
import { MathBase } from "../n-ary";
|
import { createMathBase } from "../n-ary";
|
||||||
import { MathFunctionName } from "./math-function-name";
|
import { MathFunctionName } from "./math-function-name";
|
||||||
import { MathFunctionProperties } from "./math-function-properties";
|
import { MathFunctionProperties } from "./math-function-properties";
|
||||||
|
|
||||||
@ -17,6 +17,6 @@ export class MathFunction extends XmlComponent {
|
|||||||
|
|
||||||
this.root.push(new MathFunctionProperties());
|
this.root.push(new MathFunctionProperties());
|
||||||
this.root.push(new MathFunctionName(options.name));
|
this.root.push(new MathFunctionName(options.name));
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathAccentCharacter } from "./math-accent-character";
|
import { createMathAccentCharacter } from "./math-accent-character";
|
||||||
|
|
||||||
describe("MathAccentCharacter", () => {
|
describe("MathAccentCharacter", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathAccentCharacter with correct root key", () => {
|
it("should create a MathAccentCharacter with correct root key", () => {
|
||||||
const mathAccentCharacter = new MathAccentCharacter("∑");
|
const mathAccentCharacter = createMathAccentCharacter({ accent: "∑" });
|
||||||
|
|
||||||
const tree = new Formatter().format(mathAccentCharacter);
|
const tree = new Formatter().format(mathAccentCharacter);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_chr-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_chr-1.html
|
||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
class MathAccentCharacterAttributes extends XmlAttributeComponent<{ readonly accent: string }> {
|
type MathAccentCharacterOptions = { readonly accent: string };
|
||||||
protected readonly xmlKeys = { accent: "m:val" };
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MathAccentCharacter extends XmlComponent {
|
export const createMathAccentCharacter = ({ accent }: MathAccentCharacterOptions): XmlComponent =>
|
||||||
public constructor(accent: string) {
|
new BuilderElement<MathAccentCharacterOptions>({
|
||||||
super("m:chr");
|
name: "m:chr",
|
||||||
|
attributes: {
|
||||||
this.root.push(new MathAccentCharacterAttributes({ accent }));
|
accent: { key: "m:val", value: accent },
|
||||||
}
|
},
|
||||||
}
|
});
|
||||||
|
@ -3,12 +3,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathRun } from "../math-run";
|
import { MathRun } from "../math-run";
|
||||||
import { MathBase } from "./math-base";
|
import { createMathBase } from "./math-base";
|
||||||
|
|
||||||
describe("MathBase", () => {
|
describe("createMathBase", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathBase with correct root key", () => {
|
it("should create a MathBase with correct root key", () => {
|
||||||
const mathBase = new MathBase([new MathRun("2+2")]);
|
const mathBase = createMathBase({ children: [new MathRun("2+2")] });
|
||||||
|
|
||||||
const tree = new Formatter().format(mathBase);
|
const tree = new Formatter().format(mathBase);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_e-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_e-1.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
|
|
||||||
export class MathBase extends XmlComponent {
|
type MathBaseOptions = {
|
||||||
public constructor(children: readonly MathComponent[]) {
|
readonly children: readonly MathComponent[];
|
||||||
super("m:e");
|
};
|
||||||
|
|
||||||
for (const child of children) {
|
export const createMathBase = ({ children }: MathBaseOptions): XmlComponent =>
|
||||||
this.root.push(child);
|
new BuilderElement({
|
||||||
}
|
name: "m:e",
|
||||||
}
|
children,
|
||||||
}
|
});
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
import { MathBase } from "./math-base";
|
import { createMathBase } from "./math-base";
|
||||||
import { MathNAryProperties } from "./math-n-ary-properties";
|
import { createMathNAryProperties } from "./math-n-ary-properties";
|
||||||
import { MathSubScriptElement } from "./math-sub-script";
|
import { createMathSubScriptElement } from "./math-sub-script";
|
||||||
import { MathSuperScriptElement } from "./math-super-script";
|
import { createMathSuperScriptElement } from "./math-super-script";
|
||||||
|
|
||||||
export type IMathIntegralOptions = {
|
export type IMathIntegralOptions = {
|
||||||
readonly children: readonly MathComponent[];
|
readonly children: readonly MathComponent[];
|
||||||
@ -16,16 +16,23 @@ export class MathIntegral extends XmlComponent {
|
|||||||
public constructor(options: IMathIntegralOptions) {
|
public constructor(options: IMathIntegralOptions) {
|
||||||
super("m:nary");
|
super("m:nary");
|
||||||
|
|
||||||
this.root.push(new MathNAryProperties("", !!options.superScript, !!options.subScript, "subSup"));
|
this.root.push(
|
||||||
|
createMathNAryProperties({
|
||||||
|
accent: "",
|
||||||
|
hasSuperScript: !!options.superScript,
|
||||||
|
hasSubScript: !!options.subScript,
|
||||||
|
limitLocationVal: "subSup",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
if (!!options.subScript) {
|
if (!!options.subScript) {
|
||||||
this.root.push(new MathSubScriptElement(options.subScript));
|
this.root.push(createMathSubScriptElement({ children: options.subScript }));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!options.superScript) {
|
if (!!options.superScript) {
|
||||||
this.root.push(new MathSuperScriptElement(options.superScript));
|
this.root.push(createMathSuperScriptElement({ children: options.superScript }));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathLimitLocation } from "./math-limit-location";
|
import { createMathLimitLocation } from "./math-limit-location";
|
||||||
|
|
||||||
describe("MathLimitLocation", () => {
|
describe("createMathLimitLocation", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathLimitLocation with correct root key", () => {
|
it("should create a MathLimitLocation with correct root key", () => {
|
||||||
const mathLimitLocation = new MathLimitLocation();
|
const mathLimitLocation = createMathLimitLocation({});
|
||||||
|
|
||||||
const tree = new Formatter().format(mathLimitLocation);
|
const tree = new Formatter().format(mathLimitLocation);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_limLoc-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_limLoc-1.html
|
||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
class MathLimitLocationAttributes extends XmlAttributeComponent<{ readonly value: string }> {
|
type MathLimitLocationOptions = { readonly value?: string };
|
||||||
protected readonly xmlKeys = { value: "m:val" };
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MathLimitLocation extends XmlComponent {
|
export const createMathLimitLocation = ({ value }: MathLimitLocationOptions): XmlComponent =>
|
||||||
public constructor(value?: string) {
|
new BuilderElement<Required<MathLimitLocationOptions>>({
|
||||||
super("m:limLoc");
|
name: "m:limLoc",
|
||||||
|
attributes: {
|
||||||
this.root.push(new MathLimitLocationAttributes({ value: value || "undOvr" }));
|
value: { key: "m:val", value: value || "undOvr" },
|
||||||
}
|
},
|
||||||
}
|
});
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
import { MathBase } from "./math-base";
|
import { createMathBase } from "./math-base";
|
||||||
import { MathLimit } from "./math-limit";
|
import { MathLimit } from "./math-limit";
|
||||||
|
|
||||||
export type IMathLimitLowerOptions = {
|
export type IMathLimitLowerOptions = {
|
||||||
@ -14,7 +14,7 @@ export class MathLimitLower extends XmlComponent {
|
|||||||
public constructor(options: IMathLimitLowerOptions) {
|
public constructor(options: IMathLimitLowerOptions) {
|
||||||
super("m:limLow");
|
super("m:limLow");
|
||||||
|
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
this.root.push(new MathLimit(options.limit));
|
this.root.push(new MathLimit(options.limit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
import { MathBase } from "./math-base";
|
import { createMathBase } from "./math-base";
|
||||||
import { MathLimit } from "./math-limit";
|
import { MathLimit } from "./math-limit";
|
||||||
|
|
||||||
export type IMathLimitUpperOptions = {
|
export type IMathLimitUpperOptions = {
|
||||||
@ -14,7 +14,7 @@ export class MathLimitUpper extends XmlComponent {
|
|||||||
public constructor(options: IMathLimitUpperOptions) {
|
public constructor(options: IMathLimitUpperOptions) {
|
||||||
super("m:limUpp");
|
super("m:limUpp");
|
||||||
|
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
this.root.push(new MathLimit(options.limit));
|
this.root.push(new MathLimit(options.limit));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,16 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathNAryProperties } from "./math-n-ary-properties";
|
import { createMathNAryProperties } from "./math-n-ary-properties";
|
||||||
|
|
||||||
describe("MathNAryProperties", () => {
|
describe("createMathNAryProperties", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathNAryProperties with correct root key", () => {
|
it("should create a MathNAryProperties with correct root key", () => {
|
||||||
const mathNAryProperties = new MathNAryProperties("∑", true, true);
|
const mathNAryProperties = createMathNAryProperties({
|
||||||
|
accent: "∑",
|
||||||
|
hasSuperScript: true,
|
||||||
|
hasSubScript: true,
|
||||||
|
});
|
||||||
|
|
||||||
const tree = new Formatter().format(mathNAryProperties);
|
const tree = new Formatter().format(mathNAryProperties);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
@ -31,7 +35,11 @@ describe("MathNAryProperties", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should add super-script hide attributes", () => {
|
it("should add super-script hide attributes", () => {
|
||||||
const mathNAryProperties = new MathNAryProperties("∑", false, true);
|
const mathNAryProperties = createMathNAryProperties({
|
||||||
|
accent: "∑",
|
||||||
|
hasSuperScript: false,
|
||||||
|
hasSubScript: true,
|
||||||
|
});
|
||||||
|
|
||||||
const tree = new Formatter().format(mathNAryProperties);
|
const tree = new Formatter().format(mathNAryProperties);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
@ -62,7 +70,11 @@ describe("MathNAryProperties", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should add sub-script hide attributes", () => {
|
it("should add sub-script hide attributes", () => {
|
||||||
const mathNAryProperties = new MathNAryProperties("∑", true, false);
|
const mathNAryProperties = createMathNAryProperties({
|
||||||
|
accent: "∑",
|
||||||
|
hasSuperScript: true,
|
||||||
|
hasSubScript: false,
|
||||||
|
});
|
||||||
|
|
||||||
const tree = new Formatter().format(mathNAryProperties);
|
const tree = new Formatter().format(mathNAryProperties);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
@ -93,7 +105,11 @@ describe("MathNAryProperties", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should add both super-script and sub-script hide attributes", () => {
|
it("should add both super-script and sub-script hide attributes", () => {
|
||||||
const mathNAryProperties = new MathNAryProperties("∑", false, false);
|
const mathNAryProperties = createMathNAryProperties({
|
||||||
|
accent: "∑",
|
||||||
|
hasSuperScript: false,
|
||||||
|
hasSubScript: false,
|
||||||
|
});
|
||||||
|
|
||||||
const tree = new Formatter().format(mathNAryProperties);
|
const tree = new Formatter().format(mathNAryProperties);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,26 +1,30 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_naryPr-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_naryPr-1.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathAccentCharacter } from "./math-accent-character";
|
import { createMathAccentCharacter } from "./math-accent-character";
|
||||||
import { MathLimitLocation } from "./math-limit-location";
|
import { createMathLimitLocation } from "./math-limit-location";
|
||||||
import { MathSubScriptHide } from "./math-sub-script-hide";
|
import { createMathSubScriptHide } from "./math-sub-script-hide";
|
||||||
import { MathSuperScriptHide } from "./math-super-script-hide";
|
import { createMathSuperScriptHide } from "./math-super-script-hide";
|
||||||
|
|
||||||
export class MathNAryProperties extends XmlComponent {
|
type MathNAryPropertiesOptions = {
|
||||||
public constructor(accent: string, hasSuperScript: boolean, hasSubScript: boolean, limitLocationVal?: string) {
|
readonly accent: string;
|
||||||
super("m:naryPr");
|
readonly hasSuperScript: boolean;
|
||||||
|
readonly hasSubScript: boolean;
|
||||||
|
readonly limitLocationVal?: string;
|
||||||
|
};
|
||||||
|
|
||||||
if (!!accent) {
|
export const createMathNAryProperties = ({
|
||||||
this.root.push(new MathAccentCharacter(accent));
|
accent,
|
||||||
}
|
hasSuperScript,
|
||||||
this.root.push(new MathLimitLocation(limitLocationVal));
|
hasSubScript,
|
||||||
|
limitLocationVal,
|
||||||
if (!hasSuperScript) {
|
}: MathNAryPropertiesOptions): XmlComponent =>
|
||||||
this.root.push(new MathSuperScriptHide());
|
new BuilderElement({
|
||||||
}
|
name: "m:naryPr",
|
||||||
|
children: [
|
||||||
if (!hasSubScript) {
|
...(!!accent ? [createMathAccentCharacter({ accent })] : []),
|
||||||
this.root.push(new MathSubScriptHide());
|
createMathLimitLocation({ value: limitLocationVal }),
|
||||||
}
|
...(!hasSuperScript ? [createMathSuperScriptHide()] : []),
|
||||||
}
|
...(!hasSubScript ? [createMathSubScriptHide()] : []),
|
||||||
}
|
],
|
||||||
|
});
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathSubScriptHide } from "./math-sub-script-hide";
|
import { createMathSubScriptHide } from "./math-sub-script-hide";
|
||||||
|
|
||||||
describe("MathSubScriptHide", () => {
|
describe("createMathSubScriptHide", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathSubScriptHide with correct root key", () => {
|
it("should create a MathSubScriptHide with correct root key", () => {
|
||||||
const mathSubScriptHide = new MathSubScriptHide();
|
const mathSubScriptHide = createMathSubScriptHide();
|
||||||
|
|
||||||
const tree = new Formatter().format(mathSubScriptHide);
|
const tree = new Formatter().format(mathSubScriptHide);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_subHide-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_subHide-1.html
|
||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
class MathSubScriptHideAttributes extends XmlAttributeComponent<{ readonly hide: number }> {
|
export const createMathSubScriptHide = (): XmlComponent =>
|
||||||
protected readonly xmlKeys = { hide: "m:val" };
|
new BuilderElement<{ readonly hide: number }>({
|
||||||
}
|
name: "m:subHide",
|
||||||
|
attributes: {
|
||||||
export class MathSubScriptHide extends XmlComponent {
|
hide: { key: "m:val", value: 1 },
|
||||||
public constructor() {
|
},
|
||||||
super("m:subHide");
|
});
|
||||||
|
|
||||||
this.root.push(new MathSubScriptHideAttributes({ hide: 1 }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -3,12 +3,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathRun } from "../math-run";
|
import { MathRun } from "../math-run";
|
||||||
import { MathSubScriptElement } from "./math-sub-script";
|
import { createMathSubScriptElement } from "./math-sub-script";
|
||||||
|
|
||||||
describe("MathSubScriptElement", () => {
|
describe("createMathSubScriptElement", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathSubScriptElement with correct root key", () => {
|
it("should create a MathSubScriptElement with correct root key", () => {
|
||||||
const mathSubScriptElement = new MathSubScriptElement([new MathRun("2+2")]);
|
const mathSubScriptElement = createMathSubScriptElement({ children: [new MathRun("2+2")] });
|
||||||
|
|
||||||
const tree = new Formatter().format(mathSubScriptElement);
|
const tree = new Formatter().format(mathSubScriptElement);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_sub-3.html
|
// http://www.datypic.com/sc/ooxml/e-m_sub-3.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
|
|
||||||
export class MathSubScriptElement extends XmlComponent {
|
type MathSubScriptElementOptions = {
|
||||||
public constructor(children: readonly MathComponent[]) {
|
readonly children: readonly MathComponent[];
|
||||||
super("m:sub");
|
};
|
||||||
|
|
||||||
for (const child of children) {
|
export const createMathSubScriptElement = ({ children }: MathSubScriptElementOptions): XmlComponent =>
|
||||||
this.root.push(child);
|
new BuilderElement({
|
||||||
}
|
name: "m:sub",
|
||||||
}
|
children,
|
||||||
}
|
});
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
import { MathBase } from "./math-base";
|
import { createMathBase } from "./math-base";
|
||||||
import { MathNAryProperties } from "./math-n-ary-properties";
|
import { createMathNAryProperties } from "./math-n-ary-properties";
|
||||||
import { MathSubScriptElement } from "./math-sub-script";
|
import { createMathSubScriptElement } from "./math-sub-script";
|
||||||
import { MathSuperScriptElement } from "./math-super-script";
|
import { createMathSuperScriptElement } from "./math-super-script";
|
||||||
|
|
||||||
export type IMathSumOptions = {
|
export type IMathSumOptions = {
|
||||||
readonly children: readonly MathComponent[];
|
readonly children: readonly MathComponent[];
|
||||||
@ -17,16 +17,22 @@ export class MathSum extends XmlComponent {
|
|||||||
public constructor(options: IMathSumOptions) {
|
public constructor(options: IMathSumOptions) {
|
||||||
super("m:nary");
|
super("m:nary");
|
||||||
|
|
||||||
this.root.push(new MathNAryProperties("∑", !!options.superScript, !!options.subScript));
|
this.root.push(
|
||||||
|
createMathNAryProperties({
|
||||||
|
accent: "∑",
|
||||||
|
hasSuperScript: !!options.superScript,
|
||||||
|
hasSubScript: !!options.subScript,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
if (!!options.subScript) {
|
if (!!options.subScript) {
|
||||||
this.root.push(new MathSubScriptElement(options.subScript));
|
this.root.push(createMathSubScriptElement({ children: options.subScript }));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!options.superScript) {
|
if (!!options.superScript) {
|
||||||
this.root.push(new MathSuperScriptElement(options.superScript));
|
this.root.push(createMathSuperScriptElement({ children: options.superScript }));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathSuperScriptHide } from "./math-super-script-hide";
|
import { createMathSuperScriptHide } from "./math-super-script-hide";
|
||||||
|
|
||||||
describe("MathSuperScriptHide", () => {
|
describe("createMathSuperScriptHide", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathSuperScriptHide with correct root key", () => {
|
it("should create a MathSuperScriptHide with correct root key", () => {
|
||||||
const mathSuperScriptHide = new MathSuperScriptHide();
|
const mathSuperScriptHide = createMathSuperScriptHide();
|
||||||
|
|
||||||
const tree = new Formatter().format(mathSuperScriptHide);
|
const tree = new Formatter().format(mathSuperScriptHide);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_subHide-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_subHide-1.html
|
||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
class MathSuperScriptHideAttributes extends XmlAttributeComponent<{ readonly hide: number }> {
|
export const createMathSuperScriptHide = (): XmlComponent =>
|
||||||
protected readonly xmlKeys = { hide: "m:val" };
|
new BuilderElement<{ readonly hide: number }>({
|
||||||
}
|
name: "m:supHide",
|
||||||
|
attributes: {
|
||||||
export class MathSuperScriptHide extends XmlComponent {
|
hide: { key: "m:val", value: 1 },
|
||||||
public constructor() {
|
},
|
||||||
super("m:supHide");
|
});
|
||||||
|
|
||||||
this.root.push(new MathSuperScriptHideAttributes({ hide: 1 }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -3,12 +3,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathRun } from "../math-run";
|
import { MathRun } from "../math-run";
|
||||||
import { MathSuperScriptElement } from "./math-super-script";
|
import { createMathSuperScriptElement } from "./math-super-script";
|
||||||
|
|
||||||
describe("MathSuperScriptElement", () => {
|
describe("createMathSuperScriptElement", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathSuperScriptElement with correct root key", () => {
|
it("should create a MathSuperScriptElement with correct root key", () => {
|
||||||
const mathSuperScriptElement = new MathSuperScriptElement([new MathRun("2+2")]);
|
const mathSuperScriptElement = createMathSuperScriptElement({ children: [new MathRun("2+2")] });
|
||||||
|
|
||||||
const tree = new Formatter().format(mathSuperScriptElement);
|
const tree = new Formatter().format(mathSuperScriptElement);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_sup-3.html
|
// http://www.datypic.com/sc/ooxml/e-m_sup-3.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
|
|
||||||
export class MathSuperScriptElement extends XmlComponent {
|
type MathSuperScriptElementOptions = {
|
||||||
public constructor(children: readonly MathComponent[]) {
|
readonly children: readonly MathComponent[];
|
||||||
super("m:sup");
|
};
|
||||||
|
|
||||||
for (const child of children) {
|
export const createMathSuperScriptElement = ({ children }: MathSuperScriptElementOptions): XmlComponent =>
|
||||||
this.root.push(child);
|
new BuilderElement({
|
||||||
}
|
name: "m:sup",
|
||||||
}
|
children,
|
||||||
}
|
});
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathComponent } from "../math-component";
|
import { MathComponent } from "../math-component";
|
||||||
import { MathBase } from "../n-ary";
|
import { createMathBase } from "../n-ary";
|
||||||
import { MathDegree } from "./math-degree";
|
import { MathDegree } from "./math-degree";
|
||||||
import { MathRadicalProperties } from "./math-radical-properties";
|
import { MathRadicalProperties } from "./math-radical-properties";
|
||||||
|
|
||||||
@ -17,6 +17,6 @@ export class MathRadical extends XmlComponent {
|
|||||||
|
|
||||||
this.root.push(new MathRadicalProperties(!!options.degree));
|
this.root.push(new MathRadicalProperties(!!options.degree));
|
||||||
this.root.push(new MathDegree(options.degree));
|
this.root.push(new MathDegree(options.degree));
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathPreSubSuperScriptProperties } from "./math-pre-sub-super-script-function-properties";
|
import { createMathPreSubSuperScriptProperties } from "./math-pre-sub-super-script-function-properties";
|
||||||
|
|
||||||
describe("MathPreSubSuperScriptProperties", () => {
|
describe("createMathPreSubSuperScriptProperties", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathPreSubSuperScriptProperties with correct root key", () => {
|
it("should create a MathPreSubSuperScriptProperties with correct root key", () => {
|
||||||
const mathPreSubSuperScriptProperties = new MathPreSubSuperScriptProperties();
|
const mathPreSubSuperScriptProperties = createMathPreSubSuperScriptProperties();
|
||||||
|
|
||||||
const tree = new Formatter().format(mathPreSubSuperScriptProperties);
|
const tree = new Formatter().format(mathPreSubSuperScriptProperties);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_sPrePr-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_sPrePr-1.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
export class MathPreSubSuperScriptProperties extends XmlComponent {
|
export const createMathPreSubSuperScriptProperties = (): XmlComponent =>
|
||||||
public constructor() {
|
new BuilderElement({
|
||||||
super("m:sPrePr");
|
name: "m:sPrePr",
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_sPre-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_sPre-1.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathPreSubSuperScriptProperties } from "./math-pre-sub-super-script-function-properties";
|
import { createMathPreSubSuperScriptProperties } from "./math-pre-sub-super-script-function-properties";
|
||||||
import { MathComponent } from "../../math-component";
|
import type { MathComponent } from "../../math-component";
|
||||||
import { MathBase, MathSubScriptElement, MathSuperScriptElement } from "../../n-ary";
|
import { createMathBase, createMathSubScriptElement, createMathSuperScriptElement } from "../../n-ary";
|
||||||
|
|
||||||
export type IMathPreSubSuperScriptOptions = {
|
export type IMathPreSubSuperScriptOptions = {
|
||||||
readonly children: readonly MathComponent[];
|
readonly children: readonly MathComponent[];
|
||||||
@ -11,13 +11,16 @@ export type IMathPreSubSuperScriptOptions = {
|
|||||||
readonly superScript: readonly MathComponent[];
|
readonly superScript: readonly MathComponent[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export class MathPreSubSuperScript extends XmlComponent {
|
export class MathPreSubSuperScript extends BuilderElement {
|
||||||
public constructor(options: IMathPreSubSuperScriptOptions) {
|
public constructor({ children, subScript, superScript }: IMathPreSubSuperScriptOptions) {
|
||||||
super("m:sPre");
|
super({
|
||||||
|
name: "m:sPre",
|
||||||
this.root.push(new MathPreSubSuperScriptProperties());
|
children: [
|
||||||
this.root.push(new MathBase(options.children));
|
createMathPreSubSuperScriptProperties(),
|
||||||
this.root.push(new MathSubScriptElement(options.subScript));
|
createMathBase({ children: children }),
|
||||||
this.root.push(new MathSuperScriptElement(options.superScript));
|
createMathSubScriptElement({ children: subScript }),
|
||||||
|
createMathSuperScriptElement({ children: superScript }),
|
||||||
|
],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathSubScriptProperties } from "./math-sub-script-function-properties";
|
import { createMathSubScriptProperties } from "./math-sub-script-function-properties";
|
||||||
|
|
||||||
describe("MathSubScriptProperties", () => {
|
describe("createMathSubScriptProperties", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathSubScriptProperties with correct root key", () => {
|
it("should create a MathSubScriptProperties with correct root key", () => {
|
||||||
const mathSubScriptProperties = new MathSubScriptProperties();
|
const mathSubScriptProperties = createMathSubScriptProperties();
|
||||||
|
|
||||||
const tree = new Formatter().format(mathSubScriptProperties);
|
const tree = new Formatter().format(mathSubScriptProperties);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_sSubPr-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_sSubPr-1.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
export class MathSubScriptProperties extends XmlComponent {
|
export const createMathSubScriptProperties = (): XmlComponent =>
|
||||||
public constructor() {
|
new BuilderElement({
|
||||||
super("m:sSubPr");
|
name: "m:sSubPr",
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_sSub-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_sSub-1.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathSubScriptProperties } from "./math-sub-script-function-properties";
|
import { createMathSubScriptProperties } from "./math-sub-script-function-properties";
|
||||||
import { MathComponent } from "../../math-component";
|
import { MathComponent } from "../../math-component";
|
||||||
import { MathBase, MathSubScriptElement } from "../../n-ary";
|
import { createMathBase, createMathSubScriptElement } from "../../n-ary";
|
||||||
|
|
||||||
export type IMathSubScriptOptions = {
|
export type IMathSubScriptOptions = {
|
||||||
readonly children: readonly MathComponent[];
|
readonly children: readonly MathComponent[];
|
||||||
@ -14,8 +14,8 @@ export class MathSubScript extends XmlComponent {
|
|||||||
public constructor(options: IMathSubScriptOptions) {
|
public constructor(options: IMathSubScriptOptions) {
|
||||||
super("m:sSub");
|
super("m:sSub");
|
||||||
|
|
||||||
this.root.push(new MathSubScriptProperties());
|
this.root.push(createMathSubScriptProperties());
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
this.root.push(new MathSubScriptElement(options.subScript));
|
this.root.push(createMathSubScriptElement({ children: options.subScript }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathSubSuperScriptProperties } from "./math-sub-super-script-function-properties";
|
import { createMathSubSuperScriptProperties } from "./math-sub-super-script-function-properties";
|
||||||
|
|
||||||
describe("MathSubSuperScriptProperties", () => {
|
describe("createMathSuperScriptProperties", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathSubSuperScriptProperties with correct root key", () => {
|
it("should create a MathSubSuperScriptProperties with correct root key", () => {
|
||||||
const mathSubSuperScriptProperties = new MathSubSuperScriptProperties();
|
const mathSubSuperScriptProperties = createMathSubSuperScriptProperties();
|
||||||
|
|
||||||
const tree = new Formatter().format(mathSubSuperScriptProperties);
|
const tree = new Formatter().format(mathSubSuperScriptProperties);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_sSubSupPr-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_sSubSupPr-1.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
export class MathSubSuperScriptProperties extends XmlComponent {
|
export const createMathSubSuperScriptProperties = (): XmlComponent =>
|
||||||
public constructor() {
|
new BuilderElement({
|
||||||
super("m:sSubSupPr");
|
name: "m:sSubSupPr",
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_sSubSup-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_sSubSup-1.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathSubSuperScriptProperties } from "./math-sub-super-script-function-properties";
|
import { createMathSubSuperScriptProperties } from "./math-sub-super-script-function-properties";
|
||||||
import { MathComponent } from "../../math-component";
|
import { MathComponent } from "../../math-component";
|
||||||
import { MathBase, MathSubScriptElement, MathSuperScriptElement } from "../../n-ary";
|
import { createMathBase, createMathSubScriptElement, createMathSuperScriptElement } from "../../n-ary";
|
||||||
|
|
||||||
export type IMathSubSuperScriptOptions = {
|
export type IMathSubSuperScriptOptions = {
|
||||||
readonly children: readonly MathComponent[];
|
readonly children: readonly MathComponent[];
|
||||||
@ -15,9 +15,9 @@ export class MathSubSuperScript extends XmlComponent {
|
|||||||
public constructor(options: IMathSubSuperScriptOptions) {
|
public constructor(options: IMathSubSuperScriptOptions) {
|
||||||
super("m:sSubSup");
|
super("m:sSubSup");
|
||||||
|
|
||||||
this.root.push(new MathSubSuperScriptProperties());
|
this.root.push(createMathSubSuperScriptProperties());
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
this.root.push(new MathSubScriptElement(options.subScript));
|
this.root.push(createMathSubScriptElement({ children: options.subScript }));
|
||||||
this.root.push(new MathSuperScriptElement(options.superScript));
|
this.root.push(createMathSuperScriptElement({ children: options.superScript }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
|
|||||||
|
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
import { MathSuperScriptProperties } from "./math-super-script-function-properties";
|
import { createMathSuperScriptProperties } from "./math-super-script-function-properties";
|
||||||
|
|
||||||
describe("MathSuperScriptProperties", () => {
|
describe("createMathSuperScriptProperties", () => {
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a MathSuperScriptProperties with correct root key", () => {
|
it("should create a MathSuperScriptProperties with correct root key", () => {
|
||||||
const mathSuperScriptProperties = new MathSuperScriptProperties();
|
const mathSuperScriptProperties = createMathSuperScriptProperties();
|
||||||
|
|
||||||
const tree = new Formatter().format(mathSuperScriptProperties);
|
const tree = new Formatter().format(mathSuperScriptProperties);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_sSupPr-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_sSupPr-1.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
export class MathSuperScriptProperties extends XmlComponent {
|
export const createMathSuperScriptProperties = (): XmlComponent =>
|
||||||
public constructor() {
|
new BuilderElement({
|
||||||
super("m:sSupPr");
|
name: "m:sSupPr",
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// http://www.datypic.com/sc/ooxml/e-m_sSup-1.html
|
// http://www.datypic.com/sc/ooxml/e-m_sSup-1.html
|
||||||
import { XmlComponent } from "@file/xml-components";
|
import { XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
import { MathSuperScriptProperties } from "./math-super-script-function-properties";
|
import { createMathSuperScriptProperties } from "./math-super-script-function-properties";
|
||||||
import { MathComponent } from "../../math-component";
|
import { MathComponent } from "../../math-component";
|
||||||
import { MathBase, MathSuperScriptElement } from "../../n-ary";
|
import { createMathBase, createMathSuperScriptElement } from "../../n-ary";
|
||||||
|
|
||||||
export type IMathSuperScriptOptions = {
|
export type IMathSuperScriptOptions = {
|
||||||
readonly children: readonly MathComponent[];
|
readonly children: readonly MathComponent[];
|
||||||
@ -14,8 +14,8 @@ export class MathSuperScript extends XmlComponent {
|
|||||||
public constructor(options: IMathSuperScriptOptions) {
|
public constructor(options: IMathSuperScriptOptions) {
|
||||||
super("m:sSup");
|
super("m:sSup");
|
||||||
|
|
||||||
this.root.push(new MathSuperScriptProperties());
|
this.root.push(createMathSuperScriptProperties());
|
||||||
this.root.push(new MathBase(options.children));
|
this.root.push(createMathBase({ children: options.children }));
|
||||||
this.root.push(new MathSuperScriptElement(options.superScript));
|
this.root.push(createMathSuperScriptElement({ children: options.superScript }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { FileChild } from "@file/file-child";
|
import { FileChild } from "@file/file-child";
|
||||||
|
import { Relationships } from "@file/relationships";
|
||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
export type ICommentOptions = {
|
export type ICommentOptions = {
|
||||||
@ -136,6 +137,8 @@ export class Comment extends XmlComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class Comments extends XmlComponent {
|
export class Comments extends XmlComponent {
|
||||||
|
private readonly relationships: Relationships;
|
||||||
|
|
||||||
public constructor({ children }: ICommentsOptions) {
|
public constructor({ children }: ICommentsOptions) {
|
||||||
super("w:comments");
|
super("w:comments");
|
||||||
|
|
||||||
@ -178,5 +181,11 @@ export class Comments extends XmlComponent {
|
|||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
this.root.push(new Comment(child));
|
this.root.push(new Comment(child));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.relationships = new Relationships();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get Relationships(): Relationships {
|
||||||
|
return this.relationships;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
src/file/table/table-cell-spacing.ts
Normal file
39
src/file/table/table-cell-spacing.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// http://officeopenxml.com/WPtableCellSpacing.php
|
||||||
|
import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
|
||||||
|
import { Percentage, UniversalMeasure, measurementOrPercentValue } from "@util/values";
|
||||||
|
|
||||||
|
// <xsd:simpleType name="ST_TblCellSpacing">
|
||||||
|
// <xsd:restriction base="xsd:string">
|
||||||
|
// <xsd:enumeration value="nil"/>
|
||||||
|
// <xsd:enumeration value="dxa"/>
|
||||||
|
// </xsd:restriction>
|
||||||
|
// </xsd:simpleType>
|
||||||
|
|
||||||
|
export const CellSpacingType = {
|
||||||
|
/** Value is in twentieths of a point */
|
||||||
|
DXA: "dxa",
|
||||||
|
/** No (empty) value. */
|
||||||
|
NIL: "nil",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
// <xsd:complexType name="CT_TblCellSpacing">
|
||||||
|
// <xsd:attribute name="w" type="ST_MeasurementOrPercent"/>
|
||||||
|
// <xsd:attribute name="type" type="ST_TblCellSpacing"/>
|
||||||
|
// </xsd:complexType>
|
||||||
|
export type ITableCellSpacingProperties = {
|
||||||
|
readonly value: number | Percentage | UniversalMeasure;
|
||||||
|
readonly type?: (typeof CellSpacingType)[keyof typeof CellSpacingType];
|
||||||
|
};
|
||||||
|
|
||||||
|
export class TableCellSpacingElement extends XmlComponent {
|
||||||
|
public constructor({ type = CellSpacingType.DXA, value }: ITableCellSpacingProperties) {
|
||||||
|
super("w:tblCellSpacing");
|
||||||
|
|
||||||
|
this.root.push(
|
||||||
|
new NextAttributeComponent<ITableCellSpacingProperties>({
|
||||||
|
type: { key: "w:type", value: type },
|
||||||
|
value: { key: "w:w", value: measurementOrPercentValue(value) },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ import { ShadingType } from "@file/shading";
|
|||||||
import { WidthType } from "../table-width";
|
import { WidthType } from "../table-width";
|
||||||
import { TableLayoutType } from "./table-layout";
|
import { TableLayoutType } from "./table-layout";
|
||||||
import { TableProperties } from "./table-properties";
|
import { TableProperties } from "./table-properties";
|
||||||
|
import { CellSpacingType } from "../table-cell-spacing";
|
||||||
|
|
||||||
describe("TableProperties", () => {
|
describe("TableProperties", () => {
|
||||||
describe("#constructor", () => {
|
describe("#constructor", () => {
|
||||||
@ -91,6 +92,19 @@ describe("TableProperties", () => {
|
|||||||
"w:tblPr": [{ "w:tblLayout": { _attr: { "w:type": "fixed" } } }],
|
"w:tblPr": [{ "w:tblLayout": { _attr: { "w:type": "fixed" } } }],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should add a table cell spacing property", () => {
|
||||||
|
const tp = new TableProperties({
|
||||||
|
cellSpacing: {
|
||||||
|
value: 1234,
|
||||||
|
type: CellSpacingType.DXA,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(tp);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:tblPr": [{ "w:tblCellSpacing": { _attr: { "w:type": "dxa", "w:w": 1234 } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#cellMargin", () => {
|
describe("#cellMargin", () => {
|
||||||
|
@ -30,6 +30,7 @@ import { ITableBordersOptions, TableBorders } from "./table-borders";
|
|||||||
import { ITableCellMarginOptions, TableCellMargin, TableCellMarginElementType } from "./table-cell-margin";
|
import { ITableCellMarginOptions, TableCellMargin, TableCellMarginElementType } from "./table-cell-margin";
|
||||||
import { ITableFloatOptions, TableFloatProperties } from "./table-float-properties";
|
import { ITableFloatOptions, TableFloatProperties } from "./table-float-properties";
|
||||||
import { TableLayout, TableLayoutType } from "./table-layout";
|
import { TableLayout, TableLayoutType } from "./table-layout";
|
||||||
|
import { ITableCellSpacingProperties, TableCellSpacingElement } from "../table-cell-spacing";
|
||||||
|
|
||||||
export type ITablePropertiesOptions = {
|
export type ITablePropertiesOptions = {
|
||||||
readonly width?: ITableWidthProperties;
|
readonly width?: ITableWidthProperties;
|
||||||
@ -42,6 +43,7 @@ export type ITablePropertiesOptions = {
|
|||||||
readonly alignment?: (typeof AlignmentType)[keyof typeof AlignmentType];
|
readonly alignment?: (typeof AlignmentType)[keyof typeof AlignmentType];
|
||||||
readonly cellMargin?: ITableCellMarginOptions;
|
readonly cellMargin?: ITableCellMarginOptions;
|
||||||
readonly visuallyRightToLeft?: boolean;
|
readonly visuallyRightToLeft?: boolean;
|
||||||
|
readonly cellSpacing?: ITableCellSpacingProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class TableProperties extends IgnoreIfEmptyXmlComponent {
|
export class TableProperties extends IgnoreIfEmptyXmlComponent {
|
||||||
@ -87,5 +89,9 @@ export class TableProperties extends IgnoreIfEmptyXmlComponent {
|
|||||||
if (options.cellMargin) {
|
if (options.cellMargin) {
|
||||||
this.root.push(new TableCellMargin(TableCellMarginElementType.TABLE, options.cellMargin));
|
this.root.push(new TableCellMargin(TableCellMarginElementType.TABLE, options.cellMargin));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.cellSpacing) {
|
||||||
|
this.root.push(new TableCellSpacingElement(options.cellSpacing));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import { Formatter } from "@export/formatter";
|
|||||||
import { HeightRule } from "@file/table/table-row/table-row-height";
|
import { HeightRule } from "@file/table/table-row/table-row-height";
|
||||||
|
|
||||||
import { TableRowProperties } from "./table-row-properties";
|
import { TableRowProperties } from "./table-row-properties";
|
||||||
|
import { CellSpacingType } from "../table-cell-spacing";
|
||||||
|
|
||||||
describe("TableRowProperties", () => {
|
describe("TableRowProperties", () => {
|
||||||
describe("#constructor", () => {
|
describe("#constructor", () => {
|
||||||
@ -60,5 +61,18 @@ describe("TableRowProperties", () => {
|
|||||||
const tree = new Formatter().format(rowProperties);
|
const tree = new Formatter().format(rowProperties);
|
||||||
expect(tree).to.deep.equal({ "w:trPr": [{ "w:trHeight": { _attr: { "w:val": 100, "w:hRule": "atLeast" } } }] });
|
expect(tree).to.deep.equal({ "w:trPr": [{ "w:trHeight": { _attr: { "w:val": 100, "w:hRule": "atLeast" } } }] });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should add a table cell spacing property", () => {
|
||||||
|
const rowProperties = new TableRowProperties({
|
||||||
|
cellSpacing: {
|
||||||
|
value: 1234,
|
||||||
|
type: CellSpacingType.DXA,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(rowProperties);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:trPr": [{ "w:tblCellSpacing": { _attr: { "w:type": "dxa", "w:w": 1234 } } }],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -31,6 +31,7 @@ import { IgnoreIfEmptyXmlComponent, OnOffElement } from "@file/xml-components";
|
|||||||
import { PositiveUniversalMeasure } from "@util/values";
|
import { PositiveUniversalMeasure } from "@util/values";
|
||||||
|
|
||||||
import { HeightRule, TableRowHeight } from "./table-row-height";
|
import { HeightRule, TableRowHeight } from "./table-row-height";
|
||||||
|
import { ITableCellSpacingProperties, TableCellSpacingElement } from "../table-cell-spacing";
|
||||||
|
|
||||||
export type ITableRowPropertiesOptions = {
|
export type ITableRowPropertiesOptions = {
|
||||||
readonly cantSplit?: boolean;
|
readonly cantSplit?: boolean;
|
||||||
@ -39,6 +40,7 @@ export type ITableRowPropertiesOptions = {
|
|||||||
readonly value: number | PositiveUniversalMeasure;
|
readonly value: number | PositiveUniversalMeasure;
|
||||||
readonly rule: (typeof HeightRule)[keyof typeof HeightRule];
|
readonly rule: (typeof HeightRule)[keyof typeof HeightRule];
|
||||||
};
|
};
|
||||||
|
readonly cellSpacing?: ITableCellSpacingProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class TableRowProperties extends IgnoreIfEmptyXmlComponent {
|
export class TableRowProperties extends IgnoreIfEmptyXmlComponent {
|
||||||
@ -56,5 +58,9 @@ export class TableRowProperties extends IgnoreIfEmptyXmlComponent {
|
|||||||
if (options.height) {
|
if (options.height) {
|
||||||
this.root.push(new TableRowHeight(options.height.value, options.height.rule));
|
this.root.push(new TableRowHeight(options.height.value, options.height.rule));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.cellSpacing) {
|
||||||
|
this.root.push(new TableCellSpacingElement(options.cellSpacing));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import { FileChild } from "@file/file-child";
|
|||||||
import { AlignmentType } from "../paragraph";
|
import { AlignmentType } from "../paragraph";
|
||||||
import { TableGrid } from "./grid";
|
import { TableGrid } from "./grid";
|
||||||
import { TableCell, VerticalMergeType } from "./table-cell";
|
import { TableCell, VerticalMergeType } from "./table-cell";
|
||||||
|
import { ITableCellSpacingProperties } from "./table-cell-spacing";
|
||||||
import { ITableBordersOptions, ITableFloatOptions, TableProperties } from "./table-properties";
|
import { ITableBordersOptions, ITableFloatOptions, TableProperties } from "./table-properties";
|
||||||
import { ITableCellMarginOptions } from "./table-properties/table-cell-margin";
|
import { ITableCellMarginOptions } from "./table-properties/table-cell-margin";
|
||||||
import { TableLayoutType } from "./table-properties/table-layout";
|
import { TableLayoutType } from "./table-properties/table-layout";
|
||||||
@ -32,6 +33,7 @@ export type ITableOptions = {
|
|||||||
readonly borders?: ITableBordersOptions;
|
readonly borders?: ITableBordersOptions;
|
||||||
readonly alignment?: (typeof AlignmentType)[keyof typeof AlignmentType];
|
readonly alignment?: (typeof AlignmentType)[keyof typeof AlignmentType];
|
||||||
readonly visuallyRightToLeft?: boolean;
|
readonly visuallyRightToLeft?: boolean;
|
||||||
|
readonly cellSpacing?: ITableCellSpacingProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Table extends FileChild {
|
export class Table extends FileChild {
|
||||||
@ -48,6 +50,7 @@ export class Table extends FileChild {
|
|||||||
borders,
|
borders,
|
||||||
alignment,
|
alignment,
|
||||||
visuallyRightToLeft,
|
visuallyRightToLeft,
|
||||||
|
cellSpacing,
|
||||||
}: ITableOptions) {
|
}: ITableOptions) {
|
||||||
super("w:tbl");
|
super("w:tbl");
|
||||||
|
|
||||||
@ -62,6 +65,7 @@ export class Table extends FileChild {
|
|||||||
alignment,
|
alignment,
|
||||||
cellMargin: margins,
|
cellMargin: margins,
|
||||||
visuallyRightToLeft,
|
visuallyRightToLeft,
|
||||||
|
cellSpacing,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -90,22 +90,19 @@ const formatShapeStyle = (style?: VmlShapeStyle): string | undefined =>
|
|||||||
.join(";")
|
.join(";")
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
export const createShape = ({
|
type ShapeOptions = {
|
||||||
id,
|
|
||||||
children,
|
|
||||||
type = SHAPE_TYPE,
|
|
||||||
style,
|
|
||||||
}: {
|
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly children?: readonly ParagraphChild[];
|
readonly children?: readonly ParagraphChild[];
|
||||||
readonly type?: string;
|
readonly type?: string;
|
||||||
readonly style?: VmlShapeStyle;
|
readonly style?: VmlShapeStyle;
|
||||||
}): XmlComponent =>
|
};
|
||||||
new BuilderElement<{
|
|
||||||
readonly id: string;
|
export const createShape = ({ id, children, type = SHAPE_TYPE, style }: ShapeOptions): XmlComponent =>
|
||||||
readonly type?: string;
|
new BuilderElement<
|
||||||
readonly style?: string;
|
Pick<ShapeOptions, "id" | "type"> & {
|
||||||
}>({
|
readonly style?: string;
|
||||||
|
}
|
||||||
|
>({
|
||||||
name: "v:shape",
|
name: "v:shape",
|
||||||
attributes: {
|
attributes: {
|
||||||
id: {
|
id: {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user