Add lifecycles to add image
This commit is contained in:
@ -36,6 +36,10 @@ export class Compiler {
|
|||||||
public async compile(file: File): Promise<JSZip> {
|
public async compile(file: File): Promise<JSZip> {
|
||||||
const zip = new JSZip();
|
const zip = new JSZip();
|
||||||
|
|
||||||
|
// Run precompile steps
|
||||||
|
file.onCompile();
|
||||||
|
file.Headers.forEach((header) => header.onCompile());
|
||||||
|
|
||||||
const xmlifiedFileMapping = this.xmlifyFile(file);
|
const xmlifiedFileMapping = this.xmlifyFile(file);
|
||||||
|
|
||||||
for (const key in xmlifiedFileMapping) {
|
for (const key in xmlifiedFileMapping) {
|
||||||
|
@ -13,10 +13,12 @@ import { IFileProperties } from "./file-properties";
|
|||||||
import { FooterWrapper, IDocumentFooter } from "./footer-wrapper";
|
import { FooterWrapper, IDocumentFooter } from "./footer-wrapper";
|
||||||
import { FootNotes } from "./footnotes";
|
import { FootNotes } from "./footnotes";
|
||||||
import { HeaderWrapper, IDocumentHeader } from "./header-wrapper";
|
import { HeaderWrapper, IDocumentHeader } from "./header-wrapper";
|
||||||
|
import { IOnCompile } from "./life-cycles";
|
||||||
import { Image, Media } from "./media";
|
import { Image, Media } from "./media";
|
||||||
import { Numbering } from "./numbering";
|
import { Numbering } from "./numbering";
|
||||||
import { Bookmark, Hyperlink, Paragraph } from "./paragraph";
|
import { Bookmark, Hyperlink, Paragraph } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
|
import { TargetModeType } from "./relationships/relationship/relationship";
|
||||||
import { Settings } from "./settings";
|
import { Settings } from "./settings";
|
||||||
import { Styles } from "./styles";
|
import { Styles } from "./styles";
|
||||||
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
||||||
@ -24,7 +26,7 @@ import { DefaultStylesFactory } from "./styles/factory";
|
|||||||
import { Table } from "./table";
|
import { Table } from "./table";
|
||||||
import { TableOfContents } from "./table-of-contents";
|
import { TableOfContents } from "./table-of-contents";
|
||||||
|
|
||||||
export class File {
|
export class File implements IOnCompile {
|
||||||
// tslint:disable-next-line:readonly-keyword
|
// tslint:disable-next-line:readonly-keyword
|
||||||
private currentRelationshipId: number = 1;
|
private currentRelationshipId: number = 1;
|
||||||
|
|
||||||
@ -147,7 +149,7 @@ export class File {
|
|||||||
hyperlink.linkId,
|
hyperlink.linkId,
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
||||||
link,
|
link,
|
||||||
"External",
|
TargetModeType.EXTERNAL,
|
||||||
);
|
);
|
||||||
return hyperlink;
|
return hyperlink;
|
||||||
}
|
}
|
||||||
@ -221,6 +223,11 @@ export class File {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onCompile(): void {
|
||||||
|
// this.media.Array.forEach((media) => {
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
private addHeaderToDocument(header: HeaderWrapper, type: HeaderReferenceType = HeaderReferenceType.DEFAULT): void {
|
private addHeaderToDocument(header: HeaderWrapper, type: HeaderReferenceType = HeaderReferenceType.DEFAULT): void {
|
||||||
this.headers.push({ header, type });
|
this.headers.push({ header, type });
|
||||||
this.docRelationships.createRelationship(
|
this.docRelationships.createRelationship(
|
||||||
|
@ -2,7 +2,8 @@ import { XmlComponent } from "file/xml-components";
|
|||||||
|
|
||||||
import { FooterReferenceType } from "./document";
|
import { FooterReferenceType } from "./document";
|
||||||
import { Footer } from "./footer/footer";
|
import { Footer } from "./footer/footer";
|
||||||
import { Image, IMediaData, Media } from "./media";
|
import { IOnCompile } from "./life-cycles";
|
||||||
|
import { Image, Media } from "./media";
|
||||||
import { ImageParagraph, Paragraph } from "./paragraph";
|
import { ImageParagraph, Paragraph } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
import { Table } from "./table";
|
import { Table } from "./table";
|
||||||
@ -12,7 +13,7 @@ export interface IDocumentFooter {
|
|||||||
readonly type: FooterReferenceType;
|
readonly type: FooterReferenceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FooterWrapper {
|
export class FooterWrapper implements IOnCompile {
|
||||||
private readonly footer: Footer;
|
private readonly footer: Footer;
|
||||||
private readonly relationships: Relationships;
|
private readonly relationships: Relationships;
|
||||||
|
|
||||||
@ -43,29 +44,8 @@ export class FooterWrapper {
|
|||||||
this.footer.addChildElement(childElement);
|
this.footer.addChildElement(childElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addImageRelationship(image: Buffer, refId: number, width?: number, height?: number): IMediaData {
|
|
||||||
const mediaData = this.media.addMedia(image, refId, width, height);
|
|
||||||
this.relationships.createRelationship(
|
|
||||||
mediaData.referenceId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
||||||
`media/${mediaData.fileName}`,
|
|
||||||
);
|
|
||||||
return mediaData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addHyperlinkRelationship(target: string, refId: number, targetMode?: "External" | undefined): void {
|
|
||||||
this.relationships.createRelationship(
|
|
||||||
refId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
|
||||||
target,
|
|
||||||
targetMode,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public createImage(image: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): void {
|
public createImage(image: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): void {
|
||||||
// TODO
|
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height);
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
const mediaData = this.addImageRelationship(image as any, this.relationships.RelationshipCount, width, height);
|
|
||||||
this.addImage(new Image(new ImageParagraph(mediaData)));
|
this.addImage(new Image(new ImageParagraph(mediaData)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +54,16 @@ export class FooterWrapper {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onCompile(): void {
|
||||||
|
this.media.Array.forEach((mediaData) => {
|
||||||
|
this.relationships.createRelationship(
|
||||||
|
mediaData.referenceId,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||||
|
`media/${mediaData.fileName}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public get Footer(): Footer {
|
public get Footer(): Footer {
|
||||||
return this.footer;
|
return this.footer;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ import { XmlComponent } from "file/xml-components";
|
|||||||
|
|
||||||
import { HeaderReferenceType } from "./document";
|
import { HeaderReferenceType } from "./document";
|
||||||
import { Header } from "./header/header";
|
import { Header } from "./header/header";
|
||||||
import { Image, IMediaData, Media } from "./media";
|
import { IOnCompile } from "./life-cycles";
|
||||||
|
import { Image, Media } from "./media";
|
||||||
import { ImageParagraph, Paragraph } from "./paragraph";
|
import { ImageParagraph, Paragraph } from "./paragraph";
|
||||||
import { Relationships } from "./relationships";
|
import { Relationships } from "./relationships";
|
||||||
import { Table } from "./table";
|
import { Table } from "./table";
|
||||||
@ -12,7 +13,7 @@ export interface IDocumentHeader {
|
|||||||
readonly type: HeaderReferenceType;
|
readonly type: HeaderReferenceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HeaderWrapper {
|
export class HeaderWrapper implements IOnCompile {
|
||||||
private readonly header: Header;
|
private readonly header: Header;
|
||||||
private readonly relationships: Relationships;
|
private readonly relationships: Relationships;
|
||||||
|
|
||||||
@ -43,29 +44,8 @@ export class HeaderWrapper {
|
|||||||
this.header.addChildElement(childElement);
|
this.header.addChildElement(childElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public addImageRelationship(image: Buffer, refId: number, width?: number, height?: number): IMediaData {
|
|
||||||
const mediaData = this.media.addMedia(image, refId, width, height);
|
|
||||||
this.relationships.createRelationship(
|
|
||||||
mediaData.referenceId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
||||||
`media/${mediaData.fileName}`,
|
|
||||||
);
|
|
||||||
return mediaData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addHyperlinkRelationship(target: string, refId: number, targetMode?: "External" | undefined): void {
|
|
||||||
this.relationships.createRelationship(
|
|
||||||
refId,
|
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
|
||||||
target,
|
|
||||||
targetMode,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public createImage(image: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): void {
|
public createImage(image: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): void {
|
||||||
// TODO
|
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height);
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
const mediaData = this.addImageRelationship(image as any, this.relationships.RelationshipCount, width, height);
|
|
||||||
this.addImage(new Image(new ImageParagraph(mediaData)));
|
this.addImage(new Image(new ImageParagraph(mediaData)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +54,16 @@ export class HeaderWrapper {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onCompile(): void {
|
||||||
|
this.media.Array.forEach((mediaData) => {
|
||||||
|
this.relationships.createRelationship(
|
||||||
|
mediaData.referenceId,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||||
|
`media/${mediaData.fileName}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public get Header(): Header {
|
public get Header(): Header {
|
||||||
return this.header;
|
return this.header;
|
||||||
}
|
}
|
||||||
|
9
src/file/life-cycles.ts
Normal file
9
src/file/life-cycles.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export interface IOnCompile {
|
||||||
|
readonly onCompile: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432
|
||||||
|
/**
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
export const WORKAROUND4 = "";
|
@ -17,7 +17,9 @@ export type RelationshipType =
|
|||||||
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
|
||||||
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
|
| "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
|
||||||
|
|
||||||
export type TargetModeType = "External";
|
export enum TargetModeType {
|
||||||
|
EXTERNAL = "External",
|
||||||
|
}
|
||||||
|
|
||||||
export class Relationship extends XmlComponent {
|
export class Relationship extends XmlComponent {
|
||||||
constructor(id: string, type: RelationshipType, target: string, targetMode?: TargetModeType) {
|
constructor(id: string, type: RelationshipType, target: string, targetMode?: TargetModeType) {
|
||||||
|
@ -5,11 +5,11 @@ import { FooterReferenceType } from "file/document/body/section-properties/foote
|
|||||||
import { HeaderReferenceType } from "file/document/body/section-properties/header-reference";
|
import { HeaderReferenceType } from "file/document/body/section-properties/header-reference";
|
||||||
import { FooterWrapper, IDocumentFooter } from "file/footer-wrapper";
|
import { FooterWrapper, IDocumentFooter } from "file/footer-wrapper";
|
||||||
import { HeaderWrapper, IDocumentHeader } from "file/header-wrapper";
|
import { HeaderWrapper, IDocumentHeader } from "file/header-wrapper";
|
||||||
import { convertToXmlComponent, ImportedXmlComponent } from "file/xml-components";
|
|
||||||
|
|
||||||
import { Media } from "file/media";
|
import { Media } from "file/media";
|
||||||
|
import { TargetModeType } from "file/relationships/relationship/relationship";
|
||||||
import { Styles } from "file/styles";
|
import { Styles } from "file/styles";
|
||||||
import { ExternalStylesFactory } from "file/styles/external-styles-factory";
|
import { ExternalStylesFactory } from "file/styles/external-styles-factory";
|
||||||
|
import { convertToXmlComponent, ImportedXmlComponent } from "file/xml-components";
|
||||||
|
|
||||||
const schemeToType = {
|
const schemeToType = {
|
||||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header": "header",
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header": "header",
|
||||||
@ -23,10 +23,17 @@ interface IDocumentRefs {
|
|||||||
readonly footers: Array<{ readonly id: number; readonly type: FooterReferenceType }>;
|
readonly footers: Array<{ readonly id: number; readonly type: FooterReferenceType }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum RelationshipType {
|
||||||
|
HEADER = "header",
|
||||||
|
FOOTER = "footer",
|
||||||
|
IMAGE = "image",
|
||||||
|
HYPERLINK = "hyperlink",
|
||||||
|
}
|
||||||
|
|
||||||
interface IRelationshipFileInfo {
|
interface IRelationshipFileInfo {
|
||||||
readonly id: number;
|
readonly id: number;
|
||||||
readonly target: string;
|
readonly target: string;
|
||||||
readonly type: "header" | "footer" | "image" | "hyperlink";
|
readonly type: RelationshipType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Document Template
|
// Document Template
|
||||||
@ -83,7 +90,7 @@ export class ImportDotx {
|
|||||||
}
|
}
|
||||||
const importedComp = convertToXmlComponent(headerXmlElement) as ImportedXmlComponent;
|
const importedComp = convertToXmlComponent(headerXmlElement) as ImportedXmlComponent;
|
||||||
const header = new HeaderWrapper(media, this.currentRelationshipId++, importedComp);
|
const header = new HeaderWrapper(media, this.currentRelationshipId++, importedComp);
|
||||||
await this.addRelationToWrapper(relationFileInfo, zipContent, header);
|
await this.addRelationshipToWrapper(relationFileInfo, zipContent, header, media);
|
||||||
headers.push({ type: headerRef.type, header });
|
headers.push({ type: headerRef.type, header });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +113,7 @@ export class ImportDotx {
|
|||||||
}
|
}
|
||||||
const importedComp = convertToXmlComponent(footerXmlElement) as ImportedXmlComponent;
|
const importedComp = convertToXmlComponent(footerXmlElement) as ImportedXmlComponent;
|
||||||
const footer = new FooterWrapper(media, this.currentRelationshipId++, importedComp);
|
const footer = new FooterWrapper(media, this.currentRelationshipId++, importedComp);
|
||||||
await this.addRelationToWrapper(relationFileInfo, zipContent, footer);
|
await this.addRelationshipToWrapper(relationFileInfo, zipContent, footer, media);
|
||||||
footers.push({ type: footerRef.type, footer });
|
footers.push({ type: footerRef.type, footer });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,29 +127,43 @@ export class ImportDotx {
|
|||||||
return templateDocument;
|
return templateDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async addRelationToWrapper(
|
private async addRelationshipToWrapper(
|
||||||
relationhipFile: IRelationshipFileInfo,
|
relationhipFile: IRelationshipFileInfo,
|
||||||
zipContent: JSZip,
|
zipContent: JSZip,
|
||||||
wrapper: HeaderWrapper | FooterWrapper,
|
wrapper: HeaderWrapper | FooterWrapper,
|
||||||
|
media: Media,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let wrapperImagesReferences: IRelationshipFileInfo[] = [];
|
|
||||||
let hyperLinkReferences: IRelationshipFileInfo[] = [];
|
|
||||||
const refFile = zipContent.files[`word/_rels/${relationhipFile.target}.rels`];
|
const refFile = zipContent.files[`word/_rels/${relationhipFile.target}.rels`];
|
||||||
if (refFile) {
|
|
||||||
const xmlRef = await refFile.async("text");
|
if (!refFile) {
|
||||||
wrapperImagesReferences = this.findReferenceFiles(xmlRef).filter((r) => r.type === "image");
|
return;
|
||||||
hyperLinkReferences = this.findReferenceFiles(xmlRef).filter((r) => r.type === "hyperlink");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const xmlRef = await refFile.async("text");
|
||||||
|
const wrapperImagesReferences = this.findReferenceFiles(xmlRef).filter((r) => r.type === RelationshipType.IMAGE);
|
||||||
|
const hyperLinkReferences = this.findReferenceFiles(xmlRef).filter((r) => r.type === RelationshipType.HYPERLINK);
|
||||||
|
|
||||||
for (const r of wrapperImagesReferences) {
|
for (const r of wrapperImagesReferences) {
|
||||||
const buffer = await zipContent.files[`word/${r.target}`].async("nodebuffer");
|
const buffer = await zipContent.files[`word/${r.target}`].async("nodebuffer");
|
||||||
wrapper.addImageRelationship(buffer, r.id);
|
const mediaData = media.addMedia(buffer, r.id);
|
||||||
|
wrapper.Relationships.createRelationship(
|
||||||
|
mediaData.referenceId,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||||
|
`media/${mediaData.fileName}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const r of hyperLinkReferences) {
|
for (const r of hyperLinkReferences) {
|
||||||
wrapper.addHyperlinkRelationship(r.target, r.id, "External");
|
wrapper.Relationships.createRelationship(
|
||||||
|
r.id,
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
||||||
|
r.target,
|
||||||
|
TargetModeType.EXTERNAL,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public findReferenceFiles(xmlData: string): IRelationshipFileInfo[] {
|
private findReferenceFiles(xmlData: string): IRelationshipFileInfo[] {
|
||||||
const xmlObj = xml2js(xmlData, { compact: true }) as XMLElementCompact;
|
const xmlObj = xml2js(xmlData, { compact: true }) as XMLElementCompact;
|
||||||
const relationXmlArray = Array.isArray(xmlObj.Relationships.Relationship)
|
const relationXmlArray = Array.isArray(xmlObj.Relationships.Relationship)
|
||||||
? xmlObj.Relationships.Relationship
|
? xmlObj.Relationships.Relationship
|
||||||
@ -162,7 +183,7 @@ export class ImportDotx {
|
|||||||
return relationships;
|
return relationships;
|
||||||
}
|
}
|
||||||
|
|
||||||
public extractDocumentRefs(xmlData: string): IDocumentRefs {
|
private extractDocumentRefs(xmlData: string): IDocumentRefs {
|
||||||
const xmlObj = xml2js(xmlData, { compact: true }) as XMLElementCompact;
|
const xmlObj = xml2js(xmlData, { compact: true }) as XMLElementCompact;
|
||||||
const sectionProp = xmlObj["w:document"]["w:body"]["w:sectPr"];
|
const sectionProp = xmlObj["w:document"]["w:body"]["w:sectPr"];
|
||||||
|
|
||||||
@ -208,13 +229,13 @@ export class ImportDotx {
|
|||||||
return { headers, footers };
|
return { headers, footers };
|
||||||
}
|
}
|
||||||
|
|
||||||
public titlePageIsDefined(xmlData: string): boolean {
|
private titlePageIsDefined(xmlData: string): boolean {
|
||||||
const xmlObj = xml2js(xmlData, { compact: true }) as XMLElementCompact;
|
const xmlObj = xml2js(xmlData, { compact: true }) as XMLElementCompact;
|
||||||
const sectionProp = xmlObj["w:document"]["w:body"]["w:sectPr"];
|
const sectionProp = xmlObj["w:document"]["w:body"]["w:sectPr"];
|
||||||
return sectionProp["w:titlePg"] !== undefined;
|
return sectionProp["w:titlePg"] !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public parseRefId(str: string): number {
|
private parseRefId(str: string): number {
|
||||||
const match = /^rId(\d+)$/.exec(str);
|
const match = /^rId(\d+)$/.exec(str);
|
||||||
if (match === null) {
|
if (match === null) {
|
||||||
throw new Error("Invalid ref id");
|
throw new Error("Invalid ref id");
|
||||||
|
Reference in New Issue
Block a user