Compare commits

..

11 Commits
3.4.0 ... 3.5.0

Author SHA1 Message Date
4d7bdc2ed9 Version bump 2018-05-08 22:19:01 +01:00
d10c707f12 Add tests for catching errors for exporter packer.pack 2018-05-08 20:40:04 +01:00
49cc8a267c Merge pull request #71 from ivanryuu/hyperlink_support
External hyperlink support
2018-05-08 01:16:28 +01:00
68cb57aea6 fix style issues 2018-05-06 23:18:00 -05:00
9d7fd55e4c add hyperlink to paragraph and doc 2018-05-06 22:24:16 -05:00
195c62f80b modify relationships to support external links 2018-05-06 22:23:35 -05:00
1fd222abea create hyperlink style 2018-05-06 22:23:04 -05:00
ac40e13e33 added support for hyperlinks 2018-05-06 22:20:56 -05:00
52e8fe576e Bump prettier version 2018-05-06 03:03:35 +01:00
b389ac6347 Add style fix command 2018-05-06 03:02:06 +01:00
8108eca2fa Update README.md 2018-04-21 00:04:14 +01:00
16 changed files with 225 additions and 9 deletions

View File

@ -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]
[![NPM](https://nodei.co/npm/docx.png?downloads=true&downloadRank=true&stars=true)](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

View File

@ -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",

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

View File

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

View File

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

View File

@ -2,3 +2,4 @@ export * from "./formatting";
export * from "./paragraph";
export * from "./properties";
export * from "./run";
export * from "./links";

View 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",
};
}

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

View 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"));
}
}

View File

@ -0,0 +1 @@
export * from "./hyperlink";

View File

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

View File

@ -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",
};
}

View File

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

View File

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

View File

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

View File

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