This commit is contained in:
amitm02
2018-09-04 17:16:31 +03:00
parent 010fde6258
commit 03c4190c2c
20 changed files with 363 additions and 117 deletions

View File

@ -2,6 +2,8 @@ import { XmlComponent } from "file/xml-components";
import { DocumentAttributes } from "../document/document-attributes";
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
import { TemplateDocument } from 'importDocx/importDocx'
export interface IPropertiesOptions {
title?: string;
subject?: string;
@ -12,7 +14,7 @@ export interface IPropertiesOptions {
revision?: string;
externalStyles?: string;
templateHeader? : XmlComponent;
templateDocument? : TemplateDocument;
}
export class CoreProperties extends XmlComponent {

View File

@ -1,7 +1,7 @@
import { expect } from "chai";
import { Formatter } from "../../../../export/formatter";
import { FooterReferenceType, PageBorderOffsetFrom, PageNumberFormat } from "./";
import { PageBorderOffsetFrom, PageNumberFormat, FooterReferenceType, HeaderReferenceType } from "./";
import { SectionProperties } from "./section-properties";
describe("SectionProperties", () => {
@ -19,9 +19,8 @@ describe("SectionProperties", () => {
gutter: 0,
space: 708,
linePitch: 360,
headerId: 100,
footerId: 200,
footerType: FooterReferenceType.EVEN,
headers: [{headerId: 100, headerType: HeaderReferenceType.DEFAULT}],
footers: [{footerId: 200, footerType: FooterReferenceType.EVEN}],
pageNumberStart: 10,
pageNumberFormatType: PageNumberFormat.CARDINAL_TEXT,
});

View File

@ -1,24 +1,27 @@
// http://officeopenxml.com/WPsection.php
import { XmlComponent } from "file/xml-components";
import { FooterReferenceType, IPageBordersOptions, IPageNumberTypeAttributes, PageBorders, PageNumberFormat, PageNumberType } from "./";
import { IPageBordersOptions, IPageNumberTypeAttributes, PageBorders, PageNumberFormat, PageNumberType } from "./";
import { Columns } from "./columns/columns";
import { IColumnsAttributes } from "./columns/columns-attributes";
import { DocumentGrid } from "./doc-grid/doc-grid";
import { IDocGridAttributesProperties } from "./doc-grid/doc-grid-attributes";
import { FooterReference, IFooterOptions } from "./footer-reference/footer-reference";
import { HeaderReference, IHeaderOptions } from "./header-reference/header-reference";
import { HeaderReferenceType } from "./header-reference/header-reference-attributes";
import { PageMargin } from "./page-margin/page-margin";
import { IPageMarginAttributes } from "./page-margin/page-margin-attributes";
import { PageSize } from "./page-size/page-size";
import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes";
import { TitlePage } from "./title-page/title-page";
type IHeadersOptions = {headers? : IHeaderOptions[]}
type IFootersOptions = {footers? : IFooterOptions[]}
export type SectionPropertiesOptions = IPageSizeAttributes &
IPageMarginAttributes &
IColumnsAttributes &
IDocGridAttributesProperties &
IHeaderOptions &
IFooterOptions &
IHeadersOptions &
IFootersOptions &
IPageNumberTypeAttributes &
IPageBordersOptions;
@ -41,10 +44,8 @@ export class SectionProperties extends XmlComponent {
space: 708,
linePitch: 360,
orientation: PageOrientation.PORTRAIT,
headerType: HeaderReferenceType.DEFAULT,
headerId: 0,
footerType: FooterReferenceType.DEFAULT,
footerId: 0,
headers: [],
footers: [],
pageNumberStart: undefined,
pageNumberFormatType: PageNumberFormat.DECIMAL,
pageBorders: undefined,
@ -52,6 +53,7 @@ export class SectionProperties extends XmlComponent {
pageBorderRight: undefined,
pageBorderBottom: undefined,
pageBorderLeft: undefined,
titlePage : true
};
const mergedOptions = {
@ -59,6 +61,7 @@ export class SectionProperties extends XmlComponent {
...options,
};
this.root.push(new PageSize(mergedOptions.width, mergedOptions.height, mergedOptions.orientation));
this.root.push(
new PageMargin(
@ -74,19 +77,24 @@ export class SectionProperties extends XmlComponent {
this.root.push(new Columns(mergedOptions.space));
this.root.push(new DocumentGrid(mergedOptions.linePitch));
this.root.push(
new HeaderReference({
headerType: mergedOptions.headerType,
headerId: mergedOptions.headerId,
}),
);
this.root.push(
new FooterReference({
footerType: mergedOptions.footerType,
footerId: mergedOptions.footerId,
}),
);
for (let header of mergedOptions.headers) {
this.root.push(
new HeaderReference({
headerType: header.headerType,
headerId: header.headerId,
}),
);
}
for (let footer of mergedOptions.footers) {
this.root.push(
new FooterReference({
footerType: footer.footerType,
footerId: footer.footerId,
}),
);
}
this.root.push(new PageNumberType(mergedOptions.pageNumberStart, mergedOptions.pageNumberFormatType));
if (
@ -107,6 +115,10 @@ export class SectionProperties extends XmlComponent {
);
}
if (mergedOptions.titlePage) {
this.root.push(new TitlePage());
}
this.options = mergedOptions;
}

View File

@ -2,7 +2,14 @@ import { AppProperties } from "./app-properties/app-properties";
import { ContentTypes } from "./content-types/content-types";
import { CoreProperties, IPropertiesOptions } from "./core-properties";
import { Document } from "./document";
import { FooterReferenceType, HeaderReference, HeaderReferenceType, SectionPropertiesOptions } from "./document/body/section-properties";
import {
FooterReferenceType,
HeaderReference,
HeaderReferenceType,
SectionPropertiesOptions,
IHeaderOptions,
IFooterOptions,
} from "./document/body/section-properties";
import { FooterWrapper } from "./footer-wrapper";
import { FootNotes } from "./footnotes";
import { HeaderWrapper } from "./header-wrapper";
@ -14,7 +21,9 @@ import { Styles } from "./styles";
import { ExternalStylesFactory } from "./styles/external-styles-factory";
import { DefaultStylesFactory } from "./styles/factory";
import { Table } from "./table";
import { XmlComponent } from "./xml-components";
type DocumentHeaders = { header: HeaderWrapper; type: HeaderReferenceType }[];
type DocumentFooters = { footer: FooterWrapper; type: FooterReferenceType }[];
export class File {
private readonly document: Document;
@ -24,8 +33,9 @@ export class File {
private readonly media: Media;
private readonly docRelationships: Relationships;
private readonly fileRelationships: Relationships;
private readonly headerWrapper: HeaderWrapper[] = [];
private readonly footerWrapper: FooterWrapper[] = [];
private readonly documentHeaders: DocumentHeaders = [];
private readonly documentFooters: DocumentFooters = [];
private readonly footNotes: FootNotes;
private readonly contentTypes: ContentTypes;
@ -42,6 +52,11 @@ export class File {
};
}
const templateDocument = options.templateDocument;
if (templateDocument) {
this.currentRelationshipId = templateDocument.currentRelationshipId + 1;
}
if (options.externalStyles) {
const stylesFactory = new ExternalStylesFactory();
this.styles = stylesFactory.newInstance(options.externalStyles);
@ -52,6 +67,7 @@ export class File {
this.coreProperties = new CoreProperties(options);
this.numbering = new Numbering();
this.docRelationships = new Relationships();
this.docRelationships.createRelationship(
this.currentRelationshipId++,
@ -70,10 +86,26 @@ export class File {
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
"footnotes.xml",
);
this.media = new Media();
const header = this.createHeader(options.templateHeader);
const footer = this.createFooter();
const templateHeaders = templateDocument && templateDocument.headers;
if (!templateHeaders) {
this.createHeader();
} else {
for (let templateHeader of templateHeaders) {
this.addHeaderToDocument(templateHeader.header, templateHeader.type);
}
}
const templateFooters = templateDocument && templateDocument.footers;
if (!templateFooters) {
this.createFooter();
} else {
for (let templateFooter of templateFooters) {
this.addFooterToDocument(templateFooter.footer, templateFooter.type);
}
}
this.fileRelationships = new Relationships();
this.fileRelationships.createRelationship(
@ -94,17 +126,34 @@ export class File {
this.appProperties = new AppProperties();
this.footNotes = new FootNotes();
let headersOptions: IHeaderOptions[] = [];
for (let documentHeader of this.documentHeaders) {
headersOptions.push({
headerId: documentHeader.header.Header.ReferenceId,
headerType: documentHeader.type,
});
}
let footersOptions: IFooterOptions[] = [];
for (let documentFooter of this.documentFooters) {
footersOptions.push({
footerId: documentFooter.footer.Footer.ReferenceId,
footerType: documentFooter.type,
});
}
if (!sectionPropertiesOptions) {
sectionPropertiesOptions = {
footerType: FooterReferenceType.DEFAULT,
headerType: HeaderReferenceType.DEFAULT,
headerId: header.Header.ReferenceId,
footerId: footer.Footer.ReferenceId,
headers: headersOptions,
footers: footersOptions,
};
} else {
sectionPropertiesOptions.headerId = header.Header.ReferenceId;
sectionPropertiesOptions.footerId = footer.Footer.ReferenceId;
}
else {
sectionPropertiesOptions.headers = headersOptions;
sectionPropertiesOptions.footers = footersOptions;
}
this.document = new Document(sectionPropertiesOptions);
}
@ -170,30 +219,36 @@ export class File {
this.footNotes.createFootNote(paragraph);
}
public createHeader(templateHeader? : XmlComponent): HeaderWrapper {
const header = new HeaderWrapper(this.media, this.currentRelationshipId++, templateHeader);
console.log('\n\n-------\n\n');
console.log('header', JSON.stringify(header.Header, null, 2));
this.headerWrapper.push(header);
this.docRelationships.createRelationship(
header.Header.ReferenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
`header${this.headerWrapper.length}.xml`,
);
this.contentTypes.addHeader(this.headerWrapper.length);
public createHeader(): HeaderWrapper {
const header = new HeaderWrapper(this.currentRelationshipId++);
this.addHeaderToDocument(header);
return header;
}
private addHeaderToDocument(header: HeaderWrapper, type: HeaderReferenceType = HeaderReferenceType.DEFAULT) {
this.documentHeaders.push({ header, type });
this.docRelationships.createRelationship(
header.Header.ReferenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
`header${this.documentHeaders.length}.xml`,
);
this.contentTypes.addHeader(this.documentHeaders.length);
}
public createFooter(): FooterWrapper {
const footer = new FooterWrapper(this.media, this.currentRelationshipId++);
this.footerWrapper.push(footer);
const footer = new FooterWrapper(this.currentRelationshipId++);
this.addFooterToDocument(footer);
return footer;
}
private addFooterToDocument(footer: FooterWrapper, type: FooterReferenceType = FooterReferenceType.DEFAULT) {
this.documentFooters.push({ footer, type });
this.docRelationships.createRelationship(
footer.Footer.ReferenceId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer",
`footer${this.footerWrapper.length}.xml`,
`footer${this.documentFooters.length}.xml`,
);
this.contentTypes.addFooter(this.footerWrapper.length);
return footer;
this.contentTypes.addFooter(this.documentFooters.length);
}
public createFirstPageHeader(): HeaderWrapper {
@ -238,15 +293,15 @@ export class File {
}
public get Header(): HeaderWrapper {
return this.headerWrapper[0];
return this.documentHeaders[0].header;
}
public get Headers(): HeaderWrapper[] {
return this.headerWrapper;
return this.documentHeaders.map((item) => item.header);
}
public HeaderByRefNumber(refId: number): HeaderWrapper {
const entry = this.headerWrapper.find((h) => h.Header.ReferenceId === refId);
const entry = this.documentHeaders.map((item) => item.header).find((h) => h.Header.ReferenceId === refId);
if (entry) {
return entry;
}
@ -254,15 +309,15 @@ export class File {
}
public get Footer(): FooterWrapper {
return this.footerWrapper[0];
return this.documentFooters[0].footer;
}
public get Footers(): FooterWrapper[] {
return this.footerWrapper;
return this.documentFooters.map((item) => item.footer);
}
public FooterByRefNumber(refId: number): FooterWrapper {
const entry = this.footerWrapper.find((h) => h.Footer.ReferenceId === refId);
const entry = this.documentFooters.map((item) => item.footer).find((h) => h.Footer.ReferenceId === refId);
if (entry) {
return entry;
}

View File

@ -4,14 +4,17 @@ import { Image, Media } from "./media";
import { ImageParagraph, Paragraph } from "./paragraph";
import { Relationships } from "./relationships";
import { Table } from "./table";
import { IMediaData } from 'file/media';
export class FooterWrapper {
private readonly footer: Footer;
private readonly relationships: Relationships;
public readonly media = new Media();
constructor(private readonly media: Media, referenceId: number) {
this.footer = new Footer(referenceId);
constructor(referenceId: number, initContent? : XmlComponent) {
this.footer = new Footer(referenceId, initContent);
this.relationships = new Relationships();
}
public addParagraph(paragraph: Paragraph): void {
@ -36,16 +39,22 @@ export class FooterWrapper {
this.footer.addChildElement(childElement);
}
public createImage(image: Buffer, width?: number, height?: number): void {
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height);
public addImageRelation(image: Buffer, refId : number, width?: number, height?: number) : IMediaData {
const mediaData = this.media.addMedia(image, refId, width, height);
this.relationships.createRelationship(
mediaData.referenceId,
refId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
`media/${mediaData.fileName}`,
);
return mediaData;
}
public createImage(image: Buffer, width?: number, height?: number): void {
let mediaData = this.addImageRelation(image, this.relationships.RelationshipCount, width, height);
this.addImage(new Image(new ImageParagraph(mediaData)));
}
public addImage(image: Image): FooterWrapper {
this.footer.addParagraph(image.Paragraph);
return this;

View File

@ -7,8 +7,8 @@ import { FooterAttributes } from "./footer-attributes";
export class Footer extends XmlComponent {
private readonly refId: number;
constructor(referenceNumber: number) {
super("w:ftr");
constructor(referenceNumber: number, initContent? : XmlComponent) {
super("w:ftr", initContent);
this.refId = referenceNumber;
this.root.push(
new FooterAttributes({

View File

@ -4,13 +4,16 @@ import { Image, Media } from "./media";
import { ImageParagraph, Paragraph } from "./paragraph";
import { Relationships } from "./relationships";
import { Table } from "./table";
import { IMediaData } from 'file/media';
export class HeaderWrapper {
private readonly header: Header;
private readonly relationships: Relationships;
public readonly media = new Media();
constructor(private readonly media: Media, referenceId: number, initContent? : XmlComponent) {
// constructor(private readonly media: Media, referenceId: number, initContent? : XmlComponent) {
constructor(referenceId: number, initContent? : XmlComponent) {
this.header = new Header(referenceId, initContent);
this.relationships = new Relationships();
}
@ -37,13 +40,18 @@ export class HeaderWrapper {
this.header.addChildElement(childElement);
}
public createImage(image: Buffer, width?: number, height?: number): void {
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height);
public addImageRelation(image: Buffer, refId : number, width?: number, height?: number) : IMediaData {
const mediaData = this.media.addMedia(image, refId, width, height);
this.relationships.createRelationship(
mediaData.referenceId,
refId,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
`media/${mediaData.fileName}`,
);
return mediaData;
}
public createImage(image: Buffer, width?: number, height?: number): void {
let mediaData = this.addImageRelation(image, this.relationships.RelationshipCount, width, height);
this.addImage(new Image(new ImageParagraph(mediaData)));
}

View File

@ -23,6 +23,17 @@ export interface IHeaderAttributesProperties {
dcmitype?: string;
xsi?: string;
type?: string;
cx? : string,
cx1? : string,
cx2? : string,
cx3? : string,
cx4? : string,
cx5? : string,
cx6? : string,
cx7? : string,
cx8? : string,
w16cid: string,
w16se: string
}
export class HeaderAttributes extends XmlAttributeComponent<IHeaderAttributesProperties> {
@ -49,5 +60,16 @@ export class HeaderAttributes extends XmlAttributeComponent<IHeaderAttributesPro
dcmitype: "xmlns:dcmitype",
xsi: "xmlns:xsi",
type: "xsi:type",
cx : "xmlns:cx",
cx1: "xmlns:cx1",
cx2: "xmlns:cx2",
cx3: "xmlns:cx3",
cx4: "xmlns:cx4",
cx5: "xmlns:cx5",
cx6: "xmlns:cx6",
cx7: "xmlns:cx7",
cx8: "xmlns:cx8",
w16cid: "xmlns:w16cid",
w16se: "xmlns:w16se"
};
}

View File

@ -7,7 +7,7 @@ import { HeaderAttributes } from "./header-attributes";
export class Header extends XmlComponent {
private readonly refId: number;
constructor(referenceNumber: number, initContent? : XmlComponent) {
constructor(referenceNumber: number, initContent?: XmlComponent) {
super("w:hdr", initContent);
this.refId = referenceNumber;
@ -30,6 +30,17 @@ export class Header extends XmlComponent {
wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
wne: "http://schemas.microsoft.com/office/word/2006/wordml",
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
cx: "http://schemas.microsoft.com/office/drawing/2014/chartex",
cx1: "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex",
cx2: "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex",
cx3: "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex",
cx4: "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex",
cx5: "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex",
cx6: "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex",
cx7: "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex",
cx8: "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex",
w16cid: "http://schemas.microsoft.com/office/word/2016/wordml/cid",
w16se: "http://schemas.microsoft.com/office/word/2015/wordml/symex"
}),
);
}

View File

@ -7,6 +7,8 @@ export const parseOptions = {
ignoreAttributes: false,
attributeNamePrefix: "",
attrNodeName: "_attr",
textNodeName: '',
trimValues: false
};
/**
@ -57,6 +59,7 @@ export class ImportedXmlComponent extends XmlComponent {
private _attr: any;
constructor(rootKey: string, _attr?: any) {
super(rootKey);
if (_attr) {
this._attr = _attr;

View File

@ -8,12 +8,6 @@ export abstract class XmlComponent extends BaseXmlComponent {
constructor(rootKey: string, initContent? : XmlComponent) {
super(rootKey);
this.root = initContent ? initContent.root : new Array<BaseXmlComponent>();
if (initContent) {
console.log('\n\n-------\n\n');
console.log('new root', JSON.stringify(initContent, null,2));
console.log('\n\n-------\n\n');
}
}
public prepForXml(): IXmlableObject {
@ -30,7 +24,7 @@ export abstract class XmlComponent extends BaseXmlComponent {
}
return comp;
})
.filter((comp) => comp); // Exclude null, undefined, and empty strings
.filter((comp) => comp !== null); // Exclude null, undefined, and empty strings
return {
[this.rootKey]: children,
};