Compare commits

...

415 Commits
1.0.1 ... 3.4.0

Author SHA1 Message Date
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
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
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
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
77255c9d5e modified build script and version bump 2017-03-08 23:35:22 +00:00
e10b8889f7 version bump 2017-03-08 23:27:55 +00:00
744b16b753 tslinting 2017-03-08 21:59:27 +00:00
77824ce1d2 tslinting fixes 2017-03-08 21:56:19 +00:00
d2f777c4e5 more listing 2017-03-08 21:54:52 +00:00
946a222d37 linting fixes 2017-03-08 21:49:41 +00:00
279a5a93f1 fixed failing test 2017-03-08 21:40:21 +00:00
0e89606ec9 lots of tslinting 2017-03-08 21:36:09 +00:00
72683ea990 fixed bug where snky badge wasn’t displaying 2017-03-08 20:42:56 +00:00
88cf5f5065 added vulnerability checker 2017-03-08 20:37:21 +00:00
540518bd54 more tslinting 2017-03-08 20:35:26 +00:00
03b34915c6 tslinting 2017-03-08 20:32:30 +00:00
f6eb412357 removed numbering.md in favour of Wiki 2017-03-08 20:26:08 +00:00
ca769cc849 Merge pull request #11 from felipeochoa/fonts
Fonts cleanup
2017-03-08 20:16:17 +00:00
727471b7e3 fix linter warnings in docx/run/index.ts 2017-03-08 20:52:37 +01:00
1a37242a3d add #font method to Run 2017-03-08 20:47:36 +01:00
81e0d56918 fix linter warnings in runTest.ts 2017-03-08 20:47:35 +01:00
237be76d33 move run-fonts to docx/run and add a test 2017-03-08 20:47:35 +01:00
a454ff9643 Merge pull request #10 from felipeochoa/numbering
Numbering
2017-03-08 19:30:21 +00:00
f7b90d4ff3 add default argument "start" to createLevel 2017-03-08 19:18:24 +01:00
cee515e43f added Numbering to top-level exports and added docs on usage 2017-03-08 19:07:44 +01:00
0e9532d835 added #setNumbering method to paragraph 2017-03-08 18:23:00 +01:00
4b300e4def add fluent interface for defining abstract numbering levels 2017-03-08 18:03:39 +01:00
1fe7ab90f2 add createLevel method to AbstractNumbering 2017-03-08 18:03:24 +01:00
a3d2323254 rename methods from addXXX to createXXX
addXXX sounds like the argument should be XXX
2017-03-08 17:49:41 +01:00
0b2de737de fix linter warnings in numbering/index.ts 2017-03-08 17:45:29 +01:00
0a70d932a0 fix numberingTest linter warnings 2017-03-08 17:45:29 +01:00
6b702c4bd6 add ID property to Num and test Numbering methods 2017-03-08 17:45:29 +01:00
709ff25702 add #addAbstractNumbering and #addConcreteNumbering to Numbering 2017-03-08 17:45:29 +01:00
82998d4f6b record ID in AbstractNumbering 2017-03-08 17:45:29 +01:00
6e6a06eba4 fix numbering/num.ts linter warnings 2017-03-08 17:45:29 +01:00
ae70c2dfde fix numbering/indent.ts linter warnings 2017-03-08 17:45:29 +01:00
28e11a9b08 fix numbering/multi-level-type linter warnings 2017-03-08 17:45:29 +01:00
f5e81f1dfc fix numbering/level linter warnings 2017-03-08 17:45:29 +01:00
38138049fe fix abstract-number linter warnings 2017-03-08 17:45:29 +01:00
5511024ca6 fix run-fonts for new numbering test (and linter warnings) 2017-03-08 17:45:29 +01:00
ef1407e640 add a test for numbering 2017-03-08 17:45:29 +01:00
f822bbb26f fix typos in default numbering definition 2017-03-08 17:45:29 +01:00
52c4e3cabd allow NumberProperties to specify custom id/level
This change allows callers to create custom numbering styles and
attach them to paragraphs
2017-03-08 16:20:44 +01:00
9ced196678 Merge pull request #8 from felipeochoa/npm-fix
Npm fixes - prepublish and files
2017-03-08 15:11:58 +00:00
ef6e195e89 add an .npmignore file which does not exclude the build dir
Per https://docs.npmjs.com/misc/developers#keeping-files-out-of-your-package,
npm automatically uses .gitignore if there is no .npmignore, which may
have been keeping the build dir out of the package
2017-03-08 14:17:46 +01:00
a77d520f41 add the build files to the npm package 2017-03-08 12:05:47 +01:00
8eb11bca29 fix npm prepublish-on-install warnings 2017-03-08 12:05:47 +01:00
660a81633f removed copy and paste description 2017-03-07 23:15:26 +00:00
a917247b60 removed inverted comma 2017-03-07 23:13:04 +00:00
f492b3fe04 fixed pages bug 2017-03-07 23:12:08 +00:00
96a8942455 updated readme 2017-03-07 23:10:35 +00:00
bca478bb81 updated tslint and ignored some files 2017-03-07 23:05:09 +00:00
f5de5fef4d added tslint support 2017-03-07 22:56:59 +00:00
0e9301c0b5 clean up comment 2017-03-07 22:48:25 +00:00
b0869567c6 used more generic .vscode gitignore 2017-03-07 22:48:12 +00:00
0585a25a5a removed typescript 2017-03-07 22:37:40 +00:00
9804091f6a removed random semi colon 2017-03-07 22:35:20 +00:00
9c3023019f huge clean up of project. Now uses @types, and removed committed typings.
Formatted the imports too
2017-03-07 22:15:53 +00:00
306 changed files with 8207 additions and 26844 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
build-tests build-tests
# vscode # VSCode
ts/.vscode .vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history
# Lock files
package-lock.json
# Documents
My Document.docx

43
.npmignore Normal file
View File

@ -0,0 +1,43 @@
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
node_modules
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history
# build
# build <-- we want this in the package
build-tests
# vscode
.vscode
# docs
docs

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 language: node_js
node_js: node_js:
- "6" - "stable"
- "node"
install: install:
- npm install - npm install
script: script:
- npm run lint
- npm test - npm test
- npm run style
- npm run build
- node ./demo/demo1.js
- node ./demo/demo2.js
- node ./demo/demo3.js
- node ./demo/demo4.js
- node ./demo/demo5.js
- node ./demo/demo6.js
- node ./demo/demo7.js
- node ./demo/demo8.js
- node ./demo/demo9.js
- node ./demo/demo10.js
- node ./demo/demo11.js
- node ./demo/demo12.js
after_failure: after_failure:
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log" - "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
after_success:
- 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

@ -1,378 +1,104 @@
# [![NPM version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url] <p align="center">
<img alt="clippy the assistant" src="http://i60.tinypic.com/339pvtt.png">
</p>
> A tool to create Word Documents (.docx) with JS or TS, written in TS. <p align="center">
Generate .docx files with JS/TS very easily, written in TS.
</p>
---
[![NPM version][npm-image]][npm-url]
[![Build Status][travis-image]][travis-url]
[![Dependency Status][gemnasium-image]][gemnasium-url]
[![Known Vulnerabilities][snky-image]][snky-url]
[![Chat on Gitter][gitter-image]][gitter-url]
[![code style: prettier][prettier-image]][prettier-url]
[![NPM](https://nodei.co/npm/docx.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/docx/) [![NPM](https://nodei.co/npm/docx.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/docx/)
![Clippy in Microsoft Office](http://i60.tinypic.com/339pvtt.png "Clippy in Microsoft Office") # docx
# Table of Contents ## Install
- [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
```sh ```sh
$ npm install --save docx $ 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 ```js
// Used to create docx files // Used to create docx files
var docx = require('docx'); var docx = require("docx");
// Create document // Create document
var doc = new docx.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 // 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 // res is express' Response object
var exporter = new docx.ExpressPacker(doc, res); 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(); exporter.pack("My First Document");
var text = new docx.TextRun('Hello World'); // If you want to export it as a .pdf file instead
paragraph.addText(text); exporter.packPdf("My First Document");
doc.addParagraph(paragraph);
// 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 ## Examples
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'
});
```
#### Full list of options: Check [the Wiki](https://github.com/dolanmiu/docx/wiki/Examples) for examples.
```
creator
description
title
subject
keywords
lastModifiedBy
revision
```
You can mix and match whatever properties you want, or provide no properties. # Contributing
## Create Paragraph Read the contribution guidelines [here](https://github.com/dolanmiu/docx/wiki/Contributing-Guidelines).
Every text block in OpenXML is organised in paragraphs. You can add more text to the paragraph by doing this:
```js
var paragraph = new docx.Paragraph(),
```
```js
var text = new docx.TextRun('Lorem Ipsum Foo Bar');
var paragraph = new docx.Paragraph();
paragraph.addText(text);
```
```js
var paragraph = new docx.Paragraph("Short hand notation for adding text.");
```
After you create the paragraph, you must add the paragraph into the `document`: ---
```js
doc.addParagraph(paragraph);
```
### Styles Made with 💖
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!
![Word 2013 Styles menu](http://content.gcflearnfree.org/topics/233/style_apply_choose.png "Word 2013 Styles menu") Huge thanks to [@felipeochoa](https://github.com/felipeochoa) for awesome contributions to this project
#### 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.
[npm-image]: https://badge.fury.io/js/docx.svg [npm-image]: https://badge.fury.io/js/docx.svg
[npm-url]: https://npmjs.org/package/docx [npm-url]: https://npmjs.org/package/docx
@ -380,3 +106,11 @@ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
[travis-url]: https://travis-ci.org/dolanmiu/docx [travis-url]: https://travis-ci.org/dolanmiu/docx
[daviddm-image]: https://david-dm.org/dolanmiu/docx.svg?theme=shields.io [daviddm-image]: https://david-dm.org/dolanmiu/docx.svg?theme=shields.io
[daviddm-url]: https://david-dm.org/dolanmiu/docx [daviddm-url]: https://david-dm.org/dolanmiu/docx
[snky-image]: https://snyk.io/test/github/dolanmiu/docx/badge.svg
[snky-url]: https://snyk.io/test/github/dolanmiu/docx
[gitter-image]: https://badges.gitter.im/dolanmiu/docx.svg
[gitter-url]: https://gitter.im/docx-lib/Lobby
[gemnasium-image]: https://gemnasium.com/badges/github.com/dolanmiu/docx.svg
[gemnasium-url]: https://gemnasium.com/github.com/dolanmiu/docx
[prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg
[prettier-url]: https://github.com/prettier/prettier

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

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,32 +1,55 @@
{ {
"name": "docx", "name": "docx",
"version": "1.0.1", "version": "3.4.0",
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)", "description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
"main": "build/index.js", "main": "build/index.js",
"scripts": { "scripts": {
"pretest": "rimraf ./build-tests && tsc -p ts/test-tsconfig.json", "pretest": "rimraf ./build",
"test": "mocha ./build-tests --recursive", "test": "mocha-webpack \"src/**/*.ts\"",
"prepublish": "tsc -p ts" "test-watch": "mocha-webpack \"src/**/*.ts\" --watch",
"prepublishOnly": "npm run build",
"lint": "tslint --project .",
"build": "npm run webpack && npm run fix-types",
"tsc": "rimraf ./build && tsc -p .",
"webpack": "rimraf ./build && webpack",
"demo": "npm run build && node ./demo",
"typedoc": "typedoc --out docs/ src/ --module commonjs --target ES6 --disableOutputCheck --excludePrivate --externalPattern \"**/*.spec.ts\"",
"style": "prettier -l \"src/**/*.ts\"",
"fix-types": "node types-absolute-fixer.js"
}, },
"files": [
"src",
"build",
"template"
],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/dolanmiu/docx.git" "url": "git+https://github.com/dolanmiu/docx.git"
}, },
"keywords": [ "keywords": [
"docx",
"office", "office",
"word",
"generate", "generate",
"creator",
"create",
"document", "document",
"doc" "doc",
"officegen",
"clippy"
], ],
"types": "./build/index.d.ts",
"dependencies": { "dependencies": {
"app-root-path": "^2.0.1", "@types/archiver": "^2.1.0",
"archiver": "^1.3.0", "@types/express": "^4.0.35",
"lodash": "^4.6.1", "@types/image-size": "0.0.29",
"@types/request-promise": "^4.1.41",
"archiver": "^2.1.1",
"image-size": "^0.6.2",
"request": "^2.83.0",
"request-promise": "^4.2.2",
"xml": "^1.0.1" "xml": "^1.0.1"
}, },
"typescript": {
"definition": "ts/typings/index.d.ts"
},
"author": "Dolan Miu", "author": "Dolan Miu",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
@ -34,9 +57,21 @@
}, },
"homepage": "https://github.com/dolanmiu/docx#readme", "homepage": "https://github.com/dolanmiu/docx#readme",
"devDependencies": { "devDependencies": {
"@types/chai": "^3.4.35",
"@types/mocha": "^2.2.39",
"awesome-typescript-loader": "^3.4.1",
"chai": "^3.5.0", "chai": "^3.5.0",
"glob": "^7.1.2",
"mocha": "^3.2.0", "mocha": "^3.2.0",
"mocha-webpack": "^1.0.1",
"prettier": "^1.10.2",
"prompt": "^1.0.0",
"replace-in-file": "^3.1.0",
"rimraf": "^2.5.2", "rimraf": "^2.5.2",
"typescript": "^2.2.1" "shelljs": "^0.7.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,105 @@
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 xmlFooter = xml(this.formatter.format(this.file.Footer.Footer));
const xmlHeaderRelationships = xml(this.formatter.format(this.file.Header.Relationships));
const xmlFooterRelationships = xml(this.formatter.format(this.file.Footer.Relationships));
const xmlContentTypes = xml(this.formatter.format(this.file.ContentTypes));
const xmlAppProperties = xml(this.formatter.format(this.file.AppProperties));
this.archive.append(xmlDocument, {
name: "word/document.xml",
});
this.archive.append(xmlStyles, {
name: "word/styles.xml",
});
this.archive.append(xmlProperties, {
name: "docProps/core.xml",
});
this.archive.append(xmlAppProperties, {
name: "docProps/app.xml",
});
this.archive.append(xmlNumbering, {
name: "word/numbering.xml",
});
this.archive.append(xmlHeader, {
name: "word/header1.xml",
});
this.archive.append(xmlFooter, {
name: "word/footer1.xml",
});
this.archive.append(xmlRelationships, {
name: "word/_rels/document.xml.rels",
});
this.archive.append(xmlHeaderRelationships, {
name: "word/_rels/header1.xml.rels",
});
this.archive.append(xmlFooterRelationships, {
name: "word/_rels/footer1.xml.rels",
});
this.archive.append(xmlContentTypes, {
name: "[Content_Types].xml",
});
this.archive.append(xmlFileRelationships, {
name: "_rels/.rels",
});
for (const data of this.file.Media.array) {
this.archive.append(data.stream, {
name: `word/media/${data.fileName}`,
});
}
this.archive.finalize();
return new Promise<void>((resolve) => {
output.on("close", () => {
resolve();
});
});
}
}

View File

@ -0,0 +1,29 @@
import * as express from "express";
import { File } from "file";
import { Compiler } from "./compiler";
import { IPacker } from "./packer";
export class ExpressPacker implements IPacker {
private readonly packer: Compiler;
constructor(file: File, private readonly res: express.Response) {
this.packer = new Compiler(file);
this.res = res;
this.res.on("close", () => {
return res
.status(200)
.send("OK")
.end();
});
}
public async pack(name: string): Promise<void> {
name = name.replace(/.docx$/, "");
this.res.attachment(`${name}.docx`);
await this.packer.compile(this.res);
}
}

View File

@ -0,0 +1,42 @@
/* tslint:disable:typedef space-before-function-paren */
import * as fs from "fs";
import { LocalPacker } from "../../export/packer/local";
import { File, Paragraph } from "../../file";
describe("LocalPacker", () => {
let packer: LocalPacker;
beforeEach(() => {
const file = new File({
creator: "Dolan Miu",
revision: "1",
lastModifiedBy: "Dolan Miu",
});
const paragraph = new Paragraph("test text");
const heading = new Paragraph("Hello world").heading1();
file.addParagraph(new Paragraph("title").title());
file.addParagraph(heading);
file.addParagraph(new Paragraph("heading 2").heading2());
file.addParagraph(paragraph);
packer = new LocalPacker(file);
});
describe("#pack()", () => {
it("should create a standard docx file", async function() {
this.timeout(99999999);
await packer.pack("build/tests/test");
fs.statSync("build/tests/test.docx");
});
});
describe("#packPdf", () => {
it("should create a standard PDF file", async function() {
this.timeout(99999999);
await packer.packPdf("build/tests/pdf-test");
fs.statSync("build/tests/pdf-test.pdf");
});
});
});

View File

@ -0,0 +1,47 @@
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import { File } from "../../file";
import { Compiler } from "./compiler";
import { IPacker } from "./packer";
import { PdfConvertWrapper } from "./pdf-convert-wrapper";
export class LocalPacker implements IPacker {
private stream: fs.WriteStream;
private readonly pdfConverter: PdfConvertWrapper;
private readonly packer: Compiler;
constructor(file: File) {
this.pdfConverter = new PdfConvertWrapper();
this.packer = new Compiler(file);
}
public async pack(filePath: string): Promise<void> {
filePath = filePath.replace(/.docx$/, "");
this.stream = fs.createWriteStream(`${filePath}.docx`);
await this.packer.compile(this.stream);
}
public async packPdf(filePath: string): Promise<void> {
filePath = filePath.replace(/.pdf$/, "");
const fileName = path.basename(filePath, path.extname(filePath));
const tempPath = path.join(os.tmpdir(), `${fileName}.docx`);
this.stream = fs.createWriteStream(tempPath);
await this.packer.compile(this.stream);
const text = await this.pdfConverter.convert(tempPath);
// const writeFile = util.promisify(fs.writeFile); --use this in future, in 3 years time. Only in node 8
// return writeFile(`${filePath}.pdf`, text);
return new Promise<void>((resolve, reject) => {
fs.writeFile(`${filePath}.pdf`, text, (err) => {
if (err) {
reject(err);
return;
}
resolve();
});
});
}
}

View File

@ -0,0 +1,6 @@
export interface IPacker {
pack(path: string): void;
}
// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432
export const WORKAROUND = "";

View File

@ -0,0 +1,35 @@
/* tslint:disable:object-literal-key-quotes */
// This tslint disable is needed, or it simply won't work
import * as fs from "fs";
import * as request from "request-promise";
export interface IConvertOutput {
data: string;
}
export class PdfConvertWrapper {
public convert(filePath: string): request.RequestPromise {
return request.post({
url: "http://mirror1.convertonlinefree.com",
encoding: null,
headers: {
"User-Agent":
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36",
},
formData: {
__EVENTTARGET: "",
__EVENTARGUMENT: "",
__VIEWSTATE: "",
ctl00$MainContent$fu: {
value: fs.readFileSync(filePath),
options: {
filename: "output.docx",
contentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
},
},
ctl00$MainContent$btnConvert: "Convert",
ctl00$MainContent$fuZip: "",
},
});
}
}

View File

@ -0,0 +1,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,34 @@
import { XmlComponent } from "file/xml-components";
import { ContentTypeAttributes } from "./content-types-attributes";
import { Default } from "./default/default";
import { Override } from "./override/override";
export class ContentTypes extends XmlComponent {
constructor() {
super("Types");
this.root.push(
new ContentTypeAttributes({
xmlns: "http://schemas.openxmlformats.org/package/2006/content-types",
}),
);
this.root.push(new Default("image/png", "png"));
this.root.push(new Default("image/jpeg", "jpeg"));
this.root.push(new Default("image/jpeg", "jpg"));
this.root.push(new Default("image/bmp", "bmp"));
this.root.push(new Default("image/gif", "gif"));
this.root.push(new Default("application/vnd.openxmlformats-package.relationships+xml", "rels"));
this.root.push(new Default("application/xml", "xml"));
this.root.push(
new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", "/word/document.xml"),
);
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", "/word/header1.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", "/word/footer1.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", "/word/styles.xml"));
this.root.push(new Override("application/vnd.openxmlformats-package.core-properties+xml", "/docProps/core.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.extended-properties+xml", "/docProps/app.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", "/word/numbering.xml"));
}
}

View File

@ -0,0 +1,13 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IDefaultAttributes {
contentType: string;
extension?: string;
}
export class DefaultAttributes extends XmlAttributeComponent<IDefaultAttributes> {
protected xmlKeys = {
contentType: "ContentType",
extension: "Extension",
};
}

View File

@ -0,0 +1,15 @@
import { XmlComponent } from "file/xml-components";
import { DefaultAttributes } from "./default-attributes";
export class Default extends XmlComponent {
constructor(contentType: string, extension?: string) {
super("Default");
this.root.push(
new DefaultAttributes({
contentType: contentType,
extension: extension,
}),
);
}
}

View File

@ -0,0 +1,13 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IOverrideAttributes {
contentType: string;
partName?: string;
}
export class OverrideAttributes extends XmlAttributeComponent<IOverrideAttributes> {
protected xmlKeys = {
contentType: "ContentType",
partName: "PartName",
};
}

View File

@ -0,0 +1,15 @@
import { XmlComponent } from "file/xml-components";
import { OverrideAttributes } from "./override-attributes";
export class Override extends XmlComponent {
constructor(contentType: string, partName?: string) {
super("Override");
this.root.push(
new OverrideAttributes({
contentType: contentType,
partName: partName,
}),
);
}
}

View File

@ -0,0 +1,89 @@
import { XmlComponent } from "file/xml-components";
import { DocumentAttributes } from "../document/document-attributes";
export class Title extends XmlComponent {
constructor(value: string) {
super("dc:title");
this.root.push(value);
}
}
export class Subject extends XmlComponent {
constructor(value: string) {
super("dc:subject");
this.root.push(value);
}
}
export class Creator extends XmlComponent {
constructor(value: string) {
super("dc:creator");
this.root.push(value);
}
}
export class Keywords extends XmlComponent {
constructor(value: string) {
super("cp:keywords");
this.root.push(value);
}
}
export class Description extends XmlComponent {
constructor(value: string) {
super("dc:description");
this.root.push(value);
}
}
export class LastModifiedBy extends XmlComponent {
constructor(value: string) {
super("cp:lastModifiedBy");
this.root.push(value);
}
}
export class Revision extends XmlComponent {
constructor(value: string) {
super("cp:revision");
this.root.push(value);
}
}
export abstract class DateComponent extends XmlComponent {
protected getCurrentDate(): string {
const date = new Date();
const year = date.getFullYear();
const month = ("0" + (date.getMonth() + 1)).slice(-2);
const day = ("0" + date.getDate()).slice(-2);
const hours = ("0" + date.getHours()).slice(-2);
const minutes = ("0" + date.getMinutes()).slice(-2);
const seconds = ("0" + date.getSeconds()).slice(-2);
return year + "-" + month + "-" + day + "T" + hours + ":" + minutes + ":" + seconds + "Z";
}
}
export class Created extends DateComponent {
constructor() {
super("dcterms:created");
this.root.push(
new DocumentAttributes({
type: "dcterms:W3CDTF",
}),
);
this.root.push(this.getCurrentDate());
}
}
export class Modified extends DateComponent {
constructor() {
super("dcterms:modified");
this.root.push(
new DocumentAttributes({
type: "dcterms:W3CDTF",
}),
);
this.root.push(this.getCurrentDate());
}
}

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,51 @@
import { XmlComponent } from "file/xml-components";
import { DocumentAttributes } from "../document/document-attributes";
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
export interface IPropertiesOptions {
title?: string;
subject?: string;
creator?: string;
keywords?: string;
description?: string;
lastModifiedBy?: string;
revision?: string;
}
export class CoreProperties extends XmlComponent {
constructor(options: IPropertiesOptions) {
super("cp:coreProperties");
this.root.push(
new DocumentAttributes({
cp: "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
dc: "http://purl.org/dc/elements/1.1/",
dcterms: "http://purl.org/dc/terms/",
dcmitype: "http://purl.org/dc/dcmitype/",
xsi: "http://www.w3.org/2001/XMLSchema-instance",
}),
);
if (options.title) {
this.root.push(new Title(options.title));
}
if (options.subject) {
this.root.push(new Subject(options.subject));
}
if (options.creator) {
this.root.push(new Creator(options.creator));
}
if (options.keywords) {
this.root.push(new Keywords(options.keywords));
}
if (options.description) {
this.root.push(new Description(options.description));
}
if (options.lastModifiedBy) {
this.root.push(new LastModifiedBy(options.lastModifiedBy));
}
if (options.revision) {
this.root.push(new Revision(options.revision));
}
this.root.push(new Created());
this.root.push(new Modified());
}
}

View File

@ -0,0 +1,39 @@
// import { assert } from "chai";
// import { Utility } from "../../../tests/utility";
// import { Body } from "./";
describe("Body", () => {
// let body: Body;
beforeEach(() => {
// body = new Body();
});
// describe("#constructor()", () => {
// it("should create the Section Properties", () => {
// const newJson = Utility.jsonify(body);
// assert.equal(newJson.root[0].rootKey, "w:sectPr");
// });
// it("should create the Page Size", () => {
// const newJson = Utility.jsonify(body);
// assert.equal(newJson.root[1].rootKey, "w:pgSz");
// });
// it("should create the Page Margin", () => {
// const newJson = Utility.jsonify(body);
// assert.equal(newJson.root[2].rootKey, "w:pgMar");
// });
// it("should create the Columns", () => {
// const newJson = Utility.jsonify(body);
// assert.equal(newJson.root[3].rootKey, "w:cols");
// });
// it("should create the Document Grid", () => {
// const newJson = Utility.jsonify(body);
// assert.equal(newJson.root[4].rootKey, "w:docGrid");
// });
// });
});

View File

@ -0,0 +1,14 @@
import { XmlComponent } from "file/xml-components";
import { SectionProperties, SectionPropertiesOptions } from "./section-properties/section-properties";
export class Body extends XmlComponent {
constructor(sectionPropertiesOptions?: SectionPropertiesOptions) {
super("w:body");
this.root.push(new SectionProperties(sectionPropertiesOptions));
}
public push(component: XmlComponent): void {
this.root.push(component);
}
}

View File

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

View File

@ -0,0 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IColumnsAttributes {
space?: number;
}
export class ColumnsAttributes extends XmlAttributeComponent<IColumnsAttributes> {
protected xmlKeys = {
space: "w:space",
};
}

View File

@ -0,0 +1,13 @@
import { XmlComponent } from "file/xml-components";
import { ColumnsAttributes } from "./columns-attributes";
export class Columns extends XmlComponent {
constructor(space: number) {
super("w:cols");
this.root.push(
new ColumnsAttributes({
space: space,
}),
);
}
}

View File

@ -0,0 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IDocGridAttributesProperties {
linePitch?: number;
}
export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
protected xmlKeys = {
linePitch: "w:linePitch",
};
}

View File

@ -0,0 +1,13 @@
import { XmlComponent } from "file/xml-components";
import { DocGridAttributes } from "./doc-grid-attributes";
export class DocumentGrid extends XmlComponent {
constructor(linePitch: number) {
super("w:docGrid");
this.root.push(
new DocGridAttributes({
linePitch: linePitch,
}),
);
}
}

View File

@ -0,0 +1,13 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IFooterReferenceAttributes {
type: string;
id: string;
}
export class FooterReferenceAttributes extends XmlAttributeComponent<IFooterReferenceAttributes> {
protected xmlKeys = {
type: "w:type",
id: "r:id",
};
}

View File

@ -0,0 +1,14 @@
import { XmlComponent } from "file/xml-components";
import { FooterReferenceAttributes } from "./footer-reference-attributes";
export class FooterReference extends XmlComponent {
constructor() {
super("w:footerReference");
this.root.push(
new FooterReferenceAttributes({
type: "default",
id: `rId${4}`,
}),
);
}
}

View File

@ -0,0 +1,13 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IHeaderReferenceAttributes {
type: string;
id: string;
}
export class HeaderReferenceAttributes extends XmlAttributeComponent<IHeaderReferenceAttributes> {
protected xmlKeys = {
type: "w:type",
id: "r:id",
};
}

View File

@ -0,0 +1,14 @@
import { XmlComponent } from "file/xml-components";
import { HeaderReferenceAttributes } from "./header-reference-attributes";
export class HeaderReference extends XmlComponent {
constructor() {
super("w:headerReference");
this.root.push(
new HeaderReferenceAttributes({
type: "default",
id: `rId${3}`,
}),
);
}
}

View File

@ -0,0 +1,23 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IPageMarginAttributes {
top?: number;
right?: number;
bottom?: number;
left?: number;
header?: number;
footer?: number;
gutter?: number;
}
export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttributes> {
protected xmlKeys = {
top: "w:top",
right: "w:right",
bottom: "w:bottom",
left: "w:left",
header: "w:header",
footer: "w:footer",
gutter: "w:gutter",
};
}

View File

@ -0,0 +1,19 @@
import { XmlComponent } from "file/xml-components";
import { PageMarginAttributes } from "./page-margin-attributes";
export class PageMargin extends XmlComponent {
constructor(top: number, right: number, bottom: number, left: number, header: number, footer: number, gutter: number) {
super("w:pgMar");
this.root.push(
new PageMarginAttributes({
top: top,
right: right,
bottom: bottom,
left: left,
header: header,
footer: footer,
gutter: gutter,
}),
);
}
}

View File

@ -0,0 +1,15 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IPageSizeAttributes {
width?: number;
height?: number;
orientation?: string;
}
export class PageSizeAttributes extends XmlAttributeComponent<IPageSizeAttributes> {
protected xmlKeys = {
width: "w:w",
height: "w:h",
orientation: "w:orient",
};
}

View File

@ -0,0 +1,26 @@
import { expect } from "chai";
import { Formatter } from "../../../../../export/formatter";
import { PageSize } from "./page-size";
describe("PageSize", () => {
describe("#constructor()", () => {
it("should create page size with portrait", () => {
const properties = new PageSize(100, 200, "portrait");
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]);
expect(tree["w:pgSz"]).to.be.an.instanceof(Array);
expect(tree["w:pgSz"][0]).to.deep.equal({ _attr: { "w:h": 200, "w:w": 100, "w:orient": "portrait" } });
});
it("should create page size with horizontal and invert the lengths", () => {
const properties = new PageSize(100, 200, "landscape");
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]);
expect(tree["w:pgSz"]).to.be.an.instanceof(Array);
expect(tree["w:pgSz"][0]).to.deep.equal({ _attr: { "w:h": 100, "w:w": 200, "w:orient": "landscape" } });
});
});
});

View File

@ -0,0 +1,18 @@
import { XmlComponent } from "file/xml-components";
import { PageSizeAttributes } from "./page-size-attributes";
export class PageSize extends XmlComponent {
constructor(width: number, height: number, orientation: string) {
super("w:pgSz");
const flip = orientation === "landscape";
this.root.push(
new PageSizeAttributes({
width: flip ? height : width,
height: flip ? width : height,
orientation: orientation,
}),
);
}
}

View File

@ -0,0 +1,142 @@
import { expect } from "chai";
import { Formatter } from "../../../../export/formatter";
import { SectionProperties } from "./section-properties";
describe("SectionProperties", () => {
describe("#constructor()", () => {
it("should create section properties with options", () => {
const properties = new SectionProperties({
width: 11906,
height: 16838,
top: 1440,
right: 1440,
bottom: 1440,
left: 1440,
header: 708,
footer: 708,
gutter: 0,
space: 708,
linePitch: 360,
});
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } }] });
expect(tree["w:sectPr"][1]).to.deep.equal({
"w:pgMar": [
{
_attr: {
"w:bottom": 1440,
"w:footer": 708,
"w:top": 1440,
"w:right": 1440,
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
},
},
],
});
});
it("should create section properties with no options", () => {
const properties = new SectionProperties();
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } }] });
expect(tree["w:sectPr"][1]).to.deep.equal({
"w:pgMar": [
{
_attr: {
"w:bottom": 1440,
"w:footer": 708,
"w:top": 1440,
"w:right": 1440,
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
},
},
],
});
});
it("should create section properties with changed options", () => {
const properties = new SectionProperties({
top: 0,
});
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } }] });
expect(tree["w:sectPr"][1]).to.deep.equal({
"w:pgMar": [
{
_attr: {
"w:bottom": 1440,
"w:footer": 708,
"w:top": 0,
"w:right": 1440,
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
},
},
],
});
});
it("should create section properties with changed options", () => {
const properties = new SectionProperties({
bottom: 0,
});
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } }] });
expect(tree["w:sectPr"][1]).to.deep.equal({
"w:pgMar": [
{
_attr: {
"w:bottom": 0,
"w:footer": 708,
"w:top": 1440,
"w:right": 1440,
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
},
},
],
});
});
it("should create section properties with changed options", () => {
const properties = new SectionProperties({
width: 0,
height: 0,
});
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
expect(tree["w:sectPr"][0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 0, "w:w": 0, "w:orient": "portrait" } }] });
expect(tree["w:sectPr"][1]).to.deep.equal({
"w:pgMar": [
{
_attr: {
"w:bottom": 1440,
"w:footer": 708,
"w:top": 1440,
"w:right": 1440,
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
},
},
],
});
});
});
});

View File

@ -0,0 +1,57 @@
// http://officeopenxml.com/WPsection.php
import { XmlComponent } from "file/xml-components";
import { Columns } from "./columns/columns";
import { IColumnsAttributes } from "./columns/columns-attributes";
import { DocumentGrid } from "./doc-grid/doc-grid";
import { IDocGridAttributesProperties } from "./doc-grid/doc-grid-attributes";
import { FooterReference } from "./footer-reference/footer-reference";
import { HeaderReference } from "./header-reference/header-reference";
import { PageMargin } from "./page-margin/page-margin";
import { IPageMarginAttributes } from "./page-margin/page-margin-attributes";
import { PageSize } from "./page-size/page-size";
import { IPageSizeAttributes } from "./page-size/page-size-attributes";
export type SectionPropertiesOptions = IPageSizeAttributes & IPageMarginAttributes & IColumnsAttributes & IDocGridAttributesProperties;
export class SectionProperties extends XmlComponent {
constructor(options?: SectionPropertiesOptions) {
super("w:sectPr");
const defaultOptions = {
width: 11906,
height: 16838,
top: 1440,
right: 1440,
bottom: 1440,
left: 1440,
header: 708,
footer: 708,
gutter: 0,
space: 708,
linePitch: 360,
orientation: "portrait",
};
const mergedOptions = {
...defaultOptions,
...options,
};
this.root.push(new PageSize(mergedOptions.width, mergedOptions.height, mergedOptions.orientation));
this.root.push(
new PageMargin(
mergedOptions.top,
mergedOptions.right,
mergedOptions.bottom,
mergedOptions.left,
mergedOptions.header,
mergedOptions.footer,
mergedOptions.gutter,
),
);
this.root.push(new Columns(mergedOptions.space));
this.root.push(new DocumentGrid(mergedOptions.linePitch));
this.root.push(new HeaderReference());
this.root.push(new FooterReference());
}
}

View File

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

View File

@ -0,0 +1,12 @@
import { XmlComponent } from "file/xml-components";
import { ChildNonVisualProperties } from "./child-non-visual-pic-properties/child-non-visual-pic-properties";
import { NonVisualProperties } from "./non-visual-properties/non-visual-properties";
export class NonVisualPicProperties extends XmlComponent {
constructor() {
super("pic:nvPicPr");
this.root.push(new NonVisualProperties());
this.root.push(new ChildNonVisualProperties());
}
}

View File

@ -0,0 +1,15 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface INonVisualPropertiesAttributes {
id?: number;
name?: string;
descr?: string;
}
export class NonVisualPropertiesAttributes extends XmlAttributeComponent<INonVisualPropertiesAttributes> {
protected xmlKeys = {
id: "id",
name: "name",
descr: "desc",
};
}

View File

@ -0,0 +1,16 @@
import { XmlComponent } from "file/xml-components";
import { NonVisualPropertiesAttributes } from "./non-visual-properties-attributes";
export class NonVisualProperties extends XmlComponent {
constructor() {
super("pic:cNvPr");
this.root.push(
new NonVisualPropertiesAttributes({
id: 0,
name: "",
descr: "",
}),
);
}
}

View File

@ -0,0 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IPicAttributes {
xmlns?: string;
}
export class PicAttributes extends XmlAttributeComponent<IPicAttributes> {
protected xmlKeys = {
xmlns: "xmlns:pic",
};
}

View File

@ -0,0 +1,30 @@
// http://officeopenxml.com/drwPic.php
import { XmlComponent } from "file/xml-components";
import { BlipFill } from "./blip/blip-fill";
import { NonVisualPicProperties } from "./non-visual-pic-properties/non-visual-pic-properties";
import { PicAttributes } from "./pic-attributes";
import { ShapeProperties } from "./shape-properties/shape-properties";
export class Pic extends XmlComponent {
private shapeProperties: ShapeProperties;
constructor(referenceId: number, x: number, y: number) {
super("pic:pic");
this.root.push(
new PicAttributes({
xmlns: "http://schemas.openxmlformats.org/drawingml/2006/picture",
}),
);
this.shapeProperties = new ShapeProperties(x, y);
this.root.push(new NonVisualPicProperties());
this.root.push(new BlipFill(referenceId));
this.root.push(new ShapeProperties(x, y));
}
public setXY(x: number, y: number): void {
this.shapeProperties.setXY(x, y);
}
}

View File

@ -0,0 +1,13 @@
import { XmlAttributeComponent } from "file/xml-components";
export interface IExtentsAttributes {
cx?: number;
cy?: number;
}
export class ExtentsAttributes extends XmlAttributeComponent<IExtentsAttributes> {
protected xmlKeys = {
cx: "cx",
cy: "cy",
};
}

View File

@ -0,0 +1,25 @@
// http://officeopenxml.com/drwSp-size.php
import { XmlComponent } from "file/xml-components";
import { ExtentsAttributes } from "./extents-attributes";
export class Extents extends XmlComponent {
private attributes: ExtentsAttributes;
constructor(x: number, y: number) {
super("a:ext");
this.attributes = new ExtentsAttributes({
cx: x,
cy: y,
});
this.root.push(this.attributes);
}
public setXY(x: number, y: number): void {
this.attributes.set({
cx: x,
cy: y,
});
}
}

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