merge with master, demo27 became demo28

This commit is contained in:
Sergio Mendonça
2018-09-21 07:40:58 -03:00
22 changed files with 164 additions and 86 deletions

4
.gitignore vendored
View File

@ -48,8 +48,12 @@ docs/.nojekyll
!.vscode/extensions.json !.vscode/extensions.json
.history .history
# IntelliJ
.idea
# Lock files # Lock files
package-lock.json package-lock.json
yarn.lock
# Documents # Documents
My Document.docx My Document.docx

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v8

View File

@ -1,5 +1,5 @@
<p align="center"> <p align="center">
<img alt="clippy the assistant" src="http://i60.tinypic.com/339pvtt.png"> <img alt="clippy the assistant" src="https://i.imgur.com/37uBGhO.gif">
</p> </p>
<p align="center"> <p align="center">
@ -17,11 +17,20 @@
[![PRs Welcome][pr-image]][pr-url] [![PRs Welcome][pr-image]][pr-url]
<p align="center"> <p align="center">
<img src="https://thumbs.gfycat.com/ComplexEminentEquine-size_restricted.gif" alt="drawing" width="800"/> <img src="https://i.imgur.com/H5FA1Qy.gif" alt="drawing" width="800"/>
</p> </p>
# Demo # 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: Press `endpoint` on the `RunKit` website:
![RunKit Instructions](https://user-images.githubusercontent.com/2917613/38582539-f84311b6-3d07-11e8-90db-5885ae02c3c4.png) ![RunKit Instructions](https://user-images.githubusercontent.com/2917613/38582539-f84311b6-3d07-11e8-90db-5885ae02c3c4.png)
@ -33,9 +42,11 @@ Press `endpoint` on the `RunKit` website:
* https://runkit.com/dolanmiu/docx-demo5 - Images * https://runkit.com/dolanmiu/docx-demo5 - Images
* https://runkit.com/dolanmiu/docx-demo6 - Margins * https://runkit.com/dolanmiu/docx-demo6 - Margins
* https://runkit.com/dolanmiu/docx-demo7 - Landscape * 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** * 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 # 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! 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!

View File

@ -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 * 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: // The first argument is an ID you use to apply the style to paragraphs
// http://officeopenxml.com/WPtableOfContents.php // The second argument is a human-friendly name to show in the UI
// Creates an table of contents with default properties myStyles.createParagraphStyle("myWonkyStyle", "My Wonky Style")
const toc = new TableOfContents(); .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. myStyles.createParagraphStyle("Heading2", "Heading 2")
doc.addTableOfContents(toc) .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.createParagraph("Hello").style("myWonkyStyle");
doc.addParagraph(new Paragraph("I'm a little text very nicely written.'")); doc.createParagraph("World").heading2(); // Uses the Heading2 style
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(); const packer = new Packer();
packer.toBuffer(doc).then((buffer) => { 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!");
}); });

28
demo/demo28.ts Normal file
View File

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

View File

@ -1,5 +1,5 @@
<p align="center"> <p align="center">
<img alt="clippy the assistant" src="http://i60.tinypic.com/339pvtt.png"> <img alt="clippy the assistant" src="https://i.imgur.com/pwCV6L8.png">
</p> </p>
<p align="center"> <p align="center">
@ -54,6 +54,10 @@ exporter.pack("My First Document");
[@h4buli](https://github.com/h4buli) [@h4buli](https://github.com/h4buli)
<p align="center">
<img alt="clippy the assistant" src="http://i60.tinypic.com/339pvtt.png">
</p>
--- ---
Made with 💖 Made with 💖

View File

@ -20,6 +20,7 @@ const name = new TextRun("Name:")
* `.size(halfPts)`: Set the font size, measured in half-points * `.size(halfPts)`: Set the font size, measured in half-points
* `.font(name)`: Set the run's font * `.font(name)`: Set the run's font
* `.style(name)`: Apply a named run style * `.style(name)`: Apply a named run style
* `.characterSpacing(value)`: Set the character spacing adjustment (in TWIPs)
* For paragraph formatting: * For paragraph formatting:
* `.heading1()`, `.heading2()`, `.heading3()`, `.heading4()`, `.heading5()`, `.title()`: apply the appropriate style to the paragraph * `.heading1()`, `.heading2()`, `.heading3()`, `.heading4()`, `.heading5()`, `.title()`: apply the appropriate style to the paragraph
* `.left()`, `.center()`, `.right()`, `.justified()`: set the paragraph's alignment * `.left()`, `.center()`, `.right()`, `.justified()`: set the paragraph's alignment

BIN
logo/logo-small.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
logo/logo-small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
logo/logo-small.psd Normal file

Binary file not shown.

BIN
logo/logo.psd Normal file

Binary file not shown.

View File

@ -1,6 +1,6 @@
{ {
"name": "docx", "name": "docx",
"version": "4.0.0", "version": "4.1.0",
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)", "description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
"main": "build/index.js", "main": "build/index.js",
"scripts": { "scripts": {
@ -82,5 +82,8 @@
"typedoc": "^0.11.1", "typedoc": "^0.11.1",
"typescript": "2.9.2", "typescript": "2.9.2",
"webpack": "^3.10.0" "webpack": "^3.10.0"
},
"engines": {
"node": ">=8"
} }
} }

View File

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

View File

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

View File

@ -17,6 +17,7 @@ describe("SectionProperties", () => {
header: 708, header: 708,
footer: 708, footer: 708,
gutter: 0, gutter: 0,
mirror: false,
space: 708, space: 708,
linePitch: 360, linePitch: 360,
headerId: 100, headerId: 100,
@ -40,6 +41,7 @@ describe("SectionProperties", () => {
"w:left": 1440, "w:left": 1440,
"w:header": 708, "w:header": 708,
"w:gutter": 0, "w:gutter": 0,
"w:mirrorMargins": false,
}, },
}, },
], ],
@ -69,6 +71,7 @@ describe("SectionProperties", () => {
"w:left": 1440, "w:left": 1440,
"w:header": 708, "w:header": 708,
"w:gutter": 0, "w:gutter": 0,
"w:mirrorMargins": false,
}, },
}, },
], ],
@ -99,6 +102,7 @@ describe("SectionProperties", () => {
"w:left": 1440, "w:left": 1440,
"w:header": 708, "w:header": 708,
"w:gutter": 0, "w:gutter": 0,
"w:mirrorMargins": false,
}, },
}, },
], ],
@ -124,6 +128,7 @@ describe("SectionProperties", () => {
"w:left": 1440, "w:left": 1440,
"w:header": 708, "w:header": 708,
"w:gutter": 0, "w:gutter": 0,
"w:mirrorMargins": false,
}, },
}, },
], ],
@ -150,6 +155,7 @@ describe("SectionProperties", () => {
"w:left": 1440, "w:left": 1440,
"w:header": 708, "w:header": 708,
"w:gutter": 0, "w:gutter": 0,
"w:mirrorMargins": false,
}, },
}, },
], ],

View File

@ -38,6 +38,7 @@ export class SectionProperties extends XmlComponent {
header: 708, header: 708,
footer: 708, footer: 708,
gutter: 0, gutter: 0,
mirror: false,
space: 708, space: 708,
linePitch: 360, linePitch: 360,
orientation: PageOrientation.PORTRAIT, orientation: PageOrientation.PORTRAIT,
@ -69,6 +70,7 @@ export class SectionProperties extends XmlComponent {
mergedOptions.header, mergedOptions.header,
mergedOptions.footer, mergedOptions.footer,
mergedOptions.gutter, mergedOptions.gutter,
mergedOptions.mirror,
), ),
); );
this.root.push(new Columns(mergedOptions.space)); this.root.push(new Columns(mergedOptions.space));

View File

@ -1,2 +1,3 @@
export * from "./document"; export * from "./document";
export * from "./document-attributes";
export * from "./body"; export * from "./body";

View File

@ -21,7 +21,7 @@ import { PageReferenceInstruction, TableOfContents } from "./table-of-contents";
export class File { export class File {
private readonly document: Document; private readonly document: Document;
private readonly styles: Styles; private styles: Styles;
private readonly coreProperties: CoreProperties; private readonly coreProperties: CoreProperties;
private readonly numbering: Numbering; private readonly numbering: Numbering;
private readonly media: Media; private readonly media: Media;
@ -225,6 +225,10 @@ export class File {
return this.styles; return this.styles;
} }
public set Styles(styles: Styles) {
this.styles = styles;
}
public get CoreProperties(): CoreProperties { public get CoreProperties(): CoreProperties {
return this.coreProperties; return this.coreProperties;
} }

View File

@ -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 { export class Italics extends XmlComponent {
constructor() { constructor() {
super("w:i"); super("w:i");

View File

@ -47,12 +47,14 @@ export class ParagraphStyle extends Style {
this.root.push(this.runProperties); this.root.push(this.runProperties);
} }
public addParagraphProperty(property: XmlComponent): void { public addParagraphProperty(property: XmlComponent): ParagraphStyle {
this.paragraphProperties.push(property); this.paragraphProperties.push(property);
return this;
} }
public addRunProperty(property: XmlComponent): void { public addRunProperty(property: XmlComponent): ParagraphStyle {
this.runProperties.push(property); this.runProperties.push(property);
return this;
} }
public basedOn(parentId: string): ParagraphStyle { public basedOn(parentId: string): ParagraphStyle {
@ -73,121 +75,101 @@ export class ParagraphStyle extends Style {
// ---------- Run formatting ---------------------- // // ---------- Run formatting ---------------------- //
public size(twips: number): ParagraphStyle { public size(twips: number): ParagraphStyle {
this.addRunProperty(new formatting.Size(twips)); return this.addRunProperty(new formatting.Size(twips)).addRunProperty(new formatting.SizeComplexScript(twips));
this.addRunProperty(new formatting.SizeComplexScript(twips));
return this;
} }
public bold(): ParagraphStyle { public bold(): ParagraphStyle {
this.addRunProperty(new formatting.Bold()); return this.addRunProperty(new formatting.Bold());
return this;
} }
public italics(): ParagraphStyle { public italics(): ParagraphStyle {
this.addRunProperty(new formatting.Italics()); return this.addRunProperty(new formatting.Italics());
return this;
} }
public smallCaps(): ParagraphStyle { public smallCaps(): ParagraphStyle {
this.addRunProperty(new formatting.SmallCaps()); return this.addRunProperty(new formatting.SmallCaps());
return this;
} }
public allCaps(): ParagraphStyle { public allCaps(): ParagraphStyle {
this.addRunProperty(new formatting.Caps()); return this.addRunProperty(new formatting.Caps());
return this;
} }
public strike(): ParagraphStyle { public strike(): ParagraphStyle {
this.addRunProperty(new formatting.Strike()); return this.addRunProperty(new formatting.Strike());
return this;
} }
public doubleStrike(): ParagraphStyle { public doubleStrike(): ParagraphStyle {
this.addRunProperty(new formatting.DoubleStrike()); return this.addRunProperty(new formatting.DoubleStrike());
return this;
} }
public subScript(): ParagraphStyle { public subScript(): ParagraphStyle {
this.addRunProperty(new formatting.SubScript()); return this.addRunProperty(new formatting.SubScript());
return this;
} }
public superScript(): ParagraphStyle { public superScript(): ParagraphStyle {
this.addRunProperty(new formatting.SuperScript()); return this.addRunProperty(new formatting.SuperScript());
return this;
} }
public underline(underlineType?: string, color?: string): ParagraphStyle { public underline(underlineType?: string, color?: string): ParagraphStyle {
this.addRunProperty(new formatting.Underline(underlineType, color)); return this.addRunProperty(new formatting.Underline(underlineType, color));
return this;
} }
public color(color: string): ParagraphStyle { public color(color: string): ParagraphStyle {
this.addRunProperty(new formatting.Color(color)); return this.addRunProperty(new formatting.Color(color));
return this;
} }
public font(fontName: string): ParagraphStyle { public font(fontName: string): ParagraphStyle {
this.addRunProperty(new formatting.RunFonts(fontName)); return this.addRunProperty(new formatting.RunFonts(fontName));
return this; }
public characterSpacing(value: number): ParagraphStyle {
return this.addRunProperty(new formatting.CharacterSpacing(value));
} }
// --------------------- Paragraph formatting ------------------------ // // --------------------- Paragraph formatting ------------------------ //
public center(): ParagraphStyle { public center(): ParagraphStyle {
this.addParagraphProperty(new paragraph.Alignment("center")); return this.addParagraphProperty(new paragraph.Alignment("center"));
return this;
} }
public left(): ParagraphStyle { public left(): ParagraphStyle {
this.addParagraphProperty(new paragraph.Alignment("left")); return this.addParagraphProperty(new paragraph.Alignment("left"));
return this;
} }
public right(): ParagraphStyle { public right(): ParagraphStyle {
this.addParagraphProperty(new paragraph.Alignment("right")); return this.addParagraphProperty(new paragraph.Alignment("right"));
return this;
} }
public justified(): ParagraphStyle { public justified(): ParagraphStyle {
this.addParagraphProperty(new paragraph.Alignment("both")); return this.addParagraphProperty(new paragraph.Alignment("both"));
return this;
} }
public thematicBreak(): ParagraphStyle { public thematicBreak(): ParagraphStyle {
this.addParagraphProperty(new paragraph.ThematicBreak()); return this.addParagraphProperty(new paragraph.ThematicBreak());
return this;
} }
public maxRightTabStop(): ParagraphStyle { public maxRightTabStop(): ParagraphStyle {
this.addParagraphProperty(new paragraph.MaxRightTabStop()); return this.addParagraphProperty(new paragraph.MaxRightTabStop());
return this;
} }
public leftTabStop(position: number): ParagraphStyle { public leftTabStop(position: number): ParagraphStyle {
this.addParagraphProperty(new paragraph.LeftTabStop(position)); return this.addParagraphProperty(new paragraph.LeftTabStop(position));
return this;
} }
public indent(attrs: object): ParagraphStyle { public indent(attrs: object): ParagraphStyle {
this.addParagraphProperty(new paragraph.Indent(attrs)); return this.addParagraphProperty(new paragraph.Indent(attrs));
return this;
} }
public spacing(params: paragraph.ISpacingProperties): ParagraphStyle { public spacing(params: paragraph.ISpacingProperties): ParagraphStyle {
this.addParagraphProperty(new paragraph.Spacing(params)); return this.addParagraphProperty(new paragraph.Spacing(params));
return this;
} }
public keepNext(): ParagraphStyle { public keepNext(): ParagraphStyle {
this.addParagraphProperty(new paragraph.KeepNext()); return this.addParagraphProperty(new paragraph.KeepNext());
return this;
} }
public keepLines(): ParagraphStyle { public keepLines(): ParagraphStyle {
this.addParagraphProperty(new paragraph.KeepLines()); return this.addParagraphProperty(new paragraph.KeepLines());
return this;
} }
} }
@ -267,24 +249,21 @@ export class CharacterStyle extends Style {
return this; return this;
} }
public addRunProperty(property: XmlComponent): void { public addRunProperty(property: XmlComponent): CharacterStyle {
this.runProperties.push(property); this.runProperties.push(property);
return this;
} }
public color(color: string): CharacterStyle { public color(color: string): CharacterStyle {
this.addRunProperty(new formatting.Color(color)); return this.addRunProperty(new formatting.Color(color));
return this;
} }
public underline(underlineType?: string, color?: string): CharacterStyle { public underline(underlineType?: string, color?: string): CharacterStyle {
this.addRunProperty(new formatting.Underline(underlineType, color)); return this.addRunProperty(new formatting.Underline(underlineType, color));
return this;
} }
public size(twips: number): CharacterStyle { public size(twips: number): CharacterStyle {
this.addRunProperty(new formatting.Size(twips)); return this.addRunProperty(new formatting.Size(twips)).addRunProperty(new formatting.SizeComplexScript(twips));
this.addRunProperty(new formatting.SizeComplexScript(twips));
return this;
} }
} }

View File

@ -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", () => { it("#left", () => {
const style = new ParagraphStyle("myStyleId").left(); const style = new ParagraphStyle("myStyleId").left();
const tree = new Formatter().format(style); const tree = new Formatter().format(style);

View File

@ -3,13 +3,13 @@ import { WidthType } from "./table-cell";
import { TableCellMargin } from "./table-cell-margin"; import { TableCellMargin } from "./table-cell-margin";
export class TableProperties extends XmlComponent { export class TableProperties extends XmlComponent {
private readonly cellMargain: TableCellMargin; private readonly cellMargin: TableCellMargin;
constructor() { constructor() {
super("w:tblPr"); super("w:tblPr");
this.cellMargain = new TableCellMargin(); this.cellMargin = new TableCellMargin();
this.root.push(this.cellMargain); this.root.push(this.cellMargin);
} }
public setWidth(type: WidthType, w: number | string): TableProperties { public setWidth(type: WidthType, w: number | string): TableProperties {
@ -28,7 +28,7 @@ export class TableProperties extends XmlComponent {
} }
public get CellMargin(): TableCellMargin { public get CellMargin(): TableCellMargin {
return this.cellMargain; return this.cellMargin;
} }
} }