Skip to content

feat: basic wps text box support #3182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/file/drawing/anchor/anchor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// http://officeopenxml.com/drwPicFloating.php
import { IMediaData, IMediaDataTransformation } from "@file/media";
import { IExtendedMediaData, IMediaDataTransformation } from "@file/media";
import { XmlComponent } from "@file/xml-components";

import { IDrawingOptions } from "../drawing";
Expand Down Expand Up @@ -43,7 +43,7 @@ export class Anchor extends XmlComponent {
transform,
drawingOptions,
}: {
readonly mediaData: IMediaData;
readonly mediaData: IExtendedMediaData;
readonly transform: IMediaDataTransformation;
readonly drawingOptions: IDrawingOptions;
}) {
Expand Down Expand Up @@ -101,6 +101,6 @@ export class Anchor extends XmlComponent {

this.root.push(new DocProperties(drawingOptions.docProperties));
this.root.push(createGraphicFrameProperties());
this.root.push(new Graphic({ mediaData, transform, outline: drawingOptions.outline }));
this.root.push(new Graphic({ mediaData, transform, outline: drawingOptions.outline, solidFill: drawingOptions.solidFill }));
}
}
5 changes: 3 additions & 2 deletions src/file/drawing/doc-properties/doc-properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,19 @@ export type DocPropertiesOptions = {
readonly name: string;
readonly description?: string;
readonly title?: string;
readonly id?: string;
};

export class DocProperties extends XmlComponent {
private readonly docPropertiesUniqueNumericId = docPropertiesUniqueNumericIdGen();

public constructor({ name, description, title }: DocPropertiesOptions = { name: "", description: "", title: "" }) {
public constructor({ name, description, title, id }: DocPropertiesOptions = { name: "", description: "", title: "" }) {
super("wp:docPr");

const attributes: Record<string, { readonly key: string; readonly value: string | number }> = {
id: {
key: "id",
value: this.docPropertiesUniqueNumericId(),
value: id ?? this.docPropertiesUniqueNumericId(),
},
name: {
key: "name",
Expand Down
7 changes: 5 additions & 2 deletions src/file/drawing/drawing.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { IMediaData } from "@file/media";
import { IExtendedMediaData } from "@file/media";
import { XmlComponent } from "@file/xml-components";

import { Anchor } from "./anchor";
import { DocPropertiesOptions } from "./doc-properties/doc-properties";
import { IFloating } from "./floating";
import { createInline } from "./inline";
import { OutlineOptions } from "./inline/graphic/graphic-data/pic/shape-properties/outline/outline";
import { SolidFillOptions } from "./inline/graphic/graphic-data/pic/shape-properties/outline/solid-fill";

export type IDistance = {
readonly distT?: number;
Expand All @@ -18,6 +19,7 @@ export type IDrawingOptions = {
readonly floating?: IFloating;
readonly docProperties?: DocPropertiesOptions;
readonly outline?: OutlineOptions;
readonly solidFill?: SolidFillOptions;
};

// <xsd:complexType name="CT_Drawing">
Expand All @@ -28,7 +30,7 @@ export type IDrawingOptions = {
// </xsd:complexType>

export class Drawing extends XmlComponent {
public constructor(imageData: IMediaData, drawingOptions: IDrawingOptions = {}) {
public constructor(imageData: IExtendedMediaData, drawingOptions: IDrawingOptions = {}) {
super("w:drawing");

if (!drawingOptions.floating) {
Expand All @@ -38,6 +40,7 @@ export class Drawing extends XmlComponent {
transform: imageData.transformation,
docProperties: drawingOptions.docProperties,
outline: drawingOptions.outline,
solidFill: drawingOptions.solidFill,
}),
);
} else {
Expand Down
38 changes: 27 additions & 11 deletions src/file/drawing/inline/graphic/graphic-data/graphic-data.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,48 @@
import { IMediaData, IMediaDataTransformation } from "@file/media";
import { WpsShape } from "@file/drawing/inline/graphic/graphic-data/wps/wps-shape";
import { IExtendedMediaData, IMediaDataTransformation } from "@file/media";
import { XmlComponent } from "@file/xml-components";

import { GraphicDataAttributes } from "./graphic-data-attribute";
import { Pic } from "./pic";
import { OutlineOptions } from "./pic/shape-properties/outline/outline";
import { SolidFillOptions } from "./pic/shape-properties/outline/solid-fill";

export class GraphicData extends XmlComponent {
private readonly pic: Pic;
// private readonly pic: Pic;

public constructor({
mediaData,
transform,
outline,
solidFill,
}: {
readonly mediaData: IMediaData;
readonly mediaData: IExtendedMediaData;
readonly transform: IMediaDataTransformation;
readonly outline?: OutlineOptions;
readonly solidFill?: SolidFillOptions;
}) {
super("a:graphicData");

this.root.push(
new GraphicDataAttributes({
uri: "http://schemas.openxmlformats.org/drawingml/2006/picture",
}),
);
if (mediaData.type === "wps") {
this.root.push(
new GraphicDataAttributes({
uri: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
}),
);
} else {
this.root.push(
new GraphicDataAttributes({
uri: "http://schemas.openxmlformats.org/drawingml/2006/picture",
}),
);
}

this.pic = new Pic({ mediaData, transform, outline });

this.root.push(this.pic);
if (mediaData.type !== "wps") {
const pic = new Pic({ mediaData, transform, outline });
this.root.push(pic);
} else {
const wps = new WpsShape({ ...mediaData.data, transformation: transform, outline, solidFill });
this.root.push(wps);
}
}
}
2 changes: 1 addition & 1 deletion src/file/drawing/inline/graphic/graphic-data/pic/pic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ export class Pic extends XmlComponent {

this.root.push(new NonVisualPicProperties());
this.root.push(new BlipFill(mediaData));
this.root.push(new ShapeProperties({ transform, outline }));
this.root.push(new ShapeProperties({ element: "pic", transform, outline }));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,25 @@ import { XmlComponent } from "@file/xml-components";
import { Form } from "./form";
import { createNoFill } from "./outline/no-fill";
import { OutlineOptions, createOutline } from "./outline/outline";
import { SolidFillOptions, createSolidFill } from "./outline/solid-fill";
import { PresetGeometry } from "./preset-geometry/preset-geometry";
import { ShapePropertiesAttributes } from "./shape-properties-attributes";

export class ShapeProperties extends XmlComponent {
private readonly form: Form;

public constructor({ outline, transform }: { readonly outline?: OutlineOptions; readonly transform: IMediaDataTransformation }) {
super("pic:spPr");
public constructor({
element,
outline,
solidFill,
transform,
}: {
readonly element: string;
readonly outline?: OutlineOptions;
readonly solidFill?: SolidFillOptions;
readonly transform: IMediaDataTransformation;
}) {
super(`${element}:spPr`);

this.root.push(
new ShapePropertiesAttributes({
Expand All @@ -29,5 +40,9 @@ export class ShapeProperties extends XmlComponent {
this.root.push(createNoFill());
this.root.push(createOutline(outline));
}

if (solidFill) {
this.root.push(createSolidFill(solidFill));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { TextWrappingType } from "@file/drawing/text-wrap";
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { OnOffElement } from "@file/xml-components/simple-elements";

export enum VerticalAnchor {
CENTER = "ctr",
TOP = "t",
BOTTOM = "b",
}

export type IBodyPropertiesOptions = {
readonly wrap?: (typeof TextWrappingType)[keyof typeof TextWrappingType];
readonly verticalAnchor?: VerticalAnchor;
readonly margins?: {
readonly top?: number;
readonly bottom?: number;
readonly left?: number;
readonly right?: number;
};
readonly noAutoFit?: boolean;
};

class BodyPropertiesAttributes extends XmlAttributeComponent<{
// readonly wrap?: (typeof TextWrappingType)[keyof typeof TextWrappingType];
readonly lIns?: number;
readonly rIns?: number;
readonly tIns?: number;
readonly bIns?: number;
readonly anchor?: VerticalAnchor;
}> {
protected readonly xmlKeys = {
wrap: "wrap",
lIns: "lIns",
rIns: "rIns",
tIns: "tIns",
bIns: "bIns",
anchor: "anchor",
};
}

export class BodyProperties extends XmlComponent {
public constructor(options: IBodyPropertiesOptions = {}) {
super("wps:bodyPr");

this.root.push(
new BodyPropertiesAttributes({
// wrap: options.wrap,
lIns: options.margins?.left,
rIns: options.margins?.right,
tIns: options.margins?.top,
bIns: options.margins?.bottom,
anchor: options.verticalAnchor,
}),
);

if (options.noAutoFit) {
this.root.push(new OnOffElement("a:noAutofit", options.noAutoFit));
}
}
}
2 changes: 2 additions & 0 deletions src/file/drawing/inline/graphic/graphic-data/wps/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./wps-shape";
export * from "./body-properties";
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";

export type INonVisualShapePropertiesOptions = {
readonly txBox: string;
};

class NonVisualShapePropertiesAttributes extends XmlAttributeComponent<{
readonly txBox: string;
}> {
protected readonly xmlKeys = {
txBox: "txBox",
};
}

export class NonVisualShapeProperties extends XmlComponent {
public constructor(options: INonVisualShapePropertiesOptions = { txBox: "1" }) {
super("wps:cNvSpPr");

this.root.push(
new NonVisualShapePropertiesAttributes({
txBox: options.txBox,
}),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Paragraph } from "@file/paragraph";
import { XmlComponent } from "@file/xml-components";

export class TextBoxContent extends XmlComponent {
public constructor(children: readonly Paragraph[]) {
super("w:txbxContent");

for (const child of children) {
this.root.push(child);
}
}
}
40 changes: 40 additions & 0 deletions src/file/drawing/inline/graphic/graphic-data/wps/wps-shape.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { IMediaDataTransformation } from "@file/media";
import { Paragraph } from "@file/paragraph";
import { XmlComponent } from "@file/xml-components";

import { BodyProperties, IBodyPropertiesOptions } from "./body-properties";
import { INonVisualShapePropertiesOptions, NonVisualShapeProperties } from "./non-visual-shape-properties";
import { WpsTextBox } from "./wps-text-box";
import { OutlineOptions } from "../pic/shape-properties/outline/outline";
import { SolidFillOptions } from "../pic/shape-properties/outline/solid-fill";
import { ShapeProperties } from "../pic/shape-properties/shape-properties";

export type WpsShapeCoreOptions = {
readonly children: readonly Paragraph[];
readonly nonVisualProperties?: INonVisualShapePropertiesOptions;
readonly bodyProperties?: IBodyPropertiesOptions;
};

export type WpsShapeOptions = WpsShapeCoreOptions & {
readonly transformation: IMediaDataTransformation;
readonly outline?: OutlineOptions;
readonly solidFill?: SolidFillOptions;
};

export class WpsShape extends XmlComponent {
public constructor(options: WpsShapeOptions) {
super("wps:wsp");

this.root.push(new NonVisualShapeProperties(options.nonVisualProperties));
this.root.push(
new ShapeProperties({
element: "wps",
transform: options.transformation,
outline: options.outline,
solidFill: options.solidFill,
}),
);
this.root.push(new WpsTextBox(options.children));
this.root.push(new BodyProperties(options.bodyProperties));
}
}
11 changes: 11 additions & 0 deletions src/file/drawing/inline/graphic/graphic-data/wps/wps-text-box.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Paragraph } from "@file/paragraph";
import { XmlComponent } from "@file/xml-components";

import { TextBoxContent } from "./text-box-content";

export class WpsTextBox extends XmlComponent {
public constructor(children: readonly Paragraph[]) {
super("wps:txbx");
this.root.push(new TextBoxContent(children));
}
}
9 changes: 6 additions & 3 deletions src/file/drawing/inline/graphic/graphic.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { IMediaData, IMediaDataTransformation } from "@file/media";
import { IExtendedMediaData, IMediaDataTransformation } from "@file/media";
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";

import { GraphicData } from "./graphic-data";
import { OutlineOptions } from "./graphic-data/pic/shape-properties/outline/outline";
import { SolidFillOptions } from "./graphic-data/pic/shape-properties/outline/solid-fill";

class GraphicAttributes extends XmlAttributeComponent<{
readonly a: string;
Expand All @@ -19,10 +20,12 @@ export class Graphic extends XmlComponent {
mediaData,
transform,
outline,
solidFill,
}: {
readonly mediaData: IMediaData;
readonly mediaData: IExtendedMediaData;
readonly transform: IMediaDataTransformation;
readonly outline?: OutlineOptions;
readonly solidFill?: SolidFillOptions;
}) {
super("a:graphic");
this.root.push(
Expand All @@ -31,7 +34,7 @@ export class Graphic extends XmlComponent {
}),
);

this.data = new GraphicData({ mediaData, transform, outline });
this.data = new GraphicData({ mediaData, transform, outline, solidFill });

this.root.push(this.data);
}
Expand Down
Loading
Loading