Compare commits
182 Commits
Author | SHA1 | Date | |
---|---|---|---|
70c4e89a65 | |||
8f632d4ecd | |||
6784dc1f3d | |||
fd63a30298 | |||
b0a29e26c9 | |||
8826fb010d | |||
97101adb10 | |||
2ec171d4a8 | |||
8876bb1fea | |||
96ca9d9c23 | |||
74a65f02fa | |||
339c017940 | |||
969b52ae05 | |||
eb8f0f4033 | |||
d7229eb049 | |||
644819ed81 | |||
96fd61d3e4 | |||
b96cfe7b19 | |||
d0e7c97a88 | |||
0ede54cfdc | |||
5be1163549 | |||
580f6eb633 | |||
321be35918 | |||
45a18742d7 | |||
7e81da404a | |||
6c2abb4abc | |||
e8b0dbf93b | |||
e59c255d85 | |||
17b28cb724 | |||
410152441b | |||
dfff4b96bd | |||
72cb75a486 | |||
53fe1dd988 | |||
043219f005 | |||
0453f28951 | |||
94716e081b | |||
30f826fd3d | |||
99b7a03b8a | |||
b1c8b2beb8 | |||
a706455a7c | |||
8c388a95c4 | |||
9a41d78ecb | |||
6fc4ad782a | |||
16b9057ac6 | |||
28c62c1ee4 | |||
91a757619e | |||
f89049e4c1 | |||
086f5f5d03 | |||
a2694f1d7d | |||
fd350d53db | |||
af48af2854 | |||
15009884e3 | |||
ad462dfe10 | |||
68fe380575 | |||
5b2a311ad4 | |||
5db2503e7b | |||
55a1d23f29 | |||
0bfd753a0d | |||
22adabd2d9 | |||
6d5c89ff47 | |||
96a9bb1a1e | |||
2be00d3f1e | |||
30b21217a9 | |||
260a680f56 | |||
486777b108 | |||
3730e2b60e | |||
e7e6d02cc5 | |||
c7b7b585be | |||
0c128ae4a5 | |||
d7a70ffe03 | |||
e1c699ec41 | |||
245f0ae2ea | |||
762fc0ca9d | |||
457d074a59 | |||
ba80440faf | |||
ae41e22df5 | |||
bf2e5201c8 | |||
2662bcc60b | |||
efa4f1933a | |||
8c58ec2ba4 | |||
e6ed3a55ff | |||
69abf509c9 | |||
66eace4a33 | |||
eeb2187db4 | |||
fa44acca1b | |||
34ce662f70 | |||
8d72fa5542 | |||
64d642b593 | |||
d9e533156f | |||
90e5cc3ad5 | |||
9f61ca7abe | |||
6af79a884c | |||
353401d148 | |||
f17360d45a | |||
4bc6ed0eda | |||
bf22866a8d | |||
a6e40d9d92 | |||
0b78e33444 | |||
6689f76c28 | |||
df8ba1e8b8 | |||
b3524971ac | |||
1cd681bc2d | |||
7f4d1bf3e7 | |||
8c6cd012e7 | |||
371398bc2c | |||
9a90818729 | |||
90049a31ee | |||
3dbd917667 | |||
d85c6ce56a | |||
db24f67e34 | |||
fb6a4383ff | |||
c33cdb450c | |||
62b6b33254 | |||
64ab91765a | |||
c0ba937c3a | |||
70f4613e1b | |||
bd9d6b74f5 | |||
bd3eb3e214 | |||
c10b576a3a | |||
210b97d00b | |||
62a238de84 | |||
7b6f5bbaef | |||
a45048a464 | |||
c0b0649f37 | |||
e7e5c61a90 | |||
f1fb0c4f22 | |||
0de30f6c59 | |||
599be5bf2b | |||
9d7573ed9c | |||
738cac0253 | |||
35ddda444a | |||
8d11ec3422 | |||
ea647d84df | |||
8c91c04afa | |||
a89718ea83 | |||
62911d6e44 | |||
766069c7cc | |||
09f1d473c3 | |||
74ea0f699f | |||
b00e4fa5b5 | |||
7ffa59d7fa | |||
d662391a64 | |||
7a9661c55a | |||
f80a5654b4 | |||
001b756866 | |||
fd1aab48f7 | |||
7ff838357a | |||
958b5ea307 | |||
3a6cf81c60 | |||
10684b34aa | |||
2fc9156e93 | |||
c521d0ce63 | |||
50ca71087e | |||
72eff21027 | |||
11bbb5e285 | |||
18bba1870e | |||
c6eef3fd79 | |||
06353a6977 | |||
2b28dd42ee | |||
7022b39d2e | |||
5fac776dca | |||
0e8d92f8bb | |||
30fef5238e | |||
0fe6ff95a2 | |||
11e918114d | |||
879b9163a3 | |||
4a2b8a1e04 | |||
d6f5fe0ae8 | |||
dd4ff944d7 | |||
aac81ffa12 | |||
d93432678b | |||
ac7799a875 | |||
766bcabcb8 | |||
f06094c91d | |||
3b18b8267a | |||
20ec9b679e | |||
449d1bc2c3 | |||
b4dca79d72 | |||
e6e0658812 | |||
18ca93e50a | |||
f5144e6d72 | |||
2684f16579 |
@ -38,3 +38,6 @@ build-tests
|
||||
|
||||
# vscode
|
||||
.vscode
|
||||
|
||||
# docs
|
||||
docs
|
@ -1,10 +1,15 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "6"
|
||||
- "node"
|
||||
- "stable"
|
||||
install:
|
||||
- npm install
|
||||
script:
|
||||
- npm test
|
||||
after_failure:
|
||||
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
|
||||
after_success:
|
||||
- bash ./deploy-docs.sh
|
||||
env:
|
||||
global:
|
||||
- ENCRYPTION_LABEL: "ad385fa3b525"
|
||||
|
||||
|
391
README.md
391
README.md
@ -3,56 +3,38 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Generate .docx files with JS/TS very easily
|
||||
Generate .docx files with JS/TS very easily, written in TS.
|
||||
</p>
|
||||
---
|
||||
|
||||
[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] [![Known Vulnerabilities][snky-image]][snky-url]
|
||||
-----
|
||||
|
||||
# docx
|
||||
> A tool to create Word Documents (.docx) with JS or TS, written in TS.
|
||||
[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][gemnasium-image]][gemnasium-url] [![Known Vulnerabilities][snky-image]][snky-url] [![Chat on Gitter][gitter-image]][gitter-url]
|
||||
|
||||
[](https://nodei.co/npm/docx/)
|
||||
|
||||
# Table of Contents
|
||||
- [Install](#)
|
||||
- [Usage](#)
|
||||
- [Create simple Word Document](#)
|
||||
- [Create Paragraph](#)
|
||||
- [Styles](#)
|
||||
- [Heading1 - Heading5](#)
|
||||
- [Title](#)
|
||||
- [Text Alignment](#)
|
||||
- [Example](#)
|
||||
- [Thematic Break (Page Break)](#)
|
||||
- [Text](#)
|
||||
- [Typographical Emphasis](#)
|
||||
- [Bold](#)
|
||||
- [Italics](#)
|
||||
- [Underline](#)
|
||||
- [Break](#)
|
||||
- [Chaining](#)
|
||||
- [Bullet Points](#)
|
||||
- [Tab Stops](#)
|
||||
- [Left Tab Stop](#)
|
||||
- [Center Tab Stop](#)
|
||||
- [Right Tab Stop](#)
|
||||
- [Max Right Tab Stop](#)
|
||||
- [Example](#)
|
||||
- [Exporting](#)
|
||||
- [Express](#)
|
||||
- [Standalone .docx file](#)
|
||||
- [Examples](#)
|
||||
- [License](#)
|
||||
# docx
|
||||
|
||||
# Install
|
||||
## Install
|
||||
|
||||
```sh
|
||||
$ npm install --save docx
|
||||
```
|
||||
|
||||
## Demo
|
||||
|
||||
# Usage
|
||||
```sh
|
||||
$ npm run demo
|
||||
```
|
||||
|
||||
will run the demo selector app in the `demo` folder. It will prompt you to select a demo number, which will run a demo from that folder.
|
||||
|
||||
## Guide
|
||||
|
||||
Please refer to [the Wiki](https://github.com/dolanmiu/docx/wiki) for details on how to use this library, examples and much more!
|
||||
|
||||
Full documentation can be found here: [http://dolanmiu.github.io/docx](http://dolanmiu.github.io/docx)
|
||||
|
||||
## Simple Usage
|
||||
|
||||
```js
|
||||
// Used to create docx files
|
||||
@ -61,326 +43,34 @@ var docx = require('docx');
|
||||
// Create document
|
||||
var doc = new docx.Document();
|
||||
|
||||
// Add some content in the document
|
||||
var paragraph = new docx.Paragraph("Some cool text here.");
|
||||
// Add more text into the paragraph if you wish
|
||||
paragraph.addRun(new docx.TextRun('Lorem Ipsum Foo Bar'));
|
||||
doc.addParagraph(paragraph);
|
||||
|
||||
// Used to export the file into a .docx file
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
|
||||
// Or use the express packer to make the file downloadable.
|
||||
// res is express' Response object
|
||||
var exporter = new docx.ExpressPacker(doc, res);
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
```
|
||||
## Create simple Word Document
|
||||
```js
|
||||
var doc = new docx.Document();
|
||||
|
||||
var paragraph = new docx.Paragraph();
|
||||
var text = new docx.TextRun('Hello World');
|
||||
paragraph.addText(text);
|
||||
doc.addParagraph(paragraph);
|
||||
exporter.pack('My First Document');
|
||||
|
||||
// done! A file called 'My First Document.docx'
|
||||
// will be in your file system if you used LocalPacker
|
||||
// Or it will start downloading if you are using Express
|
||||
```
|
||||
|
||||
### Document properties
|
||||
You can add properties to the Word document by specifying options, for example:
|
||||
```js
|
||||
var doc = new docx.Document({
|
||||
creator: 'Dolan Miu',
|
||||
description: 'My extremely interesting document',
|
||||
title: 'My Document'
|
||||
});
|
||||
```
|
||||
## Examples
|
||||
Check [the Wiki](https://github.com/dolanmiu/docx/wiki/Examples) for examples.
|
||||
|
||||
#### Full list of options:
|
||||
```
|
||||
creator
|
||||
description
|
||||
title
|
||||
subject
|
||||
keywords
|
||||
lastModifiedBy
|
||||
revision
|
||||
```
|
||||
-----
|
||||
|
||||
You can mix and match whatever properties you want, or provide no properties.
|
||||
Made with 💖
|
||||
|
||||
## Create Paragraph
|
||||
Every text block in OpenXML is organised in paragraphs. You can add more text to the paragraph by doing this:
|
||||
```js
|
||||
var paragraph = new docx.Paragraph(),
|
||||
```
|
||||
```js
|
||||
var text = new docx.TextRun('Lorem Ipsum Foo Bar');
|
||||
var paragraph = new docx.Paragraph();
|
||||
paragraph.addText(text);
|
||||
```
|
||||
```js
|
||||
var paragraph = new docx.Paragraph("Short hand notation for adding text.");
|
||||
```
|
||||
|
||||
After you create the paragraph, you must add the paragraph into the `document`:
|
||||
```js
|
||||
doc.addParagraph(paragraph);
|
||||
```
|
||||
|
||||
### Styles
|
||||
Styles is a very important part of the look of a word document. At the moment, only headings and title is supported, but son the rest will be supported along with custom styles!
|
||||
|
||||

|
||||
|
||||
#### Heading1 - Heading5
|
||||
```js
|
||||
paragraph.heading1();
|
||||
paragraph.heading2();
|
||||
paragraph.heading3();
|
||||
paragraph.heading4();
|
||||
paragraph.heading5();
|
||||
```
|
||||
|
||||
#### Title
|
||||
```js
|
||||
paragraph.title();
|
||||
```
|
||||
|
||||
### Text Alignment
|
||||
To change the text alignment of a paragraph, for center, left, right or justified:
|
||||
```js
|
||||
paragraph.center();
|
||||
```
|
||||
```js
|
||||
paragraph.left();
|
||||
```
|
||||
```js
|
||||
paragraph.right();
|
||||
```
|
||||
```js
|
||||
paragraph.justified();
|
||||
```
|
||||
|
||||
#### Example
|
||||
```js
|
||||
paragraph.heading1().center();
|
||||
```
|
||||
The above will create a `heading 1` which is `centered`.
|
||||
|
||||
### Thematic Break
|
||||
To add a break in the page, simply add `.thematicBreak()` on a paragraph:
|
||||
|
||||
```js
|
||||
var paragraph = new docx.Paragraph("Amazing Heading").heading1().thematicBreak();
|
||||
```
|
||||
The above example will create a heading with a page break directly under it.
|
||||
|
||||
### Page Break
|
||||
To move to a new page (insert a page break), simply add `.pageBreak()` on a paragraph:
|
||||
|
||||
```js
|
||||
var paragraph = new docx.Paragraph("Amazing Heading").heading1().pageBreak();
|
||||
```
|
||||
The above example will create a heading and start a new page immediately afterwards.
|
||||
|
||||
## Text
|
||||
Paragraphs need `text run` objects. To create text:
|
||||
```js
|
||||
var text = new docx.TextRun("My awesome text here for my university dissertation");
|
||||
paragraph.addText(text);
|
||||
```
|
||||
Text objects have methods inside which changes the way the text is displayed.
|
||||
|
||||
### Typographical Emphasis
|
||||
More info [here](https://english.stackexchange.com/questions/97081/what-is-the-typography-term-which-refers-to-the-usage-of-bold-italics-and-unde)
|
||||
#### Bold
|
||||
```js
|
||||
text.bold();
|
||||
```
|
||||
|
||||
#### Italics
|
||||
```js
|
||||
text.italic();
|
||||
```
|
||||
|
||||
#### Underline
|
||||
```js
|
||||
text.underline();
|
||||
```
|
||||
|
||||
#### Strike through
|
||||
```js
|
||||
text.strike();
|
||||
```
|
||||
|
||||
#### Double strike through
|
||||
```js
|
||||
text.doubleStrike();
|
||||
```
|
||||
|
||||
#### Superscript
|
||||
```js
|
||||
text.superScript();
|
||||
```
|
||||
|
||||
#### Subscript
|
||||
```js
|
||||
text.subScript();
|
||||
```
|
||||
|
||||
#### All Capitals
|
||||
```js
|
||||
text.allCaps();
|
||||
```
|
||||
|
||||
#### Small Capitals
|
||||
```js
|
||||
text.smallCaps();
|
||||
```
|
||||
|
||||
### Break
|
||||
Sometimes you would want to put text underneath another line of text but inside the same paragraph.
|
||||
```js
|
||||
text.break();
|
||||
```
|
||||
|
||||
### Chaining
|
||||
What if you want to create a paragraph which is ***bold*** and ***italic***?
|
||||
```js
|
||||
paragraph.bold().italic();
|
||||
```
|
||||
|
||||
## Bullet Points
|
||||
To make a bullet point, simply make a paragraph into a bullet point:
|
||||
```js
|
||||
var text = new docx.TextRun("Bullet points");
|
||||
var paragraph = new docx.Paragraph(text).bullet();
|
||||
|
||||
var text2 = new docx.TextRun("Are awesome");
|
||||
var paragraph2 = new docx.Paragraph(text2).bullet();
|
||||
|
||||
doc.addParagraph(paragraph);
|
||||
doc.addParagraph(paragraph2);
|
||||
```
|
||||
This will produce:
|
||||
* Bullet points
|
||||
* Are awesome
|
||||
|
||||
## Tab Stops
|
||||
If you do not know why tab stops are useful, then I recommend you do a bit of research. It enables side by side text which is nicely laid out without the need for tables, or constantly pressing space bar.
|
||||
|
||||
**Note**: At the moment, the unit of measurement for a tab stop is counter intuitive for a human. It is using OpenXMLs own measuring system. For example, 2268 roughly translates to 3cm. Therefore in the future, I may consider changing it to percentages or even cm.
|
||||
|
||||

|
||||
|
||||
Simply call the relevant methods on the paragraph listed below. Then just add a `tab()` method call to a text object. Adding multiple `tabStops` will mean you would have to chain `tab()` until the desired `tabStop` is selected. Example is shown below.
|
||||
|
||||
### Left Tab Stop
|
||||
```js
|
||||
paragraph.leftTabStop(2268);
|
||||
```
|
||||
2268 is the distance from the left side.
|
||||
|
||||
### Center Tab Stop
|
||||
```js
|
||||
paragraph.centerTabStp(2268);
|
||||
```
|
||||
2268 is the distance from the left side.
|
||||
|
||||
### Right Tab Stop
|
||||
```js
|
||||
paragraph.rightTabStop(2268);
|
||||
```
|
||||
2268 is the distance from the left side.
|
||||
|
||||
### Max Right Tab Stop
|
||||
```js
|
||||
paragraph.maxRightTabStop();
|
||||
```
|
||||
This will create a tab stop on the very edge of the right hand side. Handy for right aligning and left aligning text on the same line.
|
||||
|
||||
### Example
|
||||
```js
|
||||
var paragraph = new docx.Paragraph().maxRightTabStop();
|
||||
var leftText = new docx.TextRun("Hey everyone").bold();
|
||||
var rightText = new docx.TextRun("11th November 2015").tab();
|
||||
paragraph.addText(leftText);
|
||||
paragraph.addText(rightText);
|
||||
```
|
||||
The example above will create a left aligned text, and a right aligned text on the same line. The laymans approach to this problem would be to either use text boxes or tables. YUK!
|
||||
|
||||
```js
|
||||
var paragraph = new docx.Paragraph();
|
||||
paragraph.maxRightTabStop();
|
||||
paragraph.leftTabStop(1000);
|
||||
var text = new docx.TextRun("Second tab stop here I come!").tab().tab();
|
||||
paragraph.addText(text);
|
||||
```
|
||||
The above shows the use of two tab stops, and how to select/use it.
|
||||
|
||||
# Exporting
|
||||
I used the express exporter in my [website](http://www.dolan.bio). It's very useful, and is the preferred way if you want to make a downloadable file for a visitor. it is much better than generating a physical file on the server, and then passing a download link to that file.
|
||||
## Express
|
||||
Simply use the exporter, and pass in the necessary parameters:
|
||||
```js
|
||||
var docx = require('docx');
|
||||
|
||||
var doc = new docx.Document();
|
||||
var exporter = new docx.ExpressPacker(doc, res);
|
||||
exporter.pack('My Document');
|
||||
```
|
||||
where `res` is the response object obtained through the Express router. It is that simple. The file will begin downloading in the browser.
|
||||
|
||||
## Standalone .docx file
|
||||
```js
|
||||
var docx = require('docx');
|
||||
|
||||
var doc = new docx.Document();
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
exporter.pack('My Document');
|
||||
```
|
||||
|
||||
# Examples
|
||||
## In practice
|
||||
I used this library in my personal portfolio/CV website. Click generate CV for a demonstration. [http://www.dolan.bio](http://www.dolan.bio)
|
||||
|
||||
## General
|
||||
#### Simple paragraph
|
||||
```js
|
||||
var doc = new docx.Document();
|
||||
|
||||
var paragraph = new docx.Paragraph("Hello World");
|
||||
var institutionText = new docx.TextRun("University College London").bold(),
|
||||
var dateText = new docx.TextRun("5th Dec 2015").tab().bold();
|
||||
paragraph.addText(institutionText);
|
||||
paragraph.addText(dateText);
|
||||
|
||||
doc.addParagraph(paragraph);
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
exporter.pack('My Document');
|
||||
```
|
||||
|
||||
Or:
|
||||
```js
|
||||
var doc = new docx.Document();
|
||||
|
||||
var paragraph = new docx.Paragraph("Hello World");
|
||||
var institutionText = new docx.TextRun("University College London").bold(),
|
||||
var dateText = new docx.TextRun("5th Dec 2015").tab().bold();
|
||||
paragraph.addText(institutionText);
|
||||
paragraph.addText(dateText);
|
||||
|
||||
var exporter = new docx.ExpressPacker(doc, res);
|
||||
exporter.pack('My Document');
|
||||
```
|
||||
Would produce:
|
||||
|
||||
***University College London***
|
||||
|
||||
***5th Dec 2015***
|
||||
|
||||
Made with 💖 by Dolan Miu 🍆 💦 😝
|
||||
|
||||
# License
|
||||
|
||||
MIT © [Dolan Miu](http://www.dolan.bio)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Huge thanks to [@felipeochoa](https://github.com/felipeochoa) for awesome contributions to this project
|
||||
|
||||
[npm-image]: https://badge.fury.io/js/docx.svg
|
||||
[npm-url]: https://npmjs.org/package/docx
|
||||
@ -390,3 +80,8 @@ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
[daviddm-url]: https://david-dm.org/dolanmiu/docx
|
||||
[snky-image]: https://snyk.io/test/github/dolanmiu/docx/badge.svg
|
||||
[snky-url]: https://snyk.io/test/github/dolanmiu/docx
|
||||
[gitter-image]: https://badges.gitter.im/dolanmiu/docx.svg
|
||||
[gitter-url]: https://gitter.im/docx-lib/Lobby
|
||||
[gemnasium-image]: https://gemnasium.com/badges/github.com/dolanmiu/docx.svg
|
||||
[gemnasium-url]: https://gemnasium.com/github.com/dolanmiu/docx
|
||||
|
||||
|
22
demo/demo1.js
Normal file
22
demo/demo1.js
Normal file
@ -0,0 +1,22 @@
|
||||
const docx = require('../build');
|
||||
|
||||
var doc = new docx.Document();
|
||||
|
||||
var paragraph = new docx.Paragraph("Hello World");
|
||||
var institutionText = new docx.TextRun("University College London").bold();
|
||||
var dateText = new docx.TextRun("5th Dec 2015").tab().bold();
|
||||
paragraph.addRun(institutionText);
|
||||
paragraph.addRun(dateText);
|
||||
|
||||
doc.addParagraph(paragraph);
|
||||
|
||||
// Feature coming soon
|
||||
// var media = new docx.Media();
|
||||
// media.addMedia("happy-penguins", "./demo/penguins.jpg");
|
||||
// var pictureRun = new docx.PictureRun(media.getMedia("happy-penguins"));
|
||||
|
||||
// var exporter = new docx.LocalPacker(doc);
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
exporter.pack('My Document');
|
||||
|
||||
console.log('Document created succesfully at project root!');
|
74
demo/demo2.js
Normal file
74
demo/demo2.js
Normal file
@ -0,0 +1,74 @@
|
||||
const docx = require('../build');
|
||||
|
||||
const styles = new docx.Styles();
|
||||
styles.createParagraphStyle('Heading1', 'Heading 1')
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.quickFormat()
|
||||
.size(28)
|
||||
.bold()
|
||||
.italics()
|
||||
.spacing({after: 120});
|
||||
|
||||
styles.createParagraphStyle('Heading2', 'Heading 2')
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.quickFormat()
|
||||
.size(26)
|
||||
.bold()
|
||||
.underline('double', 'FF0000')
|
||||
.spacing({before: 240, after: 120});
|
||||
|
||||
styles.createParagraphStyle('aside', 'Aside')
|
||||
.basedOn('Normal')
|
||||
.next('Normal')
|
||||
.color('999999')
|
||||
.italics()
|
||||
.indent(720)
|
||||
.spacing({line: 276});
|
||||
|
||||
styles.createParagraphStyle('wellSpaced', 'Well Spaced')
|
||||
.basedOn('Normal')
|
||||
.spacing({line: 276, before: 20 * 72 * .1, after: 20 * 72 * .05});
|
||||
|
||||
styles.createParagraphStyle('ListParagraph', 'List Paragraph')
|
||||
.quickFormat()
|
||||
.basedOn('Normal');
|
||||
|
||||
|
||||
const numbering = new docx.Numbering();
|
||||
const numberedAbstract = numbering.createAbstractNumbering();
|
||||
numberedAbstract.createLevel(0, "lowerLetter", "%1)", "left");
|
||||
|
||||
const doc = new docx.Document({
|
||||
creator: 'Clippy',
|
||||
title: 'Sample Document',
|
||||
description: 'A brief example of using docx',
|
||||
});
|
||||
|
||||
doc.createParagraph('Test heading1, bold and italicized').heading1();
|
||||
doc.createParagraph('Some simple content');
|
||||
doc.createParagraph('Test heading2 with double red underline').heading2();
|
||||
|
||||
const letterNumbering = numbering.createConcreteNumbering(numberedAbstract);
|
||||
const letterNumbering5 = numbering.createConcreteNumbering(numberedAbstract);
|
||||
letterNumbering5.overrideLevel(0, 5);
|
||||
|
||||
doc.createParagraph('Option1').setNumbering(letterNumbering, 0);
|
||||
doc.createParagraph('Option5 -- override 2 to 5').setNumbering(letterNumbering5, 0);
|
||||
doc.createParagraph('Option3').setNumbering(letterNumbering, 0);
|
||||
|
||||
doc.createParagraph()
|
||||
.createTextRun('Some monospaced content')
|
||||
.font('Monospace');
|
||||
|
||||
doc.createParagraph('An aside, in light gray italics and indented').style('aside');
|
||||
doc.createParagraph('This is normal, but well-spaced text').style('wellSpaced');
|
||||
const para = doc.createParagraph();
|
||||
para.createTextRun('This is a bold run,').bold();
|
||||
para.createTextRun(' switching to normal ');
|
||||
para.createTextRun('and then underlined ').underline();
|
||||
para.createTextRun('and back to normal.');
|
||||
|
||||
const exporter = new docx.LocalPacker(doc, styles, undefined, numbering);
|
||||
exporter.pack('test.docx');
|
29
demo/index.js
Normal file
29
demo/index.js
Normal file
@ -0,0 +1,29 @@
|
||||
var prompt = require('prompt');
|
||||
var shelljs = require('shelljs');
|
||||
var fs = require('fs');
|
||||
|
||||
console.log('What demo do you wish to run? (Enter a number)');
|
||||
|
||||
var schema = {
|
||||
properties: {
|
||||
number: {
|
||||
pattern: /^[0-9]+$/,
|
||||
message: 'Please enter a number.',
|
||||
required: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
prompt.start();
|
||||
|
||||
prompt.get(schema, function (err, result) {
|
||||
var demoNumber = result.number;
|
||||
var filePath = `./demo/demo${demoNumber}.js`;
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.error(`demo${demoNumber} does not exist: ${filePath}`);
|
||||
return;
|
||||
}
|
||||
console.log(`Running demo ${demoNumber}`);
|
||||
shelljs.exec(`node ${filePath}`);
|
||||
});
|
BIN
demo/penguins.jpg
Normal file
BIN
demo/penguins.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 162 KiB |
68
deploy-docs.sh
Normal file
68
deploy-docs.sh
Normal file
@ -0,0 +1,68 @@
|
||||
#!/bin/bash
|
||||
set -e # Exit with nonzero exit code if anything fails
|
||||
|
||||
SOURCE_BRANCH="master"
|
||||
TARGET_BRANCH="gh-pages"
|
||||
|
||||
function doCompile {
|
||||
npm run typedoc
|
||||
}
|
||||
|
||||
# Pull requests and commits to other branches shouldn't try to deploy, just build to verify
|
||||
if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "$SOURCE_BRANCH" ]; then
|
||||
echo "Skipping deploy; just doing a build."
|
||||
doCompile
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Save some useful information
|
||||
REPO=`git config remote.origin.url`
|
||||
SSH_REPO=${REPO/https:\/\/github.com\//git@github.com:}
|
||||
SHA=`git rev-parse --verify HEAD`
|
||||
|
||||
# Clone the existing gh-pages for this repo into docs/
|
||||
# Create a new empty branch if gh-pages doesn't exist yet (should only happen on first deply)
|
||||
git clone $REPO docs
|
||||
cd docs
|
||||
git checkout $TARGET_BRANCH || git checkout --orphan $TARGET_BRANCH
|
||||
cd ..
|
||||
|
||||
# Clean out existing contents
|
||||
# echo "Cleaning out existing contents."
|
||||
# rm -rf docs/*
|
||||
|
||||
# Run our compile script
|
||||
doCompile
|
||||
|
||||
# Now let's go have some fun with the cloned repo
|
||||
cd docs
|
||||
git config user.name "Travis CI"
|
||||
git config user.email "dolan_miu@hotmail.com"
|
||||
ls
|
||||
|
||||
# add .nojekyll file
|
||||
touch .nojekyll
|
||||
|
||||
# If there are no changes to the compiled out (e.g. this is a README update) then just bail.
|
||||
if [ -z `git diff --exit-code` ]; then
|
||||
echo "No changes to the output on this push; exiting."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Commit the "changes", i.e. the new version.
|
||||
# The delta will show diffs between new and old versions.
|
||||
git add .
|
||||
git commit -m "Deploy to GitHub Pages: ${SHA}"
|
||||
|
||||
# Get the deploy key by using Travis's stored variables to decrypt deploy-key.enc
|
||||
ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key"
|
||||
ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv"
|
||||
ENCRYPTED_KEY=${!ENCRYPTED_KEY_VAR}
|
||||
ENCRYPTED_IV=${!ENCRYPTED_IV_VAR}
|
||||
openssl aes-256-cbc -K $ENCRYPTED_KEY -iv $ENCRYPTED_IV -in deploy-key.enc -out deploy-key -d
|
||||
chmod 600 deploy-key
|
||||
eval `ssh-agent -s`
|
||||
ssh-add deploy-key
|
||||
|
||||
# Now that we're all set up, we can push.
|
||||
git push $SSH_REPO $TARGET_BRANCH
|
BIN
deploy-key.enc
Normal file
BIN
deploy-key.enc
Normal file
Binary file not shown.
27
package.json
27
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docx",
|
||||
"version": "1.2.1",
|
||||
"version": "2.1.1",
|
||||
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
|
||||
"main": "build/index.js",
|
||||
"scripts": {
|
||||
@ -8,11 +8,14 @@
|
||||
"test": "mocha ./build-tests --recursive",
|
||||
"prepublishOnly": "npm run build",
|
||||
"lint": "tslint --project ./ts",
|
||||
"build": "rimraf ./build && tsc -p ts"
|
||||
"build": "rimraf ./build && tsc -p ts",
|
||||
"demo": "npm run build && node ./demo",
|
||||
"typedoc": "typedoc --out docs/ ts/ --module commonjs --target ES6 --disableOutputCheck"
|
||||
},
|
||||
"files": [
|
||||
"ts",
|
||||
"build"
|
||||
"build",
|
||||
"template"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -20,21 +23,20 @@
|
||||
},
|
||||
"keywords": [
|
||||
"office",
|
||||
"word",
|
||||
"generate",
|
||||
"creator",
|
||||
"create",
|
||||
"document",
|
||||
"doc",
|
||||
"officegen",
|
||||
"clippy"
|
||||
],
|
||||
"types": "./build/index.d.ts",
|
||||
"dependencies": {
|
||||
"@types/archiver": "^0.15.37",
|
||||
"@types/archiver": "^1.3.4",
|
||||
"@types/express": "^4.0.35",
|
||||
"@types/lodash": "^4.14.54",
|
||||
"app-root-path": "^2.0.1",
|
||||
"archiver": "^1.3.0",
|
||||
"install": "^0.8.7",
|
||||
"lodash": "^4.6.1",
|
||||
"npm": "^4.3.0",
|
||||
"xml": "^1.0.1"
|
||||
},
|
||||
"author": "Dolan Miu",
|
||||
@ -48,8 +50,11 @@
|
||||
"@types/mocha": "^2.2.39",
|
||||
"chai": "^3.5.0",
|
||||
"mocha": "^3.2.0",
|
||||
"prompt": "^1.0.0",
|
||||
"rimraf": "^2.5.2",
|
||||
"tslint": "^4.5.1",
|
||||
"typescript": "^2.2.1"
|
||||
"shelljs": "^0.7.7",
|
||||
"tslint": "^5.1.0",
|
||||
"typedoc": "^0.5.10",
|
||||
"typescript": "^2.4.1"
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
import { Attributes, XmlComponent } from "../../xml-components";
|
||||
import { SectionProperties } from "./section-properties";
|
||||
import { XmlComponent } from "../../xml-components";
|
||||
|
||||
export class Body extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("w:body");
|
||||
// this.root.push(new SectionProperties()); not actually needed
|
||||
}
|
||||
|
||||
public push(component: XmlComponent): void {
|
||||
// this.root.splice(this.body.length - 1, 0, component);
|
||||
this.root.push(component);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { XmlAttributeComponent } from "../xml-components";
|
||||
|
||||
interface IDocumentAttributesProperties {
|
||||
export interface IDocumentAttributesProperties {
|
||||
wpc?: string;
|
||||
mc?: string;
|
||||
o?: string;
|
||||
@ -26,10 +26,8 @@ interface IDocumentAttributesProperties {
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export class DocumentAttributes extends XmlAttributeComponent {
|
||||
|
||||
constructor(properties?: IDocumentAttributesProperties) {
|
||||
super({
|
||||
export class DocumentAttributes extends XmlAttributeComponent<IDocumentAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
wpc: "xmlns:wpc",
|
||||
mc: "xmlns:mc",
|
||||
o: "xmlns:o",
|
||||
@ -53,12 +51,5 @@ export class DocumentAttributes extends XmlAttributeComponent {
|
||||
dcmitype: "xmlns:dcmitype",
|
||||
xsi: "xmlns:xsi",
|
||||
type: "xsi:type",
|
||||
}, properties);
|
||||
|
||||
this.root = properties;
|
||||
|
||||
if (!properties) {
|
||||
this.root = {};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { Paragraph } from "../paragraph";
|
||||
import { Table } from "../table";
|
||||
import { XmlComponent } from "../xml-components";
|
||||
import { Body } from "./body";
|
||||
import { DocumentAttributes } from "./document-attributes";
|
||||
|
||||
export class Document extends XmlComponent {
|
||||
private body: Body;
|
||||
|
||||
@ -34,8 +36,20 @@ export class Document extends XmlComponent {
|
||||
this.body.push(paragraph);
|
||||
}
|
||||
|
||||
public clearVariables(): void {
|
||||
this.body.clearVariables();
|
||||
delete this.body;
|
||||
public createParagraph(text?: string): Paragraph {
|
||||
const para = new Paragraph(text);
|
||||
this.addParagraph(para);
|
||||
return para;
|
||||
}
|
||||
|
||||
public addTable(table: Table): void {
|
||||
this.body.push(table);
|
||||
}
|
||||
|
||||
public createTable(rows: number, cols: number): Table {
|
||||
const table = new Table(rows, cols);
|
||||
this.addTable(table);
|
||||
return table;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,3 +2,6 @@ export { Document } from "./document";
|
||||
export { Paragraph } from "./paragraph";
|
||||
export { Run } from "./run";
|
||||
export { TextRun } from "./run/text-run";
|
||||
export { PictureRun } from "./run/picture-run";
|
||||
export { Table } from "./table";
|
||||
// Perhaps all run related stuff can be exported from run, instead of exporting Run, TextRun, PictureRun seperately.
|
||||
|
15
ts/docx/paragraph/alignment.ts
Normal file
15
ts/docx/paragraph/alignment.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
||||
|
||||
export type AlignmentOptions = "left" | "center" | "right" | "both";
|
||||
|
||||
export class AlignmentAttributes extends XmlAttributeComponent<{val: AlignmentOptions}> {
|
||||
protected xmlKeys = {val: "w:val"};
|
||||
}
|
||||
|
||||
export class Alignment extends XmlComponent {
|
||||
|
||||
constructor(type: AlignmentOptions) {
|
||||
super("w:jc");
|
||||
this.root.push(new AlignmentAttributes({val: type}));
|
||||
}
|
||||
}
|
10
ts/docx/paragraph/formatting.ts
Normal file
10
ts/docx/paragraph/formatting.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export { Alignment } from "./alignment";
|
||||
export { ThematicBreak } from "./border";
|
||||
export { Indent } from "./indent";
|
||||
export { KeepLines, KeepNext } from "./keep";
|
||||
export { PageBreak } from "./page-break";
|
||||
export { ParagraphProperties } from "./properties";
|
||||
export { ISpacingProperties, Spacing } from "./spacing";
|
||||
export { Style } from "./style";
|
||||
export { LeftTabStop, MaxRightTabStop } from "./tab-stop";
|
||||
export { NumberProperties } from "./unordered-list";
|
24
ts/docx/paragraph/indent.ts
Normal file
24
ts/docx/paragraph/indent.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
||||
|
||||
interface IIndentAttributesProperties {
|
||||
left?: number;
|
||||
hanging?: number;
|
||||
}
|
||||
|
||||
class IndentAttributes extends XmlAttributeComponent<IIndentAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
left: "w:left",
|
||||
hanging: "w:hanging",
|
||||
};
|
||||
}
|
||||
|
||||
export class Indent extends XmlComponent {
|
||||
|
||||
constructor(left: number, hanging?: number) {
|
||||
super("w:ind");
|
||||
this.root.push(new IndentAttributes({
|
||||
left: left,
|
||||
hanging: hanging,
|
||||
}));
|
||||
}
|
||||
}
|
@ -1,23 +1,21 @@
|
||||
import { IData } from "../../media/data";
|
||||
import { Num } from "../../numbering/num";
|
||||
import { Run } from "../run";
|
||||
import { PictureRun } from "../run/picture-run";
|
||||
import { TextRun } from "../run/text-run";
|
||||
import { Attributes, XmlComponent } from "../xml-components";
|
||||
import { XmlComponent } from "../xml-components";
|
||||
|
||||
import { Alignment } from "./alignment";
|
||||
import { ThematicBreak } from "./border";
|
||||
import { Indent } from "./indent";
|
||||
import { KeepLines, KeepNext } from "./keep";
|
||||
import { PageBreak } from "./page-break";
|
||||
import { ParagraphProperties } from "./properties";
|
||||
import { ISpacingProperties, Spacing } from "./spacing";
|
||||
import { Style } from "./style";
|
||||
import { LeftTabStop, MaxRightTabStop } from "./tab-stop";
|
||||
import { NumberProperties } from "./unordered-list";
|
||||
|
||||
class Alignment extends XmlComponent {
|
||||
|
||||
constructor(type: string) {
|
||||
super("w:jc");
|
||||
this.root.push(new Attributes({
|
||||
val: type,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export class Paragraph extends XmlComponent {
|
||||
private properties: ParagraphProperties;
|
||||
|
||||
@ -30,11 +28,23 @@ export class Paragraph extends XmlComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public addText(run: TextRun): Paragraph {
|
||||
public addRun(run: Run): Paragraph {
|
||||
this.root.push(run);
|
||||
return this;
|
||||
}
|
||||
|
||||
public createTextRun(text: string): TextRun {
|
||||
const run = new TextRun(text);
|
||||
this.addRun(run);
|
||||
return run;
|
||||
}
|
||||
|
||||
public createPictureRun(imageData: IData): PictureRun {
|
||||
const run = new PictureRun(imageData);
|
||||
this.addRun(run);
|
||||
return run;
|
||||
}
|
||||
|
||||
public heading1(): Paragraph {
|
||||
this.properties.push(new Style("Heading1"));
|
||||
return this;
|
||||
@ -116,4 +126,29 @@ export class Paragraph extends XmlComponent {
|
||||
this.properties.push(new NumberProperties(numbering.id, indentLevel));
|
||||
return this;
|
||||
}
|
||||
|
||||
public style(styleId: string): Paragraph {
|
||||
this.properties.push(new Style(styleId));
|
||||
return this;
|
||||
}
|
||||
|
||||
public indent(start: number, hanging?: number): Paragraph {
|
||||
this.properties.push(new Indent(start, hanging));
|
||||
return this;
|
||||
}
|
||||
|
||||
public spacing(params: ISpacingProperties): Paragraph {
|
||||
this.properties.push(new Spacing(params));
|
||||
return this;
|
||||
}
|
||||
|
||||
public keepNext(): Paragraph {
|
||||
this.properties.push(new KeepNext());
|
||||
return this;
|
||||
}
|
||||
|
||||
public keepLines(): Paragraph {
|
||||
this.properties.push(new KeepLines());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
13
ts/docx/paragraph/keep.ts
Normal file
13
ts/docx/paragraph/keep.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { XmlComponent } from "../xml-components";
|
||||
|
||||
export class KeepLines extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:keepLines");
|
||||
}
|
||||
}
|
||||
|
||||
export class KeepNext extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:keepNext");
|
||||
}
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
import { Attributes, XmlComponent } from "../xml-components";
|
||||
import { XmlComponent } from "../xml-components";
|
||||
|
||||
export class ParagraphProperties extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("w:pPr");
|
||||
this.root.push(new Attributes());
|
||||
}
|
||||
|
||||
public push(item: XmlComponent): void {
|
||||
|
22
ts/docx/paragraph/spacing.ts
Normal file
22
ts/docx/paragraph/spacing.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
||||
|
||||
export interface ISpacingProperties {
|
||||
after?: number;
|
||||
before?: number;
|
||||
line?: number;
|
||||
}
|
||||
|
||||
class SpacingAttributes extends XmlAttributeComponent<ISpacingProperties> {
|
||||
protected xmlKeys = {
|
||||
after: "w:after",
|
||||
before: "w:before",
|
||||
line: "w:line",
|
||||
};
|
||||
}
|
||||
|
||||
export class Spacing extends XmlComponent {
|
||||
constructor(opts: ISpacingProperties) {
|
||||
super("w:spacing");
|
||||
this.root.push(new SpacingAttributes(opts));
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { Attributes, XmlComponent } from "../xml-components";
|
||||
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
||||
|
||||
class TabStop extends XmlComponent {
|
||||
export class TabStop extends XmlComponent {
|
||||
|
||||
constructor(tab: Tab) {
|
||||
super("w:tabs");
|
||||
@ -8,11 +8,17 @@ class TabStop extends XmlComponent {
|
||||
}
|
||||
}
|
||||
|
||||
class Tab extends XmlComponent {
|
||||
export type TabOptions = "left" | "right";
|
||||
|
||||
constructor(value: string, position: any) {
|
||||
export class TabAttributes extends XmlAttributeComponent<{val: TabOptions, pos: string | number}> {
|
||||
protected xmlKeys = {val: "w:val", pos: "w:pos"};
|
||||
}
|
||||
|
||||
export class Tab extends XmlComponent {
|
||||
|
||||
constructor(value: TabOptions, position: string | number) {
|
||||
super("w:tab");
|
||||
this.root.push(new Attributes({
|
||||
this.root.push(new TabAttributes({
|
||||
val: value,
|
||||
pos: position,
|
||||
}));
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Attributes, XmlComponent } from "../xml-components";
|
||||
import { Style } from "./style";
|
||||
|
||||
export class NumberProperties extends XmlComponent {
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { Attributes, XmlComponent } from "../xml-components";
|
||||
export { Underline } from "./underline";
|
||||
export { SubScript, SuperScript } from "./script";
|
||||
export { RunFonts } from "./run-fonts";
|
||||
|
||||
export class Bold extends XmlComponent {
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { Break } from "./break";
|
||||
import { Caps, SmallCaps } from "./caps";
|
||||
import { Bold, Italics } from "./formatting";
|
||||
import { Bold, Color, DoubleStrike, Italics, Size, Strike } from "./formatting";
|
||||
import { RunProperties } from "./properties";
|
||||
import { RunFonts } from "./run-fonts";
|
||||
import { SubScript, SuperScript } from "./script";
|
||||
import { DoubleStrike, Strike } from "./strike";
|
||||
import { Style } from "./style";
|
||||
import { Tab } from "./tab";
|
||||
import { Underline } from "./underline";
|
||||
|
||||
import { Attributes, XmlComponent } from "../xml-components";
|
||||
import { XmlComponent } from "../xml-components";
|
||||
|
||||
export class Run extends XmlComponent {
|
||||
private properties: RunProperties;
|
||||
@ -29,8 +29,18 @@ export class Run extends XmlComponent {
|
||||
return this;
|
||||
}
|
||||
|
||||
public underline(): Run {
|
||||
this.properties.push(new Underline());
|
||||
public underline(underlineType?: string, color?: string): Run {
|
||||
this.properties.push(new Underline(underlineType, color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public color(color: string): Run {
|
||||
this.properties.push(new Color(color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public size(size: number): Run {
|
||||
this.properties.push(new Size(size));
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -78,4 +88,9 @@ export class Run extends XmlComponent {
|
||||
this.properties.push(new RunFonts(fontName));
|
||||
return this;
|
||||
}
|
||||
|
||||
public style(styleId: string): Run {
|
||||
this.properties.push(new Style(styleId));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
16
ts/docx/run/picture-run.ts
Normal file
16
ts/docx/run/picture-run.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { IData } from "../../media/data";
|
||||
import { Run } from "../run";
|
||||
import { Drawing } from "./run-components/drawing";
|
||||
|
||||
export class PictureRun extends Run {
|
||||
|
||||
constructor(imageData: IData) {
|
||||
super();
|
||||
|
||||
if (imageData === undefined) {
|
||||
throw new Error("imageData cannot be undefined");
|
||||
}
|
||||
|
||||
this.root.push(new Drawing(imageData));
|
||||
}
|
||||
}
|
16
ts/docx/run/run-components/drawing/index.ts
Normal file
16
ts/docx/run/run-components/drawing/index.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { IData } from "../../../../media/data";
|
||||
import { XmlComponent } from "../../../xml-components";
|
||||
import { Inline } from "./inline";
|
||||
|
||||
export class Drawing extends XmlComponent {
|
||||
|
||||
constructor(imageData: IData) {
|
||||
super("w:drawing");
|
||||
|
||||
if (imageData === undefined) {
|
||||
throw new Error("imageData cannot be undefined");
|
||||
}
|
||||
|
||||
this.root.push(new Inline(imageData.referenceId));
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import { XmlComponent } from "../../../../../../xml-components";
|
||||
import { Pic } from "./pic";
|
||||
|
||||
export class GraphicData extends XmlComponent {
|
||||
|
||||
constructor(referenceId: number) {
|
||||
super("a:graphicData");
|
||||
this.root.push(new Pic(referenceId));
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import { XmlComponent } from "../../../../../../../../xml-components";
|
||||
import { Blip } from "./blip";
|
||||
import { SourceRectangle } from "./source-rectangle";
|
||||
import { Stretch } from "./stretch";
|
||||
|
||||
export class BlipFill extends XmlComponent {
|
||||
|
||||
constructor(referenceId: number) {
|
||||
super("pic:blipFill");
|
||||
this.root.push(new Blip(referenceId));
|
||||
this.root.push(new SourceRectangle());
|
||||
this.root.push(new Stretch());
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../../../../../../../../xml-components";
|
||||
|
||||
interface IBlipProperties {
|
||||
embed: string;
|
||||
}
|
||||
|
||||
class BlipAttributes extends XmlAttributeComponent<IBlipProperties> {
|
||||
protected xmlKeys = {
|
||||
embed: "r:embed",
|
||||
};
|
||||
}
|
||||
|
||||
export class Blip extends XmlComponent {
|
||||
|
||||
constructor(referenceId: number) {
|
||||
super("a:blip");
|
||||
this.root.push(new BlipAttributes({
|
||||
embed: `rId${referenceId}`,
|
||||
}));
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import { XmlComponent } from "../../../../../../../../xml-components";
|
||||
|
||||
export class SourceRectangle extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("a:srcRect");
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { XmlComponent } from "../../../../../../../../xml-components";
|
||||
|
||||
class FillRectangle extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("a:fillRect");
|
||||
}
|
||||
}
|
||||
|
||||
export class Stretch extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("a:stretch");
|
||||
this.root.push(new FillRectangle());
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import { XmlComponent } from "../../../../../../../xml-components";
|
||||
import { BlipFill } from "./blip/blip-fill";
|
||||
|
||||
export class Pic extends XmlComponent {
|
||||
|
||||
constructor(referenceId: number) {
|
||||
super("pic:pic");
|
||||
this.root.push(new BlipFill(referenceId));
|
||||
}
|
||||
}
|
23
ts/docx/run/run-components/drawing/inline/graphic/index.ts
Normal file
23
ts/docx/run/run-components/drawing/inline/graphic/index.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../../../../../xml-components";
|
||||
import { GraphicData } from "./graphic-data";
|
||||
|
||||
interface IGraphicProperties {
|
||||
a: string;
|
||||
}
|
||||
|
||||
class GraphicAttributes extends XmlAttributeComponent<IGraphicProperties> {
|
||||
protected xmlKeys = {
|
||||
a: "xmlns:a",
|
||||
};
|
||||
}
|
||||
|
||||
export class Graphic extends XmlComponent {
|
||||
|
||||
constructor(referenceId: number) {
|
||||
super("a:graphic");
|
||||
this.root.push(new GraphicAttributes({
|
||||
a: "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||
}));
|
||||
this.root.push(new GraphicData(referenceId));
|
||||
}
|
||||
}
|
10
ts/docx/run/run-components/drawing/inline/index.ts
Normal file
10
ts/docx/run/run-components/drawing/inline/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { XmlComponent } from "../../../../xml-components";
|
||||
import { Graphic } from "./graphic";
|
||||
|
||||
export class Inline extends XmlComponent {
|
||||
|
||||
constructor(referenceId: number) {
|
||||
super("wp:inline");
|
||||
this.root.push(new Graphic(referenceId));
|
||||
}
|
||||
}
|
15
ts/docx/run/run-components/text.ts
Normal file
15
ts/docx/run/run-components/text.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../../xml-components";
|
||||
|
||||
class TextAttributes extends XmlAttributeComponent<{space: "default" | "preserve"}> {
|
||||
protected xmlKeys = {space: "xml:space"};
|
||||
}
|
||||
|
||||
export class Text extends XmlComponent {
|
||||
constructor(text: string) {
|
||||
super("w:t");
|
||||
this.root.push(new TextAttributes({space: "preserve"}));
|
||||
if (text) {
|
||||
this.root.push(text);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,15 +6,12 @@ interface IRunFontAttributesProperties {
|
||||
hint?: string;
|
||||
}
|
||||
|
||||
class RunFontAttributes extends XmlAttributeComponent {
|
||||
|
||||
constructor(properties: IRunFontAttributesProperties) {
|
||||
super({
|
||||
class RunFontAttributes extends XmlAttributeComponent<IRunFontAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
ascii: "w:ascii",
|
||||
hAnsi: "w:hAnsi",
|
||||
hint: "w:hint",
|
||||
}, properties);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class RunFonts extends XmlComponent {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Attributes, XmlComponent } from "../xml-components";
|
||||
|
||||
abstract class VerticalAlign extends XmlComponent {
|
||||
export abstract class VerticalAlign extends XmlComponent {
|
||||
|
||||
constructor(type: string) {
|
||||
super("w:vertAlign");
|
||||
|
@ -1,15 +0,0 @@
|
||||
import { XmlComponent } from "../xml-components";
|
||||
|
||||
export class Strike extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("w:strike");
|
||||
}
|
||||
}
|
||||
|
||||
export class DoubleStrike extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("w:dstrike");
|
||||
}
|
||||
}
|
13
ts/docx/run/style.ts
Normal file
13
ts/docx/run/style.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
||||
|
||||
class StyleAttributes extends XmlAttributeComponent<{val: string}> {
|
||||
protected xmlKeys = {val: "w:val"};
|
||||
}
|
||||
|
||||
export class Style extends XmlComponent {
|
||||
|
||||
constructor(styleId: string) {
|
||||
super("w:rStyle");
|
||||
this.root.push(new StyleAttributes({val: styleId}));
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { Run } from "../run";
|
||||
import { Text } from "./text";
|
||||
import { Text } from "./run-components/text";
|
||||
|
||||
export class TextRun extends Run {
|
||||
|
||||
|
@ -1,9 +0,0 @@
|
||||
import { XmlUnitComponent } from "../xml-components";
|
||||
|
||||
export class Text extends XmlUnitComponent {
|
||||
|
||||
constructor(text: string) {
|
||||
super("w:t");
|
||||
this.root = text;
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { Attributes, XmlComponent } from "../xml-components";
|
||||
|
||||
abstract class BaseUnderline extends XmlComponent {
|
||||
export abstract class BaseUnderline extends XmlComponent {
|
||||
|
||||
constructor(underlineType: string, color?: string) {
|
||||
super("w:u");
|
||||
@ -13,8 +13,8 @@ abstract class BaseUnderline extends XmlComponent {
|
||||
|
||||
export class Underline extends BaseUnderline {
|
||||
|
||||
constructor() {
|
||||
super("");
|
||||
constructor(underlineType: string = "single", color?: string) {
|
||||
super(underlineType, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
export class Table {
|
||||
|
||||
}
|
21
ts/docx/table/grid.ts
Normal file
21
ts/docx/table/grid.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
||||
|
||||
export class TableGrid extends XmlComponent {
|
||||
constructor(cols: number[]) {
|
||||
super("w:tblGrid");
|
||||
cols.forEach((col) => this.root.push(new GridCol(col)));
|
||||
}
|
||||
}
|
||||
|
||||
class GridColAttributes extends XmlAttributeComponent<{w: number}> {
|
||||
protected xmlKeys = {w: "w:w"};
|
||||
}
|
||||
|
||||
export class GridCol extends XmlComponent {
|
||||
constructor(width?: number) {
|
||||
super("w:gridCol");
|
||||
if (width !== undefined) {
|
||||
this.root.push(new GridColAttributes({w: width}));
|
||||
}
|
||||
}
|
||||
}
|
123
ts/docx/table/index.ts
Normal file
123
ts/docx/table/index.ts
Normal file
@ -0,0 +1,123 @@
|
||||
import { Paragraph } from "../paragraph";
|
||||
import { XmlComponent } from "../xml-components";
|
||||
import { IXmlableObject } from "../xml-components/xmlable-object";
|
||||
import { TableGrid } from "./grid";
|
||||
import { TableProperties, WidthTypes } from "./properties";
|
||||
|
||||
export class Table extends XmlComponent {
|
||||
private properties: TableProperties;
|
||||
private rows: TableRow[];
|
||||
private grid: TableGrid;
|
||||
|
||||
constructor(rows: number, cols: number) {
|
||||
super("w:tbl");
|
||||
this.properties = new TableProperties();
|
||||
this.root.push(this.properties);
|
||||
|
||||
const gridCols: number[] = [];
|
||||
for (let i = 0; i < cols; i++) {
|
||||
/*
|
||||
0-width columns don't get rendered correctly, so we need
|
||||
to give them some value. A reasonable default would be
|
||||
~6in / numCols, but if we do that it becomes very hard
|
||||
to resize the table using setWidth, unless the layout
|
||||
algorithm is set to 'fixed'. Instead, the approach here
|
||||
means even in 'auto' layout, setting a width on the
|
||||
table will make it look reasonable, as the layout
|
||||
algorithm will expand columns to fit its content
|
||||
*/
|
||||
gridCols.push(1);
|
||||
}
|
||||
this.grid = new TableGrid(gridCols);
|
||||
this.root.push(this.grid);
|
||||
|
||||
this.rows = [];
|
||||
for (let i = 0; i < rows; i++) {
|
||||
const cells: TableCell[] = [];
|
||||
for (let j = 0; j < cols; j++) {
|
||||
cells.push(new TableCell());
|
||||
}
|
||||
const row = new TableRow(cells);
|
||||
this.rows.push(row);
|
||||
this.root.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
public getRow(ix: number): TableRow {
|
||||
return this.rows[ix];
|
||||
}
|
||||
|
||||
public getCell(row: number, col: number): TableCell {
|
||||
return this.getRow(row).getCell(col);
|
||||
}
|
||||
|
||||
public setWidth(type: WidthTypes, width: number | string): Table {
|
||||
this.properties.setWidth(type, width);
|
||||
return this;
|
||||
}
|
||||
|
||||
public fixedWidthLayout(): Table {
|
||||
this.properties.fixedWidthLayout();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class TableRow extends XmlComponent {
|
||||
private properties: TableRowProperties;
|
||||
private cells: TableCell[];
|
||||
|
||||
constructor(cells: TableCell[]) {
|
||||
super("w:tr");
|
||||
this.properties = new TableRowProperties();
|
||||
this.root.push(this.properties);
|
||||
this.cells = cells;
|
||||
cells.forEach((c) => this.root.push(c));
|
||||
}
|
||||
|
||||
public getCell(ix: number): TableCell {
|
||||
return this.cells[ix];
|
||||
}
|
||||
}
|
||||
|
||||
export class TableRowProperties extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:trPr");
|
||||
}
|
||||
}
|
||||
|
||||
export class TableCell extends XmlComponent {
|
||||
private properties: TableCellProperties;
|
||||
|
||||
constructor() {
|
||||
super("w:tc");
|
||||
this.properties = new TableCellProperties();
|
||||
this.root.push(this.properties);
|
||||
}
|
||||
|
||||
public addContent(content: Paragraph | Table): TableCell {
|
||||
this.root.push(content);
|
||||
return this;
|
||||
}
|
||||
|
||||
public prepForXml(): IXmlableObject {
|
||||
// Cells must end with a paragraph
|
||||
const retval = super.prepForXml();
|
||||
const content = retval["w:tc"];
|
||||
if (!content[content.length - 1]["w:p"]) {
|
||||
content.push(new Paragraph().prepForXml());
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
public createParagraph(text?: string): Paragraph {
|
||||
const para = new Paragraph(text);
|
||||
this.addContent(para);
|
||||
return para;
|
||||
}
|
||||
}
|
||||
|
||||
export class TableCellProperties extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:tcPr");
|
||||
}
|
||||
}
|
48
ts/docx/table/properties.ts
Normal file
48
ts/docx/table/properties.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../xml-components";
|
||||
|
||||
export type WidthTypes = "dxa" | "pct" | "nil" | "auto";
|
||||
|
||||
export class TableProperties extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:tblPr");
|
||||
}
|
||||
|
||||
public setWidth(type: WidthTypes, w: number | string): TableProperties {
|
||||
this.root.push(new PreferredTableWidth(type, w));
|
||||
return this;
|
||||
}
|
||||
|
||||
public fixedWidthLayout(): TableProperties {
|
||||
this.root.push(new TableLayout("fixed"));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
interface ITableWidth {
|
||||
type: WidthTypes;
|
||||
w: number | string;
|
||||
}
|
||||
|
||||
class TableWidthAttributes extends XmlAttributeComponent<ITableWidth> {
|
||||
protected xmlKeys = {type: "w:type", w: "w:w"};
|
||||
}
|
||||
|
||||
class PreferredTableWidth extends XmlComponent {
|
||||
constructor(type: WidthTypes, w: number | string) {
|
||||
super("w:tblW");
|
||||
this.root.push(new TableWidthAttributes({type, w}));
|
||||
}
|
||||
}
|
||||
|
||||
type TableLayoutOptions = "autofit" | "fixed";
|
||||
|
||||
class TableLayoutAttributes extends XmlAttributeComponent<{type: TableLayoutOptions}> {
|
||||
protected xmlKeys = {type: "w:type"};
|
||||
}
|
||||
|
||||
class TableLayout extends XmlComponent {
|
||||
constructor(type: TableLayoutOptions) {
|
||||
super("w:tblLayout");
|
||||
this.root.push(new TableLayoutAttributes({type}));
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { XmlAttributeComponent } from "./default-attributes";
|
||||
|
||||
interface IAttributesProperties {
|
||||
export interface IAttributesProperties {
|
||||
val?: string | number | boolean;
|
||||
color?: string;
|
||||
space?: string;
|
||||
@ -19,13 +19,11 @@ interface IAttributesProperties {
|
||||
footer?: string;
|
||||
gutter?: string;
|
||||
linePitch?: string;
|
||||
pos?: string;
|
||||
pos?: string | number; // Little strange. Perhaps it is normal. Need to clarify in the spec.
|
||||
}
|
||||
|
||||
export class Attributes extends XmlAttributeComponent {
|
||||
|
||||
constructor(properties?: IAttributesProperties) {
|
||||
super({
|
||||
export class Attributes extends XmlAttributeComponent<IAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
val: "w:val",
|
||||
color: "w:color",
|
||||
space: "w:space",
|
||||
@ -45,6 +43,5 @@ export class Attributes extends XmlAttributeComponent {
|
||||
gutter: "w:gutter",
|
||||
linePitch: "w:linePitch",
|
||||
pos: "w:pos",
|
||||
}, properties);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { IXmlableObject } from "./xmlable-object";
|
||||
|
||||
export abstract class BaseXmlComponent {
|
||||
protected rootKey: string;
|
||||
|
||||
@ -5,9 +7,5 @@ export abstract class BaseXmlComponent {
|
||||
this.rootKey = rootKey;
|
||||
}
|
||||
|
||||
public abstract replaceKey(): void;
|
||||
|
||||
public clearVariables(): void {
|
||||
// Do Nothing
|
||||
}
|
||||
public abstract prepForXml(): IXmlableObject;
|
||||
}
|
||||
|
@ -1,30 +1,26 @@
|
||||
import * as _ from "lodash";
|
||||
import { BaseXmlComponent } from "./base";
|
||||
import { IXmlableObject } from "./xmlable-object";
|
||||
|
||||
export abstract class XmlAttributeComponent extends BaseXmlComponent {
|
||||
protected root: Object;
|
||||
private xmlKeys: Object;
|
||||
export type AttributeMap<T> = {[P in keyof T]: string};
|
||||
|
||||
constructor(xmlKeys: Object, properties: Object) {
|
||||
export abstract class XmlAttributeComponent<T> extends BaseXmlComponent {
|
||||
protected root: T;
|
||||
protected xmlKeys: AttributeMap<T>;
|
||||
|
||||
constructor(properties: T) {
|
||||
super("_attr");
|
||||
this.xmlKeys = xmlKeys;
|
||||
|
||||
this.root = properties;
|
||||
|
||||
if (!properties) {
|
||||
this.root = {};
|
||||
}
|
||||
}
|
||||
|
||||
public replaceKey(): void {
|
||||
if (this.root !== undefined) {
|
||||
_.forOwn(this.root, (value, key) => {
|
||||
public prepForXml(): IXmlableObject {
|
||||
const attrs = {};
|
||||
Object.keys(this.root).forEach((key) => {
|
||||
const value = this.root[key];
|
||||
if (value !== undefined) {
|
||||
const newKey = this.xmlKeys[key];
|
||||
this.root[newKey] = value;
|
||||
delete this.root[key];
|
||||
attrs[newKey] = value;
|
||||
}
|
||||
});
|
||||
this[this.rootKey] = this.root;
|
||||
delete this.root;
|
||||
}
|
||||
return {_attr: attrs};
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,27 @@
|
||||
import * as _ from "lodash";
|
||||
import { BaseXmlComponent } from "./base";
|
||||
import { IXmlableObject } from "./xmlable-object";
|
||||
export { BaseXmlComponent };
|
||||
|
||||
export abstract class XmlComponent extends BaseXmlComponent {
|
||||
protected root: BaseXmlComponent[];
|
||||
protected root: Array<BaseXmlComponent | string>;
|
||||
|
||||
constructor(rootKey: string) {
|
||||
super(rootKey);
|
||||
this.root = new Array<BaseXmlComponent>();
|
||||
}
|
||||
|
||||
public replaceKey(): void {
|
||||
// console.log(this.rootKey);
|
||||
// console.log(this.root);
|
||||
if (this.root !== undefined) {
|
||||
this.root.forEach((root) => {
|
||||
if (root && root instanceof BaseXmlComponent) {
|
||||
root.replaceKey();
|
||||
}
|
||||
});
|
||||
this[this.rootKey] = this.root;
|
||||
delete this.root;
|
||||
public prepForXml(): IXmlableObject {
|
||||
const children = this.root.map((comp) => {
|
||||
if (comp instanceof BaseXmlComponent) {
|
||||
return comp.prepForXml();
|
||||
}
|
||||
return comp;
|
||||
}).filter((comp) => comp); // Exclude null, undefined, and empty strings
|
||||
return {
|
||||
[this.rootKey]: children,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export * from "./attributes"
|
||||
export * from "./attributes";
|
||||
export * from "./default-attributes";
|
||||
export * from "./unit";
|
||||
export * from "./property";
|
||||
|
@ -1,57 +0,0 @@
|
||||
import { ParagraphProperties } from "../paragraph/properties";
|
||||
import { RunProperties } from "../run/properties";
|
||||
import { XmlComponent } from "./";
|
||||
|
||||
export class ParagraphPropertyXmlComponent extends XmlComponent {
|
||||
private paragraphProperties: ParagraphProperties;
|
||||
|
||||
constructor(rootKey: string) {
|
||||
super(rootKey);
|
||||
this.paragraphProperties = new ParagraphProperties();
|
||||
this.root.push(this.paragraphProperties);
|
||||
}
|
||||
|
||||
public clearVariables(): void {
|
||||
this.paragraphProperties.clearVariables();
|
||||
|
||||
delete this.paragraphProperties;
|
||||
}
|
||||
}
|
||||
|
||||
export class RunPropertyXmlComponent extends XmlComponent {
|
||||
private runProperties: RunProperties;
|
||||
|
||||
constructor(rootKey: string) {
|
||||
super(rootKey);
|
||||
this.runProperties = new RunProperties();
|
||||
this.root.push(this.runProperties);
|
||||
}
|
||||
|
||||
public clearVariables(): void {
|
||||
this.runProperties.clearVariables();
|
||||
|
||||
delete this.runProperties;
|
||||
}
|
||||
}
|
||||
|
||||
export class MultiPropertyXmlComponent extends XmlComponent {
|
||||
private runProperties: RunProperties;
|
||||
private paragraphProperties: ParagraphProperties;
|
||||
|
||||
constructor(rootKey: string) {
|
||||
super(rootKey);
|
||||
this.runProperties = new RunProperties();
|
||||
this.root.push(this.runProperties);
|
||||
|
||||
this.paragraphProperties = new ParagraphProperties();
|
||||
this.root.push(this.paragraphProperties);
|
||||
}
|
||||
|
||||
public clearVariables(): void {
|
||||
this.runProperties.clearVariables();
|
||||
this.paragraphProperties.clearVariables();
|
||||
|
||||
delete this.runProperties;
|
||||
delete this.paragraphProperties;
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import {BaseXmlComponent} from "./base";
|
||||
|
||||
export abstract class XmlUnitComponent extends BaseXmlComponent {
|
||||
protected root: string;
|
||||
|
||||
constructor(rootKey: string) {
|
||||
super(rootKey);
|
||||
}
|
||||
|
||||
public replaceKey(): void {
|
||||
if (this.root !== undefined) {
|
||||
this[this.rootKey] = this.root;
|
||||
delete this.root;
|
||||
}
|
||||
}
|
||||
}
|
3
ts/docx/xml-components/xmlable-object.ts
Normal file
3
ts/docx/xml-components/xmlable-object.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface IXmlableObject extends Object {
|
||||
_attr?: { [key: string]: (string | number | boolean) };
|
||||
}
|
@ -1,52 +1,8 @@
|
||||
import * as _ from "lodash";
|
||||
import {XmlComponent} from "../docx/xml-components";
|
||||
import { BaseXmlComponent } from "../docx/xml-components";
|
||||
import { IXmlableObject } from "../docx/xml-components/xmlable-object";
|
||||
|
||||
export class Formatter {
|
||||
|
||||
public format(input: any): Object {
|
||||
input.clearVariables();
|
||||
this.replaceKeys(input);
|
||||
const newJson = this.clense(input);
|
||||
// console.log(JSON.stringify(newJson, null, " "));
|
||||
return newJson;
|
||||
public format(input: BaseXmlComponent): IXmlableObject {
|
||||
return input.prepForXml();
|
||||
}
|
||||
|
||||
private replaceKeys(input: XmlComponent): Object {
|
||||
input.replaceKey();
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private clense(input: any): Object {
|
||||
const newJson = this.jsonify(input);
|
||||
|
||||
this.deepTraverseJson(newJson, (parent, value, key) => {
|
||||
if (key === "properties") {
|
||||
delete parent[key];
|
||||
}
|
||||
if (key === "xmlKeys") {
|
||||
delete parent[key];
|
||||
}
|
||||
if (key === "rootKey") {
|
||||
delete parent[key];
|
||||
}
|
||||
});
|
||||
|
||||
return newJson;
|
||||
}
|
||||
|
||||
private jsonify(obj: Object): Object {
|
||||
let stringifiedJson = JSON.stringify(obj);
|
||||
return JSON.parse(stringifiedJson);
|
||||
}
|
||||
|
||||
private deepTraverseJson(json: Object, lambda: (json: any, value: any, key: any) => void): void {
|
||||
_.forOwn(json, (value, key) => {
|
||||
if (_.isObject(value) && key !== "xmlKeys" && key !== "rootKey") {
|
||||
this.deepTraverseJson(value, lambda);
|
||||
}
|
||||
lambda(json, value, key);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
export { LocalPacker } from "./packer/local";
|
||||
export { ExpressPacker } from "./packer/express";
|
||||
export { Packer } from "./packer/packer";
|
||||
|
@ -1,16 +1,16 @@
|
||||
import * as express from "express";
|
||||
import * as fs from "fs";
|
||||
import { Document } from "../../docx/document";
|
||||
import { Media } from "../../media";
|
||||
import { Numbering } from "../../numbering";
|
||||
import { Properties } from "../../properties";
|
||||
import { Styles } from "../../styles";
|
||||
import { Packer } from "./packer";
|
||||
|
||||
|
||||
export class ExpressPacker extends Packer {
|
||||
private res: express.Response;
|
||||
|
||||
constructor(document: Document, res: express.Response, styles?: any, properties?: Properties, numbering?: Numbering) {
|
||||
super(document, styles, properties, numbering);
|
||||
constructor(document: Document, res: express.Response, styles?: Styles, properties?: Properties, numbering?: Numbering, media?: Media) {
|
||||
super(document, styles, properties, numbering, media);
|
||||
this.res = res;
|
||||
|
||||
this.res.on("close", () => {
|
||||
@ -19,7 +19,7 @@ export class ExpressPacker extends Packer {
|
||||
}
|
||||
|
||||
public pack(name: string): void {
|
||||
this.res.attachment(name + ".docx");
|
||||
super.pack(this.res);
|
||||
this.res.attachment(`${name}.docx`);
|
||||
super.compile(this.res);
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,21 @@
|
||||
import * as fs from "fs";
|
||||
import { Document } from "../../docx/document";
|
||||
import { Media } from "../../media";
|
||||
import { Numbering } from "../../numbering";
|
||||
import { Properties } from "../../properties";
|
||||
import { Styles } from "../../styles";
|
||||
import { Packer } from "./packer";
|
||||
|
||||
|
||||
export class LocalPacker extends Packer {
|
||||
private stream: fs.WriteStream;
|
||||
|
||||
constructor(document: Document, styles?: any, properties?: Properties, numbering?: Numbering) {
|
||||
super(document, styles, properties, numbering);
|
||||
constructor(document: Document, styles?: Styles, properties?: Properties, numbering?: Numbering, media?: Media) {
|
||||
super(document, styles, properties, numbering, media);
|
||||
}
|
||||
|
||||
public pack(path: string): void {
|
||||
this.stream = fs.createWriteStream(path);
|
||||
super.pack(this.stream);
|
||||
path = path.replace(/.docx$/, "");
|
||||
this.stream = fs.createWriteStream(`${path}.docx`);
|
||||
super.compile(this.stream);
|
||||
}
|
||||
}
|
||||
|
@ -1,46 +1,42 @@
|
||||
import * as archiver from "archiver";
|
||||
import * as express from "express";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as xml from "xml";
|
||||
import { Document } from "../../docx";
|
||||
import { Media } from "../../media";
|
||||
import { Numbering } from "../../numbering";
|
||||
import { Properties } from "../../properties";
|
||||
import { Styles } from "../../styles";
|
||||
import { DefaultStylesFactory } from "../../styles/factory";
|
||||
import { Formatter } from "../formatter";
|
||||
|
||||
const appRoot = require("app-root-path");
|
||||
const TEMPLATE_PATH = path.resolve(__dirname, "../../../template");
|
||||
|
||||
export abstract class Packer {
|
||||
protected archive: any;
|
||||
protected document: Document;
|
||||
protected archive: archiver.Archiver;
|
||||
private formatter: Formatter;
|
||||
private style: Styles;
|
||||
private properties: Properties;
|
||||
private numbering: Numbering;
|
||||
|
||||
constructor(document: Document, style?: any, properties?: Properties, numbering?: Numbering) {
|
||||
this.formatter = new Formatter();
|
||||
this.document = document;
|
||||
this.style = style;
|
||||
this.properties = properties;
|
||||
this.numbering = numbering;
|
||||
this.archive = archiver.create("zip", {});
|
||||
|
||||
if (!style) {
|
||||
const stylesFactory = new DefaultStylesFactory();
|
||||
this.style = stylesFactory.newInstance();
|
||||
}
|
||||
|
||||
if (!properties) {
|
||||
this.properties = new Properties({
|
||||
constructor(
|
||||
protected document: Document,
|
||||
style?: Styles,
|
||||
private properties: Properties = new Properties({
|
||||
creator: "Un-named",
|
||||
revision: "1",
|
||||
lastModifiedBy: "Un-named",
|
||||
});
|
||||
}
|
||||
}),
|
||||
private numbering: Numbering = new Numbering(),
|
||||
private media: Media = new Media(),
|
||||
) {
|
||||
this.formatter = new Formatter();
|
||||
this.archive = archiver.create("zip", {});
|
||||
|
||||
if (!numbering) {
|
||||
this.numbering = new Numbering();
|
||||
if (style) {
|
||||
this.style = style;
|
||||
} else {
|
||||
const stylesFactory = new DefaultStylesFactory();
|
||||
this.style = stylesFactory.newInstance();
|
||||
}
|
||||
|
||||
this.archive.on("error", (err) => {
|
||||
@ -48,33 +44,26 @@ export abstract class Packer {
|
||||
});
|
||||
}
|
||||
|
||||
public pack(output: any): void {
|
||||
protected compile(output: fs.WriteStream | express.Response): void {
|
||||
this.archive.pipe(output);
|
||||
console.log(appRoot.path + "/template");
|
||||
this.archive.glob("**", {
|
||||
expand: true,
|
||||
cwd: appRoot.path + "/template",
|
||||
cwd: TEMPLATE_PATH,
|
||||
});
|
||||
|
||||
this.archive.glob("**/.rels", {
|
||||
expand: true,
|
||||
cwd: appRoot.path + "/template",
|
||||
cwd: TEMPLATE_PATH,
|
||||
});
|
||||
|
||||
// this.archive.file(appRoot.path + "/template/[Content_Types].xml", { name: "[Content_Types].xml" });
|
||||
// console.log(__dirname + "/packer.js");
|
||||
// this.archive.file(__dirname + "/packer.js", { name: "/[Content_Types].xml" });
|
||||
|
||||
/*this.archive.directory(appRoot.path + "/template", {
|
||||
name: "/root/g.txt",
|
||||
prefix: "root"
|
||||
});*/
|
||||
const xmlDocument = xml(this.formatter.format(this.document));
|
||||
const xmlStyles = xml(this.formatter.format(this.style));
|
||||
const xmlProperties = xml(this.formatter.format(this.properties), { declaration: { standalone: "yes", encoding: "UTF-8" } });
|
||||
const xmlProperties = xml(this.formatter.format(this.properties), {
|
||||
declaration: {
|
||||
standalone: "yes",
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
});
|
||||
const xmlNumbering = xml(this.formatter.format(this.numbering));
|
||||
// console.log(JSON.stringify(this.numbering, null, " "));
|
||||
console.log(xmlNumbering);
|
||||
|
||||
this.archive.append(xmlDocument, {
|
||||
name: "word/document.xml",
|
||||
});
|
||||
@ -91,6 +80,12 @@ export abstract class Packer {
|
||||
name: "word/numbering.xml",
|
||||
});
|
||||
|
||||
for (const data of this.media.array) {
|
||||
this.archive.append(data.stream, {
|
||||
name: `media/${data.fileName}`,
|
||||
});
|
||||
}
|
||||
|
||||
this.archive.finalize();
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
export * from "./docx";
|
||||
export * from "./export";
|
||||
export { Numbering } from "./numbering";
|
||||
export { Styles } from "./styles";
|
||||
export { Media } from "./media";
|
||||
export * from "./export";
|
||||
|
8
ts/media/data.ts
Normal file
8
ts/media/data.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import * as fs from "fs";
|
||||
|
||||
export interface IData {
|
||||
referenceId: number;
|
||||
stream: fs.ReadStream;
|
||||
path: string;
|
||||
fileName: string;
|
||||
}
|
40
ts/media/index.ts
Normal file
40
ts/media/index.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { IData } from "./data";
|
||||
|
||||
export class Media {
|
||||
private map: Map<string, IData>;
|
||||
|
||||
constructor() {
|
||||
this.map = new Map<string, IData>();
|
||||
}
|
||||
|
||||
public getMedia(key: string): IData {
|
||||
const data = this.map.get(key);
|
||||
|
||||
if (data === undefined) {
|
||||
throw new Error(`Cannot find image with the key ${key}`);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public addMedia(key: string, filePath: string): void {
|
||||
this.map.set(key, {
|
||||
referenceId: this.map.values.length,
|
||||
stream: fs.createReadStream(filePath),
|
||||
path: filePath,
|
||||
fileName: path.basename(filePath),
|
||||
});
|
||||
}
|
||||
|
||||
public get array(): IData[] {
|
||||
const array = new Array<IData>();
|
||||
|
||||
this.map.forEach((data) => {
|
||||
array.push(data);
|
||||
});
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
import * as _ from "lodash";
|
||||
import { XmlAttributeComponent, XmlComponent } from "../docx/xml-components";
|
||||
import { Level } from "./level";
|
||||
import { MultiLevelType } from "./multi-level-type";
|
||||
@ -8,14 +7,11 @@ interface IAbstractNumberingAttributesProperties {
|
||||
restartNumberingAfterBreak?: number;
|
||||
}
|
||||
|
||||
class AbstractNumberingAttributes extends XmlAttributeComponent {
|
||||
|
||||
constructor(properties: IAbstractNumberingAttributesProperties) {
|
||||
super({
|
||||
class AbstractNumberingAttributes extends XmlAttributeComponent<IAbstractNumberingAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
abstractNumId: "w:abstractNumId",
|
||||
restartNumberingAfterBreak: "w15:restartNumberingAfterBreak",
|
||||
}, properties);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class AbstractNumbering extends XmlComponent {
|
||||
@ -40,11 +36,4 @@ export class AbstractNumbering extends XmlComponent {
|
||||
this.addLevel(level);
|
||||
return level;
|
||||
}
|
||||
|
||||
public clearVariables(): void {
|
||||
_.forEach(this.root, (element) => {
|
||||
element.clearVariables();
|
||||
});
|
||||
delete this.id;
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../docx/xml-components";
|
||||
|
||||
interface IndentAttributesProperties {
|
||||
left: number;
|
||||
hanging: number;
|
||||
}
|
||||
|
||||
class IndentAttributes extends XmlAttributeComponent {
|
||||
|
||||
constructor(properties: IndentAttributesProperties) {
|
||||
super({
|
||||
left: "w:left",
|
||||
hanging: "w:hanging",
|
||||
}, properties);
|
||||
}
|
||||
}
|
||||
|
||||
export class Indent extends XmlComponent {
|
||||
|
||||
constructor(left: number, hanging: number) {
|
||||
super("w:ind");
|
||||
this.root.push(new IndentAttributes({
|
||||
left: left,
|
||||
hanging: hanging,
|
||||
}));
|
||||
}
|
||||
}
|
@ -1,13 +1,11 @@
|
||||
import * as _ from "lodash";
|
||||
import { DocumentAttributes } from "../docx/document/document-attributes";
|
||||
import { Indent } from "../docx/paragraph/indent";
|
||||
import { RunFonts } from "../docx/run/run-fonts";
|
||||
import { MultiPropertyXmlComponent } from "../docx/xml-components";
|
||||
import { XmlComponent } from "../docx/xml-components";
|
||||
import { AbstractNumbering } from "./abstract-numbering";
|
||||
import { Indent } from "./indent";
|
||||
import { Level } from "./level";
|
||||
import { Num } from "./num";
|
||||
|
||||
export class Numbering extends MultiPropertyXmlComponent {
|
||||
export class Numbering extends XmlComponent {
|
||||
private nextId: number;
|
||||
|
||||
constructor() {
|
||||
@ -86,12 +84,4 @@ export class Numbering extends MultiPropertyXmlComponent {
|
||||
this.root.push(num);
|
||||
return num;
|
||||
}
|
||||
|
||||
public clearVariables(): void {
|
||||
super.clearVariables();
|
||||
_.forEach(this.root, (element) => {
|
||||
element.clearVariables();
|
||||
});
|
||||
delete this.nextId;
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,19 @@
|
||||
import * as paragraph from "../docx/paragraph/formatting";
|
||||
import { ParagraphProperties } from "../docx/paragraph/properties";
|
||||
import * as formatting from "../docx/run/formatting";
|
||||
import { RunProperties } from "../docx/run/properties";
|
||||
import { Attributes, MultiPropertyXmlComponent, XmlAttributeComponent, XmlComponent } from "../docx/xml-components";
|
||||
import { Attributes, XmlAttributeComponent, XmlComponent } from "../docx/xml-components";
|
||||
|
||||
interface ILevelAttributesProperties {
|
||||
ilvl?: number;
|
||||
tentative?: number;
|
||||
}
|
||||
|
||||
class LevelAttributes extends XmlAttributeComponent {
|
||||
|
||||
constructor(properties: ILevelAttributesProperties) {
|
||||
super({
|
||||
class LevelAttributes extends XmlAttributeComponent<ILevelAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
ilvl: "w:ilvl",
|
||||
tentative: "w15:tentative",
|
||||
}, properties);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class Start extends XmlComponent {
|
||||
@ -57,21 +56,29 @@ class LevelJc extends XmlComponent {
|
||||
}
|
||||
}
|
||||
|
||||
export class Level extends XmlComponent {
|
||||
export class LevelBase extends XmlComponent {
|
||||
private paragraphProperties: ParagraphProperties;
|
||||
private runProperties: RunProperties;
|
||||
|
||||
constructor(level: number, numberFormat: string, levelText: string, lvlJc: string) {
|
||||
constructor(level: number, start?: number, numberFormat?: string, levelText?: string, lvlJc?: string) {
|
||||
super("w:lvl");
|
||||
this.root.push(new LevelAttributes({
|
||||
ilvl: level,
|
||||
tentative: 1,
|
||||
}));
|
||||
|
||||
this.root.push(new Start(1));
|
||||
if (start !== undefined) {
|
||||
this.root.push(new Start(start));
|
||||
}
|
||||
if (numberFormat !== undefined) {
|
||||
this.root.push(new NumberFormat(numberFormat));
|
||||
}
|
||||
if (levelText !== undefined) {
|
||||
this.root.push(new LevelText(levelText));
|
||||
}
|
||||
if (lvlJc !== undefined) {
|
||||
this.root.push(new LevelJc(lvlJc));
|
||||
}
|
||||
|
||||
this.paragraphProperties = new ParagraphProperties();
|
||||
this.runProperties = new RunProperties();
|
||||
@ -80,14 +87,6 @@ export class Level extends XmlComponent {
|
||||
this.root.push(this.runProperties);
|
||||
}
|
||||
|
||||
public clearVariables(): void {
|
||||
this.paragraphProperties.clearVariables();
|
||||
this.runProperties.clearVariables();
|
||||
|
||||
delete this.paragraphProperties;
|
||||
delete this.runProperties;
|
||||
}
|
||||
|
||||
public addParagraphProperty(property: XmlComponent): Level {
|
||||
this.paragraphProperties.push(property);
|
||||
return this;
|
||||
@ -97,4 +96,133 @@ export class Level extends XmlComponent {
|
||||
this.runProperties.push(property);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ---------- Run formatting ---------------------- //
|
||||
|
||||
public size(twips: number): Level {
|
||||
this.addRunProperty(new formatting.Size(twips));
|
||||
return this;
|
||||
}
|
||||
|
||||
public bold(): Level {
|
||||
this.addRunProperty(new formatting.Bold());
|
||||
return this;
|
||||
}
|
||||
|
||||
public italics(): Level {
|
||||
this.addRunProperty(new formatting.Italics());
|
||||
return this;
|
||||
}
|
||||
|
||||
public smallCaps(): Level {
|
||||
this.addRunProperty(new formatting.SmallCaps());
|
||||
return this;
|
||||
}
|
||||
|
||||
public allCaps(): Level {
|
||||
this.addRunProperty(new formatting.Caps());
|
||||
return this;
|
||||
}
|
||||
|
||||
public strike(): Level {
|
||||
this.addRunProperty(new formatting.Strike());
|
||||
return this;
|
||||
}
|
||||
|
||||
public doubleStrike(): Level {
|
||||
this.addRunProperty(new formatting.DoubleStrike());
|
||||
return this;
|
||||
}
|
||||
|
||||
public subScript(): Level {
|
||||
this.addRunProperty(new formatting.SubScript());
|
||||
return this;
|
||||
}
|
||||
|
||||
public superScript(): Level {
|
||||
this.addRunProperty(new formatting.SuperScript());
|
||||
return this;
|
||||
}
|
||||
|
||||
public underline(underlineType?: string, color?: string): Level {
|
||||
this.addRunProperty(new formatting.Underline(underlineType, color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public color(color: string): Level {
|
||||
this.addRunProperty(new formatting.Color(color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public font(fontName: string): Level {
|
||||
this.addRunProperty(new formatting.RunFonts(fontName));
|
||||
return this;
|
||||
}
|
||||
|
||||
// --------------------- Paragraph formatting ------------------------ //
|
||||
|
||||
public center(): Level {
|
||||
this.addParagraphProperty(new paragraph.Alignment("center"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public left(): Level {
|
||||
this.addParagraphProperty(new paragraph.Alignment("left"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public right(): Level {
|
||||
this.addParagraphProperty(new paragraph.Alignment("right"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public justified(): Level {
|
||||
this.addParagraphProperty(new paragraph.Alignment("both"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public thematicBreak(): Level {
|
||||
this.addParagraphProperty(new paragraph.ThematicBreak());
|
||||
return this;
|
||||
}
|
||||
|
||||
public maxRightTabStop(): Level {
|
||||
this.addParagraphProperty(new paragraph.MaxRightTabStop());
|
||||
return this;
|
||||
}
|
||||
|
||||
public leftTabStop(position: number): Level {
|
||||
this.addParagraphProperty(new paragraph.LeftTabStop(position));
|
||||
return this;
|
||||
}
|
||||
|
||||
public indent(left: number, hanging?: number): Level {
|
||||
this.addParagraphProperty(new paragraph.Indent(left, hanging));
|
||||
return this;
|
||||
}
|
||||
|
||||
public spacing(params: paragraph.ISpacingProperties): Level {
|
||||
this.addParagraphProperty(new paragraph.Spacing(params));
|
||||
return this;
|
||||
}
|
||||
|
||||
public keepNext(): Level {
|
||||
this.addParagraphProperty(new paragraph.KeepNext());
|
||||
return this;
|
||||
}
|
||||
|
||||
public keepLines(): Level {
|
||||
this.addParagraphProperty(new paragraph.KeepLines());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class Level extends LevelBase {
|
||||
// This is the level that sits under abstractNum. We make a
|
||||
// handful of properties required
|
||||
constructor(level: number, numberFormat: string, levelText: string, lvlJc: string) {
|
||||
super(level, 1, numberFormat, levelText, lvlJc);
|
||||
}
|
||||
}
|
||||
|
||||
export class LevelForOverride extends LevelBase {}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Attributes, XmlAttributeComponent, XmlComponent } from "../docx/xml-components";
|
||||
import { LevelForOverride } from "./level";
|
||||
|
||||
class AbstractNumId extends XmlComponent {
|
||||
|
||||
@ -14,13 +15,8 @@ interface INumAttributesProperties {
|
||||
numId: number;
|
||||
}
|
||||
|
||||
class NumAttributes extends XmlAttributeComponent {
|
||||
|
||||
constructor(properties: INumAttributesProperties) {
|
||||
super({
|
||||
numId: "w:numId",
|
||||
}, properties);
|
||||
}
|
||||
class NumAttributes extends XmlAttributeComponent<INumAttributesProperties> {
|
||||
protected xmlKeys = {numId: "w:numId"};
|
||||
}
|
||||
|
||||
export class Num extends XmlComponent {
|
||||
@ -35,8 +31,50 @@ export class Num extends XmlComponent {
|
||||
this.id = numId;
|
||||
}
|
||||
|
||||
public clearVariables(): void {
|
||||
super.clearVariables();
|
||||
delete this.id;
|
||||
public overrideLevel(num: number, start?: number): LevelOverride {
|
||||
const olvl = new LevelOverride(num, start);
|
||||
this.root.push(olvl);
|
||||
return olvl;
|
||||
}
|
||||
}
|
||||
|
||||
class LevelOverrideAttributes extends XmlAttributeComponent<{ilvl: number}> {
|
||||
protected xmlKeys = {ilvl: "w:ilvl"};
|
||||
}
|
||||
|
||||
export class LevelOverride extends XmlComponent {
|
||||
private levelNum: number;
|
||||
private lvl?: LevelForOverride;
|
||||
|
||||
constructor(levelNum: number, start?: number) {
|
||||
super("w:lvlOverride");
|
||||
this.root.push(new LevelOverrideAttributes({ilvl: levelNum}));
|
||||
if (start !== undefined) {
|
||||
this.root.push(new StartOverride(start));
|
||||
}
|
||||
this.levelNum = levelNum;
|
||||
}
|
||||
|
||||
get level(): LevelForOverride {
|
||||
let lvl: LevelForOverride;
|
||||
if (!this.lvl) {
|
||||
lvl = new LevelForOverride(this.levelNum);
|
||||
this.root.push(lvl);
|
||||
this.lvl = lvl;
|
||||
} else {
|
||||
lvl = this.lvl;
|
||||
}
|
||||
return lvl;
|
||||
}
|
||||
}
|
||||
|
||||
class StartOverrideAttributes extends XmlAttributeComponent<{val: number}> {
|
||||
protected xmlKeys = {val: "w:val"};
|
||||
}
|
||||
|
||||
class StartOverride extends XmlComponent {
|
||||
constructor(start: number) {
|
||||
super("w:startOverride");
|
||||
this.root.push(new StartOverrideAttributes({val: start}));
|
||||
}
|
||||
}
|
||||
|
@ -1,66 +1,64 @@
|
||||
import { DocumentAttributes } from "../docx/document/document-attributes";
|
||||
import { XmlUnitComponent } from "../docx/xml-components";
|
||||
import { XmlComponent } from "../docx/xml-components";
|
||||
|
||||
export class Title extends XmlUnitComponent {
|
||||
export class Title extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("dc:title");
|
||||
this.root = value;
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Subject extends XmlUnitComponent {
|
||||
export class Subject extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("dc:subject");
|
||||
this.root = value;
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Creator extends XmlUnitComponent {
|
||||
export class Creator extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("dc:creator");
|
||||
this.root = value;
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Keywords extends XmlUnitComponent {
|
||||
export class Keywords extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("cp:keywords");
|
||||
this.root = value;
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Description extends XmlUnitComponent {
|
||||
export class Description extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("dc:description");
|
||||
this.root = value;
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class LastModifiedBy extends XmlUnitComponent {
|
||||
export class LastModifiedBy extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("cp:lastModifiedBy");
|
||||
this.root = value;
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Revision extends XmlUnitComponent {
|
||||
export class Revision extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("cp:revision");
|
||||
const revision = value;
|
||||
this.root = value;
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DateComponent extends XmlComponent {
|
||||
protected getCurrentDate(): any {
|
||||
export abstract class DateComponent extends XmlComponent {
|
||||
protected getCurrentDate(): string {
|
||||
const date = new Date();
|
||||
const year = date.getFullYear();
|
||||
const month = ("0" + (date.getMonth() + 1)).slice(-2);
|
||||
|
@ -2,7 +2,7 @@ import { DocumentAttributes } from "../docx/document/document-attributes";
|
||||
import { XmlComponent } from "../docx/xml-components";
|
||||
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
|
||||
|
||||
interface IPropertiesOptions {
|
||||
export interface IPropertiesOptions {
|
||||
title?: string;
|
||||
subject?: string;
|
||||
creator?: string;
|
||||
@ -23,13 +23,27 @@ export class Properties extends XmlComponent {
|
||||
dcmitype: "http://purl.org/dc/dcmitype/",
|
||||
xsi: "http://www.w3.org/2001/XMLSchema-instance",
|
||||
}));
|
||||
if (options.title) {
|
||||
this.root.push(new Title(options.title));
|
||||
}
|
||||
if (options.subject) {
|
||||
this.root.push(new Subject(options.subject));
|
||||
}
|
||||
if (options.creator) {
|
||||
this.root.push(new Creator(options.creator));
|
||||
}
|
||||
if (options.keywords) {
|
||||
this.root.push(new Keywords(options.keywords));
|
||||
}
|
||||
if (options.description) {
|
||||
this.root.push(new Description(options.description));
|
||||
}
|
||||
if (options.lastModifiedBy) {
|
||||
this.root.push(new LastModifiedBy(options.lastModifiedBy));
|
||||
}
|
||||
if (options.revision) {
|
||||
this.root.push(new Revision(options.revision));
|
||||
}
|
||||
this.root.push(new Created());
|
||||
this.root.push(new Modified());
|
||||
}
|
||||
|
11
ts/relationships/attributes.ts
Normal file
11
ts/relationships/attributes.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { XmlAttributeComponent } from "../docx/xml-components";
|
||||
|
||||
export interface IRelationshipsAttributesProperties {
|
||||
xmlns: string;
|
||||
}
|
||||
|
||||
export class RelationshipsAttributes extends XmlAttributeComponent<IRelationshipsAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
xmlns: "xmlns",
|
||||
};
|
||||
}
|
14
ts/relationships/index.ts
Normal file
14
ts/relationships/index.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { XmlComponent } from "../docx/xml-components";
|
||||
import { RelationshipsAttributes } from "./attributes";
|
||||
|
||||
export class Relationships extends XmlComponent {
|
||||
|
||||
constructor() {
|
||||
super("Relationships");
|
||||
this.root.push(new RelationshipsAttributes({
|
||||
xmlns: "http://schemas.openxmlformats.org/package/2006/relationships",
|
||||
}));
|
||||
|
||||
// this.root.push(new Created());
|
||||
}
|
||||
}
|
0
ts/relationships/relationship.ts
Normal file
0
ts/relationships/relationship.ts
Normal file
@ -14,11 +14,4 @@ export class DocumentDefaults extends XmlComponent {
|
||||
this.root.push(this.runPropertiesDefaults);
|
||||
this.root.push(this.paragraphPropertiesDefaults);
|
||||
}
|
||||
|
||||
clearVariables(): void {
|
||||
this.runPropertiesDefaults.clearVariables();
|
||||
this.paragraphPropertiesDefaults.clearVariables();
|
||||
delete this.runPropertiesDefaults;
|
||||
delete this.paragraphPropertiesDefaults;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import {XmlComponent} from "../../docx/xml-components";
|
||||
import { ParagraphProperties } from "../../docx/paragraph/properties";
|
||||
import { XmlComponent } from "../../docx/xml-components";
|
||||
|
||||
export class ParagraphPropertiesDefaults extends XmlComponent {
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {XmlComponent} from "../../docx/xml-components";
|
||||
import { RunProperties } from "../../docx/run/properties";
|
||||
import { XmlComponent } from "../../docx/xml-components";
|
||||
|
||||
export class RunPropertiesDefaults extends XmlComponent {
|
||||
|
||||
|
@ -1,56 +1,54 @@
|
||||
import { Color, Italics, Size } from "../docx/run/formatting";
|
||||
|
||||
import { Styles } from "./";
|
||||
import { DocumentDefaults } from "./defaults";
|
||||
import {ParagraphPropertiesDefaults} from "./defaults/paragraph-properties";
|
||||
import {RunPropertiesDefaults} from "./defaults/run-properties";
|
||||
import {Heading1Style, Heading2Style, TitleStyle, Heading3Style, Heading4Style, Heading5Style, Heading6Style, ListParagraph} from "./style";
|
||||
// import {StyleAttributes} from "./style/attributes";
|
||||
import {ParagraphProperties} from "../docx/paragraph/properties";
|
||||
import {RunProperties} from "../docx/run/properties";
|
||||
import {Color, Size, Italics} from "../docx/run/formatting";
|
||||
import {
|
||||
Heading1Style, Heading2Style, Heading3Style, Heading4Style, Heading5Style, Heading6Style,
|
||||
ListParagraph, TitleStyle,
|
||||
} from "./style";
|
||||
|
||||
export class DefaultStylesFactory {
|
||||
|
||||
newInstance(): Styles {
|
||||
let styles = new Styles();
|
||||
public newInstance(): Styles {
|
||||
const styles = new Styles();
|
||||
styles.push(new DocumentDefaults());
|
||||
|
||||
let titleStyle = new TitleStyle();
|
||||
const titleStyle = new TitleStyle();
|
||||
titleStyle.addRunProperty(new Size(56));
|
||||
styles.push(titleStyle);
|
||||
|
||||
let heading1Style = new Heading1Style();
|
||||
const heading1Style = new Heading1Style();
|
||||
heading1Style.addRunProperty(new Color("2E74B5"));
|
||||
heading1Style.addRunProperty(new Size(32));
|
||||
styles.push(heading1Style);
|
||||
|
||||
let heading2Style = new Heading2Style();
|
||||
const heading2Style = new Heading2Style();
|
||||
heading2Style.addRunProperty(new Color("2E74B5"));
|
||||
heading2Style.addRunProperty(new Size(26));
|
||||
styles.push(heading2Style);
|
||||
|
||||
let heading3Style = new Heading3Style();
|
||||
const heading3Style = new Heading3Style();
|
||||
heading3Style.addRunProperty(new Color("1F4D78"));
|
||||
heading3Style.addRunProperty(new Size(24));
|
||||
styles.push(heading3Style);
|
||||
|
||||
let heading4Style = new Heading4Style();
|
||||
const heading4Style = new Heading4Style();
|
||||
heading4Style.addRunProperty(new Color("2E74B5"));
|
||||
heading4Style.addRunProperty(new Italics());
|
||||
styles.push(heading4Style);
|
||||
|
||||
let heading5Style = new Heading5Style();
|
||||
const heading5Style = new Heading5Style();
|
||||
heading5Style.addRunProperty(new Color("2E74B5"));
|
||||
styles.push(heading5Style);
|
||||
|
||||
let heading6Style = new Heading6Style();
|
||||
const heading6Style = new Heading6Style();
|
||||
heading6Style.addRunProperty(new Color("1F4D78"));
|
||||
styles.push(heading6Style);
|
||||
|
||||
let listParagraph = new ListParagraph();
|
||||
const listParagraph = new ListParagraph();
|
||||
// listParagraph.addParagraphProperty();
|
||||
styles.push(listParagraph);
|
||||
|
||||
// console.log(JSON.stringify(styles, null, " "));
|
||||
return styles;
|
||||
}
|
||||
}
|
@ -1,9 +1,6 @@
|
||||
import {XmlComponent} from "../docx/xml-components";
|
||||
import { DocumentAttributes } from "../docx/document/document-attributes";
|
||||
import {DocumentDefaults} from "./defaults";
|
||||
import {LatentStyles} from "./latent-styles";
|
||||
import {LatentStyleException} from "./latent-styles/exceptions";
|
||||
import {LatentStyleExceptionAttributes} from "./latent-styles/exceptions/attributes";
|
||||
import { XmlComponent } from "../docx/xml-components";
|
||||
import { ParagraphStyle } from "./style";
|
||||
|
||||
export class Styles extends XmlComponent {
|
||||
|
||||
@ -15,7 +12,7 @@ export class Styles extends XmlComponent {
|
||||
w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||
w14: "http://schemas.microsoft.com/office/word/2010/wordml",
|
||||
w15: "http://schemas.microsoft.com/office/word/2012/wordml",
|
||||
Ignorable: "w14 w15"
|
||||
Ignorable: "w14 w15",
|
||||
}));
|
||||
// let latentStyles = new LatentStyles();
|
||||
// latentStyles.push(new LatentStyleException(new LatentStyleExceptionAttributes({
|
||||
@ -24,13 +21,14 @@ export class Styles extends XmlComponent {
|
||||
// this.root.push(latentStyles);
|
||||
}
|
||||
|
||||
push(style: XmlComponent): void {
|
||||
public push(style: XmlComponent): Styles {
|
||||
this.root.push(style);
|
||||
return this;
|
||||
}
|
||||
|
||||
clearVariables() {
|
||||
this.root.forEach(element => {
|
||||
element.clearVariables();
|
||||
});
|
||||
public createParagraphStyle(styleId: string, name?: string): ParagraphStyle {
|
||||
const para = new ParagraphStyle(styleId, name);
|
||||
this.push(para);
|
||||
return para;
|
||||
}
|
||||
}
|
27
ts/styles/latent-styles/exceptions.ts
Normal file
27
ts/styles/latent-styles/exceptions.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "../../docx/xml-components";
|
||||
|
||||
export interface ILatentStyleExceptionAttributesProperties {
|
||||
name?: string;
|
||||
uiPriority?: string;
|
||||
qFormat?: string;
|
||||
semiHidden?: string;
|
||||
unhideWhenUsed?: string;
|
||||
}
|
||||
|
||||
export class LatentStyleExceptionAttributes extends XmlAttributeComponent<ILatentStyleExceptionAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
name: "w:name",
|
||||
uiPriority: "w:uiPriority",
|
||||
qFormat: "w:qFormat",
|
||||
semiHidden: "w:semiHidden",
|
||||
unhideWhenUsed: "w:unhideWhenUsed",
|
||||
};
|
||||
}
|
||||
|
||||
export class LatentStyleException extends XmlComponent {
|
||||
|
||||
constructor(attributes: ILatentStyleExceptionAttributesProperties) {
|
||||
super("w:lsdException");
|
||||
this.root.push(new LatentStyleExceptionAttributes(attributes));
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
import {XmlComponent} from "../../../docx/xml-components";
|
||||
|
||||
interface LatentStyleExceptionAttributesProperties {
|
||||
name?: string;
|
||||
uiPriority?: string;
|
||||
qFormat?: string;
|
||||
semiHidden?: string;
|
||||
unhideWhenUsed?: string;
|
||||
}
|
||||
|
||||
export class LatentStyleExceptionAttributes extends XmlComponent {
|
||||
private _attr: Object;
|
||||
|
||||
xmlKeys = {
|
||||
name: "w:name",
|
||||
uiPriority: "w:uiPriority",
|
||||
qFormat: "w:qFormat",
|
||||
semiHidden: "w:semiHidden",
|
||||
unhideWhenUsed: "w:unhideWhenUsed"
|
||||
};
|
||||
|
||||
constructor(properties?: LatentStyleExceptionAttributesProperties) {
|
||||
super("_attr");
|
||||
this._attr = properties;
|
||||
|
||||
if (!properties) {
|
||||
this._attr = {};
|
||||
}
|
||||
this._attr["xmlKeys"] = this.xmlKeys;
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import {XmlComponent} from "../../../docx/xml-components";
|
||||
import {LatentStyleExceptionAttributes} from "./attributes";
|
||||
|
||||
export class LatentStyleException extends XmlComponent {
|
||||
|
||||
constructor(attributes: LatentStyleExceptionAttributes) {
|
||||
super("w:lsdException");
|
||||
this.root.push(attributes);
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ export class LatentStyles extends XmlComponent {
|
||||
super("w:latentStyles");
|
||||
}
|
||||
|
||||
push(latentException: LatentStyleException): void {
|
||||
public push(latentException: LatentStyleException): void {
|
||||
this.root.push(latentException);
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
import {XmlComponent} from "../../docx/xml-components";
|
||||
import {XmlAttributeComponent} from "../../docx/xml-components";
|
||||
|
||||
interface StyleAttributesProperties {
|
||||
type?: string;
|
||||
styleId?: string;
|
||||
default?: string;
|
||||
customStyle?: string;
|
||||
val?: string;
|
||||
}
|
||||
|
||||
export class StyleAttributes extends XmlAttributeComponent {
|
||||
private _attr: Object;
|
||||
|
||||
constructor(properties: StyleAttributesProperties) {
|
||||
super({
|
||||
type: "w:type",
|
||||
styleId: "w:styleId",
|
||||
default: "w:default",
|
||||
customStyle: "w:customStyle",
|
||||
val: "w:val"
|
||||
}, properties);
|
||||
}
|
||||
}
|
@ -1,13 +1,18 @@
|
||||
import {XmlComponent} from "../../docx/xml-components";
|
||||
import {StyleAttributes} from "./attributes";
|
||||
import { XmlAttributeComponent, XmlComponent } from "../../docx/xml-components";
|
||||
|
||||
interface IComponentAttributes {
|
||||
val: string;
|
||||
}
|
||||
|
||||
class ComponentAttributes extends XmlAttributeComponent<IComponentAttributes> {
|
||||
protected xmlKeys = {val: "w:val"};
|
||||
}
|
||||
|
||||
export class Name extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("w:name");
|
||||
this.root.push(new StyleAttributes({
|
||||
val: value
|
||||
}));
|
||||
this.root.push(new ComponentAttributes({val: value}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,9 +20,7 @@ export class BasedOn extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("w:basedOn");
|
||||
this.root.push(new StyleAttributes({
|
||||
val: value
|
||||
}));
|
||||
this.root.push(new ComponentAttributes({val: value}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,10 +28,7 @@ export class Next extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("w:next");
|
||||
this.root.push(new StyleAttributes({
|
||||
styleId: "1",
|
||||
val: value
|
||||
}));
|
||||
this.root.push(new ComponentAttributes({val: value}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,9 +36,7 @@ export class Link extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("w:link");
|
||||
this.root.push(new StyleAttributes({
|
||||
val: value
|
||||
}));
|
||||
this.root.push(new ComponentAttributes({val: value}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,9 +44,8 @@ export class UiPriority extends XmlComponent {
|
||||
|
||||
constructor(value: string) {
|
||||
super("w:uiPriority");
|
||||
this.root.push(new StyleAttributes({
|
||||
val: value
|
||||
}));
|
||||
// TODO: this value should be a ST_DecimalNumber
|
||||
this.root.push(new ComponentAttributes({val: value}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,63 +1,204 @@
|
||||
import {XmlComponent} from "../../docx/xml-components";
|
||||
import {StyleAttributes} from "./attributes";
|
||||
import {ParagraphProperties} from "../../docx/paragraph/properties";
|
||||
import * as paragraph from "../../docx/paragraph/formatting";
|
||||
import * as formatting from "../../docx/run/formatting";
|
||||
import { RunProperties } from "../../docx/run/properties";
|
||||
import {Name, BasedOn, Next, QuickFormat} from "./components";
|
||||
import { XmlAttributeComponent, XmlComponent } from "../../docx/xml-components";
|
||||
|
||||
import { BasedOn, Name, Next, QuickFormat } from "./components";
|
||||
|
||||
export interface IStyleAttributes {
|
||||
type?: string;
|
||||
styleId?: string;
|
||||
default?: boolean;
|
||||
customStyle?: string;
|
||||
}
|
||||
|
||||
class StyleAttributes extends XmlAttributeComponent<IStyleAttributes> {
|
||||
protected xmlKeys = {
|
||||
type: "w:type",
|
||||
styleId: "w:styleId",
|
||||
default: "w:default",
|
||||
customStyle: "w:customStyle",
|
||||
};
|
||||
}
|
||||
|
||||
export class Style extends XmlComponent {
|
||||
|
||||
constructor(attributes: StyleAttributes) {
|
||||
constructor(attributes: IStyleAttributes, name?: string) {
|
||||
super("w:style");
|
||||
this.root.push(attributes);
|
||||
this.root.push(new StyleAttributes(attributes));
|
||||
if (name) {
|
||||
this.root.push(new Name(name));
|
||||
}
|
||||
}
|
||||
|
||||
push(styleSegment: XmlComponent): void {
|
||||
public push(styleSegment: XmlComponent): void {
|
||||
this.root.push(styleSegment);
|
||||
}
|
||||
}
|
||||
|
||||
export class ParagraphStyle extends Style {
|
||||
|
||||
private paragraphProperties: ParagraphProperties;
|
||||
private paragraphProperties: paragraph.ParagraphProperties;
|
||||
private runProperties: RunProperties;
|
||||
|
||||
constructor(styleId: string) {
|
||||
|
||||
let attributes = new StyleAttributes({
|
||||
type: "paragraph",
|
||||
styleId: styleId
|
||||
});
|
||||
super(attributes);
|
||||
this.paragraphProperties = new ParagraphProperties();
|
||||
constructor(styleId: string, name?: string) {
|
||||
super({type: "paragraph", styleId: styleId}, name);
|
||||
this.paragraphProperties = new paragraph.ParagraphProperties();
|
||||
this.runProperties = new RunProperties();
|
||||
this.root.push(this.paragraphProperties);
|
||||
this.root.push(this.runProperties);
|
||||
}
|
||||
|
||||
clearVariables(): void {
|
||||
this.paragraphProperties.clearVariables();
|
||||
this.runProperties.clearVariables();
|
||||
delete this.paragraphProperties;
|
||||
delete this.runProperties;
|
||||
}
|
||||
|
||||
addParagraphProperty(property: XmlComponent): void {
|
||||
public addParagraphProperty(property: XmlComponent): void {
|
||||
this.paragraphProperties.push(property);
|
||||
}
|
||||
|
||||
addRunProperty(property: XmlComponent): void {
|
||||
public addRunProperty(property: XmlComponent): void {
|
||||
this.runProperties.push(property);
|
||||
}
|
||||
|
||||
public basedOn(parentId: string): ParagraphStyle {
|
||||
this.root.push(new BasedOn(parentId));
|
||||
return this;
|
||||
}
|
||||
|
||||
public quickFormat(): ParagraphStyle {
|
||||
this.root.push(new QuickFormat());
|
||||
return this;
|
||||
}
|
||||
|
||||
public next(nextId: string): ParagraphStyle {
|
||||
this.root.push(new Next(nextId));
|
||||
return this;
|
||||
}
|
||||
|
||||
// ---------- Run formatting ---------------------- //
|
||||
|
||||
public size(twips: number): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Size(twips));
|
||||
return this;
|
||||
}
|
||||
|
||||
public bold(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Bold());
|
||||
return this;
|
||||
}
|
||||
|
||||
public italics(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Italics());
|
||||
return this;
|
||||
}
|
||||
|
||||
public smallCaps(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.SmallCaps());
|
||||
return this;
|
||||
}
|
||||
|
||||
public allCaps(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Caps());
|
||||
return this;
|
||||
}
|
||||
|
||||
public strike(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Strike());
|
||||
return this;
|
||||
}
|
||||
|
||||
public doubleStrike(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.DoubleStrike());
|
||||
return this;
|
||||
}
|
||||
|
||||
public subScript(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.SubScript());
|
||||
return this;
|
||||
}
|
||||
|
||||
public superScript(): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.SuperScript());
|
||||
return this;
|
||||
}
|
||||
|
||||
public underline(underlineType?: string, color?: string): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Underline(underlineType, color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public color(color: string): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.Color(color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public font(fontName: string): ParagraphStyle {
|
||||
this.addRunProperty(new formatting.RunFonts(fontName));
|
||||
return this;
|
||||
}
|
||||
|
||||
// --------------------- Paragraph formatting ------------------------ //
|
||||
|
||||
public center(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Alignment("center"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public left(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Alignment("left"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public right(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Alignment("right"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public justified(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Alignment("both"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public thematicBreak(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.ThematicBreak());
|
||||
return this;
|
||||
}
|
||||
|
||||
public maxRightTabStop(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.MaxRightTabStop());
|
||||
return this;
|
||||
}
|
||||
|
||||
public leftTabStop(position: number): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.LeftTabStop(position));
|
||||
return this;
|
||||
}
|
||||
|
||||
public indent(left: number, hanging?: number): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Indent(left, hanging));
|
||||
return this;
|
||||
}
|
||||
|
||||
public spacing(params: paragraph.ISpacingProperties): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.Spacing(params));
|
||||
return this;
|
||||
}
|
||||
|
||||
public keepNext(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.KeepNext());
|
||||
return this;
|
||||
}
|
||||
|
||||
public keepLines(): ParagraphStyle {
|
||||
this.addParagraphProperty(new paragraph.KeepLines());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class HeadingStyle extends ParagraphStyle {
|
||||
|
||||
constructor(styleId: string, name: string) {
|
||||
super(styleId);
|
||||
this.root.push(new Name(name));
|
||||
this.root.push(new BasedOn("Normal"));
|
||||
this.root.push(new Next("Normal"));
|
||||
this.root.push(new QuickFormat());
|
||||
super(styleId, name);
|
||||
this.basedOn("Normal");
|
||||
this.next("Normal");
|
||||
this.quickFormat();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"strictNullChecks": true,
|
||||
"sourceMap": true,
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"outDir": "../build-tests",
|
||||
"sourceRoot": "./",
|
||||
"rootDir": "./",
|
||||
"module": "commonjs"
|
||||
}
|
||||
|
@ -1,19 +1,17 @@
|
||||
/* tslint:disable */
|
||||
import { assert } from "chai";
|
||||
|
||||
function jsonify(obj: Object) {
|
||||
let stringifiedJson = JSON.stringify(obj);
|
||||
return JSON.parse(stringifiedJson);
|
||||
}
|
||||
import { Utility } from "./utility";
|
||||
/* tslint:enable */
|
||||
|
||||
describe("", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
// TODO
|
||||
});
|
||||
|
||||
describe("#methodName()", () => {
|
||||
it("should ", () => {
|
||||
|
||||
// TODO
|
||||
});
|
||||
});
|
||||
});
|
@ -1,15 +1,11 @@
|
||||
import { Body } from "../../../docx/document/body";
|
||||
import { assert } from "chai";
|
||||
import { SectionProperties } from "../../../docx/document/body/section-properties";
|
||||
import { PageSize } from "../../../docx/document/body/page-size";
|
||||
import { PageMargin } from "../../../docx/document/body/page-margin";
|
||||
import { Body } from "../../../docx/document/body";
|
||||
import { Columns } from "../../../docx/document/body/columns";
|
||||
import { DocumentGrid } from "../../../docx/document/body/doc-grid";
|
||||
|
||||
function jsonify(obj: Object) {
|
||||
let stringifiedJson = JSON.stringify(obj);
|
||||
return JSON.parse(stringifiedJson);
|
||||
}
|
||||
import { PageMargin } from "../../../docx/document/body/page-margin";
|
||||
import { PageSize } from "../../../docx/document/body/page-size";
|
||||
import { SectionProperties } from "../../../docx/document/body/section-properties";
|
||||
import { Utility } from "../../utility";
|
||||
|
||||
describe("Body", () => {
|
||||
let body: Body;
|
||||
@ -26,27 +22,27 @@ describe("Body", () => {
|
||||
describe("#constructor()", () => {
|
||||
|
||||
it("should create the Section Properties", () => {
|
||||
let newJson = jsonify(body);
|
||||
const newJson = Utility.jsonify(body);
|
||||
assert.equal(newJson.root[0].rootKey, "w:sectPr");
|
||||
});
|
||||
|
||||
it("should create the Page Size", () => {
|
||||
let newJson = jsonify(body);
|
||||
const newJson = Utility.jsonify(body);
|
||||
assert.equal(newJson.root[1].rootKey, "w:pgSz");
|
||||
});
|
||||
|
||||
it("should create the Page Margin", () => {
|
||||
let newJson = jsonify(body);
|
||||
const newJson = Utility.jsonify(body);
|
||||
assert.equal(newJson.root[2].rootKey, "w:pgMar");
|
||||
});
|
||||
|
||||
it("should create the Columns", () => {
|
||||
let newJson = jsonify(body);
|
||||
const newJson = Utility.jsonify(body);
|
||||
assert.equal(newJson.root[3].rootKey, "w:cols");
|
||||
});
|
||||
|
||||
it("should create the Document Grid", () => {
|
||||
let newJson = jsonify(body);
|
||||
const newJson = Utility.jsonify(body);
|
||||
assert.equal(newJson.root[4].rootKey, "w:docGrid");
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { assert, expect } from "chai";
|
||||
import * as docx from "../../../docx";
|
||||
import { assert } from "chai";
|
||||
import { Formatter } from "../../../export/formatter";
|
||||
|
||||
describe("Document", () => {
|
||||
let document: docx.Document;
|
||||
@ -11,7 +12,7 @@ describe("Document", () => {
|
||||
describe("#constructor()", () => {
|
||||
|
||||
it("should create valid JSON", () => {
|
||||
let stringifiedJson = JSON.stringify(document);
|
||||
const stringifiedJson = JSON.stringify(document);
|
||||
let newJson;
|
||||
|
||||
try {
|
||||
@ -22,4 +23,51 @@ describe("Document", () => {
|
||||
assert.isTrue(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#createParagraph", () => {
|
||||
it("should create a new paragraph and append it to body", () => {
|
||||
const para = document.createParagraph();
|
||||
expect(para).to.be.an.instanceof(docx.Paragraph);
|
||||
const body = new Formatter().format(document)["w:document"][1]["w:body"];
|
||||
expect(body).to.be.an("array").which.has.length.at.least(1);
|
||||
expect(body[0]).to.have.property("w:p");
|
||||
});
|
||||
|
||||
it("should use the text given to create a run in the paragraph", () => {
|
||||
const para = document.createParagraph("sample paragraph text");
|
||||
expect(para).to.be.an.instanceof(docx.Paragraph);
|
||||
const body = new Formatter().format(document)["w:document"][1]["w:body"];
|
||||
expect(body).to.be.an("array").which.has.length.at.least(1);
|
||||
expect(body[0]).to.have.property("w:p").which.includes({
|
||||
"w:r": [
|
||||
{"w:rPr": []},
|
||||
{"w:t": [{_attr: {"xml:space": "preserve"}}, "sample paragraph text"]},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#createTable", () => {
|
||||
it("should create a new table and append it to body", () => {
|
||||
const table = document.createTable(2, 3);
|
||||
expect(table).to.be.an.instanceof(docx.Table);
|
||||
const body = new Formatter().format(document)["w:document"][1]["w:body"];
|
||||
expect(body).to.be.an("array").which.has.length.at.least(1);
|
||||
expect(body[0]).to.have.property("w:tbl");
|
||||
});
|
||||
|
||||
it("should create a table with the correct dimensions", () => {
|
||||
document.createTable(2, 3);
|
||||
const body = new Formatter().format(document)["w:document"][1]["w:body"];
|
||||
expect(body).to.be.an("array").which.has.length.at.least(1);
|
||||
expect(body[0]).to.have.property("w:tbl").which.includes({
|
||||
"w:tblGrid": [
|
||||
{"w:gridCol": [{_attr: {"w:w": 1}}]},
|
||||
{"w:gridCol": [{_attr: {"w:w": 1}}]},
|
||||
{"w:gridCol": [{_attr: {"w:w": 1}}]},
|
||||
],
|
||||
});
|
||||
expect(body[0]["w:tbl"].filter((x) => x["w:tr"])).to.have.length(2);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,13 +1,9 @@
|
||||
import { ThematicBreak } from "../../../docx/paragraph/border";
|
||||
import { assert } from "chai";
|
||||
|
||||
function jsonify(obj: Object) {
|
||||
let stringifiedJson = JSON.stringify(obj);
|
||||
return JSON.parse(stringifiedJson);
|
||||
}
|
||||
import { ThematicBreak } from "../../../docx/paragraph/border";
|
||||
import { Utility } from "../../utility";
|
||||
|
||||
describe("Border", () => {
|
||||
|
||||
// TODO: Need tests here
|
||||
});
|
||||
|
||||
describe("ThematicBreak", () => {
|
||||
@ -19,12 +15,12 @@ describe("ThematicBreak", () => {
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Thematic Break with correct border properties", () => {
|
||||
let newJson = jsonify(thematicBreak);
|
||||
let attributes = {
|
||||
const newJson = Utility.jsonify(thematicBreak);
|
||||
const attributes = {
|
||||
color: "auto",
|
||||
space: "1",
|
||||
val: "single",
|
||||
sz: "6"
|
||||
sz: "6",
|
||||
};
|
||||
assert.equal(JSON.stringify(newJson.root[0].root[0].root), JSON.stringify(attributes));
|
||||
});
|
||||
|
@ -1,10 +1,6 @@
|
||||
import { PageBreak } from "../../../docx/paragraph/page-break";
|
||||
import { assert } from "chai";
|
||||
|
||||
function jsonify(obj: Object) {
|
||||
let stringifiedJson = JSON.stringify(obj);
|
||||
return JSON.parse(stringifiedJson);
|
||||
}
|
||||
import { PageBreak } from "../../../docx/paragraph/page-break";
|
||||
import { Utility } from "../../utility";
|
||||
|
||||
describe("PageBreak", () => {
|
||||
let pageBreak: PageBreak;
|
||||
@ -15,20 +11,20 @@ describe("PageBreak", () => {
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Page Break with correct attributes", () => {
|
||||
let newJson = jsonify(pageBreak);
|
||||
let attributes = {
|
||||
type: "page"
|
||||
const newJson = Utility.jsonify(pageBreak);
|
||||
const attributes = {
|
||||
type: "page",
|
||||
};
|
||||
assert.equal(JSON.stringify(newJson.root[1].root[0].root), JSON.stringify(attributes));
|
||||
});
|
||||
|
||||
it("should create a Page Break with w:r", () => {
|
||||
let newJson = jsonify(pageBreak);
|
||||
const newJson = Utility.jsonify(pageBreak);
|
||||
assert.equal(newJson.rootKey, "w:r");
|
||||
});
|
||||
|
||||
it("should create a Page Break with a Break inside", () => {
|
||||
let newJson = jsonify(pageBreak);
|
||||
const newJson = Utility.jsonify(pageBreak);
|
||||
assert.equal(newJson.root[1].rootKey, "w:br");
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,6 @@
|
||||
import { Style } from "../../../docx/paragraph/style";
|
||||
import { assert } from "chai";
|
||||
|
||||
function jsonify(obj: Object) {
|
||||
let stringifiedJson = JSON.stringify(obj);
|
||||
return JSON.parse(stringifiedJson);
|
||||
}
|
||||
import { Style } from "../../../docx/paragraph/style";
|
||||
import { Utility } from "../../utility";
|
||||
|
||||
describe("ParagraphStyle", () => {
|
||||
let style: Style;
|
||||
@ -12,15 +8,14 @@ describe("ParagraphStyle", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a style with given value", () => {
|
||||
style = new Style("test");
|
||||
let newJson = jsonify(style);
|
||||
const newJson = Utility.jsonify(style);
|
||||
assert.equal(newJson.root[0].root.val, "test");
|
||||
});
|
||||
|
||||
it("should create a style with blank val", () => {
|
||||
style = new Style("");
|
||||
let newJson = jsonify(style);
|
||||
const newJson = Utility.jsonify(style);
|
||||
assert.equal(newJson.root[0].root.val, "");
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@ -1,12 +1,7 @@
|
||||
import { assert, expect } from "chai";
|
||||
import * as docx from "../../../docx";
|
||||
import { Formatter } from "../../../export/formatter";
|
||||
import { Numbering } from "../../../numbering";
|
||||
import { assert, expect } from "chai";
|
||||
|
||||
function jsonify(obj: Object) {
|
||||
let stringifiedJson = JSON.stringify(obj);
|
||||
return JSON.parse(stringifiedJson);
|
||||
}
|
||||
|
||||
describe("Paragraph", () => {
|
||||
let paragraph: docx.Paragraph;
|
||||
@ -18,7 +13,7 @@ describe("Paragraph", () => {
|
||||
describe("#constructor()", () => {
|
||||
|
||||
it("should create valid JSON", () => {
|
||||
let stringifiedJson = JSON.stringify(paragraph);
|
||||
const stringifiedJson = JSON.stringify(paragraph);
|
||||
let newJson;
|
||||
|
||||
try {
|
||||
@ -30,89 +25,158 @@ describe("Paragraph", () => {
|
||||
});
|
||||
|
||||
it("should create have valid properties", () => {
|
||||
let stringifiedJson = JSON.stringify(paragraph);
|
||||
let newJson = JSON.parse(stringifiedJson);
|
||||
const stringifiedJson = JSON.stringify(paragraph);
|
||||
const newJson = JSON.parse(stringifiedJson);
|
||||
assert.equal(newJson.root[0].rootKey, "w:pPr");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#createTextRun", () => {
|
||||
it("should add a new run to the paragraph and return it", () => {
|
||||
const run = paragraph.createTextRun("this is a test run");
|
||||
expect(run).to.be.instanceof(docx.TextRun);
|
||||
const tree = new Formatter().format(paragraph)["w:p"];
|
||||
expect(tree).to.be.an("array").which.includes({
|
||||
"w:r": [
|
||||
{"w:rPr": []},
|
||||
{"w:t": [{_attr: {"xml:space": "preserve"}}, "this is a test run"]},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#heading1()", () => {
|
||||
it("should add heading style to JSON", () => {
|
||||
paragraph.heading1();
|
||||
let newJson = jsonify(paragraph);
|
||||
assert.equal(newJson.root[0].root[1].root[0].root.val, "Heading1");
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:pPr": [{"w:pStyle": [{_attr: {"w:val": "Heading1"}}]}],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#heading2()", () => {
|
||||
it("should add heading style to JSON", () => {
|
||||
paragraph.heading2();
|
||||
let newJson = jsonify(paragraph);
|
||||
|
||||
assert.equal(newJson.root[0].root[1].root[0].root.val, "Heading2");
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:pPr": [{"w:pStyle": [{_attr: {"w:val": "Heading2"}}]}],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#heading3()", () => {
|
||||
it("should add heading style to JSON", () => {
|
||||
paragraph.heading3();
|
||||
let newJson = jsonify(paragraph);
|
||||
|
||||
assert.equal(newJson.root[0].root[1].root[0].root.val, "Heading3");
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:pPr": [{"w:pStyle": [{_attr: {"w:val": "Heading3"}}]}],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#title()", () => {
|
||||
it("should add title style to JSON", () => {
|
||||
paragraph.title();
|
||||
let newJson = jsonify(paragraph);
|
||||
|
||||
assert.equal(newJson.root[0].root[1].root[0].root.val, "Title");
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:pPr": [{"w:pStyle": [{_attr: {"w:val": "Title"}}]}],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#center()", () => {
|
||||
it("should add center alignment to JSON", () => {
|
||||
paragraph.center();
|
||||
let newJson = jsonify(paragraph);
|
||||
|
||||
assert.equal(newJson.root[0].root[1].root[0].root.val, "center");
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:pPr": [{"w:jc": [{_attr: {"w:val": "center"}}]}],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#thematicBreak()", () => {
|
||||
it("should add thematic break to JSON", () => {
|
||||
paragraph.thematicBreak();
|
||||
let newJson = jsonify(paragraph);
|
||||
assert.equal(newJson.root[0].root[1].rootKey, "w:pBdr");
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [{
|
||||
"w:pPr": [{
|
||||
"w:pBdr": [{
|
||||
"w:bottom": [{
|
||||
_attr: {
|
||||
"w:val": "single",
|
||||
"w:color": "auto",
|
||||
"w:space": "1",
|
||||
"w:sz": "6",
|
||||
},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#pageBreak()", () => {
|
||||
it("should add page break to JSON", () => {
|
||||
paragraph.pageBreak();
|
||||
let newJson = jsonify(paragraph);
|
||||
assert.equal(newJson.root[0].root[1].root[1].rootKey, "w:br");
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [{
|
||||
"w:pPr": [{
|
||||
"w:r": [
|
||||
{"w:rPr": []},
|
||||
{"w:br": [{_attr: {"w:type": "page"}}]},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
});
|
||||
|
||||
it("should add page break with 'page' type", () => {
|
||||
paragraph.pageBreak();
|
||||
let newJson = jsonify(paragraph);
|
||||
assert.equal(newJson.root[0].root[1].root[1].root[0].root.type, "page");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#bullet()", () => {
|
||||
it("should add list paragraph style to JSON", () => {
|
||||
paragraph.bullet();
|
||||
let newJson = jsonify(paragraph);
|
||||
assert.equal(newJson.root[0].root[1].root[0].root.val, "ListParagraph");
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.have.property("w:p").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]).to.have.property("w:pPr").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]["w:pPr"][0]).to.deep.equal({
|
||||
"w:pStyle": [{_attr: {"w:val": "ListParagraph"}}],
|
||||
});
|
||||
});
|
||||
|
||||
it("it should add numbered properties", () => {
|
||||
paragraph.bullet();
|
||||
let newJson = jsonify(paragraph);
|
||||
assert.isDefined(newJson.root[0].root[2]);
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.have.property("w:p").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]).to.have.property("w:pPr").which.is.an("array").which.has.length.at.least(2);
|
||||
expect(tree["w:p"][0]["w:pPr"][1]).to.deep.equal({
|
||||
"w:numPr": [
|
||||
{"w:ilvl": [{_attr: {"w:val": 0}}]},
|
||||
{"w:numId": [{_attr: {"w:val": 1}}]},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -124,8 +188,12 @@ describe("Paragraph", () => {
|
||||
const letterNumbering = numbering.createConcreteNumbering(numberedAbstract);
|
||||
|
||||
paragraph.setNumbering(letterNumbering, 0);
|
||||
let newJson = jsonify(paragraph);
|
||||
assert.equal(newJson.root[0].root[1].root[0].root.val, "ListParagraph");
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.have.property("w:p").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]).to.have.property("w:pPr").which.is.an("array").which.has.length.at.least(1);
|
||||
expect(tree["w:p"][0]["w:pPr"][0]).to.deep.equal({
|
||||
"w:pStyle": [{_attr: {"w:val": "ListParagraph"}}],
|
||||
});
|
||||
});
|
||||
|
||||
it("it should add numbered properties", () => {
|
||||
@ -136,23 +204,89 @@ describe("Paragraph", () => {
|
||||
|
||||
paragraph.setNumbering(letterNumbering, 0);
|
||||
const tree = new Formatter().format(paragraph);
|
||||
console.log(JSON.stringify(tree, null, 2));
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:pPr": [
|
||||
{"_attr": {}},
|
||||
{"w:pStyle": [{"_attr": {"w:val": "ListParagraph"}}]},
|
||||
{"w:pStyle": [{_attr: {"w:val": "ListParagraph"}}]},
|
||||
{
|
||||
"w:numPr": [
|
||||
{"w:ilvl": [{"_attr": {"w:val": 0}}]},
|
||||
{"w:numId": [{"_attr": {"w:val": letterNumbering.id}}]}
|
||||
]
|
||||
{"w:ilvl": [{_attr: {"w:val": 0}}]},
|
||||
{"w:numId": [{_attr: {"w:val": letterNumbering.id}}]},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
})
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#style", () => {
|
||||
it("should set the paragraph style to the given styleId", () => {
|
||||
paragraph.style("myFancyStyle");
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:pPr": [
|
||||
{"w:pStyle": [{_attr: {"w:val": "myFancyStyle"}}]},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#indent", () => {
|
||||
it("should set the paragraph indent to the given values", () => {
|
||||
paragraph.indent(720);
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:pPr": [
|
||||
{"w:ind": [{_attr: {"w:left": 720}}]},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#spacing", () => {
|
||||
it("should set the paragraph spacing to the given values", () => {
|
||||
paragraph.spacing({before: 90, line: 50});
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:pPr": [
|
||||
{"w:spacing": [{_attr: {"w:before": 90, "w:line": 50}}]},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#keepLines", () => {
|
||||
it("should set the paragraph keepLines sub-component", () => {
|
||||
paragraph.keepLines();
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [{"w:pPr": [{"w:keepLines": []}]}],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#keepNext", () => {
|
||||
it("should set the paragraph keepNext sub-component", () => {
|
||||
paragraph.keepNext();
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [{"w:pPr": [{"w:keepNext": []}]}],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
23
ts/tests/docx/paragraph/spacingTest.ts
Normal file
23
ts/tests/docx/paragraph/spacingTest.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { expect } from "chai";
|
||||
import { Spacing } from "../../../docx/paragraph/spacing";
|
||||
import { Formatter } from "../../../export/formatter";
|
||||
|
||||
describe("Spacing", () => {
|
||||
describe("#constructor", () => {
|
||||
it("should set the properties given", () => {
|
||||
const spacing = new Spacing({before: 100, after: 120, line: 150});
|
||||
const tree = new Formatter().format(spacing);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:spacing": [{_attr: {"w:after": 120, "w:before": 100, "w:line": 150}}],
|
||||
});
|
||||
});
|
||||
|
||||
it("should only set the given properties", () => {
|
||||
const spacing = new Spacing({before: 100});
|
||||
const tree = new Formatter().format(spacing);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:spacing": [{_attr: {"w:before": 100}}],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,10 +1,6 @@
|
||||
import { LeftTabStop, MaxRightTabStop } from "../../../docx/paragraph/tab-stop";
|
||||
import { assert } from "chai";
|
||||
|
||||
function jsonify(obj: Object) {
|
||||
let stringifiedJson = JSON.stringify(obj);
|
||||
return JSON.parse(stringifiedJson);
|
||||
}
|
||||
import { LeftTabStop, MaxRightTabStop } from "../../../docx/paragraph/tab-stop";
|
||||
import { Utility } from "../../utility";
|
||||
|
||||
describe("LeftTabStop", () => {
|
||||
let tabStop: LeftTabStop;
|
||||
@ -15,23 +11,23 @@ describe("LeftTabStop", () => {
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Tab Stop with correct attributes", () => {
|
||||
let newJson = jsonify(tabStop);
|
||||
let attributes = {
|
||||
const newJson = Utility.jsonify(tabStop);
|
||||
const attributes = {
|
||||
val: "left",
|
||||
pos: 100
|
||||
pos: 100,
|
||||
};
|
||||
assert.equal(JSON.stringify(newJson.root[0].root[0].root), JSON.stringify(attributes));
|
||||
});
|
||||
|
||||
it("should create a Tab Stop with w:tab", () => {
|
||||
let newJson = jsonify(tabStop);
|
||||
const newJson = Utility.jsonify(tabStop);
|
||||
assert.equal(newJson.root[0].rootKey, "w:tab");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("RightTabStop", () => {
|
||||
|
||||
// TODO
|
||||
});
|
||||
|
||||
describe("MaxRightTabStop", () => {
|
||||
@ -43,17 +39,17 @@ describe("MaxRightTabStop", () => {
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Tab Stop with correct attributes", () => {
|
||||
let newJson = jsonify(tabStop);
|
||||
const newJson = Utility.jsonify(tabStop);
|
||||
|
||||
let attributes = {
|
||||
const attributes = {
|
||||
val: "right",
|
||||
pos: 9026
|
||||
pos: 9026,
|
||||
};
|
||||
assert.equal(JSON.stringify(newJson.root[0].root[0].root), JSON.stringify(attributes));
|
||||
});
|
||||
|
||||
it("should create a Tab Stop with w:tab", () => {
|
||||
let newJson = jsonify(tabStop);
|
||||
const newJson = Utility.jsonify(tabStop);
|
||||
assert.equal(newJson.root[0].rootKey, "w:tab");
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,6 @@
|
||||
import { NumberProperties } from "../../../docx/paragraph/unordered-list";
|
||||
import { assert } from "chai";
|
||||
|
||||
function jsonify(obj: Object) {
|
||||
let stringifiedJson = JSON.stringify(obj);
|
||||
return JSON.parse(stringifiedJson);
|
||||
}
|
||||
import { NumberProperties } from "../../../docx/paragraph/unordered-list";
|
||||
import { Utility } from "../../utility";
|
||||
|
||||
describe("NumberProperties", () => {
|
||||
let numberProperties: NumberProperties;
|
||||
@ -15,18 +11,18 @@ describe("NumberProperties", () => {
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Number Properties with correct root key", () => {
|
||||
let newJson = jsonify(numberProperties);
|
||||
const newJson = Utility.jsonify(numberProperties);
|
||||
assert.equal(newJson.rootKey, "w:numPr");
|
||||
});
|
||||
|
||||
it("should create a Page Break with a Indent Level inside", () => {
|
||||
let newJson = jsonify(numberProperties);
|
||||
const newJson = Utility.jsonify(numberProperties);
|
||||
assert.equal(newJson.root[0].rootKey, "w:ilvl");
|
||||
assert.equal(newJson.root[0].root[0].root.val, 10);
|
||||
});
|
||||
|
||||
it("should create a Page Break with a Number Id inside", () => {
|
||||
let newJson = jsonify(numberProperties);
|
||||
const newJson = Utility.jsonify(numberProperties);
|
||||
assert.equal(newJson.root[1].rootKey, "w:numId");
|
||||
assert.equal(newJson.root[1].root[0].root.val, 5);
|
||||
});
|
||||
|
@ -1,10 +1,6 @@
|
||||
import { Break } from "../../../docx/run/break";
|
||||
import { assert } from "chai";
|
||||
|
||||
function jsonify(obj: Object) {
|
||||
let stringifiedJson = JSON.stringify(obj);
|
||||
return JSON.parse(stringifiedJson);
|
||||
}
|
||||
import { Break } from "../../../docx/run/break";
|
||||
import { Utility } from "../../utility";
|
||||
|
||||
describe("Break", () => {
|
||||
let currentBreak: Break;
|
||||
@ -15,7 +11,7 @@ describe("Break", () => {
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Break with correct root key", () => {
|
||||
let newJson = jsonify(currentBreak);
|
||||
const newJson = Utility.jsonify(currentBreak);
|
||||
assert.equal(newJson.rootKey, "w:br");
|
||||
});
|
||||
});
|
||||
|
26
ts/tests/docx/run/run-components/drawingTests.ts
Normal file
26
ts/tests/docx/run/run-components/drawingTests.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { assert } from "chai";
|
||||
import * as fs from "fs";
|
||||
import { Drawing } from "../../../../docx/run/run-components/drawing";
|
||||
import { Utility } from "../../../utility";
|
||||
|
||||
describe("Drawing", () => {
|
||||
let currentBreak: Drawing;
|
||||
|
||||
beforeEach(() => {
|
||||
const path = "./demo/penguins.jpg";
|
||||
currentBreak = new Drawing({
|
||||
fileName: "test.jpg",
|
||||
referenceId: 1,
|
||||
stream: fs.createReadStream(path),
|
||||
path: path,
|
||||
});
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Drawing with correct root key", () => {
|
||||
const newJson = Utility.jsonify(currentBreak);
|
||||
assert.equal(newJson.rootKey, "w:drawing");
|
||||
// console.log(JSON.stringify(newJson, null, 2));
|
||||
});
|
||||
});
|
||||
});
|
22
ts/tests/docx/run/run-components/text.ts
Normal file
22
ts/tests/docx/run/run-components/text.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { expect } from "chai";
|
||||
import { Text } from "../../../../docx/run/run-components/text";
|
||||
import { Formatter } from "../../../../export/formatter";
|
||||
|
||||
describe("Text", () => {
|
||||
describe("#constructor", () => {
|
||||
it("creates an empty text run if no text is given", () => {
|
||||
const t = new Text("");
|
||||
const f = new Formatter().format(t);
|
||||
expect(f).to.deep.equal({"w:t": [{_attr: {"xml:space": "preserve"}}]});
|
||||
});
|
||||
|
||||
it("adds the passed in text to the component", () => {
|
||||
const t = new Text(" this is\n text");
|
||||
const f = new Formatter().format(t);
|
||||
expect(f).to.deep.equal({"w:t": [
|
||||
{_attr: {"xml:space": "preserve"}},
|
||||
" this is\n text",
|
||||
]});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,11 +1,7 @@
|
||||
import { assert, expect } from "chai";
|
||||
import { Run } from "../../../docx/run";
|
||||
import { TextRun } from "../../../docx/run/text-run";
|
||||
import { Formatter } from "../../../export/formatter";
|
||||
|
||||
function jsonify(obj: object) {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
import { Utility } from "../../utility";
|
||||
|
||||
describe("Run", () => {
|
||||
let run: Run;
|
||||
@ -17,7 +13,7 @@ describe("Run", () => {
|
||||
describe("#bold()", () => {
|
||||
it("it should add bold to the properties", () => {
|
||||
run.bold();
|
||||
const newJson = jsonify(run);
|
||||
const newJson = Utility.jsonify(run);
|
||||
assert.equal(newJson.root[0].root[0].rootKey, "w:b");
|
||||
});
|
||||
});
|
||||
@ -25,7 +21,7 @@ describe("Run", () => {
|
||||
describe("#italic()", () => {
|
||||
it("it should add italics to the properties", () => {
|
||||
run.italic();
|
||||
const newJson = jsonify(run);
|
||||
const newJson = Utility.jsonify(run);
|
||||
assert.equal(newJson.root[0].root[0].rootKey, "w:i");
|
||||
});
|
||||
});
|
||||
@ -33,15 +29,35 @@ describe("Run", () => {
|
||||
describe("#underline()", () => {
|
||||
it("it should add underline to the properties", () => {
|
||||
run.underline();
|
||||
const newJson = jsonify(run);
|
||||
const newJson = Utility.jsonify(run);
|
||||
assert.equal(newJson.root[0].root[0].rootKey, "w:u");
|
||||
});
|
||||
|
||||
it("should default to 'single' and no color", () => {
|
||||
run.underline();
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [
|
||||
{"w:rPr": [{"w:u": [{_attr: {"w:val": "single"}}]}]},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should set the style type and color if given", () => {
|
||||
run.underline("double", "990011");
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [
|
||||
{"w:rPr": [{"w:u": [{_attr: {"w:val": "double", "w:color": "990011"}}]}]},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#smallCaps()", () => {
|
||||
it("it should add smallCaps to the properties", () => {
|
||||
run.smallCaps();
|
||||
const newJson = jsonify(run);
|
||||
const newJson = Utility.jsonify(run);
|
||||
assert.equal(newJson.root[0].root[0].rootKey, "w:smallCaps");
|
||||
});
|
||||
});
|
||||
@ -49,7 +65,7 @@ describe("Run", () => {
|
||||
describe("#caps()", () => {
|
||||
it("it should add caps to the properties", () => {
|
||||
run.allCaps();
|
||||
const newJson = jsonify(run);
|
||||
const newJson = Utility.jsonify(run);
|
||||
assert.equal(newJson.root[0].root[0].rootKey, "w:caps");
|
||||
});
|
||||
});
|
||||
@ -57,7 +73,7 @@ describe("Run", () => {
|
||||
describe("#strike()", () => {
|
||||
it("it should add strike to the properties", () => {
|
||||
run.strike();
|
||||
const newJson = jsonify(run);
|
||||
const newJson = Utility.jsonify(run);
|
||||
assert.equal(newJson.root[0].root[0].rootKey, "w:strike");
|
||||
});
|
||||
});
|
||||
@ -65,7 +81,7 @@ describe("Run", () => {
|
||||
describe("#doubleStrike()", () => {
|
||||
it("it should add caps to the properties", () => {
|
||||
run.doubleStrike();
|
||||
const newJson = jsonify(run);
|
||||
const newJson = Utility.jsonify(run);
|
||||
assert.equal(newJson.root[0].root[0].rootKey, "w:dstrike");
|
||||
});
|
||||
});
|
||||
@ -73,7 +89,7 @@ describe("Run", () => {
|
||||
describe("#break()", () => {
|
||||
it("it should add break to the run", () => {
|
||||
run.break();
|
||||
const newJson = jsonify(run);
|
||||
const newJson = Utility.jsonify(run);
|
||||
assert.equal(newJson.root[1].rootKey, "w:br");
|
||||
});
|
||||
});
|
||||
@ -81,7 +97,7 @@ describe("Run", () => {
|
||||
describe("#tab()", () => {
|
||||
it("it should add break to the run", () => {
|
||||
run.tab();
|
||||
const newJson = jsonify(run);
|
||||
const newJson = Utility.jsonify(run);
|
||||
assert.equal(newJson.root[1].rootKey, "w:tab");
|
||||
});
|
||||
});
|
||||
@ -101,4 +117,40 @@ describe("Run", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#color", () => {
|
||||
it("should set the run to the color given", () => {
|
||||
run.color("001122");
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [
|
||||
{"w:rPr": [{"w:color": [{_attr: {"w:val": "001122"}}]}]},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#size", () => {
|
||||
it("should set the run to the given size", () => {
|
||||
run.size(24);
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [
|
||||
{"w:rPr": [{"w:sz": [{_attr: {"w:val": 24}}]}]},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#style", () => {
|
||||
it("should set the style to the given styleId", () => {
|
||||
run.style("myRunStyle");
|
||||
const tree = new Formatter().format(run);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:r": [
|
||||
{"w:rPr": [{"w:rStyle": [{_attr: {"w:val": "myRunStyle"}}]}]},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,6 @@
|
||||
import { SubScript, SuperScript } from "../../../docx/run/script";
|
||||
import { assert } from "chai";
|
||||
|
||||
function jsonify(obj: Object) {
|
||||
let stringifiedJson = JSON.stringify(obj);
|
||||
return JSON.parse(stringifiedJson);
|
||||
}
|
||||
import { SubScript, SuperScript } from "../../../docx/run/script";
|
||||
import { Utility } from "../../utility";
|
||||
|
||||
describe("SubScript", () => {
|
||||
let subScript: SubScript;
|
||||
@ -15,15 +11,15 @@ describe("SubScript", () => {
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Sub Script with correct attributes", () => {
|
||||
let newJson = jsonify(subScript);
|
||||
let attributes = {
|
||||
val: "subscript"
|
||||
const newJson = Utility.jsonify(subScript);
|
||||
const attributes = {
|
||||
val: "subscript",
|
||||
};
|
||||
assert.equal(JSON.stringify(newJson.root[0].root), JSON.stringify(attributes));
|
||||
});
|
||||
|
||||
it("should create a Sub Script with correct root key", () => {
|
||||
let newJson = jsonify(subScript);
|
||||
const newJson = Utility.jsonify(subScript);
|
||||
assert.equal(newJson.rootKey, "w:vertAlign");
|
||||
});
|
||||
});
|
||||
@ -38,15 +34,15 @@ describe("SuperScript", () => {
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Super Script with correct attributes", () => {
|
||||
let newJson = jsonify(superScript);
|
||||
let attributes = {
|
||||
val: "superscript"
|
||||
const newJson = Utility.jsonify(superScript);
|
||||
const attributes = {
|
||||
val: "superscript",
|
||||
};
|
||||
assert.equal(JSON.stringify(newJson.root[0].root), JSON.stringify(attributes));
|
||||
});
|
||||
|
||||
it("should create a Super Script with correct root key", () => {
|
||||
let newJson = jsonify(superScript);
|
||||
const newJson = Utility.jsonify(superScript);
|
||||
assert.equal(newJson.rootKey, "w:vertAlign");
|
||||
});
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user