diff --git a/.gitignore b/.gitignore
index 1510fe9647..e6143b4db7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,8 +48,12 @@ docs/.nojekyll
!.vscode/extensions.json
.history
+# IntelliJ
+.idea
+
# Lock files
package-lock.json
+yarn.lock
# Documents
My Document.docx
diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 0000000000..469d080845
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+v8
\ No newline at end of file
diff --git a/README.md b/README.md
index 7e25666ee0..020cb78f96 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-
+
@@ -17,11 +17,20 @@
[![PRs Welcome][pr-image]][pr-url]
-
+
# Demo
+## Browser
+
+Here are examples of `docx` being used with basic `HTML/JS` in a browser environment.
+
+* https://codepen.io/anon/pen/dqoVgQ
+* https://jsfiddle.net/3xhezb5w/2
+
+## Node
+
Press `endpoint` on the `RunKit` website:

@@ -33,9 +42,11 @@ Press `endpoint` on the `RunKit` website:
* https://runkit.com/dolanmiu/docx-demo5 - Images
* https://runkit.com/dolanmiu/docx-demo6 - Margins
* https://runkit.com/dolanmiu/docx-demo7 - Landscape
-* https://runkit.com/dolanmiu/docx-demo8/1.0.1 - Header and Footer
+* https://runkit.com/dolanmiu/docx-demo8 - Header and Footer
* https://runkit.com/dolanmiu/docx-demo10 - **My CV generated with docx**
+More [here](https://docx.js.org/#/examples) and [here](https://github.com/dolanmiu/docx/tree/master/demo)
+
# How to use & Documentation
Please refer to the [documentation at https://docx.js.org/](https://docx.js.org/) for details on how to use this library, examples and much more!
diff --git a/demo/demo27.ts b/demo/demo27.ts
index bbba325052..e04fc07e02 100644
--- a/demo/demo27.ts
+++ b/demo/demo27.ts
@@ -1,28 +1,34 @@
-// Creates two paragraphs, one with a border and one without
-// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
-import { File, Packer, Paragraph, TableOfContents } from "../build";
+import { Document, Packer } from "../build";
-const doc = new File();
+const doc = new Document();
+const myStyles = doc.Styles;
-// WordprocessingML docs for TableOfContents can be found here:
-// http://officeopenxml.com/WPtableOfContents.php
-// Creates an table of contents with default properties
-const toc = new TableOfContents();
+// The first argument is an ID you use to apply the style to paragraphs
+// The second argument is a human-friendly name to show in the UI
+myStyles.createParagraphStyle("myWonkyStyle", "My Wonky Style")
+ .basedOn("Normal")
+ .next("Normal")
+ .color("990000")
+ .italics()
+ .indent({left: 720}) // 720 TWIP === 720 / 20 pt === .5 in
+ .spacing({line: 276}); // 276 / 240 = 1.15x line spacing
-// A TableOfContents must be added via File class.
-doc.addTableOfContents(toc)
+myStyles.createParagraphStyle("Heading2", "Heading 2")
+ .basedOn("Normal")
+ .next("Normal")
+ .quickFormat()
+ .size(26) // 26 half-points === 13pt font
+ .bold()
+ .underline("double", "FF0000")
+ .spacing({before: 240, after: 120}); // TWIP for both
-doc.addParagraph(new Paragraph("Header #1").heading1().pageBreakBefore());
-doc.addParagraph(new Paragraph("I'm a little text very nicely written.'"));
-
-doc.addParagraph(new Paragraph("Header #2").heading1().pageBreakBefore());
-doc.addParagraph(new Paragraph("I'm a other text very nicely written.'"));
-doc.addParagraph(new Paragraph("Header #2.1").heading2());
-doc.addParagraph(new Paragraph("I'm a another text very nicely written.'"));
+doc.createParagraph("Hello").style("myWonkyStyle");
+doc.createParagraph("World").heading2(); // Uses the Heading2 style
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
- fs.writeFileSync("tmp/My Document.docx", buffer);
+ fs.writeFileSync("My Document.docx", buffer);
+ console.log("Document created successfully at project root!");
});
diff --git a/demo/demo28.ts b/demo/demo28.ts
new file mode 100644
index 0000000000..3fdd14da46
--- /dev/null
+++ b/demo/demo28.ts
@@ -0,0 +1,28 @@
+// Creates two paragraphs, one with a border and one without
+// Import from 'docx' rather than '../build' if you install from npm
+import * as fs from "fs";
+import { File, Packer, Paragraph, TableOfContents } from "../build";
+
+const doc = new File();
+
+// WordprocessingML docs for TableOfContents can be found here:
+// http://officeopenxml.com/WPtableOfContents.php
+// Creates an table of contents with default properties
+const toc = new TableOfContents();
+
+// A TableOfContents must be added via File class.
+doc.addTableOfContents(toc);
+
+doc.addParagraph(new Paragraph("Header #1").heading1().pageBreakBefore());
+doc.addParagraph(new Paragraph("I'm a little text very nicely written.'"));
+
+doc.addParagraph(new Paragraph("Header #2").heading1().pageBreakBefore());
+doc.addParagraph(new Paragraph("I'm a other text very nicely written.'"));
+doc.addParagraph(new Paragraph("Header #2.1").heading2());
+doc.addParagraph(new Paragraph("I'm a another text very nicely written.'"));
+
+const packer = new Packer();
+
+packer.toBuffer(doc).then((buffer) => {
+ fs.writeFileSync("tmp/My Document.docx", buffer);
+});
diff --git a/docs/README.md b/docs/README.md
index f3134b8fa3..4fc5757477 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,5 +1,5 @@
-
+
@@ -54,6 +54,10 @@ exporter.pack("My First Document");
[@h4buli](https://github.com/h4buli)
+
+
+
+
---
Made with 💖
diff --git a/docs/usage/styling-with-js.md b/docs/usage/styling-with-js.md
index 3e482bca14..4f362192af 100644
--- a/docs/usage/styling-with-js.md
+++ b/docs/usage/styling-with-js.md
@@ -20,6 +20,7 @@ const name = new TextRun("Name:")
* `.size(halfPts)`: Set the font size, measured in half-points
* `.font(name)`: Set the run's font
* `.style(name)`: Apply a named run style
+ * `.characterSpacing(value)`: Set the character spacing adjustment (in TWIPs)
* For paragraph formatting:
* `.heading1()`, `.heading2()`, `.heading3()`, `.heading4()`, `.heading5()`, `.title()`: apply the appropriate style to the paragraph
* `.left()`, `.center()`, `.right()`, `.justified()`: set the paragraph's alignment
diff --git a/logo/logo-small.gif b/logo/logo-small.gif
new file mode 100644
index 0000000000..4b4a567c02
Binary files /dev/null and b/logo/logo-small.gif differ
diff --git a/logo/logo-small.png b/logo/logo-small.png
new file mode 100644
index 0000000000..966fd4b1e7
Binary files /dev/null and b/logo/logo-small.png differ
diff --git a/logo/logo-small.psd b/logo/logo-small.psd
new file mode 100644
index 0000000000..4c6b32123c
Binary files /dev/null and b/logo/logo-small.psd differ
diff --git a/logo/logo.psd b/logo/logo.psd
new file mode 100644
index 0000000000..9763168e2c
Binary files /dev/null and b/logo/logo.psd differ
diff --git a/package.json b/package.json
index 330ad72bac..e63dd166bf 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "docx",
- "version": "4.0.0",
+ "version": "4.1.0",
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
"main": "build/index.js",
"scripts": {
@@ -82,5 +82,8 @@
"typedoc": "^0.11.1",
"typescript": "2.9.2",
"webpack": "^3.10.0"
+ },
+ "engines": {
+ "node": ">=8"
}
}
diff --git a/src/file/document/body/section-properties/page-margin/page-margin-attributes.ts b/src/file/document/body/section-properties/page-margin/page-margin-attributes.ts
index a9d1ae46ee..e486ae5c72 100644
--- a/src/file/document/body/section-properties/page-margin/page-margin-attributes.ts
+++ b/src/file/document/body/section-properties/page-margin/page-margin-attributes.ts
@@ -8,6 +8,7 @@ export interface IPageMarginAttributes {
header?: number;
footer?: number;
gutter?: number;
+ mirror?: boolean;
}
export class PageMarginAttributes extends XmlAttributeComponent {
@@ -19,5 +20,6 @@ export class PageMarginAttributes extends XmlAttributeComponent {
header: 708,
footer: 708,
gutter: 0,
+ mirror: false,
space: 708,
linePitch: 360,
headerId: 100,
@@ -40,6 +41,7 @@ describe("SectionProperties", () => {
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
+ "w:mirrorMargins": false,
},
},
],
@@ -69,6 +71,7 @@ describe("SectionProperties", () => {
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
+ "w:mirrorMargins": false,
},
},
],
@@ -99,6 +102,7 @@ describe("SectionProperties", () => {
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
+ "w:mirrorMargins": false,
},
},
],
@@ -124,6 +128,7 @@ describe("SectionProperties", () => {
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
+ "w:mirrorMargins": false,
},
},
],
@@ -150,6 +155,7 @@ describe("SectionProperties", () => {
"w:left": 1440,
"w:header": 708,
"w:gutter": 0,
+ "w:mirrorMargins": false,
},
},
],
diff --git a/src/file/document/body/section-properties/section-properties.ts b/src/file/document/body/section-properties/section-properties.ts
index c23964cd14..5042c8a3ab 100644
--- a/src/file/document/body/section-properties/section-properties.ts
+++ b/src/file/document/body/section-properties/section-properties.ts
@@ -38,6 +38,7 @@ export class SectionProperties extends XmlComponent {
header: 708,
footer: 708,
gutter: 0,
+ mirror: false,
space: 708,
linePitch: 360,
orientation: PageOrientation.PORTRAIT,
@@ -69,6 +70,7 @@ export class SectionProperties extends XmlComponent {
mergedOptions.header,
mergedOptions.footer,
mergedOptions.gutter,
+ mergedOptions.mirror,
),
);
this.root.push(new Columns(mergedOptions.space));
diff --git a/src/file/document/index.ts b/src/file/document/index.ts
index 6b128299f6..3430666623 100644
--- a/src/file/document/index.ts
+++ b/src/file/document/index.ts
@@ -1,2 +1,3 @@
export * from "./document";
+export * from "./document-attributes";
export * from "./body";
diff --git a/src/file/file.ts b/src/file/file.ts
index dcf0b0499c..8d1b07f827 100644
--- a/src/file/file.ts
+++ b/src/file/file.ts
@@ -21,7 +21,7 @@ import { PageReferenceInstruction, TableOfContents } from "./table-of-contents";
export class File {
private readonly document: Document;
- private readonly styles: Styles;
+ private styles: Styles;
private readonly coreProperties: CoreProperties;
private readonly numbering: Numbering;
private readonly media: Media;
@@ -225,6 +225,10 @@ export class File {
return this.styles;
}
+ public set Styles(styles: Styles) {
+ this.styles = styles;
+ }
+
public get CoreProperties(): CoreProperties {
return this.coreProperties;
}
diff --git a/src/file/paragraph/run/formatting.ts b/src/file/paragraph/run/formatting.ts
index 8b1be933ec..30d437e268 100644
--- a/src/file/paragraph/run/formatting.ts
+++ b/src/file/paragraph/run/formatting.ts
@@ -25,6 +25,17 @@ export class BoldComplexScript extends XmlComponent {
}
}
+export class CharacterSpacing extends XmlComponent {
+ constructor(value: number) {
+ super("w:spacing");
+ this.root.push(
+ new Attributes({
+ val: value,
+ }),
+ );
+ }
+}
+
export class Italics extends XmlComponent {
constructor() {
super("w:i");
diff --git a/src/file/styles/style/index.ts b/src/file/styles/style/index.ts
index 655cc28d2a..ee2d6d84aa 100644
--- a/src/file/styles/style/index.ts
+++ b/src/file/styles/style/index.ts
@@ -47,12 +47,14 @@ export class ParagraphStyle extends Style {
this.root.push(this.runProperties);
}
- public addParagraphProperty(property: XmlComponent): void {
+ public addParagraphProperty(property: XmlComponent): ParagraphStyle {
this.paragraphProperties.push(property);
+ return this;
}
- public addRunProperty(property: XmlComponent): void {
+ public addRunProperty(property: XmlComponent): ParagraphStyle {
this.runProperties.push(property);
+ return this;
}
public basedOn(parentId: string): ParagraphStyle {
@@ -73,121 +75,101 @@ export class ParagraphStyle extends Style {
// ---------- Run formatting ---------------------- //
public size(twips: number): ParagraphStyle {
- this.addRunProperty(new formatting.Size(twips));
- this.addRunProperty(new formatting.SizeComplexScript(twips));
- return this;
+ return this.addRunProperty(new formatting.Size(twips)).addRunProperty(new formatting.SizeComplexScript(twips));
}
public bold(): ParagraphStyle {
- this.addRunProperty(new formatting.Bold());
- return this;
+ return this.addRunProperty(new formatting.Bold());
}
public italics(): ParagraphStyle {
- this.addRunProperty(new formatting.Italics());
- return this;
+ return this.addRunProperty(new formatting.Italics());
}
public smallCaps(): ParagraphStyle {
- this.addRunProperty(new formatting.SmallCaps());
- return this;
+ return this.addRunProperty(new formatting.SmallCaps());
}
public allCaps(): ParagraphStyle {
- this.addRunProperty(new formatting.Caps());
- return this;
+ return this.addRunProperty(new formatting.Caps());
}
public strike(): ParagraphStyle {
- this.addRunProperty(new formatting.Strike());
- return this;
+ return this.addRunProperty(new formatting.Strike());
}
public doubleStrike(): ParagraphStyle {
- this.addRunProperty(new formatting.DoubleStrike());
- return this;
+ return this.addRunProperty(new formatting.DoubleStrike());
}
public subScript(): ParagraphStyle {
- this.addRunProperty(new formatting.SubScript());
- return this;
+ return this.addRunProperty(new formatting.SubScript());
}
public superScript(): ParagraphStyle {
- this.addRunProperty(new formatting.SuperScript());
- return this;
+ return this.addRunProperty(new formatting.SuperScript());
}
public underline(underlineType?: string, color?: string): ParagraphStyle {
- this.addRunProperty(new formatting.Underline(underlineType, color));
- return this;
+ return this.addRunProperty(new formatting.Underline(underlineType, color));
}
public color(color: string): ParagraphStyle {
- this.addRunProperty(new formatting.Color(color));
- return this;
+ return this.addRunProperty(new formatting.Color(color));
}
public font(fontName: string): ParagraphStyle {
- this.addRunProperty(new formatting.RunFonts(fontName));
- return this;
+ return this.addRunProperty(new formatting.RunFonts(fontName));
+ }
+
+ public characterSpacing(value: number): ParagraphStyle {
+ return this.addRunProperty(new formatting.CharacterSpacing(value));
}
// --------------------- Paragraph formatting ------------------------ //
public center(): ParagraphStyle {
- this.addParagraphProperty(new paragraph.Alignment("center"));
- return this;
+ return this.addParagraphProperty(new paragraph.Alignment("center"));
}
public left(): ParagraphStyle {
- this.addParagraphProperty(new paragraph.Alignment("left"));
- return this;
+ return this.addParagraphProperty(new paragraph.Alignment("left"));
}
public right(): ParagraphStyle {
- this.addParagraphProperty(new paragraph.Alignment("right"));
- return this;
+ return this.addParagraphProperty(new paragraph.Alignment("right"));
}
public justified(): ParagraphStyle {
- this.addParagraphProperty(new paragraph.Alignment("both"));
- return this;
+ return this.addParagraphProperty(new paragraph.Alignment("both"));
}
public thematicBreak(): ParagraphStyle {
- this.addParagraphProperty(new paragraph.ThematicBreak());
- return this;
+ return this.addParagraphProperty(new paragraph.ThematicBreak());
}
public maxRightTabStop(): ParagraphStyle {
- this.addParagraphProperty(new paragraph.MaxRightTabStop());
- return this;
+ return this.addParagraphProperty(new paragraph.MaxRightTabStop());
}
public leftTabStop(position: number): ParagraphStyle {
- this.addParagraphProperty(new paragraph.LeftTabStop(position));
- return this;
+ return this.addParagraphProperty(new paragraph.LeftTabStop(position));
}
public indent(attrs: object): ParagraphStyle {
- this.addParagraphProperty(new paragraph.Indent(attrs));
- return this;
+ return this.addParagraphProperty(new paragraph.Indent(attrs));
}
public spacing(params: paragraph.ISpacingProperties): ParagraphStyle {
- this.addParagraphProperty(new paragraph.Spacing(params));
- return this;
+ return this.addParagraphProperty(new paragraph.Spacing(params));
}
public keepNext(): ParagraphStyle {
- this.addParagraphProperty(new paragraph.KeepNext());
- return this;
+ return this.addParagraphProperty(new paragraph.KeepNext());
}
public keepLines(): ParagraphStyle {
- this.addParagraphProperty(new paragraph.KeepLines());
- return this;
+ return this.addParagraphProperty(new paragraph.KeepLines());
}
}
@@ -267,24 +249,21 @@ export class CharacterStyle extends Style {
return this;
}
- public addRunProperty(property: XmlComponent): void {
+ public addRunProperty(property: XmlComponent): CharacterStyle {
this.runProperties.push(property);
+ return this;
}
public color(color: string): CharacterStyle {
- this.addRunProperty(new formatting.Color(color));
- return this;
+ return this.addRunProperty(new formatting.Color(color));
}
public underline(underlineType?: string, color?: string): CharacterStyle {
- this.addRunProperty(new formatting.Underline(underlineType, color));
- return this;
+ return this.addRunProperty(new formatting.Underline(underlineType, color));
}
public size(twips: number): CharacterStyle {
- this.addRunProperty(new formatting.Size(twips));
- this.addRunProperty(new formatting.SizeComplexScript(twips));
- return this;
+ return this.addRunProperty(new formatting.Size(twips)).addRunProperty(new formatting.SizeComplexScript(twips));
}
}
diff --git a/src/file/styles/styles.spec.ts b/src/file/styles/styles.spec.ts
index 1c828337b2..6262b3cb9e 100644
--- a/src/file/styles/styles.spec.ts
+++ b/src/file/styles/styles.spec.ts
@@ -219,6 +219,20 @@ describe("ParagraphStyle", () => {
});
});
+ it("#character spacing", () => {
+ const style = new ParagraphStyle("myStyleId").characterSpacing(24);
+ const tree = new Formatter().format(style);
+ expect(tree).to.deep.equal({
+ "w:style": [
+ { _attr: { "w:type": "paragraph", "w:styleId": "myStyleId" } },
+ { "w:pPr": [] },
+ {
+ "w:rPr": [{ "w:spacing": [{ _attr: { "w:val": 24 } }] }],
+ },
+ ],
+ });
+ });
+
it("#left", () => {
const style = new ParagraphStyle("myStyleId").left();
const tree = new Formatter().format(style);
diff --git a/src/file/table/properties.ts b/src/file/table/properties.ts
index 7c5b0bad76..91ef393df3 100644
--- a/src/file/table/properties.ts
+++ b/src/file/table/properties.ts
@@ -3,13 +3,13 @@ import { WidthType } from "./table-cell";
import { TableCellMargin } from "./table-cell-margin";
export class TableProperties extends XmlComponent {
- private readonly cellMargain: TableCellMargin;
+ private readonly cellMargin: TableCellMargin;
constructor() {
super("w:tblPr");
- this.cellMargain = new TableCellMargin();
- this.root.push(this.cellMargain);
+ this.cellMargin = new TableCellMargin();
+ this.root.push(this.cellMargin);
}
public setWidth(type: WidthType, w: number | string): TableProperties {
@@ -28,7 +28,7 @@ export class TableProperties extends XmlComponent {
}
public get CellMargin(): TableCellMargin {
- return this.cellMargain;
+ return this.cellMargin;
}
}