Compare commits
379 Commits
Author | SHA1 | Date | |
---|---|---|---|
cb8e9fdd36 | |||
53ce3c1526 | |||
a78f06b41b | |||
ce7ef30806 | |||
fd93c0776a | |||
6a762c6c0e | |||
23c5aef276 | |||
69707a7207 | |||
cfd3505414 | |||
ee958dc351 | |||
680f2325a3 | |||
2f0ad3eeb2 | |||
c895a9c7d9 | |||
388a8404f5 | |||
320cb1c418 | |||
8a6b73915f | |||
774355d608 | |||
35dbce3a68 | |||
6d0a267ba4 | |||
df701be572 | |||
1edad47e6e | |||
c873abfe18 | |||
989446ef36 | |||
fc6daed620 | |||
5e921f1dfc | |||
45bbf1b693 | |||
8b8c664f0f | |||
079334f71b | |||
3fe0c76d54 | |||
1e55a3e6a8 | |||
950a2f8b53 | |||
bbe2e1e46e | |||
635c58c131 | |||
ba39d806b7 | |||
355e97cb5e | |||
4339f8cfc0 | |||
448572d7a1 | |||
2132c7b6da | |||
d0bd83d6c5 | |||
1037b7c23d | |||
df197f73ea | |||
ea08f603f5 | |||
fa2f1235f7 | |||
ff5d02c964 | |||
e93d6799fd | |||
f2027230a0 | |||
cb47d4f772 | |||
eebc9fbcfa | |||
0e698491f3 | |||
ae52e8fabb | |||
ccd655ef8b | |||
3dc6e71aaf | |||
e6d3577f74 | |||
ef05024f2f | |||
d3bc784248 | |||
979701331e | |||
76b1682296 | |||
7c31b72f99 | |||
f7c2072cff | |||
392db1cd11 | |||
ca244bcfe1 | |||
2d02f51f25 | |||
592fb5ca9f | |||
a3945bc7f1 | |||
2adde9830c | |||
0355afe11c | |||
998fe3f370 | |||
eb71fc20e6 | |||
ab348bd5f9 | |||
c518d1c6c7 | |||
d8d16b4a7d | |||
928e4b9bc2 | |||
4f900d6566 | |||
362a997187 | |||
89c658746d | |||
75d699f7ef | |||
f7412690b6 | |||
ece2b23407 | |||
f84af9a44b | |||
90dc1103f6 | |||
c469fb24db | |||
32be6e36da | |||
b34ad22ad6 | |||
2358139a6b | |||
43ebfe7a2f | |||
0b8094dea8 | |||
f1d1570b10 | |||
e9e68bc802 | |||
4c369510ce | |||
96413d6c47 | |||
df6c7cf19f | |||
49fc28d86c | |||
cc67a83ce8 | |||
742e2b5089 | |||
d19ff1e300 | |||
01950ed443 | |||
cf1689a3c2 | |||
66d0bab0a5 | |||
5889f20f1e | |||
ebec10e312 | |||
ae8a0c7fd0 | |||
bb49200fad | |||
a6bba0bc6c | |||
fb08f79344 | |||
741c74825e | |||
28539cd47b | |||
8ca7c5a343 | |||
32b56e7071 | |||
7dad717952 | |||
34e928755f | |||
51e0f311fe | |||
cc9dff6b94 | |||
101cc0fdea | |||
d408262fa8 | |||
ed53c30f42 | |||
ebbf6a99c1 | |||
b98c103e45 | |||
518fec0595 | |||
659936f3f0 | |||
b0febf5054 | |||
56b951a2b1 | |||
a3a9958a69 | |||
4f36bbf426 | |||
357bc7f377 | |||
da8405b5b9 | |||
492face7ab | |||
b6351f0260 | |||
3a7f9053b9 | |||
19b122684c | |||
72e89cfc3c | |||
5ae02c3342 | |||
258adba94c | |||
190208d5df | |||
32cda4dfb3 | |||
b2c3dd2f7b | |||
58eca3ff5b | |||
d5c04f9042 | |||
67ea7c95de | |||
e57fd8fc57 | |||
411c0dadb5 | |||
ee81f3c502 | |||
8263b93c36 | |||
be709d082c | |||
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 | |||
77255c9d5e | |||
e10b8889f7 | |||
744b16b753 | |||
77824ce1d2 | |||
d2f777c4e5 | |||
946a222d37 | |||
279a5a93f1 | |||
0e89606ec9 | |||
72683ea990 | |||
88cf5f5065 | |||
540518bd54 | |||
03b34915c6 | |||
f6eb412357 | |||
ca769cc849 | |||
727471b7e3 | |||
1a37242a3d | |||
81e0d56918 | |||
237be76d33 | |||
a454ff9643 | |||
f7b90d4ff3 | |||
cee515e43f | |||
0e9532d835 | |||
4b300e4def | |||
1fe7ab90f2 | |||
a3d2323254 | |||
0b2de737de | |||
0a70d932a0 | |||
6b702c4bd6 | |||
709ff25702 | |||
82998d4f6b | |||
6e6a06eba4 | |||
ae70c2dfde | |||
28e11a9b08 | |||
f5e81f1dfc | |||
38138049fe | |||
5511024ca6 | |||
ef1407e640 | |||
f822bbb26f | |||
52c4e3cabd | |||
9ced196678 | |||
ef6e195e89 | |||
a77d520f41 | |||
8eb11bca29 | |||
660a81633f | |||
a917247b60 | |||
f492b3fe04 | |||
96a8942455 | |||
bca478bb81 | |||
f5de5fef4d | |||
0e9301c0b5 | |||
b0869567c6 | |||
0585a25a5a | |||
9804091f6a | |||
9c3023019f |
13
.editorconfig
Normal file
13
.editorconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# Editor configuration, see http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
12
.gitignore
vendored
12
.gitignore
vendored
@ -36,5 +36,13 @@ node_modules
|
||||
build
|
||||
build-tests
|
||||
|
||||
# vscode
|
||||
ts/.vscode
|
||||
# VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history
|
||||
|
||||
# Lock files
|
||||
package-lock.json
|
||||
|
43
.npmignore
Normal file
43
.npmignore
Normal file
@ -0,0 +1,43 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directory
|
||||
node_modules
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# build
|
||||
# build <-- we want this in the package
|
||||
build-tests
|
||||
|
||||
# vscode
|
||||
.vscode
|
||||
|
||||
# docs
|
||||
docs
|
19
.travis.yml
19
.travis.yml
@ -1,10 +1,25 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "6"
|
||||
- "node"
|
||||
- "stable"
|
||||
install:
|
||||
- npm install
|
||||
script:
|
||||
- npm run lint
|
||||
- npm test
|
||||
- npm run style
|
||||
- npm run build
|
||||
- node ./demo/demo1.js
|
||||
- node ./demo/demo2.js
|
||||
- node ./demo/demo3.js
|
||||
- node ./demo/demo4.js
|
||||
- node ./demo/demo5.js
|
||||
- node ./demo/demo6.js
|
||||
- node ./demo/demo7.js
|
||||
after_failure:
|
||||
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
|
||||
after_success:
|
||||
- bash ./deploy-docs.sh
|
||||
env:
|
||||
global:
|
||||
- ENCRYPTION_LABEL: "ad385fa3b525"
|
||||
|
||||
|
9
.vscode/settings.json
vendored
Normal file
9
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"cSpell.words": ["clippy", "docx", "dolan", "miu", "officegen", "typedoc"],
|
||||
"prettier.trailingComma": "all",
|
||||
"prettier.printWidth": 140,
|
||||
"editor.formatOnSave": false,
|
||||
"prettier.tabWidth": 4,
|
||||
"prettier.arrowParens": "always",
|
||||
"prettier.bracketSpacing": true
|
||||
}
|
407
README.md
407
README.md
@ -1,50 +1,45 @@
|
||||
# [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url]
|
||||
<p align="center">
|
||||
<img alt="clippy the assistant" src="http://i60.tinypic.com/339pvtt.png">
|
||||
</p>
|
||||
|
||||
> A tool to create Word Documents (.docx) with JS or TS, written in TS.
|
||||
<p align="center">
|
||||
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][gemnasium-image]][gemnasium-url]
|
||||
[![Known Vulnerabilities][snky-image]][snky-url]
|
||||
[![Chat on Gitter][gitter-image]][gitter-url]
|
||||
[![code style: prettier][prettier-image]][prettier-url]
|
||||
|
||||
[](https://nodei.co/npm/docx/)
|
||||
|
||||

|
||||
# 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](#)
|
||||
|
||||
# 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
|
||||
@ -53,326 +48,40 @@ 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');
|
||||
// If you want to export it as a .pdf file instead
|
||||
exporter.packPdf('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
|
||||
```
|
||||
# Contributing
|
||||
|
||||
You can mix and match whatever properties you want, or provide no properties.
|
||||
Read the contribution guidelines [here](https://github.com/dolanmiu/docx/wiki/Contributing-Guidelines).
|
||||
|
||||
## 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);
|
||||
```
|
||||
Made with 💖
|
||||
|
||||
### 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
|
||||
@ -380,3 +89,11 @@ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
[travis-url]: https://travis-ci.org/dolanmiu/docx
|
||||
[daviddm-image]: https://david-dm.org/dolanmiu/docx.svg?theme=shields.io
|
||||
[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
|
||||
[prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg
|
||||
[prettier-url]: https://github.com/prettier/prettier
|
||||
|
16
demo/demo1.js
Normal file
16
demo/demo1.js
Normal file
@ -0,0 +1,16 @@
|
||||
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);
|
||||
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
exporter.pack('My Document');
|
||||
|
||||
console.log('Document created successfully at project root!');
|
74
demo/demo2.js
Normal file
74
demo/demo2.js
Normal file
@ -0,0 +1,74 @@
|
||||
const docx = require('../build');
|
||||
|
||||
const doc = new docx.Document({
|
||||
creator: 'Clippy',
|
||||
title: 'Sample Document',
|
||||
description: 'A brief example of using docx',
|
||||
});
|
||||
|
||||
doc.Styles.createParagraphStyle('Heading1', 'Heading 1')
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.quickFormat()
|
||||
.size(28)
|
||||
.bold()
|
||||
.italics()
|
||||
.spacing({after: 120});
|
||||
|
||||
doc.Styles.createParagraphStyle('Heading2', 'Heading 2')
|
||||
.basedOn("Normal")
|
||||
.next("Normal")
|
||||
.quickFormat()
|
||||
.size(26)
|
||||
.bold()
|
||||
.underline('double', 'FF0000')
|
||||
.spacing({before: 240, after: 120});
|
||||
|
||||
doc.Styles.createParagraphStyle('aside', 'Aside')
|
||||
.basedOn('Normal')
|
||||
.next('Normal')
|
||||
.color('999999')
|
||||
.italics()
|
||||
.indent(720)
|
||||
.spacing({line: 276});
|
||||
|
||||
doc.Styles.createParagraphStyle('wellSpaced', 'Well Spaced')
|
||||
.basedOn('Normal')
|
||||
.spacing({line: 276, before: 20 * 72 * .1, after: 20 * 72 * .05});
|
||||
|
||||
doc.Styles.createParagraphStyle('ListParagraph', 'List Paragraph')
|
||||
.quickFormat()
|
||||
.basedOn('Normal');
|
||||
|
||||
|
||||
const numberedAbstract = doc.Numbering.createAbstractNumbering();
|
||||
numberedAbstract.createLevel(0, "lowerLetter", "%1)", "left");
|
||||
|
||||
doc.createParagraph('Test heading1, bold and italicized').heading1();
|
||||
doc.createParagraph('Some simple content');
|
||||
doc.createParagraph('Test heading2 with double red underline').heading2();
|
||||
|
||||
const letterNumbering = doc.Numbering.createConcreteNumbering(numberedAbstract);
|
||||
const letterNumbering5 = doc.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);
|
||||
exporter.pack('My Document');
|
||||
|
||||
console.log('Document created successfully at project root!');
|
35
demo/demo3.js
Normal file
35
demo/demo3.js
Normal file
@ -0,0 +1,35 @@
|
||||
const docx = require('../build');
|
||||
|
||||
var doc = new docx.Document();
|
||||
|
||||
const numbering = new docx.Numbering();
|
||||
|
||||
const abstractNum = numbering.createAbstractNumbering();
|
||||
abstractNum.createLevel(0, "upperRoman", "%1", "start")
|
||||
.addParagraphProperty(new docx.Indent(720, 260));
|
||||
abstractNum.createLevel(1, "decimal", "%2.", "start")
|
||||
.addParagraphProperty(new docx.Indent(1440, 980));
|
||||
abstractNum.createLevel(2, "lowerLetter", "%3)", "start")
|
||||
.addParagraphProperty(new docx.Indent(2160, 1700));
|
||||
|
||||
const concrete = numbering.createConcreteNumbering(abstractNum);
|
||||
|
||||
var topLevelP = new docx.Paragraph("Hey you");
|
||||
var subP = new docx.Paragraph("What's up fam");
|
||||
var secondSubP = new docx.Paragraph("Hello World 2");
|
||||
var subSubP = new docx.Paragraph("Yeah boi");
|
||||
|
||||
topLevelP.setNumbering(concrete, 0);
|
||||
subP.setNumbering(concrete, 1);
|
||||
secondSubP.setNumbering(concrete, 1);
|
||||
subSubP.setNumbering(concrete, 2);
|
||||
|
||||
doc.addParagraph(topLevelP);
|
||||
doc.addParagraph(subP);
|
||||
doc.addParagraph(secondSubP);
|
||||
doc.addParagraph(subSubP);
|
||||
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
exporter.pack('My Document');
|
||||
|
||||
console.log('Document created successfully at project root!');
|
12
demo/demo4.js
Normal file
12
demo/demo4.js
Normal file
@ -0,0 +1,12 @@
|
||||
const docx = require('../build');
|
||||
|
||||
var doc = new docx.Document();
|
||||
|
||||
const table = doc.createTable(4, 4);
|
||||
table.getCell(2, 2).addContent(new docx.Paragraph('Hello'));
|
||||
|
||||
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
exporter.pack('My Document');
|
||||
|
||||
console.log('Document created successfully at project root!');
|
17
demo/demo5.js
Normal file
17
demo/demo5.js
Normal file
@ -0,0 +1,17 @@
|
||||
const docx = require('../build');
|
||||
|
||||
var doc = new docx.Document();
|
||||
|
||||
var paragraph = new docx.Paragraph("Hello World");
|
||||
doc.addParagraph(paragraph);
|
||||
|
||||
const image = doc.createImage("./demo/images/image1.jpeg");
|
||||
const image2 = doc.createImage("./demo/images/dog.png");
|
||||
const image3 = doc.createImage("./demo/images/cat.jpg");
|
||||
const image4 = doc.createImage("./demo/images/parrots.bmp");
|
||||
const image5 = doc.createImage("./demo/images/pizza.gif");
|
||||
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
exporter.pack('My Document');
|
||||
|
||||
console.log('Document created successfully at project root!');
|
25
demo/demo6.js
Normal file
25
demo/demo6.js
Normal file
@ -0,0 +1,25 @@
|
||||
const docx = require("../build");
|
||||
|
||||
var doc = new docx.Document(undefined, {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
doc.createParagraph("Hello World").heading1();
|
||||
doc.createParagraph("University College London");
|
||||
doc.createParagraph("5th Dec 2015");
|
||||
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
exporter.pack("My Document");
|
||||
|
||||
console.log("Document created successfully at project root!");
|
14
demo/demo7.js
Normal file
14
demo/demo7.js
Normal file
@ -0,0 +1,14 @@
|
||||
const docx = require("../build");
|
||||
|
||||
var doc = new docx.Document(undefined, {
|
||||
orientation: "landscape",
|
||||
});
|
||||
|
||||
var paragraph = new docx.Paragraph("Hello World");
|
||||
|
||||
doc.addParagraph(paragraph);
|
||||
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
exporter.pack("My Document");
|
||||
|
||||
console.log("Document created successfully at project root!");
|
13
demo/demo8.js
Normal file
13
demo/demo8.js
Normal file
@ -0,0 +1,13 @@
|
||||
const docx = require('../build');
|
||||
|
||||
var doc = new docx.Document();
|
||||
|
||||
doc.createParagraph("Hello World");
|
||||
|
||||
doc.Header.createParagraph("Header text");
|
||||
doc.Footer.createParagraph("Footer text");
|
||||
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
exporter.pack('My Document');
|
||||
|
||||
console.log('Document created successfully at project root!');
|
13
demo/demo9.js
Normal file
13
demo/demo9.js
Normal file
@ -0,0 +1,13 @@
|
||||
const docx = require('../build');
|
||||
|
||||
var doc = new docx.Document();
|
||||
|
||||
doc.createParagraph("Hello World");
|
||||
|
||||
doc.Header.createImage("./demo/images/pizza.gif");
|
||||
doc.Footer.createImage("./demo/images/pizza.gif");
|
||||
|
||||
var exporter = new docx.LocalPacker(doc);
|
||||
exporter.pack('My Document');
|
||||
|
||||
console.log('Document created successfully at project root!');
|
BIN
demo/images/cat.jpg
Normal file
BIN
demo/images/cat.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 154 KiB |
BIN
demo/images/dog.png
Normal file
BIN
demo/images/dog.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 190 KiB |
BIN
demo/images/image1.jpeg
Normal file
BIN
demo/images/image1.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 162 KiB |
BIN
demo/images/parrots.bmp
Normal file
BIN
demo/images/parrots.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 818 KiB |
BIN
demo/images/pizza.gif
Normal file
BIN
demo/images/pizza.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 310 KiB |
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}`);
|
||||
});
|
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.
59
package.json
59
package.json
@ -1,32 +1,55 @@
|
||||
{
|
||||
"name": "docx",
|
||||
"version": "1.0.1",
|
||||
"version": "3.2.0",
|
||||
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
|
||||
"main": "build/index.js",
|
||||
"scripts": {
|
||||
"pretest": "rimraf ./build-tests && tsc -p ts/test-tsconfig.json",
|
||||
"test": "mocha ./build-tests --recursive",
|
||||
"prepublish": "tsc -p ts"
|
||||
"pretest": "rimraf ./build",
|
||||
"test": "mocha-webpack \"src/**/*.ts\"",
|
||||
"test-watch": "mocha-webpack \"src/**/*.ts\" --watch",
|
||||
"prepublishOnly": "npm run build",
|
||||
"lint": "tslint --project .",
|
||||
"build": "npm run webpack && npm run fix-types",
|
||||
"tsc": "rimraf ./build && tsc -p .",
|
||||
"webpack": "rimraf ./build && webpack",
|
||||
"demo": "npm run build && node ./demo",
|
||||
"typedoc": "npm run build && typedoc --out docs/ src/ --module commonjs --target ES6 --disableOutputCheck",
|
||||
"style": "prettier -l --trailing-comma all --print-width 140 --arrow-parens always \"src/**/*.ts\"",
|
||||
"fix-types": "node types-absolute-fixer.js"
|
||||
},
|
||||
"files": [
|
||||
"src",
|
||||
"build",
|
||||
"template"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/dolanmiu/docx.git"
|
||||
},
|
||||
"keywords": [
|
||||
"docx",
|
||||
"office",
|
||||
"word",
|
||||
"generate",
|
||||
"creator",
|
||||
"create",
|
||||
"document",
|
||||
"doc"
|
||||
"doc",
|
||||
"officegen",
|
||||
"clippy"
|
||||
],
|
||||
"types": "./build/index.d.ts",
|
||||
"dependencies": {
|
||||
"app-root-path": "^2.0.1",
|
||||
"archiver": "^1.3.0",
|
||||
"lodash": "^4.6.1",
|
||||
"@types/archiver": "^2.1.0",
|
||||
"@types/express": "^4.0.35",
|
||||
"@types/image-size": "0.0.29",
|
||||
"@types/request-promise": "^4.1.41",
|
||||
"archiver": "^2.1.1",
|
||||
"image-size": "^0.6.2",
|
||||
"request": "^2.83.0",
|
||||
"request-promise": "^4.2.2",
|
||||
"xml": "^1.0.1"
|
||||
},
|
||||
"typescript": {
|
||||
"definition": "ts/typings/index.d.ts"
|
||||
},
|
||||
"author": "Dolan Miu",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
@ -34,9 +57,21 @@
|
||||
},
|
||||
"homepage": "https://github.com/dolanmiu/docx#readme",
|
||||
"devDependencies": {
|
||||
"@types/chai": "^3.4.35",
|
||||
"@types/mocha": "^2.2.39",
|
||||
"awesome-typescript-loader": "^3.4.1",
|
||||
"chai": "^3.5.0",
|
||||
"glob": "^7.1.2",
|
||||
"mocha": "^3.2.0",
|
||||
"mocha-webpack": "^1.0.1",
|
||||
"prettier": "^1.10.2",
|
||||
"prompt": "^1.0.0",
|
||||
"replace-in-file": "^3.1.0",
|
||||
"rimraf": "^2.5.2",
|
||||
"typescript": "^2.2.1"
|
||||
"shelljs": "^0.7.7",
|
||||
"tslint": "^5.1.0",
|
||||
"typedoc": "^0.9.0",
|
||||
"typescript": "2.6.2",
|
||||
"webpack": "^3.10.0"
|
||||
}
|
||||
}
|
||||
|
78
src/export/formatter.spec.ts
Normal file
78
src/export/formatter.spec.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import { assert } from "chai";
|
||||
|
||||
import { Formatter } from "../export/formatter";
|
||||
import * as file from "../file";
|
||||
import { CoreProperties } from "../file/core-properties";
|
||||
import { Attributes } from "../file/xml-components";
|
||||
import { Utility } from "../tests/utility";
|
||||
|
||||
describe("Formatter", () => {
|
||||
let formatter: Formatter;
|
||||
|
||||
beforeEach(() => {
|
||||
formatter = new Formatter();
|
||||
});
|
||||
|
||||
describe("#format()", () => {
|
||||
it("should format simple paragraph", () => {
|
||||
const paragraph = new file.Paragraph();
|
||||
const newJson = formatter.format(paragraph);
|
||||
assert.isDefined(newJson["w:p"]);
|
||||
});
|
||||
|
||||
it("should remove xmlKeys", () => {
|
||||
const paragraph = new file.Paragraph();
|
||||
const newJson = formatter.format(paragraph);
|
||||
const stringifiedJson = JSON.stringify(newJson);
|
||||
assert(stringifiedJson.indexOf("xmlKeys") < 0);
|
||||
});
|
||||
|
||||
it("should format simple paragraph with bold text", () => {
|
||||
const paragraph = new file.Paragraph();
|
||||
paragraph.addRun(new file.TextRun("test").bold());
|
||||
const newJson = formatter.format(paragraph);
|
||||
assert.isDefined(newJson["w:p"][1]["w:r"][0]["w:rPr"][0]["w:b"][0]._attr["w:val"]);
|
||||
});
|
||||
|
||||
it("should format attributes (rsidSect)", () => {
|
||||
const attributes = new Attributes({
|
||||
rsidSect: "test2",
|
||||
});
|
||||
let newJson = formatter.format(attributes);
|
||||
newJson = Utility.jsonify(newJson);
|
||||
if (newJson._attr === undefined) {
|
||||
assert.fail();
|
||||
return;
|
||||
}
|
||||
assert.isDefined(newJson._attr["w:rsidSect"]);
|
||||
});
|
||||
|
||||
it("should format attributes (val)", () => {
|
||||
const attributes = new Attributes({
|
||||
val: "test",
|
||||
});
|
||||
let newJson = formatter.format(attributes);
|
||||
newJson = Utility.jsonify(newJson);
|
||||
if (newJson._attr === undefined) {
|
||||
assert.fail();
|
||||
return;
|
||||
}
|
||||
assert.isDefined(newJson._attr["w:val"]);
|
||||
});
|
||||
|
||||
it("should should change 'p' tag into 'w:p' tag", () => {
|
||||
const paragraph = new file.Paragraph();
|
||||
const newJson = formatter.format(paragraph);
|
||||
assert.isDefined(newJson["w:p"]);
|
||||
});
|
||||
|
||||
it("should format Properties object correctly", () => {
|
||||
const properties = new CoreProperties({
|
||||
title: "test document",
|
||||
creator: "Dolan",
|
||||
});
|
||||
const newJson = formatter.format(properties);
|
||||
assert.isDefined(newJson["cp:coreProperties"]);
|
||||
});
|
||||
});
|
||||
});
|
7
src/export/formatter.ts
Normal file
7
src/export/formatter.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { BaseXmlComponent, IXmlableObject } from "file/xml-components";
|
||||
|
||||
export class Formatter {
|
||||
public format(input: BaseXmlComponent): IXmlableObject {
|
||||
return input.prepForXml();
|
||||
}
|
||||
}
|
3
src/export/index.ts
Normal file
3
src/export/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from "./packer/local";
|
||||
export * from "./packer/express";
|
||||
export * from "./packer/packer";
|
105
src/export/packer/compiler.ts
Normal file
105
src/export/packer/compiler.ts
Normal file
@ -0,0 +1,105 @@
|
||||
import * as archiver from "archiver";
|
||||
import * as express from "express";
|
||||
import * as fs from "fs";
|
||||
import * as xml from "xml";
|
||||
|
||||
import { File } from "file";
|
||||
import { Formatter } from "../formatter";
|
||||
|
||||
export class Compiler {
|
||||
protected archive: archiver.Archiver;
|
||||
private formatter: Formatter;
|
||||
|
||||
constructor(private file: File) {
|
||||
this.formatter = new Formatter();
|
||||
this.archive = archiver.create("zip", {});
|
||||
|
||||
this.archive.on("error", (err) => {
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
public async compile(output: fs.WriteStream | express.Response): Promise<void> {
|
||||
this.archive.pipe(output);
|
||||
|
||||
const xmlDocument = xml(this.formatter.format(this.file.Document), true);
|
||||
const xmlStyles = xml(this.formatter.format(this.file.Styles));
|
||||
const xmlProperties = xml(this.formatter.format(this.file.CoreProperties), {
|
||||
declaration: {
|
||||
standalone: "yes",
|
||||
encoding: "UTF-8",
|
||||
},
|
||||
});
|
||||
const xmlNumbering = xml(this.formatter.format(this.file.Numbering));
|
||||
const xmlRelationships = xml(this.formatter.format(this.file.DocumentRelationships));
|
||||
const xmlFileRelationships = xml(this.formatter.format(this.file.FileRelationships));
|
||||
const xmlHeader = xml(this.formatter.format(this.file.Header.Header));
|
||||
const xmlFooter = xml(this.formatter.format(this.file.Footer.Footer));
|
||||
const xmlHeaderRelationships = xml(this.formatter.format(this.file.Header.Relationships));
|
||||
const xmlFooterRelationships = xml(this.formatter.format(this.file.Footer.Relationships));
|
||||
const xmlContentTypes = xml(this.formatter.format(this.file.ContentTypes));
|
||||
const xmlAppProperties = xml(this.formatter.format(this.file.AppProperties));
|
||||
|
||||
this.archive.append(xmlDocument, {
|
||||
name: "word/document.xml",
|
||||
});
|
||||
|
||||
this.archive.append(xmlStyles, {
|
||||
name: "word/styles.xml",
|
||||
});
|
||||
|
||||
this.archive.append(xmlProperties, {
|
||||
name: "docProps/core.xml",
|
||||
});
|
||||
|
||||
this.archive.append(xmlAppProperties, {
|
||||
name: "docProps/app.xml",
|
||||
});
|
||||
|
||||
this.archive.append(xmlNumbering, {
|
||||
name: "word/numbering.xml",
|
||||
});
|
||||
|
||||
this.archive.append(xmlHeader, {
|
||||
name: "word/header1.xml",
|
||||
});
|
||||
|
||||
this.archive.append(xmlFooter, {
|
||||
name: "word/footer1.xml",
|
||||
});
|
||||
|
||||
this.archive.append(xmlRelationships, {
|
||||
name: "word/_rels/document.xml.rels",
|
||||
});
|
||||
|
||||
this.archive.append(xmlHeaderRelationships, {
|
||||
name: "word/_rels/header1.xml.rels",
|
||||
});
|
||||
|
||||
this.archive.append(xmlFooterRelationships, {
|
||||
name: "word/_rels/footer1.xml.rels",
|
||||
});
|
||||
|
||||
this.archive.append(xmlContentTypes, {
|
||||
name: "[Content_Types].xml",
|
||||
});
|
||||
|
||||
this.archive.append(xmlFileRelationships, {
|
||||
name: "_rels/.rels",
|
||||
});
|
||||
|
||||
for (const data of this.file.Media.array) {
|
||||
this.archive.append(data.stream, {
|
||||
name: `word/media/${data.fileName}`,
|
||||
});
|
||||
}
|
||||
|
||||
this.archive.finalize();
|
||||
|
||||
return new Promise<void>((resolve) => {
|
||||
output.on("close", () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
29
src/export/packer/express.ts
Normal file
29
src/export/packer/express.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import * as express from "express";
|
||||
|
||||
import { File } from "file";
|
||||
import { Compiler } from "./compiler";
|
||||
import { IPacker } from "./packer";
|
||||
|
||||
export class ExpressPacker implements IPacker {
|
||||
private readonly packer: Compiler;
|
||||
|
||||
constructor(file: File, private readonly res: express.Response) {
|
||||
this.packer = new Compiler(file);
|
||||
|
||||
this.res = res;
|
||||
|
||||
this.res.on("close", () => {
|
||||
return res
|
||||
.status(200)
|
||||
.send("OK")
|
||||
.end();
|
||||
});
|
||||
}
|
||||
|
||||
public async pack(name: string): Promise<void> {
|
||||
name = name.replace(/.docx$/, "");
|
||||
|
||||
this.res.attachment(`${name}.docx`);
|
||||
await this.packer.compile(this.res);
|
||||
}
|
||||
}
|
42
src/export/packer/local.spec.ts
Normal file
42
src/export/packer/local.spec.ts
Normal file
@ -0,0 +1,42 @@
|
||||
/* tslint:disable:typedef space-before-function-paren */
|
||||
import * as fs from "fs";
|
||||
|
||||
import { LocalPacker } from "../../export/packer/local";
|
||||
import { File, Paragraph } from "../../file";
|
||||
|
||||
describe("LocalPacker", () => {
|
||||
let packer: LocalPacker;
|
||||
|
||||
beforeEach(() => {
|
||||
const file = new File({
|
||||
creator: "Dolan Miu",
|
||||
revision: "1",
|
||||
lastModifiedBy: "Dolan Miu",
|
||||
});
|
||||
const paragraph = new Paragraph("test text");
|
||||
const heading = new Paragraph("Hello world").heading1();
|
||||
file.addParagraph(new Paragraph("title").title());
|
||||
file.addParagraph(heading);
|
||||
file.addParagraph(new Paragraph("heading 2").heading2());
|
||||
file.addParagraph(paragraph);
|
||||
|
||||
packer = new LocalPacker(file);
|
||||
});
|
||||
|
||||
describe("#pack()", () => {
|
||||
it("should create a standard docx file", async function() {
|
||||
this.timeout(99999999);
|
||||
await packer.pack("build/tests/test");
|
||||
fs.statSync("build/tests/test.docx");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#packPdf", () => {
|
||||
it("should create a standard PDF file", async function() {
|
||||
this.timeout(99999999);
|
||||
|
||||
await packer.packPdf("build/tests/pdf-test");
|
||||
fs.statSync("build/tests/pdf-test.pdf");
|
||||
});
|
||||
});
|
||||
});
|
47
src/export/packer/local.ts
Normal file
47
src/export/packer/local.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import * as fs from "fs";
|
||||
import * as os from "os";
|
||||
import * as path from "path";
|
||||
|
||||
import { File } from "../../file";
|
||||
import { Compiler } from "./compiler";
|
||||
import { IPacker } from "./packer";
|
||||
import { PdfConvertWrapper } from "./pdf-convert-wrapper";
|
||||
|
||||
export class LocalPacker implements IPacker {
|
||||
private stream: fs.WriteStream;
|
||||
private readonly pdfConverter: PdfConvertWrapper;
|
||||
private readonly packer: Compiler;
|
||||
|
||||
constructor(file: File) {
|
||||
this.pdfConverter = new PdfConvertWrapper();
|
||||
this.packer = new Compiler(file);
|
||||
}
|
||||
|
||||
public async pack(filePath: string): Promise<void> {
|
||||
filePath = filePath.replace(/.docx$/, "");
|
||||
|
||||
this.stream = fs.createWriteStream(`${filePath}.docx`);
|
||||
await this.packer.compile(this.stream);
|
||||
}
|
||||
|
||||
public async packPdf(filePath: string): Promise<void> {
|
||||
filePath = filePath.replace(/.pdf$/, "");
|
||||
|
||||
const fileName = path.basename(filePath, path.extname(filePath));
|
||||
const tempPath = path.join(os.tmpdir(), `${fileName}.docx`);
|
||||
this.stream = fs.createWriteStream(tempPath);
|
||||
await this.packer.compile(this.stream);
|
||||
const text = await this.pdfConverter.convert(tempPath);
|
||||
// const writeFile = util.promisify(fs.writeFile); --use this in future, in 3 years time. Only in node 8
|
||||
// return writeFile(`${filePath}.pdf`, text);
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
fs.writeFile(`${filePath}.pdf`, text, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
6
src/export/packer/packer.ts
Normal file
6
src/export/packer/packer.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export interface IPacker {
|
||||
pack(path: string): void;
|
||||
}
|
||||
|
||||
// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432
|
||||
export const WORKAROUND = "";
|
35
src/export/packer/pdf-convert-wrapper.ts
Normal file
35
src/export/packer/pdf-convert-wrapper.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/* tslint:disable:object-literal-key-quotes */
|
||||
// This tslint disable is needed, or it simply won't work
|
||||
import * as fs from "fs";
|
||||
import * as request from "request-promise";
|
||||
|
||||
export interface IConvertOutput {
|
||||
data: string;
|
||||
}
|
||||
|
||||
export class PdfConvertWrapper {
|
||||
public convert(filePath: string): request.RequestPromise {
|
||||
return request.post({
|
||||
url: "http://mirror1.convertonlinefree.com",
|
||||
encoding: null,
|
||||
headers: {
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36",
|
||||
},
|
||||
formData: {
|
||||
__EVENTTARGET: "",
|
||||
__EVENTARGUMENT: "",
|
||||
__VIEWSTATE: "",
|
||||
ctl00$MainContent$fu: {
|
||||
value: fs.readFileSync(filePath),
|
||||
options: {
|
||||
filename: "output.docx",
|
||||
contentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
},
|
||||
},
|
||||
ctl00$MainContent$btnConvert: "Convert",
|
||||
ctl00$MainContent$fuZip: "",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
13
src/file/app-properties/app-properties-attributes.ts
Normal file
13
src/file/app-properties/app-properties-attributes.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IAppPropertiesAttributes {
|
||||
xmlns: string;
|
||||
vt: string;
|
||||
}
|
||||
|
||||
export class AppPropertiesAttributes extends XmlAttributeComponent<IAppPropertiesAttributes> {
|
||||
protected xmlKeys = {
|
||||
xmlns: "xmlns",
|
||||
vt: "xmlns:vt",
|
||||
};
|
||||
}
|
15
src/file/app-properties/app-properties.ts
Normal file
15
src/file/app-properties/app-properties.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { AppPropertiesAttributes } from "./app-properties-attributes";
|
||||
|
||||
export class AppProperties extends XmlComponent {
|
||||
constructor() {
|
||||
super("Properties");
|
||||
|
||||
this.root.push(
|
||||
new AppPropertiesAttributes({
|
||||
xmlns: "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties",
|
||||
vt: "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes",
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
11
src/file/content-types/content-types-attributes.ts
Normal file
11
src/file/content-types/content-types-attributes.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IContentTypeAttributes {
|
||||
xmlns?: string;
|
||||
}
|
||||
|
||||
export class ContentTypeAttributes extends XmlAttributeComponent<IContentTypeAttributes> {
|
||||
protected xmlKeys = {
|
||||
xmlns: "xmlns",
|
||||
};
|
||||
}
|
34
src/file/content-types/content-types.ts
Normal file
34
src/file/content-types/content-types.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { ContentTypeAttributes } from "./content-types-attributes";
|
||||
import { Default } from "./default/default";
|
||||
import { Override } from "./override/override";
|
||||
|
||||
export class ContentTypes extends XmlComponent {
|
||||
constructor() {
|
||||
super("Types");
|
||||
|
||||
this.root.push(
|
||||
new ContentTypeAttributes({
|
||||
xmlns: "http://schemas.openxmlformats.org/package/2006/content-types",
|
||||
}),
|
||||
);
|
||||
|
||||
this.root.push(new Default("image/png", "png"));
|
||||
this.root.push(new Default("image/jpeg", "jpeg"));
|
||||
this.root.push(new Default("image/jpeg", "jpg"));
|
||||
this.root.push(new Default("image/bmp", "bmp"));
|
||||
this.root.push(new Default("image/gif", "gif"));
|
||||
this.root.push(new Default("application/vnd.openxmlformats-package.relationships+xml", "rels"));
|
||||
this.root.push(new Default("application/xml", "xml"));
|
||||
|
||||
this.root.push(
|
||||
new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", "/word/document.xml"),
|
||||
);
|
||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", "/word/header1.xml"));
|
||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", "/word/footer1.xml"));
|
||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", "/word/styles.xml"));
|
||||
this.root.push(new Override("application/vnd.openxmlformats-package.core-properties+xml", "/docProps/core.xml"));
|
||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.extended-properties+xml", "/docProps/app.xml"));
|
||||
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", "/word/numbering.xml"));
|
||||
}
|
||||
}
|
13
src/file/content-types/default/default-attributes.ts
Normal file
13
src/file/content-types/default/default-attributes.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IDefaultAttributes {
|
||||
contentType: string;
|
||||
extension?: string;
|
||||
}
|
||||
|
||||
export class DefaultAttributes extends XmlAttributeComponent<IDefaultAttributes> {
|
||||
protected xmlKeys = {
|
||||
contentType: "ContentType",
|
||||
extension: "Extension",
|
||||
};
|
||||
}
|
15
src/file/content-types/default/default.ts
Normal file
15
src/file/content-types/default/default.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { DefaultAttributes } from "./default-attributes";
|
||||
|
||||
export class Default extends XmlComponent {
|
||||
constructor(contentType: string, extension?: string) {
|
||||
super("Default");
|
||||
|
||||
this.root.push(
|
||||
new DefaultAttributes({
|
||||
contentType: contentType,
|
||||
extension: extension,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
13
src/file/content-types/override/override-attributes.ts
Normal file
13
src/file/content-types/override/override-attributes.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IOverrideAttributes {
|
||||
contentType: string;
|
||||
partName?: string;
|
||||
}
|
||||
|
||||
export class OverrideAttributes extends XmlAttributeComponent<IOverrideAttributes> {
|
||||
protected xmlKeys = {
|
||||
contentType: "ContentType",
|
||||
partName: "PartName",
|
||||
};
|
||||
}
|
15
src/file/content-types/override/override.ts
Normal file
15
src/file/content-types/override/override.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { OverrideAttributes } from "./override-attributes";
|
||||
|
||||
export class Override extends XmlComponent {
|
||||
constructor(contentType: string, partName?: string) {
|
||||
super("Override");
|
||||
|
||||
this.root.push(
|
||||
new OverrideAttributes({
|
||||
contentType: contentType,
|
||||
partName: partName,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
89
src/file/core-properties/components.ts
Normal file
89
src/file/core-properties/components.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { DocumentAttributes } from "../document/document-attributes";
|
||||
|
||||
export class Title extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("dc:title");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Subject extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("dc:subject");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Creator extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("dc:creator");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Keywords extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("cp:keywords");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Description extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("dc:description");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class LastModifiedBy extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("cp:lastModifiedBy");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export class Revision extends XmlComponent {
|
||||
constructor(value: string) {
|
||||
super("cp:revision");
|
||||
this.root.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class DateComponent extends XmlComponent {
|
||||
protected getCurrentDate(): string {
|
||||
const date = new Date();
|
||||
const year = date.getFullYear();
|
||||
const month = ("0" + (date.getMonth() + 1)).slice(-2);
|
||||
const day = ("0" + date.getDate()).slice(-2);
|
||||
const hours = ("0" + date.getHours()).slice(-2);
|
||||
const minutes = ("0" + date.getMinutes()).slice(-2);
|
||||
const seconds = ("0" + date.getSeconds()).slice(-2);
|
||||
|
||||
return year + "-" + month + "-" + day + "T" + hours + ":" + minutes + ":" + seconds + "Z";
|
||||
}
|
||||
}
|
||||
|
||||
export class Created extends DateComponent {
|
||||
constructor() {
|
||||
super("dcterms:created");
|
||||
this.root.push(
|
||||
new DocumentAttributes({
|
||||
type: "dcterms:W3CDTF",
|
||||
}),
|
||||
);
|
||||
this.root.push(this.getCurrentDate());
|
||||
}
|
||||
}
|
||||
|
||||
export class Modified extends DateComponent {
|
||||
constructor() {
|
||||
super("dcterms:modified");
|
||||
this.root.push(
|
||||
new DocumentAttributes({
|
||||
type: "dcterms:W3CDTF",
|
||||
}),
|
||||
);
|
||||
this.root.push(this.getCurrentDate());
|
||||
}
|
||||
}
|
1
src/file/core-properties/index.ts
Normal file
1
src/file/core-properties/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./properties";
|
71
src/file/core-properties/properties.spec.ts
Normal file
71
src/file/core-properties/properties.spec.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "../../export/formatter";
|
||||
import { CoreProperties } from "./properties";
|
||||
|
||||
describe("Properties", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("sets the appropriate attributes on the top-level", () => {
|
||||
const properties = new CoreProperties({});
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["cp:coreProperties"]);
|
||||
expect(tree["cp:coreProperties"]).to.be.an.instanceof(Array);
|
||||
expect(tree["cp:coreProperties"][0]).to.deep.equal({
|
||||
_attr: {
|
||||
"xmlns:cp": "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
|
||||
"xmlns:dc": "http://purl.org/dc/elements/1.1/",
|
||||
"xmlns:dcmitype": "http://purl.org/dc/dcmitype/",
|
||||
"xmlns:dcterms": "http://purl.org/dc/terms/",
|
||||
"xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should create properties with a title", () => {
|
||||
const properties = new CoreProperties({ title: "test document" });
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["cp:coreProperties"]);
|
||||
expect(tree["cp:coreProperties"]).to.be.an.instanceof(Array);
|
||||
expect(Object.keys(tree["cp:coreProperties"][0])).to.deep.equal(["_attr"]);
|
||||
expect(tree["cp:coreProperties"][1]).to.deep.equal({ "dc:title": ["test document"] });
|
||||
});
|
||||
|
||||
it("should create properties with all the attributes given", () => {
|
||||
const properties = new CoreProperties({
|
||||
title: "test document",
|
||||
subject: "test subject",
|
||||
creator: "me",
|
||||
keywords: "test docx",
|
||||
description: "testing document",
|
||||
lastModifiedBy: "the author",
|
||||
revision: "123",
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["cp:coreProperties"]);
|
||||
expect(tree["cp:coreProperties"]).to.be.an.instanceof(Array);
|
||||
const key = (obj) => Object.keys(obj)[0];
|
||||
const props = tree["cp:coreProperties"].map(key).sort();
|
||||
expect(props).to.deep.equal([
|
||||
"_attr",
|
||||
"cp:keywords",
|
||||
"cp:lastModifiedBy",
|
||||
"cp:revision",
|
||||
"dc:creator",
|
||||
"dc:description",
|
||||
"dc:subject",
|
||||
"dc:title",
|
||||
"dcterms:created",
|
||||
"dcterms:modified",
|
||||
]);
|
||||
expect(tree["cp:coreProperties"].slice(1, -2).sort((a, b) => (key(a) < key(b) ? -1 : 1))).to.deep.equal([
|
||||
{ "cp:keywords": ["test docx"] },
|
||||
{ "cp:lastModifiedBy": ["the author"] },
|
||||
{ "cp:revision": ["123"] },
|
||||
{ "dc:creator": ["me"] },
|
||||
{ "dc:description": ["testing document"] },
|
||||
{ "dc:subject": ["test subject"] },
|
||||
{ "dc:title": ["test document"] },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
51
src/file/core-properties/properties.ts
Normal file
51
src/file/core-properties/properties.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { DocumentAttributes } from "../document/document-attributes";
|
||||
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
|
||||
|
||||
export interface IPropertiesOptions {
|
||||
title?: string;
|
||||
subject?: string;
|
||||
creator?: string;
|
||||
keywords?: string;
|
||||
description?: string;
|
||||
lastModifiedBy?: string;
|
||||
revision?: string;
|
||||
}
|
||||
|
||||
export class CoreProperties extends XmlComponent {
|
||||
constructor(options: IPropertiesOptions) {
|
||||
super("cp:coreProperties");
|
||||
this.root.push(
|
||||
new DocumentAttributes({
|
||||
cp: "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
|
||||
dc: "http://purl.org/dc/elements/1.1/",
|
||||
dcterms: "http://purl.org/dc/terms/",
|
||||
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());
|
||||
}
|
||||
}
|
39
src/file/document/body/body.spec.ts
Normal file
39
src/file/document/body/body.spec.ts
Normal file
@ -0,0 +1,39 @@
|
||||
// import { assert } from "chai";
|
||||
|
||||
// import { Utility } from "../../../tests/utility";
|
||||
// import { Body } from "./";
|
||||
|
||||
describe("Body", () => {
|
||||
// let body: Body;
|
||||
|
||||
beforeEach(() => {
|
||||
// body = new Body();
|
||||
});
|
||||
|
||||
// describe("#constructor()", () => {
|
||||
// it("should create the Section Properties", () => {
|
||||
// const newJson = Utility.jsonify(body);
|
||||
// assert.equal(newJson.root[0].rootKey, "w:sectPr");
|
||||
// });
|
||||
|
||||
// it("should create the Page Size", () => {
|
||||
// const newJson = Utility.jsonify(body);
|
||||
// assert.equal(newJson.root[1].rootKey, "w:pgSz");
|
||||
// });
|
||||
|
||||
// it("should create the Page Margin", () => {
|
||||
// const newJson = Utility.jsonify(body);
|
||||
// assert.equal(newJson.root[2].rootKey, "w:pgMar");
|
||||
// });
|
||||
|
||||
// it("should create the Columns", () => {
|
||||
// const newJson = Utility.jsonify(body);
|
||||
// assert.equal(newJson.root[3].rootKey, "w:cols");
|
||||
// });
|
||||
|
||||
// it("should create the Document Grid", () => {
|
||||
// const newJson = Utility.jsonify(body);
|
||||
// assert.equal(newJson.root[4].rootKey, "w:docGrid");
|
||||
// });
|
||||
// });
|
||||
});
|
14
src/file/document/body/body.ts
Normal file
14
src/file/document/body/body.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { SectionProperties, SectionPropertiesOptions } from "./section-properties/section-properties";
|
||||
|
||||
export class Body extends XmlComponent {
|
||||
constructor(sectionPropertiesOptions?: SectionPropertiesOptions) {
|
||||
super("w:body");
|
||||
|
||||
this.root.push(new SectionProperties(sectionPropertiesOptions));
|
||||
}
|
||||
|
||||
public push(component: XmlComponent): void {
|
||||
this.root.push(component);
|
||||
}
|
||||
}
|
1
src/file/document/body/index.ts
Normal file
1
src/file/document/body/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./body";
|
@ -0,0 +1,11 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IColumnsAttributes {
|
||||
space?: number;
|
||||
}
|
||||
|
||||
export class ColumnsAttributes extends XmlAttributeComponent<IColumnsAttributes> {
|
||||
protected xmlKeys = {
|
||||
space: "w:space",
|
||||
};
|
||||
}
|
13
src/file/document/body/section-properties/columns/columns.ts
Normal file
13
src/file/document/body/section-properties/columns/columns.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { ColumnsAttributes } from "./columns-attributes";
|
||||
|
||||
export class Columns extends XmlComponent {
|
||||
constructor(space: number) {
|
||||
super("w:cols");
|
||||
this.root.push(
|
||||
new ColumnsAttributes({
|
||||
space: space,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IDocGridAttributesProperties {
|
||||
linePitch?: number;
|
||||
}
|
||||
|
||||
export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
linePitch: "w:linePitch",
|
||||
};
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { DocGridAttributes } from "./doc-grid-attributes";
|
||||
|
||||
export class DocumentGrid extends XmlComponent {
|
||||
constructor(linePitch: number) {
|
||||
super("w:docGrid");
|
||||
this.root.push(
|
||||
new DocGridAttributes({
|
||||
linePitch: linePitch,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IFooterReferenceAttributes {
|
||||
type: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export class FooterReferenceAttributes extends XmlAttributeComponent<IFooterReferenceAttributes> {
|
||||
protected xmlKeys = {
|
||||
type: "w:type",
|
||||
id: "r:id",
|
||||
};
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { FooterReferenceAttributes } from "./footer-reference-attributes";
|
||||
|
||||
export class FooterReference extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:footerReference");
|
||||
this.root.push(
|
||||
new FooterReferenceAttributes({
|
||||
type: "default",
|
||||
id: `rId${4}`,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IHeaderReferenceAttributes {
|
||||
type: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export class HeaderReferenceAttributes extends XmlAttributeComponent<IHeaderReferenceAttributes> {
|
||||
protected xmlKeys = {
|
||||
type: "w:type",
|
||||
id: "r:id",
|
||||
};
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { HeaderReferenceAttributes } from "./header-reference-attributes";
|
||||
|
||||
export class HeaderReference extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:headerReference");
|
||||
this.root.push(
|
||||
new HeaderReferenceAttributes({
|
||||
type: "default",
|
||||
id: `rId${3}`,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IPageMarginAttributes {
|
||||
top?: number;
|
||||
right?: number;
|
||||
bottom?: number;
|
||||
left?: number;
|
||||
header?: number;
|
||||
footer?: number;
|
||||
gutter?: number;
|
||||
}
|
||||
|
||||
export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttributes> {
|
||||
protected xmlKeys = {
|
||||
top: "w:top",
|
||||
right: "w:right",
|
||||
bottom: "w:bottom",
|
||||
left: "w:left",
|
||||
header: "w:header",
|
||||
footer: "w:footer",
|
||||
gutter: "w:gutter",
|
||||
};
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { PageMarginAttributes } from "./page-margin-attributes";
|
||||
|
||||
export class PageMargin extends XmlComponent {
|
||||
constructor(top: number, right: number, bottom: number, left: number, header: number, footer: number, gutter: number) {
|
||||
super("w:pgMar");
|
||||
this.root.push(
|
||||
new PageMarginAttributes({
|
||||
top: top,
|
||||
right: right,
|
||||
bottom: bottom,
|
||||
left: left,
|
||||
header: header,
|
||||
footer: footer,
|
||||
gutter: gutter,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IPageSizeAttributes {
|
||||
width?: number;
|
||||
height?: number;
|
||||
orientation?: string;
|
||||
}
|
||||
|
||||
export class PageSizeAttributes extends XmlAttributeComponent<IPageSizeAttributes> {
|
||||
protected xmlKeys = {
|
||||
width: "w:w",
|
||||
height: "w:h",
|
||||
orientation: "w:orient",
|
||||
};
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "../../../../../export/formatter";
|
||||
import { PageSize } from "./page-size";
|
||||
|
||||
describe("PageSize", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create page size with portrait", () => {
|
||||
const properties = new PageSize(100, 200, "portrait");
|
||||
const tree = new Formatter().format(properties);
|
||||
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]);
|
||||
expect(tree["w:pgSz"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:pgSz"][0]).to.deep.equal({ _attr: { "w:h": 200, "w:w": 100, "w:orient": "portrait" } });
|
||||
});
|
||||
|
||||
it("should create page size with horizontal and invert the lengths", () => {
|
||||
const properties = new PageSize(100, 200, "landscape");
|
||||
const tree = new Formatter().format(properties);
|
||||
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]);
|
||||
expect(tree["w:pgSz"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:pgSz"][0]).to.deep.equal({ _attr: { "w:h": 100, "w:w": 200, "w:orient": "landscape" } });
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,18 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { PageSizeAttributes } from "./page-size-attributes";
|
||||
|
||||
export class PageSize extends XmlComponent {
|
||||
constructor(width: number, height: number, orientation: string) {
|
||||
super("w:pgSz");
|
||||
|
||||
const flip = orientation === "landscape";
|
||||
|
||||
this.root.push(
|
||||
new PageSizeAttributes({
|
||||
width: flip ? height : width,
|
||||
height: flip ? width : height,
|
||||
orientation: orientation,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "../../../../export/formatter";
|
||||
import { SectionProperties } from "./section-properties";
|
||||
|
||||
describe("SectionProperties", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create section properties with options", () => {
|
||||
const properties = new SectionProperties({
|
||||
width: 11906,
|
||||
height: 16838,
|
||||
top: 1440,
|
||||
right: 1440,
|
||||
bottom: 1440,
|
||||
left: 1440,
|
||||
header: 708,
|
||||
footer: 708,
|
||||
gutter: 0,
|
||||
space: 708,
|
||||
linePitch: 360,
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } }] });
|
||||
expect(tree["w:sectPr"][1]).to.deep.equal({
|
||||
"w:pgMar": [
|
||||
{
|
||||
_attr: {
|
||||
"w:bottom": 1440,
|
||||
"w:footer": 708,
|
||||
"w:top": 1440,
|
||||
"w:right": 1440,
|
||||
"w:left": 1440,
|
||||
"w:header": 708,
|
||||
"w:gutter": 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should create section properties with no options", () => {
|
||||
const properties = new SectionProperties();
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } }] });
|
||||
expect(tree["w:sectPr"][1]).to.deep.equal({
|
||||
"w:pgMar": [
|
||||
{
|
||||
_attr: {
|
||||
"w:bottom": 1440,
|
||||
"w:footer": 708,
|
||||
"w:top": 1440,
|
||||
"w:right": 1440,
|
||||
"w:left": 1440,
|
||||
"w:header": 708,
|
||||
"w:gutter": 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should create section properties with changed options", () => {
|
||||
const properties = new SectionProperties({
|
||||
top: 0,
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } }] });
|
||||
expect(tree["w:sectPr"][1]).to.deep.equal({
|
||||
"w:pgMar": [
|
||||
{
|
||||
_attr: {
|
||||
"w:bottom": 1440,
|
||||
"w:footer": 708,
|
||||
"w:top": 0,
|
||||
"w:right": 1440,
|
||||
"w:left": 1440,
|
||||
"w:header": 708,
|
||||
"w:gutter": 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should create section properties with changed options", () => {
|
||||
const properties = new SectionProperties({
|
||||
bottom: 0,
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } }] });
|
||||
expect(tree["w:sectPr"][1]).to.deep.equal({
|
||||
"w:pgMar": [
|
||||
{
|
||||
_attr: {
|
||||
"w:bottom": 0,
|
||||
"w:footer": 708,
|
||||
"w:top": 1440,
|
||||
"w:right": 1440,
|
||||
"w:left": 1440,
|
||||
"w:header": 708,
|
||||
"w:gutter": 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should create section properties with changed options", () => {
|
||||
const properties = new SectionProperties({
|
||||
width: 0,
|
||||
height: 0,
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
|
||||
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 0, "w:w": 0, "w:orient": "portrait" } }] });
|
||||
expect(tree["w:sectPr"][1]).to.deep.equal({
|
||||
"w:pgMar": [
|
||||
{
|
||||
_attr: {
|
||||
"w:bottom": 1440,
|
||||
"w:footer": 708,
|
||||
"w:top": 1440,
|
||||
"w:right": 1440,
|
||||
"w:left": 1440,
|
||||
"w:header": 708,
|
||||
"w:gutter": 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,57 @@
|
||||
// http://officeopenxml.com/WPsection.php
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { Columns } from "./columns/columns";
|
||||
import { IColumnsAttributes } from "./columns/columns-attributes";
|
||||
import { DocumentGrid } from "./doc-grid/doc-grid";
|
||||
import { IDocGridAttributesProperties } from "./doc-grid/doc-grid-attributes";
|
||||
import { FooterReference } from "./footer-reference/footer-reference";
|
||||
import { HeaderReference } from "./header-reference/header-reference";
|
||||
import { PageMargin } from "./page-margin/page-margin";
|
||||
import { IPageMarginAttributes } from "./page-margin/page-margin-attributes";
|
||||
import { PageSize } from "./page-size/page-size";
|
||||
import { IPageSizeAttributes } from "./page-size/page-size-attributes";
|
||||
|
||||
export type SectionPropertiesOptions = IPageSizeAttributes & IPageMarginAttributes & IColumnsAttributes & IDocGridAttributesProperties;
|
||||
|
||||
export class SectionProperties extends XmlComponent {
|
||||
constructor(options?: SectionPropertiesOptions) {
|
||||
super("w:sectPr");
|
||||
|
||||
const defaultOptions = {
|
||||
width: 11906,
|
||||
height: 16838,
|
||||
top: 1440,
|
||||
right: 1440,
|
||||
bottom: 1440,
|
||||
left: 1440,
|
||||
header: 708,
|
||||
footer: 708,
|
||||
gutter: 0,
|
||||
space: 708,
|
||||
linePitch: 360,
|
||||
orientation: "portrait",
|
||||
};
|
||||
|
||||
const mergedOptions = {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
};
|
||||
|
||||
this.root.push(new PageSize(mergedOptions.width, mergedOptions.height, mergedOptions.orientation));
|
||||
this.root.push(
|
||||
new PageMargin(
|
||||
mergedOptions.top,
|
||||
mergedOptions.right,
|
||||
mergedOptions.bottom,
|
||||
mergedOptions.left,
|
||||
mergedOptions.header,
|
||||
mergedOptions.footer,
|
||||
mergedOptions.gutter,
|
||||
),
|
||||
);
|
||||
this.root.push(new Columns(mergedOptions.space));
|
||||
this.root.push(new DocumentGrid(mergedOptions.linePitch));
|
||||
this.root.push(new HeaderReference());
|
||||
this.root.push(new FooterReference());
|
||||
}
|
||||
}
|
55
src/file/document/document-attributes.ts
Normal file
55
src/file/document/document-attributes.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IDocumentAttributesProperties {
|
||||
wpc?: string;
|
||||
mc?: string;
|
||||
o?: string;
|
||||
r?: string;
|
||||
m?: string;
|
||||
v?: string;
|
||||
wp14?: string;
|
||||
wp?: string;
|
||||
w10?: string;
|
||||
w?: string;
|
||||
w14?: string;
|
||||
w15?: string;
|
||||
wpg?: string;
|
||||
wpi?: string;
|
||||
wne?: string;
|
||||
wps?: string;
|
||||
Ignorable?: string;
|
||||
cp?: string;
|
||||
dc?: string;
|
||||
dcterms?: string;
|
||||
dcmitype?: string;
|
||||
xsi?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export class DocumentAttributes extends XmlAttributeComponent<IDocumentAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
wpc: "xmlns:wpc",
|
||||
mc: "xmlns:mc",
|
||||
o: "xmlns:o",
|
||||
r: "xmlns:r",
|
||||
m: "xmlns:m",
|
||||
v: "xmlns:v",
|
||||
wp14: "xmlns:wp14",
|
||||
wp: "xmlns:wp",
|
||||
w10: "xmlns:w10",
|
||||
w: "xmlns:w",
|
||||
w14: "xmlns:w14",
|
||||
w15: "xmlns:w15",
|
||||
wpg: "xmlns:wpg",
|
||||
wpi: "xmlns:wpi",
|
||||
wne: "xmlns:wne",
|
||||
wps: "xmlns:wps",
|
||||
Ignorable: "mc:Ignorable",
|
||||
cp: "xmlns:cp",
|
||||
dc: "xmlns:dc",
|
||||
dcterms: "xmlns:dcterms",
|
||||
dcmitype: "xmlns:dcmitype",
|
||||
xsi: "xmlns:xsi",
|
||||
type: "xsi:type",
|
||||
};
|
||||
}
|
83
src/file/document/document.spec.ts
Normal file
83
src/file/document/document.spec.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { assert, expect } from "chai";
|
||||
|
||||
import { Formatter } from "../../export/formatter";
|
||||
import { Paragraph } from "../paragraph";
|
||||
import { Table } from "../table";
|
||||
import { Document } from "./document";
|
||||
|
||||
describe("Document", () => {
|
||||
let document: Document;
|
||||
|
||||
beforeEach(() => {
|
||||
document = new Document();
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create valid JSON", () => {
|
||||
const stringifiedJson = JSON.stringify(document);
|
||||
|
||||
try {
|
||||
JSON.parse(stringifiedJson);
|
||||
} catch (e) {
|
||||
assert.isTrue(false);
|
||||
}
|
||||
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(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[1]).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(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[1])
|
||||
.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(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[1]).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[1])
|
||||
.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[1]["w:tbl"].filter((x) => x["w:tr"])).to.have.length(2);
|
||||
});
|
||||
});
|
||||
});
|
73
src/file/document/document.ts
Normal file
73
src/file/document/document.ts
Normal file
@ -0,0 +1,73 @@
|
||||
// http://officeopenxml.com/WPdocument.php
|
||||
import { IMediaData } from "file/media";
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { Paragraph, PictureRun } from "../paragraph";
|
||||
import { Table } from "../table";
|
||||
import { Body } from "./body";
|
||||
import { SectionPropertiesOptions } from "./body/section-properties/section-properties";
|
||||
import { DocumentAttributes } from "./document-attributes";
|
||||
|
||||
export class Document extends XmlComponent {
|
||||
private readonly body: Body;
|
||||
|
||||
constructor(sectionPropertiesOptions?: SectionPropertiesOptions) {
|
||||
super("w:document");
|
||||
this.root.push(
|
||||
new DocumentAttributes({
|
||||
wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
|
||||
mc: "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
||||
o: "urn:schemas-microsoft-com:office:office",
|
||||
r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
||||
m: "http://schemas.openxmlformats.org/officeDocument/2006/math",
|
||||
v: "urn:schemas-microsoft-com:vml",
|
||||
wp14: "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
|
||||
wp: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
|
||||
w10: "urn:schemas-microsoft-com:office:word",
|
||||
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",
|
||||
wpg: "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
|
||||
wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
|
||||
wne: "http://schemas.microsoft.com/office/word/2006/wordml",
|
||||
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
|
||||
Ignorable: "w14 w15 wp14",
|
||||
}),
|
||||
);
|
||||
this.body = new Body(sectionPropertiesOptions);
|
||||
this.root.push(this.body);
|
||||
}
|
||||
|
||||
public addParagraph(paragraph: Paragraph): void {
|
||||
this.body.push(paragraph);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public addDrawing(imageData: IMediaData): void {
|
||||
const paragraph = new Paragraph();
|
||||
const run = new PictureRun(imageData);
|
||||
paragraph.addRun(run);
|
||||
|
||||
this.body.push(paragraph);
|
||||
}
|
||||
|
||||
public createDrawing(imageData: IMediaData): void {
|
||||
this.addDrawing(imageData);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
1
src/file/document/index.ts
Normal file
1
src/file/document/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./document";
|
37
src/file/drawing/drawing.spec.ts
Normal file
37
src/file/drawing/drawing.spec.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { assert } from "chai";
|
||||
import * as fs from "fs";
|
||||
|
||||
import { Utility } from "../../tests/utility";
|
||||
import { Drawing } from "./";
|
||||
|
||||
describe("Drawing", () => {
|
||||
let currentBreak: Drawing;
|
||||
|
||||
beforeEach(() => {
|
||||
const path = "./demo/images/image1.jpeg";
|
||||
currentBreak = new Drawing({
|
||||
fileName: "test.jpg",
|
||||
referenceId: 1,
|
||||
stream: fs.createReadStream(path),
|
||||
path: path,
|
||||
dimensions: {
|
||||
pixels: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
},
|
||||
emus: {
|
||||
x: 100 * 9525,
|
||||
y: 100 * 9525,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
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));
|
||||
});
|
||||
});
|
||||
});
|
15
src/file/drawing/drawing.ts
Normal file
15
src/file/drawing/drawing.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { IMediaData } from "file/media";
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { Inline } from "./inline";
|
||||
|
||||
export class Drawing extends XmlComponent {
|
||||
constructor(imageData: IMediaData) {
|
||||
super("w:drawing");
|
||||
|
||||
if (imageData === undefined) {
|
||||
throw new Error("imageData cannot be undefined");
|
||||
}
|
||||
|
||||
this.root.push(new Inline(imageData.referenceId, imageData.dimensions));
|
||||
}
|
||||
}
|
1
src/file/drawing/index.ts
Normal file
1
src/file/drawing/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Drawing } from "./drawing";
|
@ -0,0 +1,15 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IDocPropertiesAttributes {
|
||||
id?: number;
|
||||
name?: string;
|
||||
descr?: string;
|
||||
}
|
||||
|
||||
export class DocPropertiesAttributes extends XmlAttributeComponent<IDocPropertiesAttributes> {
|
||||
protected xmlKeys = {
|
||||
id: "id",
|
||||
name: "name",
|
||||
descr: "descr",
|
||||
};
|
||||
}
|
16
src/file/drawing/inline/doc-properties/doc-properties.ts
Normal file
16
src/file/drawing/inline/doc-properties/doc-properties.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { DocPropertiesAttributes } from "./doc-properties-attributes";
|
||||
|
||||
export class DocProperties extends XmlComponent {
|
||||
constructor() {
|
||||
super("wp:docPr");
|
||||
|
||||
this.root.push(
|
||||
new DocPropertiesAttributes({
|
||||
id: 0,
|
||||
name: "",
|
||||
descr: "",
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IEffectExtentAttributes {
|
||||
b?: number;
|
||||
l?: number;
|
||||
r?: number;
|
||||
t?: number;
|
||||
}
|
||||
|
||||
export class EffectExtentAttributes extends XmlAttributeComponent<IEffectExtentAttributes> {
|
||||
protected xmlKeys = {
|
||||
b: "b",
|
||||
l: "l",
|
||||
r: "r",
|
||||
t: "t",
|
||||
};
|
||||
}
|
17
src/file/drawing/inline/effect-extent/effect-extent.ts
Normal file
17
src/file/drawing/inline/effect-extent/effect-extent.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { EffectExtentAttributes } from "./effect-extent-attributes";
|
||||
|
||||
export class EffectExtent extends XmlComponent {
|
||||
constructor() {
|
||||
super("wp:effectExtent");
|
||||
|
||||
this.root.push(
|
||||
new EffectExtentAttributes({
|
||||
b: 0,
|
||||
l: 0,
|
||||
r: 0,
|
||||
t: 0,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
13
src/file/drawing/inline/extent/extent-attributes.ts
Normal file
13
src/file/drawing/inline/extent/extent-attributes.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IExtentAttributes {
|
||||
cx?: number;
|
||||
cy?: number;
|
||||
}
|
||||
|
||||
export class ExtentAttributes extends XmlAttributeComponent<IExtentAttributes> {
|
||||
protected xmlKeys = {
|
||||
cx: "cx",
|
||||
cy: "cy",
|
||||
};
|
||||
}
|
15
src/file/drawing/inline/extent/extent.ts
Normal file
15
src/file/drawing/inline/extent/extent.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { ExtentAttributes } from "./extent-attributes";
|
||||
|
||||
export class Extent extends XmlComponent {
|
||||
constructor(x: number, y: number) {
|
||||
super("wp:extent");
|
||||
|
||||
this.root.push(
|
||||
new ExtentAttributes({
|
||||
cx: x,
|
||||
cy: y,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IGraphicFrameLockAttributes {
|
||||
xmlns?: string;
|
||||
noChangeAspect?: number;
|
||||
}
|
||||
|
||||
export class GraphicFrameLockAttributes extends XmlAttributeComponent<IGraphicFrameLockAttributes> {
|
||||
protected xmlKeys = {
|
||||
xmlns: "xmlns:a",
|
||||
noChangeAspect: "noChangeAspect",
|
||||
};
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { GraphicFrameLockAttributes } from "./graphic-frame-lock-attributes";
|
||||
|
||||
export class GraphicFrameLocks extends XmlComponent {
|
||||
constructor() {
|
||||
super("a:graphicFrameLocks");
|
||||
|
||||
this.root.push(
|
||||
new GraphicFrameLockAttributes({
|
||||
xmlns: "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||
noChangeAspect: 1,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { GraphicFrameLocks } from "./graphic-frame-locks/graphic-frame-locks";
|
||||
|
||||
export class GraphicFrameProperties extends XmlComponent {
|
||||
constructor() {
|
||||
super("wp:cNvGraphicFramePr");
|
||||
|
||||
this.root.push(new GraphicFrameLocks());
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IGraphicDataAttributes {
|
||||
uri?: string;
|
||||
}
|
||||
|
||||
export class GraphicDataAttributes extends XmlAttributeComponent<IGraphicDataAttributes> {
|
||||
protected xmlKeys = {
|
||||
uri: "uri",
|
||||
};
|
||||
}
|
17
src/file/drawing/inline/graphic/graphic-data/graphic-data.ts
Normal file
17
src/file/drawing/inline/graphic/graphic-data/graphic-data.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { GraphicDataAttributes } from "./graphic-data-attribute";
|
||||
import { Pic } from "./pic";
|
||||
|
||||
export class GraphicData extends XmlComponent {
|
||||
constructor(referenceId: number, x: number, y: number) {
|
||||
super("a:graphicData");
|
||||
|
||||
this.root.push(
|
||||
new GraphicDataAttributes({
|
||||
uri: "http://schemas.openxmlformats.org/drawingml/2006/picture",
|
||||
}),
|
||||
);
|
||||
|
||||
this.root.push(new Pic(referenceId, x, y));
|
||||
}
|
||||
}
|
1
src/file/drawing/inline/graphic/graphic-data/index.ts
Normal file
1
src/file/drawing/inline/graphic/graphic-data/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./graphic-data";
|
@ -0,0 +1,13 @@
|
||||
import { XmlComponent } from "file/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,25 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
interface IBlipProperties {
|
||||
embed: string;
|
||||
cstate: string;
|
||||
}
|
||||
|
||||
class BlipAttributes extends XmlAttributeComponent<IBlipProperties> {
|
||||
protected xmlKeys = {
|
||||
embed: "r:embed",
|
||||
cstate: "cstate",
|
||||
};
|
||||
}
|
||||
|
||||
export class Blip extends XmlComponent {
|
||||
constructor(referenceId: number) {
|
||||
super("a:blip");
|
||||
this.root.push(
|
||||
new BlipAttributes({
|
||||
embed: `rId${referenceId}`,
|
||||
cstate: "none",
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
export class SourceRectangle extends XmlComponent {
|
||||
constructor() {
|
||||
super("a:srcRect");
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import { XmlComponent } from "file/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 @@
|
||||
export * from "./pic";
|
@ -0,0 +1,10 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { PicLocks } from "./pic-locks/pic-locks";
|
||||
|
||||
export class ChildNonVisualProperties extends XmlComponent {
|
||||
constructor() {
|
||||
super("pic:cNvPicPr");
|
||||
|
||||
this.root.push(new PicLocks());
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IPicLocksAttributes {
|
||||
noChangeAspect?: number;
|
||||
noChangeArrowheads?: number;
|
||||
}
|
||||
|
||||
export class PicLocksAttributes extends XmlAttributeComponent<IPicLocksAttributes> {
|
||||
protected xmlKeys = {
|
||||
noChangeAspect: "noChangeAspect",
|
||||
noChangeArrowheads: "noChangeArrowheads",
|
||||
};
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { PicLocksAttributes } from "./pic-locks-attributes";
|
||||
|
||||
export class PicLocks extends XmlComponent {
|
||||
constructor() {
|
||||
super("a:picLocks");
|
||||
this.root.push(
|
||||
new PicLocksAttributes({
|
||||
noChangeAspect: 1,
|
||||
noChangeArrowheads: 1,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { ChildNonVisualProperties } from "./child-non-visual-pic-properties/child-non-visual-pic-properties";
|
||||
import { NonVisualProperties } from "./non-visual-properties/non-visual-properties";
|
||||
|
||||
export class NonVisualPicProperties extends XmlComponent {
|
||||
constructor() {
|
||||
super("pic:nvPicPr");
|
||||
|
||||
this.root.push(new NonVisualProperties());
|
||||
this.root.push(new ChildNonVisualProperties());
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface INonVisualPropertiesAttributes {
|
||||
id?: number;
|
||||
name?: string;
|
||||
descr?: string;
|
||||
}
|
||||
|
||||
export class NonVisualPropertiesAttributes extends XmlAttributeComponent<INonVisualPropertiesAttributes> {
|
||||
protected xmlKeys = {
|
||||
id: "id",
|
||||
name: "name",
|
||||
descr: "desc",
|
||||
};
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { NonVisualPropertiesAttributes } from "./non-visual-properties-attributes";
|
||||
|
||||
export class NonVisualProperties extends XmlComponent {
|
||||
constructor() {
|
||||
super("pic:cNvPr");
|
||||
|
||||
this.root.push(
|
||||
new NonVisualPropertiesAttributes({
|
||||
id: 0,
|
||||
name: "",
|
||||
descr: "",
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IPicAttributes {
|
||||
xmlns?: string;
|
||||
}
|
||||
|
||||
export class PicAttributes extends XmlAttributeComponent<IPicAttributes> {
|
||||
protected xmlKeys = {
|
||||
xmlns: "xmlns:pic",
|
||||
};
|
||||
}
|
21
src/file/drawing/inline/graphic/graphic-data/pic/pic.ts
Normal file
21
src/file/drawing/inline/graphic/graphic-data/pic/pic.ts
Normal file
@ -0,0 +1,21 @@
|
||||
// http://officeopenxml.com/drwPic.php
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { BlipFill } from "./blip/blip-fill";
|
||||
import { NonVisualPicProperties } from "./non-visual-pic-properties/non-visual-pic-properties";
|
||||
import { PicAttributes } from "./pic-attributes";
|
||||
import { ShapeProperties } from "./shape-properties/shape-properties";
|
||||
|
||||
export class Pic extends XmlComponent {
|
||||
constructor(referenceId: number, x: number, y: number) {
|
||||
super("pic:pic");
|
||||
|
||||
this.root.push(
|
||||
new PicAttributes({
|
||||
xmlns: "http://schemas.openxmlformats.org/drawingml/2006/picture",
|
||||
}),
|
||||
);
|
||||
this.root.push(new NonVisualPicProperties());
|
||||
this.root.push(new BlipFill(referenceId));
|
||||
this.root.push(new ShapeProperties(x, y));
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IExtentsAttributes {
|
||||
cx?: number;
|
||||
cy?: number;
|
||||
}
|
||||
|
||||
export class ExtentsAttributes extends XmlAttributeComponent<IExtentsAttributes> {
|
||||
protected xmlKeys = {
|
||||
cx: "cx",
|
||||
cy: "cy",
|
||||
};
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
// http://officeopenxml.com/drwSp-size.php
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { ExtentsAttributes } from "./extents-attributes";
|
||||
|
||||
export class Extents extends XmlComponent {
|
||||
constructor(x: number, y: number) {
|
||||
super("a:ext");
|
||||
|
||||
this.root.push(
|
||||
new ExtentsAttributes({
|
||||
cx: x,
|
||||
cy: y,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
// http://officeopenxml.com/drwSp-size.php
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { Extents } from "./extents/extents";
|
||||
import { Offset } from "./offset/off";
|
||||
|
||||
export class Form extends XmlComponent {
|
||||
constructor(x: number, y: number) {
|
||||
super("a:xfrm");
|
||||
|
||||
this.root.push(new Extents(x, y));
|
||||
this.root.push(new Offset());
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export * from "./form";
|
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IOffsetAttributes {
|
||||
x?: number;
|
||||
y?: number;
|
||||
}
|
||||
|
||||
export class OffsetAttributes extends XmlAttributeComponent<IOffsetAttributes> {
|
||||
protected xmlKeys = {
|
||||
x: "x",
|
||||
y: "y",
|
||||
};
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user