add support for floating drawings
- added need elements and test for them
This commit is contained in:
26
src/file/drawing/anchor/anchor-attributes.ts
Normal file
26
src/file/drawing/anchor/anchor-attributes.ts
Normal file
@ -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<IAnchorAttributes> {
|
||||||
|
protected xmlKeys = {
|
||||||
|
distT: "distT",
|
||||||
|
distB: "distB",
|
||||||
|
distL: "distL",
|
||||||
|
distR: "distR",
|
||||||
|
allowOverlap: "allowOverlap",
|
||||||
|
behindDoc: "behindDoc",
|
||||||
|
layoutInCell: "layoutInCell",
|
||||||
|
locked: "locked",
|
||||||
|
relativeHeight: "relativeHeight",
|
||||||
|
simplePos: "simplePos",
|
||||||
|
};
|
||||||
|
}
|
118
src/file/drawing/anchor/anchor.spec.ts
Normal file
118
src/file/drawing/anchor/anchor.spec.ts
Normal file
@ -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");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
88
src/file/drawing/anchor/anchor.ts
Normal file
88
src/file/drawing/anchor/anchor.ts
Normal file
@ -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));
|
||||||
|
}
|
||||||
|
}
|
2
src/file/drawing/anchor/index.ts
Normal file
2
src/file/drawing/anchor/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from "./anchor";
|
||||||
|
export * from "./anchor-attributes";
|
@ -2,14 +2,12 @@ import { assert } from "chai";
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
|
||||||
import { Utility } from "../../tests/utility";
|
import { Utility } from "../../tests/utility";
|
||||||
import { Drawing } from "./";
|
import { Drawing, DrawingOptions, PlacementPosition } from "./";
|
||||||
|
|
||||||
describe("Drawing", () => {
|
function createDrawing(drawingOptions?: DrawingOptions) {
|
||||||
let currentBreak: Drawing;
|
const path = "./demo/images/image1.jpeg";
|
||||||
|
return new Drawing(
|
||||||
beforeEach(() => {
|
{
|
||||||
const path = "./demo/images/image1.jpeg";
|
|
||||||
currentBreak = new Drawing({
|
|
||||||
fileName: "test.jpg",
|
fileName: "test.jpg",
|
||||||
referenceId: 1,
|
referenceId: 1,
|
||||||
stream: fs.createReadStream(path),
|
stream: fs.createReadStream(path),
|
||||||
@ -24,14 +22,33 @@ describe("Drawing", () => {
|
|||||||
y: 100 * 9525,
|
y: 100 * 9525,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
});
|
drawingOptions,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("Drawing", () => {
|
||||||
|
let currentBreak: Drawing;
|
||||||
|
|
||||||
describe("#constructor()", () => {
|
describe("#constructor()", () => {
|
||||||
it("should create a Drawing with correct root key", () => {
|
it("should create a Drawing with correct root key", () => {
|
||||||
|
currentBreak = createDrawing();
|
||||||
const newJson = Utility.jsonify(currentBreak);
|
const newJson = Utility.jsonify(currentBreak);
|
||||||
assert.equal(newJson.rootKey, "w:drawing");
|
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");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,15 +1,49 @@
|
|||||||
import { IMediaData } from "file/media";
|
import { IMediaData } from "file/media";
|
||||||
import { XmlComponent } from "file/xml-components";
|
import { XmlComponent } from "file/xml-components";
|
||||||
import { Inline } from "./inline";
|
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 {
|
export class Drawing extends XmlComponent {
|
||||||
constructor(imageData: IMediaData) {
|
constructor(imageData: IMediaData, drawingOptions?: DrawingOptions) {
|
||||||
super("w:drawing");
|
super("w:drawing");
|
||||||
|
|
||||||
if (imageData === undefined) {
|
if (imageData === undefined) {
|
||||||
throw new Error("imageData cannot be 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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
src/file/drawing/floating/align.spec.ts
Normal file
15
src/file/drawing/floating/align.spec.ts
Normal file
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
10
src/file/drawing/floating/align.ts
Normal file
10
src/file/drawing/floating/align.ts
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
60
src/file/drawing/floating/floating-position.ts
Normal file
60
src/file/drawing/floating/floating-position.ts
Normal file
@ -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;
|
||||||
|
}
|
41
src/file/drawing/floating/horizontal-position.spec.ts
Normal file
41
src/file/drawing/floating/horizontal-position.spec.ts
Normal file
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
35
src/file/drawing/floating/horizontal-position.ts
Normal file
35
src/file/drawing/floating/horizontal-position.ts
Normal file
@ -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<IHorizontalPositionAttributes> {
|
||||||
|
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)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
4
src/file/drawing/floating/index.ts
Normal file
4
src/file/drawing/floating/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from "./floating-position";
|
||||||
|
export * from "./simple-pos";
|
||||||
|
export * from "./horizontal-position";
|
||||||
|
export * from "./vertical-position";
|
14
src/file/drawing/floating/position-offset.spec.ts
Normal file
14
src/file/drawing/floating/position-offset.spec.ts
Normal file
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
9
src/file/drawing/floating/position-offset.ts
Normal file
9
src/file/drawing/floating/position-offset.ts
Normal file
@ -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());
|
||||||
|
}
|
||||||
|
}
|
17
src/file/drawing/floating/simple-pos.spec.ts
Normal file
17
src/file/drawing/floating/simple-pos.spec.ts
Normal file
@ -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,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
28
src/file/drawing/floating/simple-pos.ts
Normal file
28
src/file/drawing/floating/simple-pos.ts
Normal file
@ -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<ISimplePosAttributes> {
|
||||||
|
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,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
41
src/file/drawing/floating/vertical-position.spec.ts
Normal file
41
src/file/drawing/floating/vertical-position.spec.ts
Normal file
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
35
src/file/drawing/floating/vertical-position.ts
Normal file
35
src/file/drawing/floating/vertical-position.ts
Normal file
@ -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<IVerticalPositionAttributes> {
|
||||||
|
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)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,3 @@
|
|||||||
export { Drawing } from "./drawing";
|
export * from "./drawing";
|
||||||
|
export * from "./text-wrap";
|
||||||
|
export * from "./floating";
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import { XmlAttributeComponent } from "file/xml-components";
|
import { XmlAttributeComponent } from "file/xml-components";
|
||||||
|
import { Distance } from "../drawing";
|
||||||
|
|
||||||
export interface IInlineAttributes {
|
export interface IInlineAttributes extends Distance {}
|
||||||
distT?: number;
|
|
||||||
distB?: number;
|
|
||||||
distL?: number;
|
|
||||||
distR?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class InlineAttributes extends XmlAttributeComponent<IInlineAttributes> {
|
export class InlineAttributes extends XmlAttributeComponent<IInlineAttributes> {
|
||||||
protected xmlKeys = {
|
protected xmlKeys = {
|
||||||
|
5
src/file/drawing/text-wrap/index.ts
Normal file
5
src/file/drawing/text-wrap/index.ts
Normal file
@ -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";
|
22
src/file/drawing/text-wrap/text-wrapping.ts
Normal file
22
src/file/drawing/text-wrap/text-wrapping.ts
Normal file
@ -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;
|
||||||
|
}
|
8
src/file/drawing/text-wrap/wrap-none.ts
Normal file
8
src/file/drawing/text-wrap/wrap-none.ts
Normal file
@ -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");
|
||||||
|
}
|
||||||
|
}
|
31
src/file/drawing/text-wrap/wrap-square.ts
Normal file
31
src/file/drawing/text-wrap/wrap-square.ts
Normal file
@ -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<IWrapSquareAttributes> {
|
||||||
|
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,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
33
src/file/drawing/text-wrap/wrap-tight.ts
Normal file
33
src/file/drawing/text-wrap/wrap-tight.ts
Normal file
@ -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<IWrapTightAttributes> {
|
||||||
|
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,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
33
src/file/drawing/text-wrap/wrap-top-and-bottom.ts
Normal file
33
src/file/drawing/text-wrap/wrap-top-and-bottom.ts
Normal file
@ -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<IWrapTopAndBottomAttributes> {
|
||||||
|
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,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,16 @@
|
|||||||
import { Drawing } from "../../drawing";
|
import { Drawing } from "../../drawing";
|
||||||
import { IMediaData } from "../../media/data";
|
import { IMediaData } from "../../media/data";
|
||||||
import { Run } from "../run";
|
import { Run } from "../run";
|
||||||
|
import { DrawingOptions } from "../../drawing/drawing";
|
||||||
|
|
||||||
export class PictureRun extends Run {
|
export class PictureRun extends Run {
|
||||||
constructor(imageData: IMediaData) {
|
constructor(imageData: IMediaData, drawingOptions?: DrawingOptions) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (imageData === undefined) {
|
if (imageData === undefined) {
|
||||||
throw new Error("imageData cannot be undefined");
|
throw new Error("imageData cannot be undefined");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.root.push(new Drawing(imageData));
|
this.root.push(new Drawing(imageData, drawingOptions));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user