Mandatory Sections

This commit is contained in:
Dolan Miu
2019-07-31 08:48:02 +01:00
parent bf80311ef7
commit ac5b15d0e3
63 changed files with 1194 additions and 1588 deletions

View File

@ -11,35 +11,7 @@ describe("Body", () => {
body = new Body();
});
describe("#constructor()", () => {
it("should create default section", () => {
const formatted = new Formatter().format(body)["w:body"][0];
expect(formatted)
.to.have.property("w:sectPr")
.and.to.be.an.instanceof(Array);
expect(formatted["w:sectPr"]).to.have.length(4);
});
});
describe("#addSection", () => {
it("should add section with options", () => {
body.addSection({
width: 10000,
height: 10000,
});
const formatted = new Formatter().format(body)["w:body"];
expect(formatted).to.be.an.instanceof(Array);
const defaultSectionPr = formatted[0]["w:p"][0]["w:pPr"][0]["w:sectPr"];
// check that this is the default section and added first in paragraph
expect(defaultSectionPr[0]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 16838, "w:w": 11906, "w:orient": "portrait" } } });
// check for new section (since it's the last one, it's direct child of body)
const newSection = formatted[1]["w:sectPr"];
expect(newSection[0]).to.deep.equal({ "w:pgSz": { _attr: { "w:h": 10000, "w:w": 10000, "w:orient": "portrait" } } });
});
it("should add section with default parameters", () => {
body.addSection({
width: 10000,
@ -51,33 +23,7 @@ describe("Body", () => {
expect(tree).to.deep.equal({
"w:body": [
{
"w:p": [
{
"w:pPr": [
{
"w:sectPr": [
{ "w:pgSz": { _attr: { "w:w": 11906, "w:h": 16838, "w:orient": "portrait" } } },
{
"w:pgMar": {
_attr: {
"w:top": 1440,
"w:right": 1440,
"w:bottom": 1440,
"w:left": 1440,
"w:header": 708,
"w:footer": 708,
"w:gutter": 0,
"w:mirrorMargins": false,
},
},
},
{ "w:cols": { _attr: { "w:space": 708, "w:num": 1 } } },
{ "w:docGrid": { _attr: { "w:linePitch": 360 } } },
],
},
],
},
],
"w:p": {},
},
{
"w:sectPr": [
@ -104,21 +50,4 @@ describe("Body", () => {
});
});
});
describe("#getParagraphs", () => {
it("should get no paragraphs", () => {
const paragraphs = body.getParagraphs();
expect(paragraphs).to.be.an.instanceof(Array);
});
});
describe("#DefaultSection", () => {
it("should get section", () => {
const section = body.DefaultSection;
const tree = new Formatter().format(section);
expect(tree["w:sectPr"]).to.be.an.instanceof(Array);
});
});
});

View File

@ -3,15 +3,10 @@ import { Paragraph, ParagraphProperties, TableOfContents } from "../..";
import { SectionProperties, SectionPropertiesOptions } from "./section-properties/section-properties";
export class Body extends XmlComponent {
private readonly defaultSection: SectionProperties;
private readonly sections: SectionProperties[] = [];
constructor(sectionPropertiesOptions?: SectionPropertiesOptions) {
constructor() {
super("w:body");
this.defaultSection = new SectionProperties(sectionPropertiesOptions);
this.sections.push(this.defaultSection);
}
/**
@ -20,21 +15,15 @@ export class Body extends XmlComponent {
* The spec says:
* - section element should be in the last paragraph of the section
* - last section should be direct child of body
* @param section new section
* @param options new section options
*/
public addSection(section: SectionPropertiesOptions | SectionProperties): void {
public addSection(options: SectionPropertiesOptions): void {
const currentSection = this.sections.pop() as SectionProperties;
this.root.push(this.createSectionParagraph(currentSection));
if (section instanceof SectionProperties) {
this.sections.push(section);
} else {
const params = {
...this.defaultSection.Options,
...section,
};
this.sections.push(new SectionProperties(params));
}
this.sections.push(new SectionProperties(options));
}
public prepForXml(): IXmlableObject | undefined {
if (this.sections.length === 1) {
this.root.push(this.sections.pop() as SectionProperties);
@ -47,18 +36,10 @@ export class Body extends XmlComponent {
this.root.push(component);
}
public get DefaultSection(): SectionProperties {
return this.defaultSection;
}
public getTablesOfContents(): TableOfContents[] {
return this.root.filter((child) => child instanceof TableOfContents) as TableOfContents[];
}
public getParagraphs(): Paragraph[] {
return this.root.filter((child) => child instanceof Paragraph) as Paragraph[];
}
private createSectionParagraph(section: SectionProperties): Paragraph {
const paragraph = new Paragraph({});
const properties = new ParagraphProperties({});

View File

@ -1,13 +1,13 @@
import { XmlComponent } from "file/xml-components";
import { HeaderReferenceAttributes, HeaderReferenceType } from "./header-reference-attributes";
export interface IHeaderOptions {
export interface IHeaderReferenceOptions {
readonly headerType?: HeaderReferenceType;
readonly headerId?: number;
}
export class HeaderReference extends XmlComponent {
constructor(options: IHeaderOptions) {
constructor(options: IHeaderReferenceOptions) {
super("w:headerReference");
this.root.push(
new HeaderReferenceAttributes({

View File

@ -1,4 +1,4 @@
import { assert, expect } from "chai";
import { expect } from "chai";
import { Formatter } from "export/formatter";
@ -13,19 +13,34 @@ describe("Document", () => {
describe("#constructor()", () => {
it("should create valid JSON", () => {
const stringifiedJson = JSON.stringify(document);
const tree = new Formatter().format(document);
try {
JSON.parse(stringifiedJson);
} catch (e) {
assert.isTrue(false);
}
assert.isTrue(true);
});
it("should create default section", () => {
const body = new Formatter().format(document)["w:document"][1]["w:body"];
expect(body[0]).to.have.property("w:sectPr");
expect(tree).to.deep.equal({
"w:document": [
{
_attr: {
"xmlns:wpc": "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
"xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
"xmlns:o": "urn:schemas-microsoft-com:office:office",
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
"xmlns:m": "http://schemas.openxmlformats.org/officeDocument/2006/math",
"xmlns:v": "urn:schemas-microsoft-com:vml",
"xmlns:wp14": "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
"xmlns:wp": "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
"xmlns:w10": "urn:schemas-microsoft-com:office:word",
"xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
"xmlns:w14": "http://schemas.microsoft.com/office/word/2010/wordml",
"xmlns:w15": "http://schemas.microsoft.com/office/word/2012/wordml",
"xmlns:wpg": "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
"xmlns:wpi": "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
"xmlns:wne": "http://schemas.microsoft.com/office/word/2006/wordml",
"xmlns:wps": "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
"mc:Ignorable": "w14 w15 wp14",
},
},
{ "w:body": {} },
],
});
});
});
});

View File

@ -4,13 +4,12 @@ import { Paragraph } from "../paragraph";
import { Table } from "../table";
import { TableOfContents } from "../table-of-contents";
import { Body } from "./body";
import { SectionPropertiesOptions } from "./body/section-properties";
import { DocumentAttributes } from "./document-attributes";
export class Document extends XmlComponent {
private readonly body: Body;
constructor(sectionPropertiesOptions?: SectionPropertiesOptions) {
constructor() {
super("w:document");
this.root.push(
new DocumentAttributes({
@ -33,17 +32,12 @@ export class Document extends XmlComponent {
Ignorable: "w14 w15 wp14",
}),
);
this.body = new Body(sectionPropertiesOptions);
this.body = new Body();
this.root.push(this.body);
}
public add(paragraph: Paragraph | Table): Document {
this.body.push(paragraph);
return this;
}
public addTableOfContents(toc: TableOfContents): Document {
this.body.push(toc);
public add(item: Paragraph | Table | TableOfContents): Document {
this.body.push(item);
return this;
}
@ -54,8 +48,4 @@ export class Document extends XmlComponent {
public getTablesOfContents(): TableOfContents[] {
return this.body.getTablesOfContents();
}
public getParagraphs(): Paragraph[] {
return this.body.getParagraphs();
}
}

View File

@ -4,24 +4,37 @@ import * as sinon from "sinon";
import { Formatter } from "export/formatter";
import { File } from "./file";
import { Footer, Header } from "./header";
import { Paragraph } from "./paragraph";
import { Table } from "./table";
import { TableOfContents } from "./table-of-contents";
describe("File", () => {
describe("#constructor", () => {
it("should create with correct headers and footers by default", () => {
const doc = new File();
doc.addSection({
children: [],
});
const tree = new Formatter().format(doc.Document.Body);
expect(tree["w:body"][1]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default");
expect(tree["w:body"][1]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("default");
});
it("should create with correct headers and footers", () => {
const doc = new File();
const header = doc.createHeader();
const footer = doc.createFooter();
doc.addSectionOld({
doc.addSection({
headers: {
default: header,
default: new Header(),
},
footers: {
default: footer,
default: new Footer(),
},
children: [],
});
const tree = new Formatter().format(doc.Document.Body);
@ -32,40 +45,40 @@ describe("File", () => {
it("should create with first headers and footers", () => {
const doc = new File();
const header = doc.createHeader();
const footer = doc.createFooter();
doc.addSectionOld({
doc.addSection({
headers: {
first: header,
first: new Header(),
},
footers: {
first: footer,
first: new Footer(),
},
children: [],
});
const tree = new Formatter().format(doc.Document.Body);
expect(tree["w:body"][1]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("first");
expect(tree["w:body"][1]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("first");
console.log(JSON.stringify(tree, null, 2));
expect(tree["w:body"][1]["w:sectPr"][5]["w:headerReference"]._attr["w:type"]).to.equal("first");
expect(tree["w:body"][1]["w:sectPr"][7]["w:footerReference"]._attr["w:type"]).to.equal("first");
});
it("should create with correct headers", () => {
const doc = new File();
const header = doc.createHeader();
const footer = doc.createFooter();
doc.addSectionOld({
doc.addSection({
headers: {
default: header,
first: header,
even: header,
default: new Header(),
first: new Header(),
even: new Header(),
},
footers: {
default: footer,
first: footer,
even: footer,
default: new Footer(),
first: new Footer(),
even: new Footer(),
},
children: [],
});
const tree = new Formatter().format(doc.Document.Body);
@ -80,60 +93,56 @@ describe("File", () => {
});
});
describe("#add", () => {
describe("#addSection", () => {
it("should call the underlying document's add a Paragraph", () => {
const file = new File();
const spy = sinon.spy(file.Document, "add");
file.add(new Paragraph({}));
file.addSection({
children: [new Paragraph({})],
});
expect(spy.called).to.equal(true);
});
it("should call the underlying document's add when adding a Table", () => {
const wrapper = new File();
const spy = sinon.spy(wrapper.Document, "add");
wrapper.add(
new Table({
rows: 1,
columns: 1,
}),
);
const file = new File();
const spy = sinon.spy(file.Document, "add");
file.addSection({
children: [
new Table({
rows: 1,
columns: 1,
}),
],
});
expect(spy.called).to.equal(true);
});
it("should call the underlying document's add when adding an Image (paragraph)", () => {
const wrapper = new File();
const spy = sinon.spy(wrapper.Document, "add");
const file = new File();
const spy = sinon.spy(file.Document, "add");
// tslint:disable-next-line:no-any
wrapper.add(new Paragraph(""));
file.addSection({
children: [new Paragraph("")],
});
expect(spy.called).to.equal(true);
});
});
describe("#add", () => {
it("should call the underlying document's addTableOfContents", () => {
const wrapper = new File();
const spy = sinon.spy(wrapper.Document, "addTableOfContents");
wrapper.add(new TableOfContents());
describe("#addSection", () => {
it("should call the underlying document's add", () => {
const file = new File();
const spy = sinon.spy(file.Document, "add");
file.addSection({
children: [new TableOfContents()],
});
expect(spy.called).to.equal(true);
});
});
describe("#createImage", () => {
it("should call the underlying document's createImage", () => {
const wrapper = new File();
const spy = sinon.spy(wrapper.Media, "addMedia");
const wrapperSpy = sinon.spy(wrapper.Document, "add");
wrapper.createImage("");
expect(spy.called).to.equal(true);
expect(wrapperSpy.called).to.equal(true);
});
});
describe("#createFootnote", () => {
it("should call the underlying document's createFootnote", () => {
const wrapper = new File();

View File

@ -3,17 +3,16 @@ import { ContentTypes } from "./content-types/content-types";
import { CoreProperties, IPropertiesOptions } from "./core-properties";
import { Document } from "./document";
import {
FooterReference,
FooterReferenceType,
HeaderReference,
HeaderReferenceType,
IHeaderFooterGroup,
IPageSizeAttributes,
SectionPropertiesOptions,
} from "./document/body/section-properties";
import { IDrawingOptions } from "./drawing";
import { IPageMarginAttributes } from "./document/body/section-properties/page-margin/page-margin-attributes";
import { IFileProperties } from "./file-properties";
import { FooterWrapper, IDocumentFooter } from "./footer-wrapper";
import { FootNotes } from "./footnotes";
import { Footer, Header } from "./header";
import { HeaderWrapper, IDocumentHeader } from "./header-wrapper";
import { Media } from "./media";
import { Numbering } from "./numbering";
@ -28,7 +27,19 @@ import { Table } from "./table";
import { TableOfContents } from "./table-of-contents";
export interface ISectionOptions {
readonly properties: SectionPropertiesOptions;
readonly headers?: {
readonly default?: Header;
readonly first?: Header;
readonly even?: Header;
};
readonly footers?: {
readonly default?: Footer;
readonly first?: Footer;
readonly even?: Footer;
};
readonly size?: IPageSizeAttributes;
readonly margins?: IPageMarginAttributes;
readonly properties?: SectionPropertiesOptions;
readonly children: Array<Paragraph | Table | TableOfContents>;
}
@ -57,7 +68,6 @@ export class File {
revision: "1",
lastModifiedBy: "Un-named",
},
sectionPropertiesOptions: SectionPropertiesOptions = {},
fileProperties: IFileProperties = {},
sections: ISectionOptions[] = [],
) {
@ -68,6 +78,8 @@ export class File {
this.appProperties = new AppProperties();
this.footNotes = new FootNotes();
this.contentTypes = new ContentTypes();
this.document = new Document();
this.settings = new Settings();
this.media = fileProperties.template && fileProperties.template.media ? fileProperties.template.media : new Media();
@ -96,65 +108,23 @@ export class File {
for (const templateHeader of fileProperties.template.headers) {
this.addHeaderToDocument(templateHeader.header, templateHeader.type);
}
} else {
this.createHeader();
}
if (fileProperties.template && fileProperties.template.footers) {
for (const templateFooter of fileProperties.template.footers) {
this.addFooterToDocument(templateFooter.footer, templateFooter.type);
}
} else {
this.createFooter();
}
const newSectionPropertiesOptions = {
...sectionPropertiesOptions,
headers: this.groupHeaders(this.headers, sectionPropertiesOptions.headers),
footers: this.groupFooters(this.footers, sectionPropertiesOptions.footers),
};
this.document = new Document(newSectionPropertiesOptions);
this.settings = new Settings();
for (const section of sections) {
this.document.Body.addSection(section.properties);
this.document.Body.addSection(section.properties ? section.properties : {});
for (const child of section.children) {
this.add(child);
this.document.add(child);
}
}
}
public add(item: Paragraph | Table | TableOfContents): File {
if (item instanceof Paragraph) {
this.document.add(item);
}
if (item instanceof Table) {
this.document.add(item);
}
if (item instanceof TableOfContents) {
this.document.addTableOfContents(item);
}
return this;
}
public createImage(
buffer: Buffer | string | Uint8Array | ArrayBuffer,
width?: number,
height?: number,
drawingOptions?: IDrawingOptions,
): Paragraph {
const image = Media.addImage(this, buffer, width, height, drawingOptions);
const paragraph = new Paragraph(image);
this.document.add(paragraph);
return paragraph;
}
public createHyperlink(link: string, text?: string): Hyperlink {
const newText = text === undefined ? link : text;
const hyperlink = new Hyperlink(newText, this.docRelationships.RelationshipCount);
@ -175,21 +145,36 @@ export class File {
return hyperlink;
}
public createBookmark(name: string, text?: string): Bookmark {
const newText = text === undefined ? name : text;
const bookmark = new Bookmark(name, newText, this.docRelationships.RelationshipCount);
return bookmark;
public createBookmark(name: string, text: string = name): Bookmark {
return new Bookmark(name, text, this.docRelationships.RelationshipCount);
}
public addSectionOld(sectionPropertiesOptions: SectionPropertiesOptions): void {
this.document.Body.addSection(sectionPropertiesOptions);
}
public addSection({
headers = { default: new Header() },
footers = { default: new Header() },
margins = {},
size = {},
properties,
children,
}: ISectionOptions): void {
this.document.Body.addSection({
...properties,
headers: {
default: headers.default ? this.createHeader(headers.default) : this.createHeader(new Header()),
first: headers.first ? this.createHeader(headers.first) : undefined,
even: headers.even ? this.createHeader(headers.even) : undefined,
},
footers: {
default: footers.default ? this.createFooter(footers.default) : this.createFooter(new Footer()),
first: footers.first ? this.createFooter(footers.first) : undefined,
even: footers.even ? this.createFooter(footers.even) : undefined,
},
...margins,
...size,
});
public addSection(section: ISectionOptions): void {
this.document.Body.addSection(section.properties);
for (const child of section.children) {
this.add(child);
for (const child of children) {
this.document.add(child);
}
}
@ -197,92 +182,34 @@ export class File {
this.footNotes.createFootNote(paragraph);
}
public createHeader(): HeaderWrapper {
const header = new HeaderWrapper(this.media, this.currentRelationshipId++);
this.addHeaderToDocument(header);
return header;
}
public createFooter(): FooterWrapper {
const footer = new FooterWrapper(this.media, this.currentRelationshipId++);
this.addFooterToDocument(footer);
return footer;
}
public createFirstPageHeader(): HeaderWrapper {
const headerWrapper = this.createHeader();
this.document.Body.DefaultSection.addChildElement(
new HeaderReference({
headerType: HeaderReferenceType.FIRST,
headerId: headerWrapper.Header.ReferenceId,
}),
);
return headerWrapper;
}
public createEvenPageHeader(): HeaderWrapper {
const headerWrapper = this.createHeader();
this.document.Body.DefaultSection.addChildElement(
new HeaderReference({
headerType: HeaderReferenceType.EVEN,
headerId: headerWrapper.Header.ReferenceId,
}),
);
return headerWrapper;
}
public createFirstPageFooter(): FooterWrapper {
const footerWrapper = this.createFooter();
this.document.Body.DefaultSection.addChildElement(
new FooterReference({
footerType: FooterReferenceType.FIRST,
footerId: footerWrapper.Footer.ReferenceId,
}),
);
return footerWrapper;
}
public createEvenPageFooter(): FooterWrapper {
const footerWrapper = this.createFooter();
this.document.Body.DefaultSection.addChildElement(
new FooterReference({
footerType: FooterReferenceType.EVEN,
footerId: footerWrapper.Footer.ReferenceId,
}),
);
return footerWrapper;
}
public getFooterByReferenceNumber(refId: number): FooterWrapper {
const entry = this.footers.map((item) => item.footer).find((h) => h.Footer.ReferenceId === refId);
if (entry) {
return entry;
}
throw new Error(`There is no footer with given reference id ${refId}`);
}
public getHeaderByReferenceNumber(refId: number): HeaderWrapper {
const entry = this.headers.map((item) => item.header).find((h) => h.Header.ReferenceId === refId);
if (entry) {
return entry;
}
throw new Error(`There is no header with given reference id ${refId}`);
}
public verifyUpdateFields(): void {
if (this.document.getTablesOfContents().length) {
this.settings.addUpdateFields();
}
}
private createHeader(header: Header): HeaderWrapper {
const wrapper = new HeaderWrapper(this.media, this.currentRelationshipId++);
for (const child of header.options.children) {
wrapper.add(child);
}
this.addHeaderToDocument(wrapper);
return wrapper;
}
private createFooter(footer: Footer): FooterWrapper {
const wrapper = new FooterWrapper(this.media, this.currentRelationshipId++);
for (const child of footer.options.children) {
wrapper.add(child);
}
this.addFooterToDocument(wrapper);
return wrapper;
}
private addHeaderToDocument(header: HeaderWrapper, type: HeaderReferenceType = HeaderReferenceType.DEFAULT): void {
this.headers.push({ header, type });
this.docRelationships.createRelationship(
@ -342,66 +269,6 @@ export class File {
);
}
private groupHeaders(headers: IDocumentHeader[], group: IHeaderFooterGroup<HeaderWrapper> = {}): IHeaderFooterGroup<HeaderWrapper> {
let newGroup = group;
for (const header of headers) {
switch (header.type) {
case HeaderReferenceType.FIRST:
newGroup = {
...newGroup,
first: header.header,
};
break;
case HeaderReferenceType.EVEN:
newGroup = {
...newGroup,
even: header.header,
};
break;
case HeaderReferenceType.DEFAULT:
default:
newGroup = {
...newGroup,
default: header.header,
};
break;
}
}
return newGroup;
}
private groupFooters(footers: IDocumentFooter[], group: IHeaderFooterGroup<FooterWrapper> = {}): IHeaderFooterGroup<FooterWrapper> {
let newGroup = group;
for (const footer of footers) {
switch (footer.type) {
case FooterReferenceType.FIRST:
newGroup = {
...newGroup,
first: footer.footer,
};
break;
case FooterReferenceType.EVEN:
newGroup = {
...newGroup,
even: footer.footer,
};
break;
case FooterReferenceType.DEFAULT:
default:
newGroup = {
...newGroup,
default: footer.footer,
};
break;
}
}
return newGroup;
}
public get Document(): Document {
return this.document;
}
@ -434,18 +301,10 @@ export class File {
return this.fileRelationships;
}
public get Header(): HeaderWrapper {
return this.headers[0].header;
}
public get Headers(): HeaderWrapper[] {
return this.headers.map((item) => item.header);
}
public get Footer(): FooterWrapper {
return this.footers[0].footer;
}
public get Footers(): FooterWrapper[] {
return this.footers.map((item) => item.footer);
}

View File

@ -39,17 +39,6 @@ describe("FooterWrapper", () => {
});
});
describe("#createImage", () => {
it("should call the underlying footer's createImage", () => {
const file = new FooterWrapper(new Media(), 1);
const spy = sinon.spy(Media, "addImage");
file.createImage("");
expect(spy.called).to.equal(true);
spy.restore();
});
});
describe("#addChildElement", () => {
it("should call the underlying footer's addChildElement", () => {
const file = new FooterWrapper(new Media(), 1);

View File

@ -1,7 +1,6 @@
import { XmlComponent } from "file/xml-components";
import { FooterReferenceType } from "./document";
import { IDrawingOptions } from "./drawing";
import { Footer } from "./footer/footer";
import { Image, Media } from "./media";
import { Paragraph } from "./paragraph";
@ -35,19 +34,6 @@ export class FooterWrapper {
this.footer.addChildElement(childElement);
}
public createImage(
buffer: Buffer | string | Uint8Array | ArrayBuffer,
width?: number,
height?: number,
drawingOptions?: IDrawingOptions,
): Paragraph {
const image = Media.addImage(this, buffer, width, height, drawingOptions);
const paragraph = new Paragraph(image);
this.add(paragraph);
return paragraph;
}
public get Footer(): Footer {
return this.footer;
}

View File

@ -41,17 +41,6 @@ describe("HeaderWrapper", () => {
});
});
describe("#createImage", () => {
it("should call the underlying header's createImage", () => {
const file = new HeaderWrapper(new Media(), 1);
const spy = sinon.spy(Media, "addImage");
file.createImage("");
expect(spy.called).to.equal(true);
spy.restore();
});
});
describe("#addChildElement", () => {
it("should call the underlying header's addChildElement", () => {
const file = new HeaderWrapper(new Media(), 1);

View File

@ -1,7 +1,6 @@
import { XmlComponent } from "file/xml-components";
import { HeaderReferenceType } from "./document";
import { IDrawingOptions } from "./drawing";
import { Header } from "./header/header";
import { Image, Media } from "./media";
import { Paragraph } from "./paragraph";
@ -37,19 +36,6 @@ export class HeaderWrapper {
this.header.addChildElement(childElement);
}
public createImage(
buffer: Buffer | string | Uint8Array | ArrayBuffer,
width?: number,
height?: number,
drawingOptions?: IDrawingOptions,
): Paragraph {
const image = Media.addImage(this, buffer, width, height, drawingOptions);
const paragraph = new Paragraph(image);
this.add(paragraph);
return paragraph;
}
public get Header(): Header {
return this.header;
}

14
src/file/header.ts Normal file
View File

@ -0,0 +1,14 @@
import { Paragraph } from "./paragraph";
import { Table } from "./table";
export interface IHeaderOptions {
readonly children: Array<Paragraph | Table>;
}
export class Header {
constructor(public readonly options: IHeaderOptions = { children: [] }) {}
}
export class Footer {
constructor(public readonly options: IHeaderOptions = { children: [] }) {}
}

View File

@ -11,3 +11,4 @@ export * from "./table-of-contents";
export * from "./xml-components";
export * from "./header-wrapper";
export * from "./footer-wrapper";
export * from "./header";

View File

@ -10,8 +10,4 @@ export class Image {
public get Run(): PictureRun {
return this.paragraph.Run;
}
public scale(factorX: number, factorY?: number): void {
this.paragraph.Run.scale(factorX, factorY);
}
}

View File

@ -2,6 +2,7 @@ import { Attributes, XmlAttributeComponent, XmlComponent } from "file/xml-compon
import {
Alignment,
AlignmentType,
IIndentAttributesProperties,
Indent,
ISpacingProperties,
KeepLines,
@ -235,7 +236,7 @@ export class LevelBase extends XmlComponent {
return this;
}
public indent(attrs: object): Level {
public indent(attrs: IIndentAttributesProperties): Level {
this.addParagraphProperty(new Indent(attrs));
return this;
}

View File

@ -1,12 +1,8 @@
// tslint:disable:object-literal-key-quotes
import { assert, expect } from "chai";
import { Formatter } from "export/formatter";
import { assert } from "chai";
import { ImageParagraph } from "./image";
import { EMPTY_OBJECT } from "file/xml-components";
describe("Image", () => {
let image: ImageParagraph;
@ -40,190 +36,4 @@ describe("Image", () => {
assert.isTrue(true);
});
});
describe("#scale()", () => {
it("should set the scale of the object properly", () => {
image.scale(2);
const tree = new Formatter().format(image);
expect(tree).to.deep.equal({
"w:p": [
{
"w:r": [
{
"w:drawing": [
{
"wp:inline": [
{
_attr: {
distB: 0,
distL: 0,
distR: 0,
distT: 0,
},
},
{
"wp:extent": {
_attr: {
cx: 20,
cy: 20,
},
},
},
{
"wp:effectExtent": {
_attr: {
b: 0,
l: 0,
r: 0,
t: 0,
},
},
},
{
"wp:docPr": {
_attr: {
descr: "",
id: 0,
name: "",
},
},
},
{
"wp:cNvGraphicFramePr": [
{
"a:graphicFrameLocks": {
_attr: {
noChangeAspect: 1,
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
},
},
},
],
},
{
"a:graphic": [
{
_attr: {
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
},
},
{
"a:graphicData": [
{
_attr: {
uri: "http://schemas.openxmlformats.org/drawingml/2006/picture",
},
},
{
"pic:pic": [
{
_attr: {
"xmlns:pic":
"http://schemas.openxmlformats.org/drawingml/2006/picture",
},
},
{
"pic:nvPicPr": [
{
"pic:cNvPr": {
_attr: {
desc: "",
id: 0,
name: "",
},
},
},
{
"pic:cNvPicPr": [
{
"a:picLocks": {
_attr: {
noChangeArrowheads: 1,
noChangeAspect: 1,
},
},
},
],
},
],
},
{
"pic:blipFill": [
{
"a:blip": {
_attr: {
cstate: "none",
"r:embed": "rId{test.png}",
},
},
},
{
"a:srcRect": EMPTY_OBJECT,
},
{
"a:stretch": [
{
"a:fillRect": EMPTY_OBJECT,
},
],
},
],
},
{
"pic:spPr": [
{
_attr: {
bwMode: "auto",
},
},
{
"a:xfrm": [
{
"a:ext": {
_attr: {
cx: 10,
cy: 10,
},
},
},
{
"a:off": {
_attr: {
x: 0,
y: 0,
},
},
},
],
},
{
"a:prstGeom": [
{
_attr: {
prst: "rect",
},
},
{
"a:avLst": EMPTY_OBJECT,
},
],
},
],
},
],
},
],
},
],
},
],
},
],
},
],
},
],
});
});
});
});

View File

@ -12,10 +12,6 @@ export class ImageParagraph extends Paragraph {
this.root.push(this.pictureRun);
}
public scale(factorX: number, factorY?: number): void {
this.pictureRun.scale(factorX, factorY);
}
public get Run(): PictureRun {
return this.pictureRun;
}

View File

@ -4,8 +4,6 @@ import { IMediaData } from "../../media/data";
import { Run } from "../run";
export class PictureRun extends Run {
private readonly drawing: Drawing;
constructor(imageData: IMediaData, drawingOptions?: IDrawingOptions) {
super({});
@ -13,12 +11,8 @@ export class PictureRun extends Run {
throw new Error("imageData cannot be undefined");
}
this.drawing = new Drawing(imageData, drawingOptions);
const drawing = new Drawing(imageData, drawingOptions);
this.root.push(this.drawing);
}
public scale(factorX: number = 1, factorY: number = factorX): void {
this.drawing.scale(factorX, factorY);
this.root.push(drawing);
}
}