Merge branch 'master' into feat/table-of-contents
This commit is contained in:
@ -1,16 +1,17 @@
|
||||
import { assert } from "chai";
|
||||
import * as fs from "fs";
|
||||
|
||||
import { Utility } from "../../tests/utility";
|
||||
import { Drawing, IDrawingOptions, PlacementPosition } from "./";
|
||||
|
||||
const imageBase64Data = `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`;
|
||||
|
||||
function createDrawing(drawingOptions?: IDrawingOptions): Drawing {
|
||||
const path = "./demo/images/image1.jpeg";
|
||||
return new Drawing(
|
||||
{
|
||||
fileName: "test.jpg",
|
||||
referenceId: 1,
|
||||
stream: fs.createReadStream(path),
|
||||
stream: Buffer.from(imageBase64Data, "base64"),
|
||||
path: path,
|
||||
dimensions: {
|
||||
pixels: {
|
||||
|
@ -123,20 +123,13 @@ export class File {
|
||||
return this.document.createTable(rows, cols);
|
||||
}
|
||||
|
||||
public createImage(filePath: string): Image {
|
||||
const image = Media.addImage(this, filePath);
|
||||
this.document.addParagraph(image.Paragraph);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
public addImage(image: Image): File {
|
||||
this.document.addParagraph(image.Paragraph);
|
||||
return this;
|
||||
}
|
||||
|
||||
public createImageFromBuffer(buffer: Buffer, width?: number, height?: number): Image {
|
||||
const image = Media.addImageFromBuffer(this, buffer, width, height);
|
||||
public createImage(buffer: Buffer | string | Uint8Array | ArrayBuffer, width?: number, height?: number): Image {
|
||||
const image = Media.addImage(this, buffer, width, height);
|
||||
this.document.addParagraph(image.Paragraph);
|
||||
|
||||
return image;
|
||||
|
@ -36,8 +36,8 @@ export class FooterWrapper {
|
||||
this.footer.addChildElement(childElement);
|
||||
}
|
||||
|
||||
public createImage(image: string): void {
|
||||
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount);
|
||||
public createImage(image: Buffer, width?: number, height?: number): void {
|
||||
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height);
|
||||
this.relationships.createRelationship(
|
||||
mediaData.referenceId,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||
|
@ -36,8 +36,8 @@ export class HeaderWrapper {
|
||||
this.header.addChildElement(childElement);
|
||||
}
|
||||
|
||||
public createImage(image: string): void {
|
||||
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount);
|
||||
public createImage(image: Buffer, width?: number, height?: number): void {
|
||||
const mediaData = this.media.addMedia(image, this.relationships.RelationshipCount, width, height);
|
||||
this.relationships.createRelationship(
|
||||
mediaData.referenceId,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||
|
@ -1,5 +1,3 @@
|
||||
import * as fs from "fs";
|
||||
|
||||
export interface IMediaDataDimensions {
|
||||
pixels: {
|
||||
x: number;
|
||||
@ -13,7 +11,7 @@ export interface IMediaDataDimensions {
|
||||
|
||||
export interface IMediaData {
|
||||
referenceId: number;
|
||||
stream: fs.ReadStream | Buffer;
|
||||
stream: Buffer | Uint8Array | ArrayBuffer;
|
||||
path?: string;
|
||||
fileName: string;
|
||||
dimensions: IMediaDataDimensions;
|
||||
|
@ -1,7 +1,4 @@
|
||||
import * as fs from "fs";
|
||||
import * as sizeOf from "image-size";
|
||||
import * as path from "path";
|
||||
|
||||
import { IDrawingOptions } from "../drawing";
|
||||
import { File } from "../file";
|
||||
import { ImageParagraph } from "../paragraph";
|
||||
import { IMediaData } from "./data";
|
||||
@ -12,35 +9,23 @@ interface IHackedFile {
|
||||
}
|
||||
|
||||
export class Media {
|
||||
public static addImage(file: File, filePath: string): Image {
|
||||
public static addImage(
|
||||
file: File,
|
||||
buffer: Buffer | string | Uint8Array | ArrayBuffer,
|
||||
width?: number,
|
||||
height?: number,
|
||||
drawingOptions?: IDrawingOptions,
|
||||
): Image {
|
||||
// Workaround to expose id without exposing to API
|
||||
const exposedFile = (file as {}) as IHackedFile;
|
||||
const mediaData = file.Media.addMedia(filePath, exposedFile.currentRelationshipId++);
|
||||
file.DocumentRelationships.createRelationship(
|
||||
mediaData.referenceId,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||
`media/${mediaData.fileName}`,
|
||||
);
|
||||
return new Image(new ImageParagraph(mediaData));
|
||||
}
|
||||
|
||||
public static addImageFromBuffer(file: File, buffer: Buffer, width?: number, height?: number): Image {
|
||||
// Workaround to expose id without exposing to API
|
||||
const exposedFile = (file as {}) as IHackedFile;
|
||||
const mediaData = file.Media.addMediaFromBuffer(
|
||||
`${Media.generateId()}.png`,
|
||||
buffer,
|
||||
exposedFile.currentRelationshipId++,
|
||||
width,
|
||||
height,
|
||||
);
|
||||
const mediaData = file.Media.addMedia(buffer, exposedFile.currentRelationshipId++, width, height);
|
||||
file.DocumentRelationships.createRelationship(
|
||||
mediaData.referenceId,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||
`media/${mediaData.fileName}`,
|
||||
);
|
||||
|
||||
return new Image(new ImageParagraph(mediaData));
|
||||
return new Image(new ImageParagraph(mediaData, drawingOptions));
|
||||
}
|
||||
|
||||
private static generateId(): string {
|
||||
@ -71,34 +56,36 @@ export class Media {
|
||||
return data;
|
||||
}
|
||||
|
||||
public addMedia(filePath: string, referenceId: number): IMediaData {
|
||||
const key = path.basename(filePath);
|
||||
const dimensions = sizeOf(filePath);
|
||||
return this.createMedia(key, referenceId, dimensions, fs.createReadStream(filePath), filePath);
|
||||
}
|
||||
public addMedia(
|
||||
buffer: Buffer | string | Uint8Array | ArrayBuffer,
|
||||
referenceId: number,
|
||||
width: number = 100,
|
||||
height: number = 100,
|
||||
): IMediaData {
|
||||
const key = `${Media.generateId()}.png`;
|
||||
|
||||
public addMediaFromBuffer(fileName: string, buffer: Buffer, referenceId: number, width?: number, height?: number): IMediaData {
|
||||
const key = fileName;
|
||||
let dimensions;
|
||||
if (width && height) {
|
||||
dimensions = {
|
||||
return this.createMedia(
|
||||
key,
|
||||
referenceId,
|
||||
{
|
||||
width: width,
|
||||
height: height,
|
||||
};
|
||||
} else {
|
||||
dimensions = sizeOf(buffer);
|
||||
}
|
||||
|
||||
return this.createMedia(key, referenceId, dimensions, buffer);
|
||||
},
|
||||
buffer,
|
||||
);
|
||||
}
|
||||
|
||||
private createMedia(
|
||||
key: string,
|
||||
relationshipsCount: number,
|
||||
dimensions: { width: number; height: number },
|
||||
data: fs.ReadStream | Buffer,
|
||||
data: Buffer | string | Uint8Array | ArrayBuffer,
|
||||
filePath?: string,
|
||||
): IMediaData {
|
||||
if (typeof data === "string") {
|
||||
data = this.convertDataURIToBinary(data);
|
||||
}
|
||||
|
||||
const imageData = {
|
||||
referenceId: this.map.size + relationshipsCount + 1,
|
||||
stream: data,
|
||||
@ -130,4 +117,23 @@ export class Media {
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
private convertDataURIToBinary(dataURI: string): Uint8Array {
|
||||
// https://gist.github.com/borismus/1032746
|
||||
// https://github.com/mafintosh/base64-to-uint8array
|
||||
const BASE64_MARKER = ";base64,";
|
||||
|
||||
const base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
|
||||
|
||||
if (typeof atob === "function") {
|
||||
return new Uint8Array(
|
||||
atob(dataURI.substring(base64Index))
|
||||
.split("")
|
||||
.map((c) => c.charCodeAt(0)),
|
||||
);
|
||||
} else {
|
||||
const b = require("buf" + "fer");
|
||||
return new b.Buffer(dataURI, "base64");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,63 @@
|
||||
// http://officeopenxml.com/WPborders.php
|
||||
import { Attributes, XmlComponent } from "file/xml-components";
|
||||
|
||||
class Border extends XmlComponent {
|
||||
class BorderProperty extends XmlComponent {
|
||||
public setProperties(color: string, space: string, value: string, size: string): XmlComponent {
|
||||
const attrs = new Attributes({
|
||||
color: color,
|
||||
space: space,
|
||||
val: value,
|
||||
sz: size,
|
||||
});
|
||||
this.root.push(attrs);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class Border extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:bottom");
|
||||
this.root.push(
|
||||
new Attributes({
|
||||
color: "auto",
|
||||
space: "1",
|
||||
val: "single",
|
||||
sz: "6",
|
||||
}),
|
||||
);
|
||||
super("w:pBdr");
|
||||
}
|
||||
|
||||
public addTopBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent {
|
||||
const top = new BorderProperty("w:top");
|
||||
top.setProperties(color, space, value, size);
|
||||
this.root.push(top);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public addBottomBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent {
|
||||
const bottom = new BorderProperty("w:bottom");
|
||||
bottom.setProperties(color, space, value, size);
|
||||
this.root.push(bottom);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public addLeftBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent {
|
||||
const left = new BorderProperty("w:left");
|
||||
left.setProperties(color, space, value, size);
|
||||
this.root.push(left);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public addRightBorder(color: string = "auto", space: string = "1", value: string = "single", size: string = "6"): XmlComponent {
|
||||
const right = new BorderProperty("w:right");
|
||||
right.setProperties(color, space, value, size);
|
||||
this.root.push(right);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class ThematicBreak extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:pBdr");
|
||||
this.root.push(new Border());
|
||||
const bottom = new BorderProperty("w:bottom");
|
||||
bottom.setProperties("auto", "1", "single", "6");
|
||||
this.root.push(bottom);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// http://officeopenxml.com/WPindentation.php
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
interface IIndentAttributesProperties {
|
||||
export interface IIndentAttributesProperties {
|
||||
left?: number;
|
||||
hanging?: number;
|
||||
firstLine?: number;
|
||||
@ -20,7 +20,7 @@ class IndentAttributes extends XmlAttributeComponent<IIndentAttributesProperties
|
||||
}
|
||||
|
||||
export class Indent extends XmlComponent {
|
||||
constructor(attrs: object) {
|
||||
constructor(attrs: IIndentAttributesProperties) {
|
||||
super("w:ind");
|
||||
this.root.push(new IndentAttributes(attrs));
|
||||
}
|
||||
|
@ -144,6 +144,51 @@ describe("Paragraph", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#paragraphBorders()", () => {
|
||||
it("should add a left and right border to a paragraph", () => {
|
||||
paragraph.createBorder();
|
||||
paragraph.Borders.addLeftBorder();
|
||||
paragraph.Borders.addRightBorder();
|
||||
const tree = new Formatter().format(paragraph);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:p": [
|
||||
{
|
||||
"w:pPr": [
|
||||
{
|
||||
"w:pBdr": [
|
||||
{
|
||||
"w:left": [
|
||||
{
|
||||
_attr: {
|
||||
"w:color": "auto",
|
||||
"w:space": "1",
|
||||
"w:sz": "6",
|
||||
"w:val": "single",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"w:right": [
|
||||
{
|
||||
_attr: {
|
||||
"w:color": "auto",
|
||||
"w:space": "1",
|
||||
"w:sz": "6",
|
||||
"w:val": "single",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#pageBreak()", () => {
|
||||
it("should add page break to JSON", () => {
|
||||
paragraph.pageBreak();
|
||||
|
@ -6,8 +6,8 @@ import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { Alignment } from "./formatting/alignment";
|
||||
import { Bidirectional } from "./formatting/bidirectional";
|
||||
import { ThematicBreak } from "./formatting/border";
|
||||
import { Indent } from "./formatting/indent";
|
||||
import { Border, ThematicBreak } from "./formatting/border";
|
||||
import { IIndentAttributesProperties, Indent } from "./formatting/indent";
|
||||
import { KeepLines, KeepNext } from "./formatting/keep";
|
||||
import { PageBreak, PageBreakBefore } from "./formatting/page-break";
|
||||
import { ISpacingProperties, Spacing } from "./formatting/spacing";
|
||||
@ -30,6 +30,15 @@ export class Paragraph extends XmlComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public get Borders(): Border {
|
||||
return this.properties.paragraphBorder;
|
||||
}
|
||||
|
||||
public createBorder(): Paragraph {
|
||||
this.properties.createBorder();
|
||||
return this;
|
||||
}
|
||||
|
||||
public addRun(run: Run): Paragraph {
|
||||
this.root.push(run);
|
||||
return this;
|
||||
@ -188,7 +197,7 @@ export class Paragraph extends XmlComponent {
|
||||
return this;
|
||||
}
|
||||
|
||||
public indent(attrs: object): Paragraph {
|
||||
public indent(attrs: IIndentAttributesProperties): Paragraph {
|
||||
this.properties.push(new Indent(attrs));
|
||||
return this;
|
||||
}
|
||||
@ -222,4 +231,8 @@ export class Paragraph extends XmlComponent {
|
||||
this.properties.push(new Bidirectional());
|
||||
return this;
|
||||
}
|
||||
|
||||
public get Properties(): ParagraphProperties {
|
||||
return this.properties;
|
||||
}
|
||||
}
|
||||
|
243
src/file/paragraph/paragraph.ts.orig
Normal file
243
src/file/paragraph/paragraph.ts.orig
Normal file
@ -0,0 +1,243 @@
|
||||
// http://officeopenxml.com/WPparagraph.php
|
||||
import { FootnoteReferenceRun } from "file/footnotes/footnote/run/reference-run";
|
||||
import { Image } from "file/media";
|
||||
import { Num } from "file/numbering/num";
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
|
||||
import { Alignment } from "./formatting/alignment";
|
||||
import { Bidirectional } from "./formatting/bidirectional";
|
||||
<<<<<<< HEAD
|
||||
import { Border, ThematicBreak } from "./formatting/border";
|
||||
import { Indent } from "./formatting/indent";
|
||||
=======
|
||||
import { ThematicBreak } from "./formatting/border";
|
||||
import { IIndentAttributesProperties, Indent } from "./formatting/indent";
|
||||
>>>>>>> a53818754a1c76b9930ee2ecc642570170fa3c06
|
||||
import { KeepLines, KeepNext } from "./formatting/keep";
|
||||
import { PageBreak, PageBreakBefore } from "./formatting/page-break";
|
||||
import { ISpacingProperties, Spacing } from "./formatting/spacing";
|
||||
import { Style } from "./formatting/style";
|
||||
import { CenterTabStop, LeftTabStop, MaxRightTabStop, RightTabStop } from "./formatting/tab-stop";
|
||||
import { NumberProperties } from "./formatting/unordered-list";
|
||||
import { Bookmark, Hyperlink } from "./links";
|
||||
import { ParagraphProperties } from "./properties";
|
||||
import { PictureRun, Run, TextRun } from "./run";
|
||||
|
||||
export class Paragraph extends XmlComponent {
|
||||
private readonly properties: ParagraphProperties;
|
||||
|
||||
constructor(text?: string) {
|
||||
super("w:p");
|
||||
this.properties = new ParagraphProperties();
|
||||
this.root.push(this.properties);
|
||||
if (text !== undefined) {
|
||||
this.root.push(new TextRun(text));
|
||||
}
|
||||
}
|
||||
|
||||
public get Borders(): Border {
|
||||
return this.properties.paragraphBorder;
|
||||
}
|
||||
|
||||
public createBorder(): Paragraph {
|
||||
this.properties.createBorder();
|
||||
return this;
|
||||
}
|
||||
|
||||
public addRun(run: Run): Paragraph {
|
||||
this.root.push(run);
|
||||
return this;
|
||||
}
|
||||
|
||||
public addHyperLink(hyperlink: Hyperlink): Paragraph {
|
||||
this.root.push(hyperlink);
|
||||
return this;
|
||||
}
|
||||
|
||||
public addBookmark(bookmark: Bookmark): Paragraph {
|
||||
// Bookmarks by spec have three components, a start, text, and end
|
||||
this.root.push(bookmark.start);
|
||||
this.root.push(bookmark.text);
|
||||
this.root.push(bookmark.end);
|
||||
return this;
|
||||
}
|
||||
|
||||
public createTextRun(text: string): TextRun {
|
||||
const run = new TextRun(text);
|
||||
this.addRun(run);
|
||||
return run;
|
||||
}
|
||||
|
||||
public addImage(image: Image): PictureRun {
|
||||
const run = image.Run;
|
||||
this.addRun(run);
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
public heading1(): Paragraph {
|
||||
this.properties.push(new Style("Heading1"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public heading2(): Paragraph {
|
||||
this.properties.push(new Style("Heading2"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public heading3(): Paragraph {
|
||||
this.properties.push(new Style("Heading3"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public heading4(): Paragraph {
|
||||
this.properties.push(new Style("Heading4"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public heading5(): Paragraph {
|
||||
this.properties.push(new Style("Heading5"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public heading6(): Paragraph {
|
||||
this.properties.push(new Style("Heading6"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public title(): Paragraph {
|
||||
this.properties.push(new Style("Title"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public center(): Paragraph {
|
||||
this.properties.push(new Alignment("center"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public left(): Paragraph {
|
||||
this.properties.push(new Alignment("left"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public right(): Paragraph {
|
||||
this.properties.push(new Alignment("right"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public start(): Paragraph {
|
||||
this.properties.push(new Alignment("start"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public end(): Paragraph {
|
||||
this.properties.push(new Alignment("end"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public distribute(): Paragraph {
|
||||
this.properties.push(new Alignment("distribute"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public justified(): Paragraph {
|
||||
this.properties.push(new Alignment("both"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public thematicBreak(): Paragraph {
|
||||
this.properties.push(new ThematicBreak());
|
||||
return this;
|
||||
}
|
||||
|
||||
public pageBreak(): Paragraph {
|
||||
this.root.push(new PageBreak());
|
||||
return this;
|
||||
}
|
||||
|
||||
public pageBreakBefore(): Paragraph {
|
||||
this.properties.push(new PageBreakBefore());
|
||||
return this;
|
||||
}
|
||||
|
||||
public maxRightTabStop(): Paragraph {
|
||||
this.properties.push(new MaxRightTabStop());
|
||||
return this;
|
||||
}
|
||||
|
||||
public leftTabStop(position: number): Paragraph {
|
||||
this.properties.push(new LeftTabStop(position));
|
||||
return this;
|
||||
}
|
||||
|
||||
public rightTabStop(position: number): Paragraph {
|
||||
this.properties.push(new RightTabStop(position));
|
||||
return this;
|
||||
}
|
||||
|
||||
public centerTabStop(position: number): Paragraph {
|
||||
this.properties.push(new CenterTabStop(position));
|
||||
return this;
|
||||
}
|
||||
|
||||
public bullet(indentLevel: number = 0): Paragraph {
|
||||
this.properties.push(new Style("ListParagraph"));
|
||||
this.properties.push(new NumberProperties(1, indentLevel));
|
||||
return this;
|
||||
}
|
||||
|
||||
public setNumbering(numbering: Num, indentLevel: number): Paragraph {
|
||||
this.properties.push(new Style("ListParagraph"));
|
||||
this.properties.push(new NumberProperties(numbering.id, indentLevel));
|
||||
return this;
|
||||
}
|
||||
|
||||
public setCustomNumbering(numberId: number, indentLevel: number): Paragraph {
|
||||
this.properties.push(new NumberProperties(numberId, indentLevel));
|
||||
return this;
|
||||
}
|
||||
|
||||
public style(styleId: string): Paragraph {
|
||||
this.properties.push(new Style(styleId));
|
||||
return this;
|
||||
}
|
||||
|
||||
public indent(attrs: IIndentAttributesProperties): Paragraph {
|
||||
this.properties.push(new Indent(attrs));
|
||||
return this;
|
||||
}
|
||||
|
||||
public spacing(params: ISpacingProperties): Paragraph {
|
||||
this.properties.push(new Spacing(params));
|
||||
return this;
|
||||
}
|
||||
|
||||
public keepNext(): Paragraph {
|
||||
this.properties.push(new KeepNext());
|
||||
return this;
|
||||
}
|
||||
|
||||
public keepLines(): Paragraph {
|
||||
this.properties.push(new KeepLines());
|
||||
return this;
|
||||
}
|
||||
|
||||
public referenceFootnote(id: number): Paragraph {
|
||||
this.root.push(new FootnoteReferenceRun(id));
|
||||
return this;
|
||||
}
|
||||
|
||||
public addRunToFront(run: Run): Paragraph {
|
||||
this.root.splice(1, 0, run);
|
||||
return this;
|
||||
}
|
||||
|
||||
public bidirectional(): Paragraph {
|
||||
this.properties.push(new Bidirectional());
|
||||
return this;
|
||||
}
|
||||
|
||||
public get Properties(): ParagraphProperties {
|
||||
return this.properties;
|
||||
}
|
||||
}
|
@ -1,9 +1,17 @@
|
||||
// http://officeopenxml.com/WPparagraphProperties.php
|
||||
import { XmlComponent } from "file/xml-components";
|
||||
import { Border } from "./formatting/border";
|
||||
|
||||
export class ParagraphProperties extends XmlComponent {
|
||||
public paragraphBorder: Border;
|
||||
|
||||
constructor() {
|
||||
super("w:pPr");
|
||||
this.paragraphBorder = new Border();
|
||||
}
|
||||
|
||||
public createBorder(): void {
|
||||
this.push(this.paragraphBorder);
|
||||
}
|
||||
|
||||
public push(item: XmlComponent): void {
|
||||
|
@ -2,6 +2,7 @@ import { expect } from "chai";
|
||||
|
||||
import { Formatter } from "../../export/formatter";
|
||||
import { TableProperties } from "./properties";
|
||||
import { WidthType } from "./table-cell";
|
||||
|
||||
describe("TableProperties", () => {
|
||||
describe("#constructor", () => {
|
||||
@ -14,7 +15,7 @@ describe("TableProperties", () => {
|
||||
|
||||
describe("#setWidth", () => {
|
||||
it("adds a table width property", () => {
|
||||
const tp = new TableProperties().setWidth("dxa", 1234);
|
||||
const tp = new TableProperties().setWidth(WidthType.DXA, 1234);
|
||||
const tree = new Formatter().format(tp);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:tblPr": [{ "w:tblW": [{ _attr: { "w:type": "dxa", "w:w": 1234 } }] }],
|
||||
@ -31,4 +32,15 @@ describe("TableProperties", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#cellMargin", () => {
|
||||
it("adds a table cell top margin", () => {
|
||||
const tp = new TableProperties();
|
||||
tp.CellMargin.addTopMargin(1234, WidthType.DXA);
|
||||
const tree = new Formatter().format(tp);
|
||||
expect(tree).to.deep.equal({
|
||||
"w:tblPr": [{ "w:tblCellMar": [{ "w:top": [{ _attr: { "w:sz": "dxa", "w:w": 1234 } }] }] }],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,13 +1,18 @@
|
||||
import { XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
|
||||
export type WidthTypes = "dxa" | "pct" | "nil" | "auto";
|
||||
import { WidthType } from "./table-cell";
|
||||
import { TableCellMargin } from "./table-cell-margin";
|
||||
|
||||
export class TableProperties extends XmlComponent {
|
||||
private readonly cellMargain: TableCellMargin;
|
||||
|
||||
constructor() {
|
||||
super("w:tblPr");
|
||||
|
||||
this.cellMargain = new TableCellMargin();
|
||||
this.root.push(this.cellMargain);
|
||||
}
|
||||
|
||||
public setWidth(type: WidthTypes, w: number | string): TableProperties {
|
||||
public setWidth(type: WidthType, w: number | string): TableProperties {
|
||||
this.root.push(new PreferredTableWidth(type, w));
|
||||
return this;
|
||||
}
|
||||
@ -21,10 +26,14 @@ export class TableProperties extends XmlComponent {
|
||||
this.root.push(new TableBorders());
|
||||
return this;
|
||||
}
|
||||
|
||||
public get CellMargin(): TableCellMargin {
|
||||
return this.cellMargain;
|
||||
}
|
||||
}
|
||||
|
||||
interface ITableWidth {
|
||||
type: WidthTypes;
|
||||
type: WidthType;
|
||||
w: number | string;
|
||||
}
|
||||
|
||||
@ -33,7 +42,7 @@ class TableWidthAttributes extends XmlAttributeComponent<ITableWidth> {
|
||||
}
|
||||
|
||||
class PreferredTableWidth extends XmlComponent {
|
||||
constructor(type: WidthTypes, w: number | string) {
|
||||
constructor(type: WidthType, w: number | string) {
|
||||
super("w:tblW");
|
||||
this.root.push(new TableWidthAttributes({ type, w }));
|
||||
}
|
||||
|
55
src/file/table/table-cell-margin.ts
Normal file
55
src/file/table/table-cell-margin.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { IXmlableObject, XmlAttributeComponent, XmlComponent } from "file/xml-components";
|
||||
import { WidthType } from "./table-cell";
|
||||
|
||||
class TableCellMarginAttributes extends XmlAttributeComponent<{ type: WidthType; value: number }> {
|
||||
protected xmlKeys = { value: "w:w", type: "w:sz" };
|
||||
}
|
||||
|
||||
class BaseTableCellMargin extends XmlComponent {
|
||||
public setProperties(value: number, type: WidthType = WidthType.DXA): void {
|
||||
this.root.push(
|
||||
new TableCellMarginAttributes({
|
||||
type: type,
|
||||
value: value,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class TableCellMargin extends XmlComponent {
|
||||
constructor() {
|
||||
super("w:tblCellMar");
|
||||
}
|
||||
|
||||
public prepForXml(): IXmlableObject {
|
||||
return this.root.length > 0 ? super.prepForXml() : "";
|
||||
}
|
||||
|
||||
public addTopMargin(value: number, type: WidthType = WidthType.DXA): void {
|
||||
const top = new BaseTableCellMargin("w:top");
|
||||
|
||||
top.setProperties(value, type);
|
||||
this.root.push(top);
|
||||
}
|
||||
|
||||
public addLeftMargin(value: number, type: WidthType = WidthType.DXA): void {
|
||||
const left = new BaseTableCellMargin("w:left");
|
||||
|
||||
left.setProperties(value, type);
|
||||
this.root.push(left);
|
||||
}
|
||||
|
||||
public addBottomMargin(value: number, type: WidthType = WidthType.DXA): void {
|
||||
const bottom = new BaseTableCellMargin("w:bottom");
|
||||
|
||||
bottom.setProperties(value, type);
|
||||
this.root.push(bottom);
|
||||
}
|
||||
|
||||
public addRightMargin(value: number, type: WidthType = WidthType.DXA): void {
|
||||
const right = new BaseTableCellMargin("w:right");
|
||||
|
||||
right.setProperties(value, type);
|
||||
this.root.push(right);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import { expect } from "chai";
|
||||
import { Formatter } from "../../export/formatter";
|
||||
import { Paragraph } from "../paragraph";
|
||||
import { Table } from "./";
|
||||
import { WidthType } from "./table-cell";
|
||||
|
||||
const DEFAULT_TABLE_PROPERTIES = {
|
||||
"w:tblBorders": [
|
||||
@ -174,7 +175,7 @@ describe("Table", () => {
|
||||
|
||||
describe("#setWidth", () => {
|
||||
it("sets the preferred width on the table", () => {
|
||||
const table = new Table(2, 2).setWidth("pct", 1000);
|
||||
const table = new Table(2, 2).setWidth(WidthType.PERCENTAGE, 1000);
|
||||
const tree = new Formatter().format(table);
|
||||
expect(tree)
|
||||
.to.have.property("w:tbl")
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
import { IXmlableObject, XmlComponent } from "file/xml-components";
|
||||
import { Paragraph } from "../paragraph";
|
||||
import { TableGrid } from "./grid";
|
||||
import { TableProperties, WidthTypes } from "./properties";
|
||||
import { TableProperties } from "./properties";
|
||||
|
||||
export class Table extends XmlComponent {
|
||||
private readonly properties: TableProperties;
|
||||
@ -67,7 +67,7 @@ export class Table extends XmlComponent {
|
||||
return this.getRow(row).getCell(col);
|
||||
}
|
||||
|
||||
public setWidth(type: WidthTypes, width: number | string): Table {
|
||||
public setWidth(type: WidthType, width: number | string): Table {
|
||||
this.properties.setWidth(type, width);
|
||||
return this;
|
||||
}
|
||||
@ -76,6 +76,10 @@ export class Table extends XmlComponent {
|
||||
this.properties.setFixedWidthLayout();
|
||||
return this;
|
||||
}
|
||||
|
||||
public get Properties(): TableProperties {
|
||||
return this.properties;
|
||||
}
|
||||
}
|
||||
|
||||
export class TableRow extends XmlComponent {
|
||||
|
Reference in New Issue
Block a user