├── .nvmrc ├── src ├── export │ ├── index.ts │ ├── formatter.ts │ └── packer │ │ ├── packer.ts │ │ └── packer.spec.ts ├── file │ ├── footer │ │ ├── index.ts │ │ └── footer-attributes.ts │ ├── header │ │ ├── index.ts │ │ └── header-attributes.ts │ ├── drawing │ │ ├── inline │ │ │ ├── index.ts │ │ │ ├── graphic │ │ │ │ ├── index.ts │ │ │ │ ├── graphic-data │ │ │ │ │ ├── pic │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── shape-properties │ │ │ │ │ │ │ ├── form │ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ │ ├── offset │ │ │ │ │ │ │ │ │ ├── off-attributes.ts │ │ │ │ │ │ │ │ │ └── off.ts │ │ │ │ │ │ │ │ ├── extents │ │ │ │ │ │ │ │ │ ├── extents-attributes.ts │ │ │ │ │ │ │ │ │ └── extents.ts │ │ │ │ │ │ │ │ └── form.ts │ │ │ │ │ │ │ ├── no-fill.ts │ │ │ │ │ │ │ ├── outline │ │ │ │ │ │ │ │ ├── no-fill.ts │ │ │ │ │ │ │ │ └── outline.ts │ │ │ │ │ │ │ ├── preset-geometry │ │ │ │ │ │ │ │ ├── adjustment-values │ │ │ │ │ │ │ │ │ └── adjustment-values.ts │ │ │ │ │ │ │ │ ├── preset-geometry-attributes.ts │ │ │ │ │ │ │ │ └── preset-geometry.ts │ │ │ │ │ │ │ ├── shape-properties-attributes.ts │ │ │ │ │ │ │ └── shape-properties.ts │ │ │ │ │ │ ├── blip │ │ │ │ │ │ │ ├── source-rectangle.ts │ │ │ │ │ │ │ ├── stretch.ts │ │ │ │ │ │ │ ├── blip-fill.ts │ │ │ │ │ │ │ └── blip.ts │ │ │ │ │ │ ├── pic-attributes.ts │ │ │ │ │ │ ├── non-visual-pic-properties │ │ │ │ │ │ │ ├── child-non-visual-pic-properties │ │ │ │ │ │ │ │ ├── child-non-visual-pic-properties.ts │ │ │ │ │ │ │ │ └── pic-locks │ │ │ │ │ │ │ │ │ ├── pic-locks.ts │ │ │ │ │ │ │ │ │ └── pic-locks-attributes.ts │ │ │ │ │ │ │ ├── non-visual-properties │ │ │ │ │ │ │ │ ├── non-visual-properties-attributes.ts │ │ │ │ │ │ │ │ └── non-visual-properties.ts │ │ │ │ │ │ │ └── non-visual-pic-properties.ts │ │ │ │ │ │ └── pic.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── graphic-data-attribute.ts │ │ │ │ │ └── graphic-data.ts │ │ │ │ └── graphic.ts │ │ │ ├── inline-attributes.ts │ │ │ └── inline.ts │ │ ├── anchor │ │ │ ├── index.ts │ │ │ └── anchor-attributes.ts │ │ ├── index.ts │ │ ├── floating │ │ │ ├── index.ts │ │ │ ├── position-offset.ts │ │ │ ├── align.ts │ │ │ ├── position-offset.spec.ts │ │ │ ├── align.spec.ts │ │ │ ├── simple-pos.spec.ts │ │ │ ├── simple-pos.ts │ │ │ ├── vertical-position.ts │ │ │ ├── horizontal-position.ts │ │ │ ├── vertical-position.spec.ts │ │ │ ├── horizontal-position.spec.ts │ │ │ └── floating-position.ts │ │ ├── text-wrap │ │ │ ├── index.ts │ │ │ ├── wrap-none.ts │ │ │ ├── text-wrapping.ts │ │ │ ├── wrap-tight.ts │ │ │ ├── wrap-top-and-bottom.ts │ │ │ └── wrap-square.ts │ │ ├── extent │ │ │ ├── extent-attributes.ts │ │ │ └── extent.ts │ │ ├── graphic-frame │ │ │ ├── graphic-frame-properties.ts │ │ │ └── graphic-frame-locks │ │ │ │ ├── graphic-frame-lock-attributes.ts │ │ │ │ └── graphic-frame-locks.ts │ │ ├── doc-properties │ │ │ ├── doc-properties-attributes.ts │ │ │ └── doc-properties.ts │ │ ├── effect-extent │ │ │ ├── effect-extent-attributes.ts │ │ │ └── effect-extent.ts │ │ └── drawing.ts │ ├── footnotes │ │ ├── index.ts │ │ ├── footnote │ │ │ ├── run │ │ │ │ ├── seperator.ts │ │ │ │ ├── footnote-ref.ts │ │ │ │ ├── continuation-seperator.ts │ │ │ │ ├── seperator-run.ts │ │ │ │ ├── continuation-seperator-run.ts │ │ │ │ ├── footnote-ref-run.ts │ │ │ │ └── reference-run.ts │ │ │ ├── footnote-attributes.ts │ │ │ ├── footnote.ts │ │ │ └── footnote.spec.ts │ │ └── footnotes-attributes.ts │ ├── core-properties │ │ ├── index.ts │ │ └── properties.ts │ ├── relationships │ │ ├── index.ts │ │ ├── attributes.ts │ │ ├── relationship │ │ │ ├── relationship-attributes.ts │ │ │ └── relationship.ts │ │ ├── relationships.spec.ts │ │ └── relationships.ts │ ├── styles │ │ ├── border │ │ │ ├── index.ts │ │ │ └── border-style.ts │ │ ├── defaults │ │ │ ├── paragraph-properties.ts │ │ │ ├── index.ts │ │ │ └── run-properties.ts │ │ ├── latent-styles │ │ │ ├── index.ts │ │ │ └── exceptions.ts │ │ ├── index.ts │ │ ├── style │ │ │ └── components.ts │ │ └── external-styles-factory.ts │ ├── document │ │ ├── index.ts │ │ ├── body │ │ │ ├── section-properties │ │ │ │ ├── page-border │ │ │ │ │ └── index.ts │ │ │ │ ├── page-number │ │ │ │ │ ├── index.ts │ │ │ │ │ └── page-number.ts │ │ │ │ ├── page-size │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── page-size-attributes.ts │ │ │ │ │ ├── page-size.ts │ │ │ │ │ └── page-size.spec.ts │ │ │ │ ├── footer-reference │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── footer-reference-attributes.ts │ │ │ │ │ └── footer-reference.ts │ │ │ │ ├── header-reference │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── header-reference-attributes.ts │ │ │ │ │ └── header-reference.ts │ │ │ │ ├── index.ts │ │ │ │ ├── columns │ │ │ │ │ ├── columns-attributes.ts │ │ │ │ │ └── columns.ts │ │ │ │ ├── title-page │ │ │ │ │ ├── title-page-attributes.ts │ │ │ │ │ ├── title-page.ts │ │ │ │ │ └── title-page.spec.ts │ │ │ │ ├── doc-grid │ │ │ │ │ ├── doc-grid-attributes.ts │ │ │ │ │ └── doc-grid.ts │ │ │ │ └── page-margin │ │ │ │ │ ├── page-margin-attributes.ts │ │ │ │ │ └── page-margin.ts │ │ │ ├── index.ts │ │ │ └── body.spec.ts │ │ └── document-attributes.ts │ ├── table │ │ ├── index.ts │ │ ├── grid.ts │ │ ├── grid.spec.ts │ │ ├── properties.spec.ts │ │ └── table-cell-margin.ts │ ├── paragraph │ │ ├── links │ │ │ ├── index.ts │ │ │ ├── hyperlink-attributes.ts │ │ │ ├── bookmark-attributes.ts │ │ │ ├── hyperlink.ts │ │ │ ├── bookmark.ts │ │ │ ├── bookmark.spec.ts │ │ │ └── hyperlink.spec.ts │ │ ├── run │ │ │ ├── index.ts │ │ │ ├── tab.ts │ │ │ ├── break.ts │ │ │ ├── text-run.ts │ │ │ ├── properties.ts │ │ │ ├── caps.ts │ │ │ ├── style.ts │ │ │ ├── run-components │ │ │ │ ├── text.ts │ │ │ │ └── text.spec.ts │ │ │ ├── tab.spec.ts │ │ │ ├── break.spec.ts │ │ │ ├── script.ts │ │ │ ├── text-run.spec.ts │ │ │ ├── picture-run.ts │ │ │ ├── run-fonts.ts │ │ │ ├── strike.spec.ts │ │ │ ├── run-fonts.spec.ts │ │ │ ├── page-number.ts │ │ │ └── script.spec.ts │ │ ├── index.ts │ │ ├── formatting │ │ │ ├── bidirectional.ts │ │ │ ├── index.ts │ │ │ ├── keep.ts │ │ │ ├── style.ts │ │ │ ├── alignment.ts │ │ │ ├── spacing.ts │ │ │ ├── style.spec.ts │ │ │ ├── page-break.ts │ │ │ ├── indent.ts │ │ │ ├── unordered-list.ts │ │ │ ├── spacing.spec.ts │ │ │ ├── unordered-list.spec.ts │ │ │ ├── border.spec.ts │ │ │ ├── page-break.spec.ts │ │ │ ├── tab-stop.ts │ │ │ ├── tab-stop.spec.ts │ │ │ └── border.ts │ │ ├── properties.ts │ │ └── image.ts │ ├── media │ │ ├── index.ts │ │ ├── image.ts │ │ └── data.ts │ ├── numbering │ │ ├── index.ts │ │ ├── multi-level-type.ts │ │ └── abstract-numbering.ts │ ├── xml-components │ │ ├── index.ts │ │ ├── xmlable-object.ts │ │ ├── base.ts │ │ ├── default-attributes.ts │ │ ├── attribute.spec.ts │ │ ├── xml-component.spec.ts │ │ ├── attributes.ts │ │ └── xml-component.ts │ ├── index.ts │ ├── content-types │ │ ├── content-types-attributes.ts │ │ ├── default │ │ │ ├── default-attributes.ts │ │ │ └── default.ts │ │ └── override │ │ │ ├── override-attributes.ts │ │ │ └── override.ts │ ├── app-properties │ │ ├── app-properties-attributes.ts │ │ └── app-properties.ts │ ├── footer-wrapper.ts │ └── header-wrapper.ts ├── index.ts └── tests │ └── utility.ts ├── logo ├── logo.psd ├── logo-small.png └── logo-small.psd ├── demo ├── images │ ├── cat.jpg │ ├── dog.png │ ├── pizza.gif │ ├── image1.jpeg │ └── parrots.bmp ├── demo4.ts ├── demo8.ts ├── demo9.ts ├── demo7.ts ├── demo15.ts ├── demo24.ts ├── demo1.ts ├── demo19.ts ├── demo17.ts ├── demo26.ts ├── demo20.ts ├── demo12.ts ├── demo5.ts ├── demo14.ts ├── demo6.ts ├── demo13.ts ├── demo22.ts ├── index.ts ├── browser-demo.html ├── demo16.ts ├── demo3.ts └── demo21.ts ├── .prettierrc.yml ├── .editorconfig ├── .vscode └── settings.json ├── docs ├── usage │ ├── bullet-points.md │ ├── document.md │ ├── headers-and-footers.md │ ├── text.md │ ├── styling-with-xml.md │ └── tab-stops.md ├── _sidebar.md ├── index.html ├── README.md └── contribution-guidelines.md ├── types-absolute-fixer.js ├── .npmignore ├── webpack.config.js ├── .gitignore ├── tslint.json ├── LICENSE ├── tsconfig.json └── .travis.yml /.nvmrc: -------------------------------------------------------------------------------- 1 | v8 -------------------------------------------------------------------------------- /src/export/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./packer/packer"; 2 | -------------------------------------------------------------------------------- /src/file/footer/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./footer"; 2 | -------------------------------------------------------------------------------- /src/file/header/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./header"; 2 | -------------------------------------------------------------------------------- /src/file/drawing/inline/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./inline"; 2 | -------------------------------------------------------------------------------- /src/file/footnotes/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./footnotes"; 2 | -------------------------------------------------------------------------------- /src/file/core-properties/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./properties"; 2 | -------------------------------------------------------------------------------- /src/file/relationships/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./relationships"; 2 | -------------------------------------------------------------------------------- /src/file/styles/border/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./border-style"; 2 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./graphic"; 2 | -------------------------------------------------------------------------------- /logo/logo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/docx/master/logo/logo.psd -------------------------------------------------------------------------------- /src/file/document/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./document"; 2 | export * from "./body"; 3 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./pic"; 2 | -------------------------------------------------------------------------------- /src/file/table/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./table"; 2 | export * from "./table-cell"; 3 | -------------------------------------------------------------------------------- /demo/images/cat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/docx/master/demo/images/cat.jpg -------------------------------------------------------------------------------- /demo/images/dog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/docx/master/demo/images/dog.png -------------------------------------------------------------------------------- /logo/logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/docx/master/logo/logo-small.png -------------------------------------------------------------------------------- /logo/logo-small.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/docx/master/logo/logo-small.psd -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./graphic-data"; 2 | -------------------------------------------------------------------------------- /demo/images/pizza.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/docx/master/demo/images/pizza.gif -------------------------------------------------------------------------------- /src/file/document/body/section-properties/page-border/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./page-borders"; 2 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/page-number/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./page-number"; 2 | -------------------------------------------------------------------------------- /src/file/paragraph/links/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./hyperlink"; 2 | export * from "./bookmark"; 3 | -------------------------------------------------------------------------------- /demo/images/image1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/docx/master/demo/images/image1.jpeg -------------------------------------------------------------------------------- /demo/images/parrots.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ml-archive/docx/master/demo/images/parrots.bmp -------------------------------------------------------------------------------- /src/file/document/body/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./body"; 2 | export * from "./section-properties"; 3 | -------------------------------------------------------------------------------- /src/file/drawing/anchor/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./anchor"; 2 | export * from "./anchor-attributes"; 3 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./form"; 2 | -------------------------------------------------------------------------------- /src/file/media/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./media"; 2 | export * from "./data"; 3 | export * from "./image"; 4 | -------------------------------------------------------------------------------- /.prettierrc.yml: -------------------------------------------------------------------------------- 1 | trailingComma: all 2 | printWidth: 140 3 | tabWidth: 4 4 | arrowParens: always 5 | bracketSpacing: true -------------------------------------------------------------------------------- /src/file/drawing/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./drawing"; 2 | export * from "./text-wrap"; 3 | export * from "./floating"; 4 | -------------------------------------------------------------------------------- /src/file/paragraph/run/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./run"; 2 | export * from "./text-run"; 3 | export * from "./picture-run"; 4 | -------------------------------------------------------------------------------- /src/file/numbering/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./numbering"; 2 | export * from "./abstract-numbering"; 3 | export * from "./level"; 4 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/page-size/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./page-size"; 2 | export * from "./page-size-attributes"; 3 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/footer-reference/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./footer-reference"; 2 | export * from "./footer-reference-attributes"; 3 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/header-reference/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./header-reference"; 2 | export * from "./header-reference-attributes"; 3 | -------------------------------------------------------------------------------- /src/file/drawing/floating/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./floating-position"; 2 | export * from "./simple-pos"; 3 | export * from "./horizontal-position"; 4 | export * from "./vertical-position"; 5 | -------------------------------------------------------------------------------- /src/file/paragraph/run/tab.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | export class Tab extends XmlComponent { 4 | constructor() { 5 | super("w:tab"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/file/paragraph/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./formatting"; 2 | export * from "./paragraph"; 3 | export * from "./properties"; 4 | export * from "./run"; 5 | export * from "./links"; 6 | export * from "./image"; 7 | -------------------------------------------------------------------------------- /src/file/drawing/text-wrap/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./text-wrapping"; 2 | export * from "./wrap-none"; 3 | export * from "./wrap-square"; 4 | export * from "./wrap-tight"; 5 | export * from "./wrap-top-and-bottom"; 6 | -------------------------------------------------------------------------------- /src/file/footnotes/footnote/run/seperator.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | export class Seperator extends XmlComponent { 4 | constructor() { 5 | super("w:separator"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/bidirectional.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | export class Bidirectional extends XmlComponent { 4 | constructor() { 5 | super("w:bidi"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/file/xml-components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./xml-component"; 2 | export * from "./attributes"; 3 | export * from "./default-attributes"; 4 | export * from "./imported-xml-component"; 5 | export * from "./xmlable-object"; 6 | -------------------------------------------------------------------------------- /src/file/footnotes/footnote/run/footnote-ref.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | export class FootnoteRef extends XmlComponent { 4 | constructor() { 5 | super("w:footnoteRef"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // Internally, the wrapper is a 'File', but export to the end user as a 'Document' 2 | // Use of 'File' also works 3 | export { File as Document } from "./file"; 4 | export * from "./file"; 5 | export * from "./export"; 6 | -------------------------------------------------------------------------------- /src/export/formatter.ts: -------------------------------------------------------------------------------- 1 | import { BaseXmlComponent, IXmlableObject } from "file/xml-components"; 2 | 3 | export class Formatter { 4 | public format(input: BaseXmlComponent): IXmlableObject { 5 | return input.prepForXml(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/no-fill.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | export class NoFill extends XmlComponent { 4 | constructor() { 5 | super("a:noFill"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/blip/source-rectangle.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | export class SourceRectangle extends XmlComponent { 4 | constructor() { 5 | super("a:srcRect"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/outline/no-fill.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | export class NoFill extends XmlComponent { 4 | constructor() { 5 | super("a:noFill"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/tests/utility.ts: -------------------------------------------------------------------------------- 1 | export class Utility { 2 | // tslint:disable-next-line:no-any 3 | public static jsonify(obj: object): any { 4 | const stringifiedJson = JSON.stringify(obj); 5 | return JSON.parse(stringifiedJson); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/file/footnotes/footnote/run/continuation-seperator.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | export class ContinuationSeperator extends XmlComponent { 4 | constructor() { 5 | super("w:continuationSeparator"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/file/paragraph/run/break.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/WPtextSpecialContent-break.php 2 | import { XmlComponent } from "file/xml-components"; 3 | 4 | export class Break extends XmlComponent { 5 | constructor() { 6 | super("w:br"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./section-properties"; 2 | export * from "./footer-reference"; 3 | export * from "./header-reference"; 4 | export * from "./page-size"; 5 | export * from "./page-number"; 6 | export * from "./page-border"; 7 | -------------------------------------------------------------------------------- /src/file/drawing/text-wrap/wrap-none.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicFloating-textWrap.php 2 | import { XmlComponent } from "file/xml-components"; 3 | 4 | export class WrapNone extends XmlComponent { 5 | constructor() { 6 | super("wp:wrapNone"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/file/paragraph/run/text-run.ts: -------------------------------------------------------------------------------- 1 | import { Run } from "../run"; 2 | import { Text } from "./run-components/text"; 3 | 4 | export class TextRun extends Run { 5 | constructor(text: string) { 6 | super(); 7 | this.root.push(new Text(text)); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/file/footnotes/footnote/run/seperator-run.ts: -------------------------------------------------------------------------------- 1 | import { Run } from "file/paragraph"; 2 | import { Seperator } from "./seperator"; 3 | 4 | export class SeperatorRun extends Run { 5 | constructor() { 6 | super(); 7 | 8 | this.root.push(new Seperator()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/file/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./paragraph"; 2 | export * from "./table"; 3 | export * from "./file"; 4 | export * from "./numbering"; 5 | export * from "./media"; 6 | export * from "./drawing"; 7 | export * from "./document"; 8 | export * from "./styles"; 9 | export * from "./xml-components"; 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /src/file/paragraph/run/properties.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | export class RunProperties extends XmlComponent { 4 | constructor() { 5 | super("w:rPr"); 6 | } 7 | 8 | public push(item: XmlComponent): void { 9 | this.root.push(item); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./alignment"; 2 | export * from "./border"; 3 | export * from "./indent"; 4 | export * from "./keep"; 5 | export * from "./page-break"; 6 | export * from "./spacing"; 7 | export * from "./style"; 8 | export * from "./tab-stop"; 9 | export * from "./unordered-list"; 10 | -------------------------------------------------------------------------------- /src/file/xml-components/xmlable-object.ts: -------------------------------------------------------------------------------- 1 | export interface IXmlableObject extends Object { 2 | _attr?: { [key: string]: string | number | boolean }; 3 | } 4 | 5 | // Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432 6 | /** 7 | * @ignore 8 | */ 9 | export const WORKAROUND3 = ""; 10 | -------------------------------------------------------------------------------- /src/file/paragraph/run/caps.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | export class SmallCaps extends XmlComponent { 4 | constructor() { 5 | super("w:smallCaps"); 6 | } 7 | } 8 | 9 | export class Caps extends XmlComponent { 10 | constructor() { 11 | super("w:caps"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": ["clippy", "docx", "dolan", "miu", "officegen", "typedoc"], 3 | "prettier.trailingComma": "all", 4 | "prettier.printWidth": 140, 5 | "editor.formatOnSave": false, 6 | "prettier.tabWidth": 4, 7 | "prettier.arrowParens": "always", 8 | "prettier.bracketSpacing": true 9 | } 10 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/adjustment-values/adjustment-values.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwSp-prstGeom.php 2 | import { XmlComponent } from "file/xml-components"; 3 | 4 | export class AdjustmentValues extends XmlComponent { 5 | constructor() { 6 | super("a:avLst"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/keep.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | export class KeepLines extends XmlComponent { 4 | constructor() { 5 | super("w:keepLines"); 6 | } 7 | } 8 | 9 | export class KeepNext extends XmlComponent { 10 | constructor() { 11 | super("w:keepNext"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/file/footnotes/footnote/run/continuation-seperator-run.ts: -------------------------------------------------------------------------------- 1 | import { Run } from "file/paragraph"; 2 | import { ContinuationSeperator } from "./continuation-seperator"; 3 | 4 | export class ContinuationSeperatorRun extends Run { 5 | constructor() { 6 | super(); 7 | 8 | this.root.push(new ContinuationSeperator()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/file/footnotes/footnote/run/footnote-ref-run.ts: -------------------------------------------------------------------------------- 1 | import { Run } from "file/paragraph"; 2 | import { FootnoteRef } from "./footnote-ref"; 3 | 4 | export class FootnoteRefRun extends Run { 5 | constructor() { 6 | super(); 7 | 8 | this.style("FootnoteReference"); 9 | this.root.push(new FootnoteRef()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/file/drawing/floating/position-offset.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicFloating-position.php 2 | import { XmlComponent } from "file/xml-components"; 3 | 4 | export class PositionOffset extends XmlComponent { 5 | constructor(offsetValue: number) { 6 | super("wp:posOffset"); 7 | this.root.push(offsetValue.toString()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/file/content-types/content-types-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IContentTypeAttributes { 4 | xmlns?: string; 5 | } 6 | 7 | export class ContentTypeAttributes extends XmlAttributeComponent { 8 | protected xmlKeys = { 9 | xmlns: "xmlns", 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/pic-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IPicAttributes { 4 | xmlns?: string; 5 | } 6 | 7 | export class PicAttributes extends XmlAttributeComponent { 8 | protected xmlKeys = { 9 | xmlns: "xmlns:pic", 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/style.ts: -------------------------------------------------------------------------------- 1 | import { Attributes, XmlComponent } from "file/xml-components"; 2 | 3 | export class Style extends XmlComponent { 4 | constructor(type: string) { 5 | super("w:pStyle"); 6 | this.root.push( 7 | new Attributes({ 8 | val: type, 9 | }), 10 | ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/file/styles/defaults/paragraph-properties.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { ParagraphProperties } from "../../paragraph/properties"; 3 | 4 | export class ParagraphPropertiesDefaults extends XmlComponent { 5 | constructor() { 6 | super("w:pPrDefault"); 7 | this.root.push(new ParagraphProperties()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/columns/columns-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IColumnsAttributes { 4 | space?: number; 5 | } 6 | 7 | export class ColumnsAttributes extends XmlAttributeComponent { 8 | protected xmlKeys = { 9 | space: "w:space", 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/file/drawing/extent/extent-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IExtentAttributes { 4 | cx?: number; 5 | cy?: number; 6 | } 7 | 8 | export class ExtentAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | cx: "cx", 11 | cy: "cy", 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/graphic-data-attribute.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IGraphicDataAttributes { 4 | uri?: string; 5 | } 6 | 7 | export class GraphicDataAttributes extends XmlAttributeComponent { 8 | protected xmlKeys = { 9 | uri: "uri", 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/file/relationships/attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IRelationshipsAttributesProperties { 4 | xmlns: string; 5 | } 6 | 7 | export class RelationshipsAttributes extends XmlAttributeComponent { 8 | protected xmlKeys = { 9 | xmlns: "xmlns", 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/file/numbering/multi-level-type.ts: -------------------------------------------------------------------------------- 1 | import { Attributes, XmlComponent } from "file/xml-components"; 2 | 3 | export class MultiLevelType extends XmlComponent { 4 | constructor(value: string) { 5 | super("w:multiLevelType"); 6 | this.root.push( 7 | new Attributes({ 8 | val: value, 9 | }), 10 | ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/outline/outline.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwSp-outline.php 2 | import { XmlComponent } from "file/xml-components"; 3 | import { NoFill } from "./no-fill"; 4 | 5 | export class Outline extends XmlComponent { 6 | constructor() { 7 | super("a:ln"); 8 | 9 | this.root.push(new NoFill()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/title-page/title-page-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IHeaderReferenceAttributes { 4 | value: string; 5 | } 6 | 7 | export class TitlePageAttributes extends XmlAttributeComponent { 8 | protected xmlKeys = { 9 | value: "w:val", 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/file/drawing/graphic-frame/graphic-frame-properties.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { GraphicFrameLocks } from "./graphic-frame-locks/graphic-frame-locks"; 3 | 4 | export class GraphicFrameProperties extends XmlComponent { 5 | constructor() { 6 | super("wp:cNvGraphicFramePr"); 7 | 8 | this.root.push(new GraphicFrameLocks()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/doc-grid/doc-grid-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IDocGridAttributesProperties { 4 | linePitch?: number; 5 | } 6 | 7 | export class DocGridAttributes extends XmlAttributeComponent { 8 | protected xmlKeys = { 9 | linePitch: "w:linePitch", 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/file/styles/latent-styles/index.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { LatentStyleException } from "./exceptions"; 3 | 4 | export class LatentStyles extends XmlComponent { 5 | constructor() { 6 | super("w:latentStyles"); 7 | } 8 | 9 | public push(latentException: LatentStyleException): void { 10 | this.root.push(latentException); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/blip/stretch.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | 3 | class FillRectangle extends XmlComponent { 4 | constructor() { 5 | super("a:fillRect"); 6 | } 7 | } 8 | 9 | export class Stretch extends XmlComponent { 10 | constructor() { 11 | super("a:stretch"); 12 | this.root.push(new FillRectangle()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/file/app-properties/app-properties-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IAppPropertiesAttributes { 4 | xmlns: string; 5 | vt: string; 6 | } 7 | 8 | export class AppPropertiesAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | xmlns: "xmlns", 11 | vt: "xmlns:vt", 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/offset/off-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IOffsetAttributes { 4 | x?: number; 5 | y?: number; 6 | } 7 | 8 | export class OffsetAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | x: "x", 11 | y: "y", 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/file/footnotes/footnote/footnote-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IFootnoteAttributesProperties { 4 | type?: string; 5 | id: number; 6 | } 7 | 8 | export class FootnoteAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | type: "w:type", 11 | id: "w:id", 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/shape-properties-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IShapePropertiesAttributes { 4 | bwMode?: string; 5 | } 6 | 7 | export class ShapePropertiesAttributes extends XmlAttributeComponent { 8 | protected xmlKeys = { 9 | bwMode: "bwMode", 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/preset-geometry-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IPresetGeometryAttributes { 4 | prst?: string; 5 | } 6 | 7 | export class PresetGeometryAttributes extends XmlAttributeComponent { 8 | protected xmlKeys = { 9 | prst: "prst", 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/file/content-types/default/default-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IDefaultAttributes { 4 | contentType: string; 5 | extension?: string; 6 | } 7 | 8 | export class DefaultAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | contentType: "ContentType", 11 | extension: "Extension", 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/file/content-types/override/override-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IOverrideAttributes { 4 | contentType: string; 5 | partName?: string; 6 | } 7 | 8 | export class OverrideAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | contentType: "ContentType", 11 | partName: "PartName", 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/child-non-visual-pic-properties.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { PicLocks } from "./pic-locks/pic-locks"; 3 | 4 | export class ChildNonVisualProperties extends XmlComponent { 5 | constructor() { 6 | super("pic:cNvPicPr"); 7 | 8 | this.root.push(new PicLocks()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/extents/extents-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IExtentsAttributes { 4 | cx?: number; 5 | cy?: number; 6 | } 7 | 8 | export class ExtentsAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | cx: "cx", 11 | cy: "cy", 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/file/drawing/floating/align.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicFloating-position.php 2 | import { XmlComponent } from "file/xml-components"; 3 | import { HorizontalPositionAlign, VerticalPositionAlign } from "./floating-position"; 4 | 5 | export class Align extends XmlComponent { 6 | constructor(value: HorizontalPositionAlign | VerticalPositionAlign) { 7 | super("wp:align"); 8 | this.root.push(value); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/file/paragraph/run/style.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 2 | 3 | class StyleAttributes extends XmlAttributeComponent<{ val: string }> { 4 | protected xmlKeys = { val: "w:val" }; 5 | } 6 | 7 | export class Style extends XmlComponent { 8 | constructor(styleId: string) { 9 | super("w:rStyle"); 10 | this.root.push(new StyleAttributes({ val: styleId })); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/columns/columns.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { ColumnsAttributes } from "./columns-attributes"; 3 | 4 | export class Columns extends XmlComponent { 5 | constructor(space: number) { 6 | super("w:cols"); 7 | this.root.push( 8 | new ColumnsAttributes({ 9 | space: space, 10 | }), 11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/title-page/title-page.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { TitlePageAttributes } from "./title-page-attributes"; 3 | 4 | export class TitlePage extends XmlComponent { 5 | constructor() { 6 | super("w:titlePg"); 7 | this.root.push( 8 | new TitlePageAttributes({ 9 | value: "1", 10 | }), 11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/file/xml-components/base.ts: -------------------------------------------------------------------------------- 1 | import { IXmlableObject } from "./xmlable-object"; 2 | 3 | export abstract class BaseXmlComponent { 4 | protected rootKey: string; 5 | protected deleted: boolean = false; 6 | 7 | constructor(rootKey: string) { 8 | this.rootKey = rootKey; 9 | } 10 | 11 | public abstract prepForXml(): IXmlableObject; 12 | 13 | public get IsDeleted(): boolean { 14 | return this.deleted; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/doc-grid/doc-grid.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { DocGridAttributes } from "./doc-grid-attributes"; 3 | 4 | export class DocumentGrid extends XmlComponent { 5 | constructor(linePitch: number) { 6 | super("w:docGrid"); 7 | this.root.push( 8 | new DocGridAttributes({ 9 | linePitch: linePitch, 10 | }), 11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/file/drawing/doc-properties/doc-properties-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IDocPropertiesAttributes { 4 | id?: number; 5 | name?: string; 6 | descr?: string; 7 | } 8 | 9 | export class DocPropertiesAttributes extends XmlAttributeComponent { 10 | protected xmlKeys = { 11 | id: "id", 12 | name: "name", 13 | descr: "descr", 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/file/drawing/effect-extent/effect-extent-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IEffectExtentAttributes { 4 | b?: number; 5 | l?: number; 6 | r?: number; 7 | t?: number; 8 | } 9 | 10 | export class EffectExtentAttributes extends XmlAttributeComponent { 11 | protected xmlKeys = { 12 | b: "b", 13 | l: "l", 14 | r: "r", 15 | t: "t", 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/file/paragraph/links/hyperlink-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IHyperlinkAttributesProperties { 4 | id?: string; 5 | anchor?: string; 6 | history: number; 7 | } 8 | 9 | export class HyperlinkAttributes extends XmlAttributeComponent { 10 | protected xmlKeys = { 11 | id: "r:id", 12 | history: "w:history", 13 | anchor: "w:anchor", 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/file/drawing/graphic-frame/graphic-frame-locks/graphic-frame-lock-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IGraphicFrameLockAttributes { 4 | xmlns?: string; 5 | noChangeAspect?: number; 6 | } 7 | 8 | export class GraphicFrameLockAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | xmlns: "xmlns:a", 11 | noChangeAspect: "noChangeAspect", 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/file/content-types/default/default.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { DefaultAttributes } from "./default-attributes"; 3 | 4 | export class Default extends XmlComponent { 5 | constructor(contentType: string, extension?: string) { 6 | super("Default"); 7 | 8 | this.root.push( 9 | new DefaultAttributes({ 10 | contentType: contentType, 11 | extension: extension, 12 | }), 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/file/drawing/doc-properties/doc-properties.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { DocPropertiesAttributes } from "./doc-properties-attributes"; 3 | 4 | export class DocProperties extends XmlComponent { 5 | constructor() { 6 | super("wp:docPr"); 7 | 8 | this.root.push( 9 | new DocPropertiesAttributes({ 10 | id: 0, 11 | name: "", 12 | descr: "", 13 | }), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/file/drawing/inline/inline-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | import { IDistance } from "../drawing"; 3 | 4 | // tslint:disable-next-line:no-empty-interface 5 | export interface IInlineAttributes extends IDistance {} 6 | 7 | export class InlineAttributes extends XmlAttributeComponent { 8 | protected xmlKeys = { 9 | distT: "distT", 10 | distB: "distB", 11 | distL: "distL", 12 | distR: "distR", 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/file/content-types/override/override.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { OverrideAttributes } from "./override-attributes"; 3 | 4 | export class Override extends XmlComponent { 5 | constructor(contentType: string, partName?: string) { 6 | super("Override"); 7 | 8 | this.root.push( 9 | new OverrideAttributes({ 10 | contentType: contentType, 11 | partName: partName, 12 | }), 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/file/media/image.ts: -------------------------------------------------------------------------------- 1 | import { ImageParagraph, PictureRun } from "../paragraph"; 2 | 3 | export class Image { 4 | constructor(private readonly paragraph: ImageParagraph) {} 5 | 6 | public get Paragraph(): ImageParagraph { 7 | return this.paragraph; 8 | } 9 | 10 | public get Run(): PictureRun { 11 | return this.paragraph.Run; 12 | } 13 | 14 | public scale(factorX: number, factorY?: number): void { 15 | this.paragraph.Run.scale(factorX, factorY); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/offset/off.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwSp-size.php 2 | import { XmlComponent } from "file/xml-components"; 3 | import { OffsetAttributes } from "./off-attributes"; 4 | 5 | export class Offset extends XmlComponent { 6 | constructor() { 7 | super("a:off"); 8 | 9 | this.root.push( 10 | new OffsetAttributes({ 11 | x: 0, 12 | y: 0, 13 | }), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/file/drawing/effect-extent/effect-extent.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { EffectExtentAttributes } from "./effect-extent-attributes"; 3 | 4 | export class EffectExtent extends XmlComponent { 5 | constructor() { 6 | super("wp:effectExtent"); 7 | 8 | this.root.push( 9 | new EffectExtentAttributes({ 10 | b: 0, 11 | l: 0, 12 | r: 0, 13 | t: 0, 14 | }), 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /demo/demo4.ts: -------------------------------------------------------------------------------- 1 | // Example of how you would create a table and add data to it 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const table = doc.createTable(4, 4); 9 | table.getCell(2, 2).addContent(new Paragraph("Hello")); 10 | 11 | const packer = new Packer(); 12 | 13 | packer.toBuffer(doc).then((buffer) => { 14 | fs.writeFileSync("My Document.docx", buffer); 15 | }); 16 | -------------------------------------------------------------------------------- /demo/demo8.ts: -------------------------------------------------------------------------------- 1 | // Add text to header and footer 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | doc.createParagraph("Hello World"); 9 | 10 | doc.Header.createParagraph("Header text"); 11 | doc.Footer.createParagraph("Footer text"); 12 | 13 | const packer = new Packer(); 14 | 15 | packer.toBuffer(doc).then((buffer) => { 16 | fs.writeFileSync("My Document.docx", buffer); 17 | }); 18 | -------------------------------------------------------------------------------- /docs/usage/bullet-points.md: -------------------------------------------------------------------------------- 1 | # Bullet Points 2 | 3 | ## Example 4 | 5 | To make a bullet point, simply make a paragraph into a bullet point: 6 | 7 | ```js 8 | var text = new docx.TextRun("Bullet points"); 9 | var paragraph = new docx.Paragraph(text).bullet(); 10 | 11 | var text2 = new docx.TextRun("Are awesome"); 12 | var paragraph2 = new docx.Paragraph(text2).bullet(); 13 | 14 | doc.addParagraph(paragraph); 15 | doc.addParagraph(paragraph2); 16 | ``` 17 | 18 | ### This will produce: 19 | 20 | * Bullet points 21 | * Are awesome 22 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/blip/blip-fill.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { Blip } from "./blip"; 3 | import { SourceRectangle } from "./source-rectangle"; 4 | import { Stretch } from "./stretch"; 5 | 6 | export class BlipFill extends XmlComponent { 7 | constructor(referenceId: number) { 8 | super("pic:blipFill"); 9 | this.root.push(new Blip(referenceId)); 10 | this.root.push(new SourceRectangle()); 11 | this.root.push(new Stretch()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/file/paragraph/run/run-components/text.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 2 | 3 | class TextAttributes extends XmlAttributeComponent<{ space: "default" | "preserve" }> { 4 | protected xmlKeys = { space: "xml:space" }; 5 | } 6 | 7 | export class Text extends XmlComponent { 8 | constructor(text: string) { 9 | super("w:t"); 10 | this.root.push(new TextAttributes({ space: "preserve" })); 11 | if (text) { 12 | this.root.push(text); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/file/paragraph/run/tab.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { Tab } from "./tab"; 5 | 6 | describe("Tab", () => { 7 | let tab: Tab; 8 | 9 | beforeEach(() => { 10 | tab = new Tab(); 11 | }); 12 | 13 | describe("#constructor()", () => { 14 | it("should create a Tab with correct root key", () => { 15 | const newJson = Utility.jsonify(tab); 16 | assert.equal(newJson.rootKey, "w:tab"); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/pic-locks/pic-locks.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { PicLocksAttributes } from "./pic-locks-attributes"; 3 | 4 | export class PicLocks extends XmlComponent { 5 | constructor() { 6 | super("a:picLocks"); 7 | this.root.push( 8 | new PicLocksAttributes({ 9 | noChangeAspect: 1, 10 | noChangeArrowheads: 1, 11 | }), 12 | ); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/file/relationships/relationship/relationship-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IRelationshipAttributesProperties { 4 | id: string; 5 | type: string; 6 | target: string; 7 | targetMode?: string; 8 | } 9 | 10 | export class RelationshipAttributes extends XmlAttributeComponent { 11 | protected xmlKeys = { 12 | id: "Id", 13 | type: "Type", 14 | target: "Target", 15 | targetMode: "TargetMode", 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/child-non-visual-pic-properties/pic-locks/pic-locks-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IPicLocksAttributes { 4 | noChangeAspect?: number; 5 | noChangeArrowheads?: number; 6 | } 7 | 8 | export class PicLocksAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | noChangeAspect: "noChangeAspect", 11 | noChangeArrowheads: "noChangeArrowheads", 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-properties/non-visual-properties-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface INonVisualPropertiesAttributes { 4 | id?: number; 5 | name?: string; 6 | descr?: string; 7 | } 8 | 9 | export class NonVisualPropertiesAttributes extends XmlAttributeComponent { 10 | protected xmlKeys = { 11 | id: "id", 12 | name: "name", 13 | descr: "desc", 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/file/drawing/floating/position-offset.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { PositionOffset } from "./position-offset"; 5 | 6 | describe("PositionOffset", () => { 7 | describe("#constructor()", () => { 8 | it("should create a element with correct root key", () => { 9 | const newJson = Utility.jsonify(new PositionOffset(50)); 10 | assert.equal(newJson.rootKey, "wp:posOffset"); 11 | assert.equal(newJson.root[0], 50); 12 | }); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /demo/demo9.ts: -------------------------------------------------------------------------------- 1 | // Add images to header and footer 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | doc.createParagraph("Hello World"); 9 | 10 | doc.Header.createImage(fs.readFileSync("./demo/images/pizza.gif")); 11 | doc.Footer.createImage(fs.readFileSync("./demo/images/pizza.gif")); 12 | 13 | const packer = new Packer(); 14 | 15 | packer.toBuffer(doc).then((buffer) => { 16 | fs.writeFileSync("My Document.docx", buffer); 17 | }); 18 | -------------------------------------------------------------------------------- /src/file/drawing/text-wrap/text-wrapping.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicFloating-textWrap.php 2 | import { IDistance } from "../drawing"; 3 | 4 | export enum TextWrapStyle { 5 | NONE, 6 | SQUARE, 7 | TIGHT, 8 | TOP_AND_BOTTOM, 9 | } 10 | 11 | export enum WrapTextOption { 12 | BOTH_SIDES = "bothSides", 13 | LEFT = "left", 14 | RIGHT = "right", 15 | LARGEST = "largest", 16 | } 17 | 18 | export interface ITextWrapping { 19 | textWrapStyle: TextWrapStyle; 20 | wrapTextOption?: WrapTextOption; 21 | distanceFromText?: IDistance; 22 | } 23 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/footer-reference/footer-reference-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export enum FooterReferenceType { 4 | DEFAULT = "default", 5 | FIRST = "first", 6 | EVEN = "even", 7 | } 8 | 9 | export interface IFooterReferenceAttributes { 10 | type: string; 11 | id: string; 12 | } 13 | 14 | export class FooterReferenceAttributes extends XmlAttributeComponent { 15 | protected xmlKeys = { 16 | type: "w:type", 17 | id: "r:id", 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/header-reference/header-reference-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export enum HeaderReferenceType { 4 | DEFAULT = "default", 5 | FIRST = "first", 6 | EVEN = "even", 7 | } 8 | 9 | export interface IHeaderReferenceAttributes { 10 | type: string; 11 | id: string; 12 | } 13 | 14 | export class HeaderReferenceAttributes extends XmlAttributeComponent { 15 | protected xmlKeys = { 16 | type: "w:type", 17 | id: "r:id", 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/file/drawing/graphic-frame/graphic-frame-locks/graphic-frame-locks.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { GraphicFrameLockAttributes } from "./graphic-frame-lock-attributes"; 3 | 4 | export class GraphicFrameLocks extends XmlComponent { 5 | constructor() { 6 | super("a:graphicFrameLocks"); 7 | 8 | this.root.push( 9 | new GraphicFrameLockAttributes({ 10 | xmlns: "http://schemas.openxmlformats.org/drawingml/2006/main", 11 | noChangeAspect: 1, 12 | }), 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/file/paragraph/run/break.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { Break } from "./break"; 5 | 6 | describe("Break", () => { 7 | let currentBreak: Break; 8 | 9 | beforeEach(() => { 10 | currentBreak = new Break(); 11 | }); 12 | 13 | describe("#constructor()", () => { 14 | it("should create a Break with correct root key", () => { 15 | const newJson = Utility.jsonify(currentBreak); 16 | assert.equal(newJson.rootKey, "w:br"); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /demo/demo7.ts: -------------------------------------------------------------------------------- 1 | // Example of how to set the document to landscape 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, PageOrientation, Paragraph } from "../build"; 5 | 6 | const doc = new Document(undefined, { 7 | orientation: PageOrientation.LANDSCAPE, 8 | }); 9 | 10 | const paragraph = new Paragraph("Hello World"); 11 | 12 | doc.addParagraph(paragraph); 13 | 14 | const packer = new Packer(); 15 | 16 | packer.toBuffer(doc).then((buffer) => { 17 | fs.writeFileSync("My Document.docx", buffer); 18 | }); 19 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-properties/non-visual-properties.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { NonVisualPropertiesAttributes } from "./non-visual-properties-attributes"; 3 | 4 | export class NonVisualProperties extends XmlComponent { 5 | constructor() { 6 | super("pic:cNvPr"); 7 | 8 | this.root.push( 9 | new NonVisualPropertiesAttributes({ 10 | id: 0, 11 | name: "", 12 | descr: "", 13 | }), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/file/media/data.ts: -------------------------------------------------------------------------------- 1 | export interface IMediaDataDimensions { 2 | pixels: { 3 | x: number; 4 | y: number; 5 | }; 6 | emus: { 7 | x: number; 8 | y: number; 9 | }; 10 | } 11 | 12 | export interface IMediaData { 13 | referenceId: number; 14 | stream: Buffer | Uint8Array | ArrayBuffer; 15 | path?: string; 16 | fileName: string; 17 | dimensions: IMediaDataDimensions; 18 | } 19 | 20 | // Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432 21 | /** 22 | * @ignore 23 | */ 24 | export const WORKAROUND2 = ""; 25 | -------------------------------------------------------------------------------- /demo/demo15.ts: -------------------------------------------------------------------------------- 1 | // Page break before example 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const paragraph = new Paragraph("Hello World"); 9 | const paragraph2 = new Paragraph("Hello World on another page").pageBreakBefore(); 10 | 11 | doc.addParagraph(paragraph); 12 | doc.addParagraph(paragraph2); 13 | 14 | const packer = new Packer(); 15 | 16 | packer.toBuffer(doc).then((buffer) => { 17 | fs.writeFileSync("My Document.docx", buffer); 18 | }); 19 | -------------------------------------------------------------------------------- /src/file/app-properties/app-properties.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { AppPropertiesAttributes } from "./app-properties-attributes"; 3 | 4 | export class AppProperties extends XmlComponent { 5 | constructor() { 6 | super("Properties"); 7 | 8 | this.root.push( 9 | new AppPropertiesAttributes({ 10 | xmlns: "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties", 11 | vt: "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", 12 | }), 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/non-visual-pic-properties/non-visual-pic-properties.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { ChildNonVisualProperties } from "./child-non-visual-pic-properties/child-non-visual-pic-properties"; 3 | import { NonVisualProperties } from "./non-visual-properties/non-visual-properties"; 4 | 5 | export class NonVisualPicProperties extends XmlComponent { 6 | constructor() { 7 | super("pic:nvPicPr"); 8 | 9 | this.root.push(new NonVisualProperties()); 10 | this.root.push(new ChildNonVisualProperties()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/page-size/page-size-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export enum PageOrientation { 4 | PORTRAIT = "portrait", 5 | LANDSCAPE = "landscape", 6 | } 7 | 8 | export interface IPageSizeAttributes { 9 | width?: number; 10 | height?: number; 11 | orientation?: PageOrientation; 12 | } 13 | 14 | export class PageSizeAttributes extends XmlAttributeComponent { 15 | protected xmlKeys = { 16 | width: "w:w", 17 | height: "w:h", 18 | orientation: "w:orient", 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /src/file/paragraph/properties.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/WPparagraphProperties.php 2 | import { XmlComponent } from "file/xml-components"; 3 | import { Border } from "./formatting/border"; 4 | 5 | export class ParagraphProperties extends XmlComponent { 6 | public paragraphBorder: Border; 7 | 8 | constructor() { 9 | super("w:pPr"); 10 | this.paragraphBorder = new Border(); 11 | } 12 | 13 | public createBorder(): void { 14 | this.push(this.paragraphBorder); 15 | } 16 | 17 | public push(item: XmlComponent): void { 18 | this.root.push(item); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/file/drawing/floating/align.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { VerticalPositionAlign } from "."; 4 | import { Utility } from "../../../tests/utility"; 5 | import { Align } from "./align"; 6 | 7 | describe("Align", () => { 8 | describe("#constructor()", () => { 9 | it("should create a element with correct root key", () => { 10 | const newJson = Utility.jsonify(new Align(VerticalPositionAlign.CENTER)); 11 | assert.equal(newJson.rootKey, "wp:align"); 12 | assert.include(newJson.root[0], VerticalPositionAlign.CENTER); 13 | }); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/file/drawing/floating/simple-pos.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { SimplePos } from "./simple-pos"; 5 | 6 | describe("SimplePos", () => { 7 | describe("#constructor()", () => { 8 | it("should create a element with correct root key", () => { 9 | const newJson = Utility.jsonify(new SimplePos()); 10 | assert.equal(newJson.rootKey, "wp:simplePos"); 11 | assert.include(newJson.root[0].root, { 12 | x: 0, 13 | y: 0, 14 | }); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /demo/demo24.ts: -------------------------------------------------------------------------------- 1 | // Add image to table cell 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Media, Packer, Paragraph } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const table = doc.createTable(4, 4); 9 | table.getCell(2, 2).addContent(new Paragraph("Hello")); 10 | 11 | const image = Media.addImage(doc, "./demo/images/image1.jpeg"); 12 | table.getCell(1, 1).addContent(image.Paragraph); 13 | 14 | const packer = new Packer(); 15 | 16 | packer.toBuffer(doc).then((buffer) => { 17 | fs.writeFileSync("My Document.docx", buffer); 18 | }); 19 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/alignment.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/WPalignment.php 2 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 3 | 4 | export type AlignmentOptions = "start" | "end" | "center" | "both" | "distribute" | "left" | "right"; 5 | 6 | export class AlignmentAttributes extends XmlAttributeComponent<{ val: AlignmentOptions }> { 7 | protected xmlKeys = { val: "w:val" }; 8 | } 9 | 10 | export class Alignment extends XmlComponent { 11 | constructor(type: AlignmentOptions) { 12 | super("w:jc"); 13 | this.root.push(new AlignmentAttributes({ val: type })); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/file/paragraph/run/script.ts: -------------------------------------------------------------------------------- 1 | import { Attributes, XmlComponent } from "file/xml-components"; 2 | 3 | export abstract class VerticalAlign extends XmlComponent { 4 | constructor(type: string) { 5 | super("w:vertAlign"); 6 | this.root.push( 7 | new Attributes({ 8 | val: type, 9 | }), 10 | ); 11 | } 12 | } 13 | 14 | export class SuperScript extends VerticalAlign { 15 | constructor() { 16 | super("superscript"); 17 | } 18 | } 19 | 20 | export class SubScript extends VerticalAlign { 21 | constructor() { 22 | super("subscript"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/file/paragraph/run/text-run.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | import { Formatter } from "../../../export/formatter"; 4 | import { TextRun } from "./text-run"; 5 | 6 | describe("TextRun", () => { 7 | let run: TextRun; 8 | 9 | describe("#constructor()", () => { 10 | it("should add text into run", () => { 11 | run = new TextRun("test"); 12 | const f = new Formatter().format(run); 13 | expect(f).to.deep.equal({ 14 | "w:r": [{ "w:rPr": [] }, { "w:t": [{ _attr: { "xml:space": "preserve" } }, "test"] }], 15 | }); 16 | }); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /types-absolute-fixer.js: -------------------------------------------------------------------------------- 1 | const glob = require("glob"); 2 | const replace = require("replace-in-file"); 3 | 4 | const files = glob.sync("build/**/*.d.ts"); 5 | 6 | for (const file of files) { 7 | replace({ 8 | files: file, 9 | from: /"file[a-z/-]*"/gi, 10 | to: (match) => { 11 | const matchSlug = match.replace(/['"]+/g, "").trim(); 12 | const levelCount = file.split("/").length - 2; 13 | const backLevels = Array(levelCount) 14 | .fill("../") 15 | .join(""); 16 | 17 | return `"${backLevels}${matchSlug}"`; 18 | }, 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /src/file/drawing/extent/extent.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { ExtentAttributes } from "./extent-attributes"; 3 | 4 | export class Extent extends XmlComponent { 5 | private readonly attributes: ExtentAttributes; 6 | 7 | constructor(x: number, y: number) { 8 | super("wp:extent"); 9 | 10 | this.attributes = new ExtentAttributes({ 11 | cx: x, 12 | cy: y, 13 | }); 14 | 15 | this.root.push(this.attributes); 16 | } 17 | 18 | public setXY(x: number, y: number): void { 19 | this.attributes.set({ 20 | cx: x, 21 | cy: y, 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/preset-geometry/preset-geometry.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwSp-prstGeom.php 2 | import { XmlComponent } from "file/xml-components"; 3 | import { AdjustmentValues } from "./adjustment-values/adjustment-values"; 4 | import { PresetGeometryAttributes } from "./preset-geometry-attributes"; 5 | 6 | export class PresetGeometry extends XmlComponent { 7 | constructor() { 8 | super("a:prstGeom"); 9 | 10 | this.root.push( 11 | new PresetGeometryAttributes({ 12 | prst: "rect", 13 | }), 14 | ); 15 | 16 | this.root.push(new AdjustmentValues()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/file/table/grid.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 2 | 3 | export class TableGrid extends XmlComponent { 4 | constructor(cols: number[]) { 5 | super("w:tblGrid"); 6 | cols.forEach((col) => this.root.push(new GridCol(col))); 7 | } 8 | } 9 | 10 | class GridColAttributes extends XmlAttributeComponent<{ w: number }> { 11 | protected xmlKeys = { w: "w:w" }; 12 | } 13 | 14 | export class GridCol extends XmlComponent { 15 | constructor(width?: number) { 16 | super("w:gridCol"); 17 | if (width !== undefined) { 18 | this.root.push(new GridColAttributes({ w: width })); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/form.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwSp-size.php 2 | import { XmlComponent } from "file/xml-components"; 3 | import { Extents } from "./extents/extents"; 4 | import { Offset } from "./offset/off"; 5 | 6 | export class Form extends XmlComponent { 7 | private readonly extents: Extents; 8 | 9 | constructor(x: number, y: number) { 10 | super("a:xfrm"); 11 | 12 | this.extents = new Extents(x, y); 13 | 14 | this.root.push(this.extents); 15 | this.root.push(new Offset()); 16 | } 17 | 18 | public setXY(x: number, y: number): void { 19 | this.extents.setXY(x, y); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/file/paragraph/links/bookmark-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IBookmarkStartAttributesProperties { 4 | id: string; 5 | name: string; 6 | } 7 | 8 | export class BookmarkStartAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | id: "w:id", 11 | name: "w:name", 12 | }; 13 | } 14 | 15 | export interface IBookmarkEndAttributesProperties { 16 | id: string; 17 | } 18 | 19 | export class BookmarkEndAttributes extends XmlAttributeComponent { 20 | protected xmlKeys = { 21 | id: "w:id", 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/page-size/page-size.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { PageOrientation, PageSizeAttributes } from "./page-size-attributes"; 3 | 4 | export class PageSize extends XmlComponent { 5 | constructor(width: number, height: number, orientation: PageOrientation) { 6 | super("w:pgSz"); 7 | 8 | const flip = orientation === PageOrientation.LANDSCAPE; 9 | 10 | this.root.push( 11 | new PageSizeAttributes({ 12 | width: flip ? height : width, 13 | height: flip ? width : height, 14 | orientation: orientation, 15 | }), 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /demo/demo1.ts: -------------------------------------------------------------------------------- 1 | // Simple example to add text to a document 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph, TextRun } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const paragraph = new Paragraph("Hello World"); 9 | const institutionText = new TextRun("Foo Bar").bold(); 10 | const dateText = new TextRun("Github is the best").tab().bold(); 11 | paragraph.addRun(institutionText); 12 | paragraph.addRun(dateText); 13 | 14 | doc.addParagraph(paragraph); 15 | 16 | const packer = new Packer(); 17 | 18 | packer.toBuffer(doc).then((buffer) => { 19 | fs.writeFileSync("My Document.docx", buffer); 20 | }); 21 | -------------------------------------------------------------------------------- /demo/demo19.ts: -------------------------------------------------------------------------------- 1 | // Export to base64 string - Useful in a browser environment. 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph, TextRun } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const paragraph = new Paragraph("Hello World"); 9 | const institutionText = new TextRun("Foo").bold(); 10 | const dateText = new TextRun("Bar").tab().bold(); 11 | paragraph.addRun(institutionText); 12 | paragraph.addRun(dateText); 13 | 14 | doc.addParagraph(paragraph); 15 | 16 | const packer = new Packer(); 17 | 18 | packer.toBase64String(doc).then((str) => { 19 | fs.writeFileSync("My Document.docx", str); 20 | }); 21 | -------------------------------------------------------------------------------- /demo/demo17.ts: -------------------------------------------------------------------------------- 1 | // Footnotes 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const paragraph = new Paragraph("Hello World").referenceFootnote(1); 9 | const paragraph2 = new Paragraph("Hello World").referenceFootnote(2); 10 | 11 | doc.addParagraph(paragraph); 12 | doc.addParagraph(paragraph2); 13 | 14 | doc.createFootnote(new Paragraph("Test")); 15 | doc.createFootnote(new Paragraph("My amazing reference")); 16 | 17 | const packer = new Packer(); 18 | 19 | packer.toBuffer(doc).then((buffer) => { 20 | fs.writeFileSync("My Document.docx", buffer); 21 | }); 22 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/page-margin/page-margin-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IPageMarginAttributes { 4 | top?: number; 5 | right?: number; 6 | bottom?: number; 7 | left?: number; 8 | header?: number; 9 | footer?: number; 10 | gutter?: number; 11 | } 12 | 13 | export class PageMarginAttributes extends XmlAttributeComponent { 14 | protected xmlKeys = { 15 | top: "w:top", 16 | right: "w:right", 17 | bottom: "w:bottom", 18 | left: "w:left", 19 | header: "w:header", 20 | footer: "w:footer", 21 | gutter: "w:gutter", 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/blip/blip.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 2 | 3 | interface IBlipProperties { 4 | embed: string; 5 | cstate: string; 6 | } 7 | 8 | class BlipAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | embed: "r:embed", 11 | cstate: "cstate", 12 | }; 13 | } 14 | 15 | export class Blip extends XmlComponent { 16 | constructor(referenceId: number) { 17 | super("a:blip"); 18 | this.root.push( 19 | new BlipAttributes({ 20 | embed: `rId${referenceId}`, 21 | cstate: "none", 22 | }), 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/header-reference/header-reference.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { HeaderReferenceAttributes, HeaderReferenceType } from "./header-reference-attributes"; 3 | 4 | export interface IHeaderOptions { 5 | headerType?: HeaderReferenceType; 6 | headerId?: number; 7 | } 8 | 9 | export class HeaderReference extends XmlComponent { 10 | constructor(options: IHeaderOptions) { 11 | super("w:headerReference"); 12 | this.root.push( 13 | new HeaderReferenceAttributes({ 14 | type: options.headerType || HeaderReferenceType.DEFAULT, 15 | id: `rId${options.headerId}`, 16 | }), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/footer-reference/footer-reference.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { FooterReferenceAttributes, FooterReferenceType } from "./footer-reference-attributes"; 3 | 4 | export interface IFooterOptions { 5 | footerType?: FooterReferenceType; 6 | footerId?: number; 7 | } 8 | 9 | export class FooterReference extends XmlComponent { 10 | constructor(options: IFooterOptions) { 11 | super("w:footerReference"); 12 | 13 | this.root.push( 14 | new FooterReferenceAttributes({ 15 | type: options.footerType || FooterReferenceType.DEFAULT, 16 | id: `rId${options.footerId}`, 17 | }), 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | * [Getting Started](/) 2 | 3 | * [Examples](examples.md) 4 | 5 | * API 6 | 7 | * [Documentation](https://docx.js.org/api/) 8 | 9 | * Usage 10 | 11 | * [Document](usage/document.md) 12 | * [Paragraph](usage/paragraph.md) 13 | * [Text](usage/text.md) 14 | * [Image](usage/images.md) 15 | * [Headers & Footers](usage/headers-and-footers.md) 16 | * [Bullet Points](usage/bullet-points.md) 17 | * [Numbering](usage/numbering.md) 18 | * [Tab Stops](usage/tab-stops.md) 19 | * Styling 20 | * [Styling with JS](usage/styling-with-js.md) 21 | * [Styling with XML](usage/styling-with-xml.md) 22 | * Exporting 23 | 24 | * [Packers](usage/packers.md) 25 | 26 | * [Contribution Guidelines](contribution-guidelines.md) 27 | 28 | -------------------------------------------------------------------------------- /demo/demo26.ts: -------------------------------------------------------------------------------- 1 | // Creates two paragraphs, one with a border and one without 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const paragraph = new Paragraph("No border!"); 9 | 10 | doc.addParagraph(paragraph); 11 | 12 | const borderParagraph = new Paragraph("I have borders on my top and bottom sides!").createBorder(); 13 | borderParagraph.Borders.addTopBorder(); 14 | borderParagraph.Borders.addBottomBorder(); 15 | 16 | doc.addParagraph(borderParagraph); 17 | 18 | const packer = new Packer(); 19 | 20 | packer.toBuffer(doc).then((buffer) => { 21 | fs.writeFileSync("My Document.docx", buffer); 22 | }); 23 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/page-margin/page-margin.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { PageMarginAttributes } from "./page-margin-attributes"; 3 | 4 | export class PageMargin extends XmlComponent { 5 | constructor(top: number, right: number, bottom: number, left: number, header: number, footer: number, gutter: number) { 6 | super("w:pgMar"); 7 | this.root.push( 8 | new PageMarginAttributes({ 9 | top: top, 10 | right: right, 11 | bottom: bottom, 12 | left: left, 13 | header: header, 14 | footer: footer, 15 | gutter: gutter, 16 | }), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/file/paragraph/image.ts: -------------------------------------------------------------------------------- 1 | import { IDrawingOptions } from "../drawing"; 2 | import { IMediaData } from "../media"; 3 | import { Paragraph } from "./paragraph"; 4 | import { PictureRun } from "./run"; 5 | 6 | export class ImageParagraph extends Paragraph { 7 | private readonly pictureRun: PictureRun; 8 | 9 | constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) { 10 | super(); 11 | this.pictureRun = new PictureRun(imageData, drawingOptions); 12 | this.root.push(this.pictureRun); 13 | } 14 | 15 | public scale(factorX: number, factorY?: number): void { 16 | this.pictureRun.scale(factorX, factorY); 17 | } 18 | 19 | public get Run(): PictureRun { 20 | return this.pictureRun; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/title-page/title-page.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | import { Formatter } from "../../../../../export/formatter"; 4 | import { TitlePage } from "./title-page"; 5 | 6 | describe("PageSize", () => { 7 | describe("#constructor()", () => { 8 | it("should create title page property for different first page header", () => { 9 | const properties = new TitlePage(); 10 | const tree = new Formatter().format(properties); 11 | 12 | expect(Object.keys(tree)).to.deep.equal(["w:titlePg"]); 13 | expect(tree["w:titlePg"]).to.be.an.instanceof(Array); 14 | expect(tree["w:titlePg"][0]).to.deep.equal({ _attr: { "w:val": "1" } }); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/spacing.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/WPspacing.php 2 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 3 | 4 | export interface ISpacingProperties { 5 | after?: number; 6 | before?: number; 7 | line?: number; 8 | lineRule?: string; 9 | } 10 | 11 | class SpacingAttributes extends XmlAttributeComponent { 12 | protected xmlKeys = { 13 | after: "w:after", 14 | before: "w:before", 15 | line: "w:line", 16 | lineRule: "w:lineRule", 17 | }; 18 | } 19 | 20 | export class Spacing extends XmlComponent { 21 | constructor(opts: ISpacingProperties) { 22 | super("w:spacing"); 23 | this.root.push(new SpacingAttributes(opts)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/file/styles/defaults/index.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { ParagraphPropertiesDefaults } from "./paragraph-properties"; 3 | import { RunPropertiesDefaults } from "./run-properties"; 4 | 5 | export class DocumentDefaults extends XmlComponent { 6 | private readonly runPropertiesDefaults: RunPropertiesDefaults; 7 | private readonly paragraphPropertiesDefaults: ParagraphPropertiesDefaults; 8 | 9 | constructor() { 10 | super("w:docDefaults"); 11 | this.runPropertiesDefaults = new RunPropertiesDefaults(); 12 | this.paragraphPropertiesDefaults = new ParagraphPropertiesDefaults(); 13 | this.root.push(this.runPropertiesDefaults); 14 | this.root.push(this.paragraphPropertiesDefaults); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/form/extents/extents.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwSp-size.php 2 | import { XmlComponent } from "file/xml-components"; 3 | import { ExtentsAttributes } from "./extents-attributes"; 4 | 5 | export class Extents extends XmlComponent { 6 | private readonly attributes: ExtentsAttributes; 7 | 8 | constructor(x: number, y: number) { 9 | super("a:ext"); 10 | 11 | this.attributes = new ExtentsAttributes({ 12 | cx: x, 13 | cy: y, 14 | }); 15 | 16 | this.root.push(this.attributes); 17 | } 18 | 19 | public setXY(x: number, y: number): void { 20 | this.attributes.set({ 21 | cx: x, 22 | cy: y, 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/style.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { Style } from "./style"; 5 | 6 | describe("ParagraphStyle", () => { 7 | let style: Style; 8 | 9 | describe("#constructor()", () => { 10 | it("should create a style with given value", () => { 11 | style = new Style("test"); 12 | const newJson = Utility.jsonify(style); 13 | assert.equal(newJson.root[0].root.val, "test"); 14 | }); 15 | 16 | it("should create a style with blank val", () => { 17 | style = new Style(""); 18 | const newJson = Utility.jsonify(style); 19 | assert.equal(newJson.root[0].root.val, ""); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /demo/demo20.ts: -------------------------------------------------------------------------------- 1 | // Add custom borders to table cell 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { BorderStyle, Document, Packer, Paragraph } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const table = doc.createTable(4, 4); 9 | table 10 | .getCell(2, 2) 11 | .addContent(new Paragraph("Hello")) 12 | .CellProperties.Borders.addTopBorder(BorderStyle.DASH_DOT_STROKED, 3, "red") 13 | .addBottomBorder(BorderStyle.DOUBLE, 3, "blue") 14 | .addStartBorder(BorderStyle.DOT_DOT_DASH, 3, "green") 15 | .addEndBorder(BorderStyle.DOT_DOT_DASH, 3, "#ff8000"); 16 | 17 | const packer = new Packer(); 18 | 19 | packer.toBuffer(doc).then((buffer) => { 20 | fs.writeFileSync("My Document.docx", buffer); 21 | }); 22 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | 35 | # build 36 | # build <-- we want this in the package 37 | build-tests 38 | 39 | # vscode 40 | .vscode 41 | 42 | # docs 43 | docs -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/graphic-data.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { GraphicDataAttributes } from "./graphic-data-attribute"; 3 | import { Pic } from "./pic"; 4 | 5 | export class GraphicData extends XmlComponent { 6 | private readonly pic: Pic; 7 | 8 | constructor(referenceId: number, x: number, y: number) { 9 | super("a:graphicData"); 10 | 11 | this.root.push( 12 | new GraphicDataAttributes({ 13 | uri: "http://schemas.openxmlformats.org/drawingml/2006/picture", 14 | }), 15 | ); 16 | 17 | this.pic = new Pic(referenceId, x, y); 18 | 19 | this.root.push(this.pic); 20 | } 21 | 22 | public setXY(x: number, y: number): void { 23 | this.pic.setXY(x, y); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/file/drawing/floating/simple-pos.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicFloating-position.php 2 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 3 | 4 | interface ISimplePosAttributes { 5 | x: number; 6 | y: number; 7 | } 8 | 9 | class SimplePosAttributes extends XmlAttributeComponent { 10 | protected xmlKeys = { 11 | x: "x", 12 | y: "y", 13 | }; 14 | } 15 | 16 | export class SimplePos extends XmlComponent { 17 | constructor() { 18 | super("wp:simplePos"); 19 | 20 | // NOTE: It's not fully supported in Microsoft Word, but this element is needed anyway 21 | this.root.push( 22 | new SimplePosAttributes({ 23 | x: 0, 24 | y: 0, 25 | }), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/page-break.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/WPtextSpecialContent-break.php 2 | import { Attributes, XmlComponent } from "file/xml-components"; 3 | import { Run } from "../run"; 4 | 5 | class Break extends XmlComponent { 6 | constructor() { 7 | super("w:br"); 8 | this.root.push( 9 | new Attributes({ 10 | type: "page", 11 | }), 12 | ); 13 | } 14 | } 15 | 16 | export class PageBreak extends Run { 17 | constructor() { 18 | super(); 19 | this.root.push(new Break()); 20 | } 21 | } 22 | 23 | /** 24 | * Add page break before the paragraph if there is no one added before. 25 | */ 26 | export class PageBreakBefore extends XmlComponent { 27 | constructor() { 28 | super("w:pageBreakBefore"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/indent.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/WPindentation.php 2 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 3 | 4 | export interface IIndentAttributesProperties { 5 | left?: number; 6 | hanging?: number; 7 | firstLine?: number; 8 | start?: number; 9 | end?: number; 10 | } 11 | 12 | class IndentAttributes extends XmlAttributeComponent { 13 | protected xmlKeys = { 14 | left: "w:left", 15 | hanging: "w:hanging", 16 | firstLine: "w:firstLine", 17 | start: "w:start", 18 | end: "w:end", 19 | }; 20 | } 21 | 22 | export class Indent extends XmlComponent { 23 | constructor(attrs: IIndentAttributesProperties) { 24 | super("w:ind"); 25 | this.root.push(new IndentAttributes(attrs)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/file/relationships/relationships.spec.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable:no-string-literal 2 | import { expect } from "chai"; 3 | 4 | import { Formatter } from "../../export/formatter"; 5 | import { Relationships } from "./relationships"; 6 | 7 | describe("Relationships", () => { 8 | describe("#constructor()", () => { 9 | it("should create section properties with options", () => { 10 | const properties = new Relationships(); 11 | const tree = new Formatter().format(properties); 12 | expect(Object.keys(tree)).to.deep.equal(["Relationships"]); 13 | expect(tree["Relationships"]).to.be.an.instanceof(Array); 14 | expect(tree["Relationships"][0]).to.deep.equal({ 15 | _attr: { xmlns: "http://schemas.openxmlformats.org/package/2006/relationships" }, 16 | }); 17 | }); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /demo/demo12.ts: -------------------------------------------------------------------------------- 1 | // Scaling images 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const paragraph = new Paragraph("Hello World"); 9 | doc.addParagraph(paragraph); 10 | 11 | const image = doc.createImage(fs.readFileSync("./demo/images/pizza.gif")); 12 | const image2 = doc.createImage(fs.readFileSync("./demo/images/pizza.gif")); 13 | const image3 = doc.createImage(fs.readFileSync("./demo/images/pizza.gif")); 14 | const image4 = doc.createImage(fs.readFileSync("./demo/images/pizza.gif")); 15 | 16 | image.scale(0.5); 17 | image2.scale(1); 18 | image3.scale(2.5); 19 | image4.scale(4); 20 | 21 | const packer = new Packer(); 22 | 23 | packer.toBuffer(doc).then((buffer) => { 24 | fs.writeFileSync("My Document.docx", buffer); 25 | }); 26 | -------------------------------------------------------------------------------- /src/file/drawing/anchor/anchor-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | import { IDistance } from "../drawing"; 3 | 4 | export interface IAnchorAttributes extends IDistance { 5 | allowOverlap?: "0" | "1"; 6 | behindDoc?: "0" | "1"; 7 | layoutInCell?: "0" | "1"; 8 | locked?: "0" | "1"; 9 | relativeHeight?: number; 10 | simplePos?: "0" | "1"; 11 | } 12 | 13 | export class AnchorAttributes extends XmlAttributeComponent { 14 | protected xmlKeys = { 15 | distT: "distT", 16 | distB: "distB", 17 | distL: "distL", 18 | distR: "distR", 19 | allowOverlap: "allowOverlap", 20 | behindDoc: "behindDoc", 21 | layoutInCell: "layoutInCell", 22 | locked: "locked", 23 | relativeHeight: "relativeHeight", 24 | simplePos: "simplePos", 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /src/file/footnotes/footnote/footnote.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { Paragraph } from "../../paragraph"; 3 | import { FootnoteAttributes } from "./footnote-attributes"; 4 | import { FootnoteRefRun } from "./run/footnote-ref-run"; 5 | 6 | export enum FootnoteType { 7 | SEPERATOR = "separator", 8 | CONTINUATION_SEPERATOR = "continuationSeparator", 9 | } 10 | 11 | export class Footnote extends XmlComponent { 12 | constructor(id: number, type?: FootnoteType) { 13 | super("w:footnote"); 14 | this.root.push( 15 | new FootnoteAttributes({ 16 | type: type, 17 | id: id, 18 | }), 19 | ); 20 | } 21 | 22 | public addParagraph(paragraph: Paragraph): void { 23 | paragraph.addRunToFront(new FootnoteRefRun()); 24 | this.root.push(paragraph); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demo/demo5.ts: -------------------------------------------------------------------------------- 1 | // Example of how to add images to the document - You can use Buffers, UInt8Arrays or Base64 strings 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const paragraph = new Paragraph("Hello World"); 9 | doc.addParagraph(paragraph); 10 | 11 | doc.createImage(fs.readFileSync("./demo/images/image1.jpeg")); 12 | doc.createImage(fs.readFileSync("./demo/images/dog.png").toString("base64")); 13 | doc.createImage(fs.readFileSync("./demo/images/cat.jpg")); 14 | doc.createImage(fs.readFileSync("./demo/images/parrots.bmp")); 15 | doc.createImage(fs.readFileSync("./demo/images/pizza.gif")); 16 | 17 | const packer = new Packer(); 18 | 19 | packer.toBuffer(doc).then((buffer) => { 20 | fs.writeFileSync("My Document.docx", buffer); 21 | }); 22 | -------------------------------------------------------------------------------- /src/file/paragraph/run/run-components/text.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | import { Formatter } from "../../../../export/formatter"; 4 | import { Text } from "./text"; 5 | 6 | describe("Text", () => { 7 | describe("#constructor", () => { 8 | it("creates an empty text run if no text is given", () => { 9 | const t = new Text(""); 10 | const f = new Formatter().format(t); 11 | expect(f).to.deep.equal({ "w:t": [{ _attr: { "xml:space": "preserve" } }] }); 12 | }); 13 | 14 | it("adds the passed in text to the component", () => { 15 | const t = new Text(" this is\n text"); 16 | const f = new Formatter().format(t); 17 | expect(f).to.deep.equal({ 18 | "w:t": [{ _attr: { "xml:space": "preserve" } }, " this is\n text"], 19 | }); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/unordered-list.ts: -------------------------------------------------------------------------------- 1 | import { Attributes, XmlComponent } from "file/xml-components"; 2 | 3 | export class NumberProperties extends XmlComponent { 4 | constructor(numberId: number, indentLevel: number) { 5 | super("w:numPr"); 6 | this.root.push(new IndentLevel(indentLevel)); 7 | this.root.push(new NumberId(numberId)); 8 | } 9 | } 10 | 11 | class IndentLevel extends XmlComponent { 12 | constructor(level: number) { 13 | super("w:ilvl"); 14 | this.root.push( 15 | new Attributes({ 16 | val: level, 17 | }), 18 | ); 19 | } 20 | } 21 | 22 | class NumberId extends XmlComponent { 23 | constructor(id: number) { 24 | super("w:numId"); 25 | this.root.push( 26 | new Attributes({ 27 | val: id, 28 | }), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | entry: "./src/index.ts", 5 | 6 | output: { 7 | path: path.resolve("build"), 8 | filename: "index.js", 9 | libraryTarget: "umd", 10 | }, 11 | 12 | resolve: { 13 | extensions: [".tsx", ".ts", ".js"], 14 | modules: [path.resolve("./src"), "node_modules"], 15 | }, 16 | 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.ts$/, 21 | loaders: ["awesome-typescript-loader"], 22 | }, 23 | { 24 | test: /\.js$/, 25 | use: { 26 | loader:'babel-loader', 27 | options: { presets: ['es2015'] } 28 | }, 29 | } 30 | ], 31 | }, 32 | 33 | // Because docx is now targetting web 34 | // target: 'node', 35 | }; 36 | -------------------------------------------------------------------------------- /docs/usage/document.md: -------------------------------------------------------------------------------- 1 | # Document 2 | 3 | > 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. 4 | 5 | To create a new document, it is very easy: 6 | 7 | ```js 8 | var doc = new docx.Document(); 9 | ``` 10 | 11 | ## Document properties 12 | 13 | You can add properties to the Word document by specifying options, for example: 14 | 15 | ```js 16 | var doc = new docx.Document({ 17 | creator: "Dolan Miu", 18 | description: "My extremely interesting document", 19 | title: "My Document", 20 | }); 21 | ``` 22 | 23 | ### Full list of options: 24 | 25 | ``` 26 | creator 27 | description 28 | title 29 | subject 30 | keywords 31 | lastModifiedBy 32 | revision 33 | ``` 34 | 35 | You can mix and match whatever properties you want, or provide no properties. 36 | -------------------------------------------------------------------------------- /demo/demo14.ts: -------------------------------------------------------------------------------- 1 | // Page numbers 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph, TextRun } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | doc.createParagraph("First Page").pageBreak(); 9 | doc.createParagraph("Second Page"); 10 | 11 | const pageNumber = new TextRun("Page ").pageNumber(); 12 | 13 | const pageoneheader = new Paragraph("First Page Header ").right(); 14 | 15 | pageoneheader.addRun(pageNumber); 16 | const firstPageHeader = doc.createFirstPageHeader(); 17 | firstPageHeader.addParagraph(pageoneheader); 18 | 19 | const pagetwoheader = new Paragraph("My Title ").right(); 20 | 21 | pagetwoheader.addRun(pageNumber); 22 | doc.Header.addParagraph(pagetwoheader); 23 | 24 | const packer = new Packer(); 25 | 26 | packer.toBuffer(doc).then((buffer) => { 27 | fs.writeFileSync("My Document.docx", buffer); 28 | }); 29 | -------------------------------------------------------------------------------- /demo/demo6.ts: -------------------------------------------------------------------------------- 1 | // Example of how to change page borders 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph, TextRun } from "../build"; 5 | 6 | const doc = new Document(undefined, { 7 | top: 0, 8 | right: 0, 9 | bottom: 0, 10 | left: 0, 11 | }); 12 | 13 | const paragraph = new Paragraph("Hello World"); 14 | const institutionText = new TextRun("Foo bar").bold(); 15 | const dateText = new TextRun("Github is the best").tab().bold(); 16 | paragraph.addRun(institutionText); 17 | paragraph.addRun(dateText); 18 | 19 | doc.addParagraph(paragraph); 20 | 21 | doc.createParagraph("Hello World").heading1(); 22 | doc.createParagraph("Foo bar"); 23 | doc.createParagraph("Github is the best"); 24 | 25 | const packer = new Packer(); 26 | 27 | packer.toBuffer(doc).then((buffer) => { 28 | fs.writeFileSync("My Document.docx", buffer); 29 | }); 30 | -------------------------------------------------------------------------------- /src/file/styles/defaults/run-properties.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { Size, SizeComplexScript } from "../../paragraph/run/formatting"; 3 | import { RunProperties } from "../../paragraph/run/properties"; 4 | import { RunFonts } from "../../paragraph/run/run-fonts"; 5 | 6 | export class RunPropertiesDefaults extends XmlComponent { 7 | private readonly properties: RunProperties; 8 | 9 | constructor() { 10 | super("w:rPrDefault"); 11 | this.properties = new RunProperties(); 12 | this.root.push(this.properties); 13 | } 14 | 15 | public size(size: number): RunPropertiesDefaults { 16 | this.properties.push(new Size(size)); 17 | this.properties.push(new SizeComplexScript(size)); 18 | return this; 19 | } 20 | 21 | public font(fontName: string): RunPropertiesDefaults { 22 | this.properties.push(new RunFonts(fontName)); 23 | return this; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/file/styles/latent-styles/exceptions.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 2 | 3 | export interface ILatentStyleExceptionAttributesProperties { 4 | name?: string; 5 | uiPriority?: string; 6 | qFormat?: string; 7 | semiHidden?: string; 8 | unhideWhenUsed?: string; 9 | } 10 | 11 | export class LatentStyleExceptionAttributes extends XmlAttributeComponent { 12 | protected xmlKeys = { 13 | name: "w:name", 14 | uiPriority: "w:uiPriority", 15 | qFormat: "w:qFormat", 16 | semiHidden: "w:semiHidden", 17 | unhideWhenUsed: "w:unhideWhenUsed", 18 | }; 19 | } 20 | 21 | export class LatentStyleException extends XmlComponent { 22 | constructor(attributes: ILatentStyleExceptionAttributesProperties) { 23 | super("w:lsdException"); 24 | this.root.push(new LatentStyleExceptionAttributes(attributes)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/file/paragraph/run/picture-run.ts: -------------------------------------------------------------------------------- 1 | import { Drawing } from "../../drawing"; 2 | import { IDrawingOptions } from "../../drawing/drawing"; 3 | import { IMediaData } from "../../media/data"; 4 | import { Run } from "../run"; 5 | 6 | export class PictureRun extends Run { 7 | private readonly drawing: Drawing; 8 | 9 | constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) { 10 | super(); 11 | 12 | if (imageData === undefined) { 13 | throw new Error("imageData cannot be undefined"); 14 | } 15 | 16 | this.drawing = new Drawing(imageData, drawingOptions); 17 | 18 | this.root.push(this.drawing); 19 | } 20 | 21 | public scale(factorX: number, factorY?: number): void { 22 | if (!factorX) { 23 | factorX = 1; 24 | } 25 | 26 | if (!factorY) { 27 | factorY = factorX; 28 | } 29 | 30 | this.drawing.scale(factorX, factorY); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/file/xml-components/default-attributes.ts: -------------------------------------------------------------------------------- 1 | import { BaseXmlComponent } from "./base"; 2 | import { IXmlableObject } from "./xmlable-object"; 3 | 4 | export type AttributeMap = { [P in keyof T]: string }; 5 | 6 | export abstract class XmlAttributeComponent extends BaseXmlComponent { 7 | protected root: T; 8 | protected xmlKeys: AttributeMap; 9 | 10 | constructor(properties: T) { 11 | super("_attr"); 12 | this.root = properties; 13 | } 14 | 15 | public prepForXml(): IXmlableObject { 16 | const attrs = {}; 17 | Object.keys(this.root).forEach((key) => { 18 | const value = this.root[key]; 19 | if (value !== undefined) { 20 | const newKey = this.xmlKeys[key]; 21 | attrs[newKey] = value; 22 | } 23 | }); 24 | return { _attr: attrs }; 25 | } 26 | 27 | public set(properties: T): void { 28 | this.root = properties; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demo/demo13.ts: -------------------------------------------------------------------------------- 1 | // This example shows 3 styles using XML styles 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph } from "../build"; 5 | 6 | const styles = fs.readFileSync("./demo/assets/custom-styles.xml", "utf-8"); 7 | const doc = new Document({ 8 | title: "Title", 9 | externalStyles: styles, 10 | }); 11 | 12 | doc.createParagraph("Cool Heading Text").heading1(); 13 | 14 | const paragraph = new Paragraph('This is a custom named style from the template "MyFancyStyle"'); 15 | paragraph.style("MyFancyStyle"); 16 | doc.addParagraph(paragraph); 17 | 18 | doc.createParagraph("Some normal text"); 19 | 20 | doc.createParagraph("MyFancyStyle again").style("MyFancyStyle"); 21 | paragraph.style("MyFancyStyle"); 22 | doc.addParagraph(paragraph); 23 | 24 | const packer = new Packer(); 25 | 26 | packer.toBuffer(doc).then((buffer) => { 27 | fs.writeFileSync("My Document.docx", buffer); 28 | }); 29 | -------------------------------------------------------------------------------- /src/file/paragraph/links/hyperlink.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/WPhyperlink.php 2 | 3 | import { XmlComponent } from "file/xml-components"; 4 | import { TextRun } from "../run"; 5 | import { HyperlinkAttributes, IHyperlinkAttributesProperties } from "./hyperlink-attributes"; 6 | 7 | export class Hyperlink extends XmlComponent { 8 | public linkId: number; 9 | 10 | constructor(text: string, relationshipsCount: number, anchor?: string) { 11 | super("w:hyperlink"); 12 | 13 | this.linkId = relationshipsCount + 1; 14 | 15 | const props: IHyperlinkAttributesProperties = { 16 | history: 1, 17 | }; 18 | 19 | if (anchor) { 20 | props.anchor = anchor; 21 | } else { 22 | props.id = `rId${this.linkId}`; 23 | } 24 | 25 | const attributes = new HyperlinkAttributes(props); 26 | this.root.push(attributes); 27 | this.root.push(new TextRun(text).style("Hyperlink")); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/spacing.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | import { Formatter } from "../../../export/formatter"; 4 | import { Spacing } from "./spacing"; 5 | 6 | describe("Spacing", () => { 7 | describe("#constructor", () => { 8 | it("should set the properties given", () => { 9 | const spacing = new Spacing({ before: 100, after: 120, line: 150 }); 10 | const tree = new Formatter().format(spacing); 11 | expect(tree).to.deep.equal({ 12 | "w:spacing": [{ _attr: { "w:after": 120, "w:before": 100, "w:line": 150 } }], 13 | }); 14 | }); 15 | 16 | it("should only set the given properties", () => { 17 | const spacing = new Spacing({ before: 100 }); 18 | const tree = new Formatter().format(spacing); 19 | expect(tree).to.deep.equal({ 20 | "w:spacing": [{ _attr: { "w:before": 100 } }], 21 | }); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 2 | import { GraphicData } from "./graphic-data"; 3 | 4 | interface IGraphicProperties { 5 | a: string; 6 | } 7 | 8 | class GraphicAttributes extends XmlAttributeComponent { 9 | protected xmlKeys = { 10 | a: "xmlns:a", 11 | }; 12 | } 13 | 14 | export class Graphic extends XmlComponent { 15 | private readonly data: GraphicData; 16 | 17 | constructor(referenceId: number, x: number, y: number) { 18 | super("a:graphic"); 19 | this.root.push( 20 | new GraphicAttributes({ 21 | a: "http://schemas.openxmlformats.org/drawingml/2006/main", 22 | }), 23 | ); 24 | 25 | this.data = new GraphicData(referenceId, x, y); 26 | 27 | this.root.push(this.data); 28 | } 29 | 30 | public setXY(x: number, y: number): void { 31 | this.data.setXY(x, y); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/file/paragraph/run/run-fonts.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 2 | 3 | interface IRunFontAttributesProperties { 4 | ascii: string; 5 | cs: string; 6 | eastAsia: string; 7 | hAnsi: string; 8 | hint?: string; 9 | } 10 | 11 | class RunFontAttributes extends XmlAttributeComponent { 12 | protected xmlKeys = { 13 | ascii: "w:ascii", 14 | cs: "w:cs", 15 | eastAsia: "w:eastAsia", 16 | hAnsi: "w:hAnsi", 17 | hint: "w:hint", 18 | }; 19 | } 20 | 21 | export class RunFonts extends XmlComponent { 22 | constructor(ascii: string, hint?: string) { 23 | super("w:rFonts"); 24 | this.root.push( 25 | new RunFontAttributes({ 26 | ascii: ascii, 27 | cs: ascii, 28 | eastAsia: ascii, 29 | hAnsi: ascii, 30 | hint: hint, 31 | }), 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/file/styles/index.ts: -------------------------------------------------------------------------------- 1 | import { BaseXmlComponent, XmlComponent } from "file/xml-components"; 2 | import { DocumentDefaults } from "./defaults"; 3 | import { ParagraphStyle } from "./style"; 4 | export * from "./border"; 5 | 6 | export class Styles extends XmlComponent { 7 | constructor(initialStyles?: BaseXmlComponent) { 8 | super("w:styles"); 9 | if (initialStyles) { 10 | this.root.push(initialStyles); 11 | } 12 | } 13 | 14 | public push(style: XmlComponent): Styles { 15 | this.root.push(style); 16 | return this; 17 | } 18 | 19 | public createDocumentDefaults(): DocumentDefaults { 20 | const defaults = new DocumentDefaults(); 21 | this.push(defaults); 22 | return defaults; 23 | } 24 | 25 | public createParagraphStyle(styleId: string, name?: string): ParagraphStyle { 26 | const para = new ParagraphStyle(styleId, name); 27 | this.push(para); 28 | return para; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/file/xml-components/attribute.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Attributes } from "./"; 4 | 5 | describe("Attribute", () => { 6 | describe("#constructor()", () => { 7 | it("should have val as defined with populated constructor", () => { 8 | const newAttrs = new Attributes({ 9 | val: "test", 10 | }); 11 | const stringifiedJson = JSON.stringify(newAttrs); 12 | const newJson = JSON.parse(stringifiedJson); 13 | assert.equal(newJson.root.val, "test"); 14 | }); 15 | 16 | it("should have space value as defined with populated constructor", () => { 17 | const newAttrs = new Attributes({ 18 | space: "spaceTest", 19 | }); 20 | const stringifiedJson = JSON.stringify(newAttrs); 21 | const newJson = JSON.parse(stringifiedJson); 22 | assert.equal(newJson.root.space, "spaceTest"); 23 | }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /demo/demo22.ts: -------------------------------------------------------------------------------- 1 | // This demo shows right to left for special languages 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, Paragraph, TextRun } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const paragraph1 = new Paragraph().bidirectional(); 9 | const textRun1 = new TextRun("שלום עולם").rightToLeft(); 10 | paragraph1.addRun(textRun1); 11 | doc.addParagraph(paragraph1); 12 | 13 | const paragraph2 = new Paragraph().bidirectional(); 14 | const textRun2 = new TextRun("שלום עולם").bold().rightToLeft(); 15 | paragraph2.addRun(textRun2); 16 | doc.addParagraph(paragraph2); 17 | 18 | const paragraph3 = new Paragraph().bidirectional(); 19 | const textRun3 = new TextRun("שלום עולם").italic().rightToLeft(); 20 | paragraph3.addRun(textRun3); 21 | doc.addParagraph(paragraph3); 22 | 23 | const packer = new Packer(); 24 | 25 | packer.toBuffer(doc).then((buffer) => { 26 | fs.writeFileSync("My Document.docx", buffer); 27 | }); 28 | -------------------------------------------------------------------------------- /src/file/drawing/text-wrap/wrap-tight.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicFloating-textWrap.php 2 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 3 | import { IDistance } from "../drawing"; 4 | 5 | interface IWrapTightAttributes { 6 | distT?: number; 7 | distB?: number; 8 | } 9 | 10 | class WrapTightAttributes extends XmlAttributeComponent { 11 | protected xmlKeys = { 12 | distT: "distT", 13 | distB: "distB", 14 | }; 15 | } 16 | 17 | export class WrapTight extends XmlComponent { 18 | constructor(distanceFromText?: IDistance) { 19 | super("wp:wrapTight"); 20 | 21 | distanceFromText = distanceFromText || { 22 | distT: 0, 23 | distB: 0, 24 | }; 25 | 26 | this.root.push( 27 | new WrapTightAttributes({ 28 | distT: distanceFromText.distT, 29 | distB: distanceFromText.distB, 30 | }), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | 35 | # build 36 | build 37 | build-tests 38 | 39 | # Documentation 40 | docs/api/ 41 | docs/.nojekyll 42 | 43 | # VSCode 44 | .vscode/* 45 | !.vscode/settings.json 46 | !.vscode/tasks.json 47 | !.vscode/launch.json 48 | !.vscode/extensions.json 49 | .history 50 | 51 | # Lock files 52 | package-lock.json 53 | 54 | # Documents 55 | My Document.docx 56 | -------------------------------------------------------------------------------- /src/export/packer/packer.ts: -------------------------------------------------------------------------------- 1 | import { File } from "file"; 2 | import { Compiler } from "./next-compiler"; 3 | 4 | export class Packer { 5 | private readonly compiler: Compiler; 6 | 7 | constructor() { 8 | this.compiler = new Compiler(); 9 | } 10 | 11 | public async toBuffer(file: File): Promise { 12 | const zip = await this.compiler.compile(file); 13 | const zipData = (await zip.generateAsync({ type: "nodebuffer" })) as Buffer; 14 | 15 | return zipData; 16 | } 17 | 18 | public async toBase64String(file: File): Promise { 19 | const zip = await this.compiler.compile(file); 20 | const zipData = (await zip.generateAsync({ type: "base64" })) as string; 21 | 22 | return zipData; 23 | } 24 | 25 | public async toBlob(file: File): Promise { 26 | const zip = await this.compiler.compile(file); 27 | const zipData = (await zip.generateAsync({ type: "blob" })) as Blob; 28 | 29 | return zipData; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/file/paragraph/run/strike.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { DoubleStrike, Strike } from "./formatting"; 5 | 6 | describe("Strike", () => { 7 | let strike: Strike; 8 | 9 | beforeEach(() => { 10 | strike = new Strike(); 11 | }); 12 | 13 | describe("#constructor()", () => { 14 | it("should create a Strike with correct root key", () => { 15 | const newJson = Utility.jsonify(strike); 16 | assert.equal(newJson.rootKey, "w:strike"); 17 | }); 18 | }); 19 | }); 20 | 21 | describe("DoubleStrike", () => { 22 | let strike: DoubleStrike; 23 | 24 | beforeEach(() => { 25 | strike = new DoubleStrike(); 26 | }); 27 | 28 | describe("#constructor()", () => { 29 | it("should create a Double Strike with correct root key", () => { 30 | const newJson = Utility.jsonify(strike); 31 | assert.equal(newJson.rootKey, "w:dstrike"); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/file/paragraph/run/run-fonts.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | import { Formatter } from "../../../export/formatter"; 4 | import { RunFonts } from "./run-fonts"; 5 | 6 | describe("RunFonts", () => { 7 | describe("#constructor()", () => { 8 | it("uses the font name for both ascii and hAnsi", () => { 9 | const tree = new Formatter().format(new RunFonts("Times")); 10 | expect(tree).to.deep.equal({ 11 | "w:rFonts": [{ _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times" } }], 12 | }); 13 | }); 14 | 15 | it("uses hint if given", () => { 16 | const tree = new Formatter().format(new RunFonts("Times", "default")); 17 | expect(tree).to.deep.equal({ 18 | "w:rFonts": [ 19 | { _attr: { "w:ascii": "Times", "w:cs": "Times", "w:eastAsia": "Times", "w:hAnsi": "Times", "w:hint": "default" } }, 20 | ], 21 | }); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /demo/index.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable:no-console 2 | import * as fs from "fs"; 3 | import * as prompt from "prompt"; 4 | import * as shelljs from "shelljs"; 5 | 6 | console.log("What demo do you wish to run? (Enter a number)"); 7 | 8 | const schema = { 9 | properties: { 10 | number: { 11 | pattern: /^[0-9]+$/, 12 | message: "Please enter a number.", 13 | required: true, 14 | }, 15 | }, 16 | }; 17 | 18 | prompt.start(); 19 | 20 | prompt.get(schema, (_, result) => { 21 | const demoNumber = result.number; 22 | const filePath = `./demo/demo${demoNumber}.ts`; 23 | 24 | if (!fs.existsSync(filePath)) { 25 | console.error(`demo${demoNumber} does not exist: ${filePath}`); 26 | return; 27 | } 28 | console.log(`Running demo ${demoNumber}`); 29 | if (shelljs.exec(`npm run ts-node -- ${filePath}`).code === 0) { 30 | console.log("Document created successfully"); 31 | } else { 32 | console.error("Something went wrong with the demo"); 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /src/file/drawing/text-wrap/wrap-top-and-bottom.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicFloating-textWrap.php 2 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 3 | import { IDistance } from "../drawing"; 4 | 5 | interface IWrapTopAndBottomAttributes { 6 | distT?: number; 7 | distB?: number; 8 | } 9 | 10 | class WrapTopAndBottomAttributes extends XmlAttributeComponent { 11 | protected xmlKeys = { 12 | distT: "distT", 13 | distB: "distB", 14 | }; 15 | } 16 | 17 | export class WrapTopAndBottom extends XmlComponent { 18 | constructor(distanceFromText?: IDistance) { 19 | super("wp:wrapTopAndBottom"); 20 | 21 | distanceFromText = distanceFromText || { 22 | distT: 0, 23 | distB: 0, 24 | }; 25 | 26 | this.root.push( 27 | new WrapTopAndBottomAttributes({ 28 | distT: distanceFromText.distT, 29 | distB: distanceFromText.distB, 30 | }), 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/file/drawing/text-wrap/wrap-square.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicFloating-textWrap.php 2 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 3 | import { ITextWrapping, WrapTextOption } from "."; 4 | import { IDistance } from "../drawing"; 5 | 6 | interface IWrapSquareAttributes extends IDistance { 7 | wrapText?: WrapTextOption; 8 | } 9 | 10 | class WrapSquareAttributes extends XmlAttributeComponent { 11 | protected xmlKeys = { 12 | distT: "distT", 13 | distB: "distB", 14 | distL: "distL", 15 | distR: "distR", 16 | wrapText: "wrapText", 17 | }; 18 | } 19 | 20 | export class WrapSquare extends XmlComponent { 21 | constructor(textWrapping: ITextWrapping) { 22 | super("wp:wrapSquare"); 23 | 24 | this.root.push( 25 | new WrapSquareAttributes({ 26 | wrapText: textWrapping.wrapTextOption || WrapTextOption.BOTH_SIDES, 27 | ...textWrapping.distanceFromText, 28 | }), 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/file/footnotes/footnote/run/reference-run.ts: -------------------------------------------------------------------------------- 1 | import { Run } from "file/paragraph/run"; 2 | import { Style } from "file/paragraph/run/style"; 3 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 4 | 5 | export interface IFootNoteReferenceRunAttributesProperties { 6 | id: number; 7 | } 8 | 9 | export class FootNoteReferenceRunAttributes extends XmlAttributeComponent { 10 | protected xmlKeys = { 11 | id: "w:id", 12 | }; 13 | } 14 | 15 | export class FootnoteReference extends XmlComponent { 16 | constructor(id: number) { 17 | super("w:footnoteReference"); 18 | 19 | this.root.push( 20 | new FootNoteReferenceRunAttributes({ 21 | id: id, 22 | }), 23 | ); 24 | } 25 | } 26 | 27 | export class FootnoteReferenceRun extends Run { 28 | constructor(id: number) { 29 | super(); 30 | 31 | this.properties.push(new Style("FootnoteReference")); 32 | 33 | this.root.push(new FootnoteReference(id)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/file/xml-components/xml-component.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../tests/utility"; 4 | import { XmlComponent } from "./"; 5 | 6 | class TestComponent extends XmlComponent {} 7 | 8 | describe("XmlComponent", () => { 9 | let xmlComponent: TestComponent; 10 | 11 | beforeEach(() => { 12 | xmlComponent = new TestComponent("w:test"); 13 | }); 14 | 15 | describe("#constructor()", () => { 16 | it("should create an Xml Component which has the correct rootKey", () => { 17 | const newJson = Utility.jsonify(xmlComponent); 18 | assert.equal(newJson.rootKey, "w:test"); 19 | }); 20 | }); 21 | 22 | describe("#prepForXml()", () => { 23 | it("should skip deleted elements", () => { 24 | const child = new TestComponent("w:test1"); 25 | child.delete(); 26 | xmlComponent.addChildElement(child); 27 | 28 | const xml = xmlComponent.prepForXml(); 29 | assert.equal(xml["w:test"].length, 0); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/file/styles/border/border-style.ts: -------------------------------------------------------------------------------- 1 | export enum BorderStyle { 2 | SINGLE = "single", 3 | DASH_DOT_STROKED = "dashDotStroked", 4 | DASHED = "dashed", 5 | DASH_SMALL_GAP = "dashSmallGap", 6 | DOT_DASH = "dotDash", 7 | DOT_DOT_DASH = "dotDotDash", 8 | DOTTED = "dotted", 9 | DOUBLE = "double", 10 | DOUBLE_WAVE = "doubleWave", 11 | INSET = "inset", 12 | NIL = "nil", 13 | NONE = "none", 14 | OUTSET = "outset", 15 | THICK = "thick", 16 | THICK_THIN_LARGE_GAP = "thickThinLargeGap", 17 | THICK_THIN_MEDIUM_GAP = "thickThinMediumGap", 18 | THICK_THIN_SMALL_GAP = "thickThinSmallGap", 19 | THIN_THICK_LARGE_GAP = "thinThickLargeGap", 20 | THIN_THICK_MEDIUM_GAP = "thinThickMediumGap", 21 | THIN_THICK_SMALL_GAP = "thinThickSmallGap", 22 | THIN_THICK_THIN_LARGE_GAP = "thinThickThinLargeGap", 23 | THIN_THICK_THIN_MEDIUM_GAP = "thinThickThinMediumGap", 24 | THIN_THICK_THIN_SMALL_GAP = "thinThickThinSmallGap", 25 | THREE_D_EMBOSS = "threeDEmboss", 26 | THREE_D_ENGRAVE = "threeDEngrave", 27 | TRIPLE = "triple", 28 | WAVE = "wave", 29 | } 30 | -------------------------------------------------------------------------------- /src/file/relationships/relationships.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { RelationshipsAttributes } from "./attributes"; 3 | import { Relationship, RelationshipType, TargetModeType } from "./relationship/relationship"; 4 | 5 | export class Relationships extends XmlComponent { 6 | constructor() { 7 | super("Relationships"); 8 | this.root.push( 9 | new RelationshipsAttributes({ 10 | xmlns: "http://schemas.openxmlformats.org/package/2006/relationships", 11 | }), 12 | ); 13 | } 14 | 15 | public addRelationship(relationship: Relationship): void { 16 | this.root.push(relationship); 17 | } 18 | 19 | public createRelationship(id: number, type: RelationshipType, target: string, targetMode?: TargetModeType): Relationship { 20 | const relationship = new Relationship(`rId${id}`, type, target, targetMode); 21 | this.addRelationship(relationship); 22 | 23 | return relationship; 24 | } 25 | 26 | public get RelationshipCount(): number { 27 | return this.root.length - 1; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:latest", 3 | "rules": { 4 | "curly": true, 5 | "one-variable-per-declaration": [ 6 | true 7 | ], 8 | "no-any": true, 9 | "no-consecutive-blank-lines": [ 10 | true 11 | ], 12 | "no-require-imports": true, 13 | "member-access": [ 14 | true, 15 | "check-accessor" 16 | ], 17 | "indent": [ 18 | true, 19 | "spaces" 20 | ], 21 | "object-literal-sort-keys": false, 22 | "object-literal-shorthand": false, 23 | "typedef": [ 24 | true, 25 | "call-signature", 26 | "parameter", 27 | "property-declaration" 28 | ], 29 | "max-line-length": [ 30 | false 31 | ], 32 | "max-classes-per-file": [ 33 | false 34 | ], 35 | "no-implicit-dependencies": false, 36 | "no-submodule-imports": false, 37 | "no-null-keyword": true, 38 | "return-undefined": true, 39 | "prefer-readonly": true 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/shape-properties/shape-properties.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwSp-SpPr.php 2 | import { XmlComponent } from "file/xml-components"; 3 | import { Form } from "./form"; 4 | // import { NoFill } from "./no-fill"; 5 | // import { Outline } from "./outline/outline"; 6 | import { PresetGeometry } from "./preset-geometry/preset-geometry"; 7 | import { ShapePropertiesAttributes } from "./shape-properties-attributes"; 8 | 9 | export class ShapeProperties extends XmlComponent { 10 | private readonly form: Form; 11 | 12 | constructor(x: number, y: number) { 13 | super("pic:spPr"); 14 | 15 | this.root.push( 16 | new ShapePropertiesAttributes({ 17 | bwMode: "auto", 18 | }), 19 | ); 20 | 21 | this.form = new Form(x, y); 22 | 23 | this.root.push(this.form); 24 | this.root.push(new PresetGeometry()); 25 | // this.root.push(new NoFill()); 26 | // this.root.push(new Outline()); 27 | } 28 | 29 | public setXY(x: number, y: number): void { 30 | this.form.setXY(x, y); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Dolan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | docx - Generate .docx documents with JavaScript 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/file/drawing/inline/graphic/graphic-data/pic/pic.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPic.php 2 | import { XmlComponent } from "file/xml-components"; 3 | import { BlipFill } from "./blip/blip-fill"; 4 | import { NonVisualPicProperties } from "./non-visual-pic-properties/non-visual-pic-properties"; 5 | import { PicAttributes } from "./pic-attributes"; 6 | import { ShapeProperties } from "./shape-properties/shape-properties"; 7 | 8 | export class Pic extends XmlComponent { 9 | private readonly shapeProperties: ShapeProperties; 10 | 11 | constructor(referenceId: number, x: number, y: number) { 12 | super("pic:pic"); 13 | 14 | this.root.push( 15 | new PicAttributes({ 16 | xmlns: "http://schemas.openxmlformats.org/drawingml/2006/picture", 17 | }), 18 | ); 19 | 20 | this.shapeProperties = new ShapeProperties(x, y); 21 | 22 | this.root.push(new NonVisualPicProperties()); 23 | this.root.push(new BlipFill(referenceId)); 24 | this.root.push(new ShapeProperties(x, y)); 25 | } 26 | 27 | public setXY(x: number, y: number): void { 28 | this.shapeProperties.setXY(x, y); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/file/footnotes/footnotes-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IFootnotesAttributesProperties { 4 | wpc?: string; 5 | mc?: string; 6 | o?: string; 7 | r?: string; 8 | m?: string; 9 | v?: string; 10 | wp14?: string; 11 | wp?: string; 12 | w10?: string; 13 | w?: string; 14 | w14?: string; 15 | w15?: string; 16 | wpg?: string; 17 | wpi?: string; 18 | wne?: string; 19 | wps?: string; 20 | Ignorable?: string; 21 | } 22 | 23 | export class FootnotesAttributes extends XmlAttributeComponent { 24 | protected xmlKeys = { 25 | wpc: "xmlns:wpc", 26 | mc: "xmlns:mc", 27 | o: "xmlns:o", 28 | r: "xmlns:r", 29 | m: "xmlns:m", 30 | v: "xmlns:v", 31 | wp14: "xmlns:wp14", 32 | wp: "xmlns:wp", 33 | w10: "xmlns:w10", 34 | w: "xmlns:w", 35 | w14: "xmlns:w14", 36 | w15: "xmlns:w15", 37 | wpg: "xmlns:wpg", 38 | wpi: "xmlns:wpi", 39 | wne: "xmlns:wne", 40 | wps: "xmlns:wps", 41 | Ignorable: "mc:Ignorable", 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /src/file/footnotes/footnote/footnote.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | import { Formatter } from "../../../export/formatter"; 3 | import { Footnote, FootnoteType } from "./footnote"; 4 | 5 | describe("Footnote", () => { 6 | describe("#constructor", () => { 7 | it("should create a footnote with a footnote type", () => { 8 | const footnote = new Footnote(1, FootnoteType.SEPERATOR); 9 | const tree = new Formatter().format(footnote); 10 | 11 | expect(Object.keys(tree)).to.deep.equal(["w:footnote"]); 12 | expect(tree["w:footnote"]).to.be.an.instanceof(Array); 13 | expect(tree["w:footnote"][0]).to.deep.equal({ _attr: { "w:type": "separator", "w:id": 1 } }); 14 | }); 15 | 16 | it("should create a footnote without a footnote type", () => { 17 | const footnote = new Footnote(1); 18 | const tree = new Formatter().format(footnote); 19 | 20 | expect(Object.keys(tree)).to.deep.equal(["w:footnote"]); 21 | expect(tree["w:footnote"]).to.be.an.instanceof(Array); 22 | expect(tree["w:footnote"][0]).to.deep.equal({ _attr: { "w:id": 1 } }); 23 | }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /demo/browser-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

DOCX browser Word document generation

12 | 13 | 14 | 15 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/file/paragraph/run/page-number.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 2 | 3 | class FidCharAttrs extends XmlAttributeComponent<{ type: "begin" | "end" | "separate" }> { 4 | protected xmlKeys = { type: "w:fldCharType" }; 5 | } 6 | 7 | class TextAttributes extends XmlAttributeComponent<{ space: "default" | "preserve" }> { 8 | protected xmlKeys = { space: "xml:space" }; 9 | } 10 | 11 | export class Begin extends XmlComponent { 12 | constructor() { 13 | super("w:fldChar"); 14 | this.root.push(new FidCharAttrs({ type: "begin" })); 15 | } 16 | } 17 | 18 | export class Page extends XmlComponent { 19 | constructor() { 20 | super("w:instrText"); 21 | this.root.push(new TextAttributes({ space: "preserve" })); 22 | this.root.push("PAGE"); 23 | } 24 | } 25 | 26 | export class Separate extends XmlComponent { 27 | constructor() { 28 | super("w:fldChar"); 29 | this.root.push(new FidCharAttrs({ type: "separate" })); 30 | } 31 | } 32 | 33 | export class End extends XmlComponent { 34 | constructor() { 35 | super("w:fldChar"); 36 | this.root.push(new FidCharAttrs({ type: "end" })); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /docs/usage/headers-and-footers.md: -------------------------------------------------------------------------------- 1 | # Headers and Footers 2 | 3 | ## Example 4 | 5 | Creating Headers and footers is simple. Access the `Header` and `Footer` by doing so like this: 6 | 7 | ```js 8 | doc.Header; 9 | doc.Footer; 10 | ``` 11 | 12 | You can call the same methods as you would with a `File`: 13 | 14 | ```js 15 | doc.Header.createParagraph("Header text"); 16 | doc.Footer.createParagraph("Footer text"); 17 | ``` 18 | 19 | Even add images: 20 | 21 | ```js 22 | doc.Header.createImage([BUFFER_OF_YOUR_IMAGE]); 23 | doc.Footer.createImage([BUFFER_OF_YOUR_IMAGE]); 24 | ``` 25 | 26 | Refer to `demo8.js` for more information 27 | 28 | ## Multiple Headers and Footers 29 | 30 | Also all the supported section properties are implemented according to: http://officeopenxml.com/WPsection.php 31 | 32 | ### Example 33 | 34 | ```js 35 | const header = this.document.createHeader(); 36 | const footer = this.document.createFooter(); 37 | 38 | // Add new section with another header and footer 39 | doc.addSection({ 40 | headerId: header.Header.ReferenceId, 41 | footerId: footer.Footer.ReferenceId, 42 | pageNumberStart: 1, 43 | pageNumberFormatType: docx.PageNumberFormat.DECIMAL, 44 | }); 45 | ``` 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/unordered-list.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { NumberProperties } from "./unordered-list"; 5 | 6 | describe("NumberProperties", () => { 7 | let numberProperties: NumberProperties; 8 | 9 | beforeEach(() => { 10 | numberProperties = new NumberProperties(5, 10); 11 | }); 12 | 13 | describe("#constructor()", () => { 14 | it("should create a Number Properties with correct root key", () => { 15 | const newJson = Utility.jsonify(numberProperties); 16 | assert.equal(newJson.rootKey, "w:numPr"); 17 | }); 18 | 19 | it("should create a Page Break with a Indent Level inside", () => { 20 | const newJson = Utility.jsonify(numberProperties); 21 | assert.equal(newJson.root[0].rootKey, "w:ilvl"); 22 | assert.equal(newJson.root[0].root[0].root.val, 10); 23 | }); 24 | 25 | it("should create a Page Break with a Number Id inside", () => { 26 | const newJson = Utility.jsonify(numberProperties); 27 | assert.equal(newJson.root[1].rootKey, "w:numId"); 28 | assert.equal(newJson.root[1].root[0].root.val, 5); 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /demo/demo16.ts: -------------------------------------------------------------------------------- 1 | // Multiple sections and headers 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer, PageNumberFormat, PageOrientation, Paragraph } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const paragraph = new Paragraph("Hello World").pageBreak(); 9 | 10 | doc.addParagraph(paragraph); 11 | 12 | const header = doc.createHeader(); 13 | header.createParagraph("Header on another page"); 14 | const footer = doc.createFooter(); 15 | footer.createParagraph("Footer on another page"); 16 | 17 | doc.addSection({ 18 | headerId: header.Header.ReferenceId, 19 | footerId: footer.Footer.ReferenceId, 20 | pageNumberStart: 1, 21 | pageNumberFormatType: PageNumberFormat.DECIMAL, 22 | }); 23 | 24 | doc.createParagraph("hello"); 25 | 26 | doc.addSection({ 27 | headerId: header.Header.ReferenceId, 28 | footerId: footer.Footer.ReferenceId, 29 | pageNumberStart: 1, 30 | pageNumberFormatType: PageNumberFormat.DECIMAL, 31 | orientation: PageOrientation.LANDSCAPE, 32 | }); 33 | 34 | doc.createParagraph("hello in landscape"); 35 | 36 | const packer = new Packer(); 37 | 38 | packer.toBuffer(doc).then((buffer) => { 39 | fs.writeFileSync("My Document.docx", buffer); 40 | }); 41 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/border.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { ThematicBreak } from "./border"; 5 | 6 | describe("Border", () => { 7 | // TODO: Need tests here 8 | }); 9 | 10 | describe("ThematicBreak", () => { 11 | let thematicBreak: ThematicBreak; 12 | 13 | beforeEach(() => { 14 | thematicBreak = new ThematicBreak(); 15 | }); 16 | 17 | describe("#constructor()", () => { 18 | it("should create valid JSON", () => { 19 | const stringifiedJson = JSON.stringify(thematicBreak); 20 | 21 | try { 22 | JSON.parse(stringifiedJson); 23 | } catch (e) { 24 | assert.isTrue(false); 25 | } 26 | assert.isTrue(true); 27 | }); 28 | 29 | it("should create a Thematic Break with correct border properties", () => { 30 | const newJson = Utility.jsonify(thematicBreak); 31 | const attributes = { 32 | color: "auto", 33 | space: "1", 34 | val: "single", 35 | sz: "6", 36 | }; 37 | assert.equal(JSON.stringify(newJson.root[0].root[0].root), JSON.stringify(attributes)); 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/page-size/page-size.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | import { Formatter } from "../../../../../export/formatter"; 4 | import { PageSize } from "./page-size"; 5 | import { PageOrientation } from "./page-size-attributes"; 6 | 7 | describe("PageSize", () => { 8 | describe("#constructor()", () => { 9 | it("should create page size with portrait", () => { 10 | const properties = new PageSize(100, 200, PageOrientation.PORTRAIT); 11 | const tree = new Formatter().format(properties); 12 | 13 | expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]); 14 | expect(tree["w:pgSz"]).to.be.an.instanceof(Array); 15 | expect(tree["w:pgSz"][0]).to.deep.equal({ _attr: { "w:h": 200, "w:w": 100, "w:orient": "portrait" } }); 16 | }); 17 | 18 | it("should create page size with horizontal and invert the lengths", () => { 19 | const properties = new PageSize(100, 200, PageOrientation.LANDSCAPE); 20 | const tree = new Formatter().format(properties); 21 | 22 | expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]); 23 | expect(tree["w:pgSz"]).to.be.an.instanceof(Array); 24 | expect(tree["w:pgSz"][0]).to.deep.equal({ _attr: { "w:h": 100, "w:w": 200, "w:orient": "landscape" } }); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es6", "dom"], 5 | "strictNullChecks": true, 6 | "sourceMap": true, 7 | "removeComments": true, 8 | "preserveConstEnums": true, 9 | "outDir": "./build", 10 | "rootDir": "./src", 11 | "module": "commonjs", 12 | "declaration": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "baseUrl": "./src", 16 | "paths" : { 17 | "/*": [ 18 | "./*" 19 | ] 20 | } 21 | }, 22 | "exclude": [ 23 | "node_modules", 24 | "tests", 25 | "**/_*", 26 | "demo" 27 | ], 28 | "typedocOptions": { 29 | "mode": "file", 30 | "out": "docs/api", 31 | "exclude": "test", 32 | "theme": "default", 33 | "ignoreCompilerErrors": true, 34 | "excludePrivate": true, 35 | "excludeProtected": true, 36 | "excludeNotExported": true, 37 | "excludeExternals": false, 38 | "target": "ES5", 39 | "moduleResolution": "node", 40 | "preserveConstEnums": true, 41 | "stripInternal": true, 42 | "suppressExcessPropertyErrors": true, 43 | "suppressImplicitAnyIndexErrors": true, 44 | "module": "commonjs" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/file/xml-components/attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "./default-attributes"; 2 | 3 | export interface IAttributesProperties { 4 | val?: string | number | boolean; 5 | color?: string; 6 | space?: string; 7 | sz?: string; 8 | type?: string; 9 | rsidR?: string; 10 | rsidRPr?: string; 11 | rsidSect?: string; 12 | w?: string; 13 | h?: string; 14 | top?: string; 15 | right?: string; 16 | bottom?: string; 17 | left?: string; 18 | header?: string; 19 | footer?: string; 20 | gutter?: string; 21 | linePitch?: string; 22 | pos?: string | number; // Little strange. Perhaps it is normal. Need to clarify in the spec. 23 | } 24 | 25 | export class Attributes extends XmlAttributeComponent { 26 | protected xmlKeys = { 27 | val: "w:val", 28 | color: "w:color", 29 | space: "w:space", 30 | sz: "w:sz", 31 | type: "w:type", 32 | rsidR: "w:rsidR", 33 | rsidRPr: "w:rsidRPr", 34 | rsidSect: "w:rsidSect", 35 | w: "w:w", 36 | h: "w:h", 37 | top: "w:top", 38 | right: "w:right", 39 | bottom: "w:bottom", 40 | left: "w:left", 41 | header: "w:header", 42 | footer: "w:footer", 43 | gutter: "w:gutter", 44 | linePitch: "w:linePitch", 45 | pos: "w:pos", 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /src/file/xml-components/xml-component.ts: -------------------------------------------------------------------------------- 1 | import { BaseXmlComponent } from "./base"; 2 | import { IXmlableObject } from "./xmlable-object"; 3 | export { BaseXmlComponent }; 4 | 5 | export abstract class XmlComponent extends BaseXmlComponent { 6 | protected root: Array; 7 | 8 | constructor(rootKey: string) { 9 | super(rootKey); 10 | this.root = new Array(); 11 | } 12 | 13 | public prepForXml(): IXmlableObject { 14 | const children = this.root 15 | .filter((c) => { 16 | if (c instanceof BaseXmlComponent) { 17 | return !c.IsDeleted; 18 | } 19 | return true; 20 | }) 21 | .map((comp) => { 22 | if (comp instanceof BaseXmlComponent) { 23 | return comp.prepForXml(); 24 | } 25 | return comp; 26 | }) 27 | .filter((comp) => comp); // Exclude null, undefined, and empty strings 28 | return { 29 | [this.rootKey]: children, 30 | }; 31 | } 32 | 33 | // TODO: Unused method 34 | public addChildElement(child: XmlComponent | string): XmlComponent { 35 | this.root.push(child); 36 | 37 | return this; 38 | } 39 | 40 | public delete(): void { 41 | this.deleted = true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/file/drawing/floating/vertical-position.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicFloating-position.php 2 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 3 | import { Align } from "./align"; 4 | import { IVerticalPositionOptions, VerticalPositionRelativeFrom } from "./floating-position"; 5 | import { PositionOffset } from "./position-offset"; 6 | 7 | interface IVerticalPositionAttributes { 8 | relativeFrom: VerticalPositionRelativeFrom; 9 | } 10 | 11 | class VerticalPositionAttributes extends XmlAttributeComponent { 12 | protected xmlKeys = { 13 | relativeFrom: "relativeFrom", 14 | }; 15 | } 16 | 17 | export class VerticalPosition extends XmlComponent { 18 | constructor(verticalPosition: IVerticalPositionOptions) { 19 | super("wp:positionV"); 20 | 21 | this.root.push( 22 | new VerticalPositionAttributes({ 23 | relativeFrom: verticalPosition.relative, 24 | }), 25 | ); 26 | 27 | if (verticalPosition.align) { 28 | this.root.push(new Align(verticalPosition.align)); 29 | } else if (verticalPosition.offset !== undefined) { 30 | this.root.push(new PositionOffset(verticalPosition.offset)); 31 | } else { 32 | throw new Error("There is no configuration provided for floating position (Align or offset)"); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/file/footer/footer-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IFooterAttributesProperties { 4 | wpc?: string; 5 | mc?: string; 6 | o?: string; 7 | r?: string; 8 | m?: string; 9 | v?: string; 10 | wp14?: string; 11 | wp?: string; 12 | w10?: string; 13 | w?: string; 14 | w14?: string; 15 | w15?: string; 16 | wpg?: string; 17 | wpi?: string; 18 | wne?: string; 19 | wps?: string; 20 | cp?: string; 21 | dc?: string; 22 | dcterms?: string; 23 | dcmitype?: string; 24 | xsi?: string; 25 | type?: string; 26 | } 27 | 28 | export class FooterAttributes extends XmlAttributeComponent { 29 | protected xmlKeys = { 30 | wpc: "xmlns:wpc", 31 | mc: "xmlns:mc", 32 | o: "xmlns:o", 33 | r: "xmlns:r", 34 | m: "xmlns:m", 35 | v: "xmlns:v", 36 | wp14: "xmlns:wp14", 37 | wp: "xmlns:wp", 38 | w10: "xmlns:w10", 39 | w: "xmlns:w", 40 | w14: "xmlns:w14", 41 | w15: "xmlns:w15", 42 | wpg: "xmlns:wpg", 43 | wpi: "xmlns:wpi", 44 | wne: "xmlns:wne", 45 | wps: "xmlns:wps", 46 | cp: "xmlns:cp", 47 | dc: "xmlns:dc", 48 | dcterms: "xmlns:dcterms", 49 | dcmitype: "xmlns:dcmitype", 50 | xsi: "xmlns:xsi", 51 | type: "xsi:type", 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /src/file/header/header-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IHeaderAttributesProperties { 4 | wpc?: string; 5 | mc?: string; 6 | o?: string; 7 | r?: string; 8 | m?: string; 9 | v?: string; 10 | wp14?: string; 11 | wp?: string; 12 | w10?: string; 13 | w?: string; 14 | w14?: string; 15 | w15?: string; 16 | wpg?: string; 17 | wpi?: string; 18 | wne?: string; 19 | wps?: string; 20 | cp?: string; 21 | dc?: string; 22 | dcterms?: string; 23 | dcmitype?: string; 24 | xsi?: string; 25 | type?: string; 26 | } 27 | 28 | export class HeaderAttributes extends XmlAttributeComponent { 29 | protected xmlKeys = { 30 | wpc: "xmlns:wpc", 31 | mc: "xmlns:mc", 32 | o: "xmlns:o", 33 | r: "xmlns:r", 34 | m: "xmlns:m", 35 | v: "xmlns:v", 36 | wp14: "xmlns:wp14", 37 | wp: "xmlns:wp", 38 | w10: "xmlns:w10", 39 | w: "xmlns:w", 40 | w14: "xmlns:w14", 41 | w15: "xmlns:w15", 42 | wpg: "xmlns:wpg", 43 | wpi: "xmlns:wpi", 44 | wne: "xmlns:wne", 45 | wps: "xmlns:wps", 46 | cp: "xmlns:cp", 47 | dc: "xmlns:dc", 48 | dcterms: "xmlns:dcterms", 49 | dcmitype: "xmlns:dcmitype", 50 | xsi: "xmlns:xsi", 51 | type: "xsi:type", 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /src/file/numbering/abstract-numbering.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 2 | import { Level } from "./level"; 3 | import { MultiLevelType } from "./multi-level-type"; 4 | 5 | interface IAbstractNumberingAttributesProperties { 6 | abstractNumId?: number; 7 | restartNumberingAfterBreak?: number; 8 | } 9 | 10 | class AbstractNumberingAttributes extends XmlAttributeComponent { 11 | protected xmlKeys = { 12 | abstractNumId: "w:abstractNumId", 13 | restartNumberingAfterBreak: "w15:restartNumberingAfterBreak", 14 | }; 15 | } 16 | 17 | export class AbstractNumbering extends XmlComponent { 18 | public id: number; 19 | 20 | constructor(id: number) { 21 | super("w:abstractNum"); 22 | this.root.push( 23 | new AbstractNumberingAttributes({ 24 | abstractNumId: id, 25 | restartNumberingAfterBreak: 0, 26 | }), 27 | ); 28 | this.root.push(new MultiLevelType("hybridMultilevel")); 29 | this.id = id; 30 | } 31 | 32 | public addLevel(level: Level): void { 33 | this.root.push(level); 34 | } 35 | 36 | public createLevel(num: number, format: string, text: string, align: string = "start"): Level { 37 | const level = new Level(num, format, text, align); 38 | this.addLevel(level); 39 | return level; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/file/drawing/floating/horizontal-position.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicFloating-position.php 2 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 3 | import { Align } from "./align"; 4 | import { HorizontalPositionRelativeFrom, IHorizontalPositionOptions } from "./floating-position"; 5 | import { PositionOffset } from "./position-offset"; 6 | 7 | interface IHorizontalPositionAttributes { 8 | relativeFrom: HorizontalPositionRelativeFrom; 9 | } 10 | 11 | class HorizontalPositionAttributes extends XmlAttributeComponent { 12 | protected xmlKeys = { 13 | relativeFrom: "relativeFrom", 14 | }; 15 | } 16 | 17 | export class HorizontalPosition extends XmlComponent { 18 | constructor(horizontalPosition: IHorizontalPositionOptions) { 19 | super("wp:positionH"); 20 | 21 | this.root.push( 22 | new HorizontalPositionAttributes({ 23 | relativeFrom: horizontalPosition.relative, 24 | }), 25 | ); 26 | 27 | if (horizontalPosition.align) { 28 | this.root.push(new Align(horizontalPosition.align)); 29 | } else if (horizontalPosition.offset !== undefined) { 30 | this.root.push(new PositionOffset(horizontalPosition.offset)); 31 | } else { 32 | throw new Error("There is no configuration provided for floating position (Align or offset)"); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 |

2 | clippy the assistant 3 |

4 | 5 |

6 | Easily generate .docx files with JS/TS. Works for Node and on the Browser. :100: 7 |

8 | 9 | --- 10 | 11 | # Welcome 12 | 13 | ## Installation 14 | 15 | ```sh 16 | npm install --save docx 17 | ``` 18 | 19 | Then you can `require` or `import` as usual: 20 | 21 | ```js 22 | let docx = require("docx"); 23 | ``` 24 | 25 | ```js 26 | import * as docx from "docx"; 27 | ``` 28 | 29 | ## Basic Usage 30 | 31 | ```js 32 | var docx = require("docx"); 33 | 34 | // Create document 35 | var doc = new docx.Document(); 36 | 37 | // Add some content in the document 38 | var paragraph = new docx.Paragraph("Some cool text here."); 39 | // Add more text into the paragraph if you wish 40 | paragraph.addRun(new docx.TextRun("Lorem Ipsum Foo Bar")); 41 | doc.addParagraph(paragraph); 42 | 43 | // Used to export the file into a .docx file 44 | var exporter = new docx.LocalPacker(doc); 45 | 46 | exporter.pack("My First Document"); 47 | 48 | // Done! A file called 'My First Document.docx' will be in your file system if you used LocalPacker 49 | ``` 50 | 51 | ## Honoured Mentions 52 | 53 | [@felipeochoa](https://github.com/felipeochoa) 54 | 55 | [@h4buli](https://github.com/h4buli) 56 | 57 |

58 | clippy the assistant 59 |

60 | 61 | --- 62 | 63 | Made with 💖 64 | -------------------------------------------------------------------------------- /src/file/table/grid.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | import { Formatter } from "../../export/formatter"; 4 | import { GridCol, TableGrid } from "./grid"; 5 | 6 | describe("GridCol", () => { 7 | describe("#constructor", () => { 8 | it("sets the width attribute to the value given", () => { 9 | const grid = new GridCol(1234); 10 | const tree = new Formatter().format(grid); 11 | expect(tree).to.deep.equal({ 12 | "w:gridCol": [{ _attr: { "w:w": 1234 } }], 13 | }); 14 | }); 15 | 16 | it("does not set a width attribute if not given", () => { 17 | const grid = new GridCol(); 18 | const tree = new Formatter().format(grid); 19 | expect(tree).to.deep.equal({ "w:gridCol": [] }); 20 | }); 21 | }); 22 | }); 23 | 24 | describe("TableGrid", () => { 25 | describe("#constructor", () => { 26 | it("creates a column for each width given", () => { 27 | const grid = new TableGrid([1234, 321, 123]); 28 | const tree = new Formatter().format(grid); 29 | expect(tree).to.deep.equal({ 30 | "w:tblGrid": [ 31 | { "w:gridCol": [{ _attr: { "w:w": 1234 } }] }, 32 | { "w:gridCol": [{ _attr: { "w:w": 321 } }] }, 33 | { "w:gridCol": [{ _attr: { "w:w": 123 } }] }, 34 | ], 35 | }); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/page-break.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { PageBreak, PageBreakBefore } from "./page-break"; 5 | 6 | describe("PageBreak", () => { 7 | let pageBreak: PageBreak; 8 | 9 | beforeEach(() => { 10 | pageBreak = new PageBreak(); 11 | }); 12 | 13 | describe("#constructor()", () => { 14 | it("should create a Page Break with correct attributes", () => { 15 | const newJson = Utility.jsonify(pageBreak); 16 | const attributes = { 17 | type: "page", 18 | }; 19 | assert.equal(JSON.stringify(newJson.root[1].root[0].root), JSON.stringify(attributes)); 20 | }); 21 | 22 | it("should create a Page Break with w:r", () => { 23 | const newJson = Utility.jsonify(pageBreak); 24 | assert.equal(newJson.rootKey, "w:r"); 25 | }); 26 | 27 | it("should create a Page Break with a Break inside", () => { 28 | const newJson = Utility.jsonify(pageBreak); 29 | assert.equal(newJson.root[1].rootKey, "w:br"); 30 | }); 31 | }); 32 | }); 33 | 34 | describe("PageBreakBefore", () => { 35 | it("should create page break before", () => { 36 | const pageBreakBefore = new PageBreakBefore(); 37 | const newJson = Utility.jsonify(pageBreakBefore); 38 | assert.equal(newJson.rootKey, "w:pageBreakBefore"); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /docs/usage/text.md: -------------------------------------------------------------------------------- 1 | # Text 2 | 3 | Paragraphs need `text run` objects. To create text: 4 | 5 | ```js 6 | var text = new docx.TextRun("My awesome text here for my university dissertation"); 7 | paragraph.addRun(text); 8 | ``` 9 | 10 | Text objects have methods inside which changes the way the text is displayed. 11 | 12 | ## Typographical Emphasis 13 | 14 | More info [here](https://english.stackexchange.com/questions/97081/what-is-the-typography-term-which-refers-to-the-usage-of-bold-italics-and-unde) 15 | 16 | ### Bold 17 | 18 | ```js 19 | text.bold(); 20 | ``` 21 | 22 | ### Italics 23 | 24 | ```js 25 | text.italic(); 26 | ``` 27 | 28 | ### Underline 29 | 30 | ```js 31 | text.underline(); 32 | ``` 33 | 34 | ### Strike through 35 | 36 | ```js 37 | text.strike(); 38 | ``` 39 | 40 | ### Double strike through 41 | 42 | ```js 43 | text.doubleStrike(); 44 | ``` 45 | 46 | ### Superscript 47 | 48 | ```js 49 | text.superScript(); 50 | ``` 51 | 52 | ### Subscript 53 | 54 | ```js 55 | text.subScript(); 56 | ``` 57 | 58 | ### All Capitals 59 | 60 | ```js 61 | text.allCaps(); 62 | ``` 63 | 64 | ### Small Capitals 65 | 66 | ```js 67 | text.smallCaps(); 68 | ``` 69 | 70 | ## Break 71 | 72 | Sometimes you would want to put text underneath another line of text but inside the same paragraph. 73 | 74 | ```js 75 | text.break(); 76 | ``` 77 | 78 | ## Chaining 79 | 80 | What if you want to create a paragraph which is **_bold_** and **_italic_**? 81 | 82 | ```js 83 | paragraph.bold().italic(); 84 | ``` 85 | -------------------------------------------------------------------------------- /src/file/document/body/section-properties/page-number/page-number.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/WPSectionPgNumType.php 2 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 3 | 4 | export enum PageNumberFormat { 5 | CARDINAL_TEXT = "cardinalText", 6 | DECIMAL = "decimal", 7 | DECIMAL_ENCLOSED_CIRCLE = "decimalEnclosedCircle", 8 | DECIMAL_ENCLOSED_FULL_STOP = "decimalEnclosedFullstop", 9 | DECIMAL_ENCLOSED_PAREN = "decimalEnclosedParen", 10 | DECIMAL_ZERO = "decimalZero", 11 | LOWER_LETTER = "lowerLetter", 12 | LOWER_ROMAN = "lowerRoman", 13 | NONE = "none", 14 | ORDINAL_TEXT = "ordinalText", 15 | UPPER_LETTER = "upperLetter", 16 | UPPER_ROMAN = "upperRoman", 17 | } 18 | 19 | export interface IPageNumberTypeAttributes { 20 | pageNumberStart?: number; 21 | pageNumberFormatType?: PageNumberFormat; 22 | } 23 | 24 | export class PageNumberTypeAttributes extends XmlAttributeComponent { 25 | protected xmlKeys = { 26 | pageNumberStart: "w:start", 27 | pageNumberFormatType: "w:fmt", 28 | }; 29 | } 30 | 31 | export class PageNumberType extends XmlComponent { 32 | constructor(start?: number, numberFormat?: PageNumberFormat) { 33 | super("w:pgNumType"); 34 | this.root.push( 35 | new PageNumberTypeAttributes({ 36 | pageNumberStart: start, 37 | pageNumberFormatType: numberFormat, 38 | }), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/file/document/document-attributes.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent } from "file/xml-components"; 2 | 3 | export interface IDocumentAttributesProperties { 4 | wpc?: string; 5 | mc?: string; 6 | o?: string; 7 | r?: string; 8 | m?: string; 9 | v?: string; 10 | wp14?: string; 11 | wp?: string; 12 | w10?: string; 13 | w?: string; 14 | w14?: string; 15 | w15?: string; 16 | wpg?: string; 17 | wpi?: string; 18 | wne?: string; 19 | wps?: string; 20 | Ignorable?: string; 21 | cp?: string; 22 | dc?: string; 23 | dcterms?: string; 24 | dcmitype?: string; 25 | xsi?: string; 26 | type?: string; 27 | } 28 | 29 | export class DocumentAttributes extends XmlAttributeComponent { 30 | protected xmlKeys = { 31 | wpc: "xmlns:wpc", 32 | mc: "xmlns:mc", 33 | o: "xmlns:o", 34 | r: "xmlns:r", 35 | m: "xmlns:m", 36 | v: "xmlns:v", 37 | wp14: "xmlns:wp14", 38 | wp: "xmlns:wp", 39 | w10: "xmlns:w10", 40 | w: "xmlns:w", 41 | w14: "xmlns:w14", 42 | w15: "xmlns:w15", 43 | wpg: "xmlns:wpg", 44 | wpi: "xmlns:wpi", 45 | wne: "xmlns:wne", 46 | wps: "xmlns:wps", 47 | Ignorable: "mc:Ignorable", 48 | cp: "xmlns:cp", 49 | dc: "xmlns:dc", 50 | dcterms: "xmlns:dcterms", 51 | dcmitype: "xmlns:dcmitype", 52 | xsi: "xmlns:xsi", 53 | type: "xsi:type", 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/tab-stop.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/WPtab.php 2 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 3 | 4 | export class TabStop extends XmlComponent { 5 | constructor(tab: Tab) { 6 | super("w:tabs"); 7 | this.root.push(tab); 8 | } 9 | } 10 | 11 | export type TabValue = "left" | "right" | "center" | "bar" | "clear" | "decimal" | "end" | "num" | "start"; 12 | 13 | export class TabAttributes extends XmlAttributeComponent<{ val: TabValue; pos: string | number }> { 14 | protected xmlKeys = { val: "w:val", pos: "w:pos" }; 15 | } 16 | 17 | export class Tab extends XmlComponent { 18 | constructor(value: TabValue, position: string | number) { 19 | super("w:tab"); 20 | this.root.push( 21 | new TabAttributes({ 22 | val: value, 23 | pos: position, 24 | }), 25 | ); 26 | } 27 | } 28 | 29 | export class MaxRightTabStop extends TabStop { 30 | constructor() { 31 | super(new Tab("right", 9026)); 32 | } 33 | } 34 | 35 | export class LeftTabStop extends TabStop { 36 | constructor(position: number) { 37 | super(new Tab("left", position)); 38 | } 39 | } 40 | 41 | export class RightTabStop extends TabStop { 42 | constructor(position: number) { 43 | super(new Tab("right", position)); 44 | } 45 | } 46 | 47 | export class CenterTabStop extends TabStop { 48 | constructor(position: number) { 49 | super(new Tab("center", position)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 9 4 | install: 5 | - npm install 6 | script: 7 | - npm run lint 8 | - npm test 9 | - npm run style 10 | - npm run build 11 | - npm run ts-node -- ./demo/demo1.ts 12 | - npm run ts-node -- ./demo/demo2.ts 13 | - npm run ts-node -- ./demo/demo3.ts 14 | - npm run ts-node -- ./demo/demo4.ts 15 | - npm run ts-node -- ./demo/demo5.ts 16 | - npm run ts-node -- ./demo/demo6.ts 17 | - npm run ts-node -- ./demo/demo7.ts 18 | - npm run ts-node -- ./demo/demo8.ts 19 | - npm run ts-node -- ./demo/demo9.ts 20 | - npm run ts-node -- ./demo/demo10.ts 21 | - npm run ts-node -- ./demo/demo11.ts 22 | - npm run ts-node -- ./demo/demo12.ts 23 | - npm run ts-node -- ./demo/demo13.ts 24 | - npm run ts-node -- ./demo/demo14.ts 25 | - npm run ts-node -- ./demo/demo15.ts 26 | - npm run ts-node -- ./demo/demo16.ts 27 | - npm run ts-node -- ./demo/demo17.ts 28 | - npm run ts-node -- ./demo/demo18.ts 29 | - npm run ts-node -- ./demo/demo19.ts 30 | - npm run ts-node -- ./demo/demo20.ts 31 | - npm run ts-node -- ./demo/demo21.ts 32 | - npm run ts-node -- ./demo/demo22.ts 33 | - npm run ts-node -- ./demo/demo23.ts 34 | - npm run ts-node -- ./demo/demo24.ts 35 | after_failure: 36 | - "cat /home/travis/builds/dolanmiu/docx/npm-debug.log" 37 | after_success: 38 | - npm run typedoc 39 | - echo "docx.js.org" > docs/.nojekyll 40 | - echo "docx.js.org" > docs/CNAME 41 | deploy: 42 | provider: pages 43 | skip-cleanup: true 44 | github-token: $GITHUB_TOKEN 45 | keep-history: true 46 | local-dir: docs 47 | on: 48 | branch: master 49 | -------------------------------------------------------------------------------- /src/export/packer/packer.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:typedef space-before-function-paren */ 2 | import { assert } from "chai"; 3 | import { stub } from "sinon"; 4 | 5 | import { File, Paragraph } from "../../file"; 6 | import { Packer } from "./packer"; 7 | 8 | describe("Packer", () => { 9 | let packer: Packer; 10 | let file: File; 11 | 12 | beforeEach(() => { 13 | file = new File({ 14 | creator: "Dolan Miu", 15 | revision: "1", 16 | lastModifiedBy: "Dolan Miu", 17 | }); 18 | const paragraph = new Paragraph("test text"); 19 | const heading = new Paragraph("Hello world").heading1(); 20 | 21 | file.addParagraph(new Paragraph("title").title()); 22 | file.addParagraph(heading); 23 | file.addParagraph(new Paragraph("heading 2").heading2()); 24 | file.addParagraph(paragraph); 25 | 26 | packer = new Packer(); 27 | }); 28 | 29 | describe("#toBuffer()", () => { 30 | it("should create a standard docx file", async function() { 31 | this.timeout(99999999); 32 | const buffer = await packer.toBuffer(file); 33 | 34 | assert.isDefined(buffer); 35 | assert.isTrue(buffer.byteLength > 0); 36 | }); 37 | 38 | it("should handle exception if it throws any", () => { 39 | // tslint:disable-next-line:no-any 40 | const compiler = stub((packer as any).compiler, "compile"); 41 | 42 | compiler.throwsException(); 43 | return packer.toBuffer(file).catch((error) => { 44 | assert.isDefined(error); 45 | }); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /src/file/paragraph/links/bookmark.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/WPbookmark.php 2 | 3 | import { XmlComponent } from "file/xml-components"; 4 | import { TextRun } from "../run"; 5 | import { BookmarkEndAttributes, BookmarkStartAttributes } from "./bookmark-attributes"; 6 | 7 | export class Bookmark { 8 | public linkId: number; 9 | 10 | public readonly start: BookmarkStart; 11 | 12 | public readonly text: TextRun; 13 | 14 | public readonly end: BookmarkEnd; 15 | 16 | constructor(name: string, text: string, relationshipsCount: number) { 17 | this.linkId = relationshipsCount + 1; 18 | 19 | this.start = new BookmarkStart(name, this.linkId); 20 | this.text = new TextRun(text); 21 | this.end = new BookmarkEnd(this.linkId); 22 | } 23 | } 24 | 25 | export class BookmarkStart extends XmlComponent { 26 | public linkId: number; 27 | 28 | constructor(name: string, relationshipsCount: number) { 29 | super("w:bookmarkStart"); 30 | 31 | this.linkId = relationshipsCount; 32 | const id = `${this.linkId}`; 33 | const attributes = new BookmarkStartAttributes({ 34 | name, 35 | id, 36 | }); 37 | this.root.push(attributes); 38 | } 39 | } 40 | 41 | export class BookmarkEnd extends XmlComponent { 42 | public linkId: number; 43 | 44 | constructor(relationshipsCount: number) { 45 | super("w:bookmarkEnd"); 46 | 47 | this.linkId = relationshipsCount; 48 | const id = `${this.linkId}`; 49 | const attributes = new BookmarkEndAttributes({ 50 | id, 51 | }); 52 | this.root.push(attributes); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/file/drawing/floating/vertical-position.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { VerticalPositionAlign, VerticalPositionRelativeFrom } from "."; 4 | import { Utility } from "../../../tests/utility"; 5 | import { VerticalPosition } from "./vertical-position"; 6 | 7 | describe("VerticalPosition", () => { 8 | describe("#constructor()", () => { 9 | it("should create a element with position align", () => { 10 | const newJson = Utility.jsonify( 11 | new VerticalPosition({ 12 | relative: VerticalPositionRelativeFrom.MARGIN, 13 | align: VerticalPositionAlign.INSIDE, 14 | }), 15 | ); 16 | assert.equal(newJson.rootKey, "wp:positionV"); 17 | assert.include(newJson.root[0].root, { 18 | relativeFrom: "margin", 19 | }); 20 | 21 | assert.equal(newJson.root[1].rootKey, "wp:align"); 22 | assert.include(newJson.root[1].root, "inside"); 23 | }); 24 | 25 | it("should create a element with offset", () => { 26 | const newJson = Utility.jsonify( 27 | new VerticalPosition({ 28 | relative: VerticalPositionRelativeFrom.MARGIN, 29 | offset: 40, 30 | }), 31 | ); 32 | assert.equal(newJson.rootKey, "wp:positionV"); 33 | assert.include(newJson.root[0].root, { 34 | relativeFrom: "margin", 35 | }); 36 | 37 | assert.equal(newJson.root[1].rootKey, "wp:posOffset"); 38 | assert.include(newJson.root[1].root[0], 40); 39 | }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /src/file/drawing/floating/horizontal-position.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { HorizontalPositionAlign, HorizontalPositionRelativeFrom } from "."; 4 | import { Utility } from "../../../tests/utility"; 5 | import { HorizontalPosition } from "./horizontal-position"; 6 | 7 | describe("HorizontalPosition", () => { 8 | describe("#constructor()", () => { 9 | it("should create a element with position align", () => { 10 | const newJson = Utility.jsonify( 11 | new HorizontalPosition({ 12 | relative: HorizontalPositionRelativeFrom.MARGIN, 13 | align: HorizontalPositionAlign.CENTER, 14 | }), 15 | ); 16 | assert.equal(newJson.rootKey, "wp:positionH"); 17 | assert.include(newJson.root[0].root, { 18 | relativeFrom: "margin", 19 | }); 20 | 21 | assert.equal(newJson.root[1].rootKey, "wp:align"); 22 | assert.include(newJson.root[1].root, "center"); 23 | }); 24 | 25 | it("should create a element with offset", () => { 26 | const newJson = Utility.jsonify( 27 | new HorizontalPosition({ 28 | relative: HorizontalPositionRelativeFrom.MARGIN, 29 | offset: 40, 30 | }), 31 | ); 32 | assert.equal(newJson.rootKey, "wp:positionH"); 33 | assert.include(newJson.root[0].root, { 34 | relativeFrom: "margin", 35 | }); 36 | 37 | assert.equal(newJson.root[1].rootKey, "wp:posOffset"); 38 | assert.include(newJson.root[1].root[0], 40); 39 | }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /src/file/document/body/body.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | import { Formatter } from "../../../export/formatter"; 4 | import { Body } from "./body"; 5 | 6 | describe("Body", () => { 7 | let body: Body; 8 | 9 | beforeEach(() => { 10 | body = new Body(); 11 | }); 12 | 13 | describe("#constructor()", () => { 14 | it("should create default section", () => { 15 | const formatted = new Formatter().format(body)["w:body"][0]; 16 | expect(formatted) 17 | .to.have.property("w:sectPr") 18 | .and.to.be.an.instanceof(Array); 19 | expect(formatted["w:sectPr"]).to.have.length(7); 20 | }); 21 | }); 22 | 23 | describe("addSection", () => { 24 | it("should add section with options", () => { 25 | body.addSection({ 26 | width: 10000, 27 | height: 10000, 28 | }); 29 | 30 | const formatted = new Formatter().format(body)["w:body"]; 31 | expect(formatted).to.be.an.instanceof(Array); 32 | const defaultSectionPr = formatted[0]["w:p"][1]["w:pPr"][0]["w:sectPr"]; 33 | 34 | // check that this is the default section and added first in paragraph 35 | expect(defaultSectionPr[0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } }] }); 36 | 37 | // check for new section (since it's the last one, it's direct child of body) 38 | const newSection = formatted[1]["w:sectPr"]; 39 | expect(newSection[0]).to.deep.equal({ "w:pgSz": [{ _attr: { "w:h": 10000, "w:w": 10000, "w:orient": "portrait" } }] }); 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/file/paragraph/links/bookmark.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { Bookmark } from "./"; 5 | 6 | describe("Bookmark", () => { 7 | let bookmark: Bookmark; 8 | 9 | beforeEach(() => { 10 | bookmark = new Bookmark("anchor", "Internal Link", 0); 11 | }); 12 | 13 | it("should create a bookmark with three root elements", () => { 14 | const newJson = Utility.jsonify(bookmark); 15 | assert.equal(newJson.rootKey, undefined); 16 | assert.equal(newJson.start.rootKey, "w:bookmarkStart"); 17 | assert.equal(newJson.text.rootKey, "w:r"); 18 | assert.equal(newJson.end.rootKey, "w:bookmarkEnd"); 19 | }); 20 | 21 | it("should create a bookmark with the correct attributes on the bookmark start element", () => { 22 | const newJson = Utility.jsonify(bookmark); 23 | const attributes = { 24 | name: "anchor", 25 | id: "1", 26 | }; 27 | assert.equal(JSON.stringify(newJson.start.root[0].root), JSON.stringify(attributes)); 28 | }); 29 | 30 | it("should create a bookmark with the correct attributes on the text element", () => { 31 | const newJson = Utility.jsonify(bookmark); 32 | assert.equal(JSON.stringify(newJson.text.root[1].root[1]), JSON.stringify("Internal Link")); 33 | }); 34 | 35 | it("should create a bookmark with the correct attributes on the bookmark end element", () => { 36 | const newJson = Utility.jsonify(bookmark); 37 | const attributes = { 38 | id: "1", 39 | }; 40 | assert.equal(JSON.stringify(newJson.end.root[0].root), JSON.stringify(attributes)); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/file/drawing/floating/floating-position.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicFloating-position.php 2 | 3 | export enum HorizontalPositionRelativeFrom { 4 | CHARACTER = "character", 5 | COLUMN = "column", 6 | INSIDE_MARGIN = "insideMargin", 7 | LEFT_MARGIN = "leftMargin", 8 | MARGIN = "margin", 9 | OUTSIDE_MARGIN = "outsideMargin", 10 | PAGE = "page", 11 | RIGHT_MARGIN = "rightMargin", 12 | } 13 | 14 | export enum VerticalPositionRelativeFrom { 15 | BOTTOM_MARGIN = "bottomMargin", 16 | INSIDE_MARGIN = "insideMargin", 17 | LINE = "line", 18 | MARGIN = "margin", 19 | OUTSIDE_MARGIN = "outsideMargin", 20 | PAGE = "page", 21 | PARAGRAPH = "paragraph", 22 | TOP_MARGIN = "topMargin", 23 | } 24 | 25 | export enum HorizontalPositionAlign { 26 | CENTER = "center", 27 | INSIDE = "inside", 28 | LEFT = "left", 29 | OUTSIDE = "outside", 30 | RIGHT = "right", 31 | } 32 | 33 | export enum VerticalPositionAlign { 34 | BOTTOM = "bottom", 35 | CENTER = "center", 36 | INSIDE = "inside", 37 | OUTSIDE = "outside", 38 | TOP = "top", 39 | } 40 | 41 | export interface IHorizontalPositionOptions { 42 | relative: HorizontalPositionRelativeFrom; 43 | align?: HorizontalPositionAlign; 44 | offset?: number; 45 | } 46 | 47 | export interface IVerticalPositionOptions { 48 | relative: VerticalPositionRelativeFrom; 49 | align?: VerticalPositionAlign; 50 | offset?: number; 51 | } 52 | 53 | export interface IFloating { 54 | horizontalPosition: IHorizontalPositionOptions; 55 | verticalPosition: IVerticalPositionOptions; 56 | allowOverlap?: boolean; 57 | lockAnchor?: boolean; 58 | behindDocument?: boolean; 59 | layoutInCell?: boolean; 60 | } 61 | -------------------------------------------------------------------------------- /src/file/paragraph/run/script.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { SubScript, SuperScript } from "./script"; 5 | 6 | describe("SubScript", () => { 7 | let subScript: SubScript; 8 | 9 | beforeEach(() => { 10 | subScript = new SubScript(); 11 | }); 12 | 13 | describe("#constructor()", () => { 14 | it("should create a Sub Script with correct attributes", () => { 15 | const newJson = Utility.jsonify(subScript); 16 | const attributes = { 17 | val: "subscript", 18 | }; 19 | assert.equal(JSON.stringify(newJson.root[0].root), JSON.stringify(attributes)); 20 | }); 21 | 22 | it("should create a Sub Script with correct root key", () => { 23 | const newJson = Utility.jsonify(subScript); 24 | assert.equal(newJson.rootKey, "w:vertAlign"); 25 | }); 26 | }); 27 | }); 28 | 29 | describe("SuperScript", () => { 30 | let superScript: SuperScript; 31 | 32 | beforeEach(() => { 33 | superScript = new SuperScript(); 34 | }); 35 | 36 | describe("#constructor()", () => { 37 | it("should create a Super Script with correct attributes", () => { 38 | const newJson = Utility.jsonify(superScript); 39 | const attributes = { 40 | val: "superscript", 41 | }; 42 | assert.equal(JSON.stringify(newJson.root[0].root), JSON.stringify(attributes)); 43 | }); 44 | 45 | it("should create a Super Script with correct root key", () => { 46 | const newJson = Utility.jsonify(superScript); 47 | assert.equal(newJson.rootKey, "w:vertAlign"); 48 | }); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /src/file/drawing/drawing.ts: -------------------------------------------------------------------------------- 1 | import { IMediaData } from "file/media"; 2 | import { XmlComponent } from "file/xml-components"; 3 | import { Anchor } from "./anchor"; 4 | import { IFloating } from "./floating"; 5 | import { Inline } from "./inline"; 6 | import { ITextWrapping } from "./text-wrap"; 7 | 8 | export enum PlacementPosition { 9 | INLINE, 10 | FLOATING, 11 | } 12 | 13 | export interface IDistance { 14 | distT?: number; 15 | distB?: number; 16 | distL?: number; 17 | distR?: number; 18 | } 19 | 20 | export interface IDrawingOptions { 21 | position?: PlacementPosition; 22 | textWrapping?: ITextWrapping; 23 | floating?: IFloating; 24 | } 25 | 26 | const defaultDrawingOptions: IDrawingOptions = { 27 | position: PlacementPosition.INLINE, 28 | }; 29 | 30 | export class Drawing extends XmlComponent { 31 | private readonly inline: Inline; 32 | 33 | constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) { 34 | super("w:drawing"); 35 | 36 | if (imageData === undefined) { 37 | throw new Error("imageData cannot be undefined"); 38 | } 39 | 40 | const mergedOptions = { 41 | ...defaultDrawingOptions, 42 | ...drawingOptions, 43 | }; 44 | 45 | if (mergedOptions.position === PlacementPosition.INLINE) { 46 | this.inline = new Inline(imageData.referenceId, imageData.dimensions); 47 | this.root.push(this.inline); 48 | } else if (mergedOptions.position === PlacementPosition.FLOATING) { 49 | this.root.push(new Anchor(imageData.referenceId, imageData.dimensions, mergedOptions)); 50 | } 51 | } 52 | 53 | public scale(factorX: number, factorY: number): void { 54 | this.inline.scale(factorX, factorY); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/file/drawing/inline/inline.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/drwPicInline.php 2 | import { IMediaDataDimensions } from "file/media"; 3 | import { XmlComponent } from "file/xml-components"; 4 | import { DocProperties } from "./../doc-properties/doc-properties"; 5 | import { EffectExtent } from "./../effect-extent/effect-extent"; 6 | import { Extent } from "./../extent/extent"; 7 | import { GraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties"; 8 | import { Graphic } from "./../inline/graphic"; 9 | import { InlineAttributes } from "./inline-attributes"; 10 | 11 | export class Inline extends XmlComponent { 12 | private readonly extent: Extent; 13 | private readonly graphic: Graphic; 14 | 15 | constructor(referenceId: number, private readonly dimensions: IMediaDataDimensions) { 16 | super("wp:inline"); 17 | 18 | this.root.push( 19 | new InlineAttributes({ 20 | distT: 0, 21 | distB: 0, 22 | distL: 0, 23 | distR: 0, 24 | }), 25 | ); 26 | 27 | this.extent = new Extent(dimensions.emus.x, dimensions.emus.y); 28 | this.graphic = new Graphic(referenceId, dimensions.emus.x, dimensions.emus.y); 29 | 30 | this.root.push(this.extent); 31 | this.root.push(new EffectExtent()); 32 | this.root.push(new DocProperties()); 33 | this.root.push(new GraphicFrameProperties()); 34 | this.root.push(this.graphic); 35 | } 36 | 37 | public scale(factorX: number, factorY: number): void { 38 | const newX = Math.round(this.dimensions.emus.x * factorX); 39 | const newY = Math.round(this.dimensions.emus.y * factorY); 40 | 41 | this.extent.setXY(newX, newY); 42 | this.graphic.setXY(newX, newY); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /demo/demo3.ts: -------------------------------------------------------------------------------- 1 | // Numbering and bullet points example 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Indent, Numbering, Packer, Paragraph } from "../build"; 5 | 6 | const doc = new Document(); 7 | 8 | const numbering = new Numbering(); 9 | 10 | const abstractNum = numbering.createAbstractNumbering(); 11 | abstractNum.createLevel(0, "upperRoman", "%1", "start").addParagraphProperty(new Indent({ left: 720, hanging: 260 })); 12 | abstractNum.createLevel(1, "decimal", "%2.", "start").addParagraphProperty(new Indent({ left: 1440, hanging: 980 })); 13 | abstractNum.createLevel(2, "lowerLetter", "%3)", "start").addParagraphProperty(new Indent({ left: 14402160, hanging: 1700 })); 14 | 15 | const concrete = numbering.createConcreteNumbering(abstractNum); 16 | 17 | const topLevelP = new Paragraph("Hey you"); 18 | const subP = new Paragraph("What's up fam"); 19 | const secondSubP = new Paragraph("Hello World 2"); 20 | const subSubP = new Paragraph("Yeah boi"); 21 | 22 | topLevelP.setNumbering(concrete, 0); 23 | subP.setNumbering(concrete, 1); 24 | secondSubP.setNumbering(concrete, 1); 25 | subSubP.setNumbering(concrete, 2); 26 | 27 | doc.addParagraph(topLevelP); 28 | doc.addParagraph(subP); 29 | doc.addParagraph(secondSubP); 30 | doc.addParagraph(subSubP); 31 | 32 | const bullet1 = new Paragraph("Hey you").bullet(); 33 | const bullet2 = new Paragraph("What's up fam").bullet(1); 34 | const bullet3 = new Paragraph("Hello World 2").bullet(2); 35 | const bullet4 = new Paragraph("Yeah boi").bullet(3); 36 | 37 | doc.addParagraph(bullet1); 38 | doc.addParagraph(bullet2); 39 | doc.addParagraph(bullet3); 40 | doc.addParagraph(bullet4); 41 | 42 | const packer = new Packer(); 43 | 44 | packer.toBuffer(doc).then((buffer) => { 45 | fs.writeFileSync("My Document.docx", buffer); 46 | }); 47 | -------------------------------------------------------------------------------- /docs/contribution-guidelines.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | ## Writing Code 4 | 5 | * Include documentation reference(s) at the top of each file: 6 | 7 | ```js 8 | // http://officeopenxml.com/WPdocument.php 9 | ``` 10 | 11 | * Follow Prettier standards, and consider using the [Prettier VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) plugin. 12 | 13 | * Follow the `TSLint` rules 14 | 15 | ## Add vs Create 16 | 17 | This is just a guideline, and the rules can sometimes be broken. 18 | 19 | * Use `create` if the method `new`'s up an element inside: 20 | 21 | ```js 22 | public createParagraph() { 23 | const paragraph = new Paragraph(); 24 | this.root.push(paragraph); 25 | } 26 | ``` 27 | 28 | * Use `add` if you add the element into the method as a parameter: 29 | 30 | ```js 31 | public addParagraph(paragraph: Paragraph) { 32 | this.root.push(paragraph); 33 | } 34 | ``` 35 | 36 | ## Getters and Setters 37 | 38 | Getters and Setters are done with a capital letter like so: 39 | 40 | ```js 41 | public get Level() { 42 | 43 | } 44 | ``` 45 | 46 | There is no performance advantage by doing this. It means we don't need to prefix all private variables with the ugly `_`: 47 | 48 | **Do not:** 49 | 50 | ```js 51 | private get _level: string; 52 | ``` 53 | 54 | **Do** 55 | 56 | ```js 57 | private get level: string; 58 | ``` 59 | 60 | ## Testing 61 | 62 | Please write a test of every file you make and suffix it with `.spec.ts`. 63 | 64 | Here is a template of a test: 65 | 66 | ```js 67 | import { assert } from "chai"; 68 | 69 | describe("ClassName", () => { 70 | beforeEach(() => { 71 | // TODO 72 | }); 73 | 74 | describe("#methodName()", () => { 75 | it("should ", () => { 76 | // TODO 77 | }); 78 | }); 79 | }); 80 | ``` 81 | -------------------------------------------------------------------------------- /docs/usage/styling-with-xml.md: -------------------------------------------------------------------------------- 1 | # Styling with XML 2 | 3 | ## Setup 4 | 5 | 1. Create a new word document in Microsoft Word 6 | 2. Customise the styles on the Ribbon Bar. 7 | For example, modify the `Normal`, `Heading 1`, `Heading 2` like so: 8 | 9 | ![image](https://user-images.githubusercontent.com/2917613/41195113-65edebfa-6c1f-11e8-97b4-77de2d60044a.png) 10 | ![image](https://user-images.githubusercontent.com/2917613/41195126-ca99c36c-6c1f-11e8-9e58-19e5f69b3b87.png) 11 | 12 | 3. You can even create a totally new `Style`: 13 | 14 | ![image](https://user-images.githubusercontent.com/2917613/41195135-f0f7862a-6c1f-11e8-8be4-dd6d8fe5be03.png) 15 | ![image](https://user-images.githubusercontent.com/2917613/41195139-0ec52130-6c20-11e8-8fae-f6b44b43fdf8.png) 16 | 17 | 4. Save 18 | 5. Re-name the saved `.docx` file to `.zip` and un-zip 19 | 6. Find `styles.xml` 20 | 21 | ![image](https://user-images.githubusercontent.com/2917613/41195178-bb9ba9c4-6c20-11e8-850e-a7a6ada9a2f6.png) 22 | 23 | ## Usage 24 | 25 | Read the styles using `fs`, and put it into the `Document` object in the constructor: 26 | 27 | ```js 28 | const styles = fs.readFileSync("./styles.xml", "utf-8"); 29 | const doc = new docx.Document({ 30 | title: "Title", 31 | externalStyles: styles, 32 | }); 33 | ``` 34 | 35 | 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: 36 | 37 | ```js 38 | doc.createParagraph("Cool Heading Text").heading1(); 39 | 40 | let paragraph = new docx.Paragraph('This is a custom named style from the template "Cool New Style"'); 41 | paragraph.style("Cool New Style"); 42 | doc.addParagraph(paragraph); 43 | 44 | doc.createParagraph("Some normal text"); 45 | ``` 46 | 47 | Example: https://github.com/dolanmiu/docx/blob/master/demo/demo13.js 48 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/tab-stop.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert } from "chai"; 2 | 3 | import { Utility } from "../../../tests/utility"; 4 | import { LeftTabStop, MaxRightTabStop } from "./tab-stop"; 5 | 6 | describe("LeftTabStop", () => { 7 | let tabStop: LeftTabStop; 8 | 9 | beforeEach(() => { 10 | tabStop = new LeftTabStop(100); 11 | }); 12 | 13 | describe("#constructor()", () => { 14 | it("should create a Tab Stop with correct attributes", () => { 15 | const newJson = Utility.jsonify(tabStop); 16 | const attributes = { 17 | val: "left", 18 | pos: 100, 19 | }; 20 | assert.equal(JSON.stringify(newJson.root[0].root[0].root), JSON.stringify(attributes)); 21 | }); 22 | 23 | it("should create a Tab Stop with w:tab", () => { 24 | const newJson = Utility.jsonify(tabStop); 25 | assert.equal(newJson.root[0].rootKey, "w:tab"); 26 | }); 27 | }); 28 | }); 29 | 30 | describe("RightTabStop", () => { 31 | // TODO 32 | }); 33 | 34 | describe("MaxRightTabStop", () => { 35 | let tabStop: MaxRightTabStop; 36 | 37 | beforeEach(() => { 38 | tabStop = new MaxRightTabStop(); 39 | }); 40 | 41 | describe("#constructor()", () => { 42 | it("should create a Tab Stop with correct attributes", () => { 43 | const newJson = Utility.jsonify(tabStop); 44 | 45 | const attributes = { 46 | val: "right", 47 | pos: 9026, 48 | }; 49 | assert.equal(JSON.stringify(newJson.root[0].root[0].root), JSON.stringify(attributes)); 50 | }); 51 | 52 | it("should create a Tab Stop with w:tab", () => { 53 | const newJson = Utility.jsonify(tabStop); 54 | assert.equal(newJson.root[0].rootKey, "w:tab"); 55 | }); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/file/table/properties.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | import { Formatter } from "../../export/formatter"; 4 | import { TableProperties } from "./properties"; 5 | import { WidthType } from "./table-cell"; 6 | 7 | describe("TableProperties", () => { 8 | describe("#constructor", () => { 9 | it("creates an initially empty property object", () => { 10 | const tp = new TableProperties(); 11 | const tree = new Formatter().format(tp); 12 | expect(tree).to.deep.equal({ "w:tblPr": [] }); 13 | }); 14 | }); 15 | 16 | describe("#setWidth", () => { 17 | it("adds a table width property", () => { 18 | const tp = new TableProperties().setWidth(WidthType.DXA, 1234); 19 | const tree = new Formatter().format(tp); 20 | expect(tree).to.deep.equal({ 21 | "w:tblPr": [{ "w:tblW": [{ _attr: { "w:type": "dxa", "w:w": 1234 } }] }], 22 | }); 23 | }); 24 | }); 25 | 26 | describe("#setFixedWidthLayout", () => { 27 | it("sets the table to fixed width layout", () => { 28 | const tp = new TableProperties().setFixedWidthLayout(); 29 | const tree = new Formatter().format(tp); 30 | expect(tree).to.deep.equal({ 31 | "w:tblPr": [{ "w:tblLayout": [{ _attr: { "w:type": "fixed" } }] }], 32 | }); 33 | }); 34 | }); 35 | 36 | describe("#cellMargin", () => { 37 | it("adds a table cell top margin", () => { 38 | const tp = new TableProperties(); 39 | tp.CellMargin.addTopMargin(1234, WidthType.DXA); 40 | const tree = new Formatter().format(tp); 41 | expect(tree).to.deep.equal({ 42 | "w:tblPr": [{ "w:tblCellMar": [{ "w:top": [{ _attr: { "w:sz": "dxa", "w:w": 1234 } }] }] }], 43 | }); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /src/file/styles/style/components.ts: -------------------------------------------------------------------------------- 1 | import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; 2 | 3 | interface IComponentAttributes { 4 | val: string; 5 | } 6 | 7 | class ComponentAttributes extends XmlAttributeComponent { 8 | protected xmlKeys = { val: "w:val" }; 9 | } 10 | 11 | export class Name extends XmlComponent { 12 | constructor(value: string) { 13 | super("w:name"); 14 | this.root.push(new ComponentAttributes({ val: value })); 15 | } 16 | } 17 | 18 | export class BasedOn extends XmlComponent { 19 | constructor(value: string) { 20 | super("w:basedOn"); 21 | this.root.push(new ComponentAttributes({ val: value })); 22 | } 23 | } 24 | 25 | export class Next extends XmlComponent { 26 | constructor(value: string) { 27 | super("w:next"); 28 | this.root.push(new ComponentAttributes({ val: value })); 29 | } 30 | } 31 | 32 | export class Link extends XmlComponent { 33 | constructor(value: string) { 34 | super("w:link"); 35 | this.root.push(new ComponentAttributes({ val: value })); 36 | } 37 | } 38 | 39 | export class UiPriority extends XmlComponent { 40 | constructor(value: string) { 41 | super("w:uiPriority"); 42 | // TODO: this value should be a ST_DecimalNumber 43 | this.root.push(new ComponentAttributes({ val: value })); 44 | } 45 | } 46 | 47 | export class UnhideWhenUsed extends XmlComponent { 48 | constructor() { 49 | super("w:unhideWhenUsed"); 50 | } 51 | } 52 | 53 | export class QuickFormat extends XmlComponent { 54 | constructor() { 55 | super("w:qFormat"); 56 | } 57 | } 58 | 59 | export class TableProperties extends XmlComponent {} 60 | 61 | export class RsId extends XmlComponent {} 62 | 63 | export class SemiHidden extends XmlComponent { 64 | constructor() { 65 | super("w:semiHidden"); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/file/table/table-cell-margin.ts: -------------------------------------------------------------------------------- 1 | import { IXmlableObject, XmlAttributeComponent, XmlComponent } from "file/xml-components"; 2 | import { WidthType } from "./table-cell"; 3 | 4 | class TableCellMarginAttributes extends XmlAttributeComponent<{ type: WidthType; value: number }> { 5 | protected xmlKeys = { value: "w:w", type: "w:sz" }; 6 | } 7 | 8 | class BaseTableCellMargin extends XmlComponent { 9 | public setProperties(value: number, type: WidthType = WidthType.DXA): void { 10 | this.root.push( 11 | new TableCellMarginAttributes({ 12 | type: type, 13 | value: value, 14 | }), 15 | ); 16 | } 17 | } 18 | 19 | export class TableCellMargin extends XmlComponent { 20 | constructor() { 21 | super("w:tblCellMar"); 22 | } 23 | 24 | public prepForXml(): IXmlableObject { 25 | return this.root.length > 0 ? super.prepForXml() : ""; 26 | } 27 | 28 | public addTopMargin(value: number, type: WidthType = WidthType.DXA): void { 29 | const top = new BaseTableCellMargin("w:top"); 30 | 31 | top.setProperties(value, type); 32 | this.root.push(top); 33 | } 34 | 35 | public addLeftMargin(value: number, type: WidthType = WidthType.DXA): void { 36 | const left = new BaseTableCellMargin("w:left"); 37 | 38 | left.setProperties(value, type); 39 | this.root.push(left); 40 | } 41 | 42 | public addBottomMargin(value: number, type: WidthType = WidthType.DXA): void { 43 | const bottom = new BaseTableCellMargin("w:bottom"); 44 | 45 | bottom.setProperties(value, type); 46 | this.root.push(bottom); 47 | } 48 | 49 | public addRightMargin(value: number, type: WidthType = WidthType.DXA): void { 50 | const right = new BaseTableCellMargin("w:right"); 51 | 52 | right.setProperties(value, type); 53 | this.root.push(right); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/file/relationships/relationship/relationship.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { RelationshipAttributes } from "./relationship-attributes"; 3 | 4 | export type RelationshipType = 5 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" 6 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" 7 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" 8 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" 9 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" 10 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" 11 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" 12 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" 13 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" 14 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" 15 | | "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" 16 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" 17 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" 18 | | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes"; 19 | 20 | export type TargetModeType = "External"; 21 | 22 | export class Relationship extends XmlComponent { 23 | constructor(id: string, type: RelationshipType, target: string, targetMode?: TargetModeType) { 24 | super("Relationship"); 25 | 26 | this.root.push( 27 | new RelationshipAttributes({ 28 | id, 29 | type, 30 | target, 31 | targetMode, 32 | }), 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /demo/demo21.ts: -------------------------------------------------------------------------------- 1 | // This demo shows how to create bookmarks then link to them with internal hyperlinks 2 | // Import from 'docx' rather than '../build' if you install from npm 3 | import * as fs from "fs"; 4 | import { Document, Packer } from "../build"; 5 | 6 | const loremIpsum = 7 | "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."; 8 | 9 | const doc = new Document({ 10 | creator: "Clippy", 11 | title: "Sample Document", 12 | description: "A brief example of using docx with bookmarks and internal hyperlinks", 13 | }); 14 | 15 | const anchorId = "anchorID"; 16 | 17 | // First create the bookmark 18 | const bookmark = doc.createBookmark(anchorId, "Lorem Ipsum"); 19 | // That has header styling 20 | doc 21 | .createParagraph() 22 | .addBookmark(bookmark) 23 | .heading1(); 24 | doc.createParagraph("\n"); 25 | 26 | doc.createParagraph(loremIpsum); 27 | doc.createParagraph().pageBreak(); 28 | 29 | // Now the link back up to the bookmark 30 | const hyperlink = doc.createInternalHyperLink(anchorId, `Click me!`); 31 | doc.createParagraph().addHyperLink(hyperlink); 32 | 33 | const packer = new Packer(); 34 | 35 | packer.toBuffer(doc).then((buffer) => { 36 | fs.writeFileSync("My Document.docx", buffer); 37 | }); 38 | -------------------------------------------------------------------------------- /src/file/core-properties/properties.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { DocumentAttributes } from "../document/document-attributes"; 3 | import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components"; 4 | 5 | export interface IPropertiesOptions { 6 | title?: string; 7 | subject?: string; 8 | creator?: string; 9 | keywords?: string; 10 | description?: string; 11 | lastModifiedBy?: string; 12 | revision?: string; 13 | externalStyles?: string; 14 | } 15 | 16 | export class CoreProperties extends XmlComponent { 17 | constructor(options: IPropertiesOptions) { 18 | super("cp:coreProperties"); 19 | this.root.push( 20 | new DocumentAttributes({ 21 | cp: "http://schemas.openxmlformats.org/package/2006/metadata/core-properties", 22 | dc: "http://purl.org/dc/elements/1.1/", 23 | dcterms: "http://purl.org/dc/terms/", 24 | dcmitype: "http://purl.org/dc/dcmitype/", 25 | xsi: "http://www.w3.org/2001/XMLSchema-instance", 26 | }), 27 | ); 28 | if (options.title) { 29 | this.root.push(new Title(options.title)); 30 | } 31 | if (options.subject) { 32 | this.root.push(new Subject(options.subject)); 33 | } 34 | if (options.creator) { 35 | this.root.push(new Creator(options.creator)); 36 | } 37 | if (options.keywords) { 38 | this.root.push(new Keywords(options.keywords)); 39 | } 40 | if (options.description) { 41 | this.root.push(new Description(options.description)); 42 | } 43 | if (options.lastModifiedBy) { 44 | this.root.push(new LastModifiedBy(options.lastModifiedBy)); 45 | } 46 | if (options.revision) { 47 | this.root.push(new Revision(options.revision)); 48 | } 49 | this.root.push(new Created()); 50 | this.root.push(new Modified()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/file/footer-wrapper.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { Footer } from "./footer/footer"; 3 | import { Image, Media } from "./media"; 4 | import { ImageParagraph, Paragraph } from "./paragraph"; 5 | import { Relationships } from "./relationships"; 6 | import { Table } from "./table"; 7 | 8 | export class FooterWrapper { 9 | private readonly footer: Footer; 10 | private readonly relationships: Relationships; 11 | 12 | constructor(private readonly media: Media, referenceId: number) { 13 | this.footer = new Footer(referenceId); 14 | this.relationships = new Relationships(); 15 | } 16 | 17 | public addParagraph(paragraph: Paragraph): void { 18 | this.footer.addParagraph(paragraph); 19 | } 20 | 21 | public createParagraph(text?: string): Paragraph { 22 | const para = new Paragraph(text); 23 | this.addParagraph(para); 24 | return para; 25 | } 26 | 27 | public addTable(table: Table): void { 28 | this.footer.addTable(table); 29 | } 30 | 31 | public createTable(rows: number, cols: number): Table { 32 | return this.footer.createTable(rows, cols); 33 | } 34 | 35 | public addChildElement(childElement: XmlComponent | string): void { 36 | this.footer.addChildElement(childElement); 37 | } 38 | 39 | public createImage(image: Buffer, width?: number, height?: number): void { 40 | const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height); 41 | this.relationships.createRelationship( 42 | mediaData.referenceId, 43 | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", 44 | `media/${mediaData.fileName}`, 45 | ); 46 | this.addImage(new Image(new ImageParagraph(mediaData))); 47 | } 48 | 49 | public addImage(image: Image): FooterWrapper { 50 | this.footer.addParagraph(image.Paragraph); 51 | return this; 52 | } 53 | 54 | public get Footer(): Footer { 55 | return this.footer; 56 | } 57 | 58 | public get Relationships(): Relationships { 59 | return this.relationships; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/file/header-wrapper.ts: -------------------------------------------------------------------------------- 1 | import { XmlComponent } from "file/xml-components"; 2 | import { Header } from "./header/header"; 3 | import { Image, Media } from "./media"; 4 | import { ImageParagraph, Paragraph } from "./paragraph"; 5 | import { Relationships } from "./relationships"; 6 | import { Table } from "./table"; 7 | 8 | export class HeaderWrapper { 9 | private readonly header: Header; 10 | private readonly relationships: Relationships; 11 | 12 | constructor(private readonly media: Media, referenceId: number) { 13 | this.header = new Header(referenceId); 14 | this.relationships = new Relationships(); 15 | } 16 | 17 | public addParagraph(paragraph: Paragraph): void { 18 | this.header.addParagraph(paragraph); 19 | } 20 | 21 | public createParagraph(text?: string): Paragraph { 22 | const para = new Paragraph(text); 23 | this.addParagraph(para); 24 | return para; 25 | } 26 | 27 | public addTable(table: Table): void { 28 | this.header.addTable(table); 29 | } 30 | 31 | public createTable(rows: number, cols: number): Table { 32 | return this.header.createTable(rows, cols); 33 | } 34 | 35 | public addChildElement(childElement: XmlComponent | string): void { 36 | this.header.addChildElement(childElement); 37 | } 38 | 39 | public createImage(image: Buffer, width?: number, height?: number): void { 40 | const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height); 41 | this.relationships.createRelationship( 42 | mediaData.referenceId, 43 | "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", 44 | `media/${mediaData.fileName}`, 45 | ); 46 | this.addImage(new Image(new ImageParagraph(mediaData))); 47 | } 48 | 49 | public addImage(image: Image): HeaderWrapper { 50 | this.header.addParagraph(image.Paragraph); 51 | return this; 52 | } 53 | 54 | public get Header(): Header { 55 | return this.header; 56 | } 57 | 58 | public get Relationships(): Relationships { 59 | return this.relationships; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/file/paragraph/links/hyperlink.spec.ts: -------------------------------------------------------------------------------- 1 | import { assert, expect } from "chai"; 2 | 3 | import { Formatter } from "../../../export/formatter"; 4 | import { Utility } from "../../../tests/utility"; 5 | import { Hyperlink } from "./"; 6 | 7 | describe("Hyperlink", () => { 8 | let hyperlink: Hyperlink; 9 | 10 | beforeEach(() => { 11 | hyperlink = new Hyperlink("https://example.com", 0); 12 | }); 13 | 14 | describe("#constructor()", () => { 15 | it("should create a hyperlink with correct root key", () => { 16 | const newJson = Utility.jsonify(hyperlink); 17 | assert.equal(newJson.rootKey, "w:hyperlink"); 18 | }); 19 | 20 | it("should create a hyperlink with right attributes", () => { 21 | const newJson = Utility.jsonify(hyperlink); 22 | const attributes = { 23 | history: 1, 24 | id: "rId1", 25 | }; 26 | assert.equal(JSON.stringify(newJson.root[0].root), JSON.stringify(attributes)); 27 | }); 28 | 29 | it("should create a hyperlink with a run component", () => { 30 | const tree = new Formatter().format(hyperlink); 31 | const runJson = { 32 | "w:r": [ 33 | { "w:rPr": [{ "w:rStyle": [{ _attr: { "w:val": "Hyperlink" } }] }] }, 34 | { "w:t": [{ _attr: { "xml:space": "preserve" } }, "https://example.com"] }, 35 | ], 36 | }; 37 | expect(tree["w:hyperlink"][1]).to.deep.equal(runJson); 38 | }); 39 | 40 | describe("with optional anchor parameter", () => { 41 | beforeEach(() => { 42 | hyperlink = new Hyperlink("Anchor Text", 0, "anchor"); 43 | }); 44 | 45 | it("should create an internal link with anchor tag", () => { 46 | const newJson = Utility.jsonify(hyperlink); 47 | const attributes = { 48 | history: 1, 49 | anchor: "anchor", 50 | }; 51 | assert.equal(JSON.stringify(newJson.root[0].root), JSON.stringify(attributes)); 52 | }); 53 | }); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /src/file/styles/external-styles-factory.ts: -------------------------------------------------------------------------------- 1 | import * as fastXmlParser from "fast-xml-parser"; 2 | import { convertToXmlComponent, ImportedRootElementAttributes, parseOptions } from "file/xml-components"; 3 | import { Styles } from "./"; 4 | 5 | export class ExternalStylesFactory { 6 | /** 7 | * Creates new Style based on the given styles. 8 | * Parses the styles and convert them to XmlComponent. 9 | * Example content from styles.xml: 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * ..... 16 | * 17 | * 18 | * 19 | * 20 | * ..... 21 | * 22 | * 23 | * Or any other element will be parsed to 24 | * 25 | * 26 | * @param externalStyles context from styles.xml 27 | */ 28 | public newInstance(externalStyles: string): Styles { 29 | const xmlStyles = fastXmlParser.parse(externalStyles, parseOptions)["w:styles"]; 30 | // create styles with attributes from the parsed xml 31 | const importedStyle = new Styles(new ImportedRootElementAttributes(xmlStyles._attr)); 32 | 33 | // convert other elements (not styles definitions, but default styles and so on ...) 34 | Object.keys(xmlStyles) 35 | .filter((element) => element !== "_attr" && element !== "w:style") 36 | .forEach((element) => { 37 | const converted = convertToXmlComponent(element, xmlStyles[element]); 38 | if (Array.isArray(converted)) { 39 | converted.forEach((c) => importedStyle.push(c)); 40 | } else { 41 | importedStyle.push(converted); 42 | } 43 | }); 44 | 45 | // convert the styles one by one 46 | xmlStyles["w:style"].map((style) => convertToXmlComponent("w:style", style)).forEach(importedStyle.push.bind(importedStyle)); 47 | return importedStyle; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/file/paragraph/formatting/border.ts: -------------------------------------------------------------------------------- 1 | // http://officeopenxml.com/WPborders.php 2 | import { Attributes, XmlComponent } from "file/xml-components"; 3 | 4 | class BorderProperty extends XmlComponent { 5 | public setProperties(color: string, space: string, value: string, size: string): XmlComponent { 6 | const attrs = new Attributes({ 7 | color: color, 8 | space: space, 9 | val: value, 10 | sz: size, 11 | }); 12 | this.root.push(attrs); 13 | 14 | return this; 15 | } 16 | } 17 | 18 | export class Border extends XmlComponent { 19 | constructor() { 20 | super("w:pBdr"); 21 | } 22 | 23 | public addTopBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent { 24 | const top = new BorderProperty("w:top"); 25 | top.setProperties(color, space, value, size); 26 | this.root.push(top); 27 | 28 | return this; 29 | } 30 | 31 | public addBottomBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent { 32 | const bottom = new BorderProperty("w:bottom"); 33 | bottom.setProperties(color, space, value, size); 34 | this.root.push(bottom); 35 | 36 | return this; 37 | } 38 | 39 | public addLeftBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent { 40 | const left = new BorderProperty("w:left"); 41 | left.setProperties(color, space, value, size); 42 | this.root.push(left); 43 | 44 | return this; 45 | } 46 | 47 | public addRightBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent { 48 | const right = new BorderProperty("w:right"); 49 | right.setProperties(color, space, value, size); 50 | this.root.push(right); 51 | 52 | return this; 53 | } 54 | } 55 | 56 | export class ThematicBreak extends XmlComponent { 57 | constructor() { 58 | super("w:pBdr"); 59 | const bottom = new BorderProperty("w:bottom"); 60 | bottom.setProperties("auto", "1", "single", "6"); 61 | this.root.push(bottom); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /docs/usage/tab-stops.md: -------------------------------------------------------------------------------- 1 | # Tab Stops 2 | 3 | > 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. 4 | 5 | **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. 6 | 7 | ![Word 2013 Tabs](http://www.teachucomp.com/wp-content/uploads/blog-4-22-2015-UsingTabStopsInWord-1024x577.png "Word 2013 Tab Stops") 8 | 9 | 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. 10 | 11 | ## Example 12 | 13 | ```js 14 | var paragraph = new docx.Paragraph().maxRightTabStop(); 15 | var leftText = new docx.TextRun("Hey everyone").bold(); 16 | var rightText = new docx.TextRun("11th November 2015").tab(); 17 | paragraph.addRun(leftText); 18 | paragraph.addRun(rightText); 19 | ``` 20 | 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! 21 | 22 | ```js 23 | var paragraph = new docx.Paragraph(); 24 | paragraph.maxRightTabStop(); 25 | paragraph.leftTabStop(1000); 26 | var text = new docx.TextRun("Second tab stop here I come!").tab().tab(); 27 | paragraph.addRun(text); 28 | ``` 29 | 30 | The above shows the use of two tab stops, and how to select/use it. 31 | 32 | ## Left Tab Stop 33 | ```js 34 | paragraph.leftTabStop(2268); 35 | ``` 36 | 2268 is the distance from the left side. 37 | 38 | ## Center Tab Stop 39 | ```js 40 | paragraph.centerTabStop(2268); 41 | ``` 42 | 2268 is the distance from the left side. 43 | 44 | ## Right Tab Stop 45 | ```js 46 | paragraph.rightTabStop(2268); 47 | ``` 48 | 2268 is the distance from the left side. 49 | 50 | ## Max Right Tab Stop 51 | ```js 52 | paragraph.maxRightTabStop(); 53 | ``` 54 | 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. 55 | --------------------------------------------------------------------------------