Compare commits

...

182 Commits
2.0.1 ... 3.2.0

Author SHA1 Message Date
cb8e9fdd36 Version bump 2018-02-08 01:19:00 +00:00
53ce3c1526 Formatting 2018-02-08 00:52:05 +00:00
a78f06b41b Remove all references to template 2018-02-08 00:12:59 +00:00
ce7ef30806 Fix Prettier styling changes 2018-02-05 01:44:28 +00:00
fd93c0776a Fix tests 2018-02-04 01:43:10 +00:00
6a762c6c0e Rename properties to core properties 2018-02-04 01:43:03 +00:00
23c5aef276 Add file relationships 2018-02-04 00:58:34 +00:00
69707a7207 Add more content type files 2018-02-03 20:56:20 +00:00
cfd3505414 Add content types initial files 2018-02-02 01:57:50 +00:00
ee958dc351 Fix exported type definitions 2018-02-02 01:56:08 +00:00
680f2325a3 Pin typescript version 2018-02-01 00:16:00 +00:00
2f0ad3eeb2 Add and fix tests 2018-01-31 23:24:55 +00:00
c895a9c7d9 Version bump 2018-01-31 21:10:15 +00:00
388a8404f5 Rename for further workaround 2018-01-31 20:12:09 +00:00
320cb1c418 Add workaround for files which only have an interface 2018-01-31 20:08:36 +00:00
8a6b73915f Update typescript 2018-01-31 19:09:30 +00:00
774355d608 Fix tests 2018-01-31 01:23:13 +00:00
35dbce3a68 Add File alias to Document for backwards compatability 2018-01-31 00:32:13 +00:00
6d0a267ba4 Add Header and Footer wrapper for their own relationship classes 2018-01-31 00:31:54 +00:00
df701be572 Merge pull request #58 from dolanmiu/feat/update-archiver
Update dependency
2018-01-30 01:47:20 +00:00
1edad47e6e Update dependency 2018-01-30 01:43:17 +00:00
c873abfe18 Fix referenceId +1 error and spelling mistakes
Add demo
2018-01-30 01:16:48 +00:00
989446ef36 Add tests 2018-01-29 23:09:54 +00:00
fc6daed620 Merge pull request #57 from dolanmiu/feat/footer
Add footer
2018-01-29 22:00:12 +00:00
5e921f1dfc Add footer 2018-01-29 21:53:22 +00:00
45bbf1b693 Merge pull request #56 from dolanmiu/feat/header
Feat/header
2018-01-29 03:00:07 +00:00
8b8c664f0f Add header objects and demo 2018-01-29 02:56:35 +00:00
079334f71b Make fields readonly 2018-01-29 01:55:25 +00:00
3fe0c76d54 Add header to type 2018-01-29 01:54:50 +00:00
1e55a3e6a8 Expose header 2018-01-29 01:54:10 +00:00
950a2f8b53 Add header class 2018-01-28 22:32:51 +00:00
bbe2e1e46e Fix styles 2018-01-28 20:34:49 +00:00
635c58c131 Fix tests 2018-01-28 20:23:30 +00:00
ba39d806b7 Add more demos to CI 2018-01-25 01:50:30 +00:00
355e97cb5e Landscape mode 2018-01-25 01:47:47 +00:00
4339f8cfc0 Add section properties 2018-01-25 01:21:03 +00:00
448572d7a1 Add section properties to root File 2018-01-24 13:09:34 +00:00
2132c7b6da Add watch to tests 2018-01-24 13:08:34 +00:00
d0bd83d6c5 Fix tests 2018-01-24 13:08:22 +00:00
1037b7c23d Merge branch 'master' of https://github.com/dolanmiu/docx 2018-01-24 00:04:29 +00:00
df197f73ea Create section properties section 2018-01-24 00:01:38 +00:00
ea08f603f5 Add build command before demos 2018-01-23 11:28:27 +00:00
fa2f1235f7 Run each demo in test 2018-01-23 11:24:44 +00:00
ff5d02c964 Add prettier badge 2018-01-23 01:36:27 +00:00
e93d6799fd Made project Prettier compliant 2018-01-23 01:33:12 +00:00
f2027230a0 Add prettier + style command 2018-01-22 23:38:49 +00:00
cb47d4f772 Merge pull request #55 from dolanmiu/feat/file-wrapper
Feat/file wrapper
2018-01-22 23:07:05 +00:00
eebc9fbcfa Merge pull request #51 from dolanmiu/feat/images
Feat/images support
2018-01-22 22:40:23 +00:00
0e698491f3 Merge pull request #52 from dolanmiu/feat/file-wrapper
Feat/file wrapper
2018-01-22 22:40:00 +00:00
ae52e8fabb Add gif support 2018-01-22 22:17:17 +00:00
ccd655ef8b Add support for jpg and bmp 2018-01-22 22:12:33 +00:00
3dc6e71aaf Add png support 2018-01-22 22:05:20 +00:00
e6d3577f74 Rename penguin 2018-01-22 21:34:09 +00:00
ef05024f2f Add image dimensions 2018-01-22 20:42:57 +00:00
d3bc784248 Add types to image-size 2018-01-22 20:42:33 +00:00
979701331e Install image-size 2018-01-22 19:34:30 +00:00
76b1682296 Put media in correct location 2018-01-22 00:53:22 +00:00
7c31b72f99 Got docx not crashing when adding image 2018-01-16 01:31:47 +00:00
f7c2072cff Progress on embeddding image 2018-01-16 00:43:00 +00:00
392db1cd11 Add more graphic files 2018-01-12 00:12:39 +00:00
ca244bcfe1 Add more files for creating a drawing 2018-01-11 01:47:09 +00:00
2d02f51f25 Offset reference id a little 2018-01-10 00:35:26 +00:00
592fb5ca9f Add dynamic relationships 2018-01-10 00:29:17 +00:00
a3945bc7f1 Media addMedia method 2018-01-09 21:57:10 +00:00
2adde9830c Add image demo 2018-01-09 21:54:48 +00:00
0355afe11c Rename IData to something more reasonable 2017-12-30 21:18:55 +00:00
998fe3f370 Made index into barrel and made seperate drawing file 2017-12-30 20:59:05 +00:00
eb71fc20e6 Use absolute path rather than silly relative path 2017-12-30 20:25:16 +00:00
ab348bd5f9 Add build before typedoc 2017-12-30 20:02:44 +00:00
c518d1c6c7 Fix tests using new mocha-webpack 2017-12-30 20:01:20 +00:00
d8d16b4a7d Absolute path imports! 2017-12-29 02:26:26 +00:00
928e4b9bc2 Turn off sourceRoot to hotfix typedoc 2017-12-29 02:06:44 +00:00
4f900d6566 Update typedoc 2017-12-29 02:05:34 +00:00
362a997187 Redundant library specification 2017-12-29 01:48:46 +00:00
89c658746d Use webpack as the main builder 2017-12-29 01:46:31 +00:00
75d699f7ef Enable dirname 2017-12-29 01:45:33 +00:00
f7412690b6 Fix library export 2017-12-29 01:36:42 +00:00
ece2b23407 Export as a library 2017-12-29 01:16:45 +00:00
f84af9a44b Move tsconfig files to root, and made webpack config build 2017-12-29 01:11:59 +00:00
90dc1103f6 Experimental webpack support 2017-12-22 16:49:25 +00:00
c469fb24db Fix imports 2017-12-20 01:41:53 +00:00
32be6e36da Add package-lock to ignore 2017-12-20 01:41:32 +00:00
b34ad22ad6 Add editorconfig 2017-12-20 01:40:52 +00:00
2358139a6b Change docx folder to more appropriate "file" folder 2017-12-20 01:03:20 +00:00
43ebfe7a2f Move properties to sub folder 2017-12-20 00:58:24 +00:00
0b8094dea8 Move styles to sub folder 2017-12-20 00:52:41 +00:00
f1d1570b10 Move relationships to sub folder 2017-12-20 00:09:01 +00:00
e9e68bc802 Move media to sub folder 2017-12-20 00:06:08 +00:00
4c369510ce Move numbering into sub folder 2017-12-20 00:01:23 +00:00
96413d6c47 Fix lint 2017-12-19 23:14:23 +00:00
df6c7cf19f Re-order package 2017-12-19 23:13:11 +00:00
49fc28d86c Updated demos 2017-12-19 21:49:44 +00:00
cc67a83ce8 For importing absolute path in future 2017-12-19 21:42:17 +00:00
742e2b5089 Make compiler take in a file 2017-12-15 02:15:44 +00:00
d19ff1e300 Add file class 2017-12-15 01:16:04 +00:00
01950ed443 Move ts to src folder for standards 2017-12-15 00:01:59 +00:00
cf1689a3c2 Version bump 2017-12-06 01:39:40 +00:00
66d0bab0a5 Add packPdf reference 2017-12-06 01:39:24 +00:00
5889f20f1e Simplify tests and made compile async 2017-12-06 01:32:57 +00:00
ebec10e312 Refactor 2017-12-06 01:03:14 +00:00
ae8a0c7fd0 Edit Tslint 2017-12-05 23:43:19 +00:00
bb49200fad Clean up code using request promise 2017-12-05 02:24:49 +00:00
a6bba0bc6c Enable pdf export 2017-12-05 00:16:21 +00:00
fb08f79344 Add initial conversion 2017-11-10 14:27:57 +00:00
741c74825e Class definition for Pdf converter wrapper 2017-09-30 18:23:02 +01:00
28539cd47b Initial scaffold of pdf convert 2017-09-30 18:15:33 +01:00
8ca7c5a343 Add test 2017-09-30 18:00:06 +01:00
32b56e7071 Move sub components of Paragraph into own folder 2017-09-30 01:52:37 +01:00
7dad717952 Add documentation links 2017-09-22 14:46:19 +01:00
34e928755f Add documentation links 2017-09-21 14:56:46 +01:00
51e0f311fe Refactor numbering into its own file 2017-09-20 13:37:39 +01:00
cc9dff6b94 Version bump 2017-09-19 16:02:32 +01:00
101cc0fdea Add docx keyword to package 2017-09-19 16:02:06 +01:00
d408262fa8 Remove unused class 2017-09-19 15:58:37 +01:00
ed53c30f42 Remove template file and placed in the Wiki
https://github.com/dolanmiu/docx/wiki/Contributing-Guidelines
2017-09-19 15:56:52 +01:00
ebbf6a99c1 Make exporting more consistent 2017-09-19 15:51:55 +01:00
b98c103e45 Export table into own file 2017-09-19 15:49:27 +01:00
518fec0595 Export like standard style 2017-09-19 15:47:29 +01:00
659936f3f0 Refactor xml component into own class 2017-09-19 15:46:20 +01:00
b0febf5054 Refactor run into own file 2017-09-19 15:42:40 +01:00
56b951a2b1 Refactor body into own file 2017-09-19 15:39:14 +01:00
a3a9958a69 Refactor document into own file 2017-09-19 15:36:41 +01:00
4f36bbf426 Refactor paragraph into its own file
Create barrel
2017-09-19 15:21:07 +01:00
357bc7f377 Add documentation reference 2017-09-19 15:17:58 +01:00
da8405b5b9 Add Right and Center tab stops 2017-09-19 12:51:37 +01:00
492face7ab 3.0.0 2017-09-17 00:20:18 +01:00
b6351f0260 Merge branch 'jacwright-indent-bc' 2017-09-17 00:09:57 +01:00
3a7f9053b9 Allow indent to use other options than left and hanging
This is a breaking change. Existing code using indent will break when padding in the number for left.
2017-09-16 17:05:40 -06:00
19b122684c Add lint to Travis
Fix linting
2017-09-17 00:01:09 +01:00
72e89cfc3c Move tests to respective folders as .spec
This is to keep to standards
2017-09-17 00:00:41 +01:00
5ae02c3342 Merge pull request #43 from jacwright/default-run-styles
Making it easier to work with default styles
2017-09-16 17:48:37 +01:00
258adba94c Version bump 2017-09-16 17:48:15 +01:00
190208d5df Making it easier to work with default styles
Adds the likely common styles, font and size, to be defined in defaults.
2017-09-16 08:24:15 -06:00
32cda4dfb3 Merge pull request #42 from jacwright/patch-1-test
Fix tests
2017-09-15 16:09:18 +01:00
b2c3dd2f7b Fix tests 2017-09-15 09:05:28 -06:00
58eca3ff5b Merge pull request #41 from jacwright/patch-1
Fix page/thematic breaks
2017-09-15 15:57:22 +01:00
d5c04f9042 Pin typescript to 2.4.1 2017-09-15 15:56:21 +01:00
67ea7c95de Just pagebreak, update test 2017-09-15 08:37:57 -06:00
e57fd8fc57 Fix page/thematic breaks
These items are not paragraph properties, but part of the content of the paragraph.
2017-09-15 08:25:43 -06:00
411c0dadb5 Add table demo 2017-07-29 01:58:29 +01:00
ee81f3c502 Version bump 2017-07-29 01:26:34 +01:00
8263b93c36 Add third demo 2017-07-29 01:26:04 +01:00
be709d082c Export formatting from paragraph folder 2017-07-29 01:15:33 +01:00
70c4e89a65 Version bump 2017-07-08 21:37:02 +01:00
8f632d4ecd Made XmlableObject non ambient typings to fix typescript problem 2017-07-08 20:45:19 +01:00
6784dc1f3d Updated archiver types 2017-07-08 01:24:25 +01:00
fd63a30298 Updated definitions 2017-07-07 16:51:22 +01:00
b0a29e26c9 Version bump 2017-07-07 14:36:34 +01:00
8826fb010d Added types to package json 2017-07-07 14:34:03 +01:00
97101adb10 Enabled declarations in tsconfig to be true 2017-07-07 14:31:08 +01:00
2ec171d4a8 Used my updated typings for archiver 1.3 2017-05-09 18:03:31 +01:00
8876bb1fea updated readme about demos 2017-04-17 19:53:53 +01:00
96ca9d9c23 commented out the rm 2017-04-17 16:36:56 +01:00
74a65f02fa remove exit code 2017-04-17 16:07:28 +01:00
339c017940 edited rm function 2017-04-17 15:41:03 +01:00
969b52ae05 added nojekyll to gh-pages 2017-04-17 13:24:43 +01:00
eb8f0f4033 added debugging to deployment 2017-04-17 13:05:02 +01:00
d7229eb049 removed rimraf 2017-04-16 12:41:24 +01:00
644819ed81 added deployment keys and scripts 2017-04-16 12:22:50 +01:00
96fd61d3e4 using stable version of node 2017-04-16 02:25:44 +01:00
b96cfe7b19 git fetch added 2017-04-16 01:29:29 +01:00
d0e7c97a88 added commit message with merge with gh pages 2017-04-16 01:18:22 +01:00
0ede54cfdc added travis doc deployment solution 2017-04-16 01:12:42 +01:00
5be1163549 remove docs in gitignore 2017-04-16 01:07:11 +01:00
580f6eb633 fixed tests 2017-04-16 00:44:35 +01:00
321be35918 added docs in gitignore 2017-04-16 00:30:27 +01:00
45a18742d7 moved documentation to gh-pages branch 2017-04-16 00:22:29 +01:00
7e81da404a updated readme 2017-04-16 00:09:07 +01:00
6c2abb4abc added typedoc generated docs 2017-04-16 00:07:16 +01:00
e8b0dbf93b added docs ignore to npmignore file 2017-04-16 00:04:29 +01:00
e59c255d85 added type to pack param 2017-04-15 23:45:27 +01:00
17b28cb724 fixed more linting issues 2017-04-15 20:11:54 +01:00
410152441b fixed tslinting issues 2017-04-15 17:54:47 +01:00
dfff4b96bd updated tslint to 5.1.0 2017-04-15 17:47:29 +01:00
72cb75a486 added comma 2017-04-15 17:46:56 +01:00
53fe1dd988 added typedoc support for generating documentation 2017-04-15 17:46:11 +01:00
043219f005 Merge pull request #32 from felipeochoa/keep-lines
add keepLines and keepNext support for paragraph formatting
2017-04-15 17:41:11 +01:00
0453f28951 add keepLines and keepNext support for paragraph formatting
This commit adds it to the three places where paragraph formatting can
be applied right now (directly on the paragraph, paragraph styles, and
bullets/numbering styles). I'm separately adding an entry to the wiki
regarding what these methods do (widow/orphan control)
2017-04-14 21:13:11 +02:00
94716e081b Merge pull request #31 from felipeochoa/spacing-bugfix
Spacing bugfix
2017-04-14 17:30:54 +01:00
30f826fd3d made a mini app which you can select the demo you want from a list with an interactive prompt. 2017-04-14 15:48:12 +01:00
99b7a03b8a update demo2 to test space preservation 2017-04-14 11:09:08 +02:00
b1c8b2beb8 add xml:space="preserve" to text runs
In MS Word 2015 (and possibly others), leading and trailing spaces are
ignored in text runs. This means that calling TextRun with
leading/trailing space would result in a document that didn't include
those spaces. The fix here (per http://officeopenxml.com/WPtext.php)
is to include an extra attribute on the "w:t" element that forces word
to recognize those spaces.
2017-04-14 11:08:19 +02:00
267 changed files with 4865 additions and 2698 deletions

13
.editorconfig Normal file
View 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
View File

@ -36,5 +36,13 @@ node_modules
build build
build-tests build-tests
# vscode # VSCode
.vscode .vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history
# Lock files
package-lock.json

View File

@ -38,3 +38,6 @@ build-tests
# vscode # vscode
.vscode .vscode
# docs
docs

View File

@ -1,10 +1,25 @@
language: node_js language: node_js
node_js: node_js:
- "6" - "stable"
- "node"
install: install:
- npm install - npm install
script: script:
- npm run lint
- npm test - 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: after_failure:
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log" - "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
View 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
}

View File

@ -8,7 +8,12 @@
----- -----
[![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] [![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]
[![NPM](https://nodei.co/npm/docx.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/docx/) [![NPM](https://nodei.co/npm/docx.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/docx/)
@ -26,12 +31,14 @@ $ npm install --save docx
$ npm run demo $ npm run demo
``` ```
will run the demo app in the `demo` folder, which creates a file called "My Document.docx" in the root of the project 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 ## Guide
Please refer to [the Wiki](https://github.com/dolanmiu/docx/wiki) for details on how to use this library, examples and much more! 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 ## Simple Usage
```js ```js
@ -55,6 +62,8 @@ var exporter = new docx.LocalPacker(doc);
var exporter = new docx.ExpressPacker(doc, res); var exporter = new docx.ExpressPacker(doc, res);
exporter.pack('My First Document'); 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' // done! A file called 'My First Document.docx'
// will be in your file system if you used LocalPacker // will be in your file system if you used LocalPacker
@ -64,6 +73,10 @@ exporter.pack('My First Document');
## Examples ## Examples
Check [the Wiki](https://github.com/dolanmiu/docx/wiki/Examples) for examples. Check [the Wiki](https://github.com/dolanmiu/docx/wiki/Examples) for examples.
# Contributing
Read the contribution guidelines [here](https://github.com/dolanmiu/docx/wiki/Contributing-Guidelines).
----- -----
Made with 💖 Made with 💖
@ -82,4 +95,5 @@ Huge thanks to [@felipeochoa](https://github.com/felipeochoa) for awesome contri
[gitter-url]: https://gitter.im/docx-lib/Lobby [gitter-url]: https://gitter.im/docx-lib/Lobby
[gemnasium-image]: https://gemnasium.com/badges/github.com/dolanmiu/docx.svg [gemnasium-image]: https://gemnasium.com/badges/github.com/dolanmiu/docx.svg
[gemnasium-url]: https://gemnasium.com/github.com/dolanmiu/docx [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

View File

@ -10,13 +10,7 @@ paragraph.addRun(dateText);
doc.addParagraph(paragraph); doc.addParagraph(paragraph);
// Feature coming soon
// var media = new docx.Media();
// media.addMedia("happy-penguins", "./demo/penguins.jpg");
// var pictureRun = new docx.PictureRun(media.getMedia("happy-penguins"));
// var exporter = new docx.LocalPacker(doc);
var exporter = new docx.LocalPacker(doc); var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document'); exporter.pack('My Document');
console.log('Document created succesfully at project root!'); console.log('Document created successfully at project root!');

View File

@ -1,7 +1,12 @@
const docx = require('../build'); const docx = require('../build');
const styles = new docx.Styles(); const doc = new docx.Document({
styles.createParagraphStyle('Heading1', 'Heading 1') creator: 'Clippy',
title: 'Sample Document',
description: 'A brief example of using docx',
});
doc.Styles.createParagraphStyle('Heading1', 'Heading 1')
.basedOn("Normal") .basedOn("Normal")
.next("Normal") .next("Normal")
.quickFormat() .quickFormat()
@ -10,7 +15,7 @@ styles.createParagraphStyle('Heading1', 'Heading 1')
.italics() .italics()
.spacing({after: 120}); .spacing({after: 120});
styles.createParagraphStyle('Heading2', 'Heading 2') doc.Styles.createParagraphStyle('Heading2', 'Heading 2')
.basedOn("Normal") .basedOn("Normal")
.next("Normal") .next("Normal")
.quickFormat() .quickFormat()
@ -19,7 +24,7 @@ styles.createParagraphStyle('Heading2', 'Heading 2')
.underline('double', 'FF0000') .underline('double', 'FF0000')
.spacing({before: 240, after: 120}); .spacing({before: 240, after: 120});
styles.createParagraphStyle('aside', 'Aside') doc.Styles.createParagraphStyle('aside', 'Aside')
.basedOn('Normal') .basedOn('Normal')
.next('Normal') .next('Normal')
.color('999999') .color('999999')
@ -27,31 +32,24 @@ styles.createParagraphStyle('aside', 'Aside')
.indent(720) .indent(720)
.spacing({line: 276}); .spacing({line: 276});
styles.createParagraphStyle('wellSpaced', 'Well Spaced') doc.Styles.createParagraphStyle('wellSpaced', 'Well Spaced')
.basedOn('Normal') .basedOn('Normal')
.spacing({line: 276, before: 20 * 72 * .1, after: 20 * 72 * .05}); .spacing({line: 276, before: 20 * 72 * .1, after: 20 * 72 * .05});
styles.createParagraphStyle('ListParagraph', 'List Paragraph') doc.Styles.createParagraphStyle('ListParagraph', 'List Paragraph')
.quickFormat() .quickFormat()
.basedOn('Normal'); .basedOn('Normal');
const numbering = new docx.Numbering(); const numberedAbstract = doc.Numbering.createAbstractNumbering();
const numberedAbstract = numbering.createAbstractNumbering();
numberedAbstract.createLevel(0, "lowerLetter", "%1)", "left"); numberedAbstract.createLevel(0, "lowerLetter", "%1)", "left");
const doc = new docx.Document({
creator: 'Clippy',
title: 'Sample Document',
description: 'A brief example of using docx',
});
doc.createParagraph('Test heading1, bold and italicized').heading1(); doc.createParagraph('Test heading1, bold and italicized').heading1();
doc.createParagraph('Some simple content'); doc.createParagraph('Some simple content');
doc.createParagraph('Test heading2 with double red underline').heading2(); doc.createParagraph('Test heading2 with double red underline').heading2();
const letterNumbering = numbering.createConcreteNumbering(numberedAbstract); const letterNumbering = doc.Numbering.createConcreteNumbering(numberedAbstract);
const letterNumbering5 = numbering.createConcreteNumbering(numberedAbstract); const letterNumbering5 = doc.Numbering.createConcreteNumbering(numberedAbstract);
letterNumbering5.overrideLevel(0, 5); letterNumbering5.overrideLevel(0, 5);
doc.createParagraph('Option1').setNumbering(letterNumbering, 0); doc.createParagraph('Option1').setNumbering(letterNumbering, 0);
@ -64,7 +62,13 @@ doc.createParagraph()
doc.createParagraph('An aside, in light gray italics and indented').style('aside'); doc.createParagraph('An aside, in light gray italics and indented').style('aside');
doc.createParagraph('This is normal, but well-spaced text').style('wellSpaced'); doc.createParagraph('This is normal, but well-spaced text').style('wellSpaced');
doc.createParagraph('This is normal'); const para = doc.createParagraph();
para.createTextRun('This is a bold run,').bold();
para.createTextRun(' switching to normal ');
para.createTextRun('and then underlined ').underline();
para.createTextRun('and back to normal.');
const exporter = new docx.LocalPacker(doc, styles, undefined, numbering); const exporter = new docx.LocalPacker(doc);
exporter.pack('test.docx'); exporter.pack('My Document');
console.log('Document created successfully at project root!');

35
demo/demo3.js Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

BIN
demo/images/dog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

View File

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 162 KiB

BIN
demo/images/parrots.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 818 KiB

BIN
demo/images/pizza.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

29
demo/index.js Normal file
View 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
View 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

Binary file not shown.

View File

@ -1,19 +1,24 @@
{ {
"name": "docx", "name": "docx",
"version": "2.0.1", "version": "3.2.0",
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)", "description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
"main": "build/index.js", "main": "build/index.js",
"scripts": { "scripts": {
"pretest": "rimraf ./build-tests && tsc -p ts/test-tsconfig.json", "pretest": "rimraf ./build",
"test": "mocha ./build-tests --recursive", "test": "mocha-webpack \"src/**/*.ts\"",
"test-watch": "mocha-webpack \"src/**/*.ts\" --watch",
"prepublishOnly": "npm run build", "prepublishOnly": "npm run build",
"lint": "tslint --project ./ts", "lint": "tslint --project .",
"build": "rimraf ./build && tsc -p ts", "build": "npm run webpack && npm run fix-types",
"demo": "npm run build && node ./demo/demo.js", "tsc": "rimraf ./build && tsc -p .",
"demo2": "npm run build && node ./demo/demo2.js" "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": [ "files": [
"ts", "src",
"build", "build",
"template" "template"
], ],
@ -22,6 +27,7 @@
"url": "git+https://github.com/dolanmiu/docx.git" "url": "git+https://github.com/dolanmiu/docx.git"
}, },
"keywords": [ "keywords": [
"docx",
"office", "office",
"word", "word",
"generate", "generate",
@ -32,10 +38,16 @@
"officegen", "officegen",
"clippy" "clippy"
], ],
"types": "./build/index.d.ts",
"dependencies": { "dependencies": {
"@types/archiver": "^0.15.37", "@types/archiver": "^2.1.0",
"@types/express": "^4.0.35", "@types/express": "^4.0.35",
"archiver": "^1.3.0", "@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" "xml": "^1.0.1"
}, },
"author": "Dolan Miu", "author": "Dolan Miu",
@ -47,10 +59,19 @@
"devDependencies": { "devDependencies": {
"@types/chai": "^3.4.35", "@types/chai": "^3.4.35",
"@types/mocha": "^2.2.39", "@types/mocha": "^2.2.39",
"awesome-typescript-loader": "^3.4.1",
"chai": "^3.5.0", "chai": "^3.5.0",
"glob": "^7.1.2",
"mocha": "^3.2.0", "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", "rimraf": "^2.5.2",
"tslint": "^4.5.1", "shelljs": "^0.7.7",
"typescript": "^2.2.1" "tslint": "^5.1.0",
"typedoc": "^0.9.0",
"typescript": "2.6.2",
"webpack": "^3.10.0"
} }
} }

View File

@ -1,10 +1,10 @@
import { assert } from "chai"; import { assert } from "chai";
import * as docx from "../../docx"; import { Formatter } from "../export/formatter";
import { Attributes } from "../../docx/xml-components"; import * as file from "../file";
import { Formatter } from "../../export/formatter"; import { CoreProperties } from "../file/core-properties";
import { Properties } from "../../properties"; import { Attributes } from "../file/xml-components";
import { Utility } from "../utility"; import { Utility } from "../tests/utility";
describe("Formatter", () => { describe("Formatter", () => {
let formatter: Formatter; let formatter: Formatter;
@ -15,21 +15,21 @@ describe("Formatter", () => {
describe("#format()", () => { describe("#format()", () => {
it("should format simple paragraph", () => { it("should format simple paragraph", () => {
const paragraph = new docx.Paragraph(); const paragraph = new file.Paragraph();
const newJson = formatter.format(paragraph); const newJson = formatter.format(paragraph);
assert.isDefined(newJson["w:p"]); assert.isDefined(newJson["w:p"]);
}); });
it("should remove xmlKeys", () => { it("should remove xmlKeys", () => {
const paragraph = new docx.Paragraph(); const paragraph = new file.Paragraph();
const newJson = formatter.format(paragraph); const newJson = formatter.format(paragraph);
const stringifiedJson = JSON.stringify(newJson); const stringifiedJson = JSON.stringify(newJson);
assert(stringifiedJson.indexOf("xmlKeys") < 0); assert(stringifiedJson.indexOf("xmlKeys") < 0);
}); });
it("should format simple paragraph with bold text", () => { it("should format simple paragraph with bold text", () => {
const paragraph = new docx.Paragraph(); const paragraph = new file.Paragraph();
paragraph.addRun(new docx.TextRun("test").bold()); paragraph.addRun(new file.TextRun("test").bold());
const newJson = formatter.format(paragraph); const newJson = formatter.format(paragraph);
assert.isDefined(newJson["w:p"][1]["w:r"][0]["w:rPr"][0]["w:b"][0]._attr["w:val"]); assert.isDefined(newJson["w:p"][1]["w:r"][0]["w:rPr"][0]["w:b"][0]._attr["w:val"]);
}); });
@ -40,6 +40,10 @@ describe("Formatter", () => {
}); });
let newJson = formatter.format(attributes); let newJson = formatter.format(attributes);
newJson = Utility.jsonify(newJson); newJson = Utility.jsonify(newJson);
if (newJson._attr === undefined) {
assert.fail();
return;
}
assert.isDefined(newJson._attr["w:rsidSect"]); assert.isDefined(newJson._attr["w:rsidSect"]);
}); });
@ -49,17 +53,21 @@ describe("Formatter", () => {
}); });
let newJson = formatter.format(attributes); let newJson = formatter.format(attributes);
newJson = Utility.jsonify(newJson); newJson = Utility.jsonify(newJson);
if (newJson._attr === undefined) {
assert.fail();
return;
}
assert.isDefined(newJson._attr["w:val"]); assert.isDefined(newJson._attr["w:val"]);
}); });
it("should should change 'p' tag into 'w:p' tag", () => { it("should should change 'p' tag into 'w:p' tag", () => {
const paragraph = new docx.Paragraph(); const paragraph = new file.Paragraph();
const newJson = formatter.format(paragraph); const newJson = formatter.format(paragraph);
assert.isDefined(newJson["w:p"]); assert.isDefined(newJson["w:p"]);
}); });
it("should format Properties object correctly", () => { it("should format Properties object correctly", () => {
const properties = new Properties({ const properties = new CoreProperties({
title: "test document", title: "test document",
creator: "Dolan", creator: "Dolan",
}); });

7
src/export/formatter.ts Normal file
View 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
View File

@ -0,0 +1,3 @@
export * from "./packer/local";
export * from "./packer/express";
export * from "./packer/packer";

View 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();
});
});
}
}

View 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);
}
}

View 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");
});
});
});

View 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();
});
});
}
}

View 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 = "";

View 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: "",
},
});
}
}

View 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",
};
}

View 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",
}),
);
}
}

View 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",
};
}

View 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"));
}
}

View 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",
};
}

View 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,
}),
);
}
}

View 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",
};
}

View 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,
}),
);
}
}

View File

@ -1,8 +1,7 @@
import { DocumentAttributes } from "../docx/document/document-attributes"; import { XmlComponent } from "file/xml-components";
import { XmlComponent } from "../docx/xml-components"; import { DocumentAttributes } from "../document/document-attributes";
export class Title extends XmlComponent { export class Title extends XmlComponent {
constructor(value: string) { constructor(value: string) {
super("dc:title"); super("dc:title");
this.root.push(value); this.root.push(value);
@ -10,7 +9,6 @@ export class Title extends XmlComponent {
} }
export class Subject extends XmlComponent { export class Subject extends XmlComponent {
constructor(value: string) { constructor(value: string) {
super("dc:subject"); super("dc:subject");
this.root.push(value); this.root.push(value);
@ -18,7 +16,6 @@ export class Subject extends XmlComponent {
} }
export class Creator extends XmlComponent { export class Creator extends XmlComponent {
constructor(value: string) { constructor(value: string) {
super("dc:creator"); super("dc:creator");
this.root.push(value); this.root.push(value);
@ -26,7 +23,6 @@ export class Creator extends XmlComponent {
} }
export class Keywords extends XmlComponent { export class Keywords extends XmlComponent {
constructor(value: string) { constructor(value: string) {
super("cp:keywords"); super("cp:keywords");
this.root.push(value); this.root.push(value);
@ -34,7 +30,6 @@ export class Keywords extends XmlComponent {
} }
export class Description extends XmlComponent { export class Description extends XmlComponent {
constructor(value: string) { constructor(value: string) {
super("dc:description"); super("dc:description");
this.root.push(value); this.root.push(value);
@ -42,7 +37,6 @@ export class Description extends XmlComponent {
} }
export class LastModifiedBy extends XmlComponent { export class LastModifiedBy extends XmlComponent {
constructor(value: string) { constructor(value: string) {
super("cp:lastModifiedBy"); super("cp:lastModifiedBy");
this.root.push(value); this.root.push(value);
@ -50,14 +44,13 @@ export class LastModifiedBy extends XmlComponent {
} }
export class Revision extends XmlComponent { export class Revision extends XmlComponent {
constructor(value: string) { constructor(value: string) {
super("cp:revision"); super("cp:revision");
this.root.push(value); this.root.push(value);
} }
} }
abstract class DateComponent extends XmlComponent { export abstract class DateComponent extends XmlComponent {
protected getCurrentDate(): string { protected getCurrentDate(): string {
const date = new Date(); const date = new Date();
const year = date.getFullYear(); const year = date.getFullYear();
@ -72,23 +65,25 @@ abstract class DateComponent extends XmlComponent {
} }
export class Created extends DateComponent { export class Created extends DateComponent {
constructor() { constructor() {
super("dcterms:created"); super("dcterms:created");
this.root.push(new DocumentAttributes({ this.root.push(
new DocumentAttributes({
type: "dcterms:W3CDTF", type: "dcterms:W3CDTF",
})); }),
);
this.root.push(this.getCurrentDate()); this.root.push(this.getCurrentDate());
} }
} }
export class Modified extends DateComponent { export class Modified extends DateComponent {
constructor() { constructor() {
super("dcterms:modified"); super("dcterms:modified");
this.root.push(new DocumentAttributes({ this.root.push(
new DocumentAttributes({
type: "dcterms:W3CDTF", type: "dcterms:W3CDTF",
})); }),
);
this.root.push(this.getCurrentDate()); this.root.push(this.getCurrentDate());
} }
} }

View File

@ -0,0 +1 @@
export * from "./properties";

View File

@ -1,13 +1,12 @@
import { expect } from "chai"; import { expect } from "chai";
import { Formatter } from "../export/formatter"; import { Formatter } from "../../export/formatter";
import { Properties } from "../properties"; import { CoreProperties } from "./properties";
describe("Properties", () => { describe("Properties", () => {
describe("#constructor()", () => { describe("#constructor()", () => {
it("sets the appropriate attributes on the top-level", () => { it("sets the appropriate attributes on the top-level", () => {
const properties = new Properties({}); const properties = new CoreProperties({});
const tree = new Formatter().format(properties); const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["cp:coreProperties"]); expect(Object.keys(tree)).to.deep.equal(["cp:coreProperties"]);
expect(tree["cp:coreProperties"]).to.be.an.instanceof(Array); expect(tree["cp:coreProperties"]).to.be.an.instanceof(Array);
@ -23,18 +22,16 @@ describe("Properties", () => {
}); });
it("should create properties with a title", () => { it("should create properties with a title", () => {
const properties = new Properties({title: "test document"}); const properties = new CoreProperties({ title: "test document" });
const tree = new Formatter().format(properties); const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["cp:coreProperties"]); expect(Object.keys(tree)).to.deep.equal(["cp:coreProperties"]);
expect(tree["cp:coreProperties"]).to.be.an.instanceof(Array); expect(tree["cp:coreProperties"]).to.be.an.instanceof(Array);
expect(Object.keys(tree["cp:coreProperties"][0])).to.deep.equal(["_attr"]); expect(Object.keys(tree["cp:coreProperties"][0])).to.deep.equal(["_attr"]);
expect(tree["cp:coreProperties"][1]).to.deep.equal( expect(tree["cp:coreProperties"][1]).to.deep.equal({ "dc:title": ["test document"] });
{"dc:title": ["test document"]},
);
}); });
it("should create properties with all the attributes given", () => { it("should create properties with all the attributes given", () => {
const properties = new Properties({ const properties = new CoreProperties({
title: "test document", title: "test document",
subject: "test subject", subject: "test subject",
creator: "me", creator: "me",
@ -60,14 +57,14 @@ describe("Properties", () => {
"dcterms:created", "dcterms:created",
"dcterms:modified", "dcterms:modified",
]); ]);
expect(tree["cp:coreProperties"].slice(1, -2).sort((a, b) => key(a) < key(b) ? -1 : 1)).to.deep.equal([ expect(tree["cp:coreProperties"].slice(1, -2).sort((a, b) => (key(a) < key(b) ? -1 : 1))).to.deep.equal([
{"cp:keywords": ["test docx"]}, { "cp:keywords": ["test docx"] },
{"cp:lastModifiedBy": ["the author"]}, { "cp:lastModifiedBy": ["the author"] },
{"cp:revision": ["123"]}, { "cp:revision": ["123"] },
{"dc:creator": ["me"]}, { "dc:creator": ["me"] },
{"dc:description": ["testing document"]}, { "dc:description": ["testing document"] },
{"dc:subject": ["test subject"]}, { "dc:subject": ["test subject"] },
{"dc:title": ["test document"]}, { "dc:title": ["test document"] },
]); ]);
}); });
}); });

View File

@ -1,8 +1,8 @@
import { DocumentAttributes } from "../docx/document/document-attributes"; import { XmlComponent } from "file/xml-components";
import { XmlComponent } from "../docx/xml-components"; import { DocumentAttributes } from "../document/document-attributes";
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components"; import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
interface IPropertiesOptions { export interface IPropertiesOptions {
title?: string; title?: string;
subject?: string; subject?: string;
creator?: string; creator?: string;
@ -12,17 +12,18 @@ interface IPropertiesOptions {
revision?: string; revision?: string;
} }
export class Properties extends XmlComponent { export class CoreProperties extends XmlComponent {
constructor(options: IPropertiesOptions) { constructor(options: IPropertiesOptions) {
super("cp:coreProperties"); super("cp:coreProperties");
this.root.push(new DocumentAttributes({ this.root.push(
new DocumentAttributes({
cp: "http://schemas.openxmlformats.org/package/2006/metadata/core-properties", cp: "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
dc: "http://purl.org/dc/elements/1.1/", dc: "http://purl.org/dc/elements/1.1/",
dcterms: "http://purl.org/dc/terms/", dcterms: "http://purl.org/dc/terms/",
dcmitype: "http://purl.org/dc/dcmitype/", dcmitype: "http://purl.org/dc/dcmitype/",
xsi: "http://www.w3.org/2001/XMLSchema-instance", xsi: "http://www.w3.org/2001/XMLSchema-instance",
})); }),
);
if (options.title) { if (options.title) {
this.root.push(new Title(options.title)); this.root.push(new Title(options.title));
} }

View 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");
// });
// });
});

View 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);
}
}

View File

@ -0,0 +1 @@
export * from "./body";

View File

@ -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",
};
}

View 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,
}),
);
}
}

View File

@ -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",
};
}

View File

@ -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,
}),
);
}
}

View File

@ -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",
};
}

View File

@ -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}`,
}),
);
}
}

View File

@ -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",
};
}

View File

@ -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}`,
}),
);
}
}

View File

@ -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",
};
}

View File

@ -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,
}),
);
}
}

View File

@ -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",
};
}

View File

@ -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" } });
});
});
});

View File

@ -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,
}),
);
}
}

View File

@ -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,
},
},
],
});
});
});
});

View File

@ -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());
}
}

View File

@ -1,6 +1,6 @@
import { XmlAttributeComponent } from "../xml-components"; import { XmlAttributeComponent } from "file/xml-components";
interface IDocumentAttributesProperties { export interface IDocumentAttributesProperties {
wpc?: string; wpc?: string;
mc?: string; mc?: string;
o?: string; o?: string;

View 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);
});
});
});

View 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;
}
}

View File

@ -0,0 +1 @@
export * from "./document";

View File

@ -1,18 +1,29 @@
import { assert } from "chai"; import { assert } from "chai";
import * as fs from "fs"; import * as fs from "fs";
import { Drawing } from "../../../../docx/run/run-components/drawing";
import { Utility } from "../../../utility"; import { Utility } from "../../tests/utility";
import { Drawing } from "./";
describe("Drawing", () => { describe("Drawing", () => {
let currentBreak: Drawing; let currentBreak: Drawing;
beforeEach(() => { beforeEach(() => {
const path = "./demo/penguins.jpg"; const path = "./demo/images/image1.jpeg";
currentBreak = new Drawing({ currentBreak = new Drawing({
fileName: "test.jpg", fileName: "test.jpg",
referenceId: 1, referenceId: 1,
stream: fs.createReadStream(path), stream: fs.createReadStream(path),
path: path, path: path,
dimensions: {
pixels: {
x: 100,
y: 100,
},
emus: {
x: 100 * 9525,
y: 100 * 9525,
},
},
}); });
}); });
@ -20,7 +31,7 @@ describe("Drawing", () => {
it("should create a Drawing with correct root key", () => { it("should create a Drawing with correct root key", () => {
const newJson = Utility.jsonify(currentBreak); const newJson = Utility.jsonify(currentBreak);
assert.equal(newJson.rootKey, "w:drawing"); assert.equal(newJson.rootKey, "w:drawing");
console.log(JSON.stringify(newJson, null, 2)); // console.log(JSON.stringify(newJson, null, 2));
}); });
}); });
}); });

View File

@ -1,16 +1,15 @@
import { IData } from "../../../../media/data"; import { IMediaData } from "file/media";
import { XmlComponent } from "../../../xml-components"; import { XmlComponent } from "file/xml-components";
import { Inline } from "./inline"; import { Inline } from "./inline";
export class Drawing extends XmlComponent { export class Drawing extends XmlComponent {
constructor(imageData: IMediaData) {
constructor(imageData: IData) {
super("w:drawing"); super("w:drawing");
if (imageData === undefined) { if (imageData === undefined) {
throw new Error("imageData cannot be undefined"); throw new Error("imageData cannot be undefined");
} }
this.root.push(new Inline(imageData.referenceId)); this.root.push(new Inline(imageData.referenceId, imageData.dimensions));
} }
} }

View File

@ -0,0 +1 @@
export { Drawing } from "./drawing";

View File

@ -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",
};
}

View 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: "",
}),
);
}
}

View File

@ -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",
};
}

View 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,
}),
);
}
}

View 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",
};
}

View 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,
}),
);
}
}

View File

@ -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",
};
}

View File

@ -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,
}),
);
}
}

View File

@ -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());
}
}

View File

@ -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",
};
}

View 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));
}
}

View File

@ -0,0 +1 @@
export * from "./graphic-data";

View File

@ -1,10 +1,9 @@
import { XmlComponent } from "../../../../../../../../xml-components"; import { XmlComponent } from "file/xml-components";
import { Blip } from "./blip"; import { Blip } from "./blip";
import { SourceRectangle } from "./source-rectangle"; import { SourceRectangle } from "./source-rectangle";
import { Stretch } from "./stretch"; import { Stretch } from "./stretch";
export class BlipFill extends XmlComponent { export class BlipFill extends XmlComponent {
constructor(referenceId: number) { constructor(referenceId: number) {
super("pic:blipFill"); super("pic:blipFill");
this.root.push(new Blip(referenceId)); this.root.push(new Blip(referenceId));

View File

@ -1,21 +1,25 @@
import { XmlAttributeComponent, XmlComponent } from "../../../../../../../../xml-components"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
interface IBlipProperties { interface IBlipProperties {
embed: string; embed: string;
cstate: string;
} }
class BlipAttributes extends XmlAttributeComponent<IBlipProperties> { class BlipAttributes extends XmlAttributeComponent<IBlipProperties> {
protected xmlKeys = { protected xmlKeys = {
embed: "r:embed", embed: "r:embed",
cstate: "cstate",
}; };
} }
export class Blip extends XmlComponent { export class Blip extends XmlComponent {
constructor(referenceId: number) { constructor(referenceId: number) {
super("a:blip"); super("a:blip");
this.root.push(new BlipAttributes({ this.root.push(
new BlipAttributes({
embed: `rId${referenceId}`, embed: `rId${referenceId}`,
})); cstate: "none",
}),
);
} }
} }

View File

@ -1,7 +1,6 @@
import { XmlComponent } from "../../../../../../../../xml-components"; import { XmlComponent } from "file/xml-components";
export class SourceRectangle extends XmlComponent { export class SourceRectangle extends XmlComponent {
constructor() { constructor() {
super("a:srcRect"); super("a:srcRect");
} }

View File

@ -1,14 +1,12 @@
import { XmlComponent } from "../../../../../../../../xml-components"; import { XmlComponent } from "file/xml-components";
class FillRectangle extends XmlComponent { class FillRectangle extends XmlComponent {
constructor() { constructor() {
super("a:fillRect"); super("a:fillRect");
} }
} }
export class Stretch extends XmlComponent { export class Stretch extends XmlComponent {
constructor() { constructor() {
super("a:stretch"); super("a:stretch");
this.root.push(new FillRectangle()); this.root.push(new FillRectangle());

View File

@ -0,0 +1 @@
export * from "./pic";

View File

@ -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());
}
}

View File

@ -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",
};
}

View File

@ -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,
}),
);
}
}

View File

@ -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());
}
}

View File

@ -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",
};
}

View File

@ -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: "",
}),
);
}
}

View File

@ -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",
};
}

View 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));
}
}

View File

@ -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",
};
}

View File

@ -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,
}),
);
}
}

View File

@ -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());
}
}

View File

@ -0,0 +1 @@
export * from "./form";

View File

@ -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