diff --git a/demo/demo8.js b/demo/demo8.js index e849ae3f11..cb447b299b 100644 --- a/demo/demo8.js +++ b/demo/demo8.js @@ -2,12 +2,27 @@ const docx = require('../build'); var doc = new docx.Document(); -doc.createParagraph("Hello World"); +doc.createParagraph("First Page").pageBreak() +doc.createParagraph("Second Page"); + + +var pageoneheader = new docx.Paragraph("Running head: My Title").right() +//var tab = new docx.TextRun().tab() +var pageNumber = new docx.TextRun().pageNumber() + +//pageoneheader.addRun(tab); +pageoneheader.addRun(pageNumber); +doc.Header2.addParagraph(pageoneheader); + +var pagetwoheader = new docx.Paragraph("My Title").maxRightTabStop(); + +//pagetwoheader.addRun(tab) +pagetwoheader.addRun(pageNumber) +doc.Header.addParagraph(pagetwoheader) +doc.Header = new docx.Paragraph("My Title") -doc.Header.createParagraph("Header text"); -doc.Footer.createParagraph("Footer text"); var exporter = new docx.LocalPacker(doc); -exporter.pack('My Document'); +exporter.pack('Testing'); console.log('Document created successfully at project root!'); diff --git a/src/export/packer/compiler.ts b/src/export/packer/compiler.ts index 44c7817249..58e97f5eed 100644 --- a/src/export/packer/compiler.ts +++ b/src/export/packer/compiler.ts @@ -34,12 +34,16 @@ export class Compiler { const xmlRelationships = xml(this.formatter.format(this.file.DocumentRelationships)); const xmlFileRelationships = xml(this.formatter.format(this.file.FileRelationships)); const xmlHeader = xml(this.formatter.format(this.file.Header.Header)); + + const xmlHeader2 = xml(this.formatter.format(this.file.Header2.Header)); + const xmlFooter = xml(this.formatter.format(this.file.Footer.Footer)); const xmlHeaderRelationships = xml(this.formatter.format(this.file.Header.Relationships)); const xmlFooterRelationships = xml(this.formatter.format(this.file.Footer.Relationships)); const xmlContentTypes = xml(this.formatter.format(this.file.ContentTypes)); const xmlAppProperties = xml(this.formatter.format(this.file.AppProperties)); + this.archive.append(xmlDocument, { name: "word/document.xml", }); @@ -64,6 +68,14 @@ export class Compiler { name: "word/header1.xml", }); + + + this.archive.append(xmlHeader2, { + name: "word/header2.xml", + }); + + + this.archive.append(xmlFooter, { name: "word/footer1.xml", }); diff --git a/src/file/content-types/content-types.ts b/src/file/content-types/content-types.ts index 4ce020a918..64c9db3113 100644 --- a/src/file/content-types/content-types.ts +++ b/src/file/content-types/content-types.ts @@ -24,7 +24,9 @@ export class ContentTypes extends XmlComponent { this.root.push( new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", "/word/document.xml"), ); + this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", "/word/header1.xml")); + this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", "/word/header2.xml")); this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", "/word/footer1.xml")); this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", "/word/styles.xml")); this.root.push(new Override("application/vnd.openxmlformats-package.core-properties+xml", "/docProps/core.xml")); diff --git a/src/file/document/body/section-properties/header-reference/header-reference.ts b/src/file/document/body/section-properties/header-reference/header-reference.ts index 3809047bef..53d75ede28 100644 --- a/src/file/document/body/section-properties/header-reference/header-reference.ts +++ b/src/file/document/body/section-properties/header-reference/header-reference.ts @@ -2,12 +2,12 @@ import { XmlComponent } from "file/xml-components"; import { HeaderReferenceAttributes } from "./header-reference-attributes"; export class HeaderReference extends XmlComponent { - constructor() { + constructor(order, ref_id) { super("w:headerReference"); this.root.push( new HeaderReferenceAttributes({ - type: "default", - id: `rId${3}`, + type: order, + id: `rId${ref_id}`, }), ); } diff --git a/src/file/document/body/section-properties/section-properties.ts b/src/file/document/body/section-properties/section-properties.ts index 27d3f0bd99..5c06ee8631 100644 --- a/src/file/document/body/section-properties/section-properties.ts +++ b/src/file/document/body/section-properties/section-properties.ts @@ -10,6 +10,7 @@ import { PageMargin } from "./page-margin/page-margin"; import { IPageMarginAttributes } from "./page-margin/page-margin-attributes"; import { PageSize } from "./page-size/page-size"; import { IPageSizeAttributes } from "./page-size/page-size-attributes"; +import { TitlePage } from "./titlepage/titlepage"; export type SectionPropertiesOptions = IPageSizeAttributes & IPageMarginAttributes & IColumnsAttributes & IDocGridAttributesProperties; @@ -51,7 +52,9 @@ export class SectionProperties extends XmlComponent { ); this.root.push(new Columns(mergedOptions.space)); this.root.push(new DocumentGrid(mergedOptions.linePitch)); - this.root.push(new HeaderReference()); + this.root.push(new HeaderReference("default",3)); + this.root.push(new HeaderReference("first",5)); + this.root.push(new TitlePage()); this.root.push(new FooterReference()); } } diff --git a/src/file/document/body/section-properties/titlepage/titlepage-attributes.ts b/src/file/document/body/section-properties/titlepage/titlepage-attributes.ts new file mode 100644 index 0000000000..960064ec1f --- /dev/null +++ b/src/file/document/body/section-properties/titlepage/titlepage-attributes.ts @@ -0,0 +1,11 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IHeaderReferenceAttributes { + value: string; +} + +export class TitlePageAttributes extends XmlAttributeComponent { + protected xmlKeys = { + value: "w:val", + }; +} \ No newline at end of file diff --git a/src/file/document/body/section-properties/titlepage/titlepage.ts b/src/file/document/body/section-properties/titlepage/titlepage.ts new file mode 100644 index 0000000000..361cc039fa --- /dev/null +++ b/src/file/document/body/section-properties/titlepage/titlepage.ts @@ -0,0 +1,13 @@ +import { XmlComponent } from "file/xml-components"; +import { TitlePageAttributes } from "./titlepage-attributes"; + +export class TitlePage extends XmlComponent { + constructor() { + super("w:titlePg"); + this.root.push( + new TitlePageAttributes({ + value: "1", + }), + ); + } +} \ No newline at end of file diff --git a/src/file/file.ts b/src/file/file.ts index 39a9e3d210..89e752e770 100644 --- a/src/file/file.ts +++ b/src/file/file.ts @@ -5,6 +5,9 @@ import { Document } from "./document"; import { SectionPropertiesOptions } from "./document/body/section-properties/section-properties"; import { FooterWrapper } from "./footer-wrapper"; import { HeaderWrapper } from "./header-wrapper"; + +import { HeaderWrapper2 } from "./header-wrapper2"; + import { Media } from "./media"; import { Numbering } from "./numbering"; import { Hyperlink, Paragraph, PictureRun } from "./paragraph"; @@ -22,6 +25,9 @@ export class File { private readonly docRelationships: Relationships; private readonly fileRelationships: Relationships; private readonly headerWrapper: HeaderWrapper; + + private readonly headerWrapper2: HeaderWrapper2; + private readonly footerWrapper: FooterWrapper; private readonly contentTypes: ContentTypes; private readonly appProperties: AppProperties; @@ -57,13 +63,23 @@ export class File { "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header", "header1.xml", ); + + this.docRelationships.createRelationship( + 5, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header", + "header2.xml", + ); + this.docRelationships.createRelationship( 4, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer", "footer1.xml", ); this.media = new Media(); + this.headerWrapper = new HeaderWrapper(this.media); + this.headerWrapper2 = new HeaderWrapper2(this.media); + this.footerWrapper = new FooterWrapper(this.media); this.contentTypes = new ContentTypes(); this.fileRelationships = new Relationships(); @@ -155,6 +171,11 @@ export class File { return this.headerWrapper; } + public get Header2(): HeaderWrapper2 { + return this.headerWrapper2; + } + + public get Footer(): FooterWrapper { return this.footerWrapper; } diff --git a/src/file/header-wrapper2.ts b/src/file/header-wrapper2.ts new file mode 100644 index 0000000000..7663842727 --- /dev/null +++ b/src/file/header-wrapper2.ts @@ -0,0 +1,55 @@ +import { Header2 } from "./header2/header"; +import { IMediaData, Media } from "./media"; +import { Paragraph } from "./paragraph"; +import { Relationships } from "./relationships"; +import { Table } from "./table"; + +export class HeaderWrapper2 { + private readonly header: Header2; + private readonly relationships: Relationships; + + constructor(private readonly media: Media) { + this.header = new Header2(); + this.relationships = new Relationships(); + } + + public addParagraph(paragraph: Paragraph): void { + this.header.addParagraph(paragraph); + } + + public createParagraph(text?: string): Paragraph { + const para = new Paragraph(text); + this.addParagraph(para); + return para; + } + + public addTable(table: Table): void { + this.header.addTable(table); + } + + public createTable(rows: number, cols: number): Table { + return this.header.createTable(rows, cols); + } + + public addDrawing(imageData: IMediaData): void { + this.header.addDrawing(imageData); + } + + public createImage(image: string): void { + const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount); + this.relationships.createRelationship( + mediaData.referenceId, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + `media/${mediaData.fileName}`, + ); + this.addDrawing(mediaData); + } + + public get Header(): Header2 { + return this.header; + } + + public get Relationships(): Relationships { + return this.relationships; + } +} diff --git a/src/file/header2/header-attributes.ts b/src/file/header2/header-attributes.ts new file mode 100644 index 0000000000..e47271841c --- /dev/null +++ b/src/file/header2/header-attributes.ts @@ -0,0 +1,53 @@ +import { XmlAttributeComponent } from "file/xml-components"; + +export interface IHeaderAttributesProperties { + 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; + cp?: string; + dc?: string; + dcterms?: string; + dcmitype?: string; + xsi?: string; + type?: string; +} + +export class HeaderAttributes extends XmlAttributeComponent { + 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", + cp: "xmlns:cp", + dc: "xmlns:dc", + dcterms: "xmlns:dcterms", + dcmitype: "xmlns:dcmitype", + xsi: "xmlns:xsi", + type: "xsi:type", + }; +} diff --git a/src/file/header2/header.ts b/src/file/header2/header.ts new file mode 100644 index 0000000000..fb34ff13ac --- /dev/null +++ b/src/file/header2/header.ts @@ -0,0 +1,60 @@ +// http://officeopenxml.com/WPheaders.php +import { IMediaData } from "file/media"; +import { XmlComponent } from "file/xml-components"; +import { Paragraph, PictureRun } from "../paragraph"; +import { Table } from "../table"; +import { HeaderAttributes } from "./header-attributes"; + +export class Header2 extends XmlComponent { + constructor() { + super("w:hdr"); + this.root.push( + new HeaderAttributes({ + wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas", + mc: "http://schemas.openxmlformats.org/markup-compatibility/2006", + o: "urn:schemas-microsoft-com:office:office", + r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + m: "http://schemas.openxmlformats.org/officeDocument/2006/math", + v: "urn:schemas-microsoft-com:vml", + wp14: "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", + wp: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + w10: "urn:schemas-microsoft-com:office:word", + w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + w14: "http://schemas.microsoft.com/office/word/2010/wordml", + w15: "http://schemas.microsoft.com/office/word/2012/wordml", + wpg: "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", + 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", + }), + ); + } + + public addParagraph(paragraph: Paragraph): void { + this.root.push(paragraph); + } + + public createParagraph(text?: string): Paragraph { + const para = new Paragraph(text); + this.addParagraph(para); + return para; + } + + public addTable(table: Table): void { + this.root.push(table); + } + + public createTable(rows: number, cols: number): Table { + const table = new Table(rows, cols); + this.addTable(table); + return table; + } + + public addDrawing(imageData: IMediaData): void { + const paragraph = new Paragraph(); + const run = new PictureRun(imageData); + paragraph.addRun(run); + + this.root.push(paragraph); + } +} diff --git a/src/file/header2/index.ts b/src/file/header2/index.ts new file mode 100644 index 0000000000..49ac70fe21 --- /dev/null +++ b/src/file/header2/index.ts @@ -0,0 +1 @@ +export * from "./header"; diff --git a/src/file/paragraph/run/pagenumber.ts b/src/file/paragraph/run/pagenumber.ts new file mode 100644 index 0000000000..20dc8f061a --- /dev/null +++ b/src/file/paragraph/run/pagenumber.ts @@ -0,0 +1,38 @@ +import { XmlAttributeComponent, XmlComponent } from "file/xml-components"; + +class fidCharAttrs extends XmlAttributeComponent<{ type: "begin" | "end" | "separate" }> { + protected xmlKeys = { type: "w:fldCharType" }; +} + +class TextAttributes extends XmlAttributeComponent<{ space: "default" | "preserve" }> { + protected xmlKeys = { space: "xml:space" }; +} + +export class Begin extends XmlComponent { + constructor() { + super("w:fldChar"); + this.root.push(new fidCharAttrs({ type: "begin" })); + } +} + +export class Page extends XmlComponent { + constructor() { + super("w:instrText"); + this.root.push(new TextAttributes({ space: "preserve" })); + this.root.push("PAGE"); + } +} + +export class Separate extends XmlComponent { + constructor() { + super("w:fldChar"); + this.root.push(new fidCharAttrs({ type: "separate" })); + } +} + +export class End extends XmlComponent { + constructor() { + super("w:fldChar"); + this.root.push(new fidCharAttrs({ type: "end" })); + } +} \ No newline at end of file diff --git a/src/file/paragraph/run/run.ts b/src/file/paragraph/run/run.ts index 243cea68d3..508aad9afa 100644 --- a/src/file/paragraph/run/run.ts +++ b/src/file/paragraph/run/run.ts @@ -8,6 +8,7 @@ import { SubScript, SuperScript } from "./script"; import { Style } from "./style"; import { Tab } from "./tab"; import { Underline } from "./underline"; +import { Begin, Page, End, Separate } from "./pagenumber"; import { XmlComponent } from "file/xml-components"; @@ -55,6 +56,14 @@ export class Run extends XmlComponent { return this; } + public pageNumber(): Run { + this.root.push(new Begin()); + this.root.push(new Page()); + this.root.push(new Separate()); + this.root.push(new End()); + return this; + } + public smallCaps(): Run { this.properties.push(new SmallCaps()); return this;