Merge branch 'master' into feat/table-of-contents

This commit is contained in:
Sergio Mendonça
2018-08-23 06:21:01 -03:00
90 changed files with 1589 additions and 1248 deletions

View File

@ -8,18 +8,30 @@ script:
- npm test - npm test
- npm run style - npm run style
- npm run build - npm run build
- node ./demo/demo1.js - npm run ts-node -- ./demo/demo1.ts
- node ./demo/demo2.js - npm run ts-node -- ./demo/demo2.ts
- node ./demo/demo3.js - npm run ts-node -- ./demo/demo3.ts
- node ./demo/demo4.js - npm run ts-node -- ./demo/demo4.ts
- node ./demo/demo5.js - npm run ts-node -- ./demo/demo5.ts
- node ./demo/demo6.js - npm run ts-node -- ./demo/demo6.ts
- node ./demo/demo7.js - npm run ts-node -- ./demo/demo7.ts
- node ./demo/demo8.js - npm run ts-node -- ./demo/demo8.ts
- node ./demo/demo9.js - npm run ts-node -- ./demo/demo9.ts
- node ./demo/demo10.js - npm run ts-node -- ./demo/demo10.ts
- node ./demo/demo11.js - npm run ts-node -- ./demo/demo11.ts
- node ./demo/demo12.js - npm run ts-node -- ./demo/demo12.ts
- npm run ts-node -- ./demo/demo13.ts
- npm run ts-node -- ./demo/demo14.ts
- npm run ts-node -- ./demo/demo15.ts
- npm run ts-node -- ./demo/demo16.ts
- npm run ts-node -- ./demo/demo17.ts
- npm run ts-node -- ./demo/demo18.ts
- npm run ts-node -- ./demo/demo19.ts
- npm run ts-node -- ./demo/demo20.ts
- npm run ts-node -- ./demo/demo21.ts
- npm run ts-node -- ./demo/demo22.ts
- npm run ts-node -- ./demo/demo23.ts
- npm run ts-node -- ./demo/demo24.ts
after_failure: after_failure:
- "cat /home/travis/builds/dolanmiu/docx/npm-debug.log" - "cat /home/travis/builds/dolanmiu/docx/npm-debug.log"
after_success: after_success:

View File

@ -3,7 +3,7 @@
</p> </p>
<p align="center"> <p align="center">
Easily generate .docx files with JS/TS. Easily generate .docx files with JS/TS. Works for Node and on the Browser.
</p> </p>
--- ---

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

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

View File

@ -1,16 +0,0 @@
const docx = require('../build');
var doc = new docx.Document();
var paragraph = new docx.Paragraph("Hello World");
var institutionText = new docx.TextRun("University College London").bold();
var dateText = new docx.TextRun("5th Dec 2015").tab().bold();
paragraph.addRun(institutionText);
paragraph.addRun(dateText);
doc.addParagraph(paragraph);
var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

20
demo/demo1.ts Normal file
View File

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

View File

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

View File

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

View File

@ -1,21 +0,0 @@
const docx = require("../build");
var doc = new docx.Document();
var paragraph = new docx.Paragraph("Hello World");
doc.addParagraph(paragraph);
const image = doc.createImage("./demo/images/pizza.gif");
const image2 = doc.createImage("./demo/images/pizza.gif");
const image3 = doc.createImage("./demo/images/pizza.gif");
const image4 = doc.createImage("./demo/images/pizza.gif");
image.scale(0.5);
image2.scale(1)
image3.scale(2.5);
image4.scale(4);
var exporter = new docx.LocalPacker(doc);
exporter.pack("My Document");
console.log("Document created successfully at project root!");

25
demo/demo12.ts Normal file
View File

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

View File

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

28
demo/demo13.ts Normal file
View File

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

View File

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

28
demo/demo14.ts Normal file
View File

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

View File

@ -1,14 +0,0 @@
const docx = require('../build');
var doc = new docx.Document();
var paragraph = new docx.Paragraph("Hello World");
var paragraph2 = new docx.Paragraph("Hello World on another page").pageBreakBefore();
doc.addParagraph(paragraph);
doc.addParagraph(paragraph2);
var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

18
demo/demo15.ts Normal file
View File

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

View File

@ -1,36 +0,0 @@
const docx = require("../build");
var doc = new docx.Document();
var paragraph = new docx.Paragraph("Hello World").pageBreak();
doc.addParagraph(paragraph);
var header = doc.createHeader();
header.createParagraph("Header on another page");
var footer = doc.createFooter();
footer.createParagraph("Footer on another page");
doc.addSection({
headerId: header.Header.ReferenceId,
footerId: footer.Footer.ReferenceId,
pageNumberStart: 1,
pageNumberFormatType: docx.PageNumberFormat.DECIMAL,
});
doc.createParagraph("hello");
doc.addSection({
headerId: header.Header.ReferenceId,
footerId: footer.Footer.ReferenceId,
pageNumberStart: 1,
pageNumberFormatType: docx.PageNumberFormat.DECIMAL,
orientation: docx.PageOrientation.LANDSCAPE,
});
doc.createParagraph("hello in landscape");
var exporter = new docx.LocalPacker(doc);
exporter.pack("My Document");
console.log("Document created successfully at project root!");

40
demo/demo16.ts Normal file
View File

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

View File

@ -1,17 +0,0 @@
const docx = require('../build');
var doc = new docx.Document();
var paragraph = new docx.Paragraph("Hello World").referenceFootnote(1);
var paragraph2 = new docx.Paragraph("Hello World").referenceFootnote(2);
doc.addParagraph(paragraph);
doc.addParagraph(paragraph2);
doc.createFootnote(new docx.Paragraph("Test"));
doc.createFootnote(new docx.Paragraph("My amazing reference"));
var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

21
demo/demo17.ts Normal file
View File

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

View File

@ -1,15 +1,17 @@
// Insert image from a buffer // Insert image from a buffer
const docx = require('../build'); // Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer } from "../build";
var doc = new docx.Document(); const doc = new Document();
const imageBase64Data = `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`;
const imageBase64Data = `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` // doc.createImage(Buffer.from(imageBase64Data, 'base64'));
doc.createImage(Buffer.from(imageBase64Data, "base64"), 100, 100);
// doc.createImageFromBuffer(Buffer.from(imageBase64Data, 'base64')); const packer = new Packer();
doc.createImageFromBuffer(Buffer.from(imageBase64Data, 'base64'), 100, 100);
var exporter = new docx.LocalPacker(doc); packer.toBuffer(doc).then((buffer) => {
exporter.pack('My Document'); fs.writeFileSync("My Document.docx", buffer);
});
console.log('Document created successfully at project root!');

View File

@ -1,20 +0,0 @@
const fs = require("fs");
const docx = require("../build");
var doc = new docx.Document();
var paragraph = new docx.Paragraph("Hello World");
var institutionText = new docx.TextRun("Foo").bold();
var dateText = new docx.TextRun("Bar").tab().bold();
paragraph.addRun(institutionText);
paragraph.addRun(dateText);
doc.addParagraph(paragraph);
var exporter = new docx.BufferPacker(doc);
exporter.pack("My Document").then((buffer) => {
// At this point, you can do anything with the buffer, including casting it to a string etc.
console.log(buffer);
fs.writeFileSync('My Document.docx', buffer);
console.log("Document created successfully at project root!");
});

20
demo/demo19.ts Normal file
View File

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

View File

@ -1,74 +0,0 @@
const docx = require('../build');
const doc = new docx.Document({
creator: 'Clippy',
title: 'Sample Document',
description: 'A brief example of using docx',
});
doc.Styles.createParagraphStyle('Heading1', 'Heading 1')
.basedOn("Normal")
.next("Normal")
.quickFormat()
.size(28)
.bold()
.italics()
.spacing({after: 120});
doc.Styles.createParagraphStyle('Heading2', 'Heading 2')
.basedOn("Normal")
.next("Normal")
.quickFormat()
.size(26)
.bold()
.underline('double', 'FF0000')
.spacing({before: 240, after: 120});
doc.Styles.createParagraphStyle('aside', 'Aside')
.basedOn('Normal')
.next('Normal')
.color('999999')
.italics()
.indent(720)
.spacing({line: 276});
doc.Styles.createParagraphStyle('wellSpaced', 'Well Spaced')
.basedOn('Normal')
.spacing({line: 276, before: 20 * 72 * .1, after: 20 * 72 * .05});
doc.Styles.createParagraphStyle('ListParagraph', 'List Paragraph')
.quickFormat()
.basedOn('Normal');
const numberedAbstract = doc.Numbering.createAbstractNumbering();
numberedAbstract.createLevel(0, "lowerLetter", "%1)", "left");
doc.createParagraph('Test heading1, bold and italicized').heading1();
doc.createParagraph('Some simple content');
doc.createParagraph('Test heading2 with double red underline').heading2();
const letterNumbering = doc.Numbering.createConcreteNumbering(numberedAbstract);
const letterNumbering5 = doc.Numbering.createConcreteNumbering(numberedAbstract);
letterNumbering5.overrideLevel(0, 5);
doc.createParagraph('Option1').setNumbering(letterNumbering, 0);
doc.createParagraph('Option5 -- override 2 to 5').setNumbering(letterNumbering5, 0);
doc.createParagraph('Option3').setNumbering(letterNumbering, 0);
doc.createParagraph()
.createTextRun('Some monospaced content')
.font('Monospace');
doc.createParagraph('An aside, in light gray italics and indented').style('aside');
doc.createParagraph('This is normal, but well-spaced text').style('wellSpaced');
const para = doc.createParagraph();
para.createTextRun('This is a bold run,').bold();
para.createTextRun(' switching to normal ');
para.createTextRun('and then underlined ').underline();
para.createTextRun('and back to normal.');
const exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

78
demo/demo2.ts Normal file
View File

@ -0,0 +1,78 @@
// Example on how to customise the look at feel using Styles
// Import from 'docx' rather than '../build' if you install from npm
import * as fs from "fs";
import { Document, Packer } from "../build";
const doc = new Document({
creator: "Clippy",
title: "Sample Document",
description: "A brief example of using docx",
});
doc.Styles.createParagraphStyle("Heading1", "Heading 1")
.basedOn("Normal")
.next("Normal")
.quickFormat()
.size(28)
.bold()
.italics()
.spacing({ after: 120 });
doc.Styles.createParagraphStyle("Heading2", "Heading 2")
.basedOn("Normal")
.next("Normal")
.quickFormat()
.size(26)
.bold()
.underline("double", "FF0000")
.spacing({ before: 240, after: 120 });
doc.Styles.createParagraphStyle("aside", "Aside")
.basedOn("Normal")
.next("Normal")
.color("999999")
.italics()
.indent({ left: 720 })
.spacing({ line: 276 });
doc.Styles.createParagraphStyle("wellSpaced", "Well Spaced")
.basedOn("Normal")
.spacing({ line: 276, before: 20 * 72 * 0.1, after: 20 * 72 * 0.05 });
doc.Styles.createParagraphStyle("ListParagraph", "List Paragraph")
.quickFormat()
.basedOn("Normal");
const numberedAbstract = doc.Numbering.createAbstractNumbering();
numberedAbstract.createLevel(0, "lowerLetter", "%1)", "left");
doc.createParagraph("Test heading1, bold and italicized").heading1();
doc.createParagraph("Some simple content");
doc.createParagraph("Test heading2 with double red underline").heading2();
const letterNumbering = doc.Numbering.createConcreteNumbering(numberedAbstract);
const letterNumbering5 = doc.Numbering.createConcreteNumbering(numberedAbstract);
letterNumbering5.overrideLevel(0, 5);
doc.createParagraph("Option1").setNumbering(letterNumbering, 0);
doc.createParagraph("Option5 -- override 2 to 5").setNumbering(letterNumbering5, 0);
doc.createParagraph("Option3").setNumbering(letterNumbering, 0);
doc
.createParagraph()
.createTextRun("Some monospaced content")
.font("Monospace");
doc.createParagraph("An aside, in light gray italics and indented").style("aside");
doc.createParagraph("This is normal, but well-spaced text").style("wellSpaced");
const para = doc.createParagraph();
para.createTextRun("This is a bold run,").bold();
para.createTextRun(" switching to normal ");
para.createTextRun("and then underlined ").underline();
para.createTextRun("and back to normal.");
const packer = new Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,17 +0,0 @@
const docx = require("../build");
var doc = new docx.Document();
const table = doc.createTable(4, 4);
table
.getCell(2, 2)
.addContent(new docx.Paragraph("Hello"))
.CellProperties.Borders.addTopBorder(docx.BorderStyle.DASH_DOT_STROKED, 3, "red")
.addBottomBorder(docx.BorderStyle.DOUBLE, 3, "blue")
.addStartBorder(docx.BorderStyle.DOT_DOT_DASH, 3, "green")
.addEndBorder(docx.BorderStyle.DOT_DOT_DASH, 3, "#ff8000");
var exporter = new docx.LocalPacker(doc);
exporter.pack("My Document");
console.log("Document created successfully at project root!");

21
demo/demo20.ts Normal file
View File

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

View File

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

37
demo/demo21.ts Normal file
View File

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

View File

@ -1,26 +0,0 @@
const docx = require('../build');
var doc = new docx.Document();
var paragraph1 = new docx.Paragraph().bidirectional();
var textRun1 = new docx.TextRun("שלום עולם").rightToLeft();
paragraph1.addRun(textRun1);
doc.addParagraph(paragraph1);
var paragraph2 = new docx.Paragraph().bidirectional();
var textRun2 = new docx.TextRun("שלום עולם").bold().rightToLeft();
paragraph2.addRun(textRun2);
doc.addParagraph(paragraph2);
var paragraph3 = new docx.Paragraph().bidirectional();
var textRun3 = new docx.TextRun("שלום עולם").italic().rightToLeft();
paragraph3.addRun(textRun3);
doc.addParagraph(paragraph3);
var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

27
demo/demo22.ts Normal file
View File

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

View File

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

View File

@ -1,15 +0,0 @@
// Add image to table cell
const docx = require('../build');
var doc = new docx.Document();
const table = doc.createTable(4, 4);
table.getCell(2, 2).addContent(new docx.Paragraph('Hello'));
const image = docx.Media.addImage(doc, "./demo/images/image1.jpeg");
table.getCell(1, 1).addContent(image);
var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

18
demo/demo24.ts Normal file
View File

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

View File

@ -1,15 +0,0 @@
const fs = require("fs");
const docx = require("../build");
var doc = new docx.Document();
var paragraph = new docx.Paragraph("Hello World");
var institutionText = new docx.TextRun("Foo").bold();
var dateText = new docx.TextRun("Bar").tab().bold();
paragraph.addRun(institutionText);
paragraph.addRun(dateText);
doc.addParagraph(paragraph);
var exporter = new docx.LocalPacker(doc);
exporter.packPdf("My Document");

22
demo/demo26.ts Normal file
View File

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

View File

@ -1,45 +0,0 @@
const docx = require('../build');
var doc = new docx.Document();
const numbering = new docx.Numbering();
const abstractNum = numbering.createAbstractNumbering();
abstractNum.createLevel(0, "upperRoman", "%1", "start")
.addParagraphProperty(new docx.Indent(720, 260));
abstractNum.createLevel(1, "decimal", "%2.", "start")
.addParagraphProperty(new docx.Indent(1440, 980));
abstractNum.createLevel(2, "lowerLetter", "%3)", "start")
.addParagraphProperty(new docx.Indent(2160, 1700));
const concrete = numbering.createConcreteNumbering(abstractNum);
var topLevelP = new docx.Paragraph("Hey you");
var subP = new docx.Paragraph("What's up fam");
var secondSubP = new docx.Paragraph("Hello World 2");
var subSubP = new docx.Paragraph("Yeah boi");
topLevelP.setNumbering(concrete, 0);
subP.setNumbering(concrete, 1);
secondSubP.setNumbering(concrete, 1);
subSubP.setNumbering(concrete, 2);
doc.addParagraph(topLevelP);
doc.addParagraph(subP);
doc.addParagraph(secondSubP);
doc.addParagraph(subSubP);
var bullet1 = new docx.Paragraph("Hey you").bullet();
var bullet2 = new docx.Paragraph("What's up fam").bullet(1);
var bullet3 = new docx.Paragraph("Hello World 2").bullet(2);
var bullet4 = new docx.Paragraph("Yeah boi").bullet(3);
doc.addParagraph(bullet1);
doc.addParagraph(bullet2);
doc.addParagraph(bullet3);
doc.addParagraph(bullet4);
var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

46
demo/demo3.ts Normal file
View File

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

View File

@ -1,12 +0,0 @@
const docx = require('../build');
var doc = new docx.Document();
const table = doc.createTable(4, 4);
table.getCell(2, 2).addContent(new docx.Paragraph('Hello'));
var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

15
demo/demo4.ts Normal file
View File

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

View File

@ -1,17 +0,0 @@
const docx = require("../build");
var doc = new docx.Document();
var paragraph = new docx.Paragraph("Hello World");
doc.addParagraph(paragraph);
doc.createImage("./demo/images/image1.jpeg");
doc.createImage("./demo/images/dog.png");
doc.createImage("./demo/images/cat.jpg");
doc.createImage("./demo/images/parrots.bmp");
doc.createImage("./demo/images/pizza.gif");
var exporter = new docx.LocalPacker(doc);
exporter.pack("My Document");
console.log("Document created successfully at project root!");

21
demo/demo5.ts Normal file
View File

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

View File

@ -1,25 +0,0 @@
const docx = require("../build");
var doc = new docx.Document(undefined, {
top: 0,
right: 0,
bottom: 0,
left: 0,
});
var paragraph = new docx.Paragraph("Hello World");
var institutionText = new docx.TextRun("University College London").bold();
var dateText = new docx.TextRun("5th Dec 2015").tab().bold();
paragraph.addRun(institutionText);
paragraph.addRun(dateText);
doc.addParagraph(paragraph);
doc.createParagraph("Hello World").heading1();
doc.createParagraph("University College London");
doc.createParagraph("5th Dec 2015");
var exporter = new docx.LocalPacker(doc);
exporter.pack("My Document");
console.log("Document created successfully at project root!");

29
demo/demo6.ts Normal file
View File

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

View File

@ -1,14 +0,0 @@
const docx = require("../build");
var doc = new docx.Document(undefined, {
orientation: "landscape",
});
var paragraph = new docx.Paragraph("Hello World");
doc.addParagraph(paragraph);
var exporter = new docx.LocalPacker(doc);
exporter.pack("My Document");
console.log("Document created successfully at project root!");

18
demo/demo7.ts Normal file
View File

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

View File

@ -1,13 +0,0 @@
const docx = require('../build');
var doc = new docx.Document();
doc.createParagraph("Hello World");
doc.Header.createParagraph("Header text");
doc.Footer.createParagraph("Footer text");
var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

17
demo/demo8.ts Normal file
View File

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

View File

@ -1,13 +0,0 @@
const docx = require('../build');
var doc = new docx.Document();
doc.createParagraph("Hello World");
doc.Header.createImage("./demo/images/pizza.gif");
doc.Footer.createImage("./demo/images/pizza.gif");
var exporter = new docx.LocalPacker(doc);
exporter.pack('My Document');
console.log('Document created successfully at project root!');

17
demo/demo9.ts Normal file
View File

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

View File

@ -1,29 +0,0 @@
var prompt = require('prompt');
var shelljs = require('shelljs');
var fs = require('fs');
console.log('What demo do you wish to run? (Enter a number)');
var schema = {
properties: {
number: {
pattern: /^[0-9]+$/,
message: 'Please enter a number.',
required: true
}
}
};
prompt.start();
prompt.get(schema, function (err, result) {
var demoNumber = result.number;
var filePath = `./demo/demo${demoNumber}.js`;
if (!fs.existsSync(filePath)) {
console.error(`demo${demoNumber} does not exist: ${filePath}`);
return;
}
console.log(`Running demo ${demoNumber}`);
shelljs.exec(`node ${filePath}`);
});

34
demo/index.ts Normal file
View File

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

View File

@ -3,7 +3,7 @@
</p> </p>
<p align="center"> <p align="center">
Easily generate .docx files with JS/TS. :100: Easily generate .docx files with JS/TS. Works for Node and on the Browser. :100:
</p> </p>
--- ---

View File

@ -14,9 +14,9 @@ This command will run the `demo selector app` in the `/demo` folder. It will pro
A simple hello world of the `docx` library: A simple hello world of the `docx` library:
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo1.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo1.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo1.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo1.ts_
## Styles ## Styles
@ -24,41 +24,41 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo1.js_
This example shows how to customise the look and feel of a document using JS configuration This example shows how to customise the look and feel of a document using JS configuration
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo2.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo2.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo2.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo2.ts_
### Styling with XML ### Styling with XML
This example shows how to customise the look and feel of a document using XML configuration This example shows how to customise the look and feel of a document using XML configuration
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo13.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo13.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo13.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo13.ts_
## Numbering ## Numbering
This example shows many levels of numbering This example shows many levels of numbering
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo3.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo3.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo3.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo3.ts_
## Table ## Table
Example of simple table Example of simple table
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo4.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo4.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo4.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo4.ts_
### Styling table borders ### Styling table borders
Styling the borders of a table Styling the borders of a table
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo20.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo20.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo20.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo20.ts_
## Images ## Images
@ -66,73 +66,73 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo20.js_
Importing Images from file system path Importing Images from file system path
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo5.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo5.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo5.ts_
### Add images to header and footer ### Add images to header and footer
Example showing how to add image to headers and footers Example showing how to add image to headers and footers
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo9.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo9.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo9.ts_
### Scaling images ### Scaling images
Example showing how to scale images Example showing how to scale images
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo12.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo12.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo12.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo12.ts_
### Add Image to media before adding to document ### Add Image to media before adding to document
This is the best way to add an image to a document because you can add the same image in two locations without increasing document size by re-using the same image This is the best way to add an image to a document because you can add the same image in two locations without increasing document size by re-using the same image
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo23.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo23.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo23.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo23.ts_
### Add image to table ### Add image to table
As before, to add an image to a table, you would need to add it to the `Media` object first As before, to add an image to a table, you would need to add it to the `Media` object first
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo24.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo24.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo24.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo24.ts_
### Images using Base64 URI ### Images using Base64 URI
If you want to use a Base64 image instead If you want to use a Base64 image instead
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo18.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo18.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo18.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo18.ts_
## Margins ## Margins
Example showing how to set custom margains Example showing how to set custom margains
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo6.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo6.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo6.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo6.ts_
## Orientation ## Orientation
Example showing how to set the document to `landscape` or `portrait` Example showing how to set the document to `landscape` or `portrait`
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo7.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo7.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo7.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo7.ts_
## Headers & Footers ## Headers & Footers
Example showing how to add headers and footers Example showing how to add headers and footers
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo8.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo8.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo8.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo8.ts_
## Multiple headers and footers ## Multiple headers and footers
@ -144,67 +144,60 @@ Check out `Sections` for this feature
Example showing how to page break Example showing how to page break
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo14.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo14.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo14.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo14.ts_
### Page break before ### Page break before
Example showing how to page break before like in Word Example showing how to page break before like in Word
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo15.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo15.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo15.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo15.ts_
## Sections ## Sections
Example of how sections work. Sections allow multiple headers and footers, and `landscape`/`portrait` inside the same document Example of how sections work. Sections allow multiple headers and footers, and `landscape`/`portrait` inside the same document
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo16.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo16.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo16.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo16.ts_
## Footnotes ## Footnotes
Example of how to add footnotes. Good for references Example of how to add footnotes. Good for references
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo17.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo17.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo17.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo17.ts_
## Packers ## Packers
## Buffer Packer ## Buffer output
Example showing how to use the Buffer packer and then write that buffer to the file system Example showing how to use the Buffer packer and then write that buffer to the file system
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo19.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo19.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo19.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo19.ts_
## PDF Packing
Example of how to use the `LocalPacker` to create a PDF document
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo25.js ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo25.js_
## Bookmarks ## Bookmarks
Example showing how to make bookmarks to make internal hyperlinks within the document Example showing how to make bookmarks to make internal hyperlinks within the document
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo21.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo21.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo21.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo21.ts_
## Bidirectional text ## Bidirectional text
Example showing how to use bidirectional text for certain languages such as Hebrew Example showing how to use bidirectional text for certain languages such as Hebrew
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo22.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo22.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo22.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo22.ts_
## Showcase ## Showcase
@ -212,14 +205,14 @@ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo22.js_
Example showing how to add headers and footers Example showing how to add headers and footers
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo10.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo10.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo10.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo10.ts_
### Style and Images ### Style and Images
This example shows how to customise the look and feel of a document and add images This example shows how to customise the look and feel of a document and add images
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo11.js ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/demo11.ts ":include")
_Source: https://github.com/dolanmiu/docx/blob/master/demo/demo11.js_ _Source: https://github.com/dolanmiu/docx/blob/master/demo/demo11.ts_

View File

@ -19,8 +19,8 @@ doc.Footer.createParagraph("Footer text");
Even add images: Even add images:
```js ```js
doc.Header.createImage([PATH_TO_YOUR_IMAGE]); doc.Header.createImage([BUFFER_OF_YOUR_IMAGE]);
doc.Footer.createImage([PATH_TO_YOUR_IMAGE]); doc.Footer.createImage([BUFFER_OF_YOUR_IMAGE]);
``` ```
Refer to `demo8.js` for more information Refer to `demo8.js` for more information

View File

@ -7,7 +7,7 @@ Adding images is very simple
Simply call the `createImage` method: Simply call the `createImage` method:
```js ```js
const image = doc.createImage([PATH_TO_YOUR_IMAGE]); const image = doc.createImage([BUFFER_OF_YOUR_IMAGE]);
``` ```
`docx` supports `jpeg`, `jpg`, `bmp`, `gif` and `png` `docx` supports `jpeg`, `jpg`, `bmp`, `gif` and `png`
@ -43,7 +43,7 @@ interface DrawingOptions {
can be passed when creating `PictureRun()` for example: can be passed when creating `PictureRun()` for example:
```js ```js
const imageData = document.createImageData(filename, buffer, 903, 1149); const imageData = document.createImage(buffer, 903, 1149);
new docx.PictureRun(imageData, { new docx.PictureRun(imageData, {
position: docx.PlacementPosition.FLOATING, position: docx.PlacementPosition.FLOATING,

View File

@ -2,7 +2,48 @@
> Packers are the way in which `docx` turns your code into `.docx` format. It is completely decoupled from the `docx.Document`. > Packers are the way in which `docx` turns your code into `.docx` format. It is completely decoupled from the `docx.Document`.
## File System Packer ## Version 4
Packers in `version 4` and above are now one single `Packer`. It works in both a node and browser environment (Angular etc). Now, the packer returns a `Buffer`, `Blob` or `base64 string`. It is up to you to take that and persist it with node's `fs`, send it down as a downloadable file, or anything else you wish. As of version 4, this library will not have options to export to PDF.
### Export as Buffer
This will return a NodeJS `Buffer`. If this is used in the browser, it will return a `UInt8Array` instead.
```js
const packer = new docx.Packer();
packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});
```
### Export as a `base64` string
```js
const packer = new docx.Packer();
packer.toBase64String(doc).then((string) => {
console.log(string);
});
```
### Export as Blob
This is useful if you want to send it as an downloadable in a browser environment.
```js
const packer = new docx.Packer();
packer.toBlob(doc).then((blob) => {
// saveAs from FileSaver will download the file
saveAs(blob, "example.docx");
});
```
## Version 3 and below
### File System Packer
```js ```js
const docx = require("docx"); const docx = require("docx");
@ -13,7 +54,7 @@ exporter.pack("My Document");
// Word Document is in file system // Word Document is in file system
``` ```
## Buffer Packer ### Buffer Packer
```js ```js
const docx = require("docx"); const docx = require("docx");
@ -23,7 +64,7 @@ const exporter = new docx.BufferPacker(doc);
const buffer = exporter.pack(); const buffer = exporter.pack();
``` ```
## Stream Packer ### Stream Packer
Creates a `node` `Readable` stream Creates a `node` `Readable` stream
@ -35,7 +76,7 @@ const exporter = new docx.StreamPacker(doc);
const stream = exporter.pack(); const stream = exporter.pack();
``` ```
## Express Packer ### Express Packer
The old express packer is now deprecated and may disappear soon, so you should upgrade. The old express packer is now deprecated and may disappear soon, so you should upgrade.
@ -56,13 +97,13 @@ const exporter = new docx.StreamPacker(doc);
const stream = exporter.pack(); const stream = exporter.pack();
// Express' response object // Express' response object
res.attachment('yourfile.xlsx'); res.attachment("yourfile.xlsx");
stream.pipe(res); stream.pipe(res);
``` ```
where `res` is the response object obtained through the Express router. It is that simple. The file will begin downloading in the browser. where `res` is the response object obtained through the Express router. It is that simple. The file will begin downloading in the browser.
## PDF Exporting ### PDF Exporting
You can export your word document as a PDF file like so: You can export your word document as a PDF file like so:
@ -74,7 +115,3 @@ exporter.packPdf("My Document");
const exporter = new docx.ExpressPacker(doc, res); const exporter = new docx.ExpressPacker(doc, res);
exporter.packPdf("My Document"); exporter.packPdf("My Document");
``` ```
## Browser based docx exporting
It is on the bucket list. It has been requested by a few, and work is already on it

View File

@ -1,6 +1,6 @@
{ {
"name": "docx", "name": "docx",
"version": "3.6.0", "version": "4.0.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": {
@ -12,11 +12,13 @@
"build": "npm run webpack && npm run fix-types", "build": "npm run webpack && npm run fix-types",
"tsc": "rimraf ./build && tsc -p .", "tsc": "rimraf ./build && tsc -p .",
"webpack": "rimraf ./build && webpack", "webpack": "rimraf ./build && webpack",
"demo": "npm run build && node ./demo", "build.web": "webpack --config webpack.web.config.js",
"demo": "npm run build && npm run ts-node ./demo",
"typedoc": "typedoc src/index.ts", "typedoc": "typedoc src/index.ts",
"style": "prettier -l \"src/**/*.ts\"", "style": "prettier -l \"src/**/*.ts\"",
"style.fix": "prettier \"src/**/*.ts\" --write", "style.fix": "prettier \"src/**/*.ts\" --write",
"fix-types": "node types-absolute-fixer.js" "fix-types": "node types-absolute-fixer.js",
"ts-node": "ts-node"
}, },
"pre-commit": [ "pre-commit": [
"style", "style",
@ -45,16 +47,11 @@
], ],
"types": "./build/index.d.ts", "types": "./build/index.d.ts",
"dependencies": { "dependencies": {
"@types/archiver": "^2.1.0",
"@types/bluebird": "3.5.20",
"@types/express": "^4.0.35",
"@types/image-size": "0.0.29", "@types/image-size": "0.0.29",
"@types/request-promise": "^4.1.42", "@types/jszip": "^3.1.3",
"archiver": "^2.1.1",
"fast-xml-parser": "^3.3.6", "fast-xml-parser": "^3.3.6",
"image-size": "^0.6.2", "image-size": "^0.6.2",
"request": "^2.83.0", "jszip": "^3.1.5",
"request-promise": "^4.2.2",
"xml": "^1.0.1" "xml": "^1.0.1"
}, },
"author": "Dolan Miu", "author": "Dolan Miu",
@ -80,6 +77,7 @@
"rimraf": "^2.5.2", "rimraf": "^2.5.2",
"shelljs": "^0.7.7", "shelljs": "^0.7.7",
"sinon": "^5.0.7", "sinon": "^5.0.7",
"ts-node": "^7.0.1",
"tslint": "^5.11.0", "tslint": "^5.11.0",
"typedoc": "^0.11.1", "typedoc": "^0.11.1",
"typescript": "2.9.2", "typescript": "2.9.2",

View File

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

View File

@ -1,28 +0,0 @@
import { Writable } from "stream";
export class BufferStream extends Writable {
private readonly data: Buffer[];
constructor() {
super();
this.data = [];
}
// tslint:disable-next-line:no-any
public _write(chunk: any, _: string, next: (err?: Error) => void): void {
this.data.push(Buffer.from(chunk));
next();
}
// tslint:disable-next-line:ban-types
public end(cb?: Function): void {
super.end(cb);
this.emit("close");
}
public get Buffer(): Buffer {
return Buffer.concat(this.data);
}
}

View File

@ -1,20 +0,0 @@
import { File } from "../../file";
import { BufferStream } from "./buffer-stream";
import { Compiler } from "./compiler";
import { IPacker } from "./packer";
export class BufferPacker implements IPacker {
private readonly packer: Compiler;
constructor(file: File) {
this.packer = new Compiler(file);
}
public async pack(): Promise<Buffer> {
const stream = new BufferStream();
await this.packer.compile(stream);
return stream.Buffer;
}
}

View File

@ -1,114 +0,0 @@
import * as archiver from "archiver";
import * as express from "express";
import { Writable } from "stream";
import * as xml from "xml";
import { File } from "file";
import { Formatter } from "../formatter";
export class Compiler {
protected archive: archiver.Archiver;
private readonly formatter: Formatter;
constructor(private readonly file: File) {
this.formatter = new Formatter();
this.archive = archiver.create("zip", {});
this.archive.on("error", (err) => {
throw err;
});
}
public async compile(output: Writable | express.Response): Promise<void> {
this.archive.pipe(output);
const xmlDocument = xml(this.formatter.format(this.file.Document));
const xmlStyles = xml(this.formatter.format(this.file.Styles));
const xmlProperties = xml(this.formatter.format(this.file.CoreProperties), {
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
});
const xmlNumbering = xml(this.formatter.format(this.file.Numbering));
const xmlRelationships = xml(this.formatter.format(this.file.DocumentRelationships));
const xmlFileRelationships = xml(this.formatter.format(this.file.FileRelationships));
const xmlContentTypes = xml(this.formatter.format(this.file.ContentTypes));
const xmlAppProperties = xml(this.formatter.format(this.file.AppProperties));
const xmlFootnotes = xml(this.formatter.format(this.file.FootNotes));
this.archive.append(xmlDocument, {
name: "word/document.xml",
});
this.archive.append(xmlStyles, {
name: "word/styles.xml",
});
this.archive.append(xmlProperties, {
name: "docProps/core.xml",
});
this.archive.append(xmlAppProperties, {
name: "docProps/app.xml",
});
this.archive.append(xmlNumbering, {
name: "word/numbering.xml",
});
// headers
for (let i = 0; i < this.file.Headers.length; i++) {
const element = this.file.Headers[i];
this.archive.append(xml(this.formatter.format(element.Header)), {
name: `word/header${i + 1}.xml`,
});
this.archive.append(xml(this.formatter.format(element.Relationships)), {
name: `word/_rels/header${i + 1}.xml.rels`,
});
}
// footers
for (let i = 0; i < this.file.Footers.length; i++) {
const element = this.file.Footers[i];
this.archive.append(xml(this.formatter.format(element.Footer)), {
name: `word/footer${i + 1}.xml`,
});
this.archive.append(xml(this.formatter.format(element.Relationships)), {
name: `word/_rels/footer${i + 1}.xml.rels`,
});
}
this.archive.append(xmlFootnotes, {
name: "word/footnotes.xml",
});
this.archive.append(xmlRelationships, {
name: "word/_rels/document.xml.rels",
});
this.archive.append(xmlContentTypes, {
name: "[Content_Types].xml",
});
this.archive.append(xmlFileRelationships, {
name: "_rels/.rels",
});
for (const data of this.file.Media.Array) {
this.archive.append(data.stream, {
name: `word/media/${data.fileName}`,
});
}
this.archive.finalize();
return new Promise<void>((resolve) => {
output.on("close", () => {
resolve();
});
});
}
}

View File

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

View File

@ -1,32 +0,0 @@
import * as express from "express";
import { File } from "file";
import { Compiler } from "./compiler";
import { IPacker } from "./packer";
/**
* @deprecated ExpressPacker is now deprecated. Please use the StreamPacker instead and pipe that to `express`' `res` object
*/
export class ExpressPacker implements IPacker {
private readonly packer: Compiler;
constructor(file: File, private readonly res: express.Response) {
this.packer = new Compiler(file);
this.res = res;
this.res.on("close", () => {
return res
.status(200)
.send("OK")
.end();
});
}
public async pack(name: string): Promise<void> {
name = name.replace(/.docx$/, "");
this.res.attachment(`${name}.docx`);
await this.packer.compile(this.res);
}
}

View File

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

View File

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

View File

@ -1,10 +1,7 @@
/* tslint:disable:typedef space-before-function-paren */ /* tslint:disable:typedef space-before-function-paren */
import * as fs from "fs";
import * as JSZip from "jszip";
import { expect } from "chai"; import { expect } from "chai";
import { File } from "../../file"; import { File } from "../../file";
import { Compiler } from "./compiler"; import { Compiler } from "./next-compiler";
describe("Compiler", () => { describe("Compiler", () => {
let compiler: Compiler; let compiler: Compiler;
@ -12,21 +9,17 @@ describe("Compiler", () => {
beforeEach(() => { beforeEach(() => {
file = new File(); file = new File();
compiler = new Compiler(file); compiler = new Compiler();
}); });
describe("#compile()", () => { describe("#compile()", () => {
it("should pack all the content", async function() { it("should pack all the content", async function() {
this.timeout(99999999); this.timeout(99999999);
const fileName = "build/tests/test.docx"; const zipFile = await compiler.compile(file);
await compiler.compile(fs.createWriteStream(fileName));
const docxFile = fs.readFileSync(fileName);
const zipFile: JSZip = await JSZip.loadAsync(docxFile);
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name); const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array); expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(13); expect(fileNames).has.length(17);
expect(fileNames).to.include("word/document.xml"); expect(fileNames).to.include("word/document.xml");
expect(fileNames).to.include("word/styles.xml"); expect(fileNames).to.include("word/styles.xml");
expect(fileNames).to.include("docProps/core.xml"); expect(fileNames).to.include("docProps/core.xml");
@ -49,15 +42,12 @@ describe("Compiler", () => {
file.createHeader(); file.createHeader();
this.timeout(99999999); this.timeout(99999999);
const fileName = "build/tests/test2.docx";
await compiler.compile(fs.createWriteStream(fileName));
const docxFile = fs.readFileSync(fileName); const zipFile = await compiler.compile(file);
const zipFile: JSZip = await JSZip.loadAsync(docxFile);
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name); const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array); expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(21); expect(fileNames).has.length(25);
expect(fileNames).to.include("word/header1.xml"); expect(fileNames).to.include("word/header1.xml");
expect(fileNames).to.include("word/_rels/header1.xml.rels"); expect(fileNames).to.include("word/_rels/header1.xml.rels");

View File

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

View File

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

View File

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

View File

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

View File

@ -1,25 +0,0 @@
import { Readable, Transform } from "stream";
import { File } from "../../file";
import { Compiler } from "./compiler";
import { IPacker } from "./packer";
class Pipe extends Transform {
public _transform(chunk: Buffer | string, encoding: string, callback: () => void): void {
this.push(chunk, encoding);
callback();
}
}
export class StreamPacker implements IPacker {
private readonly compiler: Compiler;
constructor(file: File) {
this.compiler = new Compiler(file);
}
public pack(): Readable {
const pipe = new Pipe();
this.compiler.compile(pipe);
return pipe;
}
}

View File

@ -1,16 +1,17 @@
import { assert } from "chai"; import { assert } from "chai";
import * as fs from "fs";
import { Utility } from "../../tests/utility"; import { Utility } from "../../tests/utility";
import { Drawing, IDrawingOptions, PlacementPosition } from "./"; import { Drawing, IDrawingOptions, PlacementPosition } from "./";
const imageBase64Data = `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`;
function createDrawing(drawingOptions?: IDrawingOptions): Drawing { function createDrawing(drawingOptions?: IDrawingOptions): Drawing {
const path = "./demo/images/image1.jpeg"; const path = "./demo/images/image1.jpeg";
return new Drawing( return new Drawing(
{ {
fileName: "test.jpg", fileName: "test.jpg",
referenceId: 1, referenceId: 1,
stream: fs.createReadStream(path), stream: Buffer.from(imageBase64Data, "base64"),
path: path, path: path,
dimensions: { dimensions: {
pixels: { pixels: {

View File

@ -123,20 +123,13 @@ export class File {
return this.document.createTable(rows, cols); return this.document.createTable(rows, cols);
} }
public createImage(filePath: string): Image {
const image = Media.addImage(this, filePath);
this.document.addParagraph(image.Paragraph);
return image;
}
public addImage(image: Image): File { public addImage(image: Image): File {
this.document.addParagraph(image.Paragraph); this.document.addParagraph(image.Paragraph);
return this; return this;
} }
public createImageFromBuffer(buffer: Buffer, width?: number, height?: number): Image { public createImage(buffer: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): Image {
const image = Media.addImageFromBuffer(this, buffer, width, height); const image = Media.addImage(this, buffer, width, height);
this.document.addParagraph(image.Paragraph); this.document.addParagraph(image.Paragraph);
return image; return image;

View File

@ -36,8 +36,8 @@ export class FooterWrapper {
this.footer.addChildElement(childElement); this.footer.addChildElement(childElement);
} }
public createImage(image: string): void { public createImage(image: Buffer, width?: number, height?: number): void {
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount); const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height);
this.relationships.createRelationship( this.relationships.createRelationship(
mediaData.referenceId, mediaData.referenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",

View File

@ -36,8 +36,8 @@ export class HeaderWrapper {
this.header.addChildElement(childElement); this.header.addChildElement(childElement);
} }
public createImage(image: string): void { public createImage(image: Buffer, width?: number, height?: number): void {
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount); const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height);
this.relationships.createRelationship( this.relationships.createRelationship(
mediaData.referenceId, mediaData.referenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",

View File

@ -1,5 +1,3 @@
import * as fs from "fs";
export interface IMediaDataDimensions { export interface IMediaDataDimensions {
pixels: { pixels: {
x: number; x: number;
@ -13,7 +11,7 @@ export interface IMediaDataDimensions {
export interface IMediaData { export interface IMediaData {
referenceId: number; referenceId: number;
stream: fs.ReadStream | Buffer; stream: Buffer | Uint8Array | ArrayBuffer;
path?: string; path?: string;
fileName: string; fileName: string;
dimensions: IMediaDataDimensions; dimensions: IMediaDataDimensions;

View File

@ -1,7 +1,4 @@
import * as fs from "fs"; import { IDrawingOptions } from "../drawing";
import * as sizeOf from "image-size";
import * as path from "path";
import { File } from "../file"; import { File } from "../file";
import { ImageParagraph } from "../paragraph"; import { ImageParagraph } from "../paragraph";
import { IMediaData } from "./data"; import { IMediaData } from "./data";
@ -12,35 +9,23 @@ interface IHackedFile {
} }
export class Media { export class Media {
public static addImage(file: File, filePath: string): Image { public static addImage(
file: File,
buffer: Buffer | string | Uint8Array | ArrayBuffer,
width?: number,
height?: number,
drawingOptions?: IDrawingOptions,
): Image {
// Workaround to expose id without exposing to API // Workaround to expose id without exposing to API
const exposedFile = (file as {}) as IHackedFile; const exposedFile = (file as {}) as IHackedFile;
const mediaData = file.Media.addMedia(filePath, exposedFile.currentRelationshipId++); const mediaData = file.Media.addMedia(buffer, exposedFile.currentRelationshipId++, width, height);
file.DocumentRelationships.createRelationship(
mediaData.referenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
`media/${mediaData.fileName}`,
);
return new Image(new ImageParagraph(mediaData));
}
public static addImageFromBuffer(file: File, buffer: Buffer, width?: number, height?: number): Image {
// Workaround to expose id without exposing to API
const exposedFile = (file as {}) as IHackedFile;
const mediaData = file.Media.addMediaFromBuffer(
`${Media.generateId()}.png`,
buffer,
exposedFile.currentRelationshipId++,
width,
height,
);
file.DocumentRelationships.createRelationship( file.DocumentRelationships.createRelationship(
mediaData.referenceId, mediaData.referenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
`media/${mediaData.fileName}`, `media/${mediaData.fileName}`,
); );
return new Image(new ImageParagraph(mediaData)); return new Image(new ImageParagraph(mediaData, drawingOptions));
} }
private static generateId(): string { private static generateId(): string {
@ -71,34 +56,36 @@ export class Media {
return data; return data;
} }
public addMedia(filePath: string, referenceId: number): IMediaData { public addMedia(
const key = path.basename(filePath); buffer: Buffer | string | Uint8Array | ArrayBuffer,
const dimensions = sizeOf(filePath); referenceId: number,
return this.createMedia(key, referenceId, dimensions, fs.createReadStream(filePath), filePath); width: number = 100,
} height: number = 100,
): IMediaData {
const key = `${Media.generateId()}.png`;
public addMediaFromBuffer(fileName: string, buffer: Buffer, referenceId: number, width?: number, height?: number): IMediaData { return this.createMedia(
const key = fileName; key,
let dimensions; referenceId,
if (width && height) { {
dimensions = {
width: width, width: width,
height: height, height: height,
}; },
} else { buffer,
dimensions = sizeOf(buffer); );
}
return this.createMedia(key, referenceId, dimensions, buffer);
} }
private createMedia( private createMedia(
key: string, key: string,
relationshipsCount: number, relationshipsCount: number,
dimensions: { width: number; height: number }, dimensions: { width: number; height: number },
data: fs.ReadStream | Buffer, data: Buffer | string | Uint8Array | ArrayBuffer,
filePath?: string, filePath?: string,
): IMediaData { ): IMediaData {
if (typeof data === "string") {
data = this.convertDataURIToBinary(data);
}
const imageData = { const imageData = {
referenceId: this.map.size + relationshipsCount + 1, referenceId: this.map.size + relationshipsCount + 1,
stream: data, stream: data,
@ -130,4 +117,23 @@ export class Media {
return array; return array;
} }
private convertDataURIToBinary(dataURI: string): Uint8Array {
// https://gist.github.com/borismus/1032746
// https://github.com/mafintosh/base64-to-uint8array
const BASE64_MARKER = ";base64,";
const base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
if (typeof atob === "function") {
return new Uint8Array(
atob(dataURI.substring(base64Index))
.split("")
.map((c) => c.charCodeAt(0)),
);
} else {
const b = require("buf" + "fer");
return new b.Buffer(dataURI, "base64");
}
}
} }

View File

@ -1,23 +1,63 @@
// http://officeopenxml.com/WPborders.php // http://officeopenxml.com/WPborders.php
import { Attributes, XmlComponent } from "file/xml-components"; import { Attributes, XmlComponent } from "file/xml-components";
class Border extends XmlComponent { class BorderProperty extends XmlComponent {
public setProperties(color: string, space: string, value: string, size: string): XmlComponent {
const attrs = new Attributes({
color: color,
space: space,
val: value,
sz: size,
});
this.root.push(attrs);
return this;
}
}
export class Border extends XmlComponent {
constructor() { constructor() {
super("w:bottom"); super("w:pBdr");
this.root.push( }
new Attributes({
color: "auto", public addTopBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent {
space: "1", const top = new BorderProperty("w:top");
val: "single", top.setProperties(color, space, value, size);
sz: "6", this.root.push(top);
}),
); return this;
}
public addBottomBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent {
const bottom = new BorderProperty("w:bottom");
bottom.setProperties(color, space, value, size);
this.root.push(bottom);
return this;
}
public addLeftBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent {
const left = new BorderProperty("w:left");
left.setProperties(color, space, value, size);
this.root.push(left);
return this;
}
public addRightBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent {
const right = new BorderProperty("w:right");
right.setProperties(color, space, value, size);
this.root.push(right);
return this;
} }
} }
export class ThematicBreak extends XmlComponent { export class ThematicBreak extends XmlComponent {
constructor() { constructor() {
super("w:pBdr"); super("w:pBdr");
this.root.push(new Border()); const bottom = new BorderProperty("w:bottom");
bottom.setProperties("auto", "1", "single", "6");
this.root.push(bottom);
} }
} }

View File

@ -1,7 +1,7 @@
// http://officeopenxml.com/WPindentation.php // http://officeopenxml.com/WPindentation.php
import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
interface IIndentAttributesProperties { export interface IIndentAttributesProperties {
left?: number; left?: number;
hanging?: number; hanging?: number;
firstLine?: number; firstLine?: number;
@ -20,7 +20,7 @@ class IndentAttributes extends XmlAttributeComponent<IIndentAttributesProperties
} }
export class Indent extends XmlComponent { export class Indent extends XmlComponent {
constructor(attrs: object) { constructor(attrs: IIndentAttributesProperties) {
super("w:ind"); super("w:ind");
this.root.push(new IndentAttributes(attrs)); this.root.push(new IndentAttributes(attrs));
} }

View File

@ -144,6 +144,51 @@ describe("Paragraph", () => {
}); });
}); });
describe("#paragraphBorders()", () => {
it("should add a left and right border to a paragraph", () => {
paragraph.createBorder();
paragraph.Borders.addLeftBorder();
paragraph.Borders.addRightBorder();
const tree = new Formatter().format(paragraph);
expect(tree).to.deep.equal({
"w:p": [
{
"w:pPr": [
{
"w:pBdr": [
{
"w:left": [
{
_attr: {
"w:color": "auto",
"w:space": "1",
"w:sz": "6",
"w:val": "single",
},
},
],
},
{
"w:right": [
{
_attr: {
"w:color": "auto",
"w:space": "1",
"w:sz": "6",
"w:val": "single",
},
},
],
},
],
},
],
},
],
});
});
});
describe("#pageBreak()", () => { describe("#pageBreak()", () => {
it("should add page break to JSON", () => { it("should add page break to JSON", () => {
paragraph.pageBreak(); paragraph.pageBreak();

View File

@ -6,8 +6,8 @@ import { XmlComponent } from "file/xml-components";
import { Alignment } from "./formatting/alignment"; import { Alignment } from "./formatting/alignment";
import { Bidirectional } from "./formatting/bidirectional"; import { Bidirectional } from "./formatting/bidirectional";
import { ThematicBreak } from "./formatting/border"; import { Border, ThematicBreak } from "./formatting/border";
import { Indent } from "./formatting/indent"; import { IIndentAttributesProperties, Indent } from "./formatting/indent";
import { KeepLines, KeepNext } from "./formatting/keep"; import { KeepLines, KeepNext } from "./formatting/keep";
import { PageBreak, PageBreakBefore } from "./formatting/page-break"; import { PageBreak, PageBreakBefore } from "./formatting/page-break";
import { ISpacingProperties, Spacing } from "./formatting/spacing"; import { ISpacingProperties, Spacing } from "./formatting/spacing";
@ -30,6 +30,15 @@ export class Paragraph extends XmlComponent {
} }
} }
public get Borders(): Border {
return this.properties.paragraphBorder;
}
public createBorder(): Paragraph {
this.properties.createBorder();
return this;
}
public addRun(run: Run): Paragraph { public addRun(run: Run): Paragraph {
this.root.push(run); this.root.push(run);
return this; return this;
@ -188,7 +197,7 @@ export class Paragraph extends XmlComponent {
return this; return this;
} }
public indent(attrs: object): Paragraph { public indent(attrs: IIndentAttributesProperties): Paragraph {
this.properties.push(new Indent(attrs)); this.properties.push(new Indent(attrs));
return this; return this;
} }
@ -222,4 +231,8 @@ export class Paragraph extends XmlComponent {
this.properties.push(new Bidirectional()); this.properties.push(new Bidirectional());
return this; return this;
} }
public get Properties(): ParagraphProperties {
return this.properties;
}
} }

View File

@ -0,0 +1,243 @@
// http://officeopenxml.com/WPparagraph.php
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
import { Image } from "file/media";
import { Num } from "file/numbering/num";
import { XmlComponent } from "file/xml-components";
import { Alignment } from "./formatting/alignment";
import { Bidirectional } from "./formatting/bidirectional";
<<<<<<< HEAD
import { Border, ThematicBreak } from "./formatting/border";
import { Indent } from "./formatting/indent";
=======
import { ThematicBreak } from "./formatting/border";
import { IIndentAttributesProperties, Indent } from "./formatting/indent";
>>>>>>> a53818754a1c76b9930ee2ecc642570170fa3c06
import { KeepLines, KeepNext } from "./formatting/keep";
import { PageBreak, PageBreakBefore } from "./formatting/page-break";
import { ISpacingProperties, Spacing } from "./formatting/spacing";
import { Style } from "./formatting/style";
import { CenterTabStop, LeftTabStop, MaxRightTabStop, RightTabStop } from "./formatting/tab-stop";
import { NumberProperties } from "./formatting/unordered-list";
import { Bookmark, Hyperlink } from "./links";
import { ParagraphProperties } from "./properties";
import { PictureRun, Run, TextRun } from "./run";
export class Paragraph extends XmlComponent {
private readonly properties: ParagraphProperties;
constructor(text?: string) {
super("w:p");
this.properties = new ParagraphProperties();
this.root.push(this.properties);
if (text !== undefined) {
this.root.push(new TextRun(text));
}
}
public get Borders(): Border {
return this.properties.paragraphBorder;
}
public createBorder(): Paragraph {
this.properties.createBorder();
return this;
}
public addRun(run: Run): Paragraph {
this.root.push(run);
return this;
}
public addHyperLink(hyperlink: Hyperlink): Paragraph {
this.root.push(hyperlink);
return this;
}
public addBookmark(bookmark: Bookmark): Paragraph {
// Bookmarks by spec have three components, a start, text, and end
this.root.push(bookmark.start);
this.root.push(bookmark.text);
this.root.push(bookmark.end);
return this;
}
public createTextRun(text: string): TextRun {
const run = new TextRun(text);
this.addRun(run);
return run;
}
public addImage(image: Image): PictureRun {
const run = image.Run;
this.addRun(run);
return run;
}
public heading1(): Paragraph {
this.properties.push(new Style("Heading1"));
return this;
}
public heading2(): Paragraph {
this.properties.push(new Style("Heading2"));
return this;
}
public heading3(): Paragraph {
this.properties.push(new Style("Heading3"));
return this;
}
public heading4(): Paragraph {
this.properties.push(new Style("Heading4"));
return this;
}
public heading5(): Paragraph {
this.properties.push(new Style("Heading5"));
return this;
}
public heading6(): Paragraph {
this.properties.push(new Style("Heading6"));
return this;
}
public title(): Paragraph {
this.properties.push(new Style("Title"));
return this;
}
public center(): Paragraph {
this.properties.push(new Alignment("center"));
return this;
}
public left(): Paragraph {
this.properties.push(new Alignment("left"));
return this;
}
public right(): Paragraph {
this.properties.push(new Alignment("right"));
return this;
}
public start(): Paragraph {
this.properties.push(new Alignment("start"));
return this;
}
public end(): Paragraph {
this.properties.push(new Alignment("end"));
return this;
}
public distribute(): Paragraph {
this.properties.push(new Alignment("distribute"));
return this;
}
public justified(): Paragraph {
this.properties.push(new Alignment("both"));
return this;
}
public thematicBreak(): Paragraph {
this.properties.push(new ThematicBreak());
return this;
}
public pageBreak(): Paragraph {
this.root.push(new PageBreak());
return this;
}
public pageBreakBefore(): Paragraph {
this.properties.push(new PageBreakBefore());
return this;
}
public maxRightTabStop(): Paragraph {
this.properties.push(new MaxRightTabStop());
return this;
}
public leftTabStop(position: number): Paragraph {
this.properties.push(new LeftTabStop(position));
return this;
}
public rightTabStop(position: number): Paragraph {
this.properties.push(new RightTabStop(position));
return this;
}
public centerTabStop(position: number): Paragraph {
this.properties.push(new CenterTabStop(position));
return this;
}
public bullet(indentLevel: number = 0): Paragraph {
this.properties.push(new Style("ListParagraph"));
this.properties.push(new NumberProperties(1, indentLevel));
return this;
}
public setNumbering(numbering: Num, indentLevel: number): Paragraph {
this.properties.push(new Style("ListParagraph"));
this.properties.push(new NumberProperties(numbering.id, indentLevel));
return this;
}
public setCustomNumbering(numberId: number, indentLevel: number): Paragraph {
this.properties.push(new NumberProperties(numberId, indentLevel));
return this;
}
public style(styleId: string): Paragraph {
this.properties.push(new Style(styleId));
return this;
}
public indent(attrs: IIndentAttributesProperties): Paragraph {
this.properties.push(new Indent(attrs));
return this;
}
public spacing(params: ISpacingProperties): Paragraph {
this.properties.push(new Spacing(params));
return this;
}
public keepNext(): Paragraph {
this.properties.push(new KeepNext());
return this;
}
public keepLines(): Paragraph {
this.properties.push(new KeepLines());
return this;
}
public referenceFootnote(id: number): Paragraph {
this.root.push(new FootnoteReferenceRun(id));
return this;
}
public addRunToFront(run: Run): Paragraph {
this.root.splice(1, 0, run);
return this;
}
public bidirectional(): Paragraph {
this.properties.push(new Bidirectional());
return this;
}
public get Properties(): ParagraphProperties {
return this.properties;
}
}

View File

@ -1,9 +1,17 @@
// http://officeopenxml.com/WPparagraphProperties.php // http://officeopenxml.com/WPparagraphProperties.php
import { XmlComponent } from "file/xml-components"; import { XmlComponent } from "file/xml-components";
import { Border } from "./formatting/border";
export class ParagraphProperties extends XmlComponent { export class ParagraphProperties extends XmlComponent {
public paragraphBorder: Border;
constructor() { constructor() {
super("w:pPr"); super("w:pPr");
this.paragraphBorder = new Border();
}
public createBorder(): void {
this.push(this.paragraphBorder);
} }
public push(item: XmlComponent): void { public push(item: XmlComponent): void {

View File

@ -2,6 +2,7 @@ import { expect } from "chai";
import { Formatter } from "../../export/formatter"; import { Formatter } from "../../export/formatter";
import { TableProperties } from "./properties"; import { TableProperties } from "./properties";
import { WidthType } from "./table-cell";
describe("TableProperties", () => { describe("TableProperties", () => {
describe("#constructor", () => { describe("#constructor", () => {
@ -14,7 +15,7 @@ describe("TableProperties", () => {
describe("#setWidth", () => { describe("#setWidth", () => {
it("adds a table width property", () => { it("adds a table width property", () => {
const tp = new TableProperties().setWidth("dxa", 1234); const tp = new TableProperties().setWidth(WidthType.DXA, 1234);
const tree = new Formatter().format(tp); const tree = new Formatter().format(tp);
expect(tree).to.deep.equal({ expect(tree).to.deep.equal({
"w:tblPr": [{ "w:tblW": [{ _attr: { "w:type": "dxa", "w:w": 1234 } }] }], "w:tblPr": [{ "w:tblW": [{ _attr: { "w:type": "dxa", "w:w": 1234 } }] }],
@ -31,4 +32,15 @@ describe("TableProperties", () => {
}); });
}); });
}); });
describe("#cellMargin", () => {
it("adds a table cell top margin", () => {
const tp = new TableProperties();
tp.CellMargin.addTopMargin(1234, WidthType.DXA);
const tree = new Formatter().format(tp);
expect(tree).to.deep.equal({
"w:tblPr": [{ "w:tblCellMar": [{ "w:top": [{ _attr: { "w:sz": "dxa", "w:w": 1234 } }] }] }],
});
});
});
}); });

View File

@ -1,13 +1,18 @@
import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
import { WidthType } from "./table-cell";
export type WidthTypes = "dxa" | "pct" | "nil" | "auto"; import { TableCellMargin } from "./table-cell-margin";
export class TableProperties extends XmlComponent { export class TableProperties extends XmlComponent {
private readonly cellMargain: TableCellMargin;
constructor() { constructor() {
super("w:tblPr"); super("w:tblPr");
this.cellMargain = new TableCellMargin();
this.root.push(this.cellMargain);
} }
public setWidth(type: WidthTypes, w: number | string): TableProperties { public setWidth(type: WidthType, w: number | string): TableProperties {
this.root.push(new PreferredTableWidth(type, w)); this.root.push(new PreferredTableWidth(type, w));
return this; return this;
} }
@ -21,10 +26,14 @@ export class TableProperties extends XmlComponent {
this.root.push(new TableBorders()); this.root.push(new TableBorders());
return this; return this;
} }
public get CellMargin(): TableCellMargin {
return this.cellMargain;
}
} }
interface ITableWidth { interface ITableWidth {
type: WidthTypes; type: WidthType;
w: number | string; w: number | string;
} }
@ -33,7 +42,7 @@ class TableWidthAttributes extends XmlAttributeComponent<ITableWidth> {
} }
class PreferredTableWidth extends XmlComponent { class PreferredTableWidth extends XmlComponent {
constructor(type: WidthTypes, w: number | string) { constructor(type: WidthType, w: number | string) {
super("w:tblW"); super("w:tblW");
this.root.push(new TableWidthAttributes({ type, w })); this.root.push(new TableWidthAttributes({ type, w }));
} }

View File

@ -0,0 +1,55 @@
import { IXmlableObject, XmlAttributeComponent, XmlComponent } from "file/xml-components";
import { WidthType } from "./table-cell";
class TableCellMarginAttributes extends XmlAttributeComponent<{ type: WidthType; value: number }> {
protected xmlKeys = { value: "w:w", type: "w:sz" };
}
class BaseTableCellMargin extends XmlComponent {
public setProperties(value: number, type: WidthType = WidthType.DXA): void {
this.root.push(
new TableCellMarginAttributes({
type: type,
value: value,
}),
);
}
}
export class TableCellMargin extends XmlComponent {
constructor() {
super("w:tblCellMar");
}
public prepForXml(): IXmlableObject {
return this.root.length > 0 ? super.prepForXml() : "";
}
public addTopMargin(value: number, type: WidthType = WidthType.DXA): void {
const top = new BaseTableCellMargin("w:top");
top.setProperties(value, type);
this.root.push(top);
}
public addLeftMargin(value: number, type: WidthType = WidthType.DXA): void {
const left = new BaseTableCellMargin("w:left");
left.setProperties(value, type);
this.root.push(left);
}
public addBottomMargin(value: number, type: WidthType = WidthType.DXA): void {
const bottom = new BaseTableCellMargin("w:bottom");
bottom.setProperties(value, type);
this.root.push(bottom);
}
public addRightMargin(value: number, type: WidthType = WidthType.DXA): void {
const right = new BaseTableCellMargin("w:right");
right.setProperties(value, type);
this.root.push(right);
}
}

View File

@ -4,6 +4,7 @@ import { expect } from "chai";
import { Formatter } from "../../export/formatter"; import { Formatter } from "../../export/formatter";
import { Paragraph } from "../paragraph"; import { Paragraph } from "../paragraph";
import { Table } from "./"; import { Table } from "./";
import { WidthType } from "./table-cell";
const DEFAULT_TABLE_PROPERTIES = { const DEFAULT_TABLE_PROPERTIES = {
"w:tblBorders": [ "w:tblBorders": [
@ -174,7 +175,7 @@ describe("Table", () => {
describe("#setWidth", () => { describe("#setWidth", () => {
it("sets the preferred width on the table", () => { it("sets the preferred width on the table", () => {
const table = new Table(2, 2).setWidth("pct", 1000); const table = new Table(2, 2).setWidth(WidthType.PERCENTAGE, 1000);
const tree = new Formatter().format(table); const tree = new Formatter().format(table);
expect(tree) expect(tree)
.to.have.property("w:tbl") .to.have.property("w:tbl")

View File

@ -12,7 +12,7 @@ import {
import { IXmlableObject, XmlComponent } from "file/xml-components"; import { IXmlableObject, XmlComponent } from "file/xml-components";
import { Paragraph } from "../paragraph"; import { Paragraph } from "../paragraph";
import { TableGrid } from "./grid"; import { TableGrid } from "./grid";
import { TableProperties, WidthTypes } from "./properties"; import { TableProperties } from "./properties";
export class Table extends XmlComponent { export class Table extends XmlComponent {
private readonly properties: TableProperties; private readonly properties: TableProperties;
@ -67,7 +67,7 @@ export class Table extends XmlComponent {
return this.getRow(row).getCell(col); return this.getRow(row).getCell(col);
} }
public setWidth(type: WidthTypes, width: number | string): Table { public setWidth(type: WidthType, width: number | string): Table {
this.properties.setWidth(type, width); this.properties.setWidth(type, width);
return this; return this;
} }
@ -76,6 +76,10 @@ export class Table extends XmlComponent {
this.properties.setFixedWidthLayout(); this.properties.setFixedWidthLayout();
return this; return this;
} }
public get Properties(): TableProperties {
return this.properties;
}
} }
export class TableRow extends XmlComponent { export class TableRow extends XmlComponent {

View File

@ -21,7 +21,8 @@
"exclude": [ "exclude": [
"node_modules", "node_modules",
"tests", "tests",
"**/_*" "**/_*",
"demo"
], ],
"typedocOptions": { "typedocOptions": {
"mode": "file", "mode": "file",

View File

@ -1,17 +1,17 @@
const path = require('path'); const path = require("path");
module.exports = { module.exports = {
entry: './src/index.ts', entry: "./src/index.ts",
output: { output: {
path: path.resolve('build'), path: path.resolve("build"),
filename: 'index.js', filename: "index.js",
libraryTarget: 'umd' libraryTarget: "umd",
}, },
resolve: { resolve: {
extensions: ['.tsx', '.ts', '.js'], extensions: [".tsx", ".ts", ".js"],
modules: [path.resolve('./src'), "node_modules"] modules: [path.resolve("./src"), "node_modules"],
}, },
module: { module: {
@ -19,13 +19,10 @@ module.exports = {
{ {
test: /\.ts$/, test: /\.ts$/,
loaders: ["awesome-typescript-loader"], loaders: ["awesome-typescript-loader"],
} },
], ],
}, },
target: 'node', // Because docx is now targetting web
// target: 'node',
node: {
__dirname: true
}
}; };