From 9c11653313e0cdb4319c5e9f74dfd16b7952e23f Mon Sep 17 00:00:00 2001 From: Dolan Date: Wed, 1 Jan 2020 20:22:42 +0000 Subject: [PATCH] Multiple paragraphs in footnotes --- demo/17-footnotes.ts | 16 ++--- src/file/core-properties/properties.ts | 6 +- src/file/file.spec.ts | 6 +- src/file/file.ts | 9 ++- .../footnotes/footnote/footnote-attributes.ts | 6 +- src/file/footnotes/footnote/footnote.spec.ts | 11 ++- src/file/footnotes/footnote/footnote.ts | 19 ++++-- .../footnotes/footnote/run/reference-run.ts | 6 +- src/file/footnotes/footnotes.ts | 68 ++++++++++--------- 9 files changed, 86 insertions(+), 61 deletions(-) diff --git a/demo/17-footnotes.ts b/demo/17-footnotes.ts index a41f84a3c8..0ba23c07cb 100644 --- a/demo/17-footnotes.ts +++ b/demo/17-footnotes.ts @@ -4,14 +4,14 @@ import * as fs from "fs"; import { Document, FootnoteReferenceRun, Packer, Paragraph, TextRun } from "../build"; const doc = new Document({ - footnotes: [ - new Paragraph("Foo"), - new Paragraph("Test"), - new Paragraph("My amazing reference"), - new Paragraph("Foo1"), - new Paragraph("Test1"), - new Paragraph("My amazing reference1"), - ], + footnotes: { + 1: { children: [new Paragraph("Foo"), new Paragraph("Bar")] }, + 2: { children: [new Paragraph("Test")] }, + 3: { children: [new Paragraph("My amazing reference")] }, + 4: { children: [new Paragraph("Foo1")] }, + 5: { children: [new Paragraph("Test1")] }, + 6: { children: [new Paragraph("My amazing reference1")] }, + }, }); doc.addSection({ diff --git a/src/file/core-properties/properties.ts b/src/file/core-properties/properties.ts index ceddff39e0..c6b4f8348d 100644 --- a/src/file/core-properties/properties.ts +++ b/src/file/core-properties/properties.ts @@ -28,7 +28,11 @@ export interface IPropertiesOptions { readonly externalStyles?: string; readonly styles?: IStylesOptions; readonly numbering?: INumberingOptions; - readonly footnotes?: Paragraph[]; + readonly footnotes?: { + readonly [key: string]: { + readonly children: Paragraph[]; + }; + }; readonly hyperlinks?: { readonly [key: string]: IInternalHyperlinkDefinition | IExternalHyperlinkDefinition; }; diff --git a/src/file/file.spec.ts b/src/file/file.spec.ts index 6ec30e1be9..8864f62d25 100644 --- a/src/file/file.spec.ts +++ b/src/file/file.spec.ts @@ -254,7 +254,11 @@ describe("File", () => { describe("#createFootnote", () => { it("should create footnote", () => { const wrapper = new File({ - footnotes: [new Paragraph("hello")], + footnotes: { + 1: { + children: [new Paragraph("hello")], + }, + }, }); const tree = new Formatter().format(wrapper.FootNotes); diff --git a/src/file/file.ts b/src/file/file.ts index 59af9fa7f7..962eefca21 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -1,4 +1,5 @@ import * as shortid from "shortid"; + import { AppProperties } from "./app-properties/app-properties"; import { ContentTypes } from "./content-types/content-types"; import { CoreProperties, IPropertiesOptions } from "./core-properties"; @@ -145,8 +146,12 @@ export class File { } if (options.footnotes) { - for (const paragraph of options.footnotes) { - this.footNotes.createFootNote(paragraph); + for (const key in options.footnotes) { + if (!options.footnotes[key]) { + continue; + } + + this.footNotes.createFootNote(parseFloat(key), options.footnotes[key].children); } } diff --git a/src/file/footnotes/footnote/footnote-attributes.ts b/src/file/footnotes/footnote/footnote-attributes.ts index ee978d0ef2..027f9213fe 100644 --- a/src/file/footnotes/footnote/footnote-attributes.ts +++ b/src/file/footnotes/footnote/footnote-attributes.ts @@ -1,11 +1,9 @@ import { XmlAttributeComponent } from "file/xml-components"; -export interface IFootnoteAttributesProperties { +export class FootnoteAttributes extends XmlAttributeComponent<{ readonly type?: string; readonly id: number; -} - -export class FootnoteAttributes extends XmlAttributeComponent { +}> { protected readonly xmlKeys = { type: "w:type", id: "w:id", diff --git a/src/file/footnotes/footnote/footnote.spec.ts b/src/file/footnotes/footnote/footnote.spec.ts index 8594cd75fd..ab1778f687 100644 --- a/src/file/footnotes/footnote/footnote.spec.ts +++ b/src/file/footnotes/footnote/footnote.spec.ts @@ -7,7 +7,11 @@ 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 footnote = new Footnote({ + id: 1, + type: FootnoteType.SEPERATOR, + children: [], + }); const tree = new Formatter().format(footnote); expect(Object.keys(tree)).to.deep.equal(["w:footnote"]); @@ -15,7 +19,10 @@ describe("Footnote", () => { }); it("should create a footnote without a footnote type", () => { - const footnote = new Footnote(1); + const footnote = new Footnote({ + id: 1, + children: [], + }); const tree = new Formatter().format(footnote); expect(Object.keys(tree)).to.deep.equal(["w:footnote"]); diff --git a/src/file/footnotes/footnote/footnote.ts b/src/file/footnotes/footnote/footnote.ts index 60e6e533c8..b890e5a0c4 100644 --- a/src/file/footnotes/footnote/footnote.ts +++ b/src/file/footnotes/footnote/footnote.ts @@ -10,18 +10,23 @@ export enum FootnoteType { } export class Footnote extends XmlComponent { - constructor(id: number, type?: FootnoteType) { + constructor(options: { readonly id: number; readonly type?: FootnoteType; readonly children: Paragraph[] }) { super("w:footnote"); this.root.push( new FootnoteAttributes({ - type: type, - id: id, + type: options.type, + id: options.id, }), ); - } - public add(paragraph: Paragraph): void { - paragraph.addRunToFront(new FootnoteRefRun()); - this.root.push(paragraph); + for (let i = 0; i < options.children.length; i++) { + const child = options.children[i]; + + if (i === 0) { + child.addRunToFront(new FootnoteRefRun()); + } + + this.root.push(child); + } } } diff --git a/src/file/footnotes/footnote/run/reference-run.ts b/src/file/footnotes/footnote/run/reference-run.ts index 7dec91473d..3bfd772f50 100644 --- a/src/file/footnotes/footnote/run/reference-run.ts +++ b/src/file/footnotes/footnote/run/reference-run.ts @@ -2,11 +2,9 @@ import { Run } from "file/paragraph/run"; import { Style } from "file/paragraph/run/style"; import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; -export interface IFootNoteReferenceRunAttributesProperties { +export class FootNoteReferenceRunAttributes extends XmlAttributeComponent<{ readonly id: number; -} - -export class FootNoteReferenceRunAttributes extends XmlAttributeComponent { +}> { protected readonly xmlKeys = { id: "w:id", }; diff --git a/src/file/footnotes/footnotes.ts b/src/file/footnotes/footnotes.ts index 91ba1d199d..965c587fc9 100644 --- a/src/file/footnotes/footnotes.ts +++ b/src/file/footnotes/footnotes.ts @@ -1,4 +1,5 @@ import { XmlComponent } from "file/xml-components"; + import { Paragraph } from "../paragraph"; import { Footnote, FootnoteType } from "./footnote/footnote"; import { ContinuationSeperatorRun } from "./footnote/run/continuation-seperator-run"; @@ -6,14 +7,9 @@ import { SeperatorRun } from "./footnote/run/seperator-run"; import { FootnotesAttributes } from "./footnotes-attributes"; export class FootNotes extends XmlComponent { - // tslint:disable-next-line:readonly-keyword - private currentId: number; - constructor() { super("w:footnotes"); - this.currentId = 1; - this.root.push( new FootnotesAttributes({ wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas", @@ -36,38 +32,46 @@ export class FootNotes extends XmlComponent { }), ); - const begin = new Footnote(-1, FootnoteType.SEPERATOR); - begin.add( - new Paragraph({ - spacing: { - after: 0, - line: 240, - lineRule: "auto", - }, - children: [new SeperatorRun()], - }), - ); + const begin = new Footnote({ + id: -1, + type: FootnoteType.SEPERATOR, + children: [ + new Paragraph({ + spacing: { + after: 0, + line: 240, + lineRule: "auto", + }, + children: [new SeperatorRun()], + }), + ], + }); + this.root.push(begin); - const spacing = new Footnote(0, FootnoteType.CONTINUATION_SEPERATOR); - spacing.add( - new Paragraph({ - spacing: { - after: 0, - line: 240, - lineRule: "auto", - }, - children: [new ContinuationSeperatorRun()], - }), - ); + const spacing = new Footnote({ + id: 0, + type: FootnoteType.CONTINUATION_SEPERATOR, + children: [ + new Paragraph({ + spacing: { + after: 0, + line: 240, + lineRule: "auto", + }, + children: [new ContinuationSeperatorRun()], + }), + ], + }); + this.root.push(spacing); } - public createFootNote(paragraph: Paragraph): void { - const footnote = new Footnote(this.currentId); - footnote.add(paragraph); + public createFootNote(id: number, paragraph: Paragraph[]): void { + const footnote = new Footnote({ + id: id, + children: paragraph, + }); this.root.push(footnote); - - this.currentId++; } }