#1699 Allow images to work with Hyperlink
Add stack to IContext for prepForXml
This commit is contained in:
@ -47,7 +47,9 @@
|
|||||||
"/xmlKeys = {[^}]+}/g",
|
"/xmlKeys = {[^}]+}/g",
|
||||||
"/\\.to\\.deep\\.equal\\({[^)]+}\\)/g",
|
"/\\.to\\.deep\\.equal\\({[^)]+}\\)/g",
|
||||||
"\\.to\\.include\\.members\\(\\[[^\\]]+]\\)",
|
"\\.to\\.include\\.members\\(\\[[^\\]]+]\\)",
|
||||||
"/new [a-zA-Z]+\\({[^£]+}\\)/g"
|
"/new [a-zA-Z]+\\({[^£]+}\\)/g",
|
||||||
|
"/<element name=\"[a-z]+\"/gi",
|
||||||
|
"/<attribute name=\"[a-z]+\"/gi"
|
||||||
],
|
],
|
||||||
"ignorePaths": ["package.json", "docs/api"],
|
"ignorePaths": ["package.json", "docs/api"],
|
||||||
"allowCompoundWords": true,
|
"allowCompoundWords": true,
|
||||||
|
@ -2,7 +2,7 @@ import { BaseXmlComponent, IContext, IXmlableObject } from "@file/xml-components
|
|||||||
|
|
||||||
export class Formatter {
|
export class Formatter {
|
||||||
// tslint:disable-next-line: no-object-literal-type-assertion
|
// tslint:disable-next-line: no-object-literal-type-assertion
|
||||||
public format(input: BaseXmlComponent, context: IContext = {} as IContext): IXmlableObject {
|
public format(input: BaseXmlComponent, context: IContext = { stack: [] } as unknown as IContext): IXmlableObject {
|
||||||
const output = input.prepForXml(context);
|
const output = input.prepForXml(context);
|
||||||
|
|
||||||
if (output) {
|
if (output) {
|
||||||
|
@ -74,6 +74,7 @@ export class Compiler {
|
|||||||
this.formatter.format(file.Document.View, {
|
this.formatter.format(file.Document.View, {
|
||||||
viewWrapper: file.Document,
|
viewWrapper: file.Document,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -100,6 +101,7 @@ export class Compiler {
|
|||||||
this.formatter.format(file.Document.Relationships, {
|
this.formatter.format(file.Document.Relationships, {
|
||||||
viewWrapper: file.Document,
|
viewWrapper: file.Document,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -125,6 +127,7 @@ export class Compiler {
|
|||||||
this.formatter.format(file.Styles, {
|
this.formatter.format(file.Styles, {
|
||||||
viewWrapper: file.Document,
|
viewWrapper: file.Document,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -144,6 +147,7 @@ export class Compiler {
|
|||||||
this.formatter.format(file.CoreProperties, {
|
this.formatter.format(file.CoreProperties, {
|
||||||
viewWrapper: file.Document,
|
viewWrapper: file.Document,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -160,6 +164,7 @@ export class Compiler {
|
|||||||
this.formatter.format(file.Numbering, {
|
this.formatter.format(file.Numbering, {
|
||||||
viewWrapper: file.Document,
|
viewWrapper: file.Document,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -176,6 +181,7 @@ export class Compiler {
|
|||||||
this.formatter.format(file.FileRelationships, {
|
this.formatter.format(file.FileRelationships, {
|
||||||
viewWrapper: file.Document,
|
viewWrapper: file.Document,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -191,6 +197,7 @@ export class Compiler {
|
|||||||
this.formatter.format(headerWrapper.View, {
|
this.formatter.format(headerWrapper.View, {
|
||||||
viewWrapper: headerWrapper,
|
viewWrapper: headerWrapper,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -214,6 +221,7 @@ export class Compiler {
|
|||||||
this.formatter.format(headerWrapper.Relationships, {
|
this.formatter.format(headerWrapper.Relationships, {
|
||||||
viewWrapper: headerWrapper,
|
viewWrapper: headerWrapper,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -230,6 +238,7 @@ export class Compiler {
|
|||||||
this.formatter.format(footerWrapper.View, {
|
this.formatter.format(footerWrapper.View, {
|
||||||
viewWrapper: footerWrapper,
|
viewWrapper: footerWrapper,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -253,6 +262,7 @@ export class Compiler {
|
|||||||
this.formatter.format(footerWrapper.Relationships, {
|
this.formatter.format(footerWrapper.Relationships, {
|
||||||
viewWrapper: footerWrapper,
|
viewWrapper: footerWrapper,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -269,6 +279,7 @@ export class Compiler {
|
|||||||
this.formatter.format(headerWrapper.View, {
|
this.formatter.format(headerWrapper.View, {
|
||||||
viewWrapper: headerWrapper,
|
viewWrapper: headerWrapper,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -293,6 +304,7 @@ export class Compiler {
|
|||||||
this.formatter.format(footerWrapper.View, {
|
this.formatter.format(footerWrapper.View, {
|
||||||
viewWrapper: footerWrapper,
|
viewWrapper: footerWrapper,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -317,6 +329,7 @@ export class Compiler {
|
|||||||
this.formatter.format(file.ContentTypes, {
|
this.formatter.format(file.ContentTypes, {
|
||||||
viewWrapper: file.Document,
|
viewWrapper: file.Document,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -332,6 +345,7 @@ export class Compiler {
|
|||||||
this.formatter.format(file.CustomProperties, {
|
this.formatter.format(file.CustomProperties, {
|
||||||
viewWrapper: file.Document,
|
viewWrapper: file.Document,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -348,6 +362,7 @@ export class Compiler {
|
|||||||
this.formatter.format(file.AppProperties, {
|
this.formatter.format(file.AppProperties, {
|
||||||
viewWrapper: file.Document,
|
viewWrapper: file.Document,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -363,7 +378,8 @@ export class Compiler {
|
|||||||
data: xml(
|
data: xml(
|
||||||
this.formatter.format(file.FootNotes.View, {
|
this.formatter.format(file.FootNotes.View, {
|
||||||
viewWrapper: file.FootNotes,
|
viewWrapper: file.FootNotes,
|
||||||
file: file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -378,7 +394,8 @@ export class Compiler {
|
|||||||
data: xml(
|
data: xml(
|
||||||
this.formatter.format(file.FootNotes.Relationships, {
|
this.formatter.format(file.FootNotes.Relationships, {
|
||||||
viewWrapper: file.FootNotes,
|
viewWrapper: file.FootNotes,
|
||||||
file: file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -394,6 +411,7 @@ export class Compiler {
|
|||||||
this.formatter.format(file.Settings, {
|
this.formatter.format(file.Settings, {
|
||||||
viewWrapper: file.Document,
|
viewWrapper: file.Document,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
@ -410,6 +428,7 @@ export class Compiler {
|
|||||||
this.formatter.format(file.Comments, {
|
this.formatter.format(file.Comments, {
|
||||||
viewWrapper: file.Document,
|
viewWrapper: file.Document,
|
||||||
file,
|
file,
|
||||||
|
stack: [],
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
indent: prettify,
|
indent: prettify,
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
|
||||||
|
import { Formatter } from "@export/formatter";
|
||||||
|
|
||||||
|
import { createHyperlinkClick, createHyperlinkHover } from "./doc-properties-children";
|
||||||
|
|
||||||
|
describe("Document Properties Children", () => {
|
||||||
|
describe("#createHyperlinkClick", () => {
|
||||||
|
it("should create a Hyperlink Click component", () => {
|
||||||
|
const tree = new Formatter().format(createHyperlinkClick("1", false));
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"a:hlinkClick": {
|
||||||
|
_attr: {
|
||||||
|
"r:id": "rId1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create a Hyperlink Click component with xmlns:a", () => {
|
||||||
|
const tree = new Formatter().format(createHyperlinkClick("1", true));
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"a:hlinkClick": {
|
||||||
|
_attr: {
|
||||||
|
"r:id": "rId1",
|
||||||
|
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("#createHyperlinkHover", () => {
|
||||||
|
it("should create a Hyperlink Hover component", () => {
|
||||||
|
const tree = new Formatter().format(createHyperlinkHover("1", false));
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"a:hlinkHover": {
|
||||||
|
_attr: {
|
||||||
|
"r:id": "rId1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create a Hyperlink Hover component with xmlns:a", () => {
|
||||||
|
const tree = new Formatter().format(createHyperlinkHover("1", true));
|
||||||
|
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"a:hlinkHover": {
|
||||||
|
_attr: {
|
||||||
|
"r:id": "rId1",
|
||||||
|
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
57
src/file/drawing/doc-properties/doc-properties-children.ts
Normal file
57
src/file/drawing/doc-properties/doc-properties-children.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// <sequence>
|
||||||
|
// <element name="hlinkClick" type="CT_Hyperlink" minOccurs="0" maxOccurs="1" />
|
||||||
|
// <element name="hlinkHover" type="CT_Hyperlink" minOccurs="0" maxOccurs="1" />
|
||||||
|
// <element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1" />
|
||||||
|
// </sequence>
|
||||||
|
|
||||||
|
import { BuilderElement, XmlComponent } from "@file/xml-components";
|
||||||
|
|
||||||
|
// <xsd:complexType name="CT_Hyperlink">
|
||||||
|
// <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded" />
|
||||||
|
// <xsd:attribute name="tgtFrame" type="s:ST_String" use="optional" />
|
||||||
|
// <xsd:attribute name="tooltip" type="s:ST_String" use="optional" />
|
||||||
|
// <xsd:attribute name="docLocation" type="s:ST_String" use="optional" />
|
||||||
|
// <xsd:attribute name="history" type="s:ST_OnOff" use="optional" />
|
||||||
|
// <xsd:attribute name="anchor" type="s:ST_String" use="optional" />
|
||||||
|
// <xsd:attribute ref="r:id" />
|
||||||
|
// </xsd:complexType>
|
||||||
|
|
||||||
|
// TODO: Implement the rest of the attributes
|
||||||
|
|
||||||
|
export const createHyperlinkClick = (linkId: string, hasXmlNs: boolean): XmlComponent =>
|
||||||
|
new BuilderElement({
|
||||||
|
name: "a:hlinkClick",
|
||||||
|
attributes: {
|
||||||
|
...(hasXmlNs
|
||||||
|
? {
|
||||||
|
xmlns: {
|
||||||
|
key: "xmlns:a",
|
||||||
|
value: "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
id: {
|
||||||
|
key: "r:id",
|
||||||
|
value: `rId${linkId}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createHyperlinkHover = (linkId: string, hasXmlNs: boolean): XmlComponent =>
|
||||||
|
new BuilderElement({
|
||||||
|
name: "a:hlinkHover",
|
||||||
|
attributes: {
|
||||||
|
...(hasXmlNs
|
||||||
|
? {
|
||||||
|
xmlns: {
|
||||||
|
key: "xmlns:a",
|
||||||
|
value: "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
id: {
|
||||||
|
key: "r:id",
|
||||||
|
value: `rId${linkId}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
@ -1,19 +1,22 @@
|
|||||||
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
|
// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_docPr_topic_ID0ES32OB.html
|
||||||
|
import { IContext, IXmlableObject, NextAttributeComponent, XmlComponent } from "@file/xml-components";
|
||||||
|
import { ConcreteHyperlink } from "@file/paragraph";
|
||||||
|
|
||||||
import { uniqueNumericId } from "@util/convenience-functions";
|
import { uniqueNumericId } from "@util/convenience-functions";
|
||||||
|
|
||||||
class DocPropertiesAttributes extends XmlAttributeComponent<{
|
import { createHyperlinkClick } from "./doc-properties-children";
|
||||||
readonly id?: number;
|
|
||||||
readonly name?: string;
|
// <complexType name="CT_NonVisualDrawingProps">
|
||||||
readonly description?: string;
|
// <sequence>
|
||||||
readonly title?: string;
|
// <element name="hlinkClick" type="CT_Hyperlink" minOccurs="0" maxOccurs="1" />
|
||||||
}> {
|
// <element name="hlinkHover" type="CT_Hyperlink" minOccurs="0" maxOccurs="1" />
|
||||||
protected readonly xmlKeys = {
|
// <element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1" />
|
||||||
id: "id",
|
// </sequence>
|
||||||
name: "name",
|
// <attribute name="id" type="ST_DrawingElementId" use="required" />
|
||||||
description: "descr",
|
// <attribute name="name" type="xsd:string" use="required" />
|
||||||
title: "title",
|
// <attribute name="descr" type="xsd:string" use="optional" default="" />
|
||||||
};
|
// <attribute name="hidden" type="xsd:boolean" use="optional" default="false" />
|
||||||
}
|
// </complexType>
|
||||||
|
|
||||||
export interface DocPropertiesOptions {
|
export interface DocPropertiesOptions {
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
@ -26,12 +29,39 @@ export class DocProperties extends XmlComponent {
|
|||||||
super("wp:docPr");
|
super("wp:docPr");
|
||||||
|
|
||||||
this.root.push(
|
this.root.push(
|
||||||
new DocPropertiesAttributes({
|
new NextAttributeComponent({
|
||||||
id: uniqueNumericId(),
|
id: {
|
||||||
name,
|
key: "id",
|
||||||
description,
|
value: uniqueNumericId(),
|
||||||
title,
|
},
|
||||||
|
name: {
|
||||||
|
key: "name",
|
||||||
|
value: name,
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
key: "descr",
|
||||||
|
value: description,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
key: "title",
|
||||||
|
value: title,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public prepForXml(context: IContext): IXmlableObject | undefined {
|
||||||
|
for (let i = context.stack.length - 1; i >= 0; i--) {
|
||||||
|
const element = context.stack[i];
|
||||||
|
if (!(element instanceof ConcreteHyperlink)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.root.push(createHyperlinkClick(element.linkId, true));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.prepForXml(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { SinonStub, stub } from "sinon";
|
import { SinonStub, stub } from "sinon";
|
||||||
|
|
||||||
|
import { IContext } from "@file/xml-components";
|
||||||
import { Formatter } from "@export/formatter";
|
import { Formatter } from "@export/formatter";
|
||||||
import * as convenienceFunctions from "@util/convenience-functions";
|
import * as convenienceFunctions from "@util/convenience-functions";
|
||||||
|
|
||||||
|
import { ConcreteHyperlink, TextRun } from "../";
|
||||||
import { Drawing, IDrawingOptions } from "./drawing";
|
import { Drawing, IDrawingOptions } from "./drawing";
|
||||||
|
|
||||||
const imageBase64Data = `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`;
|
const imageBase64Data = `iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAACzVBMVEUAAAAAAAAAAAAAAAA/AD8zMzMqKiokJCQfHx8cHBwZGRkuFxcqFSonJyckJCQiIiIfHx8eHh4cHBwoGhomGSYkJCQhISEfHx8eHh4nHR0lHBwkGyQjIyMiIiIgICAfHx8mHh4lHh4kHR0jHCMiGyIhISEgICAfHx8lHx8kHh4jHR0hHCEhISEgICAlHx8kHx8jHh4jHh4iHSIhHCEhISElICAkHx8jHx8jHh4iHh4iHSIhHSElICAkICAjHx8jHx8iHh4iHh4hHiEhHSEkICAjHx8iHx8iHx8hHh4hHiEkHSEjHSAjHx8iHx8iHx8hHh4kHiEkHiEjHSAiHx8hHx8hHh4kHiEjHiAjHSAiHx8iHx8hHx8kHh4jHiEjHiAjHiAiICAiHx8kHx8jHh4jHiEjHiAiHiAiHSAiHx8jHx8jHx8jHiAiHiAiHiAiHSAiHx8jHx8jHx8iHiAiHiAiHiAjHx8jHx8jHx8jHx8iHiAiHiAiHiAjHx8jHx8jHx8iHx8iHSAiHiAjHiAjHx8jHx8hHx8iHx8iHyAiHiAjHiAjHiAjHh4hHx8iHx8iHx8iHyAjHSAjHiAjHiAjHh4hHx8iHx8iHx8jHyAjHiAhHh4iHx8iHx8jHyAjHSAjHSAhHiAhHh4iHx8iHx8jHx8jHyAjHSAjHSAiHh4iHh4jHx8jHx8jHyAjHyAhHSAhHSAiHh4iHh4jHx8jHx8jHyAhHyAhHSAiHSAiHh4jHh4jHx8jHx8jHyAhHyAhHSAiHSAjHR4jHh4jHx8jHx8hHyAhHyAiHSAjHSAjHR4jHh4jHx8hHx8hHyAhHyAiHyAjHSAjHR4jHR4hHh4hHx8hHyAiHyAjHyAjHSAjHR4jHR4hHh4hHx8hHyAjHyAjHyAjHSAjHR4hHR4hHR4hHx8iHyAjHyAjHyAjHSAhHR4hHR4hHR4hHx8jHyAjHyAjHyAjHyC9S2xeAAAA7nRSTlMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFxgZGhscHR4fICEiIyQlJicoKSorLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZISUpLTE1OUFFSU1RVVllaW1xdXmBhYmNkZWZnaGprbG1ub3Byc3R1dnd4eXp8fn+AgYKDhIWGiImKi4yNj5CRkpOUlZaXmJmam5ydnp+goaKjpKaoqqusra6vsLGys7S1tri5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+fkZpVQAABcBJREFUGBntwftjlQMcBvDnnLNL22qzJjWlKLHFVogyty3SiFq6EZliqZGyhnSxsLlMRahYoZKRFcul5dKFCatYqWZaNKvWtrPz/A2+7/b27qRzec/lPfvl/XxgMplMJpPJZDKZAtA9HJ3ppnIez0KnSdtC0RCNznHdJrbrh85wdSlVVRaEXuoGamYi5K5430HNiTiEWHKJg05eRWgNfKeV7RxbqUhGKPV/207VupQ8is0IoX5vtFC18SqEHaK4GyHTZ2kzVR8PBTCO4oANIZL4ShNVZcOhKKeYg9DoWdhI1ec3os2VFI0JCIUez5+i6st0qJZRrEAIJCw+QdW223BG/EmKwTBc/IJ/qfp2FDrkUnwFo8U9dZyqnaPhxLqfYjyM1S3vb6p+GGOBszsojoTDSDFz6qj66R4LzvYJxVMwUNRjf1H1ywQr/megg2RzLximy8waqvbda8M5iijegVEiHjlM1W/3h+FcXesphsMY4dMOUnUgOxyuPEzxPQwRNvV3qg5Nj4BreyimwADWe/dRVTMjEm6MoGLzGwtystL6RyOY3qSqdlYU3FpLZw1VW0sK5943MvUCKwJ1noNtjs6Ohge76Zq9ZkfpigU5WWkDYuCfbs1U5HWFR8/Qq4a9W0uK5k4ZmdrTCl8spGIePLPlbqqsc1Afe83O0hULc8alDYiBd7ZyitYMeBfR55rR2fOKP6ioPk2dGvZ+UVI0d8rtqT2tcCexlqK2F3wRn5Q+YVbBqrLKOupkr9lZujAOrmS0UpTb4JeIPkNHZ+cXr6uoPk2vyuBSPhWLEKj45PQJuQWryyqP0Z14uGLdROHIRNBEXDR09EP5r62rOHCazhrD4VKPwxTH+sIA3ZPTJ+YuWV22n+IruHFDC8X2CBjnPoolcGc2FYUwzmsUWXDHsoGKLBhmN0VvuBVfTVE/AAbpaid5CB4MbaLY1QXGuIViLTyZQcVyGGMuxWPwaA0Vk2GI9RRp8Ci2iuLkIBjhT5LNUfAspZFiTwyC72KK7+DNg1SsRvCNp3gZXq2k4iEEXSHFJHgVXUlxejCCbTvFAHiXdIJiXxyCK7KJ5FHoMZGK9xBcwyg2QpdlVMxEUM2iyIMuXXZQNF+HswxMsSAAJRQjoE//eoqDCXBSTO6f1xd+O0iyNRY6jaWi1ALNYCocZROj4JdEikroVkjFk9DcStXxpdfCD2MoXodu4RUU9ptxxmXssOfxnvDVcxRTod9FxyhqLoAqis5aPhwTDp9spRgEH2Q6KLbYoKqlaKTm6Isp0C/sJMnjFvhiERXPQvUNRe9p29lhR04CdBpC8Sl8YiuncIxEuzUUg4Dkgj+paVozygY9plPMh28SaymO9kabAopREGF3vt9MzeFFl8G7lRSZ8FFGK8XX4VA8QjEd7XrM3M0OXz8YCy+qKBLgq3wqnofiTorF0Ax56Rg1J1elW+BBAsVe+My6iYq7IK6keBdOIseV2qn5Pb8f3MqkWAXf9ThM8c8lAOIotuFsF875lRrH5klRcG0+xcPwQ1oLxfeRAP4heQTnGL78X2rqlw2DK59SXAV/zKaiGMAuko5InCt68mcOan5+ohf+z1pP8lQY/GHZQMV4YD3FpXDp4qerqbF/lBWBswyi+AL+ia+maLgcRRQj4IYlY/UpauqKBsPJAxQF8NM1TRQ/RudSPAD34rK3scOuR8/HGcspxsJfOVS8NZbiGXiUtPgINU3v3WFDmx8pEuG3EiqKKVbCC1vm2iZqap5LAtCtleQf8F9sFYWDohzeJczYyQ4V2bEZFGsQgJRGqqqhS2phHTWn9lDkIhBTqWqxQZ+IsRvtdHY9AvI2VX2hW68nfqGmuQsCEl3JdjfCF8OW1bPdtwhQ0gm2mQzfRE3a7KCYj0BNZJs8+Kxf/r6WtTEI2FIqlsMfFgRB5A6KUnSe/vUkX0AnuvUIt8SjM1m6wWQymUwmk8lkMgXRf5vi8rLQxtUhAAAAAElFTkSuQmCC`;
|
||||||
@ -450,5 +452,257 @@ describe("Drawing", () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should create a drawing with a hyperlink", () => {
|
||||||
|
currentBreak = createDrawing({
|
||||||
|
floating: {
|
||||||
|
horizontalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
verticalPosition: {
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const tree = new Formatter().format(currentBreak, {
|
||||||
|
stack: [new ConcreteHyperlink([new TextRun("Test")], "1")],
|
||||||
|
} as unknown as IContext);
|
||||||
|
expect(tree).to.deep.equal({
|
||||||
|
"w:drawing": [
|
||||||
|
{
|
||||||
|
"wp:anchor": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
allowOverlap: "1",
|
||||||
|
behindDoc: "0",
|
||||||
|
distB: 0,
|
||||||
|
distL: 0,
|
||||||
|
distR: 0,
|
||||||
|
distT: 0,
|
||||||
|
layoutInCell: "1",
|
||||||
|
locked: "0",
|
||||||
|
relativeHeight: 952500,
|
||||||
|
simplePos: "0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wp:simplePos": {
|
||||||
|
_attr: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wp:positionH": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
relativeFrom: "page",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wp:posOffset": ["0"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wp:positionV": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
relativeFrom: "page",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wp:posOffset": ["0"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wp:extent": {
|
||||||
|
_attr: {
|
||||||
|
cx: 952500,
|
||||||
|
cy: 952500,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wp:effectExtent": {
|
||||||
|
_attr: {
|
||||||
|
b: 0,
|
||||||
|
l: 0,
|
||||||
|
r: 0,
|
||||||
|
t: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wp:wrapNone": {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wp:docPr": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
descr: "",
|
||||||
|
id: 0,
|
||||||
|
name: "",
|
||||||
|
title: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:hlinkClick": {
|
||||||
|
_attr: {
|
||||||
|
"r:id": "rId1",
|
||||||
|
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"wp:cNvGraphicFramePr": [
|
||||||
|
{
|
||||||
|
"a:graphicFrameLocks": {
|
||||||
|
_attr: {
|
||||||
|
// tslint:disable-next-line:object-literal-key-quotes
|
||||||
|
noChangeAspect: 1,
|
||||||
|
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:graphic": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:graphicData": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
uri: "http://schemas.openxmlformats.org/drawingml/2006/picture",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pic:pic": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
"xmlns:pic": "http://schemas.openxmlformats.org/drawingml/2006/picture",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pic:nvPicPr": [
|
||||||
|
{
|
||||||
|
"pic:cNvPr": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
descr: "",
|
||||||
|
id: 0,
|
||||||
|
name: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:hlinkClick": {
|
||||||
|
_attr: {
|
||||||
|
"r:id": "rId1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pic:cNvPicPr": [
|
||||||
|
{
|
||||||
|
"a:picLocks": {
|
||||||
|
_attr: {
|
||||||
|
noChangeArrowheads: 1,
|
||||||
|
noChangeAspect: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pic:blipFill": [
|
||||||
|
{
|
||||||
|
"a:blip": {
|
||||||
|
_attr: {
|
||||||
|
// tslint:disable-next-line:object-literal-key-quotes
|
||||||
|
cstate: "none",
|
||||||
|
"r:embed": "rId{test.jpg}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:srcRect": {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:stretch": [
|
||||||
|
{
|
||||||
|
"a:fillRect": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pic:spPr": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
bwMode: "auto",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:xfrm": [
|
||||||
|
{
|
||||||
|
_attr: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:off": {
|
||||||
|
_attr: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:ext": {
|
||||||
|
_attr: {
|
||||||
|
cx: 952500,
|
||||||
|
cy: 952500,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:prstGeom": [
|
||||||
|
{
|
||||||
|
_attr: {
|
||||||
|
prst: "rect",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:avLst": {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,21 @@
|
|||||||
import { XmlComponent } from "@file/xml-components";
|
import { IContext, IXmlableObject, XmlComponent } from "@file/xml-components";
|
||||||
|
import { createHyperlinkClick } from "@file/drawing/doc-properties/doc-properties-children";
|
||||||
|
import { ConcreteHyperlink } from "@file/paragraph";
|
||||||
|
|
||||||
import { NonVisualPropertiesAttributes } from "./non-visual-properties-attributes";
|
import { NonVisualPropertiesAttributes } from "./non-visual-properties-attributes";
|
||||||
|
|
||||||
|
// <complexType name="CT_NonVisualDrawingProps">
|
||||||
|
// <sequence>
|
||||||
|
// <element name="hlinkClick" type="CT_Hyperlink" minOccurs="0" maxOccurs="1" />
|
||||||
|
// <element name="hlinkHover" type="CT_Hyperlink" minOccurs="0" maxOccurs="1" />
|
||||||
|
// <element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1" />
|
||||||
|
// </sequence>
|
||||||
|
// <attribute name="id" type="ST_DrawingElementId" use="required" />
|
||||||
|
// <attribute name="name" type="xsd:string" use="required" />
|
||||||
|
// <attribute name="descr" type="xsd:string" use="optional" default="" />
|
||||||
|
// <attribute name="hidden" type="xsd:boolean" use="optional" default="false" />
|
||||||
|
// </complexType>
|
||||||
|
|
||||||
export class NonVisualProperties extends XmlComponent {
|
export class NonVisualProperties extends XmlComponent {
|
||||||
public constructor() {
|
public constructor() {
|
||||||
super("pic:cNvPr");
|
super("pic:cNvPr");
|
||||||
@ -13,4 +28,19 @@ export class NonVisualProperties extends XmlComponent {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public prepForXml(context: IContext): IXmlableObject | undefined {
|
||||||
|
for (let i = context.stack.length - 1; i >= 0; i--) {
|
||||||
|
const element = context.stack[i];
|
||||||
|
if (!(element instanceof ConcreteHyperlink)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.root.push(createHyperlinkClick(element.linkId, false));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.prepForXml(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -954,6 +954,7 @@ describe("Paragraph", () => {
|
|||||||
paragraph.prepForXml({
|
paragraph.prepForXml({
|
||||||
viewWrapper: viewWrapperMock,
|
viewWrapper: viewWrapperMock,
|
||||||
file: file,
|
file: file,
|
||||||
|
stack: [],
|
||||||
});
|
});
|
||||||
const tree = new Formatter().format(paragraph);
|
const tree = new Formatter().format(paragraph);
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -31,6 +31,7 @@ describe("ParagraphProperties", () => {
|
|||||||
} as File,
|
} as File,
|
||||||
// tslint:disable-next-line: no-object-literal-type-assertion
|
// tslint:disable-next-line: no-object-literal-type-assertion
|
||||||
viewWrapper: new DocumentWrapper({ background: {} }),
|
viewWrapper: new DocumentWrapper({ background: {} }),
|
||||||
|
stack: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -47,6 +47,7 @@ describe("ImageRun", () => {
|
|||||||
},
|
},
|
||||||
} as unknown as File,
|
} as unknown as File,
|
||||||
viewWrapper: {} as unknown as IViewWrapper,
|
viewWrapper: {} as unknown as IViewWrapper,
|
||||||
|
stack: [],
|
||||||
});
|
});
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:r": [
|
"w:r": [
|
||||||
@ -298,6 +299,7 @@ describe("ImageRun", () => {
|
|||||||
},
|
},
|
||||||
} as unknown as File,
|
} as unknown as File,
|
||||||
viewWrapper: {} as unknown as IViewWrapper,
|
viewWrapper: {} as unknown as IViewWrapper,
|
||||||
|
stack: [],
|
||||||
});
|
});
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
"w:r": [
|
"w:r": [
|
||||||
@ -552,6 +554,7 @@ describe("ImageRun", () => {
|
|||||||
},
|
},
|
||||||
} as unknown as File,
|
} as unknown as File,
|
||||||
viewWrapper: {} as unknown as IViewWrapper,
|
viewWrapper: {} as unknown as IViewWrapper,
|
||||||
|
stack: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
@ -810,6 +813,7 @@ describe("ImageRun", () => {
|
|||||||
},
|
},
|
||||||
} as unknown as File,
|
} as unknown as File,
|
||||||
viewWrapper: {} as unknown as IViewWrapper,
|
viewWrapper: {} as unknown as IViewWrapper,
|
||||||
|
stack: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree).to.deep.equal({
|
expect(tree).to.deep.equal({
|
||||||
|
@ -5,6 +5,8 @@ import { IXmlableObject } from "./xmlable-object";
|
|||||||
export interface IContext {
|
export interface IContext {
|
||||||
readonly file: File;
|
readonly file: File;
|
||||||
readonly viewWrapper: IViewWrapper;
|
readonly viewWrapper: IViewWrapper;
|
||||||
|
// eslint-disable-next-line functional/prefer-readonly-type
|
||||||
|
readonly stack: IXmlableObject[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class BaseXmlComponent {
|
export abstract class BaseXmlComponent {
|
||||||
|
@ -34,7 +34,7 @@ export class NextAttributeComponent<T extends AttributeData> extends BaseXmlComp
|
|||||||
|
|
||||||
public prepForXml(_: IContext): IXmlableObject {
|
public prepForXml(_: IContext): IXmlableObject {
|
||||||
const attrs = Object.values<{ readonly key: string; readonly value: string | boolean | number }>(this.root)
|
const attrs = Object.values<{ readonly key: string; readonly value: string | boolean | number }>(this.root)
|
||||||
.filter(({ value }) => !!value)
|
.filter(({ value }) => value !== undefined)
|
||||||
.reduce((acc, { key, value }) => ({ ...acc, [key]: value }), {} as IXmlAttribute);
|
.reduce((acc, { key, value }) => ({ ...acc, [key]: value }), {} as IXmlAttribute);
|
||||||
return { _attr: attrs };
|
return { _attr: attrs };
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ describe("ImportedXmlComponent", () => {
|
|||||||
describe("#prepForXml()", () => {
|
describe("#prepForXml()", () => {
|
||||||
it("should transform for xml", () => {
|
it("should transform for xml", () => {
|
||||||
// tslint:disable-next-line: no-object-literal-type-assertion
|
// tslint:disable-next-line: no-object-literal-type-assertion
|
||||||
const converted = importedXmlComponent.prepForXml({} as IContext);
|
const converted = importedXmlComponent.prepForXml({ stack: [] } as unknown as IContext);
|
||||||
expect(converted).to.deep.equal({
|
expect(converted).to.deep.equal({
|
||||||
"w:test": [
|
"w:test": [
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,15 @@ export abstract class XmlComponent extends BaseXmlComponent {
|
|||||||
this.root = new Array<BaseXmlComponent | string>();
|
this.root = new Array<BaseXmlComponent | string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This method is called by the formatter to get the XML representation of this component.
|
||||||
|
// It is called recursively for all child components.
|
||||||
|
// It is a serializer to be used in the xml library.
|
||||||
|
// https://www.npmjs.com/package/xml
|
||||||
|
// Child components can override this method to customize the XML representation, or execute side effects.
|
||||||
public prepForXml(context: IContext): IXmlableObject | undefined {
|
public prepForXml(context: IContext): IXmlableObject | undefined {
|
||||||
|
// Mutating the stack is required for performance reasons
|
||||||
|
// eslint-disable-next-line functional/immutable-data
|
||||||
|
context.stack.push(this);
|
||||||
const children = this.root
|
const children = this.root
|
||||||
.map((comp) => {
|
.map((comp) => {
|
||||||
if (comp instanceof BaseXmlComponent) {
|
if (comp instanceof BaseXmlComponent) {
|
||||||
@ -21,6 +29,9 @@ export abstract class XmlComponent extends BaseXmlComponent {
|
|||||||
return comp;
|
return comp;
|
||||||
})
|
})
|
||||||
.filter((comp) => comp !== undefined); // Exclude undefined
|
.filter((comp) => comp !== undefined); // Exclude undefined
|
||||||
|
|
||||||
|
// eslint-disable-next-line functional/immutable-data
|
||||||
|
context.stack.pop();
|
||||||
// If we only have a single IXmlableObject in our children array and it
|
// If we only have a single IXmlableObject in our children array and it
|
||||||
// represents our attributes, use the object itself as our children to
|
// represents our attributes, use the object itself as our children to
|
||||||
// avoid an unneeded XML close element.
|
// avoid an unneeded XML close element.
|
||||||
|
8
tsconfig.mjs.json
Normal file
8
tsconfig.mjs.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "esnext",
|
||||||
|
"outDir": "dist/mjs",
|
||||||
|
"target": "esnext"
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user