Compare commits

..

425 Commits
1.2.1 ... 3.6.0

Author SHA1 Message Date
ba0ca78696 Version bump 2018-05-22 02:35:03 +01:00
22ba53ad4c Merge pull request #79 from formatically/master
Removed unnecessary header2 references
2018-05-20 20:28:23 +01:00
81304f50d1 Removed unnecessary header2 references 2018-05-19 20:52:45 -06:00
3c22372f49 Merge pull request #76 from formatically/master
Added DifferentFirstPageHeader and Page Number features
2018-05-19 12:30:39 +01:00
7584671312 Fixed TSLint Errors 2018-05-18 09:21:27 -06:00
7296c9e744 Removed extra empty lines 2018-05-17 19:51:01 -06:00
c63a8982e4 Added demo14 to showcase differentFirstPageHeader and pagenumbers 2018-05-17 19:44:37 -06:00
8d35dc1bb0 Added tests, renamed pagenumber to page-number 2018-05-17 13:32:33 -06:00
0fedfcf709 Renamed titlepage to title-page 2018-05-17 11:54:13 -06:00
6c2eb882bb Added differentFirstPageHeader section property 2018-05-17 11:45:06 -06:00
59560d96ba Add downloads badge and remove existing node badge 2018-05-16 20:10:12 +01:00
864c9afd93 Remove Gemnasium because they no longer exist :( 2018-05-16 20:00:01 +01:00
b4f07f51ae Merge pull request #70 from dolanmiu/feat/h4buli-update
H4 update
2018-05-16 19:51:40 +01:00
e9b153095c Add demo for custom xml styles 2018-05-16 19:34:25 +01:00
7968c1efcf Removed header-wrapper-2 2018-05-12 22:22:54 -04:00
87648a742c Initial Commit 2018-05-12 20:04:54 -04:00
4d7bdc2ed9 Version bump 2018-05-08 22:19:01 +01:00
d10c707f12 Add tests for catching errors for exporter packer.pack 2018-05-08 20:40:04 +01:00
ac512b2eab Merge branch 'feat/h4buli-update' of https://github.com/dolanmiu/docx into feat/h4buli-update 2018-05-08 02:12:20 +01:00
fdf6a59c4c Add back xml-component export 2018-05-08 01:26:13 +01:00
4b9a6a6735 Merge branch 'master' into feat/h4buli-update 2018-05-08 01:23:56 +01:00
49cc8a267c Merge pull request #71 from ivanryuu/hyperlink_support
External hyperlink support
2018-05-08 01:16:28 +01:00
68cb57aea6 fix style issues 2018-05-06 23:18:00 -05:00
9d7fd55e4c add hyperlink to paragraph and doc 2018-05-06 22:24:16 -05:00
195c62f80b modify relationships to support external links 2018-05-06 22:23:35 -05:00
1fd222abea create hyperlink style 2018-05-06 22:23:04 -05:00
ac40e13e33 added support for hyperlinks 2018-05-06 22:20:56 -05:00
53ab822dbc Fix style 2018-05-06 03:38:08 +01:00
0c9c292291 Fix tests. _attr is needed 2018-05-06 03:27:58 +01:00
573dd753a7 Fix styling and linting 2018-05-06 03:19:36 +01:00
79b5b3a1f6 Merge branch 'master' into feat/h4buli-update 2018-05-06 03:03:45 +01:00
52e8fe576e Bump prettier version 2018-05-06 03:03:35 +01:00
0d34d2d92e Merge branch 'master' into feat/h4buli-update 2018-05-06 03:02:26 +01:00
b389ac6347 Add style fix command 2018-05-06 03:02:06 +01:00
534c601068 Linting fixes 2018-05-06 02:58:16 +01:00
424436579b Remove xml component from main export 2018-05-06 02:58:08 +01:00
a716360faa Restore numbering 2018-05-06 02:57:40 +01:00
af485c678d Merge branch 'master' of https://github.com/h4buli/docx into feat/h4buli-update
# Conflicts:
#	package.json
#	src/file/numbering/numbering.ts
2018-05-06 02:57:15 +01:00
84e298e7ee Version bump 2018-05-04 15:59:46 +02:00
753287d9d1 extend table and table cell support for cell merge, span, borders ... (#6)
* extend table and table cell support for cell merge, span, borders ...

* added tests for table cell borders and table cell width, renamed some variables, added jsdoc
2018-05-04 15:56:28 +02:00
21bb8f9016 Version bump 2018-04-26 14:18:22 +02:00
dc136daeab tables: add option to pass column size when creating a table
- add optionto the XmlComponent to `delete`/skip elements when exporting to xml
2018-04-26 14:16:02 +02:00
e67f5f80e1 Version bump 2018-04-23 11:50:40 +02:00
3691d79a4a add method to add child to an element 2018-04-23 11:49:57 +02:00
8108eca2fa Update README.md 2018-04-21 00:04:14 +01:00
4f48c8fb80 Merge branch 'master' of github.com:h4buli/docx 2018-04-20 16:01:09 +02:00
20ba081308 Version bump 2018-04-20 16:00:44 +02:00
2119ae769b Images: Extend API for working with images (#5)
* extend creating image using buffer and dimensions from outside

* remove empty space
2018-04-20 15:59:06 +02:00
c618ca7539 Version bump 2018-04-17 16:33:08 +02:00
8b11140be2 export AbstractNumbering class 2018-04-17 16:31:36 +02:00
bebfec7755 version bump 2018-04-17 15:39:57 +02:00
124aac4888 fixed failing tests - removed test for the ctor for Numbering class 2018-04-17 15:38:51 +02:00
b3bfd063d8 Merge branch 'master' of github.com:h4buli/docx 2018-04-17 15:34:46 +02:00
c92cab5e5b Fix Numbering (#4)
* Version bump

* (fix): fixed issue with numbering in document
2018-04-17 15:33:53 +02:00
8c613195f3 Version bump 2018-04-10 21:55:02 +01:00
41f941728e Clean up and tests 2018-04-10 21:54:52 +01:00
ecf1542d95 Add instructions image 2018-04-10 21:42:21 +01:00
06b2bbba25 Add image demo 2018-04-10 21:36:11 +01:00
0494fdeabd Add other demo scripts as part of build 2018-04-10 21:08:40 +01:00
226206b100 Fix build 2018-04-10 21:06:02 +01:00
02f80bc616 Merge pull request #68 from citizenos/master
Updated bullet list creating
2018-04-10 21:04:27 +01:00
3189c9251a modified style script 2018-04-10 11:00:25 +03:00
ae43137906 revert demo10.js, fix paragraph tests 2018-04-10 10:25:12 +03:00
50bee30799 reverted gitignore 2018-04-09 23:21:51 +03:00
38484a3063 removed build folder 2018-04-09 23:18:55 +03:00
919327ed08 bullet points update 2018-04-05 16:50:25 +03:00
c00c5fa02d Merge pull request #67 from citizenos/master
image scaling add rounding
2018-04-03 22:51:15 +01:00
80f09ac10b modified git ignore 2018-04-02 14:37:54 +03:00
ee721ffbec image scaling add rounding 2018-04-02 12:55:43 +03:00
323f91dd68 Version bump 2018-03-28 16:31:44 +02:00
810ccb40d7 Merge pull request #3 from h4buli/feature/import-styles
styles: support for external styles. parsing external styles.
2018-03-28 16:02:11 +02:00
5242f7d55c styles: support for external styles. parsing external styles. 2018-03-28 14:54:07 +02:00
d293ae516c Merge pull request #2 from h4buli/revert-1-feature/external-styles-support
Revert "(styles): add support to provide external styles (as complete file co…"
2018-03-26 16:29:16 +02:00
3fb563f9c8 Revert "(styles): add support to provide external styles (as complete file co…" 2018-03-26 16:28:40 +02:00
1dd1c65341 Version bump 2018-03-24 19:24:24 +00:00
e593327fea Merge pull request #66 from dolanmiu/feat/resizable-pictures
Feat/resizable pictures
2018-03-24 19:23:22 +00:00
64e0aeeb18 Fix demo 2018-03-24 19:11:25 +00:00
05816abc12 Add scalable image feature 2018-03-24 19:06:10 +00:00
ce306aef07 Version bump 2018-03-23 12:25:30 +01:00
373c850f35 Merge pull request #1 from h4buli/feature/external-styles-support
(styles): add support to provide external styles (as complete file co…
2018-03-23 12:21:00 +01:00
a0e00b8eff (styles): add support to provide external styles (as complete file content) 2018-03-23 12:18:31 +01:00
a954c69458 Fix tests 2018-03-22 23:04:46 +00:00
a0e034bd55 Version bump 2018-03-22 22:56:05 +00:00
1a1c1f26d9 Border for tables by default 2018-03-22 22:55:33 +00:00
114c429aed pdf-export: remove option to export to pdf 2018-03-21 10:53:07 +01:00
40251a76f6 setup: rename npm package 2018-03-21 10:46:22 +01:00
a102b479e6 Add new demo 2018-03-10 23:04:45 +00:00
5b5f5ea203 Merge pull request #63 from felipeochoa/stream-packer
Added generic stream packer
2018-02-25 15:40:46 +00:00
40a8e581f1 Added generic stream packer 2018-02-23 19:21:00 -05:00
1b988e7135 Remove old deployment scripts 2018-02-21 22:09:55 +00:00
9433c7aedc Update documentation links 2018-02-21 22:09:42 +00:00
479dfed987 Clean up and nojekyll 2018-02-21 21:51:17 +00:00
1866033128 Remove spec files from docs 2018-02-21 21:46:02 +00:00
844b9ab2ec Update travis for docs 2018-02-21 21:34:43 +00:00
e6713d6ce2 Ignore My Document generated file 2018-02-13 23:21:20 +00:00
069ce73c07 Add My CV Demo 2018-02-13 23:20:14 +00:00
6dda6a5513 Formatting 2018-02-13 02:10:42 +00:00
329def42ac Prettier formatting 2018-02-13 02:08:28 +00:00
c5137b5fad Add RunKit examples 2018-02-13 02:07:56 +00:00
ab05ccb846 Simplify prettier command 2018-02-10 17:56:52 +00:00
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
a706455a7c Merge pull request #30 from felipeochoa/overrides
Add support for numbering level overrides
2017-04-12 18:34:07 +01:00
8c388a95c4 bump patch version 2017-04-12 16:01:26 +02:00
9a41d78ecb add an additional demo 2017-04-12 16:00:16 +02:00
6fc4ad782a add #overrideLevel method to concrete numberings 2017-04-12 16:00:16 +02:00
16b9057ac6 prepare Level to be extended for overrides 2017-04-12 15:57:26 +02:00
28c62c1ee4 version 2.0.0 2017-04-01 13:31:24 +01:00
91a757619e fixed unit tests 2017-04-01 12:30:27 +01:00
f89049e4c1 version bump 2017-04-01 12:23:01 +01:00
086f5f5d03 Merge branch 'image-support' 2017-04-01 12:22:23 +01:00
a2694f1d7d edited demo code 2017-04-01 12:21:59 +01:00
fd350d53db fixed some typescript compile issues 2017-04-01 12:18:23 +01:00
af48af2854 added error checking and updated demo 2017-03-29 22:57:52 +01:00
15009884e3 made image take in IData instead of image path 2017-03-29 22:47:34 +01:00
ad462dfe10 added relationships 2017-03-27 01:28:52 +01:00
68fe380575 renamed template constant 2017-03-27 01:28:31 +01:00
5b2a311ad4 media now adds object into docx /media folder 2017-03-26 20:57:43 +01:00
5db2503e7b added media class and packer to handle it 2017-03-25 21:50:33 +00:00
55a1d23f29 fixed missing comma 2017-03-14 11:33:46 +00:00
0bfd753a0d fixed json, missing comma 2017-03-14 11:28:05 +00:00
22adabd2d9 updated keywords 2017-03-14 10:51:05 +00:00
6d5c89ff47 corrected underline 2017-03-14 10:48:24 +00:00
96a9bb1a1e corrected underline 2017-03-14 10:47:50 +00:00
2be00d3f1e corrected example 2017-03-14 10:38:05 +00:00
30b21217a9 added create picture run method 2017-03-13 23:41:14 +00:00
260a680f56 Merge branch 'master' into image-support 2017-03-13 23:37:09 +00:00
486777b108 named this addRun because I realised Text can be a Run, but also a Picture can be a run 2017-03-13 23:35:24 +00:00
3730e2b60e clean up of packer 2017-03-13 23:30:26 +00:00
e7e6d02cc5 Merge pull request #28 from felipeochoa/npm-fixes
NPM fixes
2017-03-13 22:38:13 +00:00
c7b7b585be fix path to template when installed via npm
I'm not sure why, buy app-root-path was not picking up the correct
path for this module when installed via NPM. Since we're already using
relative paths for imports, I don't think we gain much from using it
anyway, so I've changed to using path.resolve instead
2017-03-13 20:40:16 +01:00
0c128ae4a5 add template to npm bundle 2017-03-13 20:40:16 +01:00
d7a70ffe03 use gemnasium rather than david-dm 2017-03-13 16:14:03 +00:00
e1c699ec41 Merge pull request #27 from felipeochoa/styles
More styles harmony
2017-03-13 12:31:25 +00:00
245f0ae2ea added gitter integration 2017-03-13 12:30:22 +00:00
762fc0ca9d added run formatting methods to levels 2017-03-13 12:38:16 +01:00
457d074a59 added paragraph formatting methods to numbering Level 2017-03-13 12:38:16 +01:00
ba80440faf formatting and correct heading values 2017-03-13 01:21:26 +00:00
ae41e22df5 moved Documents section to Wiki.
Cleaned up Wiki
Added felipeochoa mention
removed TOC
2017-03-13 01:19:39 +00:00
bf2e5201c8 made usage much more clear 2017-03-13 01:11:11 +00:00
2662bcc60b removed Paragraph from readme, and put it in the Wiki 2017-03-13 01:03:57 +00:00
efa4f1933a moved Text section to Wiki 2017-03-13 00:57:57 +00:00
8c58ec2ba4 moved bullet points to Wiki 2017-03-13 00:54:05 +00:00
e6ed3a55ff updated contents 2017-03-13 00:51:01 +00:00
69abf509c9 removed tab stops and placed it in the Wiki 2017-03-13 00:50:29 +00:00
66eace4a33 added a attribute to graphic 2017-03-13 00:40:39 +00:00
eeb2187db4 added source rectangle and stretch in the blip fill 2017-03-13 00:33:59 +00:00
fa44acca1b added the remaining classes required 2017-03-13 00:02:56 +00:00
34ce662f70 added basic test for drawing 2017-03-12 23:32:02 +00:00
8d72fa5542 added more boilerplate files to drawing 2017-03-12 23:31:43 +00:00
64d642b593 Merge branch 'master' into image-support 2017-03-12 21:44:17 +00:00
d9e533156f fixed the build :P removed .docx extension if one is already present 2017-03-12 21:43:52 +00:00
90e5cc3ad5 Revert "fixed the build :P removed .docx extension if one is already present"
This reverts commit 9f61ca7abe.
2017-03-12 21:43:15 +00:00
9f61ca7abe fixed the build :P removed .docx extension if one is already present 2017-03-12 21:42:45 +00:00
6af79a884c Merge branch 'master' into image-support 2017-03-12 21:38:38 +00:00
353401d148 updated readme to add demo folder 2017-03-12 21:37:36 +00:00
f17360d45a add simple demo page 2017-03-12 21:34:49 +00:00
4bc6ed0eda added more files to drawing 2017-03-12 21:30:46 +00:00
bf22866a8d Merge pull request #26 from felipeochoa/styles
Standardizing formatting methods
2017-03-12 21:26:47 +00:00
a6e40d9d92 tightened type checking for tab stops 2017-03-12 22:06:43 +01:00
0b78e33444 added #leftTabStop and #maxRightTabStop methods to paragraph styles 2017-03-12 22:05:54 +01:00
6689f76c28 added #thematicBreak method to paragraph styles 2017-03-12 21:58:12 +01:00
df8ba1e8b8 added alignment methods to paragraph style 2017-03-12 21:40:01 +01:00
b3524971ac clean up imports into paragraph and paragraph style
(this prep for importing it from styles)
2017-03-12 21:39:29 +01:00
1cd681bc2d added #font method to paragraph styles 2017-03-12 17:53:32 +01:00
7f4d1bf3e7 added #SubScript and #SuperScript methods to ParagraphStyle 2017-03-12 17:52:03 +01:00
8c6cd012e7 eliminated duplicate implementation of strikethrough 2017-03-12 17:51:52 +01:00
371398bc2c added #strike and #doubleStrike methods to paragraphStyle 2017-03-12 17:44:42 +01:00
9a90818729 added #smallCaps and #allCaps methods to ParagraphStyle 2017-03-12 17:43:00 +01:00
90049a31ee added #style method to runs 2017-03-12 17:35:15 +01:00
3dbd917667 added #color and #size methods to Run 2017-03-12 17:31:36 +01:00
d85c6ce56a allow Run#underline to take style and color arguments 2017-03-12 17:28:52 +01:00
db24f67e34 Merge pull request #21 from felipeochoa/tables
Tables!
2017-03-11 20:31:57 +00:00
fb6a4383ff renamed cell#push to cell#addContent 2017-03-11 21:15:45 +01:00
c33cdb450c added initial constructor 2017-03-11 18:21:31 +00:00
62b6b33254 created drawing file and refactored run components in components folder 2017-03-11 16:56:35 +00:00
64ab91765a edited contents 2017-03-11 16:06:09 +00:00
c0ba937c3a simplified readme 2017-03-11 16:05:20 +00:00
70f4613e1b appease the linter 2017-03-11 10:30:25 +01:00
bd9d6b74f5 added Cell#createParagraph method 2017-03-11 10:30:08 +01:00
bd3eb3e214 move the cell-paragraph validation into prepForXml
Instead of forcing table cells to only have a single paragraph as
their content, we now check whether they end in a paragraph (and
insert one if necessary) during #prepForXml
2017-03-11 10:22:30 +01:00
c10b576a3a added fixedWidthLayout option and method 2017-03-11 09:59:29 +01:00
210b97d00b added document#createTable 2017-03-11 09:02:36 +01:00
62a238de84 more sane width management 2017-03-11 09:02:22 +01:00
7b6f5bbaef forgot to test #getCell 2017-03-10 17:48:05 +01:00
a45048a464 fix a handful of strict null errors; make test config also be strict
These errors only arose because I didn't run `npm build`, only `npm
test`. Then, when I tried building the null checks failed. Keeping the
two config fiels in sync will help prevent this issue in the future
2017-03-10 17:45:37 +01:00
c0b0649f37 added tests for table v1 2017-03-10 17:39:37 +01:00
e7e5c61a90 clean up initial table attempt (linter, interfaces, etc.) 2017-03-10 17:11:08 +01:00
f1fb0c4f22 initial attempt at Table 2017-03-10 16:55:39 +01:00
0de30f6c59 Merge pull request #19 from felipeochoa/cleanup
fix unused imports linter warnings
2017-03-10 15:43:19 +00:00
599be5bf2b got a little carried away with the purge! fixed failing errors 2017-03-10 16:35:48 +01:00
9d7573ed9c fix unused imports linter warnings 2017-03-10 16:09:21 +01:00
738cac0253 Merge pull request #17 from felipeochoa/cleanup
More cleanup
2017-03-10 14:53:42 +00:00
35ddda444a rename paragraph#createRun to paragraph#createTextRun 2017-03-10 14:44:25 +01:00
8d11ec3422 add paragraph.createRun method 2017-03-10 14:36:16 +01:00
ea647d84df add document.createParagraph method 2017-03-10 14:31:21 +01:00
8c91c04afa clean up latentstyles to use modern attribute implementation 2017-03-10 14:31:21 +01:00
a89718ea83 fix a couple of compiler null warnings 2017-03-10 14:31:21 +01:00
62911d6e44 make XmlAttributeComponent into a generic class
This change brings increased type safety to uses of
XmlAttributeComponent. Now the compiler is checkign for us that the
properties that get passed in to every subclass match the intended
interface, and also that the xmlKeys property -> xml attribute mapping
has all the right keys
2017-03-10 14:19:45 +01:00
766069c7cc make packers a top-level export 2017-03-10 13:54:49 +01:00
09f1d473c3 remove lodash from dependencies as it's no longer used 2017-03-10 13:54:44 +01:00
74ea0f699f remove npm and install from dependencies
These aren't actually needed at run time or build time
2017-03-10 13:54:37 +01:00
b00e4fa5b5 moved exporting to the wiki 2017-03-10 11:35:43 +00:00
7ffa59d7fa formatting 2017-03-10 11:27:48 +00:00
d662391a64 removed LICENCE in readme.
It is already in the repository as the LICENCE file. No need to repeat
2017-03-10 11:26:04 +00:00
7a9661c55a moved examples to Wiki 2017-03-10 11:24:41 +00:00
f80a5654b4 adding unused variable checking 2017-03-10 10:33:42 +00:00
001b756866 Merge pull request #16 from felipeochoa/cleanup
Cleanup
2017-03-10 10:32:05 +00:00
fd1aab48f7 removed some dead code causing tslint problems 2017-03-10 10:35:38 +01:00
7ff838357a removed empty Attributes from ParagraphProperties
I checked the spec, and "w:pPr" does not take any attributes. I also
converted the paragraph tests to use the deep.equal style to get rid
of some more jsonify!
2017-03-10 10:32:40 +01:00
958b5ea307 improved type annotation for Attributes#prepForXml 2017-03-10 08:58:29 +01:00
3a6cf81c60 use strict null checks for added type safety
From the TypeScript manual "In strict null checking mode, the null and
undefined values are not in the domain of every type and are only
assignable to themselves and any (the one exception being that
undefined is also assignable to void)."

In other words, this setting means the compiler will complain if you
try to use a variable, but it might be null or undefined. Since the
project builds and tests pass with it, I think it's good to turn it
on. If it becomes annoying, you can always turn it off later
2017-03-10 08:54:55 +01:00
10684b34aa clean up unused imports and a linter warning 2017-03-10 08:52:47 +01:00
2fc9156e93 remove console.log statements 2017-03-10 08:25:11 +01:00
c521d0ce63 rename toXml -> prepForXml 2017-03-10 08:23:27 +01:00
50ca71087e reverted back as they’re both buggy 2017-03-10 00:52:43 +00:00
72eff21027 used html as markdown version is buggy 2017-03-10 00:51:42 +00:00
11bbb5e285 linting 2017-03-09 23:32:52 +00:00
18bba1870e added types for app-root-path 2017-03-09 23:20:37 +00:00
c6eef3fd79 tslint fixes 2017-03-09 23:20:28 +00:00
06353a6977 linting 2017-03-09 22:57:37 +00:00
2b28dd42ee unclear variable name. please improve 2017-03-09 22:57:30 +00:00
7022b39d2e linting 2017-03-09 22:56:08 +00:00
5fac776dca listing stuff 2017-03-09 22:31:55 +00:00
0e8d92f8bb Merge pull request #14 from felipeochoa/formatting
Clean up xml formatting (clearVariables) and introduced toXml()
2017-03-09 22:17:04 +00:00
30fef5238e fix some linter warnings 2017-03-09 21:06:54 +01:00
0fe6ff95a2 fix an incorrect test 2017-03-09 20:49:34 +01:00
11e918114d clear out clearVariables! In comes toXml 2017-03-09 20:49:14 +01:00
879b9163a3 Allow XmlComponent to take strings and remove XmlUnit 2017-03-09 20:21:49 +01:00
4a2b8a1e04 remove unused XmlProperty code 2017-03-09 19:04:17 +01:00
d6f5fe0ae8 Remove extraneous multi-property from base numbering object 2017-03-09 17:59:17 +01:00
dd4ff944d7 Merge pull request #12 from felipeochoa/styles
Styles cleanup
2017-03-09 15:25:19 +00:00
aac81ffa12 add Styles to top-level exports 2017-03-09 13:27:53 +01:00
d93432678b added #createParagraphStyle method to Styles 2017-03-09 13:27:40 +01:00
ac7799a875 add an #underline method to ParagraphStyle 2017-03-09 13:19:50 +01:00
766bcabcb8 allow Underline to be called with type and color; fix default 2017-03-09 12:42:19 +01:00
f06094c91d clean up underlineTests linter warnings 2017-03-09 12:36:33 +01:00
3b18b8267a fix paragraphTests.ts linter warnings 2017-03-09 12:25:59 +01:00
20ec9b679e added Spacing for paragraphs and ParagraphStyle 2017-03-09 12:16:49 +01:00
449d1bc2c3 added fluent formatting methods to ParagraphStyle 2017-03-09 11:27:47 +01:00
b4dca79d72 added optional name parameter to style constructor 2017-03-09 11:11:07 +01:00
e6e0658812 clean up style & components attributes 2017-03-09 11:11:07 +01:00
18ca93e50a add paragraph#style method to quickly set the style 2017-03-09 11:11:07 +01:00
f5144e6d72 ts/styles linter warnings 2017-03-09 11:11:07 +01:00
2684f16579 move indent.ts over to paragraph and add a #indent method 2017-03-09 09:59:48 +01:00
304 changed files with 9060 additions and 3200 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

15
.gitignore vendored
View File

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

View File

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

5
.prettierrc.yml Normal file
View File

@ -0,0 +1,5 @@
trailingComma: all
printWidth: 140
tabWidth: 4
arrowParens: always
bracketSpacing: true

View File

@ -1,10 +1,35 @@
language: node_js
node_js:
- "6"
- "node"
- "stable"
install:
- npm install
script:
- npm run lint
- npm test
after_failure:
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
- 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
- node ./demo/demo8.js
- node ./demo/demo9.js
- node ./demo/demo10.js
- node ./demo/demo11.js
- node ./demo/demo12.js
after_failure:
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
after_success:
- npm run typedoc
- echo "janchi.co.uk" > docs/.nojekyll
deploy:
provider: pages
skip-cleanup: true
github-token: $GITHUB_TOKEN
keep-history: true
local-dir: docs
on:
branch: master

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
}

424
README.md
View File

@ -3,390 +3,116 @@
</p>
<p align="center">
Generate .docx files with JS/TS very easily
Generate .docx files with JS/TS very easily, written in TS.
</p>
---
[![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] [![Known Vulnerabilities][snky-image]][snky-url]
[![NPM version][npm-image]][npm-url]
[![Downloads per month][downloads-image]][downloads-url]
[![Build Status][travis-image]][travis-url]
[![Dependency Status][daviddm-image]][daviddm-url]
[![Known Vulnerabilities][snky-image]][snky-url]
[![Chat on Gitter][gitter-image]][gitter-url]
[![code style: prettier][prettier-image]][prettier-url]
[![PRs Welcome][pr-image]][pr-url]
# docx
> A tool to create Word Documents (.docx) with JS or TS, written in TS.
[![NPM](https://nodei.co/npm/docx.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/docx/)
# Table of Contents
- [Install](#)
- [Usage](#)
- [Create simple Word Document](#)
- [Create Paragraph](#)
- [Styles](#)
- [Heading1 - Heading5](#)
- [Title](#)
- [Text Alignment](#)
- [Example](#)
- [Thematic Break (Page Break)](#)
- [Text](#)
- [Typographical Emphasis](#)
- [Bold](#)
- [Italics](#)
- [Underline](#)
- [Break](#)
- [Chaining](#)
- [Bullet Points](#)
- [Tab Stops](#)
- [Left Tab Stop](#)
- [Center Tab Stop](#)
- [Right Tab Stop](#)
- [Max Right Tab Stop](#)
- [Example](#)
- [Exporting](#)
- [Express](#)
- [Standalone .docx file](#)
- [Examples](#)
- [License](#)
# Install
## Install
```sh
$ npm install --save docx
```
## Demo
# Usage
Press `endpoint` on the `RunKit` website:
![RunKit Instructions](https://user-images.githubusercontent.com/2917613/38582539-f84311b6-3d07-11e8-90db-5885ae02c3c4.png)
* https://runkit.com/dolanmiu/docx-demo1 - Simple paragraph and text
* https://runkit.com/dolanmiu/docx-demo2 - Advanced Paragraphs and text
* https://runkit.com/dolanmiu/docx-demo3 - Bullet points
* https://runkit.com/dolanmiu/docx-demo4 - Simple table
* https://runkit.com/dolanmiu/docx-demo5 - Images
* https://runkit.com/dolanmiu/docx-demo6 - Margins
* https://runkit.com/dolanmiu/docx-demo7 - Landscape
* https://runkit.com/dolanmiu/docx-demo8/1.0.1 - Header and Footer
* https://runkit.com/dolanmiu/docx-demo10 - **My CV generated with docx**
#### Run demos locally:
```sh
$ npm run demo
```
This command will run the demo selector app in the `demo` folder. It will prompt you to select a demo number, which will run a demo from that folder.
## 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/index.html](http://dolanmiu.github.io/docx/index.html)
## Simple Usage
```js
// Used to create docx files
var docx = require('docx');
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
#### Full list of options:
```
creator
description
title
subject
keywords
lastModifiedBy
revision
```
Check [the Wiki](https://github.com/dolanmiu/docx/wiki/Examples) for examples.
You can mix and match whatever properties you want, or provide no properties.
# Contributing
## 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.");
```
Read the contribution guidelines [here](https://github.com/dolanmiu/docx/wiki/Contributing-Guidelines).
After you create the paragraph, you must add the paragraph into the `document`:
```js
doc.addParagraph(paragraph);
```
---
### Styles
Styles is a very important part of the look of a word document. At the moment, only headings and title is supported, but son the rest will be supported along with custom styles!
Made with 💖
![Word 2013 Styles menu](http://content.gcflearnfree.org/topics/233/style_apply_choose.png "Word 2013 Styles menu")
#### 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.
![Word 2013 Tabs](http://www.teachucomp.com/wp-content/uploads/blog-4-22-2015-UsingTabStopsInWord-1024x577.png "Word 2013 Tab Stops")
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
[downloads-image]: https://img.shields.io/npm/dm/docx.svg
[downloads-url]: https://npmjs.org/package/docx
[travis-image]: https://travis-ci.org/dolanmiu/docx.svg?branch=master
[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
[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
[prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg
[prettier-url]: https://github.com/prettier/prettier
[pr-image]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
[pr-url]: http://makeapullrequest.com

File diff suppressed because one or more lines are too long

16
demo/demo1.js Normal file
View 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!');

314
demo/demo10.js Normal file
View File

@ -0,0 +1,314 @@
const docx = require("../build");
const PHONE_NUMBER = "07534563401";
const PROFILE_URL = "https://www.linkedin.com/in/dolan1";
const EMAIL = "docx@docx.com";
const experiences = [
{
isCurrent: true,
summary: "Full-stack developer working with Angular and Java. Working for the iShares platform",
title: "Associate Software Developer",
startDate: {
month: 11,
year: 2017,
},
company: {
name: "BlackRock",
},
},
{
isCurrent: false,
summary:
"Full-stack developer working with Angular, Node and TypeScript. Working for the iShares platform. Emphasis on Dev-ops and developing the continous integration pipeline.",
title: "Software Developer",
endDate: {
month: 11,
year: 2017,
},
startDate: {
month: 10,
year: 2016,
},
company: {
name: "Torch Markets",
},
},
{
isCurrent: false,
summary:
"Used ASP.NET MVC 5 to produce a diversity data collection tool for the future of British television.\n\nUsed AngularJS and C# best practices. Technologies used include JavaScript, ASP.NET MVC 5, SQL, Oracle, SASS, Bootstrap, Grunt.",
title: "Software Developer",
endDate: {
month: 10,
year: 2016,
},
startDate: {
month: 3,
year: 2015,
},
company: {
name: "Soundmouse",
},
},
{
isCurrent: false,
summary:
"Develop web commerce platforms for various high profile clients.\n\nCreated a log analysis web application with the Play Framework in Java, incorporating Test Driven Development. It asynchronously uploads and processes large (2 GB) log files, and outputs meaningful results in context with the problem. \n\nAnalysis and development of the payment system infrastructure and user accounts section to be used by several clients of the company such as Waitrose, Tally Weijl, DJ Sports, Debenhams, Ann Summers, John Lewis and others.\n\nTechnologies used include WebSphere Commerce, Java, JavaScript and JSP.",
title: "Java Developer",
endDate: {
month: 10,
year: 2014,
},
startDate: {
month: 3,
year: 2013,
},
company: {
name: "Soundmouse",
},
},
];
const education = [
{
degree: "Master of Science (MSc)",
fieldOfStudy: "Computer Science",
notes:
"Exam Results: 1st Class with Distinction, Dissertation: 1st Class with Distinction\n\nRelevant Courses: Java and C# Programming, Software Engineering, Artificial Intelligence, \nComputational Photography, Algorithmics, Architecture and Hardware.\n\nCreated a Windows 8 game in JavaScript for the dissertation. \n\nCreated an award-winning 3D stereoscopic game in C# using XNA.",
schoolName: "University College London",
startDate: {
year: 2012,
},
endDate: {
year: 2013,
},
},
{
degree: "Bachelor of Engineering (BEng)",
fieldOfStudy: "Material Science and Engineering",
notes:
"Exam Results: 2:1, Dissertation: 1st Class with Distinction\n\nRelevant courses: C Programming, Mathematics and Business for Engineers.",
schoolName: "Imperial College London",
startDate: {
year: 2009,
},
endDate: {
year: 2012,
},
},
];
const skills = [
{
name: "Angular",
},
{
name: "TypeScript",
},
{
name: "JavaScript",
},
{
name: "NodeJS",
},
];
const achievements = [
{
issuer: "Oracle",
name: "Oracle Certified Expert",
},
];
class DocumentCreator {
create(data) {
const experiences = data[0];
const educations = data[1];
const skills = data[2];
const achivements = data[3];
const document = new docx.Document();
document.addParagraph(new docx.Paragraph("Dolan Miu").title());
document.addParagraph(this.createContactInfo(PHONE_NUMBER, PROFILE_URL, EMAIL));
document.addParagraph(this.createHeading("Education"));
for (const education of educations) {
document.addParagraph(
this.createInstitutionHeader(education.schoolName, `${education.startDate.year} - ${education.endDate.year}`),
);
document.addParagraph(this.createRoleText(`${education.fieldOfStudy} - ${education.degree}`));
const bulletPoints = this.splitParagraphIntoBullets(education.notes);
bulletPoints.forEach((bulletPoint) => {
document.addParagraph(this.createBullet(bulletPoint));
});
}
document.addParagraph(this.createHeading("Experience"));
for (const position of experiences) {
document.addParagraph(
this.createInstitutionHeader(
position.company.name,
this.createPositionDateText(position.startDate, position.endDate, position.isCurrent),
),
);
document.addParagraph(this.createRoleText(position.title));
const bulletPoints = this.splitParagraphIntoBullets(position.summary);
bulletPoints.forEach((bulletPoint) => {
document.addParagraph(this.createBullet(bulletPoint));
});
}
document.addParagraph(this.createHeading("Skills, Achievements and Interests"));
document.addParagraph(this.createSubHeading("Skills"));
document.addParagraph(this.createSkillList(skills));
document.addParagraph(this.createSubHeading("Achievements"));
for (const achievementParagraph of this.createAchivementsList(achivements)) {
document.addParagraph(achievementParagraph);
}
document.addParagraph(this.createSubHeading("Interests"));
document.addParagraph(this.createInterests("Programming, Technology, Music Production, Web Design, 3D Modelling, Dancing."));
document.addParagraph(this.createHeading("References"));
document.addParagraph(
new docx.Paragraph(
"Dr. Dean Mohamedally Director of Postgraduate Studies Department of Computer Science, University College London Malet Place, Bloomsbury, London WC1E d.mohamedally@ucl.ac.uk",
),
);
document.addParagraph(new docx.Paragraph("More references upon request"));
document.addParagraph(
new docx.Paragraph(
"This CV was generated in real-time based on my Linked-In profile from my personal website www.dolan.bio.",
).center(),
);
return document;
}
createContactInfo(phoneNumber, profileUrl, email) {
const paragraph = new docx.Paragraph().center();
const contactInfo = new docx.TextRun(`Mobile: ${phoneNumber} | LinkedIn: ${profileUrl} | Email: ${email}`);
const address = new docx.TextRun("Address: 58 Elm Avenue, Kent ME4 6ER, UK").break();
paragraph.addRun(contactInfo);
paragraph.addRun(address);
return paragraph;
}
createHeading(text) {
return new docx.Paragraph(text).heading1().thematicBreak();
}
createSubHeading(text) {
return new docx.Paragraph(text).heading2();
}
createInstitutionHeader(institutionName, dateText) {
const paragraph = new docx.Paragraph().maxRightTabStop();
const institution = new docx.TextRun(institutionName).bold();
const date = new docx.TextRun(dateText).tab().bold();
paragraph.addRun(institution);
paragraph.addRun(date);
return paragraph;
}
createRoleText(roleText) {
const paragraph = new docx.Paragraph();
const role = new docx.TextRun(roleText).italic();
paragraph.addRun(role);
return paragraph;
}
createBullet(text) {
return new docx.Paragraph(text).bullet();
}
createSkillList(skills) {
const paragraph = new docx.Paragraph();
const skillConcat = skills.map((skill) => skill.name).join(", ") + ".";
paragraph.addRun(new docx.TextRun(skillConcat));
return paragraph;
}
createAchivementsList(achivements) {
const arr = [];
for (const achievement of achivements) {
arr.push(new docx.Paragraph(achievement.name).bullet());
}
return arr;
}
createInterests(interests) {
const paragraph = new docx.Paragraph();
paragraph.addRun(new docx.TextRun(interests));
return paragraph;
}
splitParagraphIntoBullets(text) {
return text.split("\n\n");
}
createPositionDateText(startDate, endDate, isCurrent) {
const startDateText = this.getMonthFromInt(startDate.month) + ". " + startDate.year;
const endDateText = isCurrent ? "Present" : `${this.getMonthFromInt(endDate.month)}. ${endDate.year}`;
return `${startDateText} - ${endDateText}`;
}
getMonthFromInt(value) {
switch (value) {
case 1:
return "Jan";
case 2:
return "Feb";
case 3:
return "Mar";
case 4:
return "Apr";
case 5:
return "May";
case 6:
return "Jun";
case 7:
return "Jul";
case 8:
return "Aug";
case 9:
return "Sept";
case 10:
return "Oct";
case 11:
return "Nov";
case 12:
return "Dec";
}
}
}
const documentCreator = new DocumentCreator();
const doc = documentCreator.create([experiences, education, skills, achievements]);
var exporter = new docx.LocalPacker(doc);
exporter.pack("Dolan Miu CV");
console.log("Document created successfully at project root!");

132
demo/demo11.js Normal file
View File

@ -0,0 +1,132 @@
const docx = require("../build");
const doc = new docx.Document(undefined, {
top: 700,
right: 700,
bottom: 700,
left: 700,
});
doc.Styles.createParagraphStyle("Heading1", "Heading 1")
.basedOn("Normal")
.next("Normal")
.quickFormat()
.font("Calibri")
.size(52)
.center()
.bold()
.color(000000)
.spacing({ line: 340 })
.underline("single", "000000");
doc.Styles.createParagraphStyle("Heading2", "Heading 2")
.basedOn("Normal")
.next("Normal")
.font("Calibri")
.quickFormat()
.size(26)
.bold()
.spacing({ line: 340 });
doc.Styles.createParagraphStyle("Heading3", "Heading 3")
.basedOn("Normal")
.next("Normal")
.font("Calibri")
.quickFormat()
.size(26)
.bold()
.spacing({ line: 276 });
doc.Styles.createParagraphStyle("Heading4", "Heading 4")
.basedOn("Normal")
.next("Normal")
.justified()
.font("Calibri")
.size(26)
.bold();
doc.Styles.createParagraphStyle("normalPara", "Normal Para")
.basedOn("Normal")
.next("Normal")
.font("Calibri")
.quickFormat()
.leftTabStop(453.543307087)
.maxRightTabStop(453.543307087)
.size(26)
.spacing({ line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 });
doc.Styles.createParagraphStyle("normalPara2", "Normal Para2")
.basedOn("Normal")
.next("Normal")
.quickFormat()
.font("Calibri")
.size(26)
.justified()
.spacing({ line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 });
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 * 0.1, after: 20 * 72 * 0.05 });
doc.Styles.createParagraphStyle("ListParagraph", "List Paragraph")
.quickFormat()
.basedOn("Normal");
doc.createImage("./demo/images/pizza.gif");
doc
.createParagraph("HEADING")
.heading1()
.center();
doc.Footer.createParagraph("1")
.style("normalPara")
.right();
doc.createParagraph("Ref. :").style("normalPara");
doc.createParagraph("Date :").style("normalPara");
doc.createParagraph("To,").style("normalPara");
doc.createParagraph("The Superindenting Engineer,(O &M)").style("normalPara");
doc.createParagraph("Sub : ").style("normalPara");
doc.createParagraph("Ref. : ").style("normalPara");
doc.createParagraph("Sir,").style("normalPara");
doc.createParagraph("BRIEF DESCRIPTION").style("normalPara");
var table = new docx.Table(4, 4);
var contentParagraph = table
.getRow(0)
.getCell(0)
.addContent(new docx.Paragraph("Pole No."));
table.properties.width = 10000;
doc.addTable(table);
var arrboth = [{
image: "./demo/images/pizza.gif",
comment: "Test"
}, {
image: "./demo/images/pizza.gif",
comment: "Test 2"
}];
arrboth.forEach(function(item) {
const para = doc.createParagraph();
para.createTextRun(doc.createImage(item.image));
para.properties.width = 60;
para.properties.height = 90;
doc.createParagraph(item.comment).style("normalPara2");
});
var exporter = new docx.LocalPacker(doc);
exporter.pack("My Document");

21
demo/demo12.js Normal file
View File

@ -0,0 +1,21 @@
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/pizza.gif");
const image2 = doc.createImage("./demo/images/pizza.gif");
const image3 = doc.createImage("./demo/images/pizza.gif");
const image4 = doc.createImage("./demo/images/pizza.gif");
image.scale(0.5);
image2.scale(1)
image3.scale(2.5);
image4.scale(4);
var exporter = new docx.LocalPacker(doc);
exporter.pack("My Document");
console.log("Document created successfully at project root!");

26
demo/demo13.js Normal file
View File

@ -0,0 +1,26 @@
// This example shows 3 styles
const fs = require('fs');
const docx = require('../build');
const styles = fs.readFileSync('./demo/assets/custom-styles.xml', 'utf-8');
const doc = new docx.Document({
title: 'Title',
externalStyles: styles
});
doc.createParagraph('Cool Heading Text').heading1();
let paragraph = new docx.Paragraph('This is a custom named style from the template "MyFancyStyle"');
paragraph.style('MyFancyStyle');
doc.addParagraph(paragraph);
doc.createParagraph('Some normal text')
doc.createParagraph('MyFancyStyle again').style('MyFancyStyle');
paragraph.style('MyFancyStyle');
doc.addParagraph(paragraph);
var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

23
demo/demo14.js Normal file
View File

@ -0,0 +1,23 @@
const docx = require('../build');
var doc = new docx.Document(undefined,{differentFirstPageHeader:true});
doc.createParagraph("First Page").pageBreak()
doc.createParagraph("Second Page");
var pageNumber = new docx.TextRun().pageNumber()
var pageoneheader = new docx.Paragraph("First Page Header ").right();
pageoneheader.addRun(pageNumber);
doc.firstPageHeader.addParagraph(pageoneheader);
var pagetwoheader = new docx.Paragraph("My Title ").right();
pagetwoheader.addRun(pageNumber)
doc.Header.addParagraph(pagetwoheader)
var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

74
demo/demo2.js Normal file
View 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!');

45
demo/demo3.js Normal file
View File

@ -0,0 +1,45 @@
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 bullet1 = new docx.Paragraph("Hey you").bullet();
var bullet2 = new docx.Paragraph("What's up fam").bullet(1);
var bullet3 = new docx.Paragraph("Hello World 2").bullet(2);
var bullet4 = new docx.Paragraph("Yeah boi").bullet(3);
doc.addParagraph(bullet1);
doc.addParagraph(bullet2);
doc.addParagraph(bullet3);
doc.addParagraph(bullet4);
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

BIN
demo/images/image1.jpeg Normal file

Binary file not shown.

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

View File

@ -1,40 +1,55 @@
{
"name": "docx",
"version": "1.2.1",
"version": "3.6.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",
"pretest": "rimraf ./build",
"test": "mocha-webpack \"src/**/*.ts\"",
"test-watch": "mocha-webpack \"src/**/*.ts\" --watch",
"prepublishOnly": "npm run build",
"lint": "tslint --project ./ts",
"build": "rimraf ./build && tsc -p ts"
"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": "typedoc --out docs/ src/ --module commonjs --target ES6 --disableOutputCheck --excludePrivate --externalPattern \"**/*.spec.ts\"",
"style": "prettier -l \"src/**/*.ts\"",
"style.fix": "prettier \"src/**/*.ts\" --write",
"fix-types": "node types-absolute-fixer.js"
},
"files": [
"ts",
"build"
"src",
"build",
"template"
],
"repository": {
"type": "git",
"url": "git+https://github.com/dolanmiu/docx.git"
},
"keywords": [
"docx",
"office",
"word",
"generate",
"creator",
"create",
"document",
"doc",
"officegen",
"clippy"
],
"types": "./build/index.d.ts",
"dependencies": {
"@types/archiver": "^0.15.37",
"@types/archiver": "^2.1.0",
"@types/express": "^4.0.35",
"@types/lodash": "^4.14.54",
"app-root-path": "^2.0.1",
"archiver": "^1.3.0",
"install": "^0.8.7",
"lodash": "^4.6.1",
"npm": "^4.3.0",
"@types/image-size": "0.0.29",
"@types/request-promise": "^4.1.41",
"archiver": "^2.1.1",
"fast-xml-parser": "^3.3.6",
"image-size": "^0.6.2",
"request": "^2.83.0",
"request-promise": "^4.2.2",
"xml": "^1.0.1"
},
"author": "Dolan Miu",
@ -46,10 +61,21 @@
"devDependencies": {
"@types/chai": "^3.4.35",
"@types/mocha": "^2.2.39",
"@types/sinon": "^4.3.1",
"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.12.1",
"prompt": "^1.0.0",
"replace-in-file": "^3.1.0",
"rimraf": "^2.5.2",
"tslint": "^4.5.1",
"typescript": "^2.2.1"
"shelljs": "^0.7.7",
"sinon": "^5.0.7",
"tslint": "^5.1.0",
"typedoc": "^0.9.0",
"typescript": "2.6.2",
"webpack": "^3.10.0"
}
}

View 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
View File

@ -0,0 +1,7 @@
import { BaseXmlComponent, IXmlableObject } from "file/xml-components";
export class Formatter {
public format(input: BaseXmlComponent): IXmlableObject {
return input.prepForXml();
}
}

4
src/export/index.ts Normal file
View File

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

View File

@ -0,0 +1,110 @@
import * as archiver from "archiver";
import * as express from "express";
import { Writable } from "stream";
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: Writable | 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 xmlHeader2 = xml(this.formatter.format(this.file.firstPageHeader.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(xmlHeader2, {
name: "word/header2.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,43 @@
// tslint:disable:typedef space-before-function-paren
// tslint:disable:no-empty
// tslint:disable:no-any
import { assert } from "chai";
import { stub } from "sinon";
import { ExpressPacker } from "../../export/packer/express";
import { File, Paragraph } from "../../file";
describe("LocalPacker", () => {
let packer: ExpressPacker;
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);
const expressResMock = {
on: () => {},
attachment: () => {},
};
packer = new ExpressPacker(file, expressResMock as any);
});
describe("#pack()", () => {
it("should handle exception if it throws any", () => {
const compiler = stub((packer as any).packer, "compile");
compiler.throwsException();
return packer.pack("build/tests/test").catch((error) => {
assert.isDefined(error);
});
});
});
});

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,66 @@
/* tslint:disable:typedef space-before-function-paren */
import { assert } from "chai";
import * as fs from "fs";
import { stub } from "sinon";
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");
});
it("should handle exception if it throws any", () => {
// tslint:disable-next-line:no-any
const compiler = stub((packer as any).packer, "compile");
compiler.throwsException();
return packer.pack("build/tests/test").catch((error) => {
assert.isDefined(error);
});
});
});
describe("#packPdf", () => {
it("should create a standard PDF file", async function() {
this.timeout(99999999);
// tslint:disable-next-line:no-any
const pdfConverterConvert = stub((packer as any).pdfConverter, "convert");
pdfConverterConvert.returns("Test PDF Contents");
await packer.packPdf("build/tests/pdf-test");
fs.statSync("build/tests/pdf-test.pdf");
});
it("should handle exception if it throws any", () => {
// tslint:disable-next-line:no-any
const compiler = stub((packer as any).packer, "compile");
compiler.throwsException();
return packer.packPdf("build/tests/pdf-test").catch((error) => {
assert.isDefined(error);
});
});
});
});

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,25 @@
import { Readable, Transform } from "stream";
import { File } from "../../file";
import { Compiler } from "./compiler";
import { IPacker } from "./packer";
class Pipe extends Transform {
public _transform(chunk: Buffer | string, encoding: string, callback: () => void): void {
this.push(chunk, encoding);
callback();
}
}
export class StreamPacker implements IPacker {
private readonly compiler: Compiler;
constructor(file: File) {
this.compiler = new Compiler(file);
}
public pack(): Readable {
const pipe = new Pipe();
this.compiler.compile(pipe);
return pipe;
}
}

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,36 @@
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.header+xml", "/word/header2.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,66 +1,57 @@
import { DocumentAttributes } from "../docx/document/document-attributes";
import { XmlUnitComponent } from "../docx/xml-components";
import { XmlComponent } from "../docx/xml-components";
export class Title extends XmlUnitComponent {
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 = value;
this.root.push(value);
}
}
export class Subject extends XmlUnitComponent {
export class Subject extends XmlComponent {
constructor(value: string) {
super("dc:subject");
this.root = value;
this.root.push(value);
}
}
export class Creator extends XmlUnitComponent {
export class Creator extends XmlComponent {
constructor(value: string) {
super("dc:creator");
this.root = value;
this.root.push(value);
}
}
export class Keywords extends XmlUnitComponent {
export class Keywords extends XmlComponent {
constructor(value: string) {
super("cp:keywords");
this.root = value;
this.root.push(value);
}
}
export class Description extends XmlUnitComponent {
export class Description extends XmlComponent {
constructor(value: string) {
super("dc:description");
this.root = value;
this.root.push(value);
}
}
export class LastModifiedBy extends XmlUnitComponent {
export class LastModifiedBy extends XmlComponent {
constructor(value: string) {
super("cp:lastModifiedBy");
this.root = value;
this.root.push(value);
}
}
export class Revision extends XmlUnitComponent {
export class Revision extends XmlComponent {
constructor(value: string) {
super("cp:revision");
const revision = value;
this.root = value;
this.root.push(value);
}
}
abstract class DateComponent extends XmlComponent {
protected getCurrentDate(): any {
export abstract class DateComponent extends XmlComponent {
protected getCurrentDate(): string {
const date = new Date();
const year = date.getFullYear();
const month = ("0" + (date.getMonth() + 1)).slice(-2);
@ -74,23 +65,25 @@ abstract class DateComponent extends XmlComponent {
}
export class Created extends DateComponent {
constructor() {
super("dcterms:created");
this.root.push(new DocumentAttributes({
type: "dcterms:W3CDTF",
}));
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(
new DocumentAttributes({
type: "dcterms:W3CDTF",
}),
);
this.root.push(this.getCurrentDate());
}
}

View File

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

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

View File

@ -0,0 +1,52 @@
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;
externalStyles?: 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());
}
}

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(order: string, refID: number) {
super("w:headerReference");
this.root.push(
new HeaderReferenceAttributes({
type: order,
id: `rId${refID}`,
}),
);
}
}

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,65 @@
// 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";
import { TitlePage } from "./title-page/title-page";
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",
differentFirstPageHeader: false,
};
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("default", 3));
if (mergedOptions.differentFirstPageHeader) {
this.root.push(new HeaderReference("first", 5));
this.root.push(new TitlePage());
}
this.root.push(new FooterReference());
}
}

View File

@ -0,0 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IHeaderReferenceAttributes {
value: string;
}
export class TitlePageAttributes extends XmlAttributeComponent<IHeaderReferenceAttributes> {
protected xmlKeys = {
value: "w:val",
};
}

View File

@ -0,0 +1,17 @@
import { expect } from "chai";
import { Formatter } from "../../../../../export/formatter";
import { TitlePage } from "./title-page";
describe("PageSize", () => {
describe("#constructor()", () => {
it("should create title page property for different first page header", () => {
const properties = new TitlePage();
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:titlePg"]);
expect(tree["w:titlePg"]).to.be.an.instanceof(Array);
expect(tree["w:titlePg"][0]).to.deep.equal({ _attr: { "w:val": "1" } });
});
});
});

View File

@ -0,0 +1,13 @@
import { XmlComponent } from "file/xml-components";
import { TitlePageAttributes } from "./title-page-attributes";
export class TitlePage extends XmlComponent {
constructor() {
super("w:titlePg");
this.root.push(
new TitlePageAttributes({
value: "1",
}),
);
}
}

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

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(pictureParagraph: Paragraph): void {
this.body.push(pictureParagraph);
}
public createDrawing(imageData: IMediaData): PictureRun {
const paragraph = new Paragraph();
const run = new PictureRun(imageData);
paragraph.addRun(run);
this.addDrawing(paragraph);
return run;
}
}

View File

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

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

View File

@ -0,0 +1,23 @@
import { IMediaData } from "file/media";
import { XmlComponent } from "file/xml-components";
import { Inline } from "./inline";
export class Drawing extends XmlComponent {
private inline: Inline;
constructor(imageData: IMediaData) {
super("w:drawing");
if (imageData === undefined) {
throw new Error("imageData cannot be undefined");
}
this.inline = new Inline(imageData.referenceId, imageData.dimensions);
this.root.push(this.inline);
}
public scale(factorX: number, factorY: number): void {
this.inline.scale(factorX, factorY);
}
}

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,24 @@
import { XmlComponent } from "file/xml-components";
import { ExtentAttributes } from "./extent-attributes";
export class Extent extends XmlComponent {
private attributes: ExtentAttributes;
constructor(x: number, y: number) {
super("wp:extent");
this.attributes = new ExtentAttributes({
cx: x,
cy: y,
});
this.root.push(this.attributes);
}
public setXY(x: number, y: number): void {
this.attributes.set({
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,25 @@
import { XmlComponent } from "file/xml-components";
import { GraphicDataAttributes } from "./graphic-data-attribute";
import { Pic } from "./pic";
export class GraphicData extends XmlComponent {
private pic: Pic;
constructor(referenceId: number, x: number, y: number) {
super("a:graphicData");
this.root.push(
new GraphicDataAttributes({
uri: "http://schemas.openxmlformats.org/drawingml/2006/picture",
}),
);
this.pic = new Pic(referenceId, x, y);
this.root.push(this.pic);
}
public setXY(x: number, y: number): void {
this.pic.setXY(x, y);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

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

Some files were not shown because too many files have changed in this diff Show More