Merge branch 'master' into custom-properties
This commit is contained in:
18
src/convenience-functions.spec.ts
Normal file
18
src/convenience-functions.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { expect } from "chai";
|
||||
import { convertInchesToTwip, convertMillimetersToTwip } from "./convenience-functions";
|
||||
|
||||
describe("Utility", () => {
|
||||
describe("#convertMillimetersToTwip", () => {
|
||||
it("should call the underlying header's addChildElement for Paragraph", () => {
|
||||
expect(convertMillimetersToTwip(1000)).to.equal(56692);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#convertInchesToTwip", () => {
|
||||
it("should call the underlying header's addChildElement", () => {
|
||||
expect(convertInchesToTwip(1)).to.equal(1440);
|
||||
expect(convertInchesToTwip(0.5)).to.equal(720);
|
||||
expect(convertInchesToTwip(0.25)).to.equal(360);
|
||||
});
|
||||
});
|
||||
});
|
8
src/convenience-functions.ts
Normal file
8
src/convenience-functions.ts
Normal file
@ -0,0 +1,8 @@
|
||||
// Twip - twentieths of a point
|
||||
export const convertMillimetersToTwip = (millimeters: number): number => {
|
||||
return Math.floor((millimeters / 25.4) * 72 * 20);
|
||||
};
|
||||
|
||||
export const convertInchesToTwip = (inches: number): number => {
|
||||
return Math.floor(inches * 72 * 20);
|
||||
};
|
@ -1,8 +1,8 @@
|
||||
import { IViewWrapper } from "file/document-wrapper";
|
||||
import { BaseXmlComponent, IXmlableObject } from "file/xml-components";
|
||||
import { File } from "../file";
|
||||
|
||||
export class Formatter {
|
||||
public format(input: BaseXmlComponent, file?: File): IXmlableObject {
|
||||
public format(input: BaseXmlComponent, file?: IViewWrapper): IXmlableObject {
|
||||
const output = input.prepForXml(file);
|
||||
|
||||
if (output) {
|
||||
|
@ -70,23 +70,23 @@ export class Compiler {
|
||||
|
||||
private xmlifyFile(file: File, prettify?: boolean): IXmlifyedFileMapping {
|
||||
file.verifyUpdateFields();
|
||||
const documentRelationshipCount = file.DocumentRelationships.RelationshipCount + 1;
|
||||
const documentRelationshipCount = file.Document.Relationships.RelationshipCount + 1;
|
||||
|
||||
const documentXmlData = xml(this.formatter.format(file.Document, file), prettify);
|
||||
const documentXmlData = xml(this.formatter.format(file.Document.View, file.Document), prettify);
|
||||
const documentMediaDatas = this.imageReplacer.getMediaData(documentXmlData, file.Media);
|
||||
|
||||
return {
|
||||
Relationships: {
|
||||
data: (() => {
|
||||
documentMediaDatas.forEach((mediaData, i) => {
|
||||
file.DocumentRelationships.createRelationship(
|
||||
file.Document.Relationships.createRelationship(
|
||||
documentRelationshipCount + i,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||
`media/${mediaData.fileName}`,
|
||||
);
|
||||
});
|
||||
|
||||
return xml(this.formatter.format(file.DocumentRelationships, file), prettify);
|
||||
return xml(this.formatter.format(file.Document.Relationships, file.Document), prettify);
|
||||
})(),
|
||||
path: "word/_rels/document.xml.rels",
|
||||
},
|
||||
@ -100,11 +100,11 @@ export class Compiler {
|
||||
path: "word/document.xml",
|
||||
},
|
||||
Styles: {
|
||||
data: xml(this.formatter.format(file.Styles, file), prettify),
|
||||
data: xml(this.formatter.format(file.Styles, file.Document), prettify),
|
||||
path: "word/styles.xml",
|
||||
},
|
||||
Properties: {
|
||||
data: xml(this.formatter.format(file.CoreProperties, file), {
|
||||
data: xml(this.formatter.format(file.CoreProperties, file.Document), {
|
||||
declaration: {
|
||||
standalone: "yes",
|
||||
encoding: "UTF-8",
|
||||
@ -113,15 +113,15 @@ export class Compiler {
|
||||
path: "docProps/core.xml",
|
||||
},
|
||||
Numbering: {
|
||||
data: xml(this.formatter.format(file.Numbering, file), prettify),
|
||||
data: xml(this.formatter.format(file.Numbering, file.Document), prettify),
|
||||
path: "word/numbering.xml",
|
||||
},
|
||||
FileRelationships: {
|
||||
data: xml(this.formatter.format(file.FileRelationships, file), prettify),
|
||||
data: xml(this.formatter.format(file.FileRelationships, file.Document), prettify),
|
||||
path: "_rels/.rels",
|
||||
},
|
||||
HeaderRelationships: file.Headers.map((headerWrapper, index) => {
|
||||
const xmlData = xml(this.formatter.format(headerWrapper.Header, file), prettify);
|
||||
const xmlData = xml(this.formatter.format(headerWrapper.View, headerWrapper), prettify);
|
||||
const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media);
|
||||
|
||||
mediaDatas.forEach((mediaData, i) => {
|
||||
@ -133,12 +133,12 @@ export class Compiler {
|
||||
});
|
||||
|
||||
return {
|
||||
data: xml(this.formatter.format(headerWrapper.Relationships, file), prettify),
|
||||
data: xml(this.formatter.format(headerWrapper.Relationships, headerWrapper), prettify),
|
||||
path: `word/_rels/header${index + 1}.xml.rels`,
|
||||
};
|
||||
}),
|
||||
FooterRelationships: file.Footers.map((footerWrapper, index) => {
|
||||
const xmlData = xml(this.formatter.format(footerWrapper.Footer, file), prettify);
|
||||
const xmlData = xml(this.formatter.format(footerWrapper.View, footerWrapper), prettify);
|
||||
const mediaDatas = this.imageReplacer.getMediaData(xmlData, file.Media);
|
||||
|
||||
mediaDatas.forEach((mediaData, i) => {
|
||||
@ -150,12 +150,12 @@ export class Compiler {
|
||||
});
|
||||
|
||||
return {
|
||||
data: xml(this.formatter.format(footerWrapper.Relationships, file), prettify),
|
||||
data: xml(this.formatter.format(footerWrapper.Relationships, footerWrapper), prettify),
|
||||
path: `word/_rels/footer${index + 1}.xml.rels`,
|
||||
};
|
||||
}),
|
||||
Headers: file.Headers.map((headerWrapper, index) => {
|
||||
const tempXmlData = xml(this.formatter.format(headerWrapper.Header, file), prettify);
|
||||
const tempXmlData = xml(this.formatter.format(headerWrapper.View, headerWrapper), prettify);
|
||||
const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media);
|
||||
// TODO: 0 needs to be changed when headers get relationships of their own
|
||||
const xmlData = this.imageReplacer.replace(tempXmlData, mediaDatas, 0);
|
||||
@ -166,7 +166,7 @@ export class Compiler {
|
||||
};
|
||||
}),
|
||||
Footers: file.Footers.map((footerWrapper, index) => {
|
||||
const tempXmlData = xml(this.formatter.format(footerWrapper.Footer, file), prettify);
|
||||
const tempXmlData = xml(this.formatter.format(footerWrapper.View, footerWrapper), prettify);
|
||||
const mediaDatas = this.imageReplacer.getMediaData(tempXmlData, file.Media);
|
||||
// TODO: 0 needs to be changed when headers get relationships of their own
|
||||
const xmlData = this.imageReplacer.replace(tempXmlData, mediaDatas, 0);
|
||||
@ -177,7 +177,7 @@ export class Compiler {
|
||||
};
|
||||
}),
|
||||
ContentTypes: {
|
||||
data: xml(this.formatter.format(file.ContentTypes, file), prettify),
|
||||
data: xml(this.formatter.format(file.ContentTypes, file.Document), prettify),
|
||||
path: "[Content_Types].xml",
|
||||
},
|
||||
CustomProperties: {
|
||||
@ -185,15 +185,15 @@ export class Compiler {
|
||||
path: "docProps/custom.xml",
|
||||
},
|
||||
AppProperties: {
|
||||
data: xml(this.formatter.format(file.AppProperties, file), prettify),
|
||||
data: xml(this.formatter.format(file.AppProperties, file.Document), prettify),
|
||||
path: "docProps/app.xml",
|
||||
},
|
||||
FootNotes: {
|
||||
data: xml(this.formatter.format(file.FootNotes, file), prettify),
|
||||
data: xml(this.formatter.format(file.FootNotes, file.Document), prettify),
|
||||
path: "word/footnotes.xml",
|
||||
},
|
||||
Settings: {
|
||||
data: xml(this.formatter.format(file.Settings, file), prettify),
|
||||
data: xml(this.formatter.format(file.Settings, file.Document), prettify),
|
||||
path: "word/settings.xml",
|
||||
},
|
||||
};
|
||||
|
@ -1,22 +1,12 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { IDocumentBackgroundOptions } from "../document";
|
||||
|
||||
import { DocumentAttributes } from "../document/document-attributes";
|
||||
import { INumberingOptions } from "../numbering";
|
||||
import { HyperlinkType, Paragraph } from "../paragraph";
|
||||
import { Paragraph } from "../paragraph";
|
||||
import { IStylesOptions } from "../styles";
|
||||
import { Created, Creator, Description, Keywords, LastModifiedBy, Modified, Revision, Subject, Title } from "./components";
|
||||
|
||||
export interface IInternalHyperlinkDefinition {
|
||||
readonly text: string;
|
||||
readonly type: HyperlinkType.INTERNAL;
|
||||
}
|
||||
|
||||
export interface IExternalHyperlinkDefinition {
|
||||
readonly link: string;
|
||||
readonly text: string;
|
||||
readonly type: HyperlinkType.EXTERNAL;
|
||||
}
|
||||
|
||||
export interface IPropertiesOptions {
|
||||
readonly title?: string;
|
||||
readonly subject?: string;
|
||||
@ -29,9 +19,11 @@ export interface IPropertiesOptions {
|
||||
readonly styles?: IStylesOptions;
|
||||
readonly numbering?: INumberingOptions;
|
||||
readonly footnotes?: Paragraph[];
|
||||
readonly hyperlinks?: {
|
||||
readonly [key: string]: IInternalHyperlinkDefinition | IExternalHyperlinkDefinition;
|
||||
readonly background?: IDocumentBackgroundOptions;
|
||||
readonly features?: {
|
||||
readonly trackRevisions?: boolean;
|
||||
};
|
||||
readonly compatabilityModeVersion?: number;
|
||||
}
|
||||
|
||||
export class CoreProperties extends XmlComponent {
|
||||
|
50
src/file/document-wrapper.spec.ts
Normal file
50
src/file/document-wrapper.spec.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { expect } from "chai";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
import { FooterWrapper } from "./footer-wrapper";
|
||||
import { Media } from "./media";
|
||||
import { Paragraph } from "./paragraph";
|
||||
import { Table, TableCell, TableRow } from "./table";
|
||||
|
||||
describe("FooterWrapper", () => {
|
||||
describe("#add", () => {
|
||||
it("should call the underlying footer's addParagraph", () => {
|
||||
const file = new FooterWrapper(new Media(), 1);
|
||||
const spy = sinon.spy(file.View, "add");
|
||||
file.add(new Paragraph({}));
|
||||
|
||||
expect(spy.called).to.equal(true);
|
||||
});
|
||||
|
||||
it("should call the underlying footer's addParagraph", () => {
|
||||
const file = new FooterWrapper(new Media(), 1);
|
||||
const spy = sinon.spy(file.View, "add");
|
||||
file.add(
|
||||
new Table({
|
||||
rows: [
|
||||
new TableRow({
|
||||
children: [
|
||||
new TableCell({
|
||||
children: [new Paragraph("hello")],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
expect(spy.called).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#addChildElement", () => {
|
||||
it("should call the underlying footer's addChildElement", () => {
|
||||
const file = new FooterWrapper(new Media(), 1);
|
||||
const spy = sinon.spy(file.View, "addChildElement");
|
||||
// tslint:disable-next-line:no-any
|
||||
file.addChildElement({} as any);
|
||||
|
||||
expect(spy.called).to.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
27
src/file/document-wrapper.ts
Normal file
27
src/file/document-wrapper.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { Document, IDocumentOptions } from "./document";
|
||||
import { Footer } from "./footer";
|
||||
import { Header } from "./header/header";
|
||||
import { Relationships } from "./relationships";
|
||||
|
||||
export interface IViewWrapper {
|
||||
readonly View: Document | Footer | Header;
|
||||
readonly Relationships: Relationships;
|
||||
}
|
||||
|
||||
export class DocumentWrapper implements IViewWrapper {
|
||||
private readonly document: Document;
|
||||
private readonly relationships: Relationships;
|
||||
|
||||
constructor(options: IDocumentOptions) {
|
||||
this.document = new Document(options);
|
||||
this.relationships = new Relationships();
|
||||
}
|
||||
|
||||
public get View(): Document {
|
||||
return this.document;
|
||||
}
|
||||
|
||||
public get Relationships(): Relationships {
|
||||
return this.relationships;
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { IViewWrapper } from "file/document-wrapper";
|
||||
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
||||
|
||||
import { Paragraph, ParagraphProperties, TableOfContents } from "../..";
|
||||
import { File } from "../../../file";
|
||||
import { SectionProperties, SectionPropertiesOptions } from "./section-properties/section-properties";
|
||||
|
||||
export class Body extends XmlComponent {
|
||||
@ -25,7 +26,7 @@ export class Body extends XmlComponent {
|
||||
this.sections.push(new SectionProperties(options));
|
||||
}
|
||||
|
||||
public prepForXml(file?: File): IXmlableObject | undefined {
|
||||
public prepForXml(file?: IViewWrapper): IXmlableObject | undefined {
|
||||
if (this.sections.length === 1) {
|
||||
this.root.splice(0, 1);
|
||||
this.root.push(this.sections.pop() as SectionProperties);
|
||||
|
@ -6,3 +6,4 @@ export * from "./page-number";
|
||||
export * from "./page-border";
|
||||
export * from "./line-number";
|
||||
export * from "./vertical-align";
|
||||
export * from "./type";
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { convertInchesToTwip } from "convenience-functions";
|
||||
import { Formatter } from "export/formatter";
|
||||
import { FooterWrapper } from "file/footer-wrapper";
|
||||
import { HeaderWrapper } from "file/header-wrapper";
|
||||
@ -8,6 +9,7 @@ import { Media } from "file/media";
|
||||
import { PageBorderOffsetFrom } from "./page-border";
|
||||
import { PageNumberFormat } from "./page-number";
|
||||
import { SectionProperties } from "./section-properties";
|
||||
import { SectionType } from "./type/section-type-attributes";
|
||||
import { SectionVerticalAlignValue } from "./vertical-align";
|
||||
|
||||
describe("SectionProperties", () => {
|
||||
@ -18,10 +20,10 @@ describe("SectionProperties", () => {
|
||||
const properties = new SectionProperties({
|
||||
width: 11906,
|
||||
height: 16838,
|
||||
top: 1440,
|
||||
right: 1440,
|
||||
bottom: 1440,
|
||||
left: 1440,
|
||||
top: convertInchesToTwip(1),
|
||||
right: convertInchesToTwip(1),
|
||||
bottom: convertInchesToTwip(1),
|
||||
left: convertInchesToTwip(1),
|
||||
header: 708,
|
||||
footer: 708,
|
||||
gutter: 0,
|
||||
@ -30,7 +32,7 @@ describe("SectionProperties", () => {
|
||||
space: 708,
|
||||
count: 1,
|
||||
},
|
||||
linePitch: 360,
|
||||
linePitch: convertInchesToTwip(0.25),
|
||||
headers: {
|
||||
default: new HeaderWrapper(media, 100),
|
||||
},
|
||||
@ -198,5 +200,17 @@ describe("SectionProperties", () => {
|
||||
const pgNumType = tree["w:sectPr"].find((item) => item["w:pgNumType"] !== undefined);
|
||||
expect(pgNumType).to.equal(undefined);
|
||||
});
|
||||
|
||||
it("should create section properties with section type", () => {
|
||||
const properties = new SectionProperties({
|
||||
type: SectionType.CONTINUOUS,
|
||||
});
|
||||
const tree = new Formatter().format(properties);
|
||||
expect(Object.keys(tree)).to.deep.equal(["w:sectPr"]);
|
||||
const type = tree["w:sectPr"].find((item) => item["w:type"] !== undefined);
|
||||
expect(type).to.deep.equal({
|
||||
"w:type": { _attr: { "w:val": "continuous" } },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,5 @@
|
||||
// http://officeopenxml.com/WPsection.php
|
||||
import { convertInchesToTwip } from "convenience-functions";
|
||||
import { FooterWrapper } from "file/footer-wrapper";
|
||||
import { HeaderWrapper } from "file/header-wrapper";
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
@ -18,6 +19,8 @@ import { IPageNumberTypeAttributes, PageNumberType } from "./page-number";
|
||||
import { PageSize } from "./page-size/page-size";
|
||||
import { IPageSizeAttributes, PageOrientation } from "./page-size/page-size-attributes";
|
||||
import { TitlePage } from "./title-page/title-page";
|
||||
import { Type } from "./type/section-type";
|
||||
import { SectionType } from "./type/section-type-attributes";
|
||||
import { ISectionVerticalAlignAttributes, SectionVerticalAlign } from "./vertical-align";
|
||||
|
||||
export interface IHeaderFooterGroup<T> {
|
||||
@ -52,6 +55,7 @@ export type SectionPropertiesOptions = IPageSizeAttributes &
|
||||
readonly space?: number;
|
||||
readonly count?: number;
|
||||
};
|
||||
readonly type?: SectionType;
|
||||
};
|
||||
// Need to decouple this from the attributes
|
||||
|
||||
@ -64,10 +68,10 @@ export class SectionProperties extends XmlComponent {
|
||||
const {
|
||||
width = 11906,
|
||||
height = 16838,
|
||||
top = 1440,
|
||||
right = 1440,
|
||||
bottom = 1440,
|
||||
left = 1440,
|
||||
top = convertInchesToTwip(1),
|
||||
right = convertInchesToTwip(1),
|
||||
bottom = convertInchesToTwip(1),
|
||||
left = convertInchesToTwip(1),
|
||||
header = 708,
|
||||
footer = 708,
|
||||
gutter = 0,
|
||||
@ -90,6 +94,7 @@ export class SectionProperties extends XmlComponent {
|
||||
pageBorderLeft,
|
||||
titlePage = false,
|
||||
verticalAlign,
|
||||
type,
|
||||
} = options;
|
||||
|
||||
this.options = options;
|
||||
@ -128,6 +133,10 @@ export class SectionProperties extends XmlComponent {
|
||||
if (verticalAlign) {
|
||||
this.root.push(new SectionVerticalAlign(verticalAlign));
|
||||
}
|
||||
|
||||
if (type) {
|
||||
this.root.push(new Type(type));
|
||||
}
|
||||
}
|
||||
|
||||
private addHeaders(headers?: IHeaderFooterGroup<HeaderWrapper>): void {
|
||||
@ -136,7 +145,7 @@ export class SectionProperties extends XmlComponent {
|
||||
this.root.push(
|
||||
new HeaderReference({
|
||||
headerType: HeaderReferenceType.DEFAULT,
|
||||
headerId: headers.default.Header.ReferenceId,
|
||||
headerId: headers.default.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -145,7 +154,7 @@ export class SectionProperties extends XmlComponent {
|
||||
this.root.push(
|
||||
new HeaderReference({
|
||||
headerType: HeaderReferenceType.FIRST,
|
||||
headerId: headers.first.Header.ReferenceId,
|
||||
headerId: headers.first.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -154,7 +163,7 @@ export class SectionProperties extends XmlComponent {
|
||||
this.root.push(
|
||||
new HeaderReference({
|
||||
headerType: HeaderReferenceType.EVEN,
|
||||
headerId: headers.even.Header.ReferenceId,
|
||||
headerId: headers.even.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -167,7 +176,7 @@ export class SectionProperties extends XmlComponent {
|
||||
this.root.push(
|
||||
new FooterReference({
|
||||
footerType: FooterReferenceType.DEFAULT,
|
||||
footerId: footers.default.Footer.ReferenceId,
|
||||
footerId: footers.default.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -176,7 +185,7 @@ export class SectionProperties extends XmlComponent {
|
||||
this.root.push(
|
||||
new FooterReference({
|
||||
footerType: FooterReferenceType.FIRST,
|
||||
footerId: footers.first.Footer.ReferenceId,
|
||||
footerId: footers.first.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -185,7 +194,7 @@ export class SectionProperties extends XmlComponent {
|
||||
this.root.push(
|
||||
new FooterReference({
|
||||
footerType: FooterReferenceType.EVEN,
|
||||
footerId: footers.even.Footer.ReferenceId,
|
||||
footerId: footers.even.View.ReferenceId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
2
src/file/document/body/section-properties/type/index.ts
Normal file
2
src/file/document/body/section-properties/type/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./section-type";
|
||||
export * from "./section-type-attributes";
|
@ -0,0 +1,17 @@
|
||||
import { XmlAttributeComponent } from "file/xml-components";
|
||||
|
||||
export enum SectionType {
|
||||
CONTINUOUS = "continuous",
|
||||
EVEN_PAGE = "evenPage",
|
||||
NEXT_COLUMN = "nextColumn",
|
||||
NEXT_PAGE = "nextPage",
|
||||
ODD_PAGE = "oddPage",
|
||||
}
|
||||
|
||||
export class SectionTypeAttributes extends XmlAttributeComponent<{
|
||||
readonly val: SectionType;
|
||||
}> {
|
||||
protected readonly xmlKeys = {
|
||||
val: "w:val",
|
||||
};
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
import { Type } from "./section-type";
|
||||
import { SectionType } from "./section-type-attributes";
|
||||
|
||||
describe("Type", () => {
|
||||
it("should create with even page section type", () => {
|
||||
const sectionType = new Type(SectionType.EVEN_PAGE);
|
||||
|
||||
const tree = new Formatter().format(sectionType);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:type": {
|
||||
_attr: {
|
||||
"w:val": "evenPage",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should create with continuous section type", () => {
|
||||
const sectionType = new Type(SectionType.CONTINUOUS);
|
||||
|
||||
const tree = new Formatter().format(sectionType);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:type": {
|
||||
_attr: {
|
||||
"w:val": "continuous",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,10 @@
|
||||
// http://officeopenxml.com/WPsection.php
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { SectionType, SectionTypeAttributes } from "./section-type-attributes";
|
||||
|
||||
export class Type extends XmlComponent {
|
||||
constructor(value: SectionType) {
|
||||
super("w:type");
|
||||
this.root.push(new SectionTypeAttributes({ val: value }));
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { DocumentBackground } from "./document-background";
|
||||
|
||||
describe("DocumentBackground", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a DocumentBackground with no options and set color to auto", () => {
|
||||
const documentBackground = new DocumentBackground({});
|
||||
const tree = new Formatter().format(documentBackground);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:background": {
|
||||
_attr: {
|
||||
"w:color": "FFFFFF",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a DocumentBackground with no options and set color to value", () => {
|
||||
const documentBackground = new DocumentBackground({ color: "ffff00" });
|
||||
const tree = new Formatter().format(documentBackground);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:background": {
|
||||
_attr: {
|
||||
"w:color": "ffff00",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a DocumentBackground with no options and set other values", () => {
|
||||
const documentBackground = new DocumentBackground({
|
||||
color: "ffff00",
|
||||
themeColor: "test",
|
||||
themeShade: "test",
|
||||
themeTint: "test",
|
||||
});
|
||||
const tree = new Formatter().format(documentBackground);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:background": {
|
||||
_attr: {
|
||||
"w:color": "ffff00",
|
||||
"w:themeColor": "test",
|
||||
"w:themeShade": "test",
|
||||
"w:themeTint": "test",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
39
src/file/document/document-background/document-background.ts
Normal file
39
src/file/document/document-background/document-background.ts
Normal file
@ -0,0 +1,39 @@
|
||||
// http://officeopenxml.com/WPdocument.php
|
||||
// http://www.datypic.com/sc/ooxml/e-w_background-1.html
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
export class DocumentBackgroundAttributes extends XmlAttributeComponent<{
|
||||
readonly color: string;
|
||||
readonly themeColor?: string;
|
||||
readonly themeShade?: string;
|
||||
readonly themeTint?: string;
|
||||
}> {
|
||||
protected readonly xmlKeys = {
|
||||
color: "w:color",
|
||||
themeColor: "w:themeColor",
|
||||
themeShade: "w:themeShade",
|
||||
themeTint: "w:themeTint",
|
||||
};
|
||||
}
|
||||
|
||||
export interface IDocumentBackgroundOptions {
|
||||
readonly color?: string;
|
||||
readonly themeColor?: string;
|
||||
readonly themeShade?: string;
|
||||
readonly themeTint?: string;
|
||||
}
|
||||
|
||||
export class DocumentBackground extends XmlComponent {
|
||||
constructor(options: IDocumentBackgroundOptions) {
|
||||
super("w:background");
|
||||
|
||||
this.root.push(
|
||||
new DocumentBackgroundAttributes({
|
||||
color: options.color ? options.color : "FFFFFF",
|
||||
themeColor: options.themeColor,
|
||||
themeShade: options.themeShade,
|
||||
themeTint: options.themeTint,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
1
src/file/document/document-background/index.ts
Normal file
1
src/file/document/document-background/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./document-background";
|
@ -8,7 +8,7 @@ describe("Document", () => {
|
||||
let document: Document;
|
||||
|
||||
beforeEach(() => {
|
||||
document = new Document();
|
||||
document = new Document({ background: {} });
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
@ -38,6 +38,13 @@ describe("Document", () => {
|
||||
"mc:Ignorable": "w14 w15 wp14",
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:background": {
|
||||
_attr: {
|
||||
"w:color": "FFFFFF",
|
||||
},
|
||||
},
|
||||
},
|
||||
{ "w:body": {} },
|
||||
],
|
||||
});
|
||||
|
@ -1,15 +1,20 @@
|
||||
// http://officeopenxml.com/WPdocument.php
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { Hyperlink, Paragraph } from "../paragraph";
|
||||
import { ConcreteHyperlink, Paragraph } from "../paragraph";
|
||||
import { Table } from "../table";
|
||||
import { TableOfContents } from "../table-of-contents";
|
||||
import { Body } from "./body";
|
||||
import { DocumentAttributes } from "./document-attributes";
|
||||
import { DocumentBackground, IDocumentBackgroundOptions } from "./document-background";
|
||||
|
||||
export interface IDocumentOptions {
|
||||
readonly background: IDocumentBackgroundOptions;
|
||||
}
|
||||
|
||||
export class Document extends XmlComponent {
|
||||
private readonly body: Body;
|
||||
|
||||
constructor() {
|
||||
constructor(options: IDocumentOptions) {
|
||||
super("w:document");
|
||||
this.root.push(
|
||||
new DocumentAttributes({
|
||||
@ -33,10 +38,11 @@ export class Document extends XmlComponent {
|
||||
}),
|
||||
);
|
||||
this.body = new Body();
|
||||
this.root.push(new DocumentBackground(options.background));
|
||||
this.root.push(this.body);
|
||||
}
|
||||
|
||||
public add(item: Paragraph | Table | TableOfContents | Hyperlink): Document {
|
||||
public add(item: Paragraph | Table | TableOfContents | ConcreteHyperlink): Document {
|
||||
this.body.push(item);
|
||||
return this;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
export * from "./document";
|
||||
export * from "./document-attributes";
|
||||
export * from "./body";
|
||||
export * from "./document-background";
|
||||
|
@ -218,5 +218,150 @@ describe("Anchor", () => {
|
||||
const textWrap = newJson.root[6];
|
||||
assert.equal(textWrap.rootKey, "wp:wrapTopAndBottom");
|
||||
});
|
||||
|
||||
it("should create a Drawing with a margin", () => {
|
||||
anchor = createAnchor({
|
||||
floating: {
|
||||
verticalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
horizontalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
margins: {
|
||||
top: 10,
|
||||
left: 10,
|
||||
bottom: 10,
|
||||
right: 10,
|
||||
},
|
||||
},
|
||||
});
|
||||
const newJson = Utility.jsonify(anchor);
|
||||
const anchorAttributes = newJson.root[0].root;
|
||||
assert.include(anchorAttributes, {
|
||||
distT: 10,
|
||||
distB: 10,
|
||||
distL: 10,
|
||||
distR: 10,
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a Drawing with a default margin", () => {
|
||||
anchor = createAnchor({
|
||||
floating: {
|
||||
verticalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
horizontalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
margins: {},
|
||||
},
|
||||
});
|
||||
const newJson = Utility.jsonify(anchor);
|
||||
const anchorAttributes = newJson.root[0].root;
|
||||
assert.include(anchorAttributes, {
|
||||
distT: 0,
|
||||
distB: 0,
|
||||
distL: 0,
|
||||
distR: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a Drawing with allowOverlap being false", () => {
|
||||
anchor = createAnchor({
|
||||
floating: {
|
||||
verticalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
horizontalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
allowOverlap: false,
|
||||
},
|
||||
});
|
||||
const newJson = Utility.jsonify(anchor);
|
||||
const anchorAttributes = newJson.root[0].root;
|
||||
assert.include(anchorAttributes, {
|
||||
allowOverlap: "0",
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a Drawing with behindDocument being true", () => {
|
||||
anchor = createAnchor({
|
||||
floating: {
|
||||
verticalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
horizontalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
behindDocument: true,
|
||||
},
|
||||
});
|
||||
const newJson = Utility.jsonify(anchor);
|
||||
const anchorAttributes = newJson.root[0].root;
|
||||
assert.include(anchorAttributes, {
|
||||
behindDoc: "1",
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a Drawing with locked being true", () => {
|
||||
anchor = createAnchor({
|
||||
floating: {
|
||||
verticalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
horizontalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
lockAnchor: true,
|
||||
},
|
||||
});
|
||||
const newJson = Utility.jsonify(anchor);
|
||||
const anchorAttributes = newJson.root[0].root;
|
||||
assert.include(anchorAttributes, {
|
||||
locked: "1",
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a Drawing with locked being false", () => {
|
||||
anchor = createAnchor({
|
||||
floating: {
|
||||
verticalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
horizontalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
layoutInCell: false,
|
||||
},
|
||||
});
|
||||
const newJson = Utility.jsonify(anchor);
|
||||
const anchorAttributes = newJson.root[0].root;
|
||||
assert.include(anchorAttributes, {
|
||||
layoutInCell: "0",
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a Drawing with a certain z-index", () => {
|
||||
anchor = createAnchor({
|
||||
floating: {
|
||||
verticalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
horizontalPosition: {
|
||||
offset: 0,
|
||||
},
|
||||
zIndex: 120,
|
||||
},
|
||||
});
|
||||
const newJson = Utility.jsonify(anchor);
|
||||
const anchorAttributes = newJson.root[0].root;
|
||||
|
||||
assert.include(anchorAttributes, {
|
||||
relativeHeight: 120,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -11,42 +11,32 @@ import { Extent } from "./../extent/extent";
|
||||
import { GraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties";
|
||||
import { AnchorAttributes } from "./anchor-attributes";
|
||||
|
||||
const defaultOptions: IFloating = {
|
||||
allowOverlap: true,
|
||||
behindDocument: false,
|
||||
lockAnchor: false,
|
||||
layoutInCell: true,
|
||||
verticalPosition: {},
|
||||
horizontalPosition: {},
|
||||
};
|
||||
|
||||
export class Anchor extends XmlComponent {
|
||||
constructor(mediaData: IMediaData, dimensions: IMediaDataDimensions, drawingOptions: IDrawingOptions) {
|
||||
super("wp:anchor");
|
||||
|
||||
const floating = {
|
||||
margins: {
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
},
|
||||
...defaultOptions,
|
||||
const floating: IFloating = {
|
||||
allowOverlap: true,
|
||||
behindDocument: false,
|
||||
lockAnchor: false,
|
||||
layoutInCell: true,
|
||||
verticalPosition: {},
|
||||
horizontalPosition: {},
|
||||
...drawingOptions.floating,
|
||||
};
|
||||
|
||||
this.root.push(
|
||||
new AnchorAttributes({
|
||||
distT: floating.margins.top || 0,
|
||||
distB: floating.margins.bottom || 0,
|
||||
distL: floating.margins.left || 0,
|
||||
distR: floating.margins.right || 0,
|
||||
distT: floating.margins ? floating.margins.top || 0 : 0,
|
||||
distB: floating.margins ? floating.margins.bottom || 0 : 0,
|
||||
distL: floating.margins ? floating.margins.left || 0 : 0,
|
||||
distR: floating.margins ? floating.margins.right || 0 : 0,
|
||||
simplePos: "0", // note: word doesn't fully support - so we use 0
|
||||
allowOverlap: floating.allowOverlap === true ? "1" : "0",
|
||||
behindDoc: floating.behindDocument === true ? "1" : "0",
|
||||
locked: floating.lockAnchor === true ? "1" : "0",
|
||||
layoutInCell: floating.layoutInCell === true ? "1" : "0",
|
||||
relativeHeight: dimensions.emus.y,
|
||||
relativeHeight: floating.zIndex ? floating.zIndex : dimensions.emus.y,
|
||||
}),
|
||||
);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
// http://officeopenxml.com/drwPicFloating-position.php
|
||||
// http://officeopenxml.com/drwPicFloating.php
|
||||
import { ITextWrapping } from "../text-wrap";
|
||||
|
||||
export enum HorizontalPositionRelativeFrom {
|
||||
@ -67,4 +68,5 @@ export interface IFloating {
|
||||
readonly layoutInCell?: boolean;
|
||||
readonly margins?: IMargins;
|
||||
readonly wrap?: ITextWrapping;
|
||||
readonly zIndex?: number;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ export class Inline extends XmlComponent {
|
||||
private readonly extent: Extent;
|
||||
private readonly graphic: Graphic;
|
||||
|
||||
constructor(readonly mediaData: IMediaData, private readonly dimensions: IMediaDataDimensions) {
|
||||
constructor(mediaData: IMediaData, private readonly dimensions: IMediaDataDimensions) {
|
||||
super("wp:inline");
|
||||
|
||||
this.root.push(
|
||||
|
@ -5,7 +5,7 @@ import { Formatter } from "export/formatter";
|
||||
|
||||
import { File } from "./file";
|
||||
import { Footer, Header } from "./header";
|
||||
import { HyperlinkRef, Paragraph } from "./paragraph";
|
||||
import { Paragraph } from "./paragraph";
|
||||
import { Table, TableCell, TableRow } from "./table";
|
||||
import { TableOfContents } from "./table-of-contents";
|
||||
|
||||
@ -18,7 +18,7 @@ describe("File", () => {
|
||||
children: [],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(doc.Document.Body);
|
||||
const tree = new Formatter().format(doc.Document.View.Body);
|
||||
|
||||
expect(tree["w:body"][0]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default");
|
||||
expect(tree["w:body"][0]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("default");
|
||||
@ -37,7 +37,7 @@ describe("File", () => {
|
||||
children: [],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(doc.Document.Body);
|
||||
const tree = new Formatter().format(doc.Document.View.Body);
|
||||
|
||||
expect(tree["w:body"][0]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default");
|
||||
expect(tree["w:body"][0]["w:sectPr"][5]["w:footerReference"]._attr["w:type"]).to.equal("default");
|
||||
@ -56,7 +56,7 @@ describe("File", () => {
|
||||
children: [],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(doc.Document.Body);
|
||||
const tree = new Formatter().format(doc.Document.View.Body);
|
||||
|
||||
expect(tree["w:body"][0]["w:sectPr"][5]["w:headerReference"]._attr["w:type"]).to.equal("first");
|
||||
expect(tree["w:body"][0]["w:sectPr"][7]["w:footerReference"]._attr["w:type"]).to.equal("first");
|
||||
@ -79,7 +79,7 @@ describe("File", () => {
|
||||
children: [],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(doc.Document.Body);
|
||||
const tree = new Formatter().format(doc.Document.View.Body);
|
||||
|
||||
expect(tree["w:body"][0]["w:sectPr"][4]["w:headerReference"]._attr["w:type"]).to.equal("default");
|
||||
expect(tree["w:body"][0]["w:sectPr"][5]["w:headerReference"]._attr["w:type"]).to.equal("first");
|
||||
@ -97,7 +97,7 @@ describe("File", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const tree = new Formatter().format(doc.Document.Body);
|
||||
const tree = new Formatter().format(doc.Document.View.Body);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:body": [
|
||||
@ -164,22 +164,12 @@ describe("File", () => {
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should add hyperlink child", () => {
|
||||
const doc = new File(undefined, undefined, [
|
||||
{
|
||||
children: [new HyperlinkRef("test")],
|
||||
},
|
||||
]);
|
||||
|
||||
expect(doc.HyperlinkCache).to.deep.equal({});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#addSection", () => {
|
||||
it("should call the underlying document's add a Paragraph", () => {
|
||||
const file = new File();
|
||||
const spy = sinon.spy(file.Document, "add");
|
||||
const spy = sinon.spy(file.Document.View, "add");
|
||||
file.addSection({
|
||||
children: [new Paragraph({})],
|
||||
});
|
||||
@ -187,19 +177,9 @@ describe("File", () => {
|
||||
expect(spy.called).to.equal(true);
|
||||
});
|
||||
|
||||
it("should add hyperlink child", () => {
|
||||
const doc = new File();
|
||||
|
||||
doc.addSection({
|
||||
children: [new HyperlinkRef("test")],
|
||||
});
|
||||
|
||||
expect(doc.HyperlinkCache).to.deep.equal({});
|
||||
});
|
||||
|
||||
it("should call the underlying document's add when adding a Table", () => {
|
||||
const file = new File();
|
||||
const spy = sinon.spy(file.Document, "add");
|
||||
const spy = sinon.spy(file.Document.View, "add");
|
||||
file.addSection({
|
||||
children: [
|
||||
new Table({
|
||||
@ -221,7 +201,7 @@ describe("File", () => {
|
||||
|
||||
it("should call the underlying document's add when adding an Image (paragraph)", () => {
|
||||
const file = new File();
|
||||
const spy = sinon.spy(file.Document, "add");
|
||||
const spy = sinon.spy(file.Document.View, "add");
|
||||
// tslint:disable-next-line:no-any
|
||||
file.addSection({
|
||||
children: [new Paragraph("")],
|
||||
@ -234,7 +214,7 @@ describe("File", () => {
|
||||
describe("#addSection", () => {
|
||||
it("should call the underlying document's add", () => {
|
||||
const file = new File();
|
||||
const spy = sinon.spy(file.Document, "add");
|
||||
const spy = sinon.spy(file.Document.View, "add");
|
||||
file.addSection({
|
||||
children: [new TableOfContents()],
|
||||
});
|
||||
@ -243,11 +223,16 @@ describe("File", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#HyperlinkCache", () => {
|
||||
it("should initially have empty hyperlink cache", () => {
|
||||
const file = new File();
|
||||
describe("#addTrackRevisionsFeature", () => {
|
||||
it("should call the underlying document's add", () => {
|
||||
const file = new File({
|
||||
features: {
|
||||
trackRevisions: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(file.HyperlinkCache).to.deep.equal({});
|
||||
// tslint:disable-next-line: no-unused-expression no-string-literal
|
||||
expect(file.Settings["trackRevisions"]).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
|
111
src/file/file.ts
111
src/file/file.ts
@ -1,9 +1,8 @@
|
||||
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";
|
||||
import { CustomProperties, ICustomPropertyOptions } from "./custom-properties";
|
||||
import { Document } from "./document";
|
||||
import { DocumentWrapper } from "./document-wrapper";
|
||||
import {
|
||||
FooterReferenceType,
|
||||
HeaderReferenceType,
|
||||
@ -18,9 +17,8 @@ import { Footer, Header } from "./header";
|
||||
import { HeaderWrapper, IDocumentHeader } from "./header-wrapper";
|
||||
import { Media } from "./media";
|
||||
import { Numbering } from "./numbering";
|
||||
import { Hyperlink, HyperlinkRef, HyperlinkType, Paragraph } from "./paragraph";
|
||||
import { Paragraph } from "./paragraph";
|
||||
import { Relationships } from "./relationships";
|
||||
import { TargetModeType } from "./relationships/relationship/relationship";
|
||||
import { Settings } from "./settings";
|
||||
import { Styles } from "./styles";
|
||||
import { ExternalStylesFactory } from "./styles/external-styles-factory";
|
||||
@ -42,17 +40,16 @@ export interface ISectionOptions {
|
||||
readonly size?: IPageSizeAttributes;
|
||||
readonly margins?: IPageMarginAttributes;
|
||||
readonly properties?: SectionPropertiesOptions;
|
||||
readonly children: (Paragraph | Table | TableOfContents | HyperlinkRef)[];
|
||||
readonly children: (Paragraph | Table | TableOfContents)[];
|
||||
}
|
||||
|
||||
export class File {
|
||||
// tslint:disable-next-line:readonly-keyword
|
||||
private currentRelationshipId: number = 1;
|
||||
|
||||
private readonly document: Document;
|
||||
private readonly documentWrapper: DocumentWrapper;
|
||||
private readonly headers: IDocumentHeader[] = [];
|
||||
private readonly footers: IDocumentFooter[] = [];
|
||||
private readonly docRelationships: Relationships;
|
||||
private readonly coreProperties: CoreProperties;
|
||||
private readonly numbering: Numbering;
|
||||
private readonly media: Media;
|
||||
@ -63,7 +60,6 @@ export class File {
|
||||
private readonly customProperties: CustomProperties;
|
||||
private readonly appProperties: AppProperties;
|
||||
private readonly styles: Styles;
|
||||
private readonly hyperlinkCache: { readonly [key: string]: Hyperlink } = {};
|
||||
|
||||
constructor(
|
||||
options: IPropertiesOptions = {
|
||||
@ -83,14 +79,16 @@ export class File {
|
||||
config: [],
|
||||
},
|
||||
);
|
||||
this.docRelationships = new Relationships();
|
||||
// this.documentWrapper.Relationships = new Relationships();
|
||||
this.fileRelationships = new Relationships();
|
||||
this.customProperties = new CustomProperties(customProperties);
|
||||
this.appProperties = new AppProperties();
|
||||
this.footNotes = new FootNotes();
|
||||
this.contentTypes = new ContentTypes();
|
||||
this.document = new Document();
|
||||
this.settings = new Settings();
|
||||
this.documentWrapper = new DocumentWrapper({ background: options.background || {} });
|
||||
this.settings = new Settings({
|
||||
compatabilityModeVersion: options.compatabilityModeVersion,
|
||||
});
|
||||
|
||||
this.media = fileProperties.template && fileProperties.template.media ? fileProperties.template.media : new Media();
|
||||
|
||||
@ -110,7 +108,7 @@ export class File {
|
||||
this.styles = stylesFactory.newInstance(options.externalStyles);
|
||||
} else if (options.styles) {
|
||||
const stylesFactory = new DefaultStylesFactory();
|
||||
const defaultStyles = stylesFactory.newInstance();
|
||||
const defaultStyles = stylesFactory.newInstance(options.styles.default);
|
||||
this.styles = new Styles({
|
||||
...defaultStyles,
|
||||
...options.styles,
|
||||
@ -135,16 +133,10 @@ export class File {
|
||||
}
|
||||
|
||||
for (const section of sections) {
|
||||
this.document.Body.addSection(section.properties ? section.properties : {});
|
||||
this.documentWrapper.View.Body.addSection(section.properties ? section.properties : {});
|
||||
|
||||
for (const child of section.children) {
|
||||
if (child instanceof HyperlinkRef) {
|
||||
const hyperlink = this.hyperlinkCache[child.id];
|
||||
this.document.add(hyperlink);
|
||||
continue;
|
||||
}
|
||||
|
||||
this.document.add(child);
|
||||
this.documentWrapper.View.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,25 +146,10 @@ export class File {
|
||||
}
|
||||
}
|
||||
|
||||
if (options.hyperlinks) {
|
||||
const cache = {};
|
||||
|
||||
for (const key in options.hyperlinks) {
|
||||
if (!options.hyperlinks[key]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const hyperlinkRef = options.hyperlinks[key];
|
||||
|
||||
const hyperlink =
|
||||
hyperlinkRef.type === HyperlinkType.EXTERNAL
|
||||
? this.createHyperlink(hyperlinkRef.link, hyperlinkRef.text)
|
||||
: this.createInternalHyperLink(key, hyperlinkRef.text);
|
||||
|
||||
cache[key] = hyperlink;
|
||||
if (options.features) {
|
||||
if (options.features.trackRevisions) {
|
||||
this.settings.addTrackRevisions();
|
||||
}
|
||||
|
||||
this.hyperlinkCache = cache;
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,7 +161,7 @@ export class File {
|
||||
properties,
|
||||
children,
|
||||
}: ISectionOptions): void {
|
||||
this.document.Body.addSection({
|
||||
this.documentWrapper.View.Body.addSection({
|
||||
...properties,
|
||||
headers: {
|
||||
default: headers.default ? this.createHeader(headers.default) : this.createHeader(new Header()),
|
||||
@ -201,40 +178,16 @@ export class File {
|
||||
});
|
||||
|
||||
for (const child of children) {
|
||||
if (child instanceof HyperlinkRef) {
|
||||
const hyperlink = this.hyperlinkCache[child.id];
|
||||
this.document.add(hyperlink);
|
||||
continue;
|
||||
}
|
||||
|
||||
this.document.add(child);
|
||||
this.documentWrapper.View.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyUpdateFields(): void {
|
||||
if (this.document.getTablesOfContents().length) {
|
||||
if (this.documentWrapper.View.getTablesOfContents().length) {
|
||||
this.settings.addUpdateFields();
|
||||
}
|
||||
}
|
||||
|
||||
private createHyperlink(link: string, text: string = link): Hyperlink {
|
||||
const hyperlink = new Hyperlink(text, shortid.generate().toLowerCase());
|
||||
this.docRelationships.createRelationship(
|
||||
hyperlink.linkId,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
||||
link,
|
||||
TargetModeType.EXTERNAL,
|
||||
);
|
||||
return hyperlink;
|
||||
}
|
||||
|
||||
private createInternalHyperLink(anchor: string, text: string = anchor): Hyperlink {
|
||||
const hyperlink = new Hyperlink(text, shortid.generate().toLowerCase(), anchor);
|
||||
// NOTE: unlike File#createHyperlink(), since the link is to an internal bookmark
|
||||
// we don't need to create a new relationship.
|
||||
return hyperlink;
|
||||
}
|
||||
|
||||
private createHeader(header: Header): HeaderWrapper {
|
||||
const wrapper = new HeaderWrapper(this.media, this.currentRelationshipId++);
|
||||
|
||||
@ -259,8 +212,8 @@ export class File {
|
||||
|
||||
private addHeaderToDocument(header: HeaderWrapper, type: HeaderReferenceType = HeaderReferenceType.DEFAULT): void {
|
||||
this.headers.push({ header, type });
|
||||
this.docRelationships.createRelationship(
|
||||
header.Header.ReferenceId,
|
||||
this.documentWrapper.Relationships.createRelationship(
|
||||
header.View.ReferenceId,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header",
|
||||
`header${this.headers.length}.xml`,
|
||||
);
|
||||
@ -269,8 +222,8 @@ export class File {
|
||||
|
||||
private addFooterToDocument(footer: FooterWrapper, type: FooterReferenceType = FooterReferenceType.DEFAULT): void {
|
||||
this.footers.push({ footer, type });
|
||||
this.docRelationships.createRelationship(
|
||||
footer.Footer.ReferenceId,
|
||||
this.documentWrapper.Relationships.createRelationship(
|
||||
footer.View.ReferenceId,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer",
|
||||
`footer${this.footers.length}.xml`,
|
||||
);
|
||||
@ -299,30 +252,30 @@ export class File {
|
||||
"docProps/custom.xml",
|
||||
);
|
||||
|
||||
this.docRelationships.createRelationship(
|
||||
this.documentWrapper.Relationships.createRelationship(
|
||||
this.currentRelationshipId++,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
|
||||
"styles.xml",
|
||||
);
|
||||
this.docRelationships.createRelationship(
|
||||
this.documentWrapper.Relationships.createRelationship(
|
||||
this.currentRelationshipId++,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering",
|
||||
"numbering.xml",
|
||||
);
|
||||
this.docRelationships.createRelationship(
|
||||
this.documentWrapper.Relationships.createRelationship(
|
||||
this.currentRelationshipId++,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes",
|
||||
"footnotes.xml",
|
||||
);
|
||||
this.docRelationships.createRelationship(
|
||||
this.documentWrapper.Relationships.createRelationship(
|
||||
this.currentRelationshipId++,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings",
|
||||
"settings.xml",
|
||||
);
|
||||
}
|
||||
|
||||
public get Document(): Document {
|
||||
return this.document;
|
||||
public get Document(): DocumentWrapper {
|
||||
return this.documentWrapper;
|
||||
}
|
||||
|
||||
public get Styles(): Styles {
|
||||
@ -341,10 +294,6 @@ export class File {
|
||||
return this.media;
|
||||
}
|
||||
|
||||
public get DocumentRelationships(): Relationships {
|
||||
return this.docRelationships;
|
||||
}
|
||||
|
||||
public get FileRelationships(): Relationships {
|
||||
return this.fileRelationships;
|
||||
}
|
||||
@ -376,8 +325,4 @@ export class File {
|
||||
public get Settings(): Settings {
|
||||
return this.settings;
|
||||
}
|
||||
|
||||
public get HyperlinkCache(): { readonly [key: string]: Hyperlink } {
|
||||
return this.hyperlinkCache;
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ describe("FooterWrapper", () => {
|
||||
describe("#add", () => {
|
||||
it("should call the underlying footer's addParagraph", () => {
|
||||
const file = new FooterWrapper(new Media(), 1);
|
||||
const spy = sinon.spy(file.Footer, "add");
|
||||
const spy = sinon.spy(file.View, "add");
|
||||
file.add(new Paragraph({}));
|
||||
|
||||
expect(spy.called).to.equal(true);
|
||||
@ -18,7 +18,7 @@ describe("FooterWrapper", () => {
|
||||
|
||||
it("should call the underlying footer's addParagraph", () => {
|
||||
const file = new FooterWrapper(new Media(), 1);
|
||||
const spy = sinon.spy(file.Footer, "add");
|
||||
const spy = sinon.spy(file.View, "add");
|
||||
file.add(
|
||||
new Table({
|
||||
rows: [
|
||||
@ -40,7 +40,7 @@ describe("FooterWrapper", () => {
|
||||
describe("#addChildElement", () => {
|
||||
it("should call the underlying footer's addChildElement", () => {
|
||||
const file = new FooterWrapper(new Media(), 1);
|
||||
const spy = sinon.spy(file.Footer, "addChildElement");
|
||||
const spy = sinon.spy(file.View, "addChildElement");
|
||||
// tslint:disable-next-line:no-any
|
||||
file.addChildElement({} as any);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { FooterReferenceType } from "./document";
|
||||
import { IViewWrapper } from "./document-wrapper";
|
||||
import { Footer } from "./footer/footer";
|
||||
import { Media } from "./media";
|
||||
import { Paragraph } from "./paragraph";
|
||||
@ -12,7 +13,7 @@ export interface IDocumentFooter {
|
||||
readonly type: FooterReferenceType;
|
||||
}
|
||||
|
||||
export class FooterWrapper {
|
||||
export class FooterWrapper implements IViewWrapper {
|
||||
private readonly footer: Footer;
|
||||
private readonly relationships: Relationships;
|
||||
|
||||
@ -29,7 +30,7 @@ export class FooterWrapper {
|
||||
this.footer.addChildElement(childElement);
|
||||
}
|
||||
|
||||
public get Footer(): Footer {
|
||||
public get View(): Footer {
|
||||
return this.footer;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ describe("HeaderWrapper", () => {
|
||||
describe("#add", () => {
|
||||
it("should call the underlying header's addChildElement for Paragraph", () => {
|
||||
const wrapper = new HeaderWrapper(new Media(), 1);
|
||||
const spy = sinon.spy(wrapper.Header, "add");
|
||||
const spy = sinon.spy(wrapper.View, "add");
|
||||
wrapper.add(new Paragraph({}));
|
||||
|
||||
expect(spy.called).to.equal(true);
|
||||
@ -18,7 +18,7 @@ describe("HeaderWrapper", () => {
|
||||
|
||||
it("should call the underlying header's addChildElement for Table", () => {
|
||||
const wrapper = new HeaderWrapper(new Media(), 1);
|
||||
const spy = sinon.spy(wrapper.Header, "add");
|
||||
const spy = sinon.spy(wrapper.View, "add");
|
||||
wrapper.add(
|
||||
new Table({
|
||||
rows: [
|
||||
@ -40,7 +40,7 @@ describe("HeaderWrapper", () => {
|
||||
describe("#addChildElement", () => {
|
||||
it("should call the underlying header's addChildElement", () => {
|
||||
const file = new HeaderWrapper(new Media(), 1);
|
||||
const spy = sinon.spy(file.Header, "addChildElement");
|
||||
const spy = sinon.spy(file.View, "addChildElement");
|
||||
// tslint:disable-next-line:no-any
|
||||
file.addChildElement({} as any);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { HeaderReferenceType } from "./document";
|
||||
import { IViewWrapper } from "./document-wrapper";
|
||||
import { Header } from "./header/header";
|
||||
import { Media } from "./media";
|
||||
import { Paragraph } from "./paragraph";
|
||||
@ -12,7 +13,7 @@ export interface IDocumentHeader {
|
||||
readonly type: HeaderReferenceType;
|
||||
}
|
||||
|
||||
export class HeaderWrapper {
|
||||
export class HeaderWrapper implements IViewWrapper {
|
||||
private readonly header: Header;
|
||||
private readonly relationships: Relationships;
|
||||
|
||||
@ -31,7 +32,7 @@ export class HeaderWrapper {
|
||||
this.header.addChildElement(childElement);
|
||||
}
|
||||
|
||||
public get Header(): Header {
|
||||
public get View(): Header {
|
||||
return this.header;
|
||||
}
|
||||
|
||||
|
@ -13,3 +13,4 @@ export * from "./header-wrapper";
|
||||
export * from "./footer-wrapper";
|
||||
export * from "./header";
|
||||
export * from "./footnotes";
|
||||
export * from "./track-revision";
|
||||
|
@ -1,14 +1,12 @@
|
||||
import { IDrawingOptions } from "../drawing";
|
||||
import { File } from "../file";
|
||||
import { FooterWrapper } from "../footer-wrapper";
|
||||
import { HeaderWrapper } from "../header-wrapper";
|
||||
import { PictureRun } from "../paragraph";
|
||||
import { IMediaData } from "./data";
|
||||
// import { Image } from "./image";
|
||||
|
||||
export class Media {
|
||||
public static addImage(
|
||||
file: File | HeaderWrapper | FooterWrapper,
|
||||
file: File,
|
||||
buffer: Buffer | string | Uint8Array | ArrayBuffer,
|
||||
width?: number,
|
||||
height?: number,
|
||||
@ -82,7 +80,7 @@ export class Media {
|
||||
return imageData;
|
||||
}
|
||||
|
||||
public get Array(): IMediaData[] {
|
||||
public get Array(): readonly IMediaData[] {
|
||||
const array = new Array<IMediaData>();
|
||||
|
||||
this.map.forEach((data) => {
|
||||
|
@ -7,7 +7,7 @@ import { AlignmentType, EmphasisMarkType, TabStopPosition } from "../paragraph";
|
||||
import { UnderlineType } from "../paragraph/run/underline";
|
||||
import { ShadingType } from "../table";
|
||||
import { AbstractNumbering } from "./abstract-numbering";
|
||||
import { LevelSuffix } from "./level";
|
||||
import { LevelFormat, LevelSuffix } from "./level";
|
||||
|
||||
describe("AbstractNumbering", () => {
|
||||
it("stores its ID at its .id property", () => {
|
||||
@ -20,7 +20,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 3,
|
||||
format: "lowerLetter",
|
||||
format: LevelFormat.LOWER_LETTER,
|
||||
text: "%1)",
|
||||
alignment: AlignmentType.END,
|
||||
},
|
||||
@ -29,7 +29,7 @@ describe("AbstractNumbering", () => {
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ _attr: { "w:ilvl": 3, "w15:tentative": 1 } });
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:start": { _attr: { "w:val": 1 } } });
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:lvlJc": { _attr: { "w:val": "end" } } });
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:numFmt": { _attr: { "w:val": "lowerLetter" } } });
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:numFmt": { _attr: { "w:val": LevelFormat.LOWER_LETTER } } });
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:lvlText": { _attr: { "w:val": "%1)" } } });
|
||||
});
|
||||
|
||||
@ -37,7 +37,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 3,
|
||||
format: "lowerLetter",
|
||||
format: LevelFormat.LOWER_LETTER,
|
||||
text: "%1)",
|
||||
},
|
||||
]);
|
||||
@ -45,7 +45,7 @@ describe("AbstractNumbering", () => {
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ _attr: { "w:ilvl": 3, "w15:tentative": 1 } });
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:start": { _attr: { "w:val": 1 } } });
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:lvlJc": { _attr: { "w:val": "start" } } });
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:numFmt": { _attr: { "w:val": "lowerLetter" } } });
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:numFmt": { _attr: { "w:val": LevelFormat.LOWER_LETTER } } });
|
||||
expect(tree["w:abstractNum"][2]["w:lvl"]).to.include({ "w:lvlText": { _attr: { "w:val": "%1)" } } });
|
||||
});
|
||||
|
||||
@ -53,7 +53,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 3,
|
||||
format: "lowerLetter",
|
||||
format: LevelFormat.LOWER_LETTER,
|
||||
text: "%1)",
|
||||
alignment: AlignmentType.END,
|
||||
suffix: LevelSuffix.SPACE,
|
||||
@ -68,7 +68,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
paragraph: {
|
||||
@ -87,7 +87,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
paragraph: {
|
||||
@ -106,7 +106,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
paragraph: {
|
||||
@ -125,7 +125,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
paragraph: {
|
||||
@ -144,7 +144,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
paragraph: {
|
||||
@ -163,7 +163,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
paragraph: {
|
||||
@ -182,7 +182,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
paragraph: {
|
||||
@ -216,7 +216,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
paragraph: {
|
||||
@ -239,7 +239,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
paragraph: {
|
||||
@ -262,7 +262,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
paragraph: {
|
||||
@ -281,7 +281,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
paragraph: {
|
||||
@ -324,7 +324,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: { size, sizeComplexScript },
|
||||
@ -340,7 +340,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -359,7 +359,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -378,7 +378,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -398,7 +398,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -417,7 +417,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -436,7 +436,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -455,7 +455,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -485,7 +485,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -533,7 +533,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: { bold, boldComplexScript },
|
||||
@ -566,7 +566,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: { italics, italicsComplexScript },
|
||||
@ -604,7 +604,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: { highlight, highlightComplexScript },
|
||||
@ -682,7 +682,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: { shadow, shading, shadingComplexScript },
|
||||
@ -699,7 +699,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -718,7 +718,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -739,7 +739,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -763,7 +763,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -782,7 +782,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
@ -804,7 +804,7 @@ describe("AbstractNumbering", () => {
|
||||
const abstractNumbering = new AbstractNumbering(1, [
|
||||
{
|
||||
level: 0,
|
||||
format: "lowerRoman",
|
||||
format: LevelFormat.LOWER_ROMAN,
|
||||
text: "%0.",
|
||||
style: {
|
||||
run: {
|
||||
|
@ -1,8 +1,26 @@
|
||||
// http://officeopenxml.com/WPnumbering-numFmt.php
|
||||
import { Attributes, XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
import { AlignmentType } from "../paragraph/formatting";
|
||||
import { IParagraphStylePropertiesOptions, ParagraphProperties } from "../paragraph/properties";
|
||||
import { IRunStylePropertiesOptions, RunProperties } from "../paragraph/run/properties";
|
||||
|
||||
export enum LevelFormat {
|
||||
BULLET = "bullet",
|
||||
CARDINAL_TEXT = "cardinalText",
|
||||
CHICAGO = "chicago",
|
||||
DECIMAL = "decimal",
|
||||
DECIMAL_ENCLOSED_CIRCLE = "decimalEnclosedCircle",
|
||||
DECIMAL_ENCLOSED_FULLSTOP = "decimalEnclosedFullstop",
|
||||
DECIMAL_ENCLOSED_PARENTHESES = "decimalEnclosedParen",
|
||||
DECIMAL_ZERO = "decimalZero",
|
||||
LOWER_LETTER = "lowerLetter",
|
||||
LOWER_ROMAN = "lowerRoman",
|
||||
NONE = "none",
|
||||
ORDINAL_TEXT = "ordinalText",
|
||||
UPPER_LETTER = "upperLetter",
|
||||
UPPER_ROMAN = "upperRoman",
|
||||
}
|
||||
|
||||
interface ILevelAttributesProperties {
|
||||
readonly ilvl?: number;
|
||||
readonly tentative?: number;
|
||||
@ -67,7 +85,7 @@ export enum LevelSuffix {
|
||||
|
||||
export interface ILevelsOptions {
|
||||
readonly level: number;
|
||||
readonly format?: string;
|
||||
readonly format?: LevelFormat;
|
||||
readonly text?: string;
|
||||
readonly alignment?: AlignmentType;
|
||||
readonly start?: number;
|
||||
|
@ -1,10 +1,11 @@
|
||||
// http://officeopenxml.com/WPnumbering.php
|
||||
import { convertInchesToTwip } from "convenience-functions";
|
||||
import { AlignmentType } from "file/paragraph";
|
||||
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
||||
|
||||
import { DocumentAttributes } from "../document/document-attributes";
|
||||
import { AbstractNumbering } from "./abstract-numbering";
|
||||
import { ILevelsOptions } from "./level";
|
||||
import { ILevelsOptions, LevelFormat } from "./level";
|
||||
import { ConcreteNumbering } from "./num";
|
||||
|
||||
export interface INumberingOptions {
|
||||
@ -50,100 +51,100 @@ export class Numbering extends XmlComponent {
|
||||
const abstractNumbering = this.createAbstractNumbering([
|
||||
{
|
||||
level: 0,
|
||||
format: "bullet",
|
||||
format: LevelFormat.BULLET,
|
||||
text: "\u25CF",
|
||||
alignment: AlignmentType.LEFT,
|
||||
style: {
|
||||
paragraph: {
|
||||
indent: { left: 720, hanging: 360 },
|
||||
indent: { left: convertInchesToTwip(0.5), hanging: convertInchesToTwip(0.25) },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
level: 1,
|
||||
format: "bullet",
|
||||
format: LevelFormat.BULLET,
|
||||
text: "\u25CB",
|
||||
alignment: AlignmentType.LEFT,
|
||||
style: {
|
||||
paragraph: {
|
||||
indent: { left: 1440, hanging: 360 },
|
||||
indent: { left: convertInchesToTwip(1), hanging: convertInchesToTwip(0.25) },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
level: 2,
|
||||
format: "bullet",
|
||||
format: LevelFormat.BULLET,
|
||||
text: "\u25A0",
|
||||
alignment: AlignmentType.LEFT,
|
||||
style: {
|
||||
paragraph: {
|
||||
indent: { left: 2160, hanging: 360 },
|
||||
indent: { left: 2160, hanging: convertInchesToTwip(0.25) },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
level: 3,
|
||||
format: "bullet",
|
||||
format: LevelFormat.BULLET,
|
||||
text: "\u25CF",
|
||||
alignment: AlignmentType.LEFT,
|
||||
style: {
|
||||
paragraph: {
|
||||
indent: { left: 2880, hanging: 360 },
|
||||
indent: { left: 2880, hanging: convertInchesToTwip(0.25) },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
level: 4,
|
||||
format: "bullet",
|
||||
format: LevelFormat.BULLET,
|
||||
text: "\u25CB",
|
||||
alignment: AlignmentType.LEFT,
|
||||
style: {
|
||||
paragraph: {
|
||||
indent: { left: 3600, hanging: 360 },
|
||||
indent: { left: 3600, hanging: convertInchesToTwip(0.25) },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
level: 5,
|
||||
format: "bullet",
|
||||
format: LevelFormat.BULLET,
|
||||
text: "\u25A0",
|
||||
alignment: AlignmentType.LEFT,
|
||||
style: {
|
||||
paragraph: {
|
||||
indent: { left: 4320, hanging: 360 },
|
||||
indent: { left: 4320, hanging: convertInchesToTwip(0.25) },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
level: 6,
|
||||
format: "bullet",
|
||||
format: LevelFormat.BULLET,
|
||||
text: "\u25CF",
|
||||
alignment: AlignmentType.LEFT,
|
||||
style: {
|
||||
paragraph: {
|
||||
indent: { left: 5040, hanging: 360 },
|
||||
indent: { left: 5040, hanging: convertInchesToTwip(0.25) },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
level: 7,
|
||||
format: "bullet",
|
||||
format: LevelFormat.BULLET,
|
||||
text: "\u25CF",
|
||||
alignment: AlignmentType.LEFT,
|
||||
style: {
|
||||
paragraph: {
|
||||
indent: { left: 5760, hanging: 360 },
|
||||
indent: { left: 5760, hanging: convertInchesToTwip(0.25) },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
level: 8,
|
||||
format: "bullet",
|
||||
format: LevelFormat.BULLET,
|
||||
text: "\u25CF",
|
||||
alignment: AlignmentType.LEFT,
|
||||
style: {
|
||||
paragraph: {
|
||||
indent: { left: 6480, hanging: 360 },
|
||||
indent: { left: 6480, hanging: convertInchesToTwip(0.25) },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -3,3 +3,4 @@ export * from "./paragraph";
|
||||
export * from "./properties";
|
||||
export * from "./run";
|
||||
export * from "./links";
|
||||
export * from "./math";
|
||||
|
@ -2,14 +2,20 @@ import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { Hyperlink } from "./";
|
||||
import { HyperlinkRef } from "./hyperlink";
|
||||
import { TextRun } from "../run";
|
||||
import { ConcreteHyperlink, ExternalHyperlink, InternalHyperlink } from "./hyperlink";
|
||||
|
||||
describe("Hyperlink", () => {
|
||||
let hyperlink: Hyperlink;
|
||||
describe("ConcreteHyperlink", () => {
|
||||
let hyperlink: ConcreteHyperlink;
|
||||
|
||||
beforeEach(() => {
|
||||
hyperlink = new Hyperlink("https://example.com", "superid");
|
||||
hyperlink = new ConcreteHyperlink(
|
||||
new TextRun({
|
||||
text: "https://example.com",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
"superid",
|
||||
);
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
@ -35,7 +41,14 @@ describe("Hyperlink", () => {
|
||||
|
||||
describe("with optional anchor parameter", () => {
|
||||
beforeEach(() => {
|
||||
hyperlink = new Hyperlink("Anchor Text", "superid2", "anchor");
|
||||
hyperlink = new ConcreteHyperlink(
|
||||
new TextRun({
|
||||
text: "Anchor Text",
|
||||
style: "Hyperlink",
|
||||
}),
|
||||
"superid2",
|
||||
"anchor",
|
||||
);
|
||||
});
|
||||
|
||||
it("should create an internal link with anchor tag", () => {
|
||||
@ -61,10 +74,53 @@ describe("Hyperlink", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("HyperlinkRef", () => {
|
||||
describe("ExternalHyperlink", () => {
|
||||
describe("#constructor()", () => {
|
||||
const hyperlinkRef = new HyperlinkRef("test-id");
|
||||
it("should create", () => {
|
||||
const externalHyperlink = new ExternalHyperlink({
|
||||
child: new TextRun("test"),
|
||||
link: "http://www.google.com",
|
||||
});
|
||||
|
||||
expect(hyperlinkRef.id).to.equal("test-id");
|
||||
expect(externalHyperlink.options.link).to.equal("http://www.google.com");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("InternalHyperlink", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create", () => {
|
||||
const internalHyperlink = new InternalHyperlink({
|
||||
child: new TextRun("test"),
|
||||
anchor: "test-id",
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(internalHyperlink);
|
||||
|
||||
expect(tree).to.deep.equal({
|
||||
"w:hyperlink": [
|
||||
{
|
||||
_attr: {
|
||||
"w:anchor": "test-id",
|
||||
"w:history": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
"w:r": [
|
||||
{
|
||||
"w:t": [
|
||||
{
|
||||
_attr: {
|
||||
"xml:space": "preserve",
|
||||
},
|
||||
},
|
||||
"test",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,9 @@
|
||||
// http://officeopenxml.com/WPhyperlink.php
|
||||
import * as shortid from "shortid";
|
||||
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { TextRun } from "../run";
|
||||
|
||||
import { ParagraphChild } from "../paragraph";
|
||||
import { HyperlinkAttributes, IHyperlinkAttributesProperties } from "./hyperlink-attributes";
|
||||
|
||||
export enum HyperlinkType {
|
||||
@ -8,15 +11,10 @@ export enum HyperlinkType {
|
||||
EXTERNAL = "EXTERNAL",
|
||||
}
|
||||
|
||||
export class HyperlinkRef {
|
||||
constructor(public readonly id: string) {}
|
||||
}
|
||||
|
||||
export class Hyperlink extends XmlComponent {
|
||||
export class ConcreteHyperlink extends XmlComponent {
|
||||
public readonly linkId: string;
|
||||
private readonly textRun: TextRun;
|
||||
|
||||
constructor(text: string, relationshipId: string, anchor?: string) {
|
||||
constructor(child: ParagraphChild, relationshipId: string, anchor?: string) {
|
||||
super("w:hyperlink");
|
||||
|
||||
this.linkId = relationshipId;
|
||||
@ -29,14 +27,16 @@ export class Hyperlink extends XmlComponent {
|
||||
|
||||
const attributes = new HyperlinkAttributes(props);
|
||||
this.root.push(attributes);
|
||||
this.textRun = new TextRun({
|
||||
text: text,
|
||||
style: "Hyperlink",
|
||||
});
|
||||
this.root.push(this.textRun);
|
||||
}
|
||||
|
||||
public get TextRun(): TextRun {
|
||||
return this.textRun;
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
export class InternalHyperlink extends ConcreteHyperlink {
|
||||
constructor(options: { readonly child: ParagraphChild; readonly anchor: string }) {
|
||||
super(options.child, shortid.generate().toLowerCase(), options.anchor);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExternalHyperlink {
|
||||
constructor(public readonly options: { readonly child: ParagraphChild; readonly link: string }) {}
|
||||
}
|
||||
|
4
src/file/paragraph/math/brackets/index.ts
Normal file
4
src/file/paragraph/math/brackets/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from "./math-round-brackets";
|
||||
export * from "./math-square-brackets";
|
||||
export * from "./math-curly-brackets";
|
||||
export * from "./math-angled-brackets";
|
@ -0,0 +1,51 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathAngledBrackets } from "./math-angled-brackets";
|
||||
|
||||
describe("MathAngledBrackets", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathAngledBrackets with correct root key", () => {
|
||||
const mathAngledBrackets = new MathAngledBrackets({
|
||||
children: [new MathRun("60")],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(mathAngledBrackets);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:d": [
|
||||
{
|
||||
"m:dPr": [
|
||||
{
|
||||
"m:begChr": {
|
||||
_attr: {
|
||||
"m:val": "〈",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:endChr": {
|
||||
_attr: {
|
||||
"m:val": "〉",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"m:e": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["60"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
20
src/file/paragraph/math/brackets/math-angled-brackets.ts
Normal file
20
src/file/paragraph/math/brackets/math-angled-brackets.ts
Normal file
@ -0,0 +1,20 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_d-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
import { MathBase } from "../n-ary";
|
||||
import { MathBracketProperties } from "./math-bracket-properties";
|
||||
|
||||
export class MathAngledBrackets extends XmlComponent {
|
||||
constructor(options: { readonly children: MathComponent[] }) {
|
||||
super("m:d");
|
||||
|
||||
this.root.push(
|
||||
new MathBracketProperties({
|
||||
beginningCharacter: "〈",
|
||||
endingCharacter: "〉",
|
||||
}),
|
||||
);
|
||||
this.root.push(new MathBase(options.children));
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathBeginningCharacter } from "./math-beginning-character";
|
||||
|
||||
describe("MathBeginningCharacter", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathBeginningCharacter with correct root key", () => {
|
||||
const mathBeginningCharacter = new MathBeginningCharacter("[");
|
||||
|
||||
const tree = new Formatter().format(mathBeginningCharacter);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:begChr": {
|
||||
_attr: {
|
||||
"m:val": "[",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
14
src/file/paragraph/math/brackets/math-beginning-character.ts
Normal file
14
src/file/paragraph/math/brackets/math-beginning-character.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_begChr-1.html
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
class MathBeginningCharacterAttributes extends XmlAttributeComponent<{ readonly character: string }> {
|
||||
protected readonly xmlKeys = { character: "m:val" };
|
||||
}
|
||||
|
||||
export class MathBeginningCharacter extends XmlComponent {
|
||||
constructor(character: string) {
|
||||
super("m:begChr");
|
||||
|
||||
this.root.push(new MathBeginningCharacterAttributes({ character }));
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathBracketProperties } from "./math-bracket-properties";
|
||||
|
||||
describe("MathBracketProperties", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathBracketProperties with correct root key", () => {
|
||||
const mathBracketProperties = new MathBracketProperties();
|
||||
|
||||
const tree = new Formatter().format(mathBracketProperties);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:dPr": {},
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a MathBracketProperties with correct root key and add brackets", () => {
|
||||
const mathBracketProperties = new MathBracketProperties({
|
||||
beginningCharacter: "[",
|
||||
endingCharacter: "]",
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(mathBracketProperties);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:dPr": [
|
||||
{
|
||||
"m:begChr": {
|
||||
_attr: {
|
||||
"m:val": "[",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:endChr": {
|
||||
_attr: {
|
||||
"m:val": "]",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
16
src/file/paragraph/math/brackets/math-bracket-properties.ts
Normal file
16
src/file/paragraph/math/brackets/math-bracket-properties.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_dPr-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathBeginningCharacter } from "./math-beginning-character";
|
||||
import { MathEndingCharacter } from "./math-ending-char";
|
||||
|
||||
export class MathBracketProperties extends XmlComponent {
|
||||
constructor(options?: { readonly beginningCharacter: string; readonly endingCharacter: string }) {
|
||||
super("m:dPr");
|
||||
|
||||
if (!!options) {
|
||||
this.root.push(new MathBeginningCharacter(options.beginningCharacter));
|
||||
this.root.push(new MathEndingCharacter(options.endingCharacter));
|
||||
}
|
||||
}
|
||||
}
|
51
src/file/paragraph/math/brackets/math-curly-brackets.spec.ts
Normal file
51
src/file/paragraph/math/brackets/math-curly-brackets.spec.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathCurlyBrackets } from "./math-curly-brackets";
|
||||
|
||||
describe("MathCurlyBrackets", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathCurlyBrackets with correct root key", () => {
|
||||
const mathCurlyBrackets = new MathCurlyBrackets({
|
||||
children: [new MathRun("60")],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(mathCurlyBrackets);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:d": [
|
||||
{
|
||||
"m:dPr": [
|
||||
{
|
||||
"m:begChr": {
|
||||
_attr: {
|
||||
"m:val": "{",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:endChr": {
|
||||
_attr: {
|
||||
"m:val": "}",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"m:e": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["60"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
20
src/file/paragraph/math/brackets/math-curly-brackets.ts
Normal file
20
src/file/paragraph/math/brackets/math-curly-brackets.ts
Normal file
@ -0,0 +1,20 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_d-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
import { MathBase } from "../n-ary";
|
||||
import { MathBracketProperties } from "./math-bracket-properties";
|
||||
|
||||
export class MathCurlyBrackets extends XmlComponent {
|
||||
constructor(options: { readonly children: MathComponent[] }) {
|
||||
super("m:d");
|
||||
|
||||
this.root.push(
|
||||
new MathBracketProperties({
|
||||
beginningCharacter: "{",
|
||||
endingCharacter: "}",
|
||||
}),
|
||||
);
|
||||
this.root.push(new MathBase(options.children));
|
||||
}
|
||||
}
|
14
src/file/paragraph/math/brackets/math-ending-char.ts
Normal file
14
src/file/paragraph/math/brackets/math-ending-char.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_endChr-1.html
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
class MathEndingCharacterAttributes extends XmlAttributeComponent<{ readonly character: string }> {
|
||||
protected readonly xmlKeys = { character: "m:val" };
|
||||
}
|
||||
|
||||
export class MathEndingCharacter extends XmlComponent {
|
||||
constructor(character: string) {
|
||||
super("m:endChr");
|
||||
|
||||
this.root.push(new MathEndingCharacterAttributes({ character }));
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathEndingCharacter } from "./math-ending-char";
|
||||
|
||||
describe("MathEndingCharacter", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathEndingCharacter with correct root key", () => {
|
||||
const mathEndingCharacter = new MathEndingCharacter("]");
|
||||
|
||||
const tree = new Formatter().format(mathEndingCharacter);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:endChr": {
|
||||
_attr: {
|
||||
"m:val": "]",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
36
src/file/paragraph/math/brackets/math-round-brackets.spec.ts
Normal file
36
src/file/paragraph/math/brackets/math-round-brackets.spec.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathRoundBrackets } from "./math-round-brackets";
|
||||
|
||||
describe("MathRoundBrackets", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathRoundBrackets with correct root key", () => {
|
||||
const mathRoundBrackets = new MathRoundBrackets({
|
||||
children: [new MathRun("60")],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(mathRoundBrackets);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:d": [
|
||||
{
|
||||
"m:dPr": {},
|
||||
},
|
||||
{
|
||||
"m:e": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["60"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
15
src/file/paragraph/math/brackets/math-round-brackets.ts
Normal file
15
src/file/paragraph/math/brackets/math-round-brackets.ts
Normal file
@ -0,0 +1,15 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_d-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
import { MathBase } from "../n-ary";
|
||||
import { MathBracketProperties } from "./math-bracket-properties";
|
||||
|
||||
export class MathRoundBrackets extends XmlComponent {
|
||||
constructor(options: { readonly children: MathComponent[] }) {
|
||||
super("m:d");
|
||||
|
||||
this.root.push(new MathBracketProperties());
|
||||
this.root.push(new MathBase(options.children));
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathSquareBrackets } from "./math-square-brackets";
|
||||
|
||||
describe("MathSquareBrackets", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathSquareBrackets with correct root key", () => {
|
||||
const mathSquareBrackets = new MathSquareBrackets({
|
||||
children: [new MathRun("60")],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(mathSquareBrackets);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:d": [
|
||||
{
|
||||
"m:dPr": [
|
||||
{
|
||||
"m:begChr": {
|
||||
_attr: {
|
||||
"m:val": "[",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:endChr": {
|
||||
_attr: {
|
||||
"m:val": "]",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"m:e": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["60"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
20
src/file/paragraph/math/brackets/math-square-brackets.ts
Normal file
20
src/file/paragraph/math/brackets/math-square-brackets.ts
Normal file
@ -0,0 +1,20 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_d-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
import { MathBase } from "../n-ary";
|
||||
import { MathBracketProperties } from "./math-bracket-properties";
|
||||
|
||||
export class MathSquareBrackets extends XmlComponent {
|
||||
constructor(options: { readonly children: MathComponent[] }) {
|
||||
super("m:d");
|
||||
|
||||
this.root.push(
|
||||
new MathBracketProperties({
|
||||
beginningCharacter: "[",
|
||||
endingCharacter: "]",
|
||||
}),
|
||||
);
|
||||
this.root.push(new MathBase(options.children));
|
||||
}
|
||||
}
|
3
src/file/paragraph/math/fraction/index.ts
Normal file
3
src/file/paragraph/math/fraction/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from "./math-fraction";
|
||||
export * from "./math-denominator";
|
||||
export * from "./math-numerator";
|
26
src/file/paragraph/math/fraction/math-denominator.spec.ts
Normal file
26
src/file/paragraph/math/fraction/math-denominator.spec.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathDenominator } from "./math-denominator";
|
||||
|
||||
describe("MathDenominator", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathDenominator with correct root key", () => {
|
||||
const mathDenominator = new MathDenominator([new MathRun("2+2")]);
|
||||
const tree = new Formatter().format(mathDenominator);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:den": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2+2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
13
src/file/paragraph/math/fraction/math-denominator.ts
Normal file
13
src/file/paragraph/math/fraction/math-denominator.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
|
||||
export class MathDenominator extends XmlComponent {
|
||||
constructor(children: MathComponent[]) {
|
||||
super("m:den");
|
||||
|
||||
for (const child of children) {
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
}
|
44
src/file/paragraph/math/fraction/math-fraction.spec.ts
Normal file
44
src/file/paragraph/math/fraction/math-fraction.spec.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathFraction } from "./math-fraction";
|
||||
|
||||
describe("MathFraction", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathFraction with correct root key", () => {
|
||||
const mathFraction = new MathFraction({
|
||||
numerator: [new MathRun("2")],
|
||||
denominator: [new MathRun("2")],
|
||||
});
|
||||
const tree = new Formatter().format(mathFraction);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:f": [
|
||||
{
|
||||
"m:num": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"m:den": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
19
src/file/paragraph/math/fraction/math-fraction.ts
Normal file
19
src/file/paragraph/math/fraction/math-fraction.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
import { MathDenominator } from "./math-denominator";
|
||||
import { MathNumerator } from "./math-numerator";
|
||||
|
||||
export interface IMathFractionOptions {
|
||||
readonly numerator: MathComponent[];
|
||||
readonly denominator: MathComponent[];
|
||||
}
|
||||
|
||||
export class MathFraction extends XmlComponent {
|
||||
constructor(options: IMathFractionOptions) {
|
||||
super("m:f");
|
||||
|
||||
this.root.push(new MathNumerator(options.numerator));
|
||||
this.root.push(new MathDenominator(options.denominator));
|
||||
}
|
||||
}
|
26
src/file/paragraph/math/fraction/math-numerator.spec.ts
Normal file
26
src/file/paragraph/math/fraction/math-numerator.spec.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathNumerator } from "./math-numerator";
|
||||
|
||||
describe("MathNumerator", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathNumerator with correct root key", () => {
|
||||
const mathNumerator = new MathNumerator([new MathRun("2+2")]);
|
||||
const tree = new Formatter().format(mathNumerator);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:num": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2+2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
13
src/file/paragraph/math/fraction/math-numerator.ts
Normal file
13
src/file/paragraph/math/fraction/math-numerator.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
|
||||
export class MathNumerator extends XmlComponent {
|
||||
constructor(children: MathComponent[]) {
|
||||
super("m:num");
|
||||
|
||||
for (const child of children) {
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
}
|
3
src/file/paragraph/math/function/index.ts
Normal file
3
src/file/paragraph/math/function/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from "./math-function";
|
||||
export * from "./math-function-name";
|
||||
export * from "./math-function-properties";
|
27
src/file/paragraph/math/function/math-function-name.spec.ts
Normal file
27
src/file/paragraph/math/function/math-function-name.spec.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathFunctionName } from "./math-function-name";
|
||||
|
||||
describe("MathFunctionName", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathFunctionName with correct root key", () => {
|
||||
const mathFunctionName = new MathFunctionName([new MathRun("2")]);
|
||||
|
||||
const tree = new Formatter().format(mathFunctionName);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:fName": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
13
src/file/paragraph/math/function/math-function-name.ts
Normal file
13
src/file/paragraph/math/function/math-function-name.ts
Normal file
@ -0,0 +1,13 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_fName-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { MathComponent } from "../math-component";
|
||||
|
||||
export class MathFunctionName extends XmlComponent {
|
||||
constructor(children: MathComponent[]) {
|
||||
super("m:fName");
|
||||
|
||||
for (const child of children) {
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathFunctionProperties } from "./math-function-properties";
|
||||
|
||||
describe("MathFunctionProperties", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathFunctionProperties with correct root key", () => {
|
||||
const mathFunctionProperties = new MathFunctionProperties();
|
||||
|
||||
const tree = new Formatter().format(mathFunctionProperties);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:funcPr": {},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,8 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_radPr-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
export class MathFunctionProperties extends XmlComponent {
|
||||
constructor() {
|
||||
super("m:funcPr");
|
||||
}
|
||||
}
|
48
src/file/paragraph/math/function/math-function.spec.ts
Normal file
48
src/file/paragraph/math/function/math-function.spec.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathFunction } from "./math-function";
|
||||
|
||||
describe("MathFunction", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathFunction with correct root key", () => {
|
||||
const mathFunction = new MathFunction({
|
||||
name: [new MathRun("sin")],
|
||||
children: [new MathRun("60")],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(mathFunction);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:func": [
|
||||
{
|
||||
"m:funcPr": {},
|
||||
},
|
||||
{
|
||||
"m:fName": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["sin"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"m:e": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["60"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
22
src/file/paragraph/math/function/math-function.ts
Normal file
22
src/file/paragraph/math/function/math-function.ts
Normal file
@ -0,0 +1,22 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_func-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
import { MathBase } from "../n-ary";
|
||||
import { MathFunctionName } from "./math-function-name";
|
||||
import { MathFunctionProperties } from "./math-function-properties";
|
||||
|
||||
export interface IMathFunctionOptions {
|
||||
readonly children: MathComponent[];
|
||||
readonly name: MathComponent[];
|
||||
}
|
||||
|
||||
export class MathFunction extends XmlComponent {
|
||||
constructor(options: IMathFunctionOptions) {
|
||||
super("m:func");
|
||||
|
||||
this.root.push(new MathFunctionProperties());
|
||||
this.root.push(new MathFunctionName(options.name));
|
||||
this.root.push(new MathBase(options.children));
|
||||
}
|
||||
}
|
9
src/file/paragraph/math/index.ts
Normal file
9
src/file/paragraph/math/index.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export * from "./math";
|
||||
export * from "./math-run";
|
||||
export * from "./fraction";
|
||||
export * from "./n-ary";
|
||||
export * from "./script";
|
||||
export * from "./math-component";
|
||||
export * from "./radical";
|
||||
export * from "./function";
|
||||
export * from "./brackets";
|
27
src/file/paragraph/math/math-component.ts
Normal file
27
src/file/paragraph/math/math-component.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { MathAngledBrackets, MathCurlyBrackets, MathRoundBrackets, MathSquareBrackets } from "./brackets";
|
||||
import { MathFraction } from "./fraction";
|
||||
import { MathFunction } from "./function";
|
||||
import { MathRun } from "./math-run";
|
||||
import { MathSum } from "./n-ary";
|
||||
import { MathRadical } from "./radical";
|
||||
import { MathSubScript, MathSubSuperScript, MathSuperScript } from "./script";
|
||||
|
||||
export type MathComponent =
|
||||
| MathRun
|
||||
| MathFraction
|
||||
| MathSum
|
||||
| MathSuperScript
|
||||
| MathSubScript
|
||||
| MathSubSuperScript
|
||||
| MathRadical
|
||||
| MathFunction
|
||||
| MathRoundBrackets
|
||||
| MathCurlyBrackets
|
||||
| MathAngledBrackets
|
||||
| MathSquareBrackets;
|
||||
|
||||
// Needed because of: https://github.com/s-panferov/awesome-typescript-loader/issues/432
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
export const WORKAROUND4 = "";
|
21
src/file/paragraph/math/math-run.spec.ts
Normal file
21
src/file/paragraph/math/math-run.spec.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "./math-run";
|
||||
|
||||
describe("MathRun", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathRun with correct root key", () => {
|
||||
const mathRun = new MathRun("2+2");
|
||||
const tree = new Formatter().format(mathRun);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2+2"],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
12
src/file/paragraph/math/math-run.ts
Normal file
12
src/file/paragraph/math/math-run.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_r-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathText } from "./math-text";
|
||||
|
||||
export class MathRun extends XmlComponent {
|
||||
constructor(text: string) {
|
||||
super("m:r");
|
||||
|
||||
this.root.push(new MathText(text));
|
||||
}
|
||||
}
|
17
src/file/paragraph/math/math-text.spec.ts
Normal file
17
src/file/paragraph/math/math-text.spec.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathText } from "./math-text";
|
||||
|
||||
describe("MathText", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathText with correct root key", () => {
|
||||
const mathText = new MathText("2+2");
|
||||
const tree = new Formatter().format(mathText);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:t": ["2+2"],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
9
src/file/paragraph/math/math-text.ts
Normal file
9
src/file/paragraph/math/math-text.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
export class MathText extends XmlComponent {
|
||||
constructor(text: string) {
|
||||
super("m:t");
|
||||
|
||||
this.root.push(text);
|
||||
}
|
||||
}
|
38
src/file/paragraph/math/math.spec.ts
Normal file
38
src/file/paragraph/math/math.spec.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { Math } from "./math";
|
||||
import { MathRun } from "./math-run";
|
||||
|
||||
describe("Math", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a Math with correct root key", () => {
|
||||
const math = new Math({
|
||||
children: [],
|
||||
});
|
||||
const tree = new Formatter().format(math);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:oMath": {},
|
||||
});
|
||||
});
|
||||
|
||||
it("should be able to add children", () => {
|
||||
const math = new Math({
|
||||
children: [new MathRun("2+2")],
|
||||
});
|
||||
const tree = new Formatter().format(math);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:oMath": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2+2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
18
src/file/paragraph/math/math.ts
Normal file
18
src/file/paragraph/math/math.ts
Normal file
@ -0,0 +1,18 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_oMath-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "./math-component";
|
||||
|
||||
export interface IMathOptions {
|
||||
readonly children: MathComponent[];
|
||||
}
|
||||
|
||||
export class Math extends XmlComponent {
|
||||
constructor(options: IMathOptions) {
|
||||
super("m:oMath");
|
||||
|
||||
for (const child of options.children) {
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
}
|
7
src/file/paragraph/math/n-ary/index.ts
Normal file
7
src/file/paragraph/math/n-ary/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export * from "./math-accent-character";
|
||||
export * from "./math-base";
|
||||
export * from "./math-limit-location";
|
||||
export * from "./math-naray-properties";
|
||||
export * from "./math-sub-script";
|
||||
export * from "./math-sum";
|
||||
export * from "./math-super-script";
|
22
src/file/paragraph/math/n-ary/math-accent-character.spec.ts
Normal file
22
src/file/paragraph/math/n-ary/math-accent-character.spec.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathAccentCharacter } from "./math-accent-character";
|
||||
|
||||
describe("MathAccentCharacter", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathAccentCharacter with correct root key", () => {
|
||||
const mathAccentCharacter = new MathAccentCharacter("∑");
|
||||
|
||||
const tree = new Formatter().format(mathAccentCharacter);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:chr": {
|
||||
_attr: {
|
||||
"m:val": "∑",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
14
src/file/paragraph/math/n-ary/math-accent-character.ts
Normal file
14
src/file/paragraph/math/n-ary/math-accent-character.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_chr-1.html
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
class MathAccentCharacterAttributes extends XmlAttributeComponent<{ readonly accent: string }> {
|
||||
protected readonly xmlKeys = { accent: "m:val" };
|
||||
}
|
||||
|
||||
export class MathAccentCharacter extends XmlComponent {
|
||||
constructor(accent: string) {
|
||||
super("m:chr");
|
||||
|
||||
this.root.push(new MathAccentCharacterAttributes({ accent }));
|
||||
}
|
||||
}
|
27
src/file/paragraph/math/n-ary/math-base.spec.ts
Normal file
27
src/file/paragraph/math/n-ary/math-base.spec.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathBase } from "./math-base";
|
||||
|
||||
describe("MathBase", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathBase with correct root key", () => {
|
||||
const mathBase = new MathBase([new MathRun("2+2")]);
|
||||
|
||||
const tree = new Formatter().format(mathBase);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:e": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2+2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
14
src/file/paragraph/math/n-ary/math-base.ts
Normal file
14
src/file/paragraph/math/n-ary/math-base.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_e-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
|
||||
export class MathBase extends XmlComponent {
|
||||
constructor(children: MathComponent[]) {
|
||||
super("m:e");
|
||||
|
||||
for (const child of children) {
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
}
|
22
src/file/paragraph/math/n-ary/math-limit-location.spec.ts
Normal file
22
src/file/paragraph/math/n-ary/math-limit-location.spec.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathLimitLocation } from "./math-limit-location";
|
||||
|
||||
describe("MathLimitLocation", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathLimitLocation with correct root key", () => {
|
||||
const mathLimitLocation = new MathLimitLocation();
|
||||
|
||||
const tree = new Formatter().format(mathLimitLocation);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:limLoc": {
|
||||
_attr: {
|
||||
"m:val": "undOvr",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
14
src/file/paragraph/math/n-ary/math-limit-location.ts
Normal file
14
src/file/paragraph/math/n-ary/math-limit-location.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_limLoc-1.html
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
class MathLimitLocationAttributes extends XmlAttributeComponent<{ readonly value: string }> {
|
||||
protected readonly xmlKeys = { value: "m:val" };
|
||||
}
|
||||
|
||||
export class MathLimitLocation extends XmlComponent {
|
||||
constructor() {
|
||||
super("m:limLoc");
|
||||
|
||||
this.root.push(new MathLimitLocationAttributes({ value: "undOvr" }));
|
||||
}
|
||||
}
|
133
src/file/paragraph/math/n-ary/math-naray-properties.spec.ts
Normal file
133
src/file/paragraph/math/n-ary/math-naray-properties.spec.ts
Normal file
@ -0,0 +1,133 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathNArayProperties } from "./math-naray-properties";
|
||||
|
||||
describe("MathNArayProperties", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathNArayProperties with correct root key", () => {
|
||||
const mathNArayProperties = new MathNArayProperties("∑", true, true);
|
||||
|
||||
const tree = new Formatter().format(mathNArayProperties);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:naryPr": [
|
||||
{
|
||||
"m:chr": {
|
||||
_attr: {
|
||||
"m:val": "∑",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:limLoc": {
|
||||
_attr: {
|
||||
"m:val": "undOvr",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should add super-script hide attributes", () => {
|
||||
const mathNArayProperties = new MathNArayProperties("∑", false, true);
|
||||
|
||||
const tree = new Formatter().format(mathNArayProperties);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:naryPr": [
|
||||
{
|
||||
"m:chr": {
|
||||
_attr: {
|
||||
"m:val": "∑",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:limLoc": {
|
||||
_attr: {
|
||||
"m:val": "undOvr",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:supHide": {
|
||||
_attr: {
|
||||
"m:val": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should add sub-script hide attributes", () => {
|
||||
const mathNArayProperties = new MathNArayProperties("∑", true, false);
|
||||
|
||||
const tree = new Formatter().format(mathNArayProperties);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:naryPr": [
|
||||
{
|
||||
"m:chr": {
|
||||
_attr: {
|
||||
"m:val": "∑",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:limLoc": {
|
||||
_attr: {
|
||||
"m:val": "undOvr",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:subHide": {
|
||||
_attr: {
|
||||
"m:val": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should add both super-script and sub-script hide attributes", () => {
|
||||
const mathNArayProperties = new MathNArayProperties("∑", false, false);
|
||||
|
||||
const tree = new Formatter().format(mathNArayProperties);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:naryPr": [
|
||||
{
|
||||
"m:chr": {
|
||||
_attr: {
|
||||
"m:val": "∑",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:limLoc": {
|
||||
_attr: {
|
||||
"m:val": "undOvr",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:supHide": {
|
||||
_attr: {
|
||||
"m:val": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:subHide": {
|
||||
_attr: {
|
||||
"m:val": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
24
src/file/paragraph/math/n-ary/math-naray-properties.ts
Normal file
24
src/file/paragraph/math/n-ary/math-naray-properties.ts
Normal file
@ -0,0 +1,24 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_naryPr-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathAccentCharacter } from "./math-accent-character";
|
||||
import { MathLimitLocation } from "./math-limit-location";
|
||||
import { MathSubScriptHide } from "./math-sub-script-hide";
|
||||
import { MathSuperScriptHide } from "./math-super-script-hide";
|
||||
|
||||
export class MathNArayProperties extends XmlComponent {
|
||||
constructor(accent: string, hasSuperScript: boolean, hasSubScript: boolean) {
|
||||
super("m:naryPr");
|
||||
|
||||
this.root.push(new MathAccentCharacter(accent));
|
||||
this.root.push(new MathLimitLocation());
|
||||
|
||||
if (!hasSuperScript) {
|
||||
this.root.push(new MathSuperScriptHide());
|
||||
}
|
||||
|
||||
if (!hasSubScript) {
|
||||
this.root.push(new MathSubScriptHide());
|
||||
}
|
||||
}
|
||||
}
|
22
src/file/paragraph/math/n-ary/math-sub-script-hide.spec.ts
Normal file
22
src/file/paragraph/math/n-ary/math-sub-script-hide.spec.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathSubScriptHide } from "./math-sub-script-hide";
|
||||
|
||||
describe("MathSubScriptHide", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathSubScriptHide with correct root key", () => {
|
||||
const mathSubScriptHide = new MathSubScriptHide();
|
||||
|
||||
const tree = new Formatter().format(mathSubScriptHide);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:subHide": {
|
||||
_attr: {
|
||||
"m:val": 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
14
src/file/paragraph/math/n-ary/math-sub-script-hide.ts
Normal file
14
src/file/paragraph/math/n-ary/math-sub-script-hide.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_subHide-1.html
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
class MathSubScriptHideAttributes extends XmlAttributeComponent<{ readonly hide: number }> {
|
||||
protected readonly xmlKeys = { hide: "m:val" };
|
||||
}
|
||||
|
||||
export class MathSubScriptHide extends XmlComponent {
|
||||
constructor() {
|
||||
super("m:subHide");
|
||||
|
||||
this.root.push(new MathSubScriptHideAttributes({ hide: 1 }));
|
||||
}
|
||||
}
|
27
src/file/paragraph/math/n-ary/math-sub-script.spec.ts
Normal file
27
src/file/paragraph/math/n-ary/math-sub-script.spec.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathSubScriptElement } from "./math-sub-script";
|
||||
|
||||
describe("MathSubScriptElement", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathSubScriptElement with correct root key", () => {
|
||||
const mathSubScriptElement = new MathSubScriptElement([new MathRun("2+2")]);
|
||||
|
||||
const tree = new Formatter().format(mathSubScriptElement);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:sub": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2+2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
14
src/file/paragraph/math/n-ary/math-sub-script.ts
Normal file
14
src/file/paragraph/math/n-ary/math-sub-script.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_sub-3.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
|
||||
export class MathSubScriptElement extends XmlComponent {
|
||||
constructor(children: MathComponent[]) {
|
||||
super("m:sub");
|
||||
|
||||
for (const child of children) {
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
}
|
75
src/file/paragraph/math/n-ary/math-sum.spec.ts
Normal file
75
src/file/paragraph/math/n-ary/math-sum.spec.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathSum } from "./math-sum";
|
||||
|
||||
describe("MathSum", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathSum with correct root key", () => {
|
||||
const mathSum = new MathSum({
|
||||
children: [new MathRun("1")],
|
||||
subScript: [new MathRun("2")],
|
||||
superScript: [new MathRun("3")],
|
||||
});
|
||||
|
||||
const tree = new Formatter().format(mathSum);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:nary": [
|
||||
{
|
||||
"m:naryPr": [
|
||||
{
|
||||
"m:chr": {
|
||||
_attr: {
|
||||
"m:val": "∑",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"m:limLoc": {
|
||||
_attr: {
|
||||
"m:val": "undOvr",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"m:sub": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"m:sup": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["3"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"m:e": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["1"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
32
src/file/paragraph/math/n-ary/math-sum.ts
Normal file
32
src/file/paragraph/math/n-ary/math-sum.ts
Normal file
@ -0,0 +1,32 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_nary-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
import { MathBase } from "./math-base";
|
||||
import { MathNArayProperties } from "./math-naray-properties";
|
||||
import { MathSubScriptElement } from "./math-sub-script";
|
||||
import { MathSuperScriptElement } from "./math-super-script";
|
||||
|
||||
export interface IMathSumOptions {
|
||||
readonly children: MathComponent[];
|
||||
readonly subScript?: MathComponent[];
|
||||
readonly superScript?: MathComponent[];
|
||||
}
|
||||
|
||||
export class MathSum extends XmlComponent {
|
||||
constructor(options: IMathSumOptions) {
|
||||
super("m:nary");
|
||||
|
||||
this.root.push(new MathNArayProperties("∑", !!options.superScript, !!options.subScript));
|
||||
|
||||
if (!!options.subScript) {
|
||||
this.root.push(new MathSubScriptElement(options.subScript));
|
||||
}
|
||||
|
||||
if (!!options.superScript) {
|
||||
this.root.push(new MathSuperScriptElement(options.superScript));
|
||||
}
|
||||
|
||||
this.root.push(new MathBase(options.children));
|
||||
}
|
||||
}
|
22
src/file/paragraph/math/n-ary/math-super-script-hide.spec.ts
Normal file
22
src/file/paragraph/math/n-ary/math-super-script-hide.spec.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathSuperScriptHide } from "./math-super-script-hide";
|
||||
|
||||
describe("MathSuperScriptHide", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathSuperScriptHide with correct root key", () => {
|
||||
const mathSuperScriptHide = new MathSuperScriptHide();
|
||||
|
||||
const tree = new Formatter().format(mathSuperScriptHide);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:supHide": {
|
||||
_attr: {
|
||||
"m:val": 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
14
src/file/paragraph/math/n-ary/math-super-script-hide.ts
Normal file
14
src/file/paragraph/math/n-ary/math-super-script-hide.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_subHide-1.html
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
class MathSuperScriptHideAttributes extends XmlAttributeComponent<{ readonly hide: number }> {
|
||||
protected readonly xmlKeys = { hide: "m:val" };
|
||||
}
|
||||
|
||||
export class MathSuperScriptHide extends XmlComponent {
|
||||
constructor() {
|
||||
super("m:supHide");
|
||||
|
||||
this.root.push(new MathSuperScriptHideAttributes({ hide: 1 }));
|
||||
}
|
||||
}
|
27
src/file/paragraph/math/n-ary/math-super-script.spec.ts
Normal file
27
src/file/paragraph/math/n-ary/math-super-script.spec.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathSuperScriptElement } from "./math-super-script";
|
||||
|
||||
describe("MathSuperScriptElement", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathSuperScriptElement with correct root key", () => {
|
||||
const mathSuperScriptElement = new MathSuperScriptElement([new MathRun("2+2")]);
|
||||
|
||||
const tree = new Formatter().format(mathSuperScriptElement);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:sup": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2+2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
14
src/file/paragraph/math/n-ary/math-super-script.ts
Normal file
14
src/file/paragraph/math/n-ary/math-super-script.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_sup-3.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { MathComponent } from "../math-component";
|
||||
|
||||
export class MathSuperScriptElement extends XmlComponent {
|
||||
constructor(children: MathComponent[]) {
|
||||
super("m:sup");
|
||||
|
||||
for (const child of children) {
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
}
|
3
src/file/paragraph/math/radical/index.ts
Normal file
3
src/file/paragraph/math/radical/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from "./math-degree";
|
||||
export * from "./math-radical";
|
||||
export * from "./math-radical-properties";
|
22
src/file/paragraph/math/radical/math-degree-hide.spec.ts
Normal file
22
src/file/paragraph/math/radical/math-degree-hide.spec.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathDegreeHide } from "./math-degree-hide";
|
||||
|
||||
describe("MathDegreeHide", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathDegreeHide with correct root key", () => {
|
||||
const mathDegreeHide = new MathDegreeHide();
|
||||
|
||||
const tree = new Formatter().format(mathDegreeHide);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:degHide": {
|
||||
_attr: {
|
||||
"m:val": 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
14
src/file/paragraph/math/radical/math-degree-hide.ts
Normal file
14
src/file/paragraph/math/radical/math-degree-hide.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_degHide-1.html
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
class MathDegreeHideAttributes extends XmlAttributeComponent<{ readonly hide: number }> {
|
||||
protected readonly xmlKeys = { hide: "m:val" };
|
||||
}
|
||||
|
||||
export class MathDegreeHide extends XmlComponent {
|
||||
constructor() {
|
||||
super("m:degHide");
|
||||
|
||||
this.root.push(new MathDegreeHideAttributes({ hide: 1 }));
|
||||
}
|
||||
}
|
36
src/file/paragraph/math/radical/math-degree.spec.ts
Normal file
36
src/file/paragraph/math/radical/math-degree.spec.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "export/formatter";
|
||||
|
||||
import { MathRun } from "../math-run";
|
||||
import { MathDegree } from "./math-degree";
|
||||
|
||||
describe("MathDegree", () => {
|
||||
describe("#constructor()", () => {
|
||||
it("should create a MathDegree with correct root key", () => {
|
||||
const mathDegree = new MathDegree();
|
||||
|
||||
const tree = new Formatter().format(mathDegree);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:deg": {},
|
||||
});
|
||||
});
|
||||
|
||||
it("should create a MathDegree with correct root key with child", () => {
|
||||
const mathDegree = new MathDegree([new MathRun("2")]);
|
||||
|
||||
const tree = new Formatter().format(mathDegree);
|
||||
expect(tree).to.deep.equal({
|
||||
"m:deg": [
|
||||
{
|
||||
"m:r": [
|
||||
{
|
||||
"m:t": ["2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
15
src/file/paragraph/math/radical/math-degree.ts
Normal file
15
src/file/paragraph/math/radical/math-degree.ts
Normal file
@ -0,0 +1,15 @@
|
||||
// http://www.datypic.com/sc/ooxml/e-m_deg-1.html
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { MathComponent } from "../math-component";
|
||||
|
||||
export class MathDegree extends XmlComponent {
|
||||
constructor(children?: MathComponent[]) {
|
||||
super("m:deg");
|
||||
|
||||
if (!!children) {
|
||||
for (const child of children) {
|
||||
this.root.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user