Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/footnotes #87

Merged
merged 16 commits into from
Jun 30, 2018
17 changes: 17 additions & 0 deletions demo/demo17.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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!');
5 changes: 3 additions & 2 deletions src/export/packer/compiler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe("Compiler", () => {
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);

expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(12);
expect(fileNames).has.length(13);
expect(fileNames).to.include("word/document.xml");
expect(fileNames).to.include("word/styles.xml");
expect(fileNames).to.include("docProps/core.xml");
Expand All @@ -35,6 +35,7 @@ describe("Compiler", () => {
expect(fileNames).to.include("word/header1.xml");
expect(fileNames).to.include("word/_rels/header1.xml.rels");
expect(fileNames).to.include("word/footer1.xml");
expect(fileNames).to.include("word/footnotes.xml");
expect(fileNames).to.include("word/_rels/footer1.xml.rels");
expect(fileNames).to.include("word/_rels/document.xml.rels");
expect(fileNames).to.include("[Content_Types].xml");
Expand All @@ -56,7 +57,7 @@ describe("Compiler", () => {
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);

expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(20);
expect(fileNames).has.length(21);

expect(fileNames).to.include("word/header1.xml");
expect(fileNames).to.include("word/_rels/header1.xml.rels");
Expand Down
5 changes: 5 additions & 0 deletions src/export/packer/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class Compiler {
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",
Expand Down Expand Up @@ -80,6 +81,10 @@ export class Compiler {
});
}

this.archive.append(xmlFootnotes, {
name: "word/footnotes.xml",
});

this.archive.append(xmlRelationships, {
name: "word/_rels/document.xml.rels",
});
Expand Down
8 changes: 4 additions & 4 deletions src/file/content-types/content-types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe("ContentTypes", () => {
contentTypes.addFooter(102);
const tree = new Formatter().format(contentTypes);

expect(tree["Types"][13]).to.deep.equal({
expect(tree["Types"][14]).to.deep.equal({
Override: [
{
_attr: {
Expand All @@ -94,7 +94,7 @@ describe("ContentTypes", () => {
],
});

expect(tree["Types"][14]).to.deep.equal({
expect(tree["Types"][15]).to.deep.equal({
Override: [
{
_attr: {
Expand All @@ -113,7 +113,7 @@ describe("ContentTypes", () => {
contentTypes.addHeader(202);
const tree = new Formatter().format(contentTypes);

expect(tree["Types"][13]).to.deep.equal({
expect(tree["Types"][14]).to.deep.equal({
Override: [
{
_attr: {
Expand All @@ -124,7 +124,7 @@ describe("ContentTypes", () => {
],
});

expect(tree["Types"][14]).to.deep.equal({
expect(tree["Types"][15]).to.deep.equal({
Override: [
{
_attr: {
Expand Down
1 change: 1 addition & 0 deletions src/file/content-types/content-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class ContentTypes extends XmlComponent {
this.root.push(new Override("application/vnd.openxmlformats-package.core-properties+xml", "/docProps/core.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.extended-properties+xml", "/docProps/app.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", "/word/numbering.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml", "/word/footnotes.xml"));
}

public addFooter(index: number): void {
Expand Down
17 changes: 17 additions & 0 deletions src/file/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Document } from "./document";
import { FooterReferenceType, HeaderReference, HeaderReferenceType } from "./document/body/section-properties";
import { SectionPropertiesOptions } from "./document/body/section-properties/section-properties";
import { FooterWrapper } from "./footer-wrapper";
import { FootNotes } from "./footnotes";
import { HeaderWrapper } from "./header-wrapper";
import { Media } from "./media";
import { Numbering } from "./numbering";
Expand All @@ -26,6 +27,7 @@ export class File {
private readonly fileRelationships: Relationships;
private readonly headerWrapper: HeaderWrapper[] = [];
private readonly footerWrapper: FooterWrapper[] = [];
private readonly footNotes: FootNotes;

private readonly contentTypes: ContentTypes;
private readonly appProperties: AppProperties;
Expand Down Expand Up @@ -63,6 +65,12 @@ export class File {
"numbering.xml",
);
this.contentTypes = new ContentTypes();

this.docRelationships.createRelationship(
this.nextId++,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
"footnotes.xml",
);
this.media = new Media();

const header = this.createHeader();
Expand All @@ -86,6 +94,7 @@ export class File {
);
this.appProperties = new AppProperties();

this.footNotes = new FootNotes();
if (!sectionPropertiesOptions) {
sectionPropertiesOptions = {
footerType: FooterReferenceType.DEFAULT,
Expand Down Expand Up @@ -152,6 +161,10 @@ export class File {
this.document.Body.addSection(sectionPropertiesOptions);
}

public createFootnote(paragraph: Paragraph): void {
this.footNotes.createFootNote(paragraph);
}

/**
* Creates new header.
*/
Expand Down Expand Up @@ -262,4 +275,8 @@ export class File {
public get AppProperties(): AppProperties {
return this.appProperties;
}

public get FootNotes(): FootNotes {
return this.footNotes;
}
}
13 changes: 13 additions & 0 deletions src/file/footnotes/footnote/footnote-attributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { XmlAttributeComponent } from "file/xml-components";

export interface IFootnoteAttributesProperties {
type?: string;
id: number;
}

export class FootnoteAttributes extends XmlAttributeComponent<IFootnoteAttributesProperties> {
protected xmlKeys = {
type: "w:type",
id: "w:id",
};
}
25 changes: 25 additions & 0 deletions src/file/footnotes/footnote/footnote.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { expect } from "chai";
import { Formatter } from "../../../export/formatter";
import { Footnote, FootnoteType } from "./footnote";

describe("Footnote", () => {
describe("#constructor", () => {
it("should create a footnote with a footnote type", () => {
const footnote = new Footnote(1, FootnoteType.SEPERATOR);
const tree = new Formatter().format(footnote);

expect(Object.keys(tree)).to.deep.equal(["w:footnote"]);
expect(tree["w:footnote"]).to.be.an.instanceof(Array);
expect(tree["w:footnote"][0]).to.deep.equal({ _attr: { "w:type": "separator", "w:id": 1 } });
});

it("should create a footnote without a footnote type", () => {
const footnote = new Footnote(1);
const tree = new Formatter().format(footnote);

expect(Object.keys(tree)).to.deep.equal(["w:footnote"]);
expect(tree["w:footnote"]).to.be.an.instanceof(Array);
expect(tree["w:footnote"][0]).to.deep.equal({ _attr: { "w:id": 1 } });
});
});
});
26 changes: 26 additions & 0 deletions src/file/footnotes/footnote/footnote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { XmlComponent } from "file/xml-components";
import { Paragraph } from "../../paragraph";
import { FootnoteAttributes } from "./footnote-attributes";
import { FootnoteRefRun } from "./run/footnote-ref-run";

export enum FootnoteType {
SEPERATOR = "separator",
CONTINUATION_SEPERATOR = "continuationSeparator",
}

export class Footnote extends XmlComponent {
constructor(id: number, type?: FootnoteType) {
super("w:footnote");
this.root.push(
new FootnoteAttributes({
type: type,
id: id,
}),
);
}

public addParagraph(paragraph: Paragraph): void {
paragraph.addRunToFront(new FootnoteRefRun());
this.root.push(paragraph);
}
}
10 changes: 10 additions & 0 deletions src/file/footnotes/footnote/run/continuation-seperator-run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Run } from "file/paragraph";
import { ContinuationSeperator } from "./continuation-seperator";

export class ContinuationSeperatorRun extends Run {
constructor() {
super();

this.root.push(new ContinuationSeperator());
}
}
7 changes: 7 additions & 0 deletions src/file/footnotes/footnote/run/continuation-seperator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { XmlComponent } from "file/xml-components";

export class ContinuationSeperator extends XmlComponent {
constructor() {
super("w:continuationSeparator");
}
}
11 changes: 11 additions & 0 deletions src/file/footnotes/footnote/run/footnote-ref-run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Run } from "file/paragraph";
import { FootnoteRef } from "./footnote-ref";

export class FootnoteRefRun extends Run {
constructor() {
super();

this.style("FootnoteReference");
this.root.push(new FootnoteRef());
}
}
7 changes: 7 additions & 0 deletions src/file/footnotes/footnote/run/footnote-ref.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { XmlComponent } from "file/xml-components";

export class FootnoteRef extends XmlComponent {
constructor() {
super("w:footnoteRef");
}
}
35 changes: 35 additions & 0 deletions src/file/footnotes/footnote/run/reference-run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Run } from "file/paragraph/run";
import { Style } from "file/paragraph/run/style";
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";

export interface IFootNoteReferenceRunAttributesProperties {
id: number;
}

export class FootNoteReferenceRunAttributes extends XmlAttributeComponent<IFootNoteReferenceRunAttributesProperties> {
protected xmlKeys = {
id: "w:id",
};
}

export class FootnoteReference extends XmlComponent {
constructor(id: number) {
super("w:footnoteReference");

this.root.push(
new FootNoteReferenceRunAttributes({
id: id,
}),
);
}
}

export class FootnoteReferenceRun extends Run {
constructor(id: number) {
super();

this.properties.push(new Style("FootnoteReference"));

this.root.push(new FootnoteReference(id));
}
}
10 changes: 10 additions & 0 deletions src/file/footnotes/footnote/run/seperator-run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Run } from "file/paragraph";
import { Seperator } from "./seperator";

export class SeperatorRun extends Run {
constructor() {
super();

this.root.push(new Seperator());
}
}
7 changes: 7 additions & 0 deletions src/file/footnotes/footnote/run/seperator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { XmlComponent } from "file/xml-components";

export class Seperator extends XmlComponent {
constructor() {
super("w:separator");
}
}
43 changes: 43 additions & 0 deletions src/file/footnotes/footnotes-attributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { XmlAttributeComponent } from "file/xml-components";

export interface IFootnotesAttributesProperties {
wpc?: string;
mc?: string;
o?: string;
r?: string;
m?: string;
v?: string;
wp14?: string;
wp?: string;
w10?: string;
w?: string;
w14?: string;
w15?: string;
wpg?: string;
wpi?: string;
wne?: string;
wps?: string;
Ignorable?: string;
}

export class FootnotesAttributes extends XmlAttributeComponent<IFootnotesAttributesProperties> {
protected xmlKeys = {
wpc: "xmlns:wpc",
mc: "xmlns:mc",
o: "xmlns:o",
r: "xmlns:r",
m: "xmlns:m",
v: "xmlns:v",
wp14: "xmlns:wp14",
wp: "xmlns:wp",
w10: "xmlns:w10",
w: "xmlns:w",
w14: "xmlns:w14",
w15: "xmlns:w15",
wpg: "xmlns:wpg",
wpi: "xmlns:wpi",
wne: "xmlns:wne",
wps: "xmlns:wps",
Ignorable: "mc:Ignorable",
};
}
Loading