Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
4d7bdc2ed9 | |||
d10c707f12 | |||
49cc8a267c | |||
68cb57aea6 | |||
9d7fd55e4c | |||
195c62f80b | |||
1fd222abea | |||
ac40e13e33 | |||
52e8fe576e | |||
b389ac6347 | |||
8108eca2fa |
@ -14,6 +14,7 @@
|
||||
[![Known Vulnerabilities][snky-image]][snky-url]
|
||||
[![Chat on Gitter][gitter-image]][gitter-url]
|
||||
[![code style: prettier][prettier-image]][prettier-url]
|
||||
[![PRs Welcome][pr-image]][pr-url]
|
||||
|
||||
[](https://nodei.co/npm/docx/)
|
||||
|
||||
@ -114,3 +115,5 @@ Huge thanks to [@felipeochoa](https://github.com/felipeochoa) for awesome contri
|
||||
[gemnasium-url]: https://gemnasium.com/github.com/dolanmiu/docx
|
||||
[prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg
|
||||
[prettier-url]: https://github.com/prettier/prettier
|
||||
[pr-image]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg
|
||||
[pr-url]: http://makeapullrequest.com
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docx",
|
||||
"version": "3.4.0",
|
||||
"version": "3.5.0",
|
||||
"description": "Generate .docx documents with JavaScript (formerly Office-Clippy)",
|
||||
"main": "build/index.js",
|
||||
"scripts": {
|
||||
@ -15,6 +15,7 @@
|
||||
"demo": "npm run build && node ./demo",
|
||||
"typedoc": "typedoc --out docs/ src/ --module commonjs --target ES6 --disableOutputCheck --excludePrivate --externalPattern \"**/*.spec.ts\"",
|
||||
"style": "prettier -l \"src/**/*.ts\"",
|
||||
"style.fix": "prettier \"src/**/*.ts\" --write",
|
||||
"fix-types": "node types-absolute-fixer.js"
|
||||
},
|
||||
"files": [
|
||||
@ -59,16 +60,18 @@
|
||||
"devDependencies": {
|
||||
"@types/chai": "^3.4.35",
|
||||
"@types/mocha": "^2.2.39",
|
||||
"@types/sinon": "^4.3.1",
|
||||
"awesome-typescript-loader": "^3.4.1",
|
||||
"chai": "^3.5.0",
|
||||
"glob": "^7.1.2",
|
||||
"mocha": "^3.2.0",
|
||||
"mocha-webpack": "^1.0.1",
|
||||
"prettier": "^1.10.2",
|
||||
"prettier": "^1.12.1",
|
||||
"prompt": "^1.0.0",
|
||||
"replace-in-file": "^3.1.0",
|
||||
"rimraf": "^2.5.2",
|
||||
"shelljs": "^0.7.7",
|
||||
"sinon": "^5.0.7",
|
||||
"tslint": "^5.1.0",
|
||||
"typedoc": "^0.9.0",
|
||||
"typescript": "2.6.2",
|
||||
|
43
src/export/packer/express.spec.ts
Normal file
43
src/export/packer/express.spec.ts
Normal file
@ -0,0 +1,43 @@
|
||||
// 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,5 +1,7 @@
|
||||
/* 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";
|
||||
@ -29,14 +31,36 @@ describe("LocalPacker", () => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -7,7 +7,7 @@ import { FooterWrapper } from "./footer-wrapper";
|
||||
import { HeaderWrapper } from "./header-wrapper";
|
||||
import { Media } from "./media";
|
||||
import { Numbering } from "./numbering";
|
||||
import { Paragraph, PictureRun } from "./paragraph";
|
||||
import { Hyperlink, Paragraph, PictureRun } from "./paragraph";
|
||||
import { Relationships } from "./relationships";
|
||||
import { Styles } from "./styles";
|
||||
import { DefaultStylesFactory } from "./styles/factory";
|
||||
@ -111,6 +111,18 @@ export class File {
|
||||
return this.document.createDrawing(mediaData);
|
||||
}
|
||||
|
||||
public createHyperlink(link: string, text?: string): Hyperlink {
|
||||
text = text === undefined ? link : text;
|
||||
const hyperlink = new Hyperlink(text, this.docRelationships.RelationshipCount);
|
||||
this.docRelationships.createRelationship(
|
||||
hyperlink.linkId,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
||||
link,
|
||||
"External",
|
||||
);
|
||||
return hyperlink;
|
||||
}
|
||||
|
||||
public get Document(): Document {
|
||||
return this.document;
|
||||
}
|
||||
|
@ -2,3 +2,4 @@ export * from "./formatting";
|
||||
export * from "./paragraph";
|
||||
export * from "./properties";
|
||||
export * from "./run";
|
||||
export * from "./links";
|
||||
|
13
src/file/paragraph/links/hyperlink-attributes.ts
Normal file
13
src/file/paragraph/links/hyperlink-attributes.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export interface IHyperlinkAttributesProperties {
|
||||
id?: string;
|
||||
history: number;
|
||||
}
|
||||
|
||||
export class HyperlinkAttributes extends XmlAttributeComponent<IHyperlinkAttributesProperties> {
|
||||
protected xmlKeys = {
|
||||
id: "r:id",
|
||||
history: "w:history",
|
||||
};
|
||||
}
|
40
src/file/paragraph/links/hyperlink.spec.ts
Normal file
40
src/file/paragraph/links/hyperlink.spec.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { assert, expect } from "chai";
|
||||
|
||||
import { Formatter } from "../../../export/formatter";
|
||||
import { Utility } from "../../../tests/utility";
|
||||
import { Hyperlink } from "./";
|
||||
|
||||
describe("Hyperlink", () => {
|
||||
let hyperlink: Hyperlink;
|
||||
|
||||
beforeEach(() => {
|
||||
hyperlink = new Hyperlink("https://example.com", 0);
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
it("should create a hyperlink with correct root key", () => {
|
||||
const newJson = Utility.jsonify(hyperlink);
|
||||
assert.equal(newJson.rootKey, "w:hyperlink");
|
||||
});
|
||||
|
||||
it("should create a hyperlink with right attributes", () => {
|
||||
const newJson = Utility.jsonify(hyperlink);
|
||||
const attributes = {
|
||||
id: "rId1",
|
||||
history: 1,
|
||||
};
|
||||
assert.equal(JSON.stringify(newJson.root[0].root), JSON.stringify(attributes));
|
||||
});
|
||||
|
||||
it("should create a hyperlink with a run component", () => {
|
||||
const tree = new Formatter().format(hyperlink);
|
||||
const runJson = {
|
||||
"w:r": [
|
||||
{ "w:rPr": [{ "w:rStyle": [{ _attr: { "w:val": "Hyperlink" } }] }] },
|
||||
{ "w:t": [{ _attr: { "xml:space": "preserve" } }, "https://example.com"] },
|
||||
],
|
||||
};
|
||||
expect(tree["w:hyperlink"][1]).to.deep.equal(runJson);
|
||||
});
|
||||
});
|
||||
});
|
21
src/file/paragraph/links/hyperlink.ts
Normal file
21
src/file/paragraph/links/hyperlink.ts
Normal file
@ -0,0 +1,21 @@
|
||||
// http://officeopenxml.com/WPhyperlink.php
|
||||
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { TextRun } from "../run";
|
||||
import { HyperlinkAttributes } from "./hyperlink-attributes";
|
||||
|
||||
export class Hyperlink extends XmlComponent {
|
||||
public linkId: number;
|
||||
|
||||
constructor(text: string, relationshipsCount: number) {
|
||||
super("w:hyperlink");
|
||||
|
||||
this.linkId = relationshipsCount + 1;
|
||||
const attributes = new HyperlinkAttributes({
|
||||
id: `rId${this.linkId}`,
|
||||
history: 1,
|
||||
});
|
||||
this.root.push(attributes);
|
||||
this.root.push(new TextRun(text).style("Hyperlink"));
|
||||
}
|
||||
}
|
1
src/file/paragraph/links/index.ts
Normal file
1
src/file/paragraph/links/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./hyperlink";
|
@ -13,6 +13,7 @@ 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 { Hyperlink } from "./links";
|
||||
import { ParagraphProperties } from "./properties";
|
||||
|
||||
export class Paragraph extends XmlComponent {
|
||||
@ -32,6 +33,11 @@ export class Paragraph extends XmlComponent {
|
||||
return this;
|
||||
}
|
||||
|
||||
public addHyperLink(hyperlink: Hyperlink): Paragraph {
|
||||
this.root.push(hyperlink);
|
||||
return this;
|
||||
}
|
||||
|
||||
public createTextRun(text: string): TextRun {
|
||||
const run = new TextRun(text);
|
||||
this.addRun(run);
|
||||
|
@ -4,6 +4,7 @@ export interface IRelationshipAttributesProperties {
|
||||
id: string;
|
||||
type: string;
|
||||
target: string;
|
||||
targetMode?: string;
|
||||
}
|
||||
|
||||
export class RelationshipAttributes extends XmlAttributeComponent<IRelationshipAttributesProperties> {
|
||||
@ -11,5 +12,6 @@ export class RelationshipAttributes extends XmlAttributeComponent<IRelationshipA
|
||||
id: "Id",
|
||||
type: "Type",
|
||||
target: "Target",
|
||||
targetMode: "TargetMode",
|
||||
};
|
||||
}
|
||||
|
@ -13,10 +13,13 @@ export type RelationshipType =
|
||||
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer"
|
||||
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
|
||||
| "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"
|
||||
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
|
||||
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"
|
||||
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
||||
|
||||
export type TargetModeType = "External";
|
||||
|
||||
export class Relationship extends XmlComponent {
|
||||
constructor(id: string, type: RelationshipType, target: string) {
|
||||
constructor(id: string, type: RelationshipType, target: string, targetMode?: TargetModeType) {
|
||||
super("Relationship");
|
||||
|
||||
this.root.push(
|
||||
@ -24,6 +27,7 @@ export class Relationship extends XmlComponent {
|
||||
id,
|
||||
type,
|
||||
target,
|
||||
targetMode,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { RelationshipsAttributes } from "./attributes";
|
||||
import { Relationship, RelationshipType } from "./relationship/relationship";
|
||||
import { Relationship, RelationshipType, TargetModeType } from "./relationship/relationship";
|
||||
|
||||
export class Relationships extends XmlComponent {
|
||||
constructor() {
|
||||
@ -16,8 +16,8 @@ export class Relationships extends XmlComponent {
|
||||
this.root.push(relationship);
|
||||
}
|
||||
|
||||
public createRelationship(id: number, type: RelationshipType, target: string): Relationship {
|
||||
const relationship = new Relationship(`rId${id}`, type, target);
|
||||
public createRelationship(id: number, type: RelationshipType, target: string, targetMode?: TargetModeType): Relationship {
|
||||
const relationship = new Relationship(`rId${id}`, type, target, targetMode);
|
||||
this.addRelationship(relationship);
|
||||
|
||||
return relationship;
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
Heading4Style,
|
||||
Heading5Style,
|
||||
Heading6Style,
|
||||
HyperlinkStyle,
|
||||
ListParagraph,
|
||||
TitleStyle,
|
||||
} from "./style";
|
||||
@ -54,6 +55,8 @@ export class DefaultStylesFactory {
|
||||
// listParagraph.addParagraphProperty();
|
||||
styles.push(listParagraph);
|
||||
|
||||
const hyperLinkStyle = new HyperlinkStyle();
|
||||
styles.push(hyperLinkStyle);
|
||||
return styles;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import * as paragraph from "../../paragraph";
|
||||
import * as formatting from "../../paragraph/run/formatting";
|
||||
import { RunProperties } from "../../paragraph/run/properties";
|
||||
|
||||
import { BasedOn, Name, Next, QuickFormat } from "./components";
|
||||
import { BasedOn, Name, Next, QuickFormat, UiPriority, UnhideWhenUsed } from "./components";
|
||||
|
||||
export interface IStyleAttributes {
|
||||
type?: string;
|
||||
@ -249,3 +249,43 @@ export class ListParagraph extends ParagraphStyle {
|
||||
this.root.push(new QuickFormat());
|
||||
}
|
||||
}
|
||||
|
||||
export class CharacterStyle extends Style {
|
||||
private readonly runProperties: RunProperties;
|
||||
|
||||
constructor(styleId: string, name?: string) {
|
||||
super({ type: "character", styleId: styleId }, name);
|
||||
this.runProperties = new RunProperties();
|
||||
this.root.push(this.runProperties);
|
||||
this.root.push(new UiPriority("99"));
|
||||
this.root.push(new UnhideWhenUsed(""));
|
||||
}
|
||||
|
||||
public basedOn(parentId: string): CharacterStyle {
|
||||
this.root.push(new BasedOn(parentId));
|
||||
return this;
|
||||
}
|
||||
|
||||
public addRunProperty(property: XmlComponent): void {
|
||||
this.runProperties.push(property);
|
||||
}
|
||||
|
||||
public color(color: string): CharacterStyle {
|
||||
this.addRunProperty(new formatting.Color(color));
|
||||
return this;
|
||||
}
|
||||
|
||||
public underline(underlineType?: string, color?: string): CharacterStyle {
|
||||
this.addRunProperty(new formatting.Underline(underlineType, color));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class HyperlinkStyle extends CharacterStyle {
|
||||
constructor() {
|
||||
super("Hyperlink", "Hyperlink");
|
||||
this.basedOn("DefaultParagraphFont")
|
||||
.color("0563C1")
|
||||
.underline("single");
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user