diff --git a/src/file/drawing/anchor/anchor-attributes.ts b/src/file/drawing/anchor/anchor-attributes.ts new file mode 100644 index 0000000000..abe8aac5d7 --- /dev/null +++ b/src/file/drawing/anchor/anchor-attributes.ts @@ -0,0 +1,26 @@ +import { XmlAttributeComponent } from "file/xml-components"; +import { Distance } from "../drawing"; + +export interface IAnchorAttributes extends Distance { + allowOverlap?: "0" | "1"; + behindDoc?: "0" | "1"; + layoutInCell?: "0" | "1"; + locked?: "0" | "1"; + relativeHeight?: number; + simplePos?: "0" | "1"; +} + +export class AnchorAttributes extends XmlAttributeComponent { + protected xmlKeys = { + distT: "distT", + distB: "distB", + distL: "distL", + distR: "distR", + allowOverlap: "allowOverlap", + behindDoc: "behindDoc", + layoutInCell: "layoutInCell", + locked: "locked", + relativeHeight: "relativeHeight", + simplePos: "simplePos", + }; +} diff --git a/src/file/drawing/anchor/anchor.spec.ts b/src/file/drawing/anchor/anchor.spec.ts new file mode 100644 index 0000000000..a071377fab --- /dev/null +++ b/src/file/drawing/anchor/anchor.spec.ts @@ -0,0 +1,118 @@ +import { assert } from "chai"; + +import { Utility } from "../../../tests/utility"; +import { DrawingOptions, TextWrapStyle } from ".././"; +import { Anchor } from "./"; + +function createDrawing(drawingOptions: DrawingOptions) { + return new Anchor( + 1, + { + pixels: { + x: 100, + y: 100, + }, + emus: { + x: 100 * 9525, + y: 100 * 9525, + }, + }, + drawingOptions, + ); +} + +describe("Anchor", () => { + let anchor: Anchor; + + describe("#constructor()", () => { + it("should create a Drawing with correct root key", () => { + anchor = createDrawing({}); + const newJson = Utility.jsonify(anchor); + assert.equal(newJson.rootKey, "wp:anchor"); + assert.equal(newJson.root.length, 10); + }); + + it("should create a Drawing with all default options", () => { + anchor = createDrawing({}); + const newJson = Utility.jsonify(anchor); + assert.equal(newJson.root.length, 10); + + const anchorAttributes = newJson.root[0].root; + assert.include(anchorAttributes, { + distT: 0, + distB: 0, + distL: 0, + distR: 0, + simplePos: "0", + allowOverlap: "1", + behindDoc: "0", + locked: "0", + layoutInCell: "1", + relativeHeight: 952500, + }); + + // 1: simple pos + assert.equal(newJson.root[1].rootKey, "wp:simplePos"); + + // 2: horizontal position + const horizontalPosition = newJson.root[2]; + assert.equal(horizontalPosition.rootKey, "wp:positionH"); + assert.include(horizontalPosition.root[0].root, { + relativeFrom: "column", + }); + assert.equal(horizontalPosition.root[1].rootKey, "wp:posOffset"); + assert.include(horizontalPosition.root[1].root[0], 0); + + // 3: vertical position + const verticalPosition = newJson.root[3]; + assert.equal(verticalPosition.rootKey, "wp:positionV"); + assert.include(verticalPosition.root[0].root, { + relativeFrom: "paragraph", + }); + assert.equal(verticalPosition.root[1].rootKey, "wp:posOffset"); + assert.include(verticalPosition.root[1].root[0], 0); + + // 4: extent + const extent = newJson.root[4]; + assert.equal(extent.rootKey, "wp:extent"); + assert.include(extent.root[0].root, { + cx: 952500, + cy: 952500, + }); + + // 5: effect extent + const effectExtent = newJson.root[5]; + assert.equal(effectExtent.rootKey, "wp:effectExtent"); + + // 6 text wrap: none + const textWrap = newJson.root[6]; + assert.equal(textWrap.rootKey, "wp:wrapNone"); + + // 7: doc properties + const docProperties = newJson.root[7]; + assert.equal(docProperties.rootKey, "wp:docPr"); + + // 8: graphic frame properties + const graphicFrame = newJson.root[8]; + assert.equal(graphicFrame.rootKey, "wp:cNvGraphicFramePr"); + + // 9: graphic + const graphic = newJson.root[9]; + assert.equal(graphic.rootKey, "a:graphic"); + }); + + it("should create a Drawing with text wrapping", () => { + anchor = createDrawing({ + textWrapping: { + textWrapStyle: TextWrapStyle.SQUARE, + }, + }); + const newJson = Utility.jsonify(anchor); + assert.equal(newJson.root.length, 10); + + // 6 text wrap: square + const textWrap = newJson.root[6]; + assert.equal(textWrap.rootKey, "wp:wrapSquare"); + }); + }); +}); diff --git a/src/file/drawing/anchor/anchor.ts b/src/file/drawing/anchor/anchor.ts new file mode 100644 index 0000000000..ad7a266aa2 --- /dev/null +++ b/src/file/drawing/anchor/anchor.ts @@ -0,0 +1,88 @@ +// http://officeopenxml.com/drwPicFloating.php +import { IMediaDataDimensions } from "file/media"; +import { XmlComponent } from "file/xml-components"; +import { DocProperties } from "./../doc-properties/doc-properties"; +import { EffectExtent } from "./../effect-extent/effect-extent"; +import { Extent } from "./../extent/extent"; +import { Graphic } from "./../graphic"; +import { GraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties"; +import { AnchorAttributes } from "./anchor-attributes"; +import { DrawingOptions } from "../drawing"; +import { + SimplePos, + HorizontalPosition, + VerticalPosition, + Floating, + VerticalPositionRelativeFrom, + HorizontalPositionRelativeFrom, +} from "../floating"; +import { WrapNone, TextWrapStyle, WrapSquare, WrapTight, WrapTopAndBottom } from "../text-wrap"; + +const defaultOptions: Floating = { + allowOverlap: true, + behindDocument: false, + lockAnchor: false, + layoutInCell: true, + verticalPosition: { + relative: VerticalPositionRelativeFrom.PARAGRAPH, + offset: 0, + }, + horizontalPosition: { + relative: HorizontalPositionRelativeFrom.COLUMN, + offset: 0, + }, +}; + +export class Anchor extends XmlComponent { + constructor(referenceId: number, dimensions: IMediaDataDimensions, drawingOptions: DrawingOptions) { + super("wp:anchor"); + + const floating = { + ...defaultOptions, + ...drawingOptions.floating, + }; + this.root.push( + new AnchorAttributes({ + distT: 0, + distB: 0, + distL: 0, + distR: 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, + }), + ); + + this.root.push(new SimplePos()); + this.root.push(new HorizontalPosition(floating.horizontalPosition)); + this.root.push(new VerticalPosition(floating.verticalPosition)); + this.root.push(new Extent(dimensions.emus.x, dimensions.emus.y)); + this.root.push(new EffectExtent()); + + if (drawingOptions.textWrapping != null) { + switch (drawingOptions.textWrapping.textWrapStyle) { + case TextWrapStyle.SQUARE: + this.root.push(new WrapSquare(drawingOptions.textWrapping)); + break; + case TextWrapStyle.TIGHT: + this.root.push(new WrapTight(drawingOptions.textWrapping.distanceFromText)); + break; + case TextWrapStyle.TOP_AND_BOTTOM: + this.root.push(new WrapTopAndBottom(drawingOptions.textWrapping.distanceFromText)); + break; + case TextWrapStyle.NONE: + default: + this.root.push(new WrapNone()); + } + } else { + this.root.push(new WrapNone()); + } + + this.root.push(new DocProperties()); + this.root.push(new GraphicFrameProperties()); + this.root.push(new Graphic(referenceId, dimensions.emus.x, dimensions.emus.y)); + } +} diff --git a/src/file/drawing/anchor/index.ts b/src/file/drawing/anchor/index.ts new file mode 100644 index 0000000000..57faf47fc0 --- /dev/null +++ b/src/file/drawing/anchor/index.ts @@ -0,0 +1,2 @@ +export * from "./anchor"; +export * from "./anchor-attributes"; diff --git a/src/file/drawing/drawing.spec.ts b/src/file/drawing/drawing.spec.ts index 9b113da0bf..1e70aecda5 100644 --- a/src/file/drawing/drawing.spec.ts +++ b/src/file/drawing/drawing.spec.ts @@ -2,14 +2,12 @@ import { assert } from "chai"; import * as fs from "fs"; import { Utility } from "../../tests/utility"; -import { Drawing } from "./"; +import { Drawing, DrawingOptions, PlacementPosition } from "./"; -describe("Drawing", () => { - let currentBreak: Drawing; - - beforeEach(() => { - const path = "./demo/images/image1.jpeg"; - currentBreak = new Drawing({ +function createDrawing(drawingOptions?: DrawingOptions) { + const path = "./demo/images/image1.jpeg"; + return new Drawing( + { fileName: "test.jpg", referenceId: 1, stream: fs.createReadStream(path), @@ -24,14 +22,33 @@ describe("Drawing", () => { y: 100 * 9525, }, }, - }); - }); + }, + drawingOptions, + ); +} + +describe("Drawing", () => { + let currentBreak: Drawing; describe("#constructor()", () => { it("should create a Drawing with correct root key", () => { + currentBreak = createDrawing(); const newJson = Utility.jsonify(currentBreak); assert.equal(newJson.rootKey, "w:drawing"); - // console.log(JSON.stringify(newJson, null, 2)); + }); + + it("should create a drawing with inline element when there are no options passed", () => { + currentBreak = createDrawing(); + const newJson = Utility.jsonify(currentBreak); + assert.equal(newJson.root[0].rootKey, "wp:inline"); + }); + + it("should create a drawing with anchor element when there options are passed", () => { + currentBreak = createDrawing({ + position: PlacementPosition.FLOATING, + }); + const newJson = Utility.jsonify(currentBreak); + assert.equal(newJson.root[0].rootKey, "wp:anchor"); }); }); }); diff --git a/src/file/drawing/drawing.ts b/src/file/drawing/drawing.ts index e6dab2f4d1..55607fadbb 100644 --- a/src/file/drawing/drawing.ts +++ b/src/file/drawing/drawing.ts @@ -1,15 +1,49 @@ import { IMediaData } from "file/media"; import { XmlComponent } from "file/xml-components"; import { Inline } from "./inline"; +import { Anchor } from "./anchor"; +import { TextWrapping } from "./text-wrap"; +import { Floating } from "./floating"; + +export enum PlacementPosition { + INLINE, + FLOATING, +} + +export interface Distance { + distT?: number; + distB?: number; + distL?: number; + distR?: number; +} + +export interface DrawingOptions { + position?: PlacementPosition; + textWrapping?: TextWrapping; + floating?: Floating; +} + +const defaultDrawingOptions: DrawingOptions = { + position: PlacementPosition.INLINE, +}; export class Drawing extends XmlComponent { - constructor(imageData: IMediaData) { + constructor(imageData: IMediaData, drawingOptions?: DrawingOptions) { super("w:drawing"); if (imageData === undefined) { throw new Error("imageData cannot be undefined"); } - this.root.push(new Inline(imageData.referenceId, imageData.dimensions)); + const mergedOptions = { + ...defaultDrawingOptions, + ...drawingOptions, + }; + + if (mergedOptions.position === PlacementPosition.INLINE) { + this.root.push(new Inline(imageData.referenceId, imageData.dimensions)); + } else if (mergedOptions.position === PlacementPosition.FLOATING) { + this.root.push(new Anchor(imageData.referenceId, imageData.dimensions, mergedOptions)); + } } } diff --git a/src/file/drawing/floating/align.spec.ts b/src/file/drawing/floating/align.spec.ts new file mode 100644 index 0000000000..119366d30f --- /dev/null +++ b/src/file/drawing/floating/align.spec.ts @@ -0,0 +1,15 @@ +import { assert } from "chai"; + +import { Align } from "./align"; +import { Utility } from "../../../tests/utility"; +import { VerticalPositionAlign } from "."; + +describe("Align", () => { + describe("#constructor()", () => { + it("should create a element with correct root key", () => { + const newJson = Utility.jsonify(new Align(VerticalPositionAlign.CENTER)); + assert.equal(newJson.rootKey, "wp:align"); + assert.include(newJson.root[0], VerticalPositionAlign.CENTER); + }); + }); +}); diff --git a/src/file/drawing/floating/align.ts b/src/file/drawing/floating/align.ts new file mode 100644 index 0000000000..2ffa4ac52b --- /dev/null +++ b/src/file/drawing/floating/align.ts @@ -0,0 +1,10 @@ +// http://officeopenxml.com/drwPicFloating-position.php +import { XmlComponent } from "file/xml-components"; +import { HorizontalPositionAlign, VerticalPositionAlign } from "./floating-position"; + +export class Align extends XmlComponent { + constructor(value: HorizontalPositionAlign | VerticalPositionAlign) { + super("wp:align"); + this.root.push(value); + } +} diff --git a/src/file/drawing/floating/floating-position.ts b/src/file/drawing/floating/floating-position.ts new file mode 100644 index 0000000000..f9c4547776 --- /dev/null +++ b/src/file/drawing/floating/floating-position.ts @@ -0,0 +1,60 @@ +// http://officeopenxml.com/drwPicFloating-position.php + +export enum HorizontalPositionRelativeFrom { + CHARACTER = "character", + COLUMN = "column", + INSIDE_MARGIN = "insideMargin", + LEFT_MARGIN = "leftMargin", + MARGIN = "margin", + OUTSIDE_MARGIN = "outsideMargin", + PAGE = "page", + RIGHT_MARGIN = "rightMargin", +} + +export enum VerticalPositionRelativeFrom { + BOTTOM_MARGIN = "bottomMargin", + INSIDE_MARGIN = "insideMargin", + LINE = "line", + MARGIN = "margin", + OUTSIDE_MARGIN = "outsideMargin", + PAGE = "page", + PARAGRAPH = "paragraph", + TOP_MARGIN = "topMargin", +} + +export enum HorizontalPositionAlign { + CENTER = "center", + INSIDE = "inside", + LEFT = "left", + OUTSIDE = "outside", + RIGHT = "right", +} + +export enum VerticalPositionAlign { + BOTTOM = "bottom", + CENTER = "center", + INSIDE = "inside", + OUTSIDE = "outside", + TOP = "top", +} + +export interface HorizontalPositionOptions { + relative: HorizontalPositionRelativeFrom; + align?: HorizontalPositionAlign; + offset?: number; +} + +export interface VerticalPositionOptions { + relative: VerticalPositionRelativeFrom; + align?: VerticalPositionAlign; + offset?: number; +} + +export interface Floating { + horizontalPosition: HorizontalPositionOptions; + verticalPosition: VerticalPositionOptions; + allowOverlap?: boolean; + lockAnchor?: boolean; + behindDocument?: boolean; + layoutInCell?: boolean; +} diff --git a/src/file/drawing/floating/horizontal-position.spec.ts b/src/file/drawing/floating/horizontal-position.spec.ts new file mode 100644 index 0000000000..69415685e1 --- /dev/null +++ b/src/file/drawing/floating/horizontal-position.spec.ts @@ -0,0 +1,41 @@ +import { assert } from "chai"; + +import { HorizontalPosition } from "./horizontal-position"; +import { Utility } from "../../../tests/utility"; +import { HorizontalPositionRelativeFrom, HorizontalPositionAlign } from "."; + +describe("HorizontalPosition", () => { + describe("#constructor()", () => { + it("should create a element with position align", () => { + const newJson = Utility.jsonify( + new HorizontalPosition({ + relative: HorizontalPositionRelativeFrom.MARGIN, + align: HorizontalPositionAlign.CENTER, + }), + ); + assert.equal(newJson.rootKey, "wp:positionH"); + assert.include(newJson.root[0].root, { + relativeFrom: "margin", + }); + + assert.equal(newJson.root[1].rootKey, "wp:align"); + assert.include(newJson.root[1].root, "center"); + }); + + it("should create a element with offset", () => { + const newJson = Utility.jsonify( + new HorizontalPosition({ + relative: HorizontalPositionRelativeFrom.MARGIN, + offset: 40, + }), + ); + assert.equal(newJson.rootKey, "wp:positionH"); + assert.include(newJson.root[0].root, { + relativeFrom: "margin", + }); + + assert.equal(newJson.root[1].rootKey, "wp:posOffset"); + assert.include(newJson.root[1].root[0], 40); + }); + }); +}); diff --git a/src/file/drawing/floating/horizontal-position.ts b/src/file/drawing/floating/horizontal-position.ts new file mode 100644 index 0000000000..5b0a0e68ca --- /dev/null +++ b/src/file/drawing/floating/horizontal-position.ts @@ -0,0 +1,35 @@ +// http://officeopenxml.com/drwPicFloating-position.php +import { XmlComponent, XmlAttributeComponent } from "file/xml-components"; +import { HorizontalPositionRelativeFrom, HorizontalPositionOptions } from "./floating-position"; +import { Align } from "./align"; +import { PositionOffset } from "./position-offset"; + +interface IHorizontalPositionAttributes { + relativeFrom: HorizontalPositionRelativeFrom; +} + +class HorizontalPositionAttributes extends XmlAttributeComponent { + protected xmlKeys = { + relativeFrom: "relativeFrom", + }; +} + +export class HorizontalPosition extends XmlComponent { + constructor(horizontalPosition: HorizontalPositionOptions) { + super("wp:positionH"); + + this.root.push( + new HorizontalPositionAttributes({ + relativeFrom: horizontalPosition.relative, + }), + ); + + if (horizontalPosition.align) { + this.root.push(new Align(horizontalPosition.align)); + } else if (horizontalPosition.offset !== undefined) { + this.root.push(new PositionOffset(horizontalPosition.offset)); + } else { + throw new Error("There is no configuration provided for floating position (Align or offset)"); + } + } +} diff --git a/src/file/drawing/floating/index.ts b/src/file/drawing/floating/index.ts new file mode 100644 index 0000000000..80061d16e1 --- /dev/null +++ b/src/file/drawing/floating/index.ts @@ -0,0 +1,4 @@ +export * from "./floating-position"; +export * from "./simple-pos"; +export * from "./horizontal-position"; +export * from "./vertical-position"; diff --git a/src/file/drawing/floating/position-offset.spec.ts b/src/file/drawing/floating/position-offset.spec.ts new file mode 100644 index 0000000000..e0360c1716 --- /dev/null +++ b/src/file/drawing/floating/position-offset.spec.ts @@ -0,0 +1,14 @@ +import { assert } from "chai"; + +import { PositionOffset } from "./position-offset"; +import { Utility } from "../../../tests/utility"; + +describe("PositionOffset", () => { + describe("#constructor()", () => { + it("should create a element with correct root key", () => { + const newJson = Utility.jsonify(new PositionOffset(50)); + assert.equal(newJson.rootKey, "wp:posOffset"); + assert.equal(newJson.root[0], 50); + }); + }); +}); diff --git a/src/file/drawing/floating/position-offset.ts b/src/file/drawing/floating/position-offset.ts new file mode 100644 index 0000000000..4d3aa96b07 --- /dev/null +++ b/src/file/drawing/floating/position-offset.ts @@ -0,0 +1,9 @@ +// http://officeopenxml.com/drwPicFloating-position.php +import { XmlComponent } from "file/xml-components"; + +export class PositionOffset extends XmlComponent { + constructor(offsetValue: number) { + super("wp:posOffset"); + this.root.push(offsetValue.toString()); + } +} diff --git a/src/file/drawing/floating/simple-pos.spec.ts b/src/file/drawing/floating/simple-pos.spec.ts new file mode 100644 index 0000000000..a86739b7b0 --- /dev/null +++ b/src/file/drawing/floating/simple-pos.spec.ts @@ -0,0 +1,17 @@ +import { assert } from "chai"; + +import { SimplePos } from "./simple-pos"; +import { Utility } from "../../../tests/utility"; + +describe("SimplePos", () => { + describe("#constructor()", () => { + it("should create a element with correct root key", () => { + const newJson = Utility.jsonify(new SimplePos()); + assert.equal(newJson.rootKey, "wp:simplePos"); + assert.include(newJson.root[0].root, { + x: 0, + y: 0, + }); + }); + }); +}); diff --git a/src/file/drawing/floating/simple-pos.ts b/src/file/drawing/floating/simple-pos.ts new file mode 100644 index 0000000000..b5e8df70d3 --- /dev/null +++ b/src/file/drawing/floating/simple-pos.ts @@ -0,0 +1,28 @@ +// http://officeopenxml.com/drwPicFloating-position.php +import { XmlComponent, XmlAttributeComponent } from "file/xml-components"; + +interface ISimplePosAttributes { + x: number; + y: number; +} + +class SimplePosAttributes extends XmlAttributeComponent { + protected xmlKeys = { + x: "x", + y: "y", + }; +} + +export class SimplePos extends XmlComponent { + constructor() { + super("wp:simplePos"); + + // NOTE: It's not fully supported in Microsoft Word, but this element is needed anyway + this.root.push( + new SimplePosAttributes({ + x: 0, + y: 0, + }), + ); + } +} diff --git a/src/file/drawing/floating/vertical-position.spec.ts b/src/file/drawing/floating/vertical-position.spec.ts new file mode 100644 index 0000000000..13e1ae2a4c --- /dev/null +++ b/src/file/drawing/floating/vertical-position.spec.ts @@ -0,0 +1,41 @@ +import { assert } from "chai"; + +import { VerticalPosition } from "./vertical-position"; +import { Utility } from "../../../tests/utility"; +import { VerticalPositionRelativeFrom, VerticalPositionAlign } from "."; + +describe("VerticalPosition", () => { + describe("#constructor()", () => { + it("should create a element with position align", () => { + const newJson = Utility.jsonify( + new VerticalPosition({ + relative: VerticalPositionRelativeFrom.MARGIN, + align: VerticalPositionAlign.INSIDE, + }), + ); + assert.equal(newJson.rootKey, "wp:positionV"); + assert.include(newJson.root[0].root, { + relativeFrom: "margin", + }); + + assert.equal(newJson.root[1].rootKey, "wp:align"); + assert.include(newJson.root[1].root, "inside"); + }); + + it("should create a element with offset", () => { + const newJson = Utility.jsonify( + new VerticalPosition({ + relative: VerticalPositionRelativeFrom.MARGIN, + offset: 40, + }), + ); + assert.equal(newJson.rootKey, "wp:positionV"); + assert.include(newJson.root[0].root, { + relativeFrom: "margin", + }); + + assert.equal(newJson.root[1].rootKey, "wp:posOffset"); + assert.include(newJson.root[1].root[0], 40); + }); + }); +}); diff --git a/src/file/drawing/floating/vertical-position.ts b/src/file/drawing/floating/vertical-position.ts new file mode 100644 index 0000000000..4c6826221d --- /dev/null +++ b/src/file/drawing/floating/vertical-position.ts @@ -0,0 +1,35 @@ +// http://officeopenxml.com/drwPicFloating-position.php +import { XmlComponent, XmlAttributeComponent } from "file/xml-components"; +import { VerticalPositionRelativeFrom, VerticalPositionOptions } from "./floating-position"; +import { Align } from "./align"; +import { PositionOffset } from "./position-offset"; + +interface IVerticalPositionAttributes { + relativeFrom: VerticalPositionRelativeFrom; +} + +class VerticalPositionAttributes extends XmlAttributeComponent { + protected xmlKeys = { + relativeFrom: "relativeFrom", + }; +} + +export class VerticalPosition extends XmlComponent { + constructor(verticalPosition: VerticalPositionOptions) { + super("wp:positionV"); + + this.root.push( + new VerticalPositionAttributes({ + relativeFrom: verticalPosition.relative, + }), + ); + + if (verticalPosition.align) { + this.root.push(new Align(verticalPosition.align)); + } else if (verticalPosition.offset !== undefined) { + this.root.push(new PositionOffset(verticalPosition.offset)); + } else { + throw new Error("There is no configuration provided for floating position (Align or offset)"); + } + } +} diff --git a/src/file/drawing/index.ts b/src/file/drawing/index.ts index ba96e11de9..8a1a62a201 100644 --- a/src/file/drawing/index.ts +++ b/src/file/drawing/index.ts @@ -1 +1,3 @@ -export { Drawing } from "./drawing"; +export * from "./drawing"; +export * from "./text-wrap"; +export * from "./floating"; diff --git a/src/file/drawing/inline/inline-attributes.ts b/src/file/drawing/inline/inline-attributes.ts index 1a4ef74e3c..c177fd9ea7 100644 --- a/src/file/drawing/inline/inline-attributes.ts +++ b/src/file/drawing/inline/inline-attributes.ts @@ -1,11 +1,7 @@ import { XmlAttributeComponent } from "file/xml-components"; +import { Distance } from "../drawing"; -export interface IInlineAttributes { - distT?: number; - distB?: number; - distL?: number; - distR?: number; -} +export interface IInlineAttributes extends Distance {} export class InlineAttributes extends XmlAttributeComponent { protected xmlKeys = { diff --git a/src/file/drawing/text-wrap/index.ts b/src/file/drawing/text-wrap/index.ts new file mode 100644 index 0000000000..ce8c0bbd13 --- /dev/null +++ b/src/file/drawing/text-wrap/index.ts @@ -0,0 +1,5 @@ +export * from "./text-wrapping"; +export * from "./wrap-none"; +export * from "./wrap-square"; +export * from "./wrap-tight"; +export * from "./wrap-top-and-bottom"; diff --git a/src/file/drawing/text-wrap/text-wrapping.ts b/src/file/drawing/text-wrap/text-wrapping.ts new file mode 100644 index 0000000000..4894ca76da --- /dev/null +++ b/src/file/drawing/text-wrap/text-wrapping.ts @@ -0,0 +1,22 @@ +// http://officeopenxml.com/drwPicFloating-textWrap.php +import { Distance } from "../drawing"; + +export enum TextWrapStyle { + NONE, + SQUARE, + TIGHT, + TOP_AND_BOTTOM, +} + +export enum WrapTextOption { + BOTH_SIDES = "bothSides", + LEFT = "left", + RIGHT = "right", + LARGEST = "largest", +} + +export interface TextWrapping { + textWrapStyle: TextWrapStyle; + wrapTextOption?: WrapTextOption; + distanceFromText?: Distance; +} diff --git a/src/file/drawing/text-wrap/wrap-none.ts b/src/file/drawing/text-wrap/wrap-none.ts new file mode 100644 index 0000000000..0ac4c632f0 --- /dev/null +++ b/src/file/drawing/text-wrap/wrap-none.ts @@ -0,0 +1,8 @@ +// http://officeopenxml.com/drwPicFloating-textWrap.php +import { XmlComponent } from "file/xml-components"; + +export class WrapNone extends XmlComponent { + constructor() { + super("wp:wrapNone"); + } +} diff --git a/src/file/drawing/text-wrap/wrap-square.ts b/src/file/drawing/text-wrap/wrap-square.ts new file mode 100644 index 0000000000..5f8b7aef57 --- /dev/null +++ b/src/file/drawing/text-wrap/wrap-square.ts @@ -0,0 +1,31 @@ +// http://officeopenxml.com/drwPicFloating-textWrap.php +import { XmlComponent, XmlAttributeComponent } from "file/xml-components"; +import { TextWrapping, WrapTextOption } from "."; +import { Distance } from "../drawing"; + +interface IWrapSquareAttributes extends Distance { + wrapText?: WrapTextOption; +} + +class WrapSquareAttributes extends XmlAttributeComponent { + protected xmlKeys = { + distT: "distT", + distB: "distB", + distL: "distL", + distR: "distR", + wrapText: "wrapText", + }; +} + +export class WrapSquare extends XmlComponent { + constructor(textWrapping: TextWrapping) { + super("wp:wrapSquare"); + + this.root.push( + new WrapSquareAttributes({ + wrapText: textWrapping.wrapTextOption || WrapTextOption.BOTH_SIDES, + ...textWrapping.distanceFromText, + }), + ); + } +} diff --git a/src/file/drawing/text-wrap/wrap-tight.ts b/src/file/drawing/text-wrap/wrap-tight.ts new file mode 100644 index 0000000000..0703ebaaff --- /dev/null +++ b/src/file/drawing/text-wrap/wrap-tight.ts @@ -0,0 +1,33 @@ +// http://officeopenxml.com/drwPicFloating-textWrap.php +import { XmlComponent, XmlAttributeComponent } from "file/xml-components"; +import { Distance } from "../drawing"; + +interface IWrapTightAttributes { + distT?: number; + distB?: number; +} + +class WrapTightAttributes extends XmlAttributeComponent { + protected xmlKeys = { + distT: "distT", + distB: "distB", + }; +} + +export class WrapTight extends XmlComponent { + constructor(distanceFromText?: Distance) { + super("wp:wrapTight"); + + distanceFromText = distanceFromText || { + distT: 0, + distB: 0, + }; + + this.root.push( + new WrapTightAttributes({ + distT: distanceFromText.distT, + distB: distanceFromText.distB, + }), + ); + } +} diff --git a/src/file/drawing/text-wrap/wrap-top-and-bottom.ts b/src/file/drawing/text-wrap/wrap-top-and-bottom.ts new file mode 100644 index 0000000000..a161058783 --- /dev/null +++ b/src/file/drawing/text-wrap/wrap-top-and-bottom.ts @@ -0,0 +1,33 @@ +// http://officeopenxml.com/drwPicFloating-textWrap.php +import { XmlComponent, XmlAttributeComponent } from "file/xml-components"; +import { Distance } from "../drawing"; + +interface IWrapTopAndBottomAttributes { + distT?: number; + distB?: number; +} + +class WrapTopAndBottomAttributes extends XmlAttributeComponent { + protected xmlKeys = { + distT: "distT", + distB: "distB", + }; +} + +export class WrapTopAndBottom extends XmlComponent { + constructor(distanceFromText?: Distance) { + super("wp:wrapTopAndBottom"); + + distanceFromText = distanceFromText || { + distT: 0, + distB: 0, + }; + + this.root.push( + new WrapTopAndBottomAttributes({ + distT: distanceFromText.distT, + distB: distanceFromText.distB, + }), + ); + } +} diff --git a/src/file/paragraph/run/picture-run.ts b/src/file/paragraph/run/picture-run.ts index b949dc023e..fac9ae3354 100644 --- a/src/file/paragraph/run/picture-run.ts +++ b/src/file/paragraph/run/picture-run.ts @@ -1,15 +1,16 @@ import { Drawing } from "../../drawing"; import { IMediaData } from "../../media/data"; import { Run } from "../run"; +import { DrawingOptions } from "../../drawing/drawing"; export class PictureRun extends Run { - constructor(imageData: IMediaData) { + constructor(imageData: IMediaData, drawingOptions?: DrawingOptions) { super(); if (imageData === undefined) { throw new Error("imageData cannot be undefined"); } - this.root.push(new Drawing(imageData)); + this.root.push(new Drawing(imageData, drawingOptions)); } }