Compare commits

...

290 Commits
3.6.0 ... 4.3.0

Author SHA1 Message Date
a466578467 Version bump 2018-10-15 23:34:35 +01:00
3a9420fedf Merge pull request #149 from dolanmiu/feat/grid-span
Feat/grid span
2018-10-15 23:23:20 +01:00
8ac19a83b2 Rename demos 2018-10-15 22:21:40 +01:00
9f0b2f7074 Improve API 2018-10-15 21:54:33 +01:00
e02ac43c07 Version bump 2018-10-10 20:39:11 +01:00
ccffdad4c0 Merge pull request #171 from amitm02/master
Contextual spacing
2018-09-26 15:57:16 +01:00
2fb5845501 contextual spacing 2018-09-26 17:47:17 +03:00
ddd84a1765 Merge pull request #3 from dolanmiu/master
from base
2018-09-26 17:27:41 +03:00
f6a13aed86 Merge pull request #169 from dolanmiu/feat/table-of-contents
Feat/table of contents
2018-09-26 02:28:44 +01:00
2da3ba0262 Rename variables 2018-09-26 02:17:39 +01:00
e08c7cbbfb Add table of contents to side bar 2018-09-26 02:12:10 +01:00
a6de5d8a21 Merge pull request #168 from dolanmiu/feat/table-of-contents
Change documentation properties to options
2018-09-26 02:10:03 +01:00
00a20b7cfc Merge pull request #166 from dolanmiu/feat/table-of-contents
Feat/table of contents
2018-09-25 23:32:58 +01:00
f27c95191b Change documentation properties to options 2018-09-25 21:19:04 +01:00
c140d2c37c ITableOfContentsProperties to ITableOfContentsOptions 2018-09-25 21:09:30 +01:00
3a42f2a2f0 Make API simplier with interfaces 2018-09-25 20:05:35 +01:00
00efedaa09 Fix spelling and linting and improve readme 2018-09-25 19:49:44 +01:00
72e3d229dc unnecessary comment removed 2018-09-25 02:36:00 -03:00
b12d6ef484 initial documentation 2018-09-25 02:35:08 -03:00
8ee6fd3e67 demo updated 2018-09-25 01:33:44 -03:00
808c5b00a0 table of contents with all the options 2018-09-25 01:18:47 -03:00
4de6b51e76 removed getStyles and clearPageBreak that became useless 2018-09-25 00:10:27 -03:00
4ca81df401 TOC content generation aborted 2018-09-21 11:16:14 -03:00
8b463b3bb6 updated clone deep dependency and make fields dirty to be updated when word is opened 2018-09-21 10:26:28 -03:00
17d696e33a merge with master, demo27 became demo28 2018-09-21 07:40:58 -03:00
2f59867db6 Merge branch 'feat/table-of-contents' of https://github.com/dolanmiu/docx into feat/table-of-contents 2018-09-21 07:37:26 -03:00
90f3da74cf Version bump 2018-09-20 21:04:21 +01:00
28d8659cb5 Merge pull request #161 from bre7/patch-1
Improve fluency (dsl like)
2018-09-20 21:03:38 +01:00
5d1740a2ef Style fixes 2018-09-20 16:54:58 -03:00
7aa44568d8 Improve fluency (dsl like)
addRunProperty / addParagraphProperty should also return this
2018-09-20 15:51:57 -03:00
bf1f702e5a created a clone method for xml-components 2018-09-20 15:13:18 -03:00
78ad3e340a Merge pull request #160 from bre7/patch-1
Added charSpacing to docs
2018-09-20 18:46:30 +01:00
63a965beab Added charSpacing 2018-09-20 14:00:49 -03:00
815354e06f Merge pull request #159 from bre7/master
Added character spacing attribute
2018-09-20 16:27:21 +01:00
1cff104bae correct sdt objects of table of contents 2018-09-20 10:47:10 -03:00
4805efad2e organized imports 2018-09-20 10:31:49 -03:00
12e2ae9e91 making leader a option field and test improvments 2018-09-20 10:30:16 -03:00
c07b5cf709 added settings.xml back 2018-09-20 10:11:59 -03:00
0684738ec2 removed lodash 2018-09-20 07:09:17 -03:00
6da3efdacc Added character spacing attribute 2018-09-19 18:41:55 -03:00
7cd8864fb9 added stdPr and stdContent to table of contents 2018-09-19 11:01:07 -03:00
a9c69664c7 Merge pull request #156 from bre7/master
Added mirror margins option
2018-09-19 12:40:31 +01:00
50569224c3 Fixed tests (included mirrorMargins attr) 2018-09-18 23:50:10 -03:00
877aa325bb Merge pull request #153 from felipeochoa/fix-109
Fix 109
2018-09-19 01:25:32 +01:00
eb797d8986 Ignore Yarn lock & IntelliJ ide 2018-09-18 21:03:50 -03:00
fcb542471b Added mirror margins options 2018-09-18 21:03:20 -03:00
baf0f17bd6 added a method for clear the page breaks of a paragraph 2018-09-18 13:53:30 -03:00
8e911698a5 generating the content for a table of contents 2018-09-18 05:24:19 -03:00
0eb36be053 there is no need for the settings.xml file anymore 2018-09-17 22:09:05 -03:00
53b24965aa Merge pull request #152 from felipeochoa/fix-typo-table-properties
Fix typo in private property
2018-09-17 19:04:58 +01:00
edce1bef92 Allow creating Styles and assigning them to File.Styles
Closes #109
2018-09-17 12:48:21 -05:00
e0d54d3af3 Fix typo in private property 2018-09-17 12:41:17 -05:00
a9167b4809 Update demos 2018-09-13 01:54:37 +01:00
5b28eb0d00 Update logo to be blinking 2018-09-12 21:19:33 +01:00
f1b176670c Add more table demos 2018-09-12 21:03:06 +01:00
11ce9a5206 Add horizontal span 2018-09-12 21:01:52 +01:00
8b667b8d4c Merge pull request #148 from dolanmiu/feat/logo
Updated logo dimensions
2018-09-11 19:18:31 +01:00
a601a82a37 Updated logo dimensions 2018-09-11 19:16:47 +01:00
dcf3767a05 Merge pull request #147 from dolanmiu/feat/logo
Add logo
2018-09-11 19:08:27 +01:00
a9278009f8 Merge branch 'feat/logo' of https://github.com/dolanmiu/docx into feat/logo 2018-09-11 19:04:19 +01:00
5220f9e07c Add correct image 2018-09-11 19:03:53 +01:00
0b88064ca2 Update README.md 2018-09-11 19:03:29 +01:00
2233ccb968 Add logo 2018-09-11 19:00:52 +01:00
311fde01a1 Update Readme 2018-09-10 22:44:44 +01:00
146d0ad9e5 Moved addTableOfContents to File and creating a settings.xml and applying updateFields=true when there is a table of contents 2018-09-10 10:01:26 -03:00
aedfca377f elements need to be inside runs 2018-09-04 18:22:08 -03:00
7926f6c189 escape bars 2018-09-04 17:29:24 -03:00
0303a9f553 Merge pull request #141 from XappMedia/min-eight
Minimum Node v8 Support
2018-09-04 18:26:34 +01:00
e9a007d446 create default properties for table-of-contents instruction 2018-09-04 12:05:41 -03:00
12c1f82efe demo27 for TableOfContents 2018-09-04 11:03:17 -03:00
b1711ae293 first simple version of TOC working 2018-09-03 11:20:36 -03:00
a367951d07 moved Begin, Separate and End from page-number.ts to field.ts 2018-09-03 10:54:53 -03:00
c55f82c425 test improvment 2018-09-03 10:48:50 -03:00
2dab11e8b3 minimum 8 2018-08-31 11:25:05 -04:00
d1044d262e table of contents extending paragraph 2018-08-31 10:22:40 -03:00
8d83219bb6 wrote some initial code 2018-08-29 12:06:01 -03:00
a710483918 Merge pull request #2 from dolanmiu/master
merge from upstream
2018-08-27 18:11:47 +03:00
4f8ecf631b Merge branch 'master' into feat/table-of-contents 2018-08-23 06:21:01 -03:00
cc453dc24e Merge pull request #134 from dolanmiu/feat/readme-update
Version bump
2018-08-23 01:27:59 +01:00
60abe4857b Version bump 2018-08-23 01:26:30 +01:00
dc942bc2e4 Merge pull request #133 from dolanmiu/feat/readme-update
Add table cell margin
2018-08-23 01:24:16 +01:00
90497036a6 Fix browser demo 2018-08-23 01:12:54 +01:00
fe2032a3d4 change demos to typescript and WidthType disparity 2018-08-23 01:05:26 +01:00
877dcb462f Add table cell margin 2018-08-23 00:55:33 +01:00
4a3b7d71fe Merge pull request #130 from dolanmiu/feat/readme-update
Fix demo examples
2018-08-22 14:48:30 +01:00
0e1bfb6524 Merge pull request #132 from dolanmiu/pull-126
Old PR #126 Fixed
2018-08-22 14:48:04 +01:00
e68bc50e6e style fixed 2018-08-22 10:39:13 -03:00
a6a8012b39 wrote some inital code 2018-08-22 10:30:19 -03:00
e9e42011cd Merge branch 'master' into master 2018-08-22 08:04:45 -03:00
85f686dede Fix demo examples 2018-08-22 01:14:17 +01:00
0f6f79ebc6 Merge pull request #128 from nschechter/feat/paragraph-borders
Feat/paragraph borders
2018-08-22 01:08:53 +01:00
9a6c92222c Change demo26 to typescript 2018-08-22 00:51:18 +01:00
33f87523e0 Merge from master 2018-08-21 23:50:58 +01:00
a53818754a Merge pull request #129 from dolanmiu/feat/readme-update
Add new slogan
2018-08-21 23:09:51 +01:00
6c2f335a31 Add new slogan 2018-08-21 22:29:40 +01:00
ff80f76855 Merge pull request #124 from dolanmiu/feat/browser-packer
Feat/browser packer
2018-08-21 22:04:01 +01:00
6f0f3ccca7 Update documentation 2018-08-21 21:46:12 +01:00
eb9cc767c6 Merge from master 2018-08-21 20:59:20 +01:00
410080a8a3 Fix tests 2018-08-21 19:27:07 +01:00
d5b6225a90 starting table of contents 2018-08-21 07:19:46 -03:00
a777842f9d updated mocha to version 5 due to vulnerabilities found by npm audit 2018-08-21 07:16:27 -03:00
62306133c8 Update .travis.yml 2018-08-21 10:27:46 +01:00
a7f6224fb2 Made demo files into typescript files 2018-08-21 02:46:21 +01:00
e97c432a64 added border specs, createBorder method, and color attribute to setProperties 2018-08-19 19:37:36 -04:00
0411153832 Added in the ability to create borders for paragraphs 2018-08-19 11:59:38 -04:00
f9a0d1b388 Fix tests 2018-08-15 23:06:48 +01:00
bf5bcea607 Make add image support base64 strings 2018-08-15 22:20:43 +01:00
f969c866a7 Update target for library 2018-08-15 01:38:00 +01:00
07261232ff Removed old compiler and unused dependencies 2018-08-15 01:22:22 +01:00
2018f41368 Discard pdf 2018-08-14 22:05:04 +01:00
bfa0edeb09 Remove pdf packer 2018-08-14 21:56:38 +01:00
3d91c84966 alphabetized import sources 2018-08-14 11:28:01 -03:00
f91fd5921f merge with upstream master 2018-08-14 11:27:08 -03:00
36157bb8db Added optional drawingOptions parameter to addImage and addImageFromBuffer methods. This way it can be passaed to Image constructor. 2018-08-14 11:06:17 -03:00
a38abeb4c2 Huge refactoring to use new compiler and deprecate all other Packers
Add new PdfPacker
2018-08-14 01:46:48 +01:00
675192b86f Refactor image to accept Buffer only 2018-08-12 23:07:31 +01:00
bc1132146f Revert test changes 2018-08-10 02:46:15 +01:00
d850f37904 Remove unused import 2018-08-10 01:49:37 +01:00
f15fdb921e Merge branch 'master' into feat/browser-packer
# Conflicts:
#	demo/demo13.js
#	package.json
#	src/export/packer/compiler.ts
#	src/file/media/data.ts
#	src/file/media/media.ts
2018-08-10 01:40:29 +01:00
7b43551148 Merge pull request #123 from dolanmiu/feat/h4-update
Feat/h4 update
2018-08-10 00:30:53 +01:00
ad356d2759 Add ignores so it doesnt get generated in documentation 2018-08-09 23:40:11 +01:00
5f594a822f Fix and enable linting on tests 2018-08-09 23:29:40 +01:00
89df3c48e0 Fix linting errors 2018-08-09 23:22:03 +01:00
3436a1584c Merge branch 'master' of https://github.com/h4buli/docx into feat/h4-update
# Conflicts:
#	package.json
#	src/file/document/body/body.ts
#	src/file/document/body/section-properties/section-properties.ts
#	src/file/file.ts
#	src/file/media/media.ts
#	src/file/styles/external-styles-factory.ts
#	src/file/table/table-cell.ts
2018-08-09 23:21:24 +01:00
d44b0d50d8 Merge pull request #118 from dolanmiu/feat/add-image-to-run
Add image to run
2018-08-09 23:06:05 +01:00
1bd94aca7c Merge pull request #117 from dolanmiu/feat/refactor-bidi
Feat/refactor bidi
2018-08-09 23:05:58 +01:00
f264e4d0f7 Add scale method to image 2018-08-09 21:58:50 +01:00
d8252141fe Update tsconfig.json 2018-08-09 11:54:05 +01:00
d9716a1cf7 Update README.md 2018-08-09 11:52:47 +01:00
e9bd27bc55 Update README.md 2018-08-09 11:52:17 +01:00
0a69851463 Update README.md 2018-08-09 11:51:27 +01:00
5e7c5aa620 Fix typo 2018-08-09 03:23:07 +01:00
f6996a1d98 Update README 2018-08-09 03:20:46 +01:00
e9ea4845be Improve README 2018-08-09 03:13:16 +01:00
d961721b33 Refactor name 2018-08-09 02:56:23 +01:00
bb8c29f4a2 Fix tests 2018-08-09 02:53:28 +01:00
e10c20fa42 Add image to run 2018-08-09 01:55:50 +01:00
94274733f4 Improve API documentation 2018-08-08 22:51:54 +01:00
42f723813a Merge branch 'master' into feat/refactor-bidi
# Conflicts:
#	demo/demo22.js
#	src/file/paragraph/run/run.ts
2018-08-08 20:20:22 +01:00
4c75b91ce9 Update README.md 2018-08-08 01:53:44 +01:00
3dd6faa620 Update README.md 2018-08-08 01:29:52 +01:00
9a1313fe89 Merge pull request #114 from amitm02/complex-font-bold
add bold and italic formatting support for complex font (e.g Hebrew)
2018-08-07 14:30:52 +01:00
fe43525dad update hebrew demo 2018-08-07 16:19:13 +03:00
92da93a160 Rename to more readable names 2018-08-07 02:47:24 +01:00
cf0c2c7691 Add Express packer deprecation warning 2018-08-07 02:23:58 +01:00
e9aecfac1c Updated lint rules 2018-08-07 01:38:15 +01:00
12c8cb93f6 Clean up API 2018-08-07 01:25:28 +01:00
f9c97a673e add complex font support to bold and italic 2018-08-06 12:14:51 +03:00
ca8f331eec Add new demo and remove tslint disable 2018-08-06 03:53:27 +01:00
9e11774a1b Add no null rule 2018-08-06 03:49:27 +01:00
257c8bde99 Add pre-commit hook 2018-08-06 03:26:30 +01:00
0bdbb1b24a Add more documentation 2018-08-06 02:57:25 +01:00
bd1aa7b49e Update URL 2018-08-05 04:25:12 +01:00
5de3dc802f Add more examples 2018-08-05 04:24:04 +01:00
f25ecd0743 Update docs 2018-08-05 04:18:12 +01:00
cdf3a6fb40 Add more examples 2018-08-05 04:14:25 +01:00
f9c5db8df7 Add sample demo 2018-08-05 03:28:51 +01:00
7d05d69707 Update documentation and README 2018-08-04 04:03:08 +01:00
08a3538d8e Update documentation 2018-08-04 03:40:41 +01:00
6b38a3637f Merge pull request #113 from dolanmiu/feat/documentation-revamp
Feat/documentation revamp
2018-08-04 03:32:48 +01:00
7d116d1ce9 Add more documentation 2018-08-04 03:28:27 +01:00
73267ac4e5 Add docsify documentation 2018-08-03 23:26:14 +01:00
efe7d594b0 Add accessor to getter and setters 2018-08-03 02:29:58 +01:00
b7a4ca9c3b Merge pull request #89 from dolanmiu/feat/base64-image
Image methods
2018-08-03 02:22:46 +01:00
810fd7e7b8 Fix style and tslint 2018-08-03 01:53:19 +01:00
22bd13a253 Add image tests 2018-08-03 01:28:20 +01:00
5f22950721 Change image API so that it now sends Images 2018-08-03 00:01:42 +01:00
31fdf08c27 Make function return Image rather than PictureRun 2018-08-02 21:14:53 +01:00
2d12f6e54c Add new Image class 2018-08-02 21:07:37 +01:00
f7c02f4679 Revert returning Paragraph 2018-08-02 02:32:57 +01:00
3fcfc29e3f Style formatting 2018-08-02 02:21:15 +01:00
817356f2a8 Merge pull request #107 from ydfzgyj/gridspan
add addGridspan to TableRow
2018-08-02 02:20:30 +01:00
8fbaec3567 Merge pull request #106 from ydfzgyj/shading
Add table cell shading
2018-08-02 02:20:16 +01:00
3f1eda60eb Rename data to buffer 2018-08-02 02:14:57 +01:00
0d5e9ce9d8 Offload media methods into Media static object
Simplified File handling of images
2018-08-02 02:09:00 +01:00
019ae24c7d Change method to createImageData 2018-08-01 23:32:31 +01:00
4dd84ded54 Merge branch 'master' into feat/base64-image 2018-08-01 23:22:38 +01:00
5232c055b1 Merge pull request #111 from felipeochoa/bugfix-110
Fix #110
2018-07-31 19:12:41 +01:00
06d3f3c34b Fix #110 2018-07-31 12:13:05 -05:00
2aca988c0b fix style 2018-07-27 17:26:23 +08:00
fc27e44471 Add addGridSpan to TableRow 2018-07-27 17:25:04 +08:00
60f312446e fix style 2018-07-27 16:59:29 +08:00
807605c0cc Add table cell Shading 2018-07-27 16:55:03 +08:00
1aa592b1b9 Merge pull request #105 from ydfzgyj/buffer
fix inheritance of BufferPacker class
2018-07-26 13:03:06 +01:00
763fa62eca Merge pull request #103 from amitm02/master
resubmitting bidi and RTL support with lint fixs
2018-07-26 13:02:42 +01:00
40ac08836d bidi+rtl demo 2018-07-26 14:49:21 +03:00
6bdcee1d1b fix inheritance of BufferPacker class 2018-07-26 17:16:18 +08:00
0ea79775c5 Merge branch 'master' of https://github.com/amitm02/docx 2018-07-25 15:04:01 +03:00
696b5daf5c rtl 2018-07-25 15:02:58 +03:00
e136f4e987 more alignments 2018-07-25 13:07:58 +03:00
41308fea13 prettier 2018-07-25 12:51:02 +03:00
0e14b2d2e3 fix lint issues 2018-07-25 09:47:09 +03:00
c9b66bf77b Merge branch 'master' of https://github.com/amitm02/docx 2018-07-25 09:28:05 +03:00
4168d1a296 revert 2018-07-25 09:28:01 +03:00
51d172b8fc Merge branch 'master' into master 2018-07-25 09:27:11 +03:00
e02e54db2c Merge pull request #100 from XappMedia/bookmarks-and-internal-hyperlinks
feat: Bookmarks and Internal hyperlinks
2018-07-24 22:40:47 +01:00
305dd84769 adding a demo 2018-07-24 17:15:23 -04:00
985ea30d36 tests 2018-07-24 16:56:27 -04:00
cc904ee211 style fix 2018-07-24 16:00:55 -04:00
8ceb38963e initial functionality 2018-07-24 15:56:13 -04:00
59ca9df663 remove post install 2018-07-24 18:58:01 +03:00
0689489985 Merge branch 'master' into build 2018-07-24 18:53:18 +03:00
3015b05c77 add rtl mode 2018-07-24 18:52:45 +03:00
f299e49966 Merge pull request #1 from dolanmiu/master
original updates
2018-07-24 18:33:33 +03:00
0186450221 Merge pull request #98 from ydfzgyj/font
Let fonts suit for more characters
2018-07-24 10:49:47 +01:00
974eb510ef Fix style 2018-07-24 12:37:15 +08:00
1fad9a666e Let fonts suit for more characters 2018-07-24 12:24:26 +08:00
b6cf1ab951 Add demo20 table border styles 2018-07-23 20:28:29 +01:00
d979ef3b40 commit 2018-07-23 10:31:48 +03:00
4a320d3031 npm postinstall 2018-07-23 10:08:09 +03:00
fbfdc6a383 add test 2018-07-22 17:08:11 +03:00
4dfce582c8 bidi support 2018-07-22 17:03:45 +03:00
ee048968cc Update request promise and pin types/bluebird 2018-07-21 01:42:34 +01:00
fe54e892cc Use node 9 2018-07-21 01:32:25 +01:00
5fab6e2714 Remove test only 2018-07-21 01:28:15 +01:00
8e80df30b9 Merge pull request #95 from dolanmiu/feat/update-dependencies
Feat/update dependencies
2018-07-21 01:24:40 +01:00
b9e7b9e1e3 Update typedoc 2018-07-21 01:21:28 +01:00
bb88053ae3 Update typescript 2018-07-21 01:13:17 +01:00
0611b94c01 Add docx.js.org CNAME 2018-07-15 23:36:13 +01:00
3da0bb38df Version bump 2018-07-06 19:01:23 +02:00
c57c7f2aa7 Merge pull request #13 from h4buli/feature/numbering-level-suffix
Add support to define suffix on a numbering level
2018-07-06 19:00:32 +02:00
a05abd0eea numbering: add support to define suffix for numbering level 2018-07-06 18:54:30 +02:00
c95e765456 Version bump 2018-07-03 14:11:19 +02:00
9d034ab48d Merge pull request #12 from h4buli/feature/section-page-borders
feature: add support for section page borders
2018-07-03 14:09:56 +02:00
796e000826 feature: add support for section page borders 2018-07-03 13:48:31 +02:00
60a92fb22b Merge pull request #90 from dolanmiu/feat/buffer-packer
Feat/buffer packer
2018-07-01 02:29:19 +01:00
ddbae91840 Add buffer packer tests 2018-07-01 02:26:23 +01:00
ded155a6af Add buffer packer 2018-07-01 02:16:11 +01:00
59cc0d3211 Add demo of current way of adding image from base64 string 2018-07-01 01:07:52 +01:00
4b06baab3f Merge pull request #87 from dolanmiu/feat/footnotes
Feat/footnotes
2018-06-30 23:53:42 +01:00
ef16dac4f4 Improve demo 2018-06-30 23:50:11 +01:00
b8934c68f2 Add counter to footnotes 2018-06-30 23:50:02 +01:00
e5fae3af64 Add footnote test 2018-06-30 23:42:48 +01:00
34a92ab448 Use enums instead of strings 2018-06-30 23:41:57 +01:00
6c85ad3188 Fix tests 2018-06-30 23:39:45 +01:00
9f0e55b7b8 Add footnotes spec file 2018-06-29 19:49:19 +01:00
612a2f90ac version bump 2018-06-29 16:31:25 +02:00
c797ed9c25 media: fixed bug when media size can be decimal
- produces invalid docx document
2018-06-29 00:32:01 +02:00
5dc82d8176 Add styles to footnote 2018-06-28 03:01:25 +01:00
802e461792 Footnotes demo 2018-06-27 23:36:04 +01:00
b9e702086a Merge branch 'master' into feat/footnotes
# Conflicts:
#	demo/demo16.js
#	src/file/file.ts
2018-06-27 23:34:23 +01:00
9f591c4d87 Merge pull request #86 from dolanmiu/feat/multiple-headers
Feat/multiple headers
2018-06-27 23:28:07 +01:00
55220c147d version bump 2018-06-27 22:10:11 +02:00
2ea5b1c0bd Merge pull request #11 from h4buli/fix/parsing-external-styles
bug: Not all content from external styles was imported correctly
2018-06-27 22:05:44 +02:00
ed72d60951 external-styles: create correct XmlComponents from imported style 2018-06-27 21:55:15 +02:00
5f6d177df9 Update README.md 2018-06-27 02:27:56 +01:00
b3e15d6729 Updated demo for sections 2018-06-26 23:34:39 +01:00
b26a9f8dcf Fix styles 2018-06-26 00:10:08 +01:00
f3a822b4b2 Add section demo 2018-06-26 00:03:37 +01:00
cee091fa58 Use method approach to different first page header 2018-06-26 00:03:28 +01:00
84ebf8e6c3 Remove old implementation of first page header 2018-06-25 22:13:12 +01:00
2a0b45dc20 make default settings in the addSection 2018-06-25 21:53:01 +01:00
00955d2e4f Fix imports 2018-06-25 19:53:40 +01:00
044442b0d7 Add footnote classes 2018-06-25 19:50:19 +01:00
99290d646e Add footnote support to API 2018-06-25 19:49:46 +01:00
52007785af version bump 2018-06-25 12:54:36 +02:00
9d3b32a841 fix: fixed wrong import causing exported SectionProperties class to be unusable 2018-06-25 12:53:25 +02:00
0b939b1cd6 Organise imports 2018-06-22 23:18:07 +01:00
d63adc7a6b Fix linting 2018-06-22 23:04:03 +01:00
026a221e5e Move header outside 2018-06-22 23:01:34 +01:00
f1ac646518 Merge branch 'feature/multiple-sections' of https://github.com/h4buli/docx into feat/multiple-headers
# Conflicts:
#	src/export/packer/compiler.ts
#	src/file/content-types/content-types.ts
#	src/file/document/body/section-properties/header-reference/header-reference.ts
#	src/file/document/body/section-properties/section-properties.ts
#	src/file/file.ts
#	src/file/media/media.ts
2018-06-22 22:59:38 +01:00
8b3cf8c38c Merge pull request #84 from dolanmiu/feat/h4-update
Feat/h4 update
2018-06-22 01:22:50 +02:00
89e2129ca4 Version bump 2018-06-21 14:50:50 +02:00
d9999f8dd9 Merge pull request #10 from h4buli/feature/multiple-sections
feature: add multiple sections to the document inc. headers and footers
2018-06-21 14:49:24 +02:00
0b963ec3b8 feature: add support to add mutiple sections to the document inc. headers and footers
- write missing tests
2018-06-21 12:03:34 +02:00
369ec9c30b Set correct ID 2018-06-11 00:50:48 +01:00
c19a2e71b5 Add footnotes as part of export 2018-06-11 00:48:50 +01:00
6085f69c22 Sorting 2018-06-11 00:46:51 +01:00
8cb8d3514a Add footnotes class 2018-06-11 00:45:21 +01:00
55005b57c6 Fix linting and style errors 2018-06-09 23:49:01 +01:00
80cdaaeb1c Fix compile error 2018-06-09 23:34:54 +01:00
deccfd7cc9 Add back scale functionality 2018-06-09 23:33:52 +01:00
0f4c2e64f4 Merge branch 'master' of https://github.com/h4buli/docx into feat/h4-update
# Conflicts:
#	package.json
#	src/file/drawing/drawing.ts
#	src/file/media/media.ts
#	src/file/paragraph/run/picture-run.ts
#	src/file/styles/external-styles-factory.ts
#	src/file/xml-components/imported-xml-component.ts
2018-06-09 23:29:59 +01:00
b8b5d18662 version bump 2018-06-08 22:21:10 +02:00
5ee5698347 Merge pull request #9 from h4buli/feature/image-position
Add support for different positioning of the images
2018-06-08 22:19:27 +02:00
97b254ee7b add support for floating drawings
- added need elements and test for them
2018-06-08 16:03:04 +02:00
ac40a40ec0 refactor: move components from /drawing/inline to /drawing
- they will be used for other positioning element (floating)
2018-06-08 07:50:23 +02:00
b5b96506ae Add footnotes scaffolding 2018-06-03 02:11:21 +01:00
548fe3c864 Version bump 2018-05-28 09:18:09 +02:00
97e976a184 import: add support to import any xml tab element to XmlComponent (#8)
- make method to import/convert to XmlComponent
 - expose method to add childElement to Header/Footer
 - add tests
2018-05-28 09:15:44 +02:00
5de6617d10 Merge pull request #75 from h4buli/feature/page-break-before
paragraph: add support for 'page break before' format property
2018-05-28 02:33:59 +01:00
bcd6110578 Add demo for page break before 2018-05-28 02:27:46 +01:00
c9eb27de11 fixed formatting styles 2018-05-17 15:34:47 +02:00
dadd8c122f fixed formatting styles 2018-05-17 15:32:15 +02:00
cdb86b741c Version bump 2018-05-10 20:25:14 +02:00
15e8d7c053 paragraph: add support for page break before format property (#7) 2018-05-10 20:24:06 +02:00
cbe9c3ac50 paragraph: add support for page break before format property 2018-05-10 19:43:58 +02:00
e8bc7952db Move fs to exporter and add browser packer 2018-04-24 22:56:56 +01:00
06418655c0 Add image support to new packer 2018-04-24 22:35:31 +01:00
c99b2940c6 Add next gen compiler using JSZip 2018-04-24 21:12:09 +01:00
252 changed files with 7152 additions and 1390 deletions

11
.gitignore vendored
View File

@ -36,6 +36,10 @@ node_modules
build
build-tests
# Documentation
docs/api/
docs/.nojekyll
# VSCode
.vscode/*
!.vscode/settings.json
@ -44,8 +48,15 @@ build-tests
!.vscode/extensions.json
.history
# IntelliJ
.idea
# Lock files
package-lock.json
yarn.lock
# Documents
My Document.docx
# Temporary folder
tmp

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v8

View File

@ -1,6 +1,6 @@
language: node_js
node_js:
- "stable"
- 9
install:
- npm install
script:
@ -8,23 +8,36 @@ script:
- 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
- npm run ts-node -- ./demo/demo1.ts
- npm run ts-node -- ./demo/demo2.ts
- npm run ts-node -- ./demo/demo3.ts
- npm run ts-node -- ./demo/demo4.ts
- npm run ts-node -- ./demo/demo5.ts
- npm run ts-node -- ./demo/demo6.ts
- npm run ts-node -- ./demo/demo7.ts
- npm run ts-node -- ./demo/demo8.ts
- npm run ts-node -- ./demo/demo9.ts
- npm run ts-node -- ./demo/demo10.ts
- npm run ts-node -- ./demo/demo11.ts
- npm run ts-node -- ./demo/demo12.ts
- npm run ts-node -- ./demo/demo13.ts
- npm run ts-node -- ./demo/demo14.ts
- npm run ts-node -- ./demo/demo15.ts
- npm run ts-node -- ./demo/demo16.ts
- npm run ts-node -- ./demo/demo17.ts
- npm run ts-node -- ./demo/demo18.ts
- npm run ts-node -- ./demo/demo19.ts
- npm run ts-node -- ./demo/demo20.ts
- npm run ts-node -- ./demo/demo21.ts
- npm run ts-node -- ./demo/demo22.ts
- npm run ts-node -- ./demo/demo23.ts
- npm run ts-node -- ./demo/demo24.ts
after_failure:
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
after_success:
- npm run typedoc
- echo "janchi.co.uk" > docs/.nojekyll
- echo "docx.js.org" > docs/.nojekyll
- echo "docx.js.org" > docs/CNAME
deploy:
provider: pages
skip-cleanup: true

View File

@ -1,9 +1,9 @@
<p align="center">
<img alt="clippy the assistant" src="http://i60.tinypic.com/339pvtt.png">
<img alt="clippy the assistant" src="https://i.imgur.com/37uBGhO.gif">
</p>
<p align="center">
Generate .docx files with JS/TS very easily, written in TS.
Easily generate .docx files with JS/TS. Works for Node and on the Browser.
</p>
---
@ -14,92 +14,55 @@
[![Dependency Status][daviddm-image]][daviddm-url]
[![Known Vulnerabilities][snky-image]][snky-url]
[![Chat on Gitter][gitter-image]][gitter-url]
[![code style: prettier][prettier-image]][prettier-url]
[![PRs Welcome][pr-image]][pr-url]
# docx
<p align="center">
<img src="https://i.imgur.com/H5FA1Qy.gif" alt="drawing" width="800"/>
</p>
## Install
# Demo
```sh
$ npm install --save docx
```
## Browser
## Demo
Here are examples of `docx` being used with basic `HTML/JS` in a browser environment.
* https://codepen.io/anon/pen/dqoVgQ
* https://jsfiddle.net/3xhezb5w/2
## Node
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**
* 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 - Header and Footer
* https://runkit.com/dolanmiu/docx-demo10 - **My CV generated with docx**
#### Run demos locally:
More [here](https://docx.js.org/#/examples) and [here](https://github.com/dolanmiu/docx/tree/master/demo)
```sh
$ npm run demo
```
# How to use & Documentation
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.
Please refer to the [documentation at https://docx.js.org/](https://docx.js.org/) for details on how to use this library, examples and much more!
## Guide
# Examples
Please refer to [the Wiki](https://github.com/dolanmiu/docx/wiki) for details on how to use this library, examples and much more!
Full documentation can be found here: [http://dolanmiu.github.io/docx/index.html](http://dolanmiu.github.io/docx/index.html)
## Simple Usage
```js
// Used to create docx files
var docx = require("docx");
// Create document
var doc = new docx.Document();
// Add some content in the document
var paragraph = new docx.Paragraph("Some cool text here.");
// Add more text into the paragraph if you wish
paragraph.addRun(new docx.TextRun("Lorem Ipsum Foo Bar"));
doc.addParagraph(paragraph);
// Used to export the file into a .docx file
var exporter = new docx.LocalPacker(doc);
// Or use the express packer to make the file downloadable.
// res is express' Response object
var exporter = new docx.ExpressPacker(doc, res);
exporter.pack("My First Document");
// If you want to export it as a .pdf file instead
exporter.packPdf("My First Document");
// done! A file called 'My First Document.docx'
// will be in your file system if you used LocalPacker
// Or it will start downloading if you are using Express
```
## Examples
Check [the Wiki](https://github.com/dolanmiu/docx/wiki/Examples) for examples.
Check the `examples` section in the [documentation](https://docx.js.org/#/examples) and the [demo folder](https://github.com/dolanmiu/docx/tree/master/demo) for examples.
# Contributing
Read the contribution guidelines [here](https://github.com/dolanmiu/docx/wiki/Contributing-Guidelines).
Read the contribution guidelines [here](https://docx.js.org/#/contribution-guidelines).
---
Made with 💖
Huge thanks to [@felipeochoa](https://github.com/felipeochoa) for awesome contributions to this project
[npm-image]: https://badge.fury.io/js/docx.svg
[npm-url]: https://npmjs.org/package/docx
[downloads-image]: https://img.shields.io/npm/dm/docx.svg
@ -112,7 +75,5 @@ Huge thanks to [@felipeochoa](https://github.com/felipeochoa) for awesome contri
[snky-url]: https://snyk.io/test/github/dolanmiu/docx
[gitter-image]: https://badges.gitter.im/dolanmiu/docx.svg
[gitter-url]: https://gitter.im/docx-lib/Lobby
[prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg
[prettier-url]: https://github.com/prettier/prettier
[pr-image]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
[pr-url]: http://makeapullrequest.com

39
demo/browser-demo.html Normal file
View File

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<script src="../build/index.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.js"></script>
</head>
<body>
<h1>DOCX browser Word document generation</h1>
<button type="button" onclick="generate()">Click to generate document</button>
<script>
function generate() {
const doc = new Document();
const paragraph = new Paragraph("Hello World");
const institutionText = new TextRun("Foo Bar").bold();
const dateText = new TextRun("Github is the best").tab().bold();
paragraph.addRun(institutionText);
paragraph.addRun(dateText);
doc.addParagraph(paragraph);
const packer = new Packer();
packer.toBlob(doc).then(blob => {
console.log(blob);
saveAs(blob, "example.docx");
console.log("Document created successfully");
});
}
</script>
</body>
</html>

View File

@ -1,16 +0,0 @@
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!');

20
demo/demo1.ts Normal file
View File

@ -0,0 +1,20 @@
// Simple example to add text to a document
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph, TextRun } from "../build";
const doc = new Document();
const paragraph = new Paragraph("Hello World");
const institutionText = new TextRun("Foo Bar").bold();
const dateText = new TextRun("Github is the best").tab().bold();
paragraph.addRun(institutionText);
paragraph.addRun(dateText);
doc.addParagraph(paragraph);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,8 +1,13 @@
const docx = require("../build");
// Add images to header and footer
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph, TextRun } from "../build";
// tslint:disable:no-shadowed-variable
const PHONE_NUMBER = "07534563401";
const PROFILE_URL = "https://www.linkedin.com/in/dolan1";
const EMAIL = "docx@docx.com";
const EMAIL = "docx@com";
const experiences = [
{
@ -122,13 +127,15 @@ const achievements = [
];
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());
public create(data: object[]): Document {
// tslint:disable-next-line:no-any
const experiences = data[0] as any[];
// tslint:disable-next-line:no-any
const educations = data[1] as any[];
const skills = data[2] as object[];
const achivements = data[3] as object[];
const document = new Document();
document.addParagraph(new Paragraph("Dolan Miu").title());
document.addParagraph(this.createContactInfo(PHONE_NUMBER, PROFILE_URL, EMAIL));
document.addParagraph(this.createHeading("Education"));
@ -181,23 +188,23 @@ class DocumentCreator {
document.addParagraph(this.createHeading("References"));
document.addParagraph(
new docx.Paragraph(
new 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 Paragraph("More references upon request"));
document.addParagraph(
new docx.Paragraph(
new 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();
public createContactInfo(phoneNumber: string, profileUrl: string, email: string): Paragraph {
const paragraph = new Paragraph().center();
const contactInfo = new TextRun(`Mobile: ${phoneNumber} | LinkedIn: ${profileUrl} | Email: ${email}`);
const address = new TextRun("Address: 58 Elm Avenue, Kent ME4 6ER, UK").break();
paragraph.addRun(contactInfo);
paragraph.addRun(address);
@ -205,18 +212,18 @@ class DocumentCreator {
return paragraph;
}
createHeading(text) {
return new docx.Paragraph(text).heading1().thematicBreak();
public createHeading(text: string): Paragraph {
return new Paragraph(text).heading1().thematicBreak();
}
createSubHeading(text) {
return new docx.Paragraph(text).heading2();
public createSubHeading(text: string): Paragraph {
return new 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();
public createInstitutionHeader(institutionName: string, dateText: string): Paragraph {
const paragraph = new Paragraph().maxRightTabStop();
const institution = new TextRun(institutionName).bold();
const date = new TextRun(dateText).tab().bold();
paragraph.addRun(institution);
paragraph.addRun(date);
@ -224,57 +231,61 @@ class DocumentCreator {
return paragraph;
}
createRoleText(roleText) {
const paragraph = new docx.Paragraph();
const role = new docx.TextRun(roleText).italic();
public createRoleText(roleText: string): Paragraph {
const paragraph = new Paragraph();
const role = new TextRun(roleText).italic();
paragraph.addRun(role);
return paragraph;
}
createBullet(text) {
return new docx.Paragraph(text).bullet();
public createBullet(text: string): Paragraph {
return new Paragraph(text).bullet();
}
createSkillList(skills) {
const paragraph = new docx.Paragraph();
// tslint:disable-next-line:no-any
public createSkillList(skills: any[]): Paragraph {
const paragraph = new Paragraph();
const skillConcat = skills.map((skill) => skill.name).join(", ") + ".";
paragraph.addRun(new docx.TextRun(skillConcat));
paragraph.addRun(new TextRun(skillConcat));
return paragraph;
}
createAchivementsList(achivements) {
const arr = [];
// tslint:disable-next-line:no-any
public createAchivementsList(achivements: any[]): Paragraph[] {
const arr: Paragraph[] = [];
for (const achievement of achivements) {
arr.push(new docx.Paragraph(achievement.name).bullet());
const paragraph = new Paragraph(achievement.name).bullet();
arr.push(paragraph);
}
return arr;
}
createInterests(interests) {
const paragraph = new docx.Paragraph();
public createInterests(interests: string): Paragraph {
const paragraph = new Paragraph();
paragraph.addRun(new docx.TextRun(interests));
paragraph.addRun(new TextRun(interests));
return paragraph;
}
splitParagraphIntoBullets(text) {
public splitParagraphIntoBullets(text: string): string[] {
return text.split("\n\n");
}
createPositionDateText(startDate, endDate, isCurrent) {
// tslint:disable-next-line:no-any
public createPositionDateText(startDate: any, endDate: any, isCurrent: boolean): string {
const startDateText = this.getMonthFromInt(startDate.month) + ". " + startDate.year;
const endDateText = isCurrent ? "Present" : `${this.getMonthFromInt(endDate.month)}. ${endDate.year}`;
return `${startDateText} - ${endDateText}`;
}
getMonthFromInt(value) {
public getMonthFromInt(value: number): string {
switch (value) {
case 1:
return "Jan";
@ -300,6 +311,8 @@ class DocumentCreator {
return "Nov";
case 12:
return "Dec";
default:
return "N/A";
}
}
}
@ -308,7 +321,8 @@ const documentCreator = new DocumentCreator();
const doc = documentCreator.create([experiences, education, skills, achievements]);
var exporter = new docx.LocalPacker(doc);
exporter.pack("Dolan Miu CV");
const packer = new Packer();
console.log("Document created successfully at project root!");
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,6 +1,9 @@
const docx = require("../build");
// Setting styles with JavaScript configuration
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph, Table } from "../build";
const doc = new docx.Document(undefined, {
const doc = new Document(undefined, {
top: 700,
right: 700,
bottom: 700,
@ -15,7 +18,7 @@ doc.Styles.createParagraphStyle("Heading1", "Heading 1")
.size(52)
.center()
.bold()
.color(000000)
.color("000000")
.spacing({ line: 340 })
.underline("single", "000000");
@ -51,7 +54,7 @@ doc.Styles.createParagraphStyle("normalPara", "Normal Para")
.font("Calibri")
.quickFormat()
.leftTabStop(453.543307087)
.maxRightTabStop(453.543307087)
.maxRightTabStop()
.size(26)
.spacing({ line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 });
@ -69,7 +72,7 @@ doc.Styles.createParagraphStyle("aside", "Aside")
.next("Normal")
.color("999999")
.italics()
.indent(720)
.indent({ left: 720 })
.spacing({ line: 276 });
doc.Styles.createParagraphStyle("wellSpaced", "Well Spaced")
@ -80,7 +83,7 @@ doc.Styles.createParagraphStyle("ListParagraph", "List Paragraph")
.quickFormat()
.basedOn("Normal");
doc.createImage("./demo/images/pizza.gif");
doc.createImage(fs.readFileSync("./demo/images/pizza.gif"));
doc
.createParagraph("HEADING")
.heading1()
@ -104,29 +107,35 @@ doc.createParagraph("Sir,").style("normalPara");
doc.createParagraph("BRIEF DESCRIPTION").style("normalPara");
var table = new docx.Table(4, 4);
var contentParagraph = table
const table = new Table(4, 4);
table
.getRow(0)
.getCell(0)
.addContent(new docx.Paragraph("Pole No."));
table.properties.width = 10000;
.addContent(new 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"
}];
const arrboth = [
{
image: "./demo/images/pizza.gif",
comment: "Test",
},
{
image: "./demo/images/pizza.gif",
comment: "Test 2",
},
];
arrboth.forEach(function(item) {
arrboth.forEach((item) => {
const para = doc.createParagraph();
para.createTextRun(doc.createImage(item.image));
para.properties.width = 60;
para.properties.height = 90;
para.addImage(doc.createImage(fs.readFileSync(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");
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,21 +0,0 @@
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!");

25
demo/demo12.ts Normal file
View File

@ -0,0 +1,25 @@
// Scaling images
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph } from "../build";
const doc = new Document();
const paragraph = new Paragraph("Hello World");
doc.addParagraph(paragraph);
const image = doc.createImage(fs.readFileSync("./demo/images/pizza.gif"));
const image2 = doc.createImage(fs.readFileSync("./demo/images/pizza.gif"));
const image3 = doc.createImage(fs.readFileSync("./demo/images/pizza.gif"));
const image4 = doc.createImage(fs.readFileSync("./demo/images/pizza.gif"));
image.scale(0.5);
image2.scale(1);
image3.scale(2.5);
image4.scale(4);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

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

28
demo/demo13.ts Normal file
View File

@ -0,0 +1,28 @@
// This example shows 3 styles using XML styles
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph } from "../build";
const styles = fs.readFileSync("./demo/assets/custom-styles.xml", "utf-8");
const doc = new Document({
title: "Title",
externalStyles: styles,
});
doc.createParagraph("Cool Heading Text").heading1();
const paragraph = new Paragraph('This is a custom named style from the template "MyFancyStyle"');
paragraph.style("MyFancyStyle");
doc.addParagraph(paragraph);
doc.createParagraph("Some normal text");
doc.createParagraph("MyFancyStyle again").style("MyFancyStyle");
paragraph.style("MyFancyStyle");
doc.addParagraph(paragraph);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

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

28
demo/demo14.ts Normal file
View File

@ -0,0 +1,28 @@
// Page numbers
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph, TextRun } from "../build";
const doc = new Document();
doc.createParagraph("First Page").pageBreak();
doc.createParagraph("Second Page");
const pageNumber = new TextRun("Page ").pageNumber();
const pageoneheader = new Paragraph("First Page Header ").right();
pageoneheader.addRun(pageNumber);
const firstPageHeader = doc.createFirstPageHeader();
firstPageHeader.addParagraph(pageoneheader);
const pagetwoheader = new Paragraph("My Title ").right();
pagetwoheader.addRun(pageNumber);
doc.Header.addParagraph(pagetwoheader);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

18
demo/demo15.ts Normal file
View File

@ -0,0 +1,18 @@
// Page break before example
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph } from "../build";
const doc = new Document();
const paragraph = new Paragraph("Hello World");
const paragraph2 = new Paragraph("Hello World on another page").pageBreakBefore();
doc.addParagraph(paragraph);
doc.addParagraph(paragraph2);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

40
demo/demo16.ts Normal file
View File

@ -0,0 +1,40 @@
// Multiple sections and headers
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, PageNumberFormat, PageOrientation, Paragraph } from "../build";
const doc = new Document();
const paragraph = new Paragraph("Hello World").pageBreak();
doc.addParagraph(paragraph);
const header = doc.createHeader();
header.createParagraph("Header on another page");
const footer = doc.createFooter();
footer.createParagraph("Footer on another page");
doc.addSection({
headerId: header.Header.ReferenceId,
footerId: footer.Footer.ReferenceId,
pageNumberStart: 1,
pageNumberFormatType: PageNumberFormat.DECIMAL,
});
doc.createParagraph("hello");
doc.addSection({
headerId: header.Header.ReferenceId,
footerId: footer.Footer.ReferenceId,
pageNumberStart: 1,
pageNumberFormatType: PageNumberFormat.DECIMAL,
orientation: PageOrientation.LANDSCAPE,
});
doc.createParagraph("hello in landscape");
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

21
demo/demo17.ts Normal file
View File

@ -0,0 +1,21 @@
// Footnotes
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph } from "../build";
const doc = new Document();
const paragraph = new Paragraph("Hello World").referenceFootnote(1);
const paragraph2 = new Paragraph("Hello World").referenceFootnote(2);
doc.addParagraph(paragraph);
doc.addParagraph(paragraph2);
doc.createFootnote(new Paragraph("Test"));
doc.createFootnote(new Paragraph("My amazing reference"));
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

17
demo/demo18.ts Normal file
View File

@ -0,0 +1,17 @@
// Insert image from a buffer
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer } from "../build";
const doc = new Document();
const imageBase64Data = `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`;
// doc.createImage(Buffer.from(imageBase64Data, 'base64'));
doc.createImage(Buffer.from(imageBase64Data, "base64"), 100, 100);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

20
demo/demo19.ts Normal file
View File

@ -0,0 +1,20 @@
// Export to base64 string - Useful in a browser environment.
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph, TextRun } from "../build";
const doc = new Document();
const paragraph = new Paragraph("Hello World");
const institutionText = new TextRun("Foo").bold();
const dateText = new TextRun("Bar").tab().bold();
paragraph.addRun(institutionText);
paragraph.addRun(dateText);
doc.addParagraph(paragraph);
const packer = new Packer();
packer.toBase64String(doc).then((str) => {
fs.writeFileSync("My Document.docx", str);
});

View File

@ -1,74 +0,0 @@
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!');

78
demo/demo2.ts Normal file
View File

@ -0,0 +1,78 @@
// Example on how to customise the look at feel using Styles
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer } from "../build";
const doc = new 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({ left: 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");
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 packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

21
demo/demo20.ts Normal file
View File

@ -0,0 +1,21 @@
// Add custom borders to table cell
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { BorderStyle, Document, Packer, Paragraph } from "../build";
const doc = new Document();
const table = doc.createTable(4, 4);
table
.getCell(2, 2)
.addContent(new Paragraph("Hello"))
.CellProperties.Borders.addTopBorder(BorderStyle.DASH_DOT_STROKED, 3, "red")
.addBottomBorder(BorderStyle.DOUBLE, 3, "blue")
.addStartBorder(BorderStyle.DOT_DOT_DASH, 3, "green")
.addEndBorder(BorderStyle.DOT_DOT_DASH, 3, "#ff8000");
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

37
demo/demo21.ts Normal file
View File

@ -0,0 +1,37 @@
// This demo shows how to create bookmarks then link to them with internal hyperlinks
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer } from "../build";
const loremIpsum =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mi velit, convallis convallis scelerisque nec, faucibus nec leo. Phasellus at posuere mauris, tempus dignissim velit. Integer et tortor dolor. Duis auctor efficitur mattis. Vivamus ut metus accumsan tellus auctor sollicitudin venenatis et nibh. Cras quis massa ac metus fringilla venenatis. Proin rutrum mauris purus, ut suscipit magna consectetur id. Integer consectetur sollicitudin ante, vitae faucibus neque efficitur in. Praesent ultricies nibh lectus. Mauris pharetra id odio eget iaculis. Duis dictum, risus id pellentesque rutrum, lorem quam malesuada massa, quis ullamcorper turpis urna a diam. Cras vulputate metus vel massa porta ullamcorper. Etiam porta condimentum nulla nec tristique. Sed nulla urna, pharetra non tortor sed, sollicitudin molestie diam. Maecenas enim leo, feugiat eget vehicula id, sollicitudin vitae ante.";
const doc = new Document({
creator: "Clippy",
title: "Sample Document",
description: "A brief example of using docx with bookmarks and internal hyperlinks",
});
const anchorId = "anchorID";
// First create the bookmark
const bookmark = doc.createBookmark(anchorId, "Lorem Ipsum");
// That has header styling
doc
.createParagraph()
.addBookmark(bookmark)
.heading1();
doc.createParagraph("\n");
doc.createParagraph(loremIpsum);
doc.createParagraph().pageBreak();
// Now the link back up to the bookmark
const hyperlink = doc.createInternalHyperLink(anchorId, `Click me!`);
doc.createParagraph().addHyperLink(hyperlink);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

27
demo/demo22.ts Normal file
View File

@ -0,0 +1,27 @@
// This demo shows right to left for special languages
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph, TextRun } from "../build";
const doc = new Document();
const paragraph1 = new Paragraph().bidirectional();
const textRun1 = new TextRun("שלום עולם").rightToLeft();
paragraph1.addRun(textRun1);
doc.addParagraph(paragraph1);
const paragraph2 = new Paragraph().bidirectional();
const textRun2 = new TextRun("שלום עולם").bold().rightToLeft();
paragraph2.addRun(textRun2);
doc.addParagraph(paragraph2);
const paragraph3 = new Paragraph().bidirectional();
const textRun3 = new TextRun("שלום עולם").italic().rightToLeft();
paragraph3.addRun(textRun3);
doc.addParagraph(paragraph3);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

34
demo/demo23.ts Normal file
View File

@ -0,0 +1,34 @@
// This demo adds an image to the Media cache, and then insert to the document afterwards
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Media, Packer, Paragraph } from "../build";
const doc = new Document();
const paragraph = new Paragraph("Hello World");
doc.addParagraph(paragraph);
const image = Media.addImage(doc, "./demo/images/image1.jpeg");
const image2 = Media.addImage(doc, "./demo/images/dog.png");
const image3 = Media.addImage(doc, "./demo/images/cat.jpg");
const image4 = Media.addImage(doc, "./demo/images/parrots.bmp");
const image5 = Media.addImage(doc, "./demo/images/pizza.gif");
const imageBase64Data = `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`;
const image6 = Media.addImage(doc, Buffer.from(imageBase64Data, "base64"), 100, 100);
// I am adding an image to the paragraph rather than the document to make the image inline
paragraph.addImage(image5);
doc.addImage(image);
doc.addImage(image2);
doc.addImage(image3);
doc.addImage(image4);
doc.addImage(image5);
doc.addImage(image6);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

18
demo/demo24.ts Normal file
View File

@ -0,0 +1,18 @@
// Add image to table cell
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Media, Packer, Paragraph } from "../build";
const doc = new Document();
const table = doc.createTable(4, 4);
table.getCell(2, 2).addContent(new Paragraph("Hello"));
const image = Media.addImage(doc, "./demo/images/image1.jpeg");
table.getCell(1, 1).addContent(image.Paragraph);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

22
demo/demo26.ts Normal file
View File

@ -0,0 +1,22 @@
// Creates two paragraphs, one with a border and one without
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph } from "../build";
const doc = new Document();
const paragraph = new Paragraph("No border!");
doc.addParagraph(paragraph);
const borderParagraph = new Paragraph("I have borders on my top and bottom sides!").createBorder();
borderParagraph.Borders.addTopBorder();
borderParagraph.Borders.addBottomBorder();
doc.addParagraph(borderParagraph);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

34
demo/demo27.ts Normal file
View File

@ -0,0 +1,34 @@
import * as fs from "fs";
import { Document, Packer } from "../build";
const doc = new Document();
const myStyles = doc.Styles;
// The first argument is an ID you use to apply the style to paragraphs
// The second argument is a human-friendly name to show in the UI
myStyles.createParagraphStyle("myWonkyStyle", "My Wonky Style")
.basedOn("Normal")
.next("Normal")
.color("990000")
.italics()
.indent({left: 720}) // 720 TWIP === 720 / 20 pt === .5 in
.spacing({line: 276}); // 276 / 240 = 1.15x line spacing
myStyles.createParagraphStyle("Heading2", "Heading 2")
.basedOn("Normal")
.next("Normal")
.quickFormat()
.size(26) // 26 half-points === 13pt font
.bold()
.underline("double", "FF0000")
.spacing({before: 240, after: 120}); // TWIP for both
doc.createParagraph("Hello").style("myWonkyStyle");
doc.createParagraph("World").heading2(); // Uses the Heading2 style
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
console.log("Document created successfully at project root!");
});

43
demo/demo28.ts Normal file
View File

@ -0,0 +1,43 @@
// Creates two paragraphs, one with a border and one without
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { File, Packer, Paragraph, StyleLevel, TableOfContents } from "../build";
const doc = new File();
// The first argument is an ID you use to apply the style to paragraphs
// The second argument is a human-friendly name to show in the UI
doc.Styles.createParagraphStyle("MySpectacularStyle", "My Spectacular Style")
.basedOn("Heading1")
.next("Heading1")
.color("990000")
.italics();
// WordprocessingML docs for TableOfContents can be found here:
// http://officeopenxml.com/WPtableOfContents.php
// Let's define the properties for generate a TOC for heading 1-5 and MySpectacularStyle,
// making the entries be hyperlinks for the paragraph
const toc = new TableOfContents("Summary", {
hyperlink: true,
headingStyleRange: "1-5",
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)],
});
doc.addTableOfContents(toc);
doc.addParagraph(new Paragraph("Header #1").heading1().pageBreakBefore());
doc.addParagraph(new Paragraph("I'm a little text very nicely written.'"));
doc.addParagraph(new Paragraph("Header #2").heading1().pageBreakBefore());
doc.addParagraph(new Paragraph("I'm a other text very nicely written.'"));
doc.addParagraph(new Paragraph("Header #2.1").heading2());
doc.addParagraph(new Paragraph("I'm a another text very nicely written.'"));
doc.addParagraph(new Paragraph("My Spectacular Style #1").style("MySpectacularStyle").pageBreakBefore());
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

32
demo/demo29.ts Normal file
View File

@ -0,0 +1,32 @@
import * as fs from "fs";
import { Document, Indent, Numbering, Packer, Paragraph } from "../build";
const doc = new Document();
const numbering = new Numbering();
const abstractNum = numbering.createAbstractNumbering();
abstractNum.createLevel(0, "upperRoman", "%1", "start").addParagraphProperty(new Indent({ left: 720, hanging: 260 }));
const concrete = numbering.createConcreteNumbering(abstractNum);
const item1 = new Paragraph("line with contextual spacing");
const item2 = new Paragraph("line with contextual spacing");
const item3 = new Paragraph("line without contextual spacing");
const item4 = new Paragraph("line without contextual spacing");
item1.setNumbering(concrete, 0).spacing({before: 200}).contextualSpacing(true);
item2.setNumbering(concrete, 0).spacing({before: 200}).contextualSpacing(true);
item3.setNumbering(concrete, 0).spacing({before: 200}).contextualSpacing(false);
item4.setNumbering(concrete, 0).spacing({before: 200}).contextualSpacing(false);
doc.addParagraph(item1);
doc.addParagraph(item2);
doc.addParagraph(item3);
doc.addParagraph(item4);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,45 +0,0 @@
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!');

46
demo/demo3.ts Normal file
View File

@ -0,0 +1,46 @@
// Numbering and bullet points example
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Indent, Numbering, Packer, Paragraph } from "../build";
const doc = new Document();
const numbering = new Numbering();
const abstractNum = numbering.createAbstractNumbering();
abstractNum.createLevel(0, "upperRoman", "%1", "start").addParagraphProperty(new Indent({ left: 720, hanging: 260 }));
abstractNum.createLevel(1, "decimal", "%2.", "start").addParagraphProperty(new Indent({ left: 1440, hanging: 980 }));
abstractNum.createLevel(2, "lowerLetter", "%3)", "start").addParagraphProperty(new Indent({ left: 14402160, hanging: 1700 }));
const concrete = numbering.createConcreteNumbering(abstractNum);
const topLevelP = new Paragraph("Hey you");
const subP = new Paragraph("What's up fam");
const secondSubP = new Paragraph("Hello World 2");
const subSubP = new 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);
const bullet1 = new Paragraph("Hey you").bullet();
const bullet2 = new Paragraph("What's up fam").bullet(1);
const bullet3 = new Paragraph("Hello World 2").bullet(2);
const bullet4 = new Paragraph("Yeah boi").bullet(3);
doc.addParagraph(bullet1);
doc.addParagraph(bullet2);
doc.addParagraph(bullet3);
doc.addParagraph(bullet4);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

26
demo/demo31.ts Normal file
View File

@ -0,0 +1,26 @@
// Example of how you would create a table and add data to it
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph, VerticalAlign } from "../build";
const doc = new Document();
const table = doc.createTable(2, 2);
table
.getCell(1, 1)
.addContent(new Paragraph("This text should be in the middle of the cell"))
.CellProperties.setVerticalAlign(VerticalAlign.CENTER);
table
.getCell(1, 0)
.addContent(
new Paragraph(
"Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah",
).heading1(),
);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

35
demo/demo32.ts Normal file
View File

@ -0,0 +1,35 @@
// Example of how you would create a table and add data to it
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph } from "../build";
const doc = new Document();
let table = doc.createTable(2, 2);
table.getCell(0, 0).addContent(new Paragraph("Hello"));
table.getRow(0).mergeCells(0, 1);
doc.createParagraph("Another table").heading2();
table = doc.createTable(2, 3);
table.getCell(0, 0).addContent(new Paragraph("World"));
table.getRow(0).mergeCells(0, 2);
doc.createParagraph("Another table").heading2();
table = doc.createTable(2, 4);
table.getCell(0, 0).addContent(new Paragraph("Foo"));
table.getCell(1, 0).addContent(new Paragraph("Bar1"));
table.getCell(1, 1).addContent(new Paragraph("Bar2"));
table.getCell(1, 2).addContent(new Paragraph("Bar3"));
table.getCell(1, 3).addContent(new Paragraph("Bar4"));
table.getRow(0).mergeCells(0, 3);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,12 +0,0 @@
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!');

15
demo/demo4.ts Normal file
View File

@ -0,0 +1,15 @@
// Example of how you would create a table and add data to it
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph } from "../build";
const doc = new Document();
const table = doc.createTable(4, 4);
table.getCell(2, 2).addContent(new Paragraph("Hello"));
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,17 +0,0 @@
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!');

21
demo/demo5.ts Normal file
View File

@ -0,0 +1,21 @@
// Example of how to add images to the document - You can use Buffers, UInt8Arrays or Base64 strings
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph } from "../build";
const doc = new Document();
const paragraph = new Paragraph("Hello World");
doc.addParagraph(paragraph);
doc.createImage(fs.readFileSync("./demo/images/image1.jpeg"));
doc.createImage(fs.readFileSync("./demo/images/dog.png").toString("base64"));
doc.createImage(fs.readFileSync("./demo/images/cat.jpg"));
doc.createImage(fs.readFileSync("./demo/images/parrots.bmp"));
doc.createImage(fs.readFileSync("./demo/images/pizza.gif"));
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,25 +0,0 @@
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!");

29
demo/demo6.ts Normal file
View File

@ -0,0 +1,29 @@
// Example of how to change page borders
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, Paragraph, TextRun } from "../build";
const doc = new Document(undefined, {
top: 0,
right: 0,
bottom: 0,
left: 0,
});
const paragraph = new Paragraph("Hello World");
const institutionText = new TextRun("Foo bar").bold();
const dateText = new TextRun("Github is the best").tab().bold();
paragraph.addRun(institutionText);
paragraph.addRun(dateText);
doc.addParagraph(paragraph);
doc.createParagraph("Hello World").heading1();
doc.createParagraph("Foo bar");
doc.createParagraph("Github is the best");
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,14 +0,0 @@
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!");

18
demo/demo7.ts Normal file
View File

@ -0,0 +1,18 @@
// Example of how to set the document to landscape
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer, PageOrientation, Paragraph } from "../build";
const doc = new Document(undefined, {
orientation: PageOrientation.LANDSCAPE,
});
const paragraph = new Paragraph("Hello World");
doc.addParagraph(paragraph);
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,13 +0,0 @@
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!');

17
demo/demo8.ts Normal file
View File

@ -0,0 +1,17 @@
// Add text to header and footer
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer } from "../build";
const doc = new Document();
doc.createParagraph("Hello World");
doc.Header.createParagraph("Header text");
doc.Footer.createParagraph("Footer text");
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,13 +0,0 @@
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!');

17
demo/demo9.ts Normal file
View File

@ -0,0 +1,17 @@
// Add images to header and footer
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer } from "../build";
const doc = new Document();
doc.createParagraph("Hello World");
doc.Header.createImage(fs.readFileSync("./demo/images/pizza.gif"));
doc.Footer.createImage(fs.readFileSync("./demo/images/pizza.gif"));
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,29 +0,0 @@
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}`);
});

34
demo/index.ts Normal file
View File

@ -0,0 +1,34 @@
// tslint:disable:no-console
import * as fs from "fs";
import * as prompt from "prompt";
import * as shelljs from "shelljs";
console.log("What demo do you wish to run? (Enter a number)");
const schema = {
properties: {
number: {
pattern: /^[0-9]+$/,
message: "Please enter a number.",
required: true,
},
},
};
prompt.start();
prompt.get(schema, (_, result) => {
const demoNumber = result.number;
const filePath = `./demo/demo${demoNumber}.ts`;
if (!fs.existsSync(filePath)) {
console.error(`demo${demoNumber} does not exist: ${filePath}`);
return;
}
console.log(`Running demo ${demoNumber}`);
if (shelljs.exec(`npm run ts-node -- ${filePath}`).code === 0) {
console.log("Document created successfully");
} else {
console.error("Something went wrong with the demo");
}
});

63
docs/README.md Normal file
View File

@ -0,0 +1,63 @@
<p align="center">
<img alt="clippy the assistant" src="https://i.imgur.com/pwCV6L8.png">
</p>
<p align="center">
Easily generate .docx files with JS/TS. Works for Node and on the Browser. :100:
</p>
---
# Welcome
## Installation
```sh
npm install --save docx
```
Then you can `require` or `import` as usual:
```js
let docx = require("docx");
```
```js
import * as docx from "docx";
```
## Basic Usage
```js
var docx = require("docx");
// Create document
var doc = new docx.Document();
// Add some content in the document
var paragraph = new docx.Paragraph("Some cool text here.");
// Add more text into the paragraph if you wish
paragraph.addRun(new docx.TextRun("Lorem Ipsum Foo Bar"));
doc.addParagraph(paragraph);
// Used to export the file into a .docx file
var exporter = new docx.LocalPacker(doc);
exporter.pack("My First Document");
// Done! A file called 'My First Document.docx' will be in your file system if you used LocalPacker
```
## Honoured Mentions
[@felipeochoa](https://github.com/felipeochoa)
[@h4buli](https://github.com/h4buli)
<p align="center">
<img alt="clippy the assistant" src="http://i60.tinypic.com/339pvtt.png">
</p>
---
Made with 💖

28
docs/_sidebar.md Normal file
View File

@ -0,0 +1,28 @@
* [Getting Started](/)
* [Examples](examples.md)
* API
* [Documentation](https://docx.js.org/api/)
* Usage
* [Document](usage/document.md)
* [Paragraph](usage/paragraph.md)
* [Text](usage/text.md)
* [Image](usage/images.md)
* [Headers & Footers](usage/headers-and-footers.md)
* [Bullet Points](usage/bullet-points.md)
* [Numbering](usage/numbering.md)
* [Tab Stops](usage/tab-stops.md)
* [Table of Contents](usage/table-of-contents.md)
* Styling
* [Styling with JS](usage/styling-with-js.md)
* [Styling with XML](usage/styling-with-xml.md)
* Exporting
* [Packers](usage/packers.md)
* [Contribution Guidelines](contribution-guidelines.md)

View File

@ -0,0 +1,80 @@
# Contribution Guidelines
## Writing Code
* Include documentation reference(s) at the top of each file:
```js
// http://officeopenxml.com/WPdocument.php
```
* Follow Prettier standards, and consider using the [Prettier VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) plugin.
* Follow the `TSLint` rules
## Add vs Create
This is just a guideline, and the rules can sometimes be broken.
* Use `create` if the method `new`'s up an element inside:
```js
public createParagraph() {
const paragraph = new Paragraph();
this.root.push(paragraph);
}
```
* Use `add` if you add the element into the method as a parameter:
```js
public addParagraph(paragraph: Paragraph) {
this.root.push(paragraph);
}
```
## Getters and Setters
Getters and Setters are done with a capital letter like so:
```js
public get Level() {
}
```
There is no performance advantage by doing this. It means we don't need to prefix all private variables with the ugly `_`:
**Do not:**
```js
private get _level: string;
```
**Do**
```js
private get level: string;
```
## Testing
Please write a test of every file you make and suffix it with `.spec.ts`.
Here is a template of a test:
```js
import { assert } from "chai";
describe("ClassName", () => {
beforeEach(() => {
// TODO
});
describe("#methodName()", () => {
it("should ", () => {
// TODO
});
});
});
```

218
docs/examples.md Normal file
View File

@ -0,0 +1,218 @@
# Examples
> All examples can run independently and can be found in the `/demo` folder of the project
All the examples below can be ran locally, to do so, run the following command:
```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.
## Simple
A simple hello world of the `docx` library:
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo1.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo1.ts_
## Styles
### Styling with JS
This example shows how to customise the look and feel of a document using JS configuration
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo2.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo2.ts_
### Styling with XML
This example shows how to customise the look and feel of a document using XML configuration
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo13.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo13.ts_
## Numbering
This example shows many levels of numbering
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo3.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo3.ts_
## Table
Example of simple table
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo4.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo4.ts_
### Styling table borders
Styling the borders of a table
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo20.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo20.ts_
## Images
### Add image to the document
Importing Images from file system path
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo5.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.ts_
### Add images to header and footer
Example showing how to add image to headers and footers
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo9.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.ts_
### Scaling images
Example showing how to scale images
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo12.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo12.ts_
### Add Image to media before adding to document
This is the best way to add an image to a document because you can add the same image in two locations without increasing document size by re-using the same image
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo23.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo23.ts_
### Add image to table
As before, to add an image to a table, you would need to add it to the `Media` object first
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo24.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo24.ts_
### Images using Base64 URI
If you want to use a Base64 image instead
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo18.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo18.ts_
## Margins
Example showing how to set custom margains
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo6.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo6.ts_
## Orientation
Example showing how to set the document to `landscape` or `portrait`
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo7.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo7.ts_
## Headers & Footers
Example showing how to add headers and footers
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo8.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo8.ts_
## Multiple headers and footers
Check out `Sections` for this feature
## Page Breaks
### Normal page breaks
Example showing how to page break
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo14.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo14.ts_
### Page break before
Example showing how to page break before like in Word
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo15.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo15.ts_
## Sections
Example of how sections work. Sections allow multiple headers and footers, and `landscape`/`portrait` inside the same document
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo16.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo16.ts_
## Footnotes
Example of how to add footnotes. Good for references
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo17.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo17.ts_
## Packers
## Buffer output
Example showing how to use the Buffer packer and then write that buffer to the file system
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo19.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo19.ts_
## Bookmarks
Example showing how to make bookmarks to make internal hyperlinks within the document
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo21.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo21.ts_
## Bidirectional text
Example showing how to use bidirectional text for certain languages such as Hebrew
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo22.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo22.ts_
## Showcase
### My CV
Example showing how to add headers and footers
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo10.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo10.ts_
### Style and Images
This example shows how to customise the look and feel of a document and add images
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo11.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo11.ts_

30
docs/index.html Normal file
View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>docx - Generate .docx documents with JavaScript</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Generate .docx documents with JavaScript">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: 'docx',
repo: 'https://github.com/dolanmiu/docx',
loadSidebar: true,
subMaxLevel: 2,
search: 'auto',
}
</script>
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
<script src="https://unpkg.com/docsify-copy-code@2"></script>
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
</body>
</html>

View File

@ -0,0 +1,21 @@
# Bullet Points
## Example
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

35
docs/usage/document.md Normal file
View File

@ -0,0 +1,35 @@
# Document
> The `Document` object is the starting point of your `.docx` journey, this is the literal Word Document. You add all your content such as `Paragraphs` to this `Document`, and at the end export it however you like.
To create a new document, it is very easy:
```js
var doc = new docx.Document();
```
## Document properties
You can add properties to the Word document by specifying options, for example:
```js
var doc = new docx.Document({
creator: "Dolan Miu",
description: "My extremely interesting document",
title: "My Document",
});
```
### Full list of options:
```
creator
description
title
subject
keywords
lastModifiedBy
revision
```
You can mix and match whatever properties you want, or provide no properties.

View File

@ -0,0 +1,47 @@
# Headers and Footers
## Example
Creating Headers and footers is simple. Access the `Header` and `Footer` by doing so like this:
```js
doc.Header;
doc.Footer;
```
You can call the same methods as you would with a `File`:
```js
doc.Header.createParagraph("Header text");
doc.Footer.createParagraph("Footer text");
```
Even add images:
```js
doc.Header.createImage([BUFFER_OF_YOUR_IMAGE]);
doc.Footer.createImage([BUFFER_OF_YOUR_IMAGE]);
```
Refer to `demo8.js` for more information
## Multiple Headers and Footers
Also all the supported section properties are implemented according to: http://officeopenxml.com/WPsection.php
### Example
```js
const header = this.document.createHeader();
const footer = this.document.createFooter();
// Add new section with another header and footer
doc.addSection({
headerId: header.Header.ReferenceId,
footerId: footer.Footer.ReferenceId,
pageNumberStart: 1,
pageNumberFormatType: docx.PageNumberFormat.DECIMAL,
});
```

156
docs/usage/images.md Normal file
View File

@ -0,0 +1,156 @@
# Images
## Intro
Adding images is very simple
Simply call the `createImage` method:
```js
const image = doc.createImage([BUFFER_OF_YOUR_IMAGE]);
```
`docx` supports `jpeg`, `jpg`, `bmp`, `gif` and `png`
Check `demo5.js` for an example
## Positioning
Images can be:
* floating position of images
* Wrapped around the text
* Inline
By default, picture are exported as `INLINE` elements.
In Word this is found in:
![Word Image Positiong](https://user-images.githubusercontent.com/34742290/41765548-b0946302-7604-11e8-96f9-166a9f0b8f39.png)
### Usage
The `PictureRun` element support various options to define the positioning of the element in the document.
```js
interface DrawingOptions {
position?: PlacementPosition;
textWrapping?: TextWrapping;
floating?: Floating;
}
```
can be passed when creating `PictureRun()` for example:
```js
const imageData = document.createImage(buffer, 903, 1149);
new docx.PictureRun(imageData, {
position: docx.PlacementPosition.FLOATING,
floating: {
horizontalPosition: {
relative: HorizontalPositionRelativeFrom.PAGE,
align: HorizontalPositionAlign.LEFT,
},
verticalPosition: {
relative: VerticalPositionRelativeFrom.PAGE,
align: VerticalPositionAlign.TOP,
},
},
});
```
So, the first thing is to define the placement position: `INLINE` or `FLOATING`. Inline is the default one so there is no need to pass drawing options for inline.
When placement position is FLOATING then we can use two options:
### Wrap text
for `drawingOptions.textWrapping` we can define various options. `textWrapping` has the following properties:
```js
interface TextWrapping {
textWrapStyle: TextWrapStyle;
wrapTextOption?: WrapTextOption;
distanceFromText?: Distance;
}
enum TextWrapStyle {
NONE,
SQUARE,
TIGHT,
TOP_AND_BOTTOM,
}
enum WrapTextOption {
BOTH_SIDES = "bothSides",
LEFT = "left",
RIGHT = "right",
LARGEST = "largest",
}
```
### Floating position
When we want to position the image relative or absolute then we need to use option `drawingOptions.floating`:
```js
export interface Floating {
horizontalPosition: HorizontalPositionOptions;
verticalPosition: VerticalPositionOptions;
allowOverlap?: boolean;
lockAnchor?: boolean;
behindDocument?: boolean;
layoutInCell?: boolean;
}
export interface HorizontalPositionOptions {
relative: HorizontalPositionRelativeFrom;
align?: HorizontalPositionAlign;
offset?: number;
}
export interface VerticalPositionOptions {
relative: VerticalPositionRelativeFrom;
align?: VerticalPositionAlign;
offset?: number;
}
export enum HorizontalPositionRelativeFrom {
CHARACTER = "character",
COLUMN = "column",
INSIDE_MARGIN = "insideMargin",
LEFT_MARGIN = "leftMargin",
MARGIN = "margin",
OUTSIDE_MARGIN = "outsideMargin",
PAGE = "page",
RIGHT_MARGIN = "rightMargin",
}
export enum VerticalPositionRelativeFrom {
BOTTOM_MARGIN = "bottomMargin",
INSIDE_MARGIN = "insideMargin",
LINE = "line",
MARGIN = "margin",
OUTSIDE_MARGIN = "outsideMargin",
PAGE = "page",
PARAGRAPH = "paragraph",
TOP_MARGIN = "topMargin",
}
export enum HorizontalPositionAlign {
CENTER = "center",
INSIDE = "inside",
LEFT = "left",
OUTSIDE = "outside",
RIGHT = "right",
}
export enum VerticalPositionAlign {
BOTTOM = "bottom",
CENTER = "center",
INSIDE = "inside",
OUTSIDE = "outside",
TOP = "top",
}
```

96
docs/usage/numbering.md Normal file
View File

@ -0,0 +1,96 @@
# Bullets and Numbering
`docx` is quite flexible in its bullets and numbering system, allowing
the user great freedom in how bullets and numbers are to be styled and
displayed. E.g., numbers can be shown using Arabic numerals, roman
numerals, or even ordinal words ("one", "two", "three", ...). The
format also supports re-using bullets/numbering styles throughout the
document, so that different lists using the same style need not
redefine them.
Because of this flexibility, bullets and numbering in DOCX involves a
couple of moving pieces:
1. Document-level bullets/numbering definitions (abstract)
2. Document-level bullets/numbering definitions (concrete)
3. Paragraph-level bullets/numbering selection
## Document-level bullets/numbering definitions (abstract)
Every document contains a set of abstract bullets/numbering
definitions which define the formatting and layout of paragraphs using
those bullets/numbering. An abstract numbering system defines how
bullets/numbers are to be shown for lists, including any sublists that
may be used. Thus each abstract definition includes a series of
_levels_ which form a sequence starting at 0 indicating the top-level
list look and increasing from there to descibe the sublists, then
sub-sublists, etc. Each level includes the following properties:
* **level**: This its 0-based index in the defintion stack
* **numberFormat**: This indicates how the bullet or number should be
generated. Options include `bullet` (meaning don't count), `decimal`
(arabic numerals), `upperRoman`, `lowerRoman`, `hex`, and many
more.
* **levelText**: This is a format string using the output of the
`numberFormat` function and generating a string to insert before
every item in the list. You may use `%1`, `%2`, ... to reference the
numbers from each numbering level before this one. Thus a level
text of `%d)` with a number format of `lowerLetter` would result in
the sequence "a)", "b)", ...
* and a few others, which you can see in the OXML spec section 17.9.6
## Document-level bullets/numbering defintions (concrete)
Concrete definitions are sort of like concrete subclasses of the
abstract defintions. They indicate their parent and are allowed to
override certain level definitions. Thus two lists that differ only in
how sub-sub-lists are to be displayed can share the same abstract
numbering definition and have slightly different concrete definitions.
## Paragraph-level bullets/numbering selection
In order to use a bullets/numbering definition (which must be
concrete), paragraphs need to select it, similar to applying a CSS
class to an element, using both the concrete numbering definition ID
and the level number that the paragraph should be at. Additionally, MS
Word and LibreOffice typically apply a "ListParagraph" style to
paragraphs that are being numbered.
## Using bullets/numbering in `docx`
`docx` includes a pre-defined bullet style which you can add to your
paragraphs using `para.bullets()`. If you require different bullet
styles or numbering of any kind, you'll have to use the
`docx.Numbering` class.
First you need to create a new numbering container class and use it to
create your abstract numbering style, define your levels, and creat
your concreate numbering style:
```js
const numbering = new docx.Numbering();
const abstractNum = numbering.createAbstractNumbering();
abstractNum.createLevel(0, "upperRoman", "%1", "start").addParagraphProperty(new Indent(720, 260));
abstractNum.createLevel(1, "decimal", "%2.", "start").addParagraphProperty(new Indent(1440, 980));
abstractNum.createLevel(2, "lowerLetter", "%3)", "start").addParagraphProperty(new Indent(2160, 1700));
const concrete = numbering.createConcreteNumbering(numberedAbstract);
```
You can then apply your concrete style to paragraphs using their
`#setNumbering` method:
```js
topLevelP.setNumbering(concrete, 0);
subP.setNumbering(concrete, 1);
subSubP.setNumbering(concrete, 2);
```
Finally, you need to let your exporter know about your numbering
styles when you're ready to render the document:
```js
const packer = new Packer(doc, undefined, undefined, numbering);
packer.pack(myOutput);
```

117
docs/usage/packers.md Normal file
View File

@ -0,0 +1,117 @@
# Packers
> Packers are the way in which `docx` turns your code into `.docx` format. It is completely decoupled from the `docx.Document`.
## Version 4
Packers in `version 4` and above are now one single `Packer`. It works in both a node and browser environment (Angular etc). Now, the packer returns a `Buffer`, `Blob` or `base64 string`. It is up to you to take that and persist it with node's `fs`, send it down as a downloadable file, or anything else you wish. As of version 4, this library will not have options to export to PDF.
### Export as Buffer
This will return a NodeJS `Buffer`. If this is used in the browser, it will return a `UInt8Array` instead.
```js
const packer = new docx.Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});
```
### Export as a `base64` string
```js
const packer = new docx.Packer();
packer.toBase64String(doc).then((string) => {
console.log(string);
});
```
### Export as Blob
This is useful if you want to send it as an downloadable in a browser environment.
```js
const packer = new docx.Packer();
packer.toBlob(doc).then((blob) => {
// saveAs from FileSaver will download the file
saveAs(blob, "example.docx");
});
```
## Version 3 and below
### File System Packer
```js
const docx = require("docx");
const doc = new docx.Document();
const exporter = new docx.LocalPacker(doc);
exporter.pack("My Document");
// Word Document is in file system
```
### Buffer Packer
```js
const docx = require("docx");
const doc = new docx.Document();
const exporter = new docx.BufferPacker(doc);
const buffer = exporter.pack();
```
### Stream Packer
Creates a `node` `Readable` stream
```js
const docx = require("docx");
const doc = new docx.Document();
const exporter = new docx.StreamPacker(doc);
const stream = exporter.pack();
```
### Express Packer
The old express packer is now deprecated and may disappear soon, so you should upgrade.
The reason for this is because it means this project needs to know about and use `express`, which for a Word document generator, does not sound right. Seperation of concerns.
It will still be usable (for now), but it is ill advised.
I used the express exporter in my [website](http://www.dolan.bio).
The recommended way is to use the `StreamPacker` and handle the `express` magic outside of the library:
```js
const docx = require("docx");
const doc = new docx.Document();
const exporter = new docx.StreamPacker(doc);
const stream = exporter.pack();
// Express' response object
res.attachment("yourfile.xlsx");
stream.pipe(res);
```
where `res` is the response object obtained through the Express router. It is that simple. The file will begin downloading in the browser.
### PDF Exporting
You can export your word document as a PDF file like so:
```js
const exporter = new docx.LocalPacker(doc);
exporter.packPdf("My Document");
// Express
const exporter = new docx.ExpressPacker(doc, res);
exporter.packPdf("My Document");
```

113
docs/usage/paragraph.md Normal file
View File

@ -0,0 +1,113 @@
# Paragraph
> Everything (text, images, graphs etc) in OpenXML is organised in paragraphs.
## Example
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.addRun(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
To create styles, please refer to the styling Wiki: https://github.com/dolanmiu/docx/wiki/Styling
![Word 2013 Styles menu](http://content.gcflearnfree.org/topics/233/style_apply_choose.png "Word 2013 Styles menu")
### Heading1 - Heading5
```js
paragraph.heading1();
paragraph.heading2();
paragraph.heading3();
paragraph.heading4();
paragraph.heading5();
```
### Title
```js
paragraph.title();
```
## Text Alignment
To change the text alignment of a paragraph, for center, left, right or justified:
```js
paragraph.center();
```
```js
paragraph.left();
```
```js
paragraph.right();
```
```js
paragraph.justified();
```
### Example
```js
paragraph.heading1().center();
```
The above will create a `heading 1` which is `centered`.
## Thematic Break
To add a break in the page, simply add `.thematicBreak()` on a paragraph:
```js
var paragraph = new docx.Paragraph("Amazing Heading").heading1().thematicBreak();
```
The above example will create a heading with a page break directly under it.
## Page Break
To move to a new page (insert a page break), simply add `.pageBreak()` on a paragraph:
```js
var paragraph = new docx.Paragraph("Amazing Heading").heading1().pageBreak();
```
The above example will create a heading and start a new page immediately afterwards.
### Page break before:
This option (available in word) will make sure that the paragraph will start on a new page (if it's not already on a new page).
```js
var paragraph = new docx.Paragraph("Hello World on another page").pageBreakBefore();
```
![Page Break Before in Word](https://user-images.githubusercontent.com/34742290/40176503-df3a8398-59db-11e8-8b9c-d719f13aa8b4.png)
Example: https://github.com/dolanmiu/docx/blob/master/demo/demo15.js
## Page break control
Paragraphs have `.keepLines()` and `.keepNext()` methods that allow restricting page breaks within and between paragraphs. See [this Microsoft article](https://support.office.com/en-us/article/Keep-lines-and-paragraphs-together-d72af534-926f-4c4b-830a-abfc2daa3bfa) for more details)

View File

@ -0,0 +1,163 @@
# Styling with JS
## Example
```js
const para = new Paragraph("To whom it may concern:").heading2().center();
const name = new TextRun("Name:")
.bold()
.font("Calibri")
.allCaps();
```
## Available methods
* For run formatting:
* `.bold()`, `.italic()`, `.smallCaps()`, `.allCaps()`, `.strike()`, `.doubleStrike()`, `.subScript()`, `.superScript()`: Set the formatting property to true
* `.underline(style="single", color=null)`: Set the underline style and color
* `.color(color)`: Set the text color, using 6 hex characters for RRGGBB (no leading `#`)
* `.size(halfPts)`: Set the font size, measured in half-points
* `.font(name)`: Set the run's font
* `.style(name)`: Apply a named run style
* `.characterSpacing(value)`: Set the character spacing adjustment (in TWIPs)
* For paragraph formatting:
* `.heading1()`, `.heading2()`, `.heading3()`, `.heading4()`, `.heading5()`, `.title()`: apply the appropriate style to the paragraph
* `.left()`, `.center()`, `.right()`, `.justified()`: set the paragraph's alignment
* `.thematicBreak()`, `.pageBreak()`: Insert a thick rule or a page break beneath the paragraph
* `.leftTabStop(position)`: Add a left tab stop (measured in TWIPs from the left)
* `.maxRightTabStop()`: Add a right tab stop at the far right
* `.bullet()`: Use the default bullet style
* `.setNumbering(numbering, indentLevel)`: Use a custom numbering format for the paragraph
* `.style(name)`: Apply a named paragraph style
* `.indent(start, hanging=0)`: Set the paragraph's indent level (in TWIPs)
* `.spacing({before=0, after=0, line=0})`: Set the line and before/after on the paragraph. Before/after is measured in TWIPs, line is measured in 240ths of a line
Paragraph styles have all the run formatting methods, except `style()`, and `.left()`, `.center()`, `.right()`, `.justified()`, `.thematicBreak()`, `.leftTabStop(position)`, `.maxRightTabStop()`, `.indent(start, hanging=0)`, and `.spacing({before=0, after=0, line=0})` methods.
## Detailed guide
There are 4 items in DOCX that can be styled:
* Characters: Attributes that can change within a paragraph. e.g., bold, italics, etc.
* Paragraphs: Attributes like indent, text alignment, line spacing, etc.
* Tables: Border styles, table formats, etc.
* List items: These are the numbers and bullets that are automatically inserted
There are a few different ways of styling this content in DOCX, which somewhat resemble the HTML/CSS approach. In order of greatest to lowest priority:
1. Direct formatting (AKA inline formatting)
2. Centrally defined styles (similar to external CSS)
3. Document defaults (similar to a `*` rule in CSS)
Unlike CSS, less specific rules don't _necessarily_ override parent rules. The rules are a bit wonky, but if you're interested, see the [advanced formatting section](#Advanced formatting).
### Direct formatting (AKA inline formatting)
This is the type of formatting that your uncle uses when he types out documents: _N ... a ... m ... e ... :_ Then he grabs the mouse, highlights _Name:_ and moves over to the **B** for bold. This manner of formatting results in markup that is similar to writing `<span style="bold: true">Name:</span>` if you were typing out HTML. DOCX (the format) allows you to specify this for any of the four types of items. `docx` (the library) only supports this type of formatting for paragraphs and characters, using a _fluent_ api. Thus you could do:
```js
const name = new TextRun("Name:")
.bold()
.font("Calibri")
.allCaps();
```
Or for paragraph formatting:
```js
const para = new Paragraph("To whom it may concern:").heading2().center();
```
### Centrally defined styles (similar to external CSS)
DOCX files contain a styles section separate from the main content, much like how HTML includes CSS files. Unlike CSS, DOCX distinguishes between styles meant for tables (which show up in the table formatting toolbar), styles for lists (which show up under bullets and numbering), and styles for runs and paragraphs, which show up as dropdowns offering standard styles, like "Heading 1", "Caption", or any custom styles defined in that document. <!-- TODO: add pictures of the panes -->. `docx` allows you to define these styles using a fluent interface as well.
There are three parts to using custom styles with `docx`:
1. Create a container object for the style definitions:
```js
const myStyles = new docx.Styles();
```
2. Define your custom styles, similar to the way you would format a paragraph or run
```js
// The first argument is an ID you use to apply the style to paragraphs
// The second argument is a human-friendly name to show in the UI
myStyles
.createParagraphStyle("myWonkyStyle", "My Wonky Style")
.basedOn("Normal")
.next("Normal")
.color("999999")
.italics()
.indent(720) // 720 TWIP === 720 / 20 pt === .5 in
.spacing({ line: 276 }); // 276 / 240 = 1.15x line spacing
myStyles
.createParagraphStyle("Heading2", "Heading 2")
.basedOn("Normal")
.next("Normal")
.quickFormat()
.size(26) // 26 half-points === 13pt font
.bold()
.underline("double", "FF0000")
.spacing({ before: 240, after: 120 }); // TWIP for both
```
3. When you generate your document, make sure to pass the `styles` container to the `Packer`:
```js
const packer = new Packer(doc, myStyles);
packer.pack(myOutStream);
```
**Note**: If you are using the `.headingX` or `.title` methods of paragraphs, you must make sure to define `HeadingX` or `Title` styles for these. Otherwise they'll show up unstyled :(. If you are using the `.bullet` or `.setNumbering` methods, you need to define a `ListParagraph` style or the numbers may not show up.
### Document defaults
Setting document defaults acts like a `*` rule in CSS: it applies to every paragraph and run in the document, but at a low priority level. Other styles affecting this property will override these defaults.
## Advanced formatting
### Style inheritance
Styles may define a `basedOn` attribute that references another style of the same type. In this case, any unspecified properties are inherited from the parent style.
### Interactions between the 4 items
In addition to the 3-layer hierarchy spelled above, there is some interaction between the 4 items that you can style.
For instance numbering styles may also specify some styling for paragraphs (typically indentation and tab stops); paragraphs may specify character formatting (e.g., heading font sizes); etc.
The elements that each style may affect are summarized in the table below. So, e.g., table styles may specify table formatting, paragraph formatting, and character formatting.
| Style type | Table | Paragraph | List item | Characters |
| :---------------- | :---: | :-------: | :-------: | :--------: |
| Document defaults | | X | | X |
| Table | X | X | | X |
| Paragraph | | X | X | X |
| Numbering | | X | X | |
| Character | | | | X |
| Direct formatting | X | X | X | X |
To determine the value of a styling property, you must first identify whether it's a table, paragraph, list item, or character property. E.g., numbering definition is a list item property. Then you need to find the last row in the table for which that property has an "X" and the document has formatting of that type. So if a particular run was in a paragraph whose style specified color as `FF0000`, but it also had a character style specifying color as `00DD00`, then the character style (lower down on the table) would trump, and the character would have color `00DD00`.
### Toggle properties
The following properties are treated in a special manner; they're called toggle properties:
* Bold
* All caps
* Small caps
* Italics
* Single strike-through
* Hidden
* Imprint
* Emboss
* Character outline
* Character shadow
For these properties, the rules state the following conflict resolution in case the property is specified at multiple points for the same item:
* Direct formatting trumps all if specified (either true or false)
* Otherwise, if the property is true in document defaults, the property is set to true
* Otherwise, the property's value is an XOR of its effective table, paragraph, and character values. (So specifying bold `true` on a table style and a paragraph style would result in non-bold text if a paragraph inside the table had that style)

View File

@ -0,0 +1,47 @@
# Styling with XML
## Setup
1. Create a new word document in Microsoft Word
2. Customise the styles on the Ribbon Bar.
For example, modify the `Normal`, `Heading 1`, `Heading 2` like so:
![image](https://user-images.githubusercontent.com/2917613/41195113-65edebfa-6c1f-11e8-97b4-77de2d60044a.png)
![image](https://user-images.githubusercontent.com/2917613/41195126-ca99c36c-6c1f-11e8-9e58-19e5f69b3b87.png)
3. You can even create a totally new `Style`:
![image](https://user-images.githubusercontent.com/2917613/41195135-f0f7862a-6c1f-11e8-8be4-dd6d8fe5be03.png)
![image](https://user-images.githubusercontent.com/2917613/41195139-0ec52130-6c20-11e8-8fae-f6b44b43fdf8.png)
4. Save
5. Re-name the saved `.docx` file to `.zip` and un-zip
6. Find `styles.xml`
![image](https://user-images.githubusercontent.com/2917613/41195178-bb9ba9c4-6c20-11e8-850e-a7a6ada9a2f6.png)
## Usage
Read the styles using `fs`, and put it into the `Document` object in the constructor:
```js
const styles = fs.readFileSync("./styles.xml", "utf-8");
const doc = new docx.Document({
title: "Title",
externalStyles: styles,
});
```
You can use paragraphs, `heading1()`, `heading2()` etc and it will be styled according to your `styles.xml` created earlier. You can even use your new style you made by calling the `style` method:
```js
doc.createParagraph("Cool Heading Text").heading1();
let paragraph = new docx.Paragraph('This is a custom named style from the template "Cool New Style"');
paragraph.style("Cool New Style");
doc.addParagraph(paragraph);
doc.createParagraph("Some normal text");
```
Example: https://github.com/dolanmiu/docx/blob/master/demo/demo13.js

54
docs/usage/tab-stops.md Normal file
View File

@ -0,0 +1,54 @@
# Tab Stops
> Tab stops are useful, if you are unclear of what they are, [here is a link explaining](https://en.wikipedia.org/wiki/Tab_stop). 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.
## 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.addRun(leftText);
paragraph.addRun(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.addRun(text);
```
The above shows the use of two tab stops, and how to select/use it.
## Left Tab Stop
```js
paragraph.leftTabStop(2268);
```
2268 is the distance from the left side.
## Center Tab Stop
```js
paragraph.centerTabStop(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.

View File

@ -0,0 +1,76 @@
# Table of Contents
You can generate table of contents with `docx`. More information can be found [here](http://officeopenxml.com/WPtableOfContents.php).
>Tables of Contents are fields and, by design, it's content is only generated or updated by Word. We can't do it programatically.
>This is why, when you open a the file, Word you will prompt the message "This document contains fields that may refer to other files. Do you want to update the fields in this document?".
>You have say yes to Word generate the content of all table of contents.
The complete documentation can be found [here](https://www.ecma-international.org/publications/standards/Ecma-376.htm) (at Part 1, Page 1251).
## How to
All you need to do is create a `TableOfContents` object and assign it to the document.
```js
const toc = new TableOfContents("Summary", {
hyperlink: true,
headingStyleRange: "1-5",
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)]
});
doc.addTableOfContents(toc);
```
## Table of Contents Options
Here is the list of all options that you can use to generate your tables of contents:
| Option | Type | TOC Field Switch | Description |
| --- | --- | --- | --- |
|captionLabel|string|`\a`|Includes captioned items, but omits caption labels and numbers. The identifier designated by `text` in this switch's field-argument corresponds to the caption label. Use ``\c`` to build a table of captions with labels and numbers.|
|entriesFromBookmark|string|`\b`|Includes entries only from the portion of the document marked by the bookmark named by `text` in this switch's field-argument.|
|captionLabelIncludingNumbers|string|`\c`|Includes figures, tables, charts, and other items that are numbered by a SEQ field (§17.16.5.56). The sequence identifier designated by `text` in this switch's field-argument, which corresponds to the caption label, shall match the identifier in the corresponding SEQ field.|
|sequenceAndPageNumbersSeparator|string|`\d`|When used with `\s`, the `text` in this switch's field-argument defines the separator between sequence and page numbers. The default separator is a hyphen (-).|
|tcFieldIdentifier|string|`\f`|Includes only those TC fields whose identifier exactly matches the `text` in this switch's field-argument (which is typically a letter).|
|hyperlink|boolean|`\h`|Makes the table of contents entries hyperlinks.|
|tcFieldLevelRange|string|`\l`|Includes TC fields that assign entries to one of the levels specified by `text` in this switch's field-argument as a range having the form startLevel-endLevel, where startLevel and endLevel are integers, and startLevel has a value equal-to or less-than endLevel. TC fields that assign entries to lower levels are skipped.|
|pageNumbersEntryLevelsRange|string|`\n`|Without field-argument, omits page numbers from the table of contents. Page numbers are omitted from all levels unless a range of entry levels is specified by `text` in this switch's field-argument. A range is specified as for `\l`.|
|headingStyleRange|string|`\o`|Uses paragraphs formatted with all or the specified range of builtin heading styles. Headings in a style range are specified by `text` in this switch's field-argument using the notation specified as for `\l`, where each integer corresponds to the style with a style ID of HeadingX (e.g. 1 corresponds to Heading1). If no heading range is specified, all heading levels used in the document are listed.|
|entryAndPageNumberSeparator|string|`\p`|`text` in this switch's field-argument specifies a sequence of characters that separate an entry and its page number. The default is a tab with leader dots.|
|seqFieldIdentifierForPrefix|string|`\s`|For entries numbered with a SEQ field (§17.16.5.56), adds a prefix to the page number. The prefix depends on the type of entry. `text` in this switch's field-argument shall match the identifier in the SEQ field.|
|stylesWithLevels|StyleLevel[]|`\t`| Uses paragraphs formatted with styles other than the built-in heading styles. `text` in this switch's field-argument specifies those styles as a set of comma-separated doublets, with each doublet being a comma-separated set of style name and table of content level. `\t` can be combined with `\o`.|
|useAppliedParagraphOutlineLevel|boolean|`\u`|Uses the applied paragraph outline level.|
|preserveTabInEntries|boolean|`\w`|Preserves tab entries within table entries.|
|preserveNewLineInEntries|boolean|`\x`|Preserves newline characters within table entries.|
|hideTabAndPageNumbersInWebView|boolean|`\z`|Hides tab leader and page numbers in web page view (§17.18.102).|
## Examples
```js
// Let's define the options for generate a TOC for heading 1-5 and MySpectacularStyle,
// making the entries be hyperlinks for the paragraph
const toc = new TableOfContents("Summary", {
hyperlink: true,
headingStyleRange: "1-5",
stylesWithLevels: [new StyleLevel("MySpectacularStyle", 1)]
});
doc.addTableOfContents(toc);
doc.addParagraph(new Paragraph("Header #1").heading1().pageBreakBefore());
doc.addParagraph(new Paragraph("I'm a little text, very nicely written.'"));
doc.addParagraph(new Paragraph("Header #2").heading1().pageBreakBefore());
doc.addParagraph(new Paragraph("I'm another text very nicely written.'"));
doc.addParagraph(new Paragraph("Header #2.1").heading2());
doc.addParagraph(new Paragraph("I'm another text very nicely written.'"));
doc.addParagraph(new Paragraph("My Spectacular Style #1").style("MySpectacularStyle").pageBreakBefore());
```
### Complete example
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo28.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo28.ts_

84
docs/usage/text.md Normal file
View File

@ -0,0 +1,84 @@
# Text
Paragraphs need `text run` objects. To create text:
```js
var text = new docx.TextRun("My awesome text here for my university dissertation");
paragraph.addRun(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();
```

BIN
logo/logo-small.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
logo/logo-small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
logo/logo-small.psd Normal file

Binary file not shown.

BIN
logo/logo.psd Normal file

Binary file not shown.

View File

@ -1,6 +1,6 @@
{
"name": "docx",
"version": "3.6.0",
"version": "4.3.0",
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
"main": "build/index.js",
"scripts": {
@ -12,12 +12,18 @@
"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\"",
"build.web": "webpack --config webpack.web.config.js",
"demo": "npm run build && npm run ts-node ./demo",
"typedoc": "typedoc src/index.ts",
"style": "prettier -l \"src/**/*.ts\"",
"style.fix": "prettier \"src/**/*.ts\" --write",
"fix-types": "node types-absolute-fixer.js"
"fix-types": "node types-absolute-fixer.js",
"ts-node": "ts-node"
},
"pre-commit": [
"style",
"lint"
],
"files": [
"src",
"build",
@ -41,15 +47,11 @@
],
"types": "./build/index.d.ts",
"dependencies": {
"@types/archiver": "^2.1.0",
"@types/express": "^4.0.35",
"@types/image-size": "0.0.29",
"@types/request-promise": "^4.1.41",
"archiver": "^2.1.1",
"@types/jszip": "^3.1.3",
"fast-xml-parser": "^3.3.6",
"image-size": "^0.6.2",
"request": "^2.83.0",
"request-promise": "^4.2.2",
"jszip": "^3.1.5",
"xml": "^1.0.1"
},
"author": "Dolan Miu",
@ -65,17 +67,23 @@
"awesome-typescript-loader": "^3.4.1",
"chai": "^3.5.0",
"glob": "^7.1.2",
"mocha": "^3.2.0",
"jszip": "^3.1.5",
"mocha": "^5.2.0",
"mocha-webpack": "^1.0.1",
"pre-commit": "^1.2.2",
"prettier": "^1.12.1",
"prompt": "^1.0.0",
"replace-in-file": "^3.1.0",
"rimraf": "^2.5.2",
"shelljs": "^0.7.7",
"sinon": "^5.0.7",
"tslint": "^5.1.0",
"typedoc": "^0.9.0",
"typescript": "2.6.2",
"ts-node": "^7.0.1",
"tslint": "^5.11.0",
"typedoc": "^0.11.1",
"typescript": "2.9.2",
"webpack": "^3.10.0"
},
"engines": {
"node": ">=8"
}
}

View File

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

View File

@ -1,110 +0,0 @@
import * as archiver from "archiver";
import * as express from "express";
import { Writable } from "stream";
import * as xml from "xml";
import { File } from "file";
import { Formatter } from "../formatter";
export class Compiler {
protected archive: archiver.Archiver;
private formatter: Formatter;
constructor(private file: File) {
this.formatter = new Formatter();
this.archive = archiver.create("zip", {});
this.archive.on("error", (err) => {
throw err;
});
}
public async compile(output: Writable | express.Response): Promise<void> {
this.archive.pipe(output);
const xmlDocument = xml(this.formatter.format(this.file.Document), true);
const xmlStyles = xml(this.formatter.format(this.file.Styles));
const xmlProperties = xml(this.formatter.format(this.file.CoreProperties), {
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
});
const xmlNumbering = xml(this.formatter.format(this.file.Numbering));
const xmlRelationships = xml(this.formatter.format(this.file.DocumentRelationships));
const xmlFileRelationships = xml(this.formatter.format(this.file.FileRelationships));
const xmlHeader = xml(this.formatter.format(this.file.Header.Header));
const xmlHeader2 = xml(this.formatter.format(this.file.firstPageHeader.Header));
const xmlFooter = xml(this.formatter.format(this.file.Footer.Footer));
const xmlHeaderRelationships = xml(this.formatter.format(this.file.Header.Relationships));
const xmlFooterRelationships = xml(this.formatter.format(this.file.Footer.Relationships));
const xmlContentTypes = xml(this.formatter.format(this.file.ContentTypes));
const xmlAppProperties = xml(this.formatter.format(this.file.AppProperties));
this.archive.append(xmlDocument, {
name: "word/document.xml",
});
this.archive.append(xmlStyles, {
name: "word/styles.xml",
});
this.archive.append(xmlProperties, {
name: "docProps/core.xml",
});
this.archive.append(xmlAppProperties, {
name: "docProps/app.xml",
});
this.archive.append(xmlNumbering, {
name: "word/numbering.xml",
});
this.archive.append(xmlHeader, {
name: "word/header1.xml",
});
this.archive.append(xmlHeader2, {
name: "word/header2.xml",
});
this.archive.append(xmlFooter, {
name: "word/footer1.xml",
});
this.archive.append(xmlRelationships, {
name: "word/_rels/document.xml.rels",
});
this.archive.append(xmlHeaderRelationships, {
name: "word/_rels/header1.xml.rels",
});
this.archive.append(xmlFooterRelationships, {
name: "word/_rels/footer1.xml.rels",
});
this.archive.append(xmlContentTypes, {
name: "[Content_Types].xml",
});
this.archive.append(xmlFileRelationships, {
name: "_rels/.rels",
});
for (const data of this.file.Media.array) {
this.archive.append(data.stream, {
name: `word/media/${data.fileName}`,
});
}
this.archive.finalize();
return new Promise<void>((resolve) => {
output.on("close", () => {
resolve();
});
});
}
}

View File

@ -1,29 +0,0 @@
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

@ -1,66 +0,0 @@
/* tslint:disable:typedef space-before-function-paren */
import { assert } from "chai";
import * as fs from "fs";
import { stub } from "sinon";
import { LocalPacker } from "../../export/packer/local";
import { File, Paragraph } from "../../file";
describe("LocalPacker", () => {
let packer: LocalPacker;
beforeEach(() => {
const file = new File({
creator: "Dolan Miu",
revision: "1",
lastModifiedBy: "Dolan Miu",
});
const paragraph = new Paragraph("test text");
const heading = new Paragraph("Hello world").heading1();
file.addParagraph(new Paragraph("title").title());
file.addParagraph(heading);
file.addParagraph(new Paragraph("heading 2").heading2());
file.addParagraph(paragraph);
packer = new LocalPacker(file);
});
describe("#pack()", () => {
it("should create a standard docx file", async function() {
this.timeout(99999999);
await packer.pack("build/tests/test");
fs.statSync("build/tests/test.docx");
});
it("should handle exception if it throws any", () => {
// tslint:disable-next-line:no-any
const compiler = stub((packer as any).packer, "compile");
compiler.throwsException();
return packer.pack("build/tests/test").catch((error) => {
assert.isDefined(error);
});
});
});
describe("#packPdf", () => {
it("should create a standard PDF file", async function() {
this.timeout(99999999);
// tslint:disable-next-line:no-any
const pdfConverterConvert = stub((packer as any).pdfConverter, "convert");
pdfConverterConvert.returns("Test PDF Contents");
await packer.packPdf("build/tests/pdf-test");
fs.statSync("build/tests/pdf-test.pdf");
});
it("should handle exception if it throws any", () => {
// tslint:disable-next-line:no-any
const compiler = stub((packer as any).packer, "compile");
compiler.throwsException();
return packer.packPdf("build/tests/pdf-test").catch((error) => {
assert.isDefined(error);
});
});
});
});

View File

@ -1,47 +0,0 @@
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,67 @@
/* tslint:disable:typedef space-before-function-paren */
import { expect } from "chai";
import { File } from "../../file";
import { Compiler } from "./next-compiler";
describe("Compiler", () => {
let compiler: Compiler;
let file: File;
beforeEach(() => {
file = new File();
compiler = new Compiler();
});
describe("#compile()", () => {
it("should pack all the content", async function() {
this.timeout(99999999);
const zipFile = await compiler.compile(file);
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(18);
expect(fileNames).to.include("word/document.xml");
expect(fileNames).to.include("word/styles.xml");
expect(fileNames).to.include("docProps/core.xml");
expect(fileNames).to.include("docProps/app.xml");
expect(fileNames).to.include("word/numbering.xml");
expect(fileNames).to.include("word/header1.xml");
expect(fileNames).to.include("word/_rels/header1.xml.rels");
expect(fileNames).to.include("word/footer1.xml");
expect(fileNames).to.include("word/footnotes.xml");
expect(fileNames).to.include("word/settings.xml");
expect(fileNames).to.include("word/_rels/footer1.xml.rels");
expect(fileNames).to.include("word/_rels/document.xml.rels");
expect(fileNames).to.include("[Content_Types].xml");
expect(fileNames).to.include("_rels/.rels");
});
it("should pack all additional headers and footers", async function() {
file.createFooter();
file.createFooter();
file.createHeader();
file.createHeader();
this.timeout(99999999);
const zipFile = await compiler.compile(file);
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(26);
expect(fileNames).to.include("word/header1.xml");
expect(fileNames).to.include("word/_rels/header1.xml.rels");
expect(fileNames).to.include("word/header2.xml");
expect(fileNames).to.include("word/_rels/header2.xml.rels");
expect(fileNames).to.include("word/header3.xml");
expect(fileNames).to.include("word/_rels/header3.xml.rels");
expect(fileNames).to.include("word/footer1.xml");
expect(fileNames).to.include("word/_rels/footer1.xml.rels");
expect(fileNames).to.include("word/footer2.xml");
expect(fileNames).to.include("word/_rels/footer2.xml.rels");
expect(fileNames).to.include("word/footer3.xml");
expect(fileNames).to.include("word/_rels/footer3.xml.rels");
});
});
});

View File

@ -0,0 +1,131 @@
import * as JSZip from "jszip";
import * as xml from "xml";
import { File } from "file";
import { Formatter } from "../formatter";
interface IXmlifyedFile {
data: string;
path: string;
}
interface IXmlifyedFileMapping {
Document: IXmlifyedFile;
Styles: IXmlifyedFile;
Properties: IXmlifyedFile;
Numbering: IXmlifyedFile;
Relationships: IXmlifyedFile;
FileRelationships: IXmlifyedFile;
Headers: IXmlifyedFile[];
Footers: IXmlifyedFile[];
HeaderRelationships: IXmlifyedFile[];
FooterRelationships: IXmlifyedFile[];
ContentTypes: IXmlifyedFile;
AppProperties: IXmlifyedFile;
FootNotes: IXmlifyedFile;
Settings: IXmlifyedFile;
}
export class Compiler {
private readonly formatter: Formatter;
constructor() {
this.formatter = new Formatter();
}
public async compile(file: File): Promise<JSZip> {
const zip = new JSZip();
const xmlifiedFileMapping = this.xmlifyFile(file);
for (const key in xmlifiedFileMapping) {
if (!xmlifiedFileMapping[key]) {
continue;
}
const obj = xmlifiedFileMapping[key] as IXmlifyedFile | IXmlifyedFile[];
if (Array.isArray(obj)) {
for (const subFile of obj) {
zip.file(subFile.path, subFile.data);
}
} else {
zip.file(obj.path, obj.data);
}
}
for (const data of file.Media.Array) {
const mediaData = data.stream;
zip.file(`word/media/${data.fileName}`, mediaData);
}
return zip;
}
private xmlifyFile(file: File): IXmlifyedFileMapping {
file.verifyUpdateFields();
return {
Document: {
data: xml(this.formatter.format(file.Document), true),
path: "word/document.xml",
},
Styles: {
data: xml(this.formatter.format(file.Styles)),
path: "word/styles.xml",
},
Properties: {
data: xml(this.formatter.format(file.CoreProperties), {
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
}),
path: "docProps/core.xml",
},
Numbering: {
data: xml(this.formatter.format(file.Numbering)),
path: "word/numbering.xml",
},
Relationships: {
data: xml(this.formatter.format(file.DocumentRelationships)),
path: "word/_rels/document.xml.rels",
},
FileRelationships: {
data: xml(this.formatter.format(file.FileRelationships)),
path: "_rels/.rels",
},
Headers: file.Headers.map((headerWrapper, index) => ({
data: xml(this.formatter.format(headerWrapper.Header)),
path: `word/header${index + 1}.xml`,
})),
Footers: file.Footers.map((footerWrapper, index) => ({
data: xml(this.formatter.format(footerWrapper.Footer)),
path: `word/footer${index + 1}.xml`,
})),
HeaderRelationships: file.Headers.map((headerWrapper, index) => ({
data: xml(this.formatter.format(headerWrapper.Relationships)),
path: `word/_rels/header${index + 1}.xml.rels`,
})),
FooterRelationships: file.Footers.map((footerWrapper, index) => ({
data: xml(this.formatter.format(footerWrapper.Relationships)),
path: `word/_rels/footer${index + 1}.xml.rels`,
})),
ContentTypes: {
data: xml(this.formatter.format(file.ContentTypes)),
path: "[Content_Types].xml",
},
AppProperties: {
data: xml(this.formatter.format(file.AppProperties)),
path: "docProps/app.xml",
},
FootNotes: {
data: xml(this.formatter.format(file.FootNotes)),
path: "word/footnotes.xml",
},
Settings: {
data: xml(this.formatter.format(file.Settings)),
path: "word/settings.xml",
},
};
}
}

View File

@ -1,41 +1,46 @@
// tslint:disable:typedef space-before-function-paren
// tslint:disable:no-empty
// tslint:disable:no-any
/* tslint:disable:typedef space-before-function-paren */
import { assert } from "chai";
import { stub } from "sinon";
import { ExpressPacker } from "../../export/packer/express";
import { File, Paragraph } from "../../file";
import { Packer } from "./packer";
describe("LocalPacker", () => {
let packer: ExpressPacker;
describe("Packer", () => {
let packer: Packer;
let file: File;
beforeEach(() => {
const file = new File({
file = new File({
creator: "Dolan Miu",
revision: "1",
lastModifiedBy: "Dolan Miu",
});
const paragraph = new Paragraph("test text");
const heading = new Paragraph("Hello world").heading1();
file.addParagraph(new Paragraph("title").title());
file.addParagraph(heading);
file.addParagraph(new Paragraph("heading 2").heading2());
file.addParagraph(paragraph);
const expressResMock = {
on: () => {},
attachment: () => {},
};
packer = new ExpressPacker(file, expressResMock as any);
packer = new Packer();
});
describe("#pack()", () => {
describe("#toBuffer()", () => {
it("should create a standard docx file", async function() {
this.timeout(99999999);
const buffer = await packer.toBuffer(file);
assert.isDefined(buffer);
assert.isTrue(buffer.byteLength > 0);
});
it("should handle exception if it throws any", () => {
const compiler = stub((packer as any).packer, "compile");
// tslint:disable-next-line:no-any
const compiler = stub((packer as any).compiler, "compile");
compiler.throwsException();
return packer.pack("build/tests/test").catch((error) => {
return packer.toBuffer(file).catch((error) => {
assert.isDefined(error);
});
});

View File

@ -1,6 +1,31 @@
export interface IPacker {
pack(path: string): void;
}
import { File } from "file";
import { Compiler } from "./next-compiler";
// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432
export const WORKAROUND = "";
export class Packer {
private readonly compiler: Compiler;
constructor() {
this.compiler = new Compiler();
}
public async toBuffer(file: File): Promise<Buffer> {
const zip = await this.compiler.compile(file);
const zipData = (await zip.generateAsync({ type: "nodebuffer" })) as Buffer;
return zipData;
}
public async toBase64String(file: File): Promise<string> {
const zip = await this.compiler.compile(file);
const zipData = (await zip.generateAsync({ type: "base64" })) as string;
return zipData;
}
public async toBlob(file: File): Promise<Blob> {
const zip = await this.compiler.compile(file);
const zipData = (await zip.generateAsync({ type: "blob" })) as Blob;
return zipData;
}
}

View File

@ -1,35 +0,0 @@
/* 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

@ -1,25 +0,0 @@
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,142 @@
// tslint:disable:no-string-literal
import { expect } from "chai";
import { Formatter } from "../../export/formatter";
import { ContentTypes } from "./content-types";
describe("ContentTypes", () => {
let contentTypes: ContentTypes;
beforeEach(() => {
contentTypes = new ContentTypes();
});
describe("#constructor()", () => {
it("should create default content types", () => {
const tree = new Formatter().format(contentTypes);
expect(tree["Types"]).to.be.an.instanceof(Array);
expect(tree["Types"][0]).to.deep.equal({ _attr: { xmlns: "http://schemas.openxmlformats.org/package/2006/content-types" } });
expect(tree["Types"][1]).to.deep.equal({ Default: [{ _attr: { ContentType: "image/png", Extension: "png" } }] });
expect(tree["Types"][2]).to.deep.equal({ Default: [{ _attr: { ContentType: "image/jpeg", Extension: "jpeg" } }] });
expect(tree["Types"][3]).to.deep.equal({ Default: [{ _attr: { ContentType: "image/jpeg", Extension: "jpg" } }] });
expect(tree["Types"][4]).to.deep.equal({ Default: [{ _attr: { ContentType: "image/bmp", Extension: "bmp" } }] });
expect(tree["Types"][5]).to.deep.equal({ Default: [{ _attr: { ContentType: "image/gif", Extension: "gif" } }] });
expect(tree["Types"][6]).to.deep.equal({
Default: [{ _attr: { ContentType: "application/vnd.openxmlformats-package.relationships+xml", Extension: "rels" } }],
});
expect(tree["Types"][7]).to.deep.equal({ Default: [{ _attr: { ContentType: "application/xml", Extension: "xml" } }] });
expect(tree["Types"][8]).to.deep.equal({
Override: [
{
_attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
PartName: "/word/document.xml",
},
},
],
});
expect(tree["Types"][9]).to.deep.equal({
Override: [
{
_attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml",
PartName: "/word/styles.xml",
},
},
],
});
expect(tree["Types"][10]).to.deep.equal({
Override: [
{
_attr: {
ContentType: "application/vnd.openxmlformats-package.core-properties+xml",
PartName: "/docProps/core.xml",
},
},
],
});
expect(tree["Types"][11]).to.deep.equal({
Override: [
{
_attr: {
ContentType: "application/vnd.openxmlformats-officedocument.extended-properties+xml",
PartName: "/docProps/app.xml",
},
},
],
});
expect(tree["Types"][12]).to.deep.equal({
Override: [
{
_attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml",
PartName: "/word/numbering.xml",
},
},
],
});
});
});
describe("#addFooter()", () => {
it("should add footer", () => {
contentTypes.addFooter(101);
contentTypes.addFooter(102);
const tree = new Formatter().format(contentTypes);
expect(tree["Types"][14]).to.deep.equal({
Override: [
{
_attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
PartName: "/word/footer101.xml",
},
},
],
});
expect(tree["Types"][15]).to.deep.equal({
Override: [
{
_attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
PartName: "/word/footer102.xml",
},
},
],
});
});
});
describe("#addHeader()", () => {
it("should add header", () => {
contentTypes.addHeader(201);
contentTypes.addHeader(202);
const tree = new Formatter().format(contentTypes);
expect(tree["Types"][14]).to.deep.equal({
Override: [
{
_attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
PartName: "/word/header201.xml",
},
},
],
});
expect(tree["Types"][15]).to.deep.equal({
Override: [
{
_attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
PartName: "/word/header202.xml",
},
},
],
});
});
});
});

View File

@ -25,12 +25,22 @@ export class ContentTypes extends XmlComponent {
new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", "/word/document.xml"),
);
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", "/word/header1.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", "/word/header2.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", "/word/footer1.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", "/word/styles.xml"));
this.root.push(new Override("application/vnd.openxmlformats-package.core-properties+xml", "/docProps/core.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.extended-properties+xml", "/docProps/app.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", "/word/numbering.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml", "/word/footnotes.xml"));
}
public addFooter(index: number): void {
this.root.push(
new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", `/word/footer${index}.xml`),
);
}
public addHeader(index: number): void {
this.root.push(
new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", `/word/header${index}.xml`),
);
}
}

View File

@ -1,39 +1,42 @@
// import { assert } from "chai";
import { expect } from "chai";
// import { Utility } from "../../../tests/utility";
// import { Body } from "./";
import { Formatter } from "../../../export/formatter";
import { Body } from "./body";
describe("Body", () => {
// let body: Body;
let body: Body;
beforeEach(() => {
// body = new Body();
body = new Body();
});
// describe("#constructor()", () => {
// it("should create the Section Properties", () => {
// const newJson = Utility.jsonify(body);
// assert.equal(newJson.root[0].rootKey, "w:sectPr");
// });
describe("#constructor()", () => {
it("should create default section", () => {
const formatted = new Formatter().format(body)["w:body"][0];
expect(formatted)
.to.have.property("w:sectPr")
.and.to.be.an.instanceof(Array);
expect(formatted["w:sectPr"]).to.have.length(7);
});
});
// it("should create the Page Size", () => {
// const newJson = Utility.jsonify(body);
// assert.equal(newJson.root[1].rootKey, "w:pgSz");
// });
describe("addSection", () => {
it("should add section with options", () => {
body.addSection({
width: 10000,
height: 10000,
});
// it("should create the Page Margin", () => {
// const newJson = Utility.jsonify(body);
// assert.equal(newJson.root[2].rootKey, "w:pgMar");
// });
const formatted = new Formatter().format(body)["w:body"];
expect(formatted).to.be.an.instanceof(Array);
const defaultSectionPr = formatted[0]["w:p"][1]["w:pPr"][0]["w:sectPr"];
// it("should create the Columns", () => {
// const newJson = Utility.jsonify(body);
// assert.equal(newJson.root[3].rootKey, "w:cols");
// });
// check that this is the default section and added first in paragraph
expect(defaultSectionPr[0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } }] });
// it("should create the Document Grid", () => {
// const newJson = Utility.jsonify(body);
// assert.equal(newJson.root[4].rootKey, "w:docGrid");
// });
// });
// check for new section (since it's the last one, it's direct child of body)
const newSection = formatted[1]["w:sectPr"];
expect(newSection[0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 10000, "w:w": 10000, "w:orient": "portrait" } }] });
});
});
});

View File

@ -1,14 +1,71 @@
import { XmlComponent } from "file/xml-components";
import { IXmlableObject, XmlComponent } from "file/xml-components";
import { Paragraph, ParagraphProperties, TableOfContents } from "../..";
import { SectionProperties, SectionPropertiesOptions } from "./section-properties/section-properties";
export class Body extends XmlComponent {
private readonly defaultSection: SectionProperties;
private readonly sections: SectionProperties[] = [];
constructor(sectionPropertiesOptions?: SectionPropertiesOptions) {
super("w:body");
this.root.push(new SectionProperties(sectionPropertiesOptions));
this.defaultSection = new SectionProperties(sectionPropertiesOptions);
this.sections.push(this.defaultSection);
}
/**
* Adds new section properties.
* Note: Previous section is created in paragraph after the current element, and then new section will be added.
* The spec says:
* - section element should be in the last paragraph of the section
* - last section should be direct child of body
* @param section new section
*/
public addSection(section: SectionPropertiesOptions | SectionProperties): void {
const currentSection = this.sections.pop() as SectionProperties;
this.root.push(this.createSectionParagraph(currentSection));
if (section instanceof SectionProperties) {
this.sections.push(section);
} else {
const params = {
...this.defaultSection.Options,
...section,
};
this.sections.push(new SectionProperties(params));
}
}
public prepForXml(): IXmlableObject {
if (this.sections.length === 1) {
this.root.push(this.sections[0]);
} else if (this.sections.length > 1) {
throw new Error("Invalid usage of sections. At the end of the body element there must be ONE section.");
}
return super.prepForXml();
}
public push(component: XmlComponent): void {
this.root.push(component);
}
public get DefaultSection(): SectionProperties {
return this.defaultSection;
}
public getTablesOfContents(): TableOfContents[] {
return this.root.filter((child) => child instanceof TableOfContents) as TableOfContents[];
}
public getParagraphs(): Paragraph[] {
return this.root.filter((child) => child instanceof Paragraph) as Paragraph[];
}
private createSectionParagraph(section: SectionProperties): Paragraph {
const paragraph = new Paragraph();
const properties = new ParagraphProperties();
properties.addChildElement(section);
paragraph.addChildElement(properties);
return paragraph;
}
}

View File

@ -1 +1,2 @@
export * from "./body";
export * from "./section-properties";

View File

@ -1,5 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components";
export enum FooterReferenceType {
DEFAULT = "default",
FIRST = "first",
EVEN = "even",
}
export interface IFooterReferenceAttributes {
type: string;
id: string;

View File

@ -1,13 +1,19 @@
import { XmlComponent } from "file/xml-components";
import { FooterReferenceAttributes } from "./footer-reference-attributes";
import { FooterReferenceAttributes, FooterReferenceType } from "./footer-reference-attributes";
export interface IFooterOptions {
footerType?: FooterReferenceType;
footerId?: number;
}
export class FooterReference extends XmlComponent {
constructor() {
constructor(options: IFooterOptions) {
super("w:footerReference");
this.root.push(
new FooterReferenceAttributes({
type: "default",
id: `rId${4}`,
type: options.footerType || FooterReferenceType.DEFAULT,
id: `rId${options.footerId}`,
}),
);
}

View File

@ -0,0 +1,2 @@
export * from "./footer-reference";
export * from "./footer-reference-attributes";

View File

@ -1,5 +1,11 @@
import { XmlAttributeComponent } from "file/xml-components";
export enum HeaderReferenceType {
DEFAULT = "default",
FIRST = "first",
EVEN = "even",
}
export interface IHeaderReferenceAttributes {
type: string;
id: string;

View File

@ -1,13 +1,18 @@
import { XmlComponent } from "file/xml-components";
import { HeaderReferenceAttributes } from "./header-reference-attributes";
import { HeaderReferenceAttributes, HeaderReferenceType } from "./header-reference-attributes";
export interface IHeaderOptions {
headerType?: HeaderReferenceType;
headerId?: number;
}
export class HeaderReference extends XmlComponent {
constructor(order: string, refID: number) {
constructor(options: IHeaderOptions) {
super("w:headerReference");
this.root.push(
new HeaderReferenceAttributes({
type: order,
id: `rId${refID}`,
type: options.headerType || HeaderReferenceType.DEFAULT,
id: `rId${options.headerId}`,
}),
);
}

View File

@ -0,0 +1,2 @@
export * from "./header-reference";
export * from "./header-reference-attributes";

View File

@ -0,0 +1,6 @@
export * from "./section-properties";
export * from "./footer-reference";
export * from "./header-reference";
export * from "./page-size";
export * from "./page-number";
export * from "./page-border";

View File

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

View File

@ -0,0 +1,91 @@
import { expect } from "chai";
import { Formatter } from "../../../../../export/formatter";
import { BorderStyle } from "../../../../styles";
import { PageBorderDisplay, PageBorders, PageBorderZOrder } from "./page-borders";
describe("PageBorders", () => {
describe("#constructor()", () => {
it("should create empty element when no options are passed", () => {
const properties = new PageBorders();
const tree = new Formatter().format(properties);
expect(tree).to.equal("");
});
it("should create page borders with some configuration", () => {
const properties = new PageBorders({
pageBorders: {
display: PageBorderDisplay.FIRST_PAGE,
},
});
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:pgBorders"]);
expect(tree["w:pgBorders"]).to.be.an.instanceof(Array);
expect(tree["w:pgBorders"][0]).to.deep.equal({ _attr: { "w:display": "firstPage" } });
});
it("should create page borders with full configuration", () => {
const properties = new PageBorders({
pageBorders: {
display: PageBorderDisplay.FIRST_PAGE,
zOrder: PageBorderZOrder.BACK,
},
pageBorderTop: {
style: BorderStyle.DOUBLE_WAVE,
size: 10,
color: "001122",
},
pageBorderRight: {
style: BorderStyle.DOUBLE,
size: 20,
color: "223344",
},
pageBorderBottom: {
style: BorderStyle.SINGLE,
size: 30,
color: "556677",
},
pageBorderLeft: {
style: BorderStyle.DOTTED,
size: 40,
color: "889900",
},
});
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:pgBorders"]);
expect(tree["w:pgBorders"]).to.be.an.instanceof(Array);
expect(tree["w:pgBorders"][0]).to.deep.equal({ _attr: { "w:display": "firstPage", "w:zOrder": "back" } });
expect(tree["w:pgBorders"][1]).to.deep.equal({
"w:top": [
{
_attr: { "w:color": "001122", "w:size": 10, "w:val": "doubleWave" },
},
],
});
expect(tree["w:pgBorders"][2]).to.deep.equal({
"w:right": [
{
_attr: { "w:color": "223344", "w:size": 20, "w:val": "double" },
},
],
});
expect(tree["w:pgBorders"][3]).to.deep.equal({
"w:bottom": [
{
_attr: { "w:color": "556677", "w:size": 30, "w:val": "single" },
},
],
});
expect(tree["w:pgBorders"][4]).to.deep.equal({
"w:left": [
{
_attr: { "w:color": "889900", "w:size": 40, "w:val": "dotted" },
},
],
});
});
});
});

View File

@ -0,0 +1,104 @@
// http://officeopenxml.com/WPsectionBorders.php
import { IXmlableObject, XmlAttributeComponent, XmlComponent } from "file/xml-components";
import { BorderStyle } from "../../../../styles";
export enum PageBorderDisplay {
ALL_PAGES = "allPages",
FIRST_PAGE = "firstPage",
NOT_FIRST_PAGE = "notFirstPage",
}
export enum PageBorderOffsetFrom {
PAGE = "page",
TEXT = "text",
}
export enum PageBorderZOrder {
BACK = "back",
FRONT = "front",
}
export interface IPageBorderAttributes {
display?: PageBorderDisplay;
offsetFrom?: PageBorderOffsetFrom;
zOrder?: PageBorderZOrder;
}
export interface IPageBorderConfiguration {
style?: BorderStyle;
size?: number;
color?: string;
space?: number;
}
export interface IPageBordersOptions {
pageBorders?: IPageBorderAttributes;
pageBorderTop?: IPageBorderConfiguration;
pageBorderRight?: IPageBorderConfiguration;
pageBorderBottom?: IPageBorderConfiguration;
pageBorderLeft?: IPageBorderConfiguration;
}
class PageBordeAttributes extends XmlAttributeComponent<IPageBorderConfiguration> {
protected xmlKeys = {
style: "w:val",
size: "w:size",
color: "w:color",
space: "w:space",
};
}
class PageBorder extends XmlComponent {
constructor(key: string, options: IPageBorderConfiguration) {
super(key);
this.root.push(new PageBordeAttributes(options));
}
}
class PageBordersAttributes extends XmlAttributeComponent<IPageBorderAttributes> {
protected xmlKeys = {
display: "w:display",
offsetFrom: "w:offsetFrom",
zOrder: "w:zOrder",
};
}
export class PageBorders extends XmlComponent {
constructor(options?: IPageBordersOptions) {
super("w:pgBorders");
if (!options) {
return;
}
let pageBordersAttributes = {};
if (options.pageBorders) {
pageBordersAttributes = {
display: options.pageBorders.display,
offsetFrom: options.pageBorders.offsetFrom,
zOrder: options.pageBorders.zOrder,
};
}
this.root.push(new PageBordersAttributes(pageBordersAttributes));
if (options.pageBorderTop) {
this.root.push(new PageBorder("w:top", options.pageBorderTop));
}
if (options.pageBorderRight) {
this.root.push(new PageBorder("w:right", options.pageBorderRight));
}
if (options.pageBorderBottom) {
this.root.push(new PageBorder("w:bottom", options.pageBorderBottom));
}
if (options.pageBorderLeft) {
this.root.push(new PageBorder("w:left", options.pageBorderLeft));
}
}
public prepForXml(): IXmlableObject {
return this.root.length > 0 ? super.prepForXml() : "";
}
}

View File

@ -8,6 +8,7 @@ export interface IPageMarginAttributes {
header?: number;
footer?: number;
gutter?: number;
mirror?: boolean;
}
export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttributes> {
@ -19,5 +20,6 @@ export class PageMarginAttributes extends XmlAttributeComponent<IPageMarginAttri
header: "w:header",
footer: "w:footer",
gutter: "w:gutter",
mirror: "w:mirrorMargins",
};
}

View File

@ -2,7 +2,7 @@ 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) {
constructor(top: number, right: number, bottom: number, left: number, header: number, footer: number, gutter: number, mirror: boolean) {
super("w:pgMar");
this.root.push(
new PageMarginAttributes({
@ -13,6 +13,7 @@ export class PageMargin extends XmlComponent {
header: header,
footer: footer,
gutter: gutter,
mirror: mirror,
}),
);
}

View File

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

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