@office-open/docx 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -30
- package/dist/context-Ca7nmKV2.mjs +5067 -0
- package/dist/context-Ca7nmKV2.mjs.map +1 -0
- package/dist/core-properties-B3ztqzLD.d.mts +3476 -0
- package/dist/core-properties-B3ztqzLD.d.mts.map +1 -0
- package/dist/document-CWr8C_OX.mjs +4404 -0
- package/dist/document-CWr8C_OX.mjs.map +1 -0
- package/dist/generate-m1Cw7CHL.mjs +490 -0
- package/dist/generate-m1Cw7CHL.mjs.map +1 -0
- package/dist/generate.d.mts +10 -0
- package/dist/generate.d.mts.map +1 -0
- package/dist/generate.mjs +2 -0
- package/dist/index.d.mts +172 -4913
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +233 -26018
- package/dist/index.mjs.map +1 -1
- package/dist/parse-D9ujyKBr.mjs +545 -0
- package/dist/parse-D9ujyKBr.mjs.map +1 -0
- package/dist/parse.d.mts +2 -0
- package/dist/parse.mjs +2 -0
- package/dist/patch/index.d.mts +50 -0
- package/dist/patch/index.d.mts.map +1 -0
- package/dist/patch/index.mjs +272 -0
- package/dist/patch/index.mjs.map +1 -0
- package/package.json +17 -4
- package/dist/chunk-BBjsoOtd.mjs +0 -27
|
@@ -0,0 +1,4404 @@
|
|
|
1
|
+
import { TargetModeType, convertEmuToPixels, convertPixelsToEmu, convertToEmu, convertToTwip, convertUniversalMeasureToEmu, decimalNumber, eighthPointMeasureValue, hexColorValue, hpsMeasureValue, measurementOrPercentValue, pointMeasureValue, signedTwipsMeasureValue, toUint8Array, twipsMeasureValue, uCharHexNumber, uniqueId, uniqueNumericIdCreator, xsdVerticalMergeRev } from "@office-open/core";
|
|
2
|
+
import { attr, attrBool, attrNum, children, element, escapeXml, findChild, findDeep, textOf } from "@office-open/xml";
|
|
3
|
+
import { calculateEffectExtent, createEffectDag, createScene3D, createShape3D, customGeometryDesc, effectListDesc, extractBlipFillMedia, fillDesc, outlineDesc, scene3DDesc, shape3DDesc, transform2DDesc } from "@office-open/core/drawingml";
|
|
4
|
+
import { chartSpaceDesc } from "@office-open/core/chart";
|
|
5
|
+
import { createDataModel } from "@office-open/core/smartart";
|
|
6
|
+
//#region src/shared/media/media.ts
|
|
7
|
+
/**
|
|
8
|
+
* Converts user-facing transformation options (pixels or universal measure) to internal
|
|
9
|
+
* transformation data (pixels + EMUs).
|
|
10
|
+
*
|
|
11
|
+
* @param options - User-facing transformation in pixels or universal measure
|
|
12
|
+
* @returns Internal transformation data with both pixel and EMU values
|
|
13
|
+
*/
|
|
14
|
+
const createTransformation = (options) => ({
|
|
15
|
+
emus: {
|
|
16
|
+
x: typeof options.width === "string" ? convertUniversalMeasureToEmu(options.width) : convertPixelsToEmu(options.width),
|
|
17
|
+
y: typeof options.height === "string" ? convertUniversalMeasureToEmu(options.height) : convertPixelsToEmu(options.height)
|
|
18
|
+
},
|
|
19
|
+
flip: options.flip,
|
|
20
|
+
offset: {
|
|
21
|
+
emus: {
|
|
22
|
+
x: typeof options.offset?.left === "string" ? convertUniversalMeasureToEmu(options.offset.left) : convertPixelsToEmu(options.offset?.left ?? 0),
|
|
23
|
+
y: typeof options.offset?.top === "string" ? convertUniversalMeasureToEmu(options.offset.top) : convertPixelsToEmu(options.offset?.top ?? 0)
|
|
24
|
+
},
|
|
25
|
+
pixels: {
|
|
26
|
+
x: typeof options.offset?.left === "number" ? Math.round(options.offset.left) : 0,
|
|
27
|
+
y: typeof options.offset?.top === "number" ? Math.round(options.offset.top) : 0
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
pixels: {
|
|
31
|
+
x: typeof options.width === "number" ? Math.round(options.width) : 0,
|
|
32
|
+
y: typeof options.height === "number" ? Math.round(options.height) : 0
|
|
33
|
+
},
|
|
34
|
+
rotation: options.rotation ? options.rotation * 6e4 : void 0
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Manages embedded media (images) in a document.
|
|
38
|
+
*
|
|
39
|
+
* Media stores all images referenced in the document and provides
|
|
40
|
+
* access to their data for packaging into the DOCX file. Each image
|
|
41
|
+
* is stored with a unique key for retrieval.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const media = new Media();
|
|
46
|
+
* media.addImage("image1", {
|
|
47
|
+
* type: "png",
|
|
48
|
+
* fileName: "image1.png",
|
|
49
|
+
* transformation: {
|
|
50
|
+
* pixels: { x: 200, y: 100 },
|
|
51
|
+
* emus: { x: 1828800, y: 914400 }
|
|
52
|
+
* },
|
|
53
|
+
* data: imageBuffer
|
|
54
|
+
* });
|
|
55
|
+
* const allImages = media.Array;
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
var Media = class {
|
|
59
|
+
map;
|
|
60
|
+
constructor() {
|
|
61
|
+
this.map = /* @__PURE__ */ new Map();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Adds an image to the media collection.
|
|
65
|
+
*
|
|
66
|
+
* @param key - Unique identifier for this image
|
|
67
|
+
* @param mediaData - Complete image data including file name, transformation, and raw data
|
|
68
|
+
*/
|
|
69
|
+
addImage(key, mediaData) {
|
|
70
|
+
this.map.set(key, mediaData);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Gets all images as an array.
|
|
74
|
+
*
|
|
75
|
+
* @returns Read-only array of all media data in the collection
|
|
76
|
+
*/
|
|
77
|
+
get array() {
|
|
78
|
+
return [...this.map.values()];
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/shared/media/data.ts
|
|
83
|
+
/**
|
|
84
|
+
* @ignore
|
|
85
|
+
*/
|
|
86
|
+
const WORKAROUND2 = "";
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/parts/drawing/inline/graphic/graphic-data/wps/body-properties.ts
|
|
89
|
+
/**
|
|
90
|
+
* Text anchoring type (ST_TextAnchoringType).
|
|
91
|
+
*
|
|
92
|
+
* ## XSD Schema
|
|
93
|
+
* ```xml
|
|
94
|
+
* <xsd:simpleType name="ST_TextAnchoringType">
|
|
95
|
+
* <xsd:restriction base="xsd:token">
|
|
96
|
+
* <xsd:enumeration value="t"/>
|
|
97
|
+
* <xsd:enumeration value="ctr"/>
|
|
98
|
+
* <xsd:enumeration value="b"/>
|
|
99
|
+
* <xsd:enumeration value="just"/>
|
|
100
|
+
* <xsd:enumeration value="dist"/>
|
|
101
|
+
* </xsd:restriction>
|
|
102
|
+
* </xsd:simpleType>
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @publicApi
|
|
106
|
+
*/
|
|
107
|
+
let VerticalAnchor = /* @__PURE__ */ function(VerticalAnchor) {
|
|
108
|
+
VerticalAnchor["TOP"] = "t";
|
|
109
|
+
VerticalAnchor["CENTER"] = "ctr";
|
|
110
|
+
VerticalAnchor["BOTTOM"] = "b";
|
|
111
|
+
VerticalAnchor["JUSTIFY"] = "just";
|
|
112
|
+
VerticalAnchor["DISTRIBUTED"] = "dist";
|
|
113
|
+
return VerticalAnchor;
|
|
114
|
+
}({});
|
|
115
|
+
/**
|
|
116
|
+
* Text vertical overflow type (ST_TextVertOverflowType).
|
|
117
|
+
*/
|
|
118
|
+
const TextVertOverflowType = {
|
|
119
|
+
OVERFLOW: "overflow",
|
|
120
|
+
ELLIPSIS: "ellipsis",
|
|
121
|
+
CLIP: "clip"
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Text horizontal overflow type (ST_TextHorzOverflowType).
|
|
125
|
+
*/
|
|
126
|
+
const TextHorzOverflowType = {
|
|
127
|
+
OVERFLOW: "overflow",
|
|
128
|
+
CLIP: "clip"
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Text vertical type (ST_TextVerticalType).
|
|
132
|
+
*
|
|
133
|
+
* ## XSD Schema
|
|
134
|
+
* ```xml
|
|
135
|
+
* <xsd:simpleType name="ST_TextVerticalType">
|
|
136
|
+
* <xsd:restriction base="xsd:token">
|
|
137
|
+
* <xsd:enumeration value="horz"/>
|
|
138
|
+
* <xsd:enumeration value="vert"/>
|
|
139
|
+
* <xsd:enumeration value="vert270"/>
|
|
140
|
+
* <xsd:enumeration value="wordArtVert"/>
|
|
141
|
+
* <xsd:enumeration value="eaVert"/>
|
|
142
|
+
* <xsd:enumeration value="mongolianVert"/>
|
|
143
|
+
* <xsd:enumeration value="wordArtVertRtl"/>
|
|
144
|
+
* </xsd:restriction>
|
|
145
|
+
* </xsd:simpleType>
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
const TextVerticalType = {
|
|
149
|
+
HORIZONTAL: "horz",
|
|
150
|
+
VERTICAL: "vert",
|
|
151
|
+
VERTICAL_270: "vert270",
|
|
152
|
+
WORD_ART_VERTICAL: "wordArtVert",
|
|
153
|
+
EAST_ASIAN_VERTICAL: "eaVert",
|
|
154
|
+
MONGOLIAN_VERTICAL: "mongolianVert",
|
|
155
|
+
WORD_ART_VERTICAL_RTL: "wordArtVertRtl"
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Text body wrapping type (ST_TextWrappingType).
|
|
159
|
+
*
|
|
160
|
+
* This is different from text wrapping around shapes (ST_WrapText).
|
|
161
|
+
*/
|
|
162
|
+
const TextBodyWrappingType = {
|
|
163
|
+
NONE: "none",
|
|
164
|
+
SQUARE: "square"
|
|
165
|
+
};
|
|
166
|
+
const filterAttrs = (options) => {
|
|
167
|
+
const attrs = {};
|
|
168
|
+
for (const [key, value] of Object.entries(options)) if (value !== void 0) attrs[key] = value;
|
|
169
|
+
return Object.keys(attrs).length > 0 ? attrs : void 0;
|
|
170
|
+
};
|
|
171
|
+
const createPresetTextShape = (options) => {
|
|
172
|
+
const adjChildren = [];
|
|
173
|
+
if (options.adjustments) for (const adj of options.adjustments) adjChildren.push(`<a:gd name="${adj.name}" fmla="${adj.formula}"/>`);
|
|
174
|
+
return element("a:prstTxWarp", { prst: options.preset }, adjChildren.length > 0 ? [element("a:avLst", void 0, adjChildren)] : void 0);
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Creates a text body properties element (wps:bodyPr).
|
|
178
|
+
*
|
|
179
|
+
* Supports all 19 CT_TextBodyProperties attributes and all child elements
|
|
180
|
+
* including preset text warp, autofit variants, 3D scene, and text 3D.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* // Simple margins and anchor
|
|
185
|
+
* createBodyProperties({
|
|
186
|
+
* margins: { top: 100, bottom: 100, left: 200, right: 200 },
|
|
187
|
+
* verticalAnchor: VerticalAnchor.CENTER,
|
|
188
|
+
* });
|
|
189
|
+
*
|
|
190
|
+
* // Full options with vertical text and autofit
|
|
191
|
+
* createBodyProperties({
|
|
192
|
+
* vert: TextVerticalType.VERTICAL,
|
|
193
|
+
* wrap: TextBodyWrappingType.NONE,
|
|
194
|
+
* normAutofit: { fontScale: 80000 },
|
|
195
|
+
* numCol: 2,
|
|
196
|
+
* anchor: VerticalAnchor.TOP,
|
|
197
|
+
* });
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
const createBodyProperties = (options = {}) => {
|
|
201
|
+
const anchor = options.anchor ?? options.verticalAnchor;
|
|
202
|
+
const lIns = options.lIns ?? options.margins?.left;
|
|
203
|
+
const tIns = options.tIns ?? options.margins?.top;
|
|
204
|
+
const rIns = options.rIns ?? options.margins?.right;
|
|
205
|
+
const bIns = options.bIns ?? options.margins?.bottom;
|
|
206
|
+
const attrs = filterAttrs({
|
|
207
|
+
rot: options.rotation,
|
|
208
|
+
spcFirstLastPara: options.spcFirstLastPara,
|
|
209
|
+
vertOverflow: options.vertOverflow,
|
|
210
|
+
horzOverflow: options.horzOverflow,
|
|
211
|
+
vert: options.vert,
|
|
212
|
+
wrap: options.wrap,
|
|
213
|
+
lIns: lIns !== void 0 ? convertToEmu(lIns) : void 0,
|
|
214
|
+
tIns: tIns !== void 0 ? convertToEmu(tIns) : void 0,
|
|
215
|
+
rIns: rIns !== void 0 ? convertToEmu(rIns) : void 0,
|
|
216
|
+
bIns: bIns !== void 0 ? convertToEmu(bIns) : void 0,
|
|
217
|
+
numCol: options.numCol,
|
|
218
|
+
spcCol: options.spcCol !== void 0 ? convertToEmu(options.spcCol) : void 0,
|
|
219
|
+
rtlCol: options.rtlCol,
|
|
220
|
+
fromWordArt: options.fromWordArt,
|
|
221
|
+
anchor,
|
|
222
|
+
anchorCtr: options.anchorCtr,
|
|
223
|
+
forceAA: options.forceAA,
|
|
224
|
+
upright: options.upright,
|
|
225
|
+
compatLnSpc: options.compatLnSpc
|
|
226
|
+
});
|
|
227
|
+
const children = [];
|
|
228
|
+
if (options.prstTxWarp) children.push(createPresetTextShape(options.prstTxWarp));
|
|
229
|
+
if (options.noAutoFit) children.push(`<a:noAutofit/>`);
|
|
230
|
+
else if (options.normAutofit) {
|
|
231
|
+
const normAttrs = filterAttrs({
|
|
232
|
+
fontScale: options.normAutofit.fontScale,
|
|
233
|
+
lnSpcReduction: options.normAutofit.lnSpcReduction
|
|
234
|
+
});
|
|
235
|
+
children.push(element("a:normAutofit", normAttrs));
|
|
236
|
+
} else if (options.spAutoFit) children.push(`<a:spAutoFit/>`);
|
|
237
|
+
if (options.scene3d) children.push(createScene3D(options.scene3d));
|
|
238
|
+
if (options.sp3d) children.push(createShape3D(options.sp3d));
|
|
239
|
+
else if (options.flatTx) {
|
|
240
|
+
const flatAttrs = filterAttrs({ z: options.flatTx.z });
|
|
241
|
+
children.push(element("a:flatTx", flatAttrs));
|
|
242
|
+
}
|
|
243
|
+
return element("wps:bodyPr", attrs, children.length > 0 ? children : void 0);
|
|
244
|
+
};
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region src/parts/table/table-cell/table-cell-components.ts
|
|
247
|
+
/**
|
|
248
|
+
* Vertical merge types for table cells.
|
|
249
|
+
*
|
|
250
|
+
* Defines the merge behavior for vertically merged cells (row span).
|
|
251
|
+
*/
|
|
252
|
+
const VerticalMergeType = {
|
|
253
|
+
/**
|
|
254
|
+
* Cell that is merged with upper one.
|
|
255
|
+
*/
|
|
256
|
+
CONTINUE: "continue",
|
|
257
|
+
/**
|
|
258
|
+
* Cell that is starting the vertical merge.
|
|
259
|
+
*/
|
|
260
|
+
RESTART: "restart"
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* Text direction values for table cells.
|
|
264
|
+
*
|
|
265
|
+
* Specifies the direction in which text flows within a table cell.
|
|
266
|
+
*/
|
|
267
|
+
const TextDirection = {
|
|
268
|
+
/** Text flows from bottom to top, left to right */
|
|
269
|
+
BOTTOM_TO_TOP_LEFT_TO_RIGHT: "btLr",
|
|
270
|
+
/** Text flows from left to right, top to bottom (default) */
|
|
271
|
+
LEFT_TO_RIGHT_TOP_TO_BOTTOM: "lrTb",
|
|
272
|
+
/** Text flows from top to bottom, right to left */
|
|
273
|
+
TOP_TO_BOTTOM_RIGHT_TO_LEFT: "tbRl"
|
|
274
|
+
};
|
|
275
|
+
//#endregion
|
|
276
|
+
//#region src/shared/border.ts
|
|
277
|
+
/**
|
|
278
|
+
* Table borders are defined with the <w:tblBorders> element. Child elements of this element specify the kinds of `border`:
|
|
279
|
+
*
|
|
280
|
+
* `bottom`, `end` (`right` in the previous version of the standard), `insideH`, `insideV`, `start` (`left` in the previous version of the standard), and `top`.
|
|
281
|
+
*
|
|
282
|
+
* Reference: http://officeopenxml.com/WPtableBorders.php
|
|
283
|
+
*
|
|
284
|
+
* ## XSD Schema
|
|
285
|
+
* ```xml
|
|
286
|
+
* <xsd:simpleType name="ST_Border">
|
|
287
|
+
* <xsd:restriction base="xsd:string">
|
|
288
|
+
* <xsd:enumeration value="single"/>
|
|
289
|
+
* <xsd:enumeration value="dashDotStroked"/>
|
|
290
|
+
* <xsd:enumeration value="dashed"/>
|
|
291
|
+
* <xsd:enumeration value="dashSmallGap"/>
|
|
292
|
+
* <xsd:enumeration value="dotDash"/>
|
|
293
|
+
* <xsd:enumeration value="dotDotDash"/>
|
|
294
|
+
* <xsd:enumeration value="dotted"/>
|
|
295
|
+
* <xsd:enumeration value="double"/>
|
|
296
|
+
* <xsd:enumeration value="doubleWave"/>
|
|
297
|
+
* <xsd:enumeration value="inset"/>
|
|
298
|
+
* <xsd:enumeration value="nil"/>
|
|
299
|
+
* <xsd:enumeration value="none"/>
|
|
300
|
+
* <xsd:enumeration value="outset"/>
|
|
301
|
+
* <xsd:enumeration value="thick"/>
|
|
302
|
+
* <xsd:enumeration value="thickThinLargeGap"/>
|
|
303
|
+
* <xsd:enumeration value="thickThinMediumGap"/>
|
|
304
|
+
* <xsd:enumeration value="thickThinSmallGap"/>
|
|
305
|
+
* <xsd:enumeration value="thinThickLargeGap"/>
|
|
306
|
+
* <xsd:enumeration value="thinThickMediumGap"/>
|
|
307
|
+
* <xsd:enumeration value="thinThickSmallGap"/>
|
|
308
|
+
* <xsd:enumeration value="thinThickThinLargeGap"/>
|
|
309
|
+
* <xsd:enumeration value="thinThickThinMediumGap"/>
|
|
310
|
+
* <xsd:enumeration value="thinThickThinSmallGap"/>
|
|
311
|
+
* <xsd:enumeration value="threeDEmboss"/>
|
|
312
|
+
* <xsd:enumeration value="threeDEngrave"/>
|
|
313
|
+
* <xsd:enumeration value="triple"/>
|
|
314
|
+
* <xsd:enumeration value="wave"/>
|
|
315
|
+
* </xsd:restriction>
|
|
316
|
+
* </xsd:simpleType>
|
|
317
|
+
* ```
|
|
318
|
+
*
|
|
319
|
+
* @publicApi
|
|
320
|
+
*/
|
|
321
|
+
const BorderStyle = {
|
|
322
|
+
/** A single line */
|
|
323
|
+
SINGLE: "single",
|
|
324
|
+
/** A line with a series of alternating thin and thick strokes */
|
|
325
|
+
DASH_DOT_STROKED: "dashDotStroked",
|
|
326
|
+
/** A dashed line */
|
|
327
|
+
DASHED: "dashed",
|
|
328
|
+
/** A dashed line with small gaps */
|
|
329
|
+
DASH_SMALL_GAP: "dashSmallGap",
|
|
330
|
+
/** A line with alternating dots and dashes */
|
|
331
|
+
DOT_DASH: "dotDash",
|
|
332
|
+
/** A line with a repeating dot - dot - dash sequence */
|
|
333
|
+
DOT_DOT_DASH: "dotDotDash",
|
|
334
|
+
/** A dotted line */
|
|
335
|
+
DOTTED: "dotted",
|
|
336
|
+
/** A double line */
|
|
337
|
+
DOUBLE: "double",
|
|
338
|
+
/** A double wavy line */
|
|
339
|
+
DOUBLE_WAVE: "doubleWave",
|
|
340
|
+
/** An inset set of lines */
|
|
341
|
+
INSET: "inset",
|
|
342
|
+
/** No border */
|
|
343
|
+
NIL: "nil",
|
|
344
|
+
/** No border */
|
|
345
|
+
NONE: "none",
|
|
346
|
+
/** An outset set of lines */
|
|
347
|
+
OUTSET: "outset",
|
|
348
|
+
/** A single line */
|
|
349
|
+
THICK: "thick",
|
|
350
|
+
/** A thick line contained within a thin line with a large-sized intermediate gap */
|
|
351
|
+
THICK_THIN_LARGE_GAP: "thickThinLargeGap",
|
|
352
|
+
/** A thick line contained within a thin line with a medium-sized intermediate gap */
|
|
353
|
+
THICK_THIN_MEDIUM_GAP: "thickThinMediumGap",
|
|
354
|
+
/** A thick line contained within a thin line with a small intermediate gap */
|
|
355
|
+
THICK_THIN_SMALL_GAP: "thickThinSmallGap",
|
|
356
|
+
/** A thin line contained within a thick line with a large-sized intermediate gap */
|
|
357
|
+
THIN_THICK_LARGE_GAP: "thinThickLargeGap",
|
|
358
|
+
/** A thick line contained within a thin line with a medium-sized intermediate gap */
|
|
359
|
+
THIN_THICK_MEDIUM_GAP: "thinThickMediumGap",
|
|
360
|
+
/** A thick line contained within a thin line with a small intermediate gap */
|
|
361
|
+
THIN_THICK_SMALL_GAP: "thinThickSmallGap",
|
|
362
|
+
/** A thin-thick-thin line with a large gap */
|
|
363
|
+
THIN_THICK_THIN_LARGE_GAP: "thinThickThinLargeGap",
|
|
364
|
+
/** A thin-thick-thin line with a medium gap */
|
|
365
|
+
THIN_THICK_THIN_MEDIUM_GAP: "thinThickThinMediumGap",
|
|
366
|
+
/** A thin-thick-thin line with a small gap */
|
|
367
|
+
THIN_THICK_THIN_SMALL_GAP: "thinThickThinSmallGap",
|
|
368
|
+
/** A three-staged gradient line, getting darker towards the paragraph */
|
|
369
|
+
THREE_D_EMBOSS: "threeDEmboss",
|
|
370
|
+
/** A three-staged gradient like, getting darker away from the paragraph */
|
|
371
|
+
THREE_D_ENGRAVE: "threeDEngrave",
|
|
372
|
+
/** A triple line */
|
|
373
|
+
TRIPLE: "triple",
|
|
374
|
+
/** A wavy line */
|
|
375
|
+
WAVE: "wave"
|
|
376
|
+
};
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/parts/table/table-width.ts
|
|
379
|
+
/**
|
|
380
|
+
* Width type values for tables and cells.
|
|
381
|
+
*
|
|
382
|
+
* ## XSD Schema
|
|
383
|
+
* ```xml
|
|
384
|
+
* <xsd:simpleType name="ST_TblWidth">
|
|
385
|
+
* <xsd:restriction base="xsd:string">
|
|
386
|
+
* <xsd:enumeration value="nil"/>
|
|
387
|
+
* <xsd:enumeration value="pct"/>
|
|
388
|
+
* <xsd:enumeration value="dxa"/>
|
|
389
|
+
* <xsd:enumeration value="auto"/>
|
|
390
|
+
* </xsd:restriction>
|
|
391
|
+
* </xsd:simpleType>
|
|
392
|
+
* ```
|
|
393
|
+
*
|
|
394
|
+
* @publicApi
|
|
395
|
+
*/
|
|
396
|
+
const WidthType = {
|
|
397
|
+
/** Auto. */
|
|
398
|
+
AUTO: "auto",
|
|
399
|
+
/** Value is in twentieths of a point */
|
|
400
|
+
DXA: "dxa",
|
|
401
|
+
/** No (empty) value. */
|
|
402
|
+
NIL: "nil",
|
|
403
|
+
/** Value is in percentage. */
|
|
404
|
+
PERCENTAGE: "pct"
|
|
405
|
+
};
|
|
406
|
+
//#endregion
|
|
407
|
+
//#region src/parts/drawing/text-wrap/text-wrapping.ts
|
|
408
|
+
/**
|
|
409
|
+
* Enumeration of text wrapping types for floating drawings.
|
|
410
|
+
*
|
|
411
|
+
* Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
|
|
412
|
+
*
|
|
413
|
+
* @publicApi
|
|
414
|
+
*/
|
|
415
|
+
const TextWrappingType = {
|
|
416
|
+
NONE: 0,
|
|
417
|
+
SQUARE: 1,
|
|
418
|
+
TIGHT: 2,
|
|
419
|
+
TOP_AND_BOTTOM: 3,
|
|
420
|
+
THROUGH: 4
|
|
421
|
+
};
|
|
422
|
+
/**
|
|
423
|
+
* Enumeration of text wrapping sides for floating drawings.
|
|
424
|
+
*
|
|
425
|
+
* Specifies on which side(s) text can wrap around the drawing.
|
|
426
|
+
*
|
|
427
|
+
* Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
|
|
428
|
+
*
|
|
429
|
+
* @publicApi
|
|
430
|
+
*/
|
|
431
|
+
const TextWrappingSide = {
|
|
432
|
+
/** Text wraps on both sides of the drawing */
|
|
433
|
+
BOTH_SIDES: "bothSides",
|
|
434
|
+
/** Text wraps only on the left side */
|
|
435
|
+
LEFT: "left",
|
|
436
|
+
/** Text wraps only on the right side */
|
|
437
|
+
RIGHT: "right",
|
|
438
|
+
/** Text wraps on the side with more space */
|
|
439
|
+
LARGEST: "largest"
|
|
440
|
+
};
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/parts/drawing/text-wrap/wrap-tight.ts
|
|
443
|
+
/**
|
|
444
|
+
* Wrap Tight module for DrawingML text wrapping.
|
|
445
|
+
*
|
|
446
|
+
* This module provides tight text wrapping for floating drawings
|
|
447
|
+
* where text wraps closely around the image shape.
|
|
448
|
+
*
|
|
449
|
+
* Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
|
|
450
|
+
*
|
|
451
|
+
* @module
|
|
452
|
+
*/
|
|
453
|
+
/**
|
|
454
|
+
* Creates a default rectangular wrap polygon matching the image extent.
|
|
455
|
+
*
|
|
456
|
+
* Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
|
|
457
|
+
*
|
|
458
|
+
* ## XSD Schema
|
|
459
|
+
* ```xml
|
|
460
|
+
* <xsd:complexType name="CT_WrapPath">
|
|
461
|
+
* <xsd:sequence>
|
|
462
|
+
* <xsd:element name="start" type="a:CT_Point2D" minOccurs="1" maxOccurs="1"/>
|
|
463
|
+
* <xsd:element name="lineTo" type="a:CT_Point2D" minOccurs="2" maxOccurs="unbounded"/>
|
|
464
|
+
* </xsd:sequence>
|
|
465
|
+
* <xsd:attribute name="edited" type="xsd:boolean" use="optional"/>
|
|
466
|
+
* </xsd:complexType>
|
|
467
|
+
* ```
|
|
468
|
+
*/
|
|
469
|
+
const createWrapPolygon$1 = (cx, cy) => element("wp:wrapPolygon", { edited: "0" }, [
|
|
470
|
+
`<wp:start x="0" y="0"/>`,
|
|
471
|
+
`<wp:lineTo x="0" y="${-cy}"/>`,
|
|
472
|
+
`<wp:lineTo x="${cx}" y="${-cy}"/>`,
|
|
473
|
+
`<wp:lineTo x="${cx}" y="0"/>`,
|
|
474
|
+
`<wp:lineTo x="0" y="0"/>`
|
|
475
|
+
]);
|
|
476
|
+
/**
|
|
477
|
+
* Creates tight text wrapping for a floating drawing.
|
|
478
|
+
*
|
|
479
|
+
* WrapTight causes text to wrap closely around the contours
|
|
480
|
+
* of the drawing rather than its rectangular bounding box.
|
|
481
|
+
* A default rectangular wrap polygon matching the image extent is generated.
|
|
482
|
+
*
|
|
483
|
+
* Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
|
|
484
|
+
*
|
|
485
|
+
* ## XSD Schema
|
|
486
|
+
* ```xml
|
|
487
|
+
* <xsd:complexType name="CT_WrapTight">
|
|
488
|
+
* <xsd:sequence>
|
|
489
|
+
* <xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
|
|
490
|
+
* </xsd:sequence>
|
|
491
|
+
* <xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
|
|
492
|
+
* <xsd:attribute name="distL" type="ST_WrapDistance"/>
|
|
493
|
+
* <xsd:attribute name="distR" type="ST_WrapDistance"/>
|
|
494
|
+
* </xsd:complexType>
|
|
495
|
+
* ```
|
|
496
|
+
*/
|
|
497
|
+
const createWrapTight = (textWrapping, margins = {
|
|
498
|
+
bottom: 0,
|
|
499
|
+
left: 0,
|
|
500
|
+
right: 0,
|
|
501
|
+
top: 0
|
|
502
|
+
}, extent) => element("wp:wrapTight", {
|
|
503
|
+
distL: margins.left,
|
|
504
|
+
distR: margins.right,
|
|
505
|
+
wrapText: textWrapping.side || TextWrappingSide.BOTH_SIDES
|
|
506
|
+
}, [createWrapPolygon$1(extent.x, extent.y)]);
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region src/parts/drawing/text-wrap/wrap-through.ts
|
|
509
|
+
/**
|
|
510
|
+
* Wrap Through module for DrawingML text wrapping.
|
|
511
|
+
*
|
|
512
|
+
* This module provides "through" text wrapping for floating drawings
|
|
513
|
+
* where text wraps through the image contours, filling any concave areas.
|
|
514
|
+
*
|
|
515
|
+
* Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
|
|
516
|
+
*
|
|
517
|
+
* @module
|
|
518
|
+
*/
|
|
519
|
+
/**
|
|
520
|
+
* Creates a default rectangular wrap polygon matching the image extent.
|
|
521
|
+
*
|
|
522
|
+
* Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
|
|
523
|
+
*
|
|
524
|
+
* ## XSD Schema
|
|
525
|
+
* ```xml
|
|
526
|
+
* <xsd:complexType name="CT_WrapPath">
|
|
527
|
+
* <xsd:sequence>
|
|
528
|
+
* <xsd:element name="start" type="a:CT_Point2D" minOccurs="1" maxOccurs="1"/>
|
|
529
|
+
* <xsd:element name="lineTo" type="a:CT_Point2D" minOccurs="2" maxOccurs="unbounded"/>
|
|
530
|
+
* </xsd:sequence>
|
|
531
|
+
* <xsd:attribute name="edited" type="xsd:boolean" use="optional"/>
|
|
532
|
+
* </xsd:complexType>
|
|
533
|
+
* ```
|
|
534
|
+
*/
|
|
535
|
+
const createWrapPolygon = (cx, cy) => element("wp:wrapPolygon", { edited: "0" }, [
|
|
536
|
+
`<wp:start x="0" y="0"/>`,
|
|
537
|
+
`<wp:lineTo x="0" y="${-cy}"/>`,
|
|
538
|
+
`<wp:lineTo x="${cx}" y="${-cy}"/>`,
|
|
539
|
+
`<wp:lineTo x="${cx}" y="0"/>`,
|
|
540
|
+
`<wp:lineTo x="0" y="0"/>`
|
|
541
|
+
]);
|
|
542
|
+
/**
|
|
543
|
+
* Creates "through" text wrapping for a floating drawing.
|
|
544
|
+
*
|
|
545
|
+
* WrapThrough is similar to WrapTight but allows text to wrap through
|
|
546
|
+
* the concave portions of the drawing shape (e.g., the inside of the letter "O").
|
|
547
|
+
* A default rectangular wrap polygon matching the image extent is generated.
|
|
548
|
+
*
|
|
549
|
+
* Reference: http://officeopenxml.com/drwPicFloating-textWrap.php
|
|
550
|
+
*
|
|
551
|
+
* ## XSD Schema
|
|
552
|
+
* ```xml
|
|
553
|
+
* <xsd:complexType name="CT_WrapThrough">
|
|
554
|
+
* <xsd:sequence>
|
|
555
|
+
* <xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
|
|
556
|
+
* </xsd:sequence>
|
|
557
|
+
* <xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
|
|
558
|
+
* <xsd:attribute name="distL" type="ST_WrapDistance"/>
|
|
559
|
+
* <xsd:attribute name="distR" type="ST_WrapDistance"/>
|
|
560
|
+
* </xsd:complexType>
|
|
561
|
+
* ```
|
|
562
|
+
*/
|
|
563
|
+
const createWrapThrough = (textWrapping, margins = {
|
|
564
|
+
bottom: 0,
|
|
565
|
+
left: 0,
|
|
566
|
+
right: 0,
|
|
567
|
+
top: 0
|
|
568
|
+
}, extent) => element("wp:wrapThrough", {
|
|
569
|
+
distL: margins.left,
|
|
570
|
+
distR: margins.right,
|
|
571
|
+
wrapText: textWrapping.side || TextWrappingSide.BOTH_SIDES
|
|
572
|
+
}, [createWrapPolygon(extent.x, extent.y)]);
|
|
573
|
+
//#endregion
|
|
574
|
+
//#region src/shared/constants.ts
|
|
575
|
+
/**
|
|
576
|
+
* Shared constants for WordprocessingML documents.
|
|
577
|
+
*
|
|
578
|
+
* Provides alignment, number format, and space type constants
|
|
579
|
+
* used across multiple document components.
|
|
580
|
+
*
|
|
581
|
+
* @module
|
|
582
|
+
*/
|
|
583
|
+
/**
|
|
584
|
+
* Horizontal alignment options for floating drawings.
|
|
585
|
+
*
|
|
586
|
+
* Reference: https://www.datypic.com/sc/ooxml/t-wp_ST_AlignH.html
|
|
587
|
+
*
|
|
588
|
+
* @publicApi
|
|
589
|
+
*/
|
|
590
|
+
const HorizontalPositionAlign = {
|
|
591
|
+
CENTER: "center",
|
|
592
|
+
INSIDE: "inside",
|
|
593
|
+
LEFT: "left",
|
|
594
|
+
OUTSIDE: "outside",
|
|
595
|
+
RIGHT: "right"
|
|
596
|
+
};
|
|
597
|
+
/**
|
|
598
|
+
* Vertical alignment options for floating drawings.
|
|
599
|
+
*
|
|
600
|
+
* Reference: https://www.datypic.com/sc/ooxml/t-wp_ST_AlignV.html
|
|
601
|
+
*
|
|
602
|
+
* @publicApi
|
|
603
|
+
*/
|
|
604
|
+
const VerticalPositionAlign = {
|
|
605
|
+
BOTTOM: "bottom",
|
|
606
|
+
CENTER: "center",
|
|
607
|
+
INSIDE: "inside",
|
|
608
|
+
OUTSIDE: "outside",
|
|
609
|
+
TOP: "top"
|
|
610
|
+
};
|
|
611
|
+
/**
|
|
612
|
+
* Number format types for page numbers and list numbering.
|
|
613
|
+
*
|
|
614
|
+
* Reference: http://officeopenxml.com/WPnumbering-numFmt.php
|
|
615
|
+
*
|
|
616
|
+
* @publicApi
|
|
617
|
+
*/
|
|
618
|
+
const NumberFormat = {
|
|
619
|
+
AIUEO: "aiueo",
|
|
620
|
+
AIUEO_FULL_WIDTH: "aiueoFullWidth",
|
|
621
|
+
ARABIC_ABJAD: "arabicAbjad",
|
|
622
|
+
ARABIC_ALPHA: "arabicAlpha",
|
|
623
|
+
BAHT_TEXT: "bahtText",
|
|
624
|
+
BULLET: "bullet",
|
|
625
|
+
CARDINAL_TEXT: "cardinalText",
|
|
626
|
+
CHICAGO: "chicago",
|
|
627
|
+
CHINESE_COUNTING: "chineseCounting",
|
|
628
|
+
CHINESE_COUNTING_TEN_THOUSAND: "chineseCountingThousand",
|
|
629
|
+
CHINESE_LEGAL_SIMPLIFIED: "chineseLegalSimplified",
|
|
630
|
+
CHOSUNG: "chosung",
|
|
631
|
+
DECIMAL: "decimal",
|
|
632
|
+
DECIMAL_ENCLOSED_CIRCLE: "decimalEnclosedCircle",
|
|
633
|
+
DECIMAL_ENCLOSED_CIRCLE_CHINESE: "decimalEnclosedCircleChinese",
|
|
634
|
+
DECIMAL_ENCLOSED_FULL_STOP: "decimalEnclosedFullstop",
|
|
635
|
+
DECIMAL_ENCLOSED_PAREN: "decimalEnclosedParen",
|
|
636
|
+
DECIMAL_FULL_WIDTH: "decimalFullWidth",
|
|
637
|
+
DECIMAL_FULL_WIDTH_2: "decimalFullWidth2",
|
|
638
|
+
DECIMAL_HALF_WIDTH: "decimalHalfWidth",
|
|
639
|
+
DECIMAL_ZERO: "decimalZero",
|
|
640
|
+
DOLLAR_TEXT: "dollarText",
|
|
641
|
+
GANADA: "ganada",
|
|
642
|
+
HEBREW_1: "hebrew1",
|
|
643
|
+
HEBREW_2: "hebrew2",
|
|
644
|
+
HEX: "hex",
|
|
645
|
+
HINDI_CONSONANTS: "hindiConsonants",
|
|
646
|
+
HINDI_COUNTING: "hindiCounting",
|
|
647
|
+
HINDI_NUMBERS: "hindiNumbers",
|
|
648
|
+
HINDI_VOWELS: "hindiVowels",
|
|
649
|
+
IDEOGRAPH_DIGITAL: "ideographDigital",
|
|
650
|
+
IDEOGRAPH_ENCLOSED_CIRCLE: "ideographEnclosedCircle",
|
|
651
|
+
IDEOGRAPH_LEGAL_TRADITIONAL: "ideographLegalTraditional",
|
|
652
|
+
IDEOGRAPH_TRADITIONAL: "ideographTraditional",
|
|
653
|
+
IDEOGRAPH_ZODIAC: "ideographZodiac",
|
|
654
|
+
IDEOGRAPH_ZODIAC_TRADITIONAL: "ideographZodiacTraditional",
|
|
655
|
+
IROHA: "iroha",
|
|
656
|
+
IROHA_FULL_WIDTH: "irohaFullWidth",
|
|
657
|
+
JAPANESE_COUNTING: "japaneseCounting",
|
|
658
|
+
JAPANESE_DIGITAL_TEN_THOUSAND: "japaneseDigitalTenThousand",
|
|
659
|
+
JAPANESE_LEGAL: "japaneseLegal",
|
|
660
|
+
KOREAN_COUNTING: "koreanCounting",
|
|
661
|
+
KOREAN_DIGITAL: "koreanDigital",
|
|
662
|
+
KOREAN_DIGITAL_2: "koreanDigital2",
|
|
663
|
+
KOREAN_LEGAL: "koreanLegal",
|
|
664
|
+
LOWER_LETTER: "lowerLetter",
|
|
665
|
+
LOWER_ROMAN: "lowerRoman",
|
|
666
|
+
NONE: "none",
|
|
667
|
+
NUMBER_IN_DASH: "numberInDash",
|
|
668
|
+
ORDINAL: "ordinal",
|
|
669
|
+
ORDINAL_TEXT: "ordinalText",
|
|
670
|
+
RUSSIAN_LOWER: "russianLower",
|
|
671
|
+
RUSSIAN_UPPER: "russianUpper",
|
|
672
|
+
TAIWANESE_COUNTING: "taiwaneseCounting",
|
|
673
|
+
TAIWANESE_COUNTING_THOUSAND: "taiwaneseCountingThousand",
|
|
674
|
+
TAIWANESE_DIGITAL: "taiwaneseDigital",
|
|
675
|
+
THAI_COUNTING: "thaiCounting",
|
|
676
|
+
THAI_LETTERS: "thaiLetters",
|
|
677
|
+
THAI_NUMBERS: "thaiNumbers",
|
|
678
|
+
UPPER_LETTER: "upperLetter",
|
|
679
|
+
UPPER_ROMAN: "upperRoman",
|
|
680
|
+
VIETNAMESE_COUNTING: "vietnameseCounting"
|
|
681
|
+
};
|
|
682
|
+
/**
|
|
683
|
+
* XML space handling modes.
|
|
684
|
+
*
|
|
685
|
+
* @publicApi
|
|
686
|
+
*/
|
|
687
|
+
const SpaceType = {
|
|
688
|
+
DEFAULT: "default",
|
|
689
|
+
PRESERVE: "preserve"
|
|
690
|
+
};
|
|
691
|
+
//#endregion
|
|
692
|
+
//#region src/parts/drawing/floating/floating-position.ts
|
|
693
|
+
/**
|
|
694
|
+
* Horizontal Relative Positioning.
|
|
695
|
+
*
|
|
696
|
+
* Specifies the horizontal base from which the drawing position is calculated.
|
|
697
|
+
*
|
|
698
|
+
* Reference: https://www.datypic.com/sc/ooxml/t-wp_ST_RelFromH.html
|
|
699
|
+
*
|
|
700
|
+
* ## XSD Schema
|
|
701
|
+
* ```xml
|
|
702
|
+
* <xsd:simpleType name="ST_RelFromH">
|
|
703
|
+
* <xsd:restriction base="xsd:token">
|
|
704
|
+
* <xsd:enumeration value="margin"/>
|
|
705
|
+
* <xsd:enumeration value="page"/>
|
|
706
|
+
* <xsd:enumeration value="column"/>
|
|
707
|
+
* <xsd:enumeration value="character"/>
|
|
708
|
+
* <xsd:enumeration value="leftMargin"/>
|
|
709
|
+
* <xsd:enumeration value="rightMargin"/>
|
|
710
|
+
* <xsd:enumeration value="insideMargin"/>
|
|
711
|
+
* <xsd:enumeration value="outsideMargin"/>
|
|
712
|
+
* </xsd:restriction>
|
|
713
|
+
* </xsd:simpleType>
|
|
714
|
+
* ```
|
|
715
|
+
*
|
|
716
|
+
* @publicApi
|
|
717
|
+
*/
|
|
718
|
+
const HorizontalPositionRelativeFrom = {
|
|
719
|
+
/**
|
|
720
|
+
* ## Character
|
|
721
|
+
*
|
|
722
|
+
* Specifies that the horizontal positioning shall be relative to the position of the anchor within its run content.
|
|
723
|
+
*/
|
|
724
|
+
CHARACTER: "character",
|
|
725
|
+
/**
|
|
726
|
+
* ## Column
|
|
727
|
+
*
|
|
728
|
+
* Specifies that the horizontal positioning shall be relative to the extents of the column which contains its anchor.
|
|
729
|
+
*/
|
|
730
|
+
COLUMN: "column",
|
|
731
|
+
/**
|
|
732
|
+
* ## Inside Margin
|
|
733
|
+
*
|
|
734
|
+
* Specifies that the horizontal positioning shall be relative to the inside margin of the current page (the left margin on odd pages, right on even pages).
|
|
735
|
+
*/
|
|
736
|
+
INSIDE_MARGIN: "insideMargin",
|
|
737
|
+
/**
|
|
738
|
+
* ## Left Margin
|
|
739
|
+
*
|
|
740
|
+
* Specifies that the horizontal positioning shall be relative to the left margin of the page.
|
|
741
|
+
*/
|
|
742
|
+
LEFT_MARGIN: "leftMargin",
|
|
743
|
+
/**
|
|
744
|
+
* ## Page Margin
|
|
745
|
+
*
|
|
746
|
+
* Specifies that the horizontal positioning shall be relative to the page margins.
|
|
747
|
+
*/
|
|
748
|
+
MARGIN: "margin",
|
|
749
|
+
/**
|
|
750
|
+
* ## Outside Margin
|
|
751
|
+
*
|
|
752
|
+
* Specifies that the horizontal positioning shall be relative to the outside margin of the current page (the right margin on odd pages, left on even pages).
|
|
753
|
+
*/
|
|
754
|
+
OUTSIDE_MARGIN: "outsideMargin",
|
|
755
|
+
/**
|
|
756
|
+
* ## Page Edge
|
|
757
|
+
*
|
|
758
|
+
* Specifies that the horizontal positioning shall be relative to the edge of the page.
|
|
759
|
+
*/
|
|
760
|
+
PAGE: "page",
|
|
761
|
+
/**
|
|
762
|
+
* ## Right Margin
|
|
763
|
+
*
|
|
764
|
+
* Specifies that the horizontal positioning shall be relative to the right margin of the page.
|
|
765
|
+
*/
|
|
766
|
+
RIGHT_MARGIN: "rightMargin"
|
|
767
|
+
};
|
|
768
|
+
/**
|
|
769
|
+
* Vertical Relative Positioning.
|
|
770
|
+
*
|
|
771
|
+
* Specifies the vertical base from which the drawing position is calculated.
|
|
772
|
+
*
|
|
773
|
+
* Reference: https://www.datypic.com/sc/ooxml/t-wp_ST_RelFromV.html
|
|
774
|
+
*
|
|
775
|
+
* ## XSD Schema
|
|
776
|
+
* ```xml
|
|
777
|
+
* <xsd:simpleType name="ST_RelFromV">
|
|
778
|
+
* <xsd:restriction base="xsd:token">
|
|
779
|
+
* <xsd:enumeration value="margin"/>
|
|
780
|
+
* <xsd:enumeration value="page"/>
|
|
781
|
+
* <xsd:enumeration value="paragraph"/>
|
|
782
|
+
* <xsd:enumeration value="line"/>
|
|
783
|
+
* <xsd:enumeration value="topMargin"/>
|
|
784
|
+
* <xsd:enumeration value="bottomMargin"/>
|
|
785
|
+
* <xsd:enumeration value="insideMargin"/>
|
|
786
|
+
* <xsd:enumeration value="outsideMargin"/>
|
|
787
|
+
* </xsd:restriction>
|
|
788
|
+
* </xsd:simpleType>
|
|
789
|
+
* ```
|
|
790
|
+
*
|
|
791
|
+
* @publicApi
|
|
792
|
+
*/
|
|
793
|
+
const VerticalPositionRelativeFrom = {
|
|
794
|
+
/**
|
|
795
|
+
* ## Bottom Margin
|
|
796
|
+
*
|
|
797
|
+
* Specifies that the vertical positioning shall be relative to the bottom margin of the current page.
|
|
798
|
+
*/
|
|
799
|
+
BOTTOM_MARGIN: "bottomMargin",
|
|
800
|
+
/**
|
|
801
|
+
* ## Inside Margin
|
|
802
|
+
*
|
|
803
|
+
* Specifies that the vertical positioning shall be relative to the inside margin of the current page.
|
|
804
|
+
*/
|
|
805
|
+
INSIDE_MARGIN: "insideMargin",
|
|
806
|
+
/**
|
|
807
|
+
* ## Line
|
|
808
|
+
*
|
|
809
|
+
* Specifies that the vertical positioning shall be relative to the line containing the anchor character.
|
|
810
|
+
*/
|
|
811
|
+
LINE: "line",
|
|
812
|
+
/**
|
|
813
|
+
* ## Page Margin
|
|
814
|
+
*
|
|
815
|
+
* Specifies that the vertical positioning shall be relative to the page margins.
|
|
816
|
+
*/
|
|
817
|
+
MARGIN: "margin",
|
|
818
|
+
/**
|
|
819
|
+
* ## Outside Margin
|
|
820
|
+
*
|
|
821
|
+
* Specifies that the vertical positioning shall be relative to the outside margin of the current page.
|
|
822
|
+
*/
|
|
823
|
+
OUTSIDE_MARGIN: "outsideMargin",
|
|
824
|
+
/**
|
|
825
|
+
* ## Page Edge
|
|
826
|
+
*
|
|
827
|
+
* Specifies that the vertical positioning shall be relative to the edge of the page.
|
|
828
|
+
*/
|
|
829
|
+
PAGE: "page",
|
|
830
|
+
/**
|
|
831
|
+
* ## Paragraph
|
|
832
|
+
*
|
|
833
|
+
* Specifies that the vertical positioning shall be relative to the paragraph which contains the drawing anchor.
|
|
834
|
+
*/
|
|
835
|
+
PARAGRAPH: "paragraph",
|
|
836
|
+
/**
|
|
837
|
+
* ## Top Margin
|
|
838
|
+
*
|
|
839
|
+
* Specifies that the vertical positioning shall be relative to the top margin of the current page.
|
|
840
|
+
*/
|
|
841
|
+
TOP_MARGIN: "topMargin"
|
|
842
|
+
};
|
|
843
|
+
//#endregion
|
|
844
|
+
//#region src/parts/drawing/floating/horizontal-position.ts
|
|
845
|
+
/**
|
|
846
|
+
* Horizontal position module for floating drawings in WordprocessingML documents.
|
|
847
|
+
*
|
|
848
|
+
* This module provides horizontal positioning for floating drawing objects,
|
|
849
|
+
* specifying the horizontal placement relative to a base element.
|
|
850
|
+
*
|
|
851
|
+
* Reference: http://officeopenxml.com/drwPicFloating-position.php
|
|
852
|
+
*
|
|
853
|
+
* @module
|
|
854
|
+
*/
|
|
855
|
+
/**
|
|
856
|
+
* Creates a horizontal position element for floating drawings.
|
|
857
|
+
*
|
|
858
|
+
* The positionH element specifies the horizontal positioning of a floating
|
|
859
|
+
* object relative to a base element (page, margin, column, etc.).
|
|
860
|
+
*
|
|
861
|
+
* Reference: https://www.datypic.com/sc/ooxml/e-wp_positionH-1.html
|
|
862
|
+
*
|
|
863
|
+
* ## XSD Schema
|
|
864
|
+
* ```xml
|
|
865
|
+
* <xsd:complexType name="CT_PosH">
|
|
866
|
+
* <xsd:choice>
|
|
867
|
+
* <xsd:element name="align" type="ST_AlignH"/>
|
|
868
|
+
* <xsd:element name="posOffset" type="ST_PositionOffset"/>
|
|
869
|
+
* </xsd:choice>
|
|
870
|
+
* <xsd:attribute name="relativeFrom" type="ST_RelFromH" use="required"/>
|
|
871
|
+
* </xsd:complexType>
|
|
872
|
+
* ```
|
|
873
|
+
*
|
|
874
|
+
* @param options - Horizontal position configuration
|
|
875
|
+
* @returns The positionH XML string
|
|
876
|
+
*
|
|
877
|
+
* @example
|
|
878
|
+
* ```typescript
|
|
879
|
+
* // Align to the left of the page
|
|
880
|
+
* createHorizontalPosition({
|
|
881
|
+
* relative: HorizontalPositionRelativeFrom.PAGE,
|
|
882
|
+
* align: HorizontalPositionAlign.LEFT,
|
|
883
|
+
* });
|
|
884
|
+
*
|
|
885
|
+
* // Offset from the margin
|
|
886
|
+
* createHorizontalPosition({
|
|
887
|
+
* relative: HorizontalPositionRelativeFrom.MARGIN,
|
|
888
|
+
* offset: 914400, // 1 inch in EMUs
|
|
889
|
+
* });
|
|
890
|
+
* ```
|
|
891
|
+
*/
|
|
892
|
+
const createHorizontalPosition = ({ relative, align, offset }) => {
|
|
893
|
+
const child = align ? `<wp:align>${align}</wp:align>` : offset !== void 0 ? `<wp:posOffset>${offset}</wp:posOffset>` : `<wp:align>${HorizontalPositionAlign.LEFT}</wp:align>`;
|
|
894
|
+
return element("wp:positionH", { relativeFrom: relative ?? HorizontalPositionRelativeFrom.PAGE }, [child]);
|
|
895
|
+
};
|
|
896
|
+
//#endregion
|
|
897
|
+
//#region src/parts/drawing/floating/vertical-position.ts
|
|
898
|
+
/**
|
|
899
|
+
* Vertical position module for floating drawings in WordprocessingML documents.
|
|
900
|
+
*
|
|
901
|
+
* This module provides vertical positioning for floating drawing objects,
|
|
902
|
+
* specifying the vertical placement relative to a base element.
|
|
903
|
+
*
|
|
904
|
+
* Reference: http://officeopenxml.com/drwPicFloating-position.php
|
|
905
|
+
*
|
|
906
|
+
* @module
|
|
907
|
+
*/
|
|
908
|
+
/**
|
|
909
|
+
* Creates a vertical position element for floating drawings.
|
|
910
|
+
*
|
|
911
|
+
* The positionV element specifies the vertical positioning of a floating
|
|
912
|
+
* object relative to a base element (page, margin, paragraph, line, etc.).
|
|
913
|
+
*
|
|
914
|
+
* Reference: https://www.datypic.com/sc/ooxml/e-wp_positionV-1.html
|
|
915
|
+
*
|
|
916
|
+
* ## XSD Schema
|
|
917
|
+
* ```xml
|
|
918
|
+
* <xsd:complexType name="CT_PosV">
|
|
919
|
+
* <xsd:choice>
|
|
920
|
+
* <xsd:element name="align" type="ST_AlignV"/>
|
|
921
|
+
* <xsd:element name="posOffset" type="ST_PositionOffset"/>
|
|
922
|
+
* </xsd:choice>
|
|
923
|
+
* <xsd:attribute name="relativeFrom" type="ST_RelFromV" use="required"/>
|
|
924
|
+
* </xsd:complexType>
|
|
925
|
+
* ```
|
|
926
|
+
*
|
|
927
|
+
* @param options - Vertical position configuration
|
|
928
|
+
* @returns The positionV XML string
|
|
929
|
+
*
|
|
930
|
+
* @example
|
|
931
|
+
* ```typescript
|
|
932
|
+
* // Align to the top of the page
|
|
933
|
+
* createVerticalPosition({
|
|
934
|
+
* relative: VerticalPositionRelativeFrom.PAGE,
|
|
935
|
+
* align: VerticalPositionAlign.TOP,
|
|
936
|
+
* });
|
|
937
|
+
*
|
|
938
|
+
* // Offset from the paragraph
|
|
939
|
+
* createVerticalPosition({
|
|
940
|
+
* relative: VerticalPositionRelativeFrom.PARAGRAPH,
|
|
941
|
+
* offset: 457200, // 0.5 inch in EMUs
|
|
942
|
+
* });
|
|
943
|
+
* ```
|
|
944
|
+
*/
|
|
945
|
+
const createVerticalPosition = ({ relative, align, offset }) => {
|
|
946
|
+
const child = align ? `<wp:align>${align}</wp:align>` : offset !== void 0 ? `<wp:posOffset>${offset}</wp:posOffset>` : `<wp:align>${VerticalPositionAlign.TOP}</wp:align>`;
|
|
947
|
+
return element("wp:positionV", { relativeFrom: relative ?? VerticalPositionRelativeFrom.PAGE }, [child]);
|
|
948
|
+
};
|
|
949
|
+
//#endregion
|
|
950
|
+
//#region src/parts/drawing/drawing-parse.ts
|
|
951
|
+
/**
|
|
952
|
+
* Drawing parser for DOCX documents.
|
|
953
|
+
*
|
|
954
|
+
* Parses w:drawing elements and extracts image, chart, or SmartArt data.
|
|
955
|
+
*
|
|
956
|
+
* @module
|
|
957
|
+
*/
|
|
958
|
+
/**
|
|
959
|
+
* Parse a w:drawing element and dispatch to the correct parser
|
|
960
|
+
* based on the graphicData URI.
|
|
961
|
+
*/
|
|
962
|
+
function parseDrawingRun(el, ctx) {
|
|
963
|
+
const graphicData = findDeep(el, "a:graphicData")[0];
|
|
964
|
+
if (!graphicData) return void 0;
|
|
965
|
+
const uri = attr(graphicData, "uri") ?? "";
|
|
966
|
+
if (uri.includes("/chart")) return parseChartDrawing(el, ctx);
|
|
967
|
+
if (uri.includes("/diagram")) return parseSmartArtDrawing(el, ctx);
|
|
968
|
+
return parseImageRun(el, ctx);
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* Determine image type from file extension or MIME type.
|
|
972
|
+
*/
|
|
973
|
+
function imageTypeFromPath(path) {
|
|
974
|
+
switch (path.split(".").pop()?.toLowerCase() ?? "") {
|
|
975
|
+
case "jpg":
|
|
976
|
+
case "jpeg": return "jpg";
|
|
977
|
+
case "png": return "png";
|
|
978
|
+
case "gif": return "gif";
|
|
979
|
+
case "bmp": return "bmp";
|
|
980
|
+
case "tif":
|
|
981
|
+
case "tiff": return "tif";
|
|
982
|
+
case "ico": return "ico";
|
|
983
|
+
case "emf": return "emf";
|
|
984
|
+
case "wmf": return "wmf";
|
|
985
|
+
default: return "png";
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Parse a w:drawing element and return image data wrapped in { image: ... }.
|
|
990
|
+
*/
|
|
991
|
+
function parseImageRun(el, ctx) {
|
|
992
|
+
const inline = findDeep(el, "wp:inline")[0];
|
|
993
|
+
const anchor = inline ? void 0 : findDeep(el, "wp:anchor")[0];
|
|
994
|
+
const parent = inline ?? anchor;
|
|
995
|
+
if (!parent) return void 0;
|
|
996
|
+
const extent = findChild(parent, "wp:extent");
|
|
997
|
+
let width;
|
|
998
|
+
let height;
|
|
999
|
+
if (extent) {
|
|
1000
|
+
const cxEmu = attrNum(extent, "cx");
|
|
1001
|
+
const cyEmu = attrNum(extent, "cy");
|
|
1002
|
+
if (cxEmu !== void 0) width = convertEmuToPixels(cxEmu);
|
|
1003
|
+
if (cyEmu !== void 0) height = convertEmuToPixels(cyEmu);
|
|
1004
|
+
}
|
|
1005
|
+
const blip = findDeep(parent, "a:blip")[0];
|
|
1006
|
+
if (!blip) return void 0;
|
|
1007
|
+
const rEmbed = attr(blip, "r:embed");
|
|
1008
|
+
if (!rEmbed) return void 0;
|
|
1009
|
+
const mediaPath = ctx.docx.partRefs.media.get(rEmbed);
|
|
1010
|
+
if (!mediaPath) return void 0;
|
|
1011
|
+
const imageData = ctx.docx.doc.getRaw(mediaPath);
|
|
1012
|
+
if (!imageData) return void 0;
|
|
1013
|
+
const imageOpts = {
|
|
1014
|
+
type: imageTypeFromPath(mediaPath),
|
|
1015
|
+
data: imageData,
|
|
1016
|
+
transformation: {
|
|
1017
|
+
...width !== void 0 ? { width } : {},
|
|
1018
|
+
...height !== void 0 ? { height } : {}
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
const docPr = findChild(parent, "wp:docPr");
|
|
1022
|
+
if (docPr) {
|
|
1023
|
+
const name = attr(docPr, "name");
|
|
1024
|
+
const descr = attr(docPr, "descr");
|
|
1025
|
+
const title = attr(docPr, "title");
|
|
1026
|
+
if (name || descr || title) imageOpts.altText = {
|
|
1027
|
+
...name ? { name } : {},
|
|
1028
|
+
...descr ? { description: descr } : {},
|
|
1029
|
+
...title ? { title } : {}
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
if (anchor && !inline) {
|
|
1033
|
+
const floating = {};
|
|
1034
|
+
const posH = findChild(anchor, "wp:positionH");
|
|
1035
|
+
if (posH) {
|
|
1036
|
+
const align = findChild(posH, "wp:align");
|
|
1037
|
+
const posOffset = findChild(posH, "wp:posOffset");
|
|
1038
|
+
if (align) floating.horizontalPosition = { align: textOf(align) };
|
|
1039
|
+
else if (posOffset) {
|
|
1040
|
+
const val = Number(textOf(posOffset));
|
|
1041
|
+
if (!isNaN(val)) floating.horizontalPosition = { offset: val };
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
const posV = findChild(anchor, "wp:positionV");
|
|
1045
|
+
if (posV) {
|
|
1046
|
+
const align = findChild(posV, "wp:align");
|
|
1047
|
+
const posOffset = findChild(posV, "wp:posOffset");
|
|
1048
|
+
if (align) floating.verticalPosition = { align: textOf(align) };
|
|
1049
|
+
else if (posOffset) {
|
|
1050
|
+
const val = Number(textOf(posOffset));
|
|
1051
|
+
if (!isNaN(val)) floating.verticalPosition = { offset: val };
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
for (const wrapType of [
|
|
1055
|
+
"wrapSquare",
|
|
1056
|
+
"wrapTight",
|
|
1057
|
+
"wrapTopAndBottom",
|
|
1058
|
+
"wrapNone"
|
|
1059
|
+
]) if (findChild(anchor, `wp:${wrapType}`)) {
|
|
1060
|
+
floating.wrap = wrapType;
|
|
1061
|
+
break;
|
|
1062
|
+
}
|
|
1063
|
+
if (attrBool(anchor, "behindDoc")) floating.behindDocument = true;
|
|
1064
|
+
if (Object.keys(floating).length > 0) imageOpts.floating = floating;
|
|
1065
|
+
}
|
|
1066
|
+
return { image: imageOpts };
|
|
1067
|
+
}
|
|
1068
|
+
function getDrawingExtent(el) {
|
|
1069
|
+
const inline = findDeep(el, "wp:inline")[0];
|
|
1070
|
+
const anchor = inline ? void 0 : findDeep(el, "wp:anchor")[0];
|
|
1071
|
+
const parent = inline ?? anchor;
|
|
1072
|
+
if (!parent) return {};
|
|
1073
|
+
const extent = findChild(parent, "wp:extent");
|
|
1074
|
+
if (!extent) return {};
|
|
1075
|
+
const cxEmu = attrNum(extent, "cx");
|
|
1076
|
+
const cyEmu = attrNum(extent, "cy");
|
|
1077
|
+
return {
|
|
1078
|
+
...cxEmu !== void 0 ? { width: convertEmuToPixels(cxEmu) } : {},
|
|
1079
|
+
...cyEmu !== void 0 ? { height: convertEmuToPixels(cyEmu) } : {}
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Look up a relationship ID in a map, with fallback for double "rId" prefix
|
|
1084
|
+
* that the library's generation code produces (e.g. "rIdrId7" → "rId7").
|
|
1085
|
+
*/
|
|
1086
|
+
function lookupRId(map, rId) {
|
|
1087
|
+
if (!rId) return void 0;
|
|
1088
|
+
const direct = map.get(rId);
|
|
1089
|
+
if (direct) return direct;
|
|
1090
|
+
if (rId.startsWith("rIdrId")) return map.get(rId.slice(3));
|
|
1091
|
+
}
|
|
1092
|
+
function parseChartDrawing(el, ctx) {
|
|
1093
|
+
const chartRef = findDeep(el, "c:chart")[0];
|
|
1094
|
+
if (!chartRef) return void 0;
|
|
1095
|
+
const rId = attr(chartRef, "r:id");
|
|
1096
|
+
const chartPath = lookupRId(ctx.docx.partRefs.charts, rId);
|
|
1097
|
+
if (!chartPath) return void 0;
|
|
1098
|
+
const chartXml = ctx.docx.doc.get(chartPath);
|
|
1099
|
+
if (!chartXml) return void 0;
|
|
1100
|
+
const opts = parseChartXml(chartXml);
|
|
1101
|
+
if (!opts) return void 0;
|
|
1102
|
+
const ext = getDrawingExtent(el);
|
|
1103
|
+
if (ext.width !== void 0 || ext.height !== void 0) opts.transformation = { ...ext };
|
|
1104
|
+
return { chart: opts };
|
|
1105
|
+
}
|
|
1106
|
+
/**
|
|
1107
|
+
* Parse c:chartSpace element into ChartOptions.
|
|
1108
|
+
*/
|
|
1109
|
+
function parseChartXml(el) {
|
|
1110
|
+
const chart = findChild(el, "c:chart");
|
|
1111
|
+
if (!chart) return void 0;
|
|
1112
|
+
const opts = {};
|
|
1113
|
+
const titleEl = findChild(chart, "c:title");
|
|
1114
|
+
if (titleEl) {
|
|
1115
|
+
const rich = findDeep(titleEl, "c:rich")[0];
|
|
1116
|
+
if (rich) {
|
|
1117
|
+
const t = findDeep(rich, "a:t")[0];
|
|
1118
|
+
if (t) {
|
|
1119
|
+
const title = textOf(t);
|
|
1120
|
+
if (title) opts.title = title;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
const plotArea = findChild(chart, "c:plotArea");
|
|
1125
|
+
if (!plotArea) return void 0;
|
|
1126
|
+
let chartType;
|
|
1127
|
+
let typeElement;
|
|
1128
|
+
for (const child of plotArea.elements ?? []) {
|
|
1129
|
+
switch (child.name) {
|
|
1130
|
+
case "c:barChart": {
|
|
1131
|
+
const barDir = findChild(child, "c:barDir");
|
|
1132
|
+
chartType = barDir && attr(barDir, "val") === "bar" ? "bar" : "column";
|
|
1133
|
+
typeElement = child;
|
|
1134
|
+
break;
|
|
1135
|
+
}
|
|
1136
|
+
case "c:lineChart":
|
|
1137
|
+
chartType = "line";
|
|
1138
|
+
typeElement = child;
|
|
1139
|
+
break;
|
|
1140
|
+
case "c:pieChart":
|
|
1141
|
+
chartType = "pie";
|
|
1142
|
+
typeElement = child;
|
|
1143
|
+
break;
|
|
1144
|
+
case "c:areaChart":
|
|
1145
|
+
chartType = "area";
|
|
1146
|
+
typeElement = child;
|
|
1147
|
+
break;
|
|
1148
|
+
case "c:scatterChart":
|
|
1149
|
+
chartType = "scatter";
|
|
1150
|
+
typeElement = child;
|
|
1151
|
+
break;
|
|
1152
|
+
}
|
|
1153
|
+
if (chartType) break;
|
|
1154
|
+
}
|
|
1155
|
+
if (!chartType || !typeElement) return void 0;
|
|
1156
|
+
opts.type = chartType;
|
|
1157
|
+
const series = [];
|
|
1158
|
+
let categories;
|
|
1159
|
+
for (const serEl of typeElement.elements ?? []) {
|
|
1160
|
+
if (serEl.name !== "c:ser") continue;
|
|
1161
|
+
const nameParts = extractStrCache(serEl, "c:tx");
|
|
1162
|
+
const cats = extractStrCache(serEl, "c:cat");
|
|
1163
|
+
if (cats.length > 0 && !categories) categories = cats;
|
|
1164
|
+
const vals = extractNumCache(serEl);
|
|
1165
|
+
series.push({
|
|
1166
|
+
name: nameParts[0] ?? "",
|
|
1167
|
+
values: vals
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
opts.categories = categories ?? [];
|
|
1171
|
+
opts.series = series;
|
|
1172
|
+
opts.showLegend = findChild(chart, "c:legend") !== void 0;
|
|
1173
|
+
const styleEl = findChild(el, "c:style");
|
|
1174
|
+
if (styleEl) {
|
|
1175
|
+
const val = attrNum(styleEl, "val");
|
|
1176
|
+
if (val !== void 0) opts.style = val;
|
|
1177
|
+
}
|
|
1178
|
+
return opts;
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Extract string values from c:strCache within a container element.
|
|
1182
|
+
*/
|
|
1183
|
+
function extractStrCache(parent, containerName) {
|
|
1184
|
+
const container = findChild(parent, containerName);
|
|
1185
|
+
if (!container) return [];
|
|
1186
|
+
const cache = findDeep(container, "c:strCache")[0];
|
|
1187
|
+
if (!cache) return [];
|
|
1188
|
+
const values = [];
|
|
1189
|
+
for (const pt of cache.elements ?? []) {
|
|
1190
|
+
if (pt.name !== "c:pt") continue;
|
|
1191
|
+
const v = findChild(pt, "c:v");
|
|
1192
|
+
if (v) values.push(textOf(v) ?? "");
|
|
1193
|
+
}
|
|
1194
|
+
return values;
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Extract numeric values from c:numCache within a c:val container.
|
|
1198
|
+
*/
|
|
1199
|
+
function extractNumCache(parent) {
|
|
1200
|
+
const valEl = findChild(parent, "c:val");
|
|
1201
|
+
if (!valEl) return [];
|
|
1202
|
+
const cache = findDeep(valEl, "c:numCache")[0];
|
|
1203
|
+
if (!cache) return [];
|
|
1204
|
+
const values = [];
|
|
1205
|
+
for (const pt of cache.elements ?? []) {
|
|
1206
|
+
if (pt.name !== "c:pt") continue;
|
|
1207
|
+
const v = findChild(pt, "c:v");
|
|
1208
|
+
if (v) {
|
|
1209
|
+
const num = Number(textOf(v));
|
|
1210
|
+
if (!isNaN(num)) values.push(num);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
return values;
|
|
1214
|
+
}
|
|
1215
|
+
function parseSmartArtDrawing(el, ctx) {
|
|
1216
|
+
const relIds = findDeep(el, "dgm:relIds")[0];
|
|
1217
|
+
if (!relIds) return void 0;
|
|
1218
|
+
const rId = attr(relIds, "r:dm");
|
|
1219
|
+
const dataPath = lookupRId(ctx.docx.partRefs.diagramData, rId);
|
|
1220
|
+
if (!dataPath) return void 0;
|
|
1221
|
+
const dataEl = ctx.docx.doc.get(dataPath);
|
|
1222
|
+
if (!dataEl) return void 0;
|
|
1223
|
+
const opts = parseSmartArtDataXml(dataEl);
|
|
1224
|
+
if (!opts) return void 0;
|
|
1225
|
+
const ext = getDrawingExtent(el);
|
|
1226
|
+
if (ext.width !== void 0 || ext.height !== void 0) opts.transformation = { ...ext };
|
|
1227
|
+
return { smartArt: opts };
|
|
1228
|
+
}
|
|
1229
|
+
/**
|
|
1230
|
+
* Parse dgm:dataModel element into SmartArtOptions.
|
|
1231
|
+
*/
|
|
1232
|
+
function parseSmartArtDataXml(el) {
|
|
1233
|
+
const ptLst = findChild(el, "dgm:ptLst");
|
|
1234
|
+
if (!ptLst) return void 0;
|
|
1235
|
+
const opts = {};
|
|
1236
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
1237
|
+
for (const pt of ptLst.elements ?? []) {
|
|
1238
|
+
if (pt.name !== "dgm:pt") continue;
|
|
1239
|
+
const type = attr(pt, "type");
|
|
1240
|
+
const modelId = attr(pt, "modelId");
|
|
1241
|
+
if (type === "doc") {
|
|
1242
|
+
const prSet = findChild(pt, "dgm:prSet");
|
|
1243
|
+
if (prSet) {
|
|
1244
|
+
const loTypeId = attr(prSet, "loTypeId") ?? "";
|
|
1245
|
+
const qsTypeId = attr(prSet, "qsTypeId") ?? "";
|
|
1246
|
+
const csTypeId = attr(prSet, "csTypeId") ?? "";
|
|
1247
|
+
const layout = loTypeId.split("/").pop();
|
|
1248
|
+
if (layout) opts.layout = layout;
|
|
1249
|
+
const style = qsTypeId.split("/").pop();
|
|
1250
|
+
if (style) opts.style = style;
|
|
1251
|
+
const color = csTypeId.split("/").pop();
|
|
1252
|
+
if (color) opts.color = color;
|
|
1253
|
+
}
|
|
1254
|
+
} else if (type === "node" && modelId) {
|
|
1255
|
+
const t = findDeep(pt, "a:t")[0];
|
|
1256
|
+
nodeMap.set(modelId, t ? textOf(t) ?? "" : "");
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
const cxnLst = findChild(el, "dgm:cxnLst");
|
|
1260
|
+
if (!cxnLst) {
|
|
1261
|
+
opts.data = { nodes: [] };
|
|
1262
|
+
return opts;
|
|
1263
|
+
}
|
|
1264
|
+
const childrenMap = /* @__PURE__ */ new Map();
|
|
1265
|
+
for (const cxn of cxnLst.elements ?? []) {
|
|
1266
|
+
if (cxn.name !== "dgm:cxn") continue;
|
|
1267
|
+
const srcId = attr(cxn, "srcId");
|
|
1268
|
+
const destId = attr(cxn, "destId");
|
|
1269
|
+
if (!srcId || !destId || !nodeMap.has(destId)) continue;
|
|
1270
|
+
let arr = childrenMap.get(srcId);
|
|
1271
|
+
if (!arr) {
|
|
1272
|
+
arr = [];
|
|
1273
|
+
childrenMap.set(srcId, arr);
|
|
1274
|
+
}
|
|
1275
|
+
arr.push(destId);
|
|
1276
|
+
}
|
|
1277
|
+
opts.data = { nodes: (childrenMap.get("0") ?? []).map((id) => buildSmartArtNode(id, nodeMap, childrenMap)) };
|
|
1278
|
+
return opts;
|
|
1279
|
+
}
|
|
1280
|
+
function buildSmartArtNode(id, nodeMap, childrenMap) {
|
|
1281
|
+
const text = nodeMap.get(id) ?? "";
|
|
1282
|
+
const childIds = childrenMap.get(id) ?? [];
|
|
1283
|
+
if (childIds.length === 0) return { text };
|
|
1284
|
+
return {
|
|
1285
|
+
text,
|
|
1286
|
+
children: childIds.map((cid) => buildSmartArtNode(cid, nodeMap, childrenMap))
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
//#endregion
|
|
1290
|
+
//#region src/parts/drawing/descriptor.ts
|
|
1291
|
+
/**
|
|
1292
|
+
* Drawing descriptor for DOCX documents.
|
|
1293
|
+
*
|
|
1294
|
+
* Produces `<w:drawing>` XML directly from media data and options,
|
|
1295
|
+
* eliminating the Drawing/Inline/Anchor/Graphic/GraphicData/Pic XmlComponent
|
|
1296
|
+
* class chain (~10 instances per drawing in the old path).
|
|
1297
|
+
*
|
|
1298
|
+
* Common path (inline image/chart/smartart without advanced properties):
|
|
1299
|
+
* zero XmlComponent instances — pure string concatenation.
|
|
1300
|
+
*
|
|
1301
|
+
* Advanced properties (outline, fill, effects on images) and floating
|
|
1302
|
+
* positioning use core `create*()` + `.toXml({stack:[]})` for sub-elements
|
|
1303
|
+
* (lightweight BuilderElement instances, not deep hierarchies).
|
|
1304
|
+
*
|
|
1305
|
+
* Reference: ISO/IEC 29500-4, wml.xsd, CT_Drawing
|
|
1306
|
+
*
|
|
1307
|
+
* @module
|
|
1308
|
+
*/
|
|
1309
|
+
const NOOP_CTX = {
|
|
1310
|
+
addRelationship: () => "",
|
|
1311
|
+
addMedia: () => ""
|
|
1312
|
+
};
|
|
1313
|
+
let _docPropsIdGen = uniqueNumericIdCreator();
|
|
1314
|
+
/** Reset the doc properties ID generator (for testing). */
|
|
1315
|
+
const resetDrawingIdGen = () => {
|
|
1316
|
+
_docPropsIdGen = uniqueNumericIdCreator();
|
|
1317
|
+
};
|
|
1318
|
+
const GRAPHIC_NS = "xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\"";
|
|
1319
|
+
const PIC_URI = "http://schemas.openxmlformats.org/drawingml/2006/picture";
|
|
1320
|
+
const CHART_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
|
|
1321
|
+
const DGM_URI = "http://schemas.openxmlformats.org/drawingml/2006/diagram";
|
|
1322
|
+
const WPS_URI = "http://schemas.microsoft.com/office/word/2010/wordprocessingShape";
|
|
1323
|
+
const WPG_URI = "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup";
|
|
1324
|
+
const HYPERLINK_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
|
1325
|
+
function registerHyperlinks(hyperlink, ctx) {
|
|
1326
|
+
if (!hyperlink) return {};
|
|
1327
|
+
const result = {};
|
|
1328
|
+
if (hyperlink.click) {
|
|
1329
|
+
const linkId = uniqueId();
|
|
1330
|
+
ctx.viewWrapper.relationships.addRelationship(linkId, HYPERLINK_REL, hyperlink.click, TargetModeType.EXTERNAL);
|
|
1331
|
+
result.clickId = `rId${linkId}`;
|
|
1332
|
+
}
|
|
1333
|
+
if (hyperlink.hover) {
|
|
1334
|
+
const linkId = uniqueId();
|
|
1335
|
+
ctx.viewWrapper.relationships.addRelationship(linkId, HYPERLINK_REL, hyperlink.hover, TargetModeType.EXTERNAL);
|
|
1336
|
+
result.hoverId = `rId${linkId}`;
|
|
1337
|
+
}
|
|
1338
|
+
return result;
|
|
1339
|
+
}
|
|
1340
|
+
function buildHyperlinkChildren(ids) {
|
|
1341
|
+
const parts = [];
|
|
1342
|
+
const aNs = "xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\"";
|
|
1343
|
+
if (ids.clickId) parts.push(`<a:hlinkClick r:id="${ids.clickId}" ${aNs}/>`);
|
|
1344
|
+
if (ids.hoverId) parts.push(`<a:hlinkHover r:id="${ids.hoverId}" ${aNs}/>`);
|
|
1345
|
+
return parts.join("");
|
|
1346
|
+
}
|
|
1347
|
+
function stringifyDocPr(opts, hlIds) {
|
|
1348
|
+
const id = opts?.id ?? _docPropsIdGen();
|
|
1349
|
+
const name = opts?.name ?? "";
|
|
1350
|
+
const attrs = [`id="${id}"`, `name="${escapeXml(name)}"`];
|
|
1351
|
+
if (opts?.description != null && opts.description !== void 0) attrs.push(`descr="${escapeXml(opts.description)}"`);
|
|
1352
|
+
if (opts?.title != null && opts.title !== void 0) attrs.push(`title="${escapeXml(opts.title)}"`);
|
|
1353
|
+
const hlXml = buildHyperlinkChildren(hlIds);
|
|
1354
|
+
if (hlXml) return `<wp:docPr ${attrs.join(" ")}>${hlXml}</wp:docPr>`;
|
|
1355
|
+
return `<wp:docPr ${attrs.join(" ")}/>`;
|
|
1356
|
+
}
|
|
1357
|
+
function stringifyBlipFill(mediaData, blipEffects, tile) {
|
|
1358
|
+
const fileName = mediaData.type === "svg" && "fallback" in mediaData ? mediaData.fallback.fileName : mediaData.fileName;
|
|
1359
|
+
const parts = [];
|
|
1360
|
+
const blipAttrs = [`r:embed="{${escapeXml(fileName)}}"`, "cstate=\"none\""];
|
|
1361
|
+
const blipContent = (mediaData.type === "svg" ? `<a:extLst><a:ext uri="{96DAC541-7B7A-43D3-8B79-37D633B846F1}"><asvg:svgBlip xmlns:asvg="http://schemas.microsoft.com/office/drawing/2016/SVG/main" r:embed="{${escapeXml(mediaData.fileName)}}"/></a:ext></a:extLst>` : "") + (blipEffects ? buildBlipEffectsXml(blipEffects) : "");
|
|
1362
|
+
if (blipContent) parts.push(`<a:blip ${blipAttrs.join(" ")}>${blipContent}</a:blip>`);
|
|
1363
|
+
else parts.push(`<a:blip ${blipAttrs.join(" ")}/>`);
|
|
1364
|
+
if (mediaData.srcRect) {
|
|
1365
|
+
const srAttrs = [];
|
|
1366
|
+
if (mediaData.srcRect.left !== void 0) srAttrs.push(`l="${mediaData.srcRect.left}"`);
|
|
1367
|
+
if (mediaData.srcRect.top !== void 0) srAttrs.push(`t="${mediaData.srcRect.top}"`);
|
|
1368
|
+
if (mediaData.srcRect.right !== void 0) srAttrs.push(`r="${mediaData.srcRect.right}"`);
|
|
1369
|
+
if (mediaData.srcRect.bottom !== void 0) srAttrs.push(`b="${mediaData.srcRect.bottom}"`);
|
|
1370
|
+
if (srAttrs.length) parts.push(`<a:srcRect ${srAttrs.join(" ")}/>`);
|
|
1371
|
+
}
|
|
1372
|
+
if (tile) {
|
|
1373
|
+
const tileAttrs = [];
|
|
1374
|
+
if (tile.tx !== void 0) tileAttrs.push(`tx="${tile.tx}"`);
|
|
1375
|
+
if (tile.ty !== void 0) tileAttrs.push(`ty="${tile.ty}"`);
|
|
1376
|
+
if (tile.sx !== void 0) tileAttrs.push(`sx="${tile.sx}"`);
|
|
1377
|
+
if (tile.sy !== void 0) tileAttrs.push(`sy="${tile.sy}"`);
|
|
1378
|
+
const tileAttrStr = tileAttrs.length ? " " + tileAttrs.join(" ") : "";
|
|
1379
|
+
parts.push(`<a:tile${tileAttrStr}/>`);
|
|
1380
|
+
} else parts.push("<a:stretch><a:fillRect/></a:stretch>");
|
|
1381
|
+
return `<pic:blipFill>${parts.join("")}</pic:blipFill>`;
|
|
1382
|
+
}
|
|
1383
|
+
function buildBlipEffectsXml(opts) {
|
|
1384
|
+
const parts = [];
|
|
1385
|
+
if (opts.grayscale) parts.push("<a:grayscl/>");
|
|
1386
|
+
if (opts.luminance) {
|
|
1387
|
+
const a = [];
|
|
1388
|
+
if (opts.luminance.bright !== void 0) a.push(`bright="${opts.luminance.bright}%"`);
|
|
1389
|
+
if (opts.luminance.contrast !== void 0) a.push(`contrast="${opts.luminance.contrast}%"`);
|
|
1390
|
+
parts.push(`<a:lum${a.length ? " " + a.join(" ") : ""}/>`);
|
|
1391
|
+
}
|
|
1392
|
+
if (opts.biLevel) parts.push(`<a:biLevel thresh="${opts.biLevel.threshold}%"/>`);
|
|
1393
|
+
if (opts.blur) {
|
|
1394
|
+
const a = [];
|
|
1395
|
+
if (opts.blur.radius !== void 0) a.push(`rad="${opts.blur.radius}"`);
|
|
1396
|
+
if (opts.blur.grow === false) a.push("grow=\"0\"");
|
|
1397
|
+
parts.push(`<a:blur${a.length ? " " + a.join(" ") : ""}/>`);
|
|
1398
|
+
}
|
|
1399
|
+
return parts.join("");
|
|
1400
|
+
}
|
|
1401
|
+
function stringifyShapeProps(transform, outline, fill, effects) {
|
|
1402
|
+
const parts = [];
|
|
1403
|
+
parts.push(transform2DDesc.stringify({
|
|
1404
|
+
x: transform.offset?.emus?.x ?? 0,
|
|
1405
|
+
y: transform.offset?.emus?.y ?? 0,
|
|
1406
|
+
width: transform.emus.x,
|
|
1407
|
+
height: transform.emus.y,
|
|
1408
|
+
flipHorizontal: transform.flip?.horizontal,
|
|
1409
|
+
flipVertical: transform.flip?.vertical,
|
|
1410
|
+
rotation: transform.rotation
|
|
1411
|
+
}, NOOP_CTX) ?? "");
|
|
1412
|
+
parts.push("<a:prstGeom prst=\"rect\"><a:avLst/></a:prstGeom>");
|
|
1413
|
+
if (fill) parts.push(fillDesc.stringify(fill, NOOP_CTX) ?? "");
|
|
1414
|
+
if (outline) parts.push(outlineDesc.stringify(outline, NOOP_CTX) ?? "");
|
|
1415
|
+
if (effects) parts.push(effectListDesc.stringify(effects, NOOP_CTX) ?? "");
|
|
1416
|
+
return `<pic:spPr bwMode="auto">${parts.join("")}</pic:spPr>`;
|
|
1417
|
+
}
|
|
1418
|
+
function stringifyNvPicPr(hlIds) {
|
|
1419
|
+
const hlXml = buildHyperlinkChildren(hlIds);
|
|
1420
|
+
return `<pic:nvPicPr><pic:cNvPr id="0" name="" descr=""${hlXml ? `>${hlXml}</pic:cNvPr>` : "/>"}<pic:cNvPicPr preferRelativeResize="1"><a:picLocks noChangeArrowheads="1" noChangeAspect="1"/></pic:cNvPicPr></pic:nvPicPr>`;
|
|
1421
|
+
}
|
|
1422
|
+
function stringifyGroupTransform2D(transform, chOff, chExt) {
|
|
1423
|
+
const attrs = [];
|
|
1424
|
+
if (transform.flip?.horizontal !== void 0) attrs.push(`flipH="${transform.flip.horizontal}"`);
|
|
1425
|
+
if (transform.flip?.vertical !== void 0) attrs.push(`flipV="${transform.flip.vertical}"`);
|
|
1426
|
+
if (transform.rotation !== void 0) attrs.push(`rot="${transform.rotation}"`);
|
|
1427
|
+
return `<a:xfrm${attrs.length ? " " + attrs.join(" ") : ""}>${`<a:off x="${transform.offset?.emus?.x ?? 0}" y="${transform.offset?.emus?.y ?? 0}"/>`}${`<a:ext cx="${transform.emus.x}" cy="${transform.emus.y}"/>`}${chOff ? `<a:chOff x="${chOff.x}" y="${chOff.y}"/>` : ""}${chExt ? `<a:chExt cx="${chExt.cx}" cy="${chExt.cy}"/>` : ""}</a:xfrm>`;
|
|
1428
|
+
}
|
|
1429
|
+
function stringifyWpsShape(opts, ctx) {
|
|
1430
|
+
const transform = opts.transformation;
|
|
1431
|
+
const spPrParts = [];
|
|
1432
|
+
spPrParts.push(transform2DDesc.stringify({
|
|
1433
|
+
x: transform.offset?.emus?.x ?? 0,
|
|
1434
|
+
y: transform.offset?.emus?.y ?? 0,
|
|
1435
|
+
width: transform.emus.x,
|
|
1436
|
+
height: transform.emus.y,
|
|
1437
|
+
flipHorizontal: transform.flip?.horizontal,
|
|
1438
|
+
flipVertical: transform.flip?.vertical,
|
|
1439
|
+
rotation: transform.rotation
|
|
1440
|
+
}, NOOP_CTX) ?? "");
|
|
1441
|
+
if (opts.customGeometry) spPrParts.push(customGeometryDesc.stringify(opts.customGeometry, NOOP_CTX) ?? "");
|
|
1442
|
+
else spPrParts.push("<a:prstGeom prst=\"rect\"><a:avLst/></a:prstGeom>");
|
|
1443
|
+
if (opts.fill) spPrParts.push(fillDesc.stringify(opts.fill, NOOP_CTX) ?? "");
|
|
1444
|
+
if (opts.outline) spPrParts.push(outlineDesc.stringify(opts.outline, NOOP_CTX) ?? "");
|
|
1445
|
+
if (opts.effectDag) spPrParts.push(createEffectDag(opts.effectDag));
|
|
1446
|
+
else if (opts.effects) spPrParts.push(effectListDesc.stringify(opts.effects, NOOP_CTX) ?? "");
|
|
1447
|
+
if (opts.scene3d) spPrParts.push(scene3DDesc.stringify(opts.scene3d, NOOP_CTX) ?? "");
|
|
1448
|
+
if (opts.shape3d) spPrParts.push(shape3DDesc.stringify(opts.shape3d, NOOP_CTX) ?? "");
|
|
1449
|
+
const cNvSpPr = opts.nonVisualProperties ? stringifyNonVisualShapeProperties(opts.nonVisualProperties) : "<wps:cNvSpPr txBox=\"1\"/>";
|
|
1450
|
+
const childXml = opts.children?.map((c) => stringifyParagraphInline(c, ctx)).join("") ?? "";
|
|
1451
|
+
return "<wps:wsp>" + cNvSpPr + `<wps:spPr bwMode="auto">${spPrParts.join("")}</wps:spPr><wps:txbx><wps:txbxContent>${childXml}</wps:txbxContent></wps:txbx>` + stringifyBodyPr(opts.bodyProperties) + "</wps:wsp>";
|
|
1452
|
+
}
|
|
1453
|
+
function stringifyNonVisualShapeProperties(opts) {
|
|
1454
|
+
if (!opts.txBox) return "<wps:cNvSpPr/>";
|
|
1455
|
+
return `<wps:cNvSpPr txBox="${opts.txBox}"/>`;
|
|
1456
|
+
}
|
|
1457
|
+
function stringifyBodyPr(opts) {
|
|
1458
|
+
if (!opts) return "<wps:bodyPr/>";
|
|
1459
|
+
const attrs = [];
|
|
1460
|
+
if (opts.anchor !== void 0) attrs.push(`anchor="${opts.anchor}"`);
|
|
1461
|
+
if (opts.vert !== void 0) attrs.push(`vert="${opts.vert}"`);
|
|
1462
|
+
if (opts.wrap !== void 0) attrs.push(`wrap="${opts.wrap}"`);
|
|
1463
|
+
if (opts.lIns !== void 0) attrs.push(`lIns="${opts.lIns}"`);
|
|
1464
|
+
if (opts.tIns !== void 0) attrs.push(`tIns="${opts.tIns}"`);
|
|
1465
|
+
if (opts.rIns !== void 0) attrs.push(`rIns="${opts.rIns}"`);
|
|
1466
|
+
if (opts.bIns !== void 0) attrs.push(`bIns="${opts.bIns}"`);
|
|
1467
|
+
if (opts.numCol !== void 0) attrs.push(`numCol="${opts.numCol}"`);
|
|
1468
|
+
if (opts.rotation !== void 0) attrs.push(`rot="${opts.rotation}"`);
|
|
1469
|
+
const attrStr = attrs.length ? " " + attrs.join(" ") : "";
|
|
1470
|
+
const parts = [];
|
|
1471
|
+
if (opts.normAutofit) {
|
|
1472
|
+
const afAttrs = [];
|
|
1473
|
+
if (opts.normAutofit.fontScale !== void 0) afAttrs.push(`fontScale="${opts.normAutofit.fontScale}"`);
|
|
1474
|
+
if (opts.normAutofit.lnSpcReduction !== void 0) afAttrs.push(`lnSpcReduction="${opts.normAutofit.lnSpcReduction}"`);
|
|
1475
|
+
parts.push(`<a:normAutofit ${afAttrs.join(" ")}/>`);
|
|
1476
|
+
}
|
|
1477
|
+
const body = parts.join("");
|
|
1478
|
+
return body ? `<wps:bodyPr${attrStr}>${body}</wps:bodyPr>` : `<wps:bodyPr${attrStr}/>`;
|
|
1479
|
+
}
|
|
1480
|
+
function stringifyWpgGroup(opts, ctx) {
|
|
1481
|
+
const transform = opts.transformation;
|
|
1482
|
+
const grpSpPrParts = [];
|
|
1483
|
+
grpSpPrParts.push(stringifyGroupTransform2D(transform, opts.chOff, opts.chExt));
|
|
1484
|
+
if (opts.fill) grpSpPrParts.push(fillDesc.stringify(opts.fill, NOOP_CTX) ?? "");
|
|
1485
|
+
if (opts.effects) grpSpPrParts.push(effectListDesc.stringify(opts.effects, NOOP_CTX) ?? "");
|
|
1486
|
+
const childXml = opts.children.map((child) => {
|
|
1487
|
+
if (child.type === "wps") {
|
|
1488
|
+
const wpsData = child;
|
|
1489
|
+
return stringifyWpsShape({
|
|
1490
|
+
...wpsData.data,
|
|
1491
|
+
outline: wpsData.outline ?? wpsData.data.outline,
|
|
1492
|
+
fill: wpsData.fill ?? wpsData.data.fill,
|
|
1493
|
+
transformation: wpsData.transformation
|
|
1494
|
+
}, ctx);
|
|
1495
|
+
}
|
|
1496
|
+
const picData = child;
|
|
1497
|
+
const picParts = [];
|
|
1498
|
+
picParts.push("<pic:nvPicPr><pic:cNvPr id=\"0\" name=\"\" descr=\"\"/><pic:cNvPicPr preferRelativeResize=\"1\"><a:picLocks noChangeAspect=\"1\"/></pic:cNvPicPr></pic:nvPicPr>");
|
|
1499
|
+
picParts.push(`<pic:blipFill><a:blip r:embed="{${picData.fileName}}" cstate="none"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill>`);
|
|
1500
|
+
picParts.push(`<pic:spPr bwMode="auto">${transform2DDesc.stringify({
|
|
1501
|
+
x: picData.transformation.offset?.emus?.x ?? 0,
|
|
1502
|
+
y: picData.transformation.offset?.emus?.y ?? 0,
|
|
1503
|
+
width: picData.transformation.emus.x,
|
|
1504
|
+
height: picData.transformation.emus.y
|
|
1505
|
+
}, NOOP_CTX) ?? "<a:xfrm/>"}<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr>`);
|
|
1506
|
+
return `<pic:pic xmlns:pic="${PIC_URI}">${picParts.join("")}</pic:pic>`;
|
|
1507
|
+
}).join("");
|
|
1508
|
+
return `<wpg:wgp><wpg:cNvGrpSpPr/><wpg:grpSpPr>${grpSpPrParts.join("")}</wpg:grpSpPr>` + childXml + "</wpg:wgp>";
|
|
1509
|
+
}
|
|
1510
|
+
function stringifyGraphicDataContent(mediaData, opts, hlIds, ctx) {
|
|
1511
|
+
const { outline, fill, effects, blipEffects, tile } = opts;
|
|
1512
|
+
const transform = mediaData.transformation;
|
|
1513
|
+
if (mediaData.type === "chart") return `<a:graphicData uri="${CHART_URI}"><c:chart xmlns:c="${CHART_URI}" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:id="{chart:${mediaData.chartKey}}"/></a:graphicData>`;
|
|
1514
|
+
if (mediaData.type === "smartart") {
|
|
1515
|
+
const md = mediaData;
|
|
1516
|
+
return `<a:graphicData uri="${DGM_URI}"><dgm:relIds xmlns:dgm="${DGM_URI}" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:dm="{smartart:${md.smartArtKey}}" r:lo="{smartart-lo:${md.smartArtKey}}" r:qs="{smartart-qs:${md.smartArtKey}}" r:cs="{smartart-cs:${md.smartArtKey}}"/></a:graphicData>`;
|
|
1517
|
+
}
|
|
1518
|
+
if (mediaData.type === "wps") return `<a:graphicData uri="${WPS_URI}">${stringifyWpsShape({
|
|
1519
|
+
...mediaData.data,
|
|
1520
|
+
outline,
|
|
1521
|
+
fill,
|
|
1522
|
+
transformation: transform
|
|
1523
|
+
}, ctx)}</a:graphicData>`;
|
|
1524
|
+
if (mediaData.type === "wpg") {
|
|
1525
|
+
const md = mediaData;
|
|
1526
|
+
return `<a:graphicData uri="${WPG_URI}">${stringifyWpgGroup({
|
|
1527
|
+
children: md.children,
|
|
1528
|
+
transformation: transform,
|
|
1529
|
+
chOff: md.chOff,
|
|
1530
|
+
chExt: md.chExt,
|
|
1531
|
+
fill: md.fill,
|
|
1532
|
+
effects: md.effects
|
|
1533
|
+
}, ctx)}</a:graphicData>`;
|
|
1534
|
+
}
|
|
1535
|
+
const md = mediaData;
|
|
1536
|
+
return `<a:graphicData uri="${PIC_URI}"><pic:pic xmlns:pic="${PIC_URI}">` + stringifyNvPicPr(hlIds) + stringifyBlipFill(md, blipEffects, tile) + stringifyShapeProps(transform, outline, fill, effects) + `</pic:pic></a:graphicData>`;
|
|
1537
|
+
}
|
|
1538
|
+
function stringifyPositionH(opts) {
|
|
1539
|
+
return `<wp:positionH relativeFrom="${opts.relative ?? HorizontalPositionRelativeFrom.PAGE}">${opts.align ? `<wp:align>${opts.align}</wp:align>` : opts.offset !== void 0 ? `<wp:posOffset>${opts.offset}</wp:posOffset>` : "<wp:align>left</wp:align>"}</wp:positionH>`;
|
|
1540
|
+
}
|
|
1541
|
+
function stringifyPositionV(opts) {
|
|
1542
|
+
return `<wp:positionV relativeFrom="${opts.relative ?? VerticalPositionRelativeFrom.PAGE}">${opts.align ? `<wp:align>${opts.align}</wp:align>` : opts.offset !== void 0 ? `<wp:posOffset>${opts.offset}</wp:posOffset>` : "<wp:align>top</wp:align>"}</wp:positionV>`;
|
|
1543
|
+
}
|
|
1544
|
+
function wrapPolygonStr(cx, cy) {
|
|
1545
|
+
return `<wp:wrapPolygon edited="0"><wp:start x="0" y="0"/><wp:lineTo x="0" y="${-cy}"/><wp:lineTo x="${cx}" y="${-cy}"/><wp:lineTo x="${cx}" y="0"/><wp:lineTo x="0" y="0"/></wp:wrapPolygon>`;
|
|
1546
|
+
}
|
|
1547
|
+
function wrapSquareStr(textWrapping, margins) {
|
|
1548
|
+
const side = textWrapping.side ?? TextWrappingSide.BOTH_SIDES;
|
|
1549
|
+
const m = margins ?? {};
|
|
1550
|
+
return `<wp:wrapSquare ${[
|
|
1551
|
+
`wrapText="${side}"`,
|
|
1552
|
+
...m.top != null ? [`distT="${m.top}"`] : [],
|
|
1553
|
+
...m.bottom != null ? [`distB="${m.bottom}"`] : [],
|
|
1554
|
+
...m.left != null ? [`distL="${m.left}"`] : [],
|
|
1555
|
+
...m.right != null ? [`distR="${m.right}"`] : []
|
|
1556
|
+
].join(" ")}/>`;
|
|
1557
|
+
}
|
|
1558
|
+
function wrapTightStr(textWrapping, margins, cx, cy) {
|
|
1559
|
+
const a = [`wrapText="${textWrapping.side ?? TextWrappingSide.BOTH_SIDES}"`];
|
|
1560
|
+
if (margins.left != null) a.push(`distL="${margins.left}"`);
|
|
1561
|
+
if (margins.right != null) a.push(`distR="${margins.right}"`);
|
|
1562
|
+
return `<wp:wrapTight ${a.join(" ")}>${wrapPolygonStr(cx, cy)}</wp:wrapTight>`;
|
|
1563
|
+
}
|
|
1564
|
+
function wrapThroughStr(textWrapping, margins, cx, cy) {
|
|
1565
|
+
const a = [`wrapText="${textWrapping.side ?? TextWrappingSide.BOTH_SIDES}"`];
|
|
1566
|
+
if (margins.left != null) a.push(`distL="${margins.left}"`);
|
|
1567
|
+
if (margins.right != null) a.push(`distR="${margins.right}"`);
|
|
1568
|
+
return `<wp:wrapThrough ${a.join(" ")}>${wrapPolygonStr(cx, cy)}</wp:wrapThrough>`;
|
|
1569
|
+
}
|
|
1570
|
+
function wrapTopAndBottomStr(margins) {
|
|
1571
|
+
const m = margins ?? {};
|
|
1572
|
+
const a = [...m.top != null ? [`distT="${m.top}"`] : [], ...m.bottom != null ? [`distB="${m.bottom}"`] : []].join(" ");
|
|
1573
|
+
return a ? `<wp:wrapTopAndBottom ${a}/>` : "<wp:wrapTopAndBottom/>";
|
|
1574
|
+
}
|
|
1575
|
+
function stringifyInline(opts, hlIds, ctx) {
|
|
1576
|
+
const { mediaData, effects, docProperties } = opts;
|
|
1577
|
+
const cx = mediaData.transformation.emus.x;
|
|
1578
|
+
const cy = mediaData.transformation.emus.y;
|
|
1579
|
+
const effectExtent = calculateEffectExtent(effects);
|
|
1580
|
+
const graphicDataXml = stringifyGraphicDataContent(mediaData, opts, hlIds, ctx);
|
|
1581
|
+
return `<w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0"><wp:extent cx="${cx}" cy="${cy}"/><wp:effectExtent l="${effectExtent.l}" t="${effectExtent.t}" r="${effectExtent.r}" b="${effectExtent.b}"/>` + stringifyDocPr(docProperties, hlIds) + `<wp:cNvGraphicFramePr><a:graphicFrameLocks noChangeAspect="1" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"/></wp:cNvGraphicFramePr><a:graphic ${GRAPHIC_NS}>${graphicDataXml}</a:graphic></wp:inline></w:drawing>`;
|
|
1582
|
+
}
|
|
1583
|
+
function stringifyAnchor(opts, hlIds, ctx) {
|
|
1584
|
+
const { mediaData, floating: rawFloating, docProperties } = opts;
|
|
1585
|
+
const cx = mediaData.transformation.emus.x;
|
|
1586
|
+
const cy = mediaData.transformation.emus.y;
|
|
1587
|
+
const floating = {
|
|
1588
|
+
allowOverlap: true,
|
|
1589
|
+
behindDocument: false,
|
|
1590
|
+
horizontalPosition: {},
|
|
1591
|
+
layoutInCell: true,
|
|
1592
|
+
lockAnchor: false,
|
|
1593
|
+
verticalPosition: {},
|
|
1594
|
+
zIndex: mediaData.transformation.emus.y,
|
|
1595
|
+
margins: {},
|
|
1596
|
+
wrap: { type: TextWrappingType.NONE },
|
|
1597
|
+
...rawFloating
|
|
1598
|
+
};
|
|
1599
|
+
const attrParts = [
|
|
1600
|
+
`distT="${floating.margins?.top ?? 0}"`,
|
|
1601
|
+
`distB="${floating.margins?.bottom ?? 0}"`,
|
|
1602
|
+
`distL="${floating.margins?.left ?? 0}"`,
|
|
1603
|
+
`distR="${floating.margins?.right ?? 0}"`,
|
|
1604
|
+
"simplePos=\"0\"",
|
|
1605
|
+
`allowOverlap="${floating.allowOverlap ? 1 : 0}"`,
|
|
1606
|
+
`behindDoc="${floating.behindDocument ? 1 : 0}"`,
|
|
1607
|
+
`locked="${floating.lockAnchor ? 1 : 0}"`,
|
|
1608
|
+
`layoutInCell="${floating.layoutInCell ? 1 : 0}"`,
|
|
1609
|
+
`relativeHeight="${floating.zIndex}"`
|
|
1610
|
+
];
|
|
1611
|
+
let wrapXml;
|
|
1612
|
+
const rawWrap = rawFloating?.wrap;
|
|
1613
|
+
if (rawWrap?.type === TextWrappingType.SQUARE) wrapXml = wrapSquareStr(rawWrap, floating.margins);
|
|
1614
|
+
else if (rawWrap?.type === TextWrappingType.TIGHT) wrapXml = wrapTightStr(rawWrap, floating.margins, cx, cy);
|
|
1615
|
+
else if (rawWrap?.type === TextWrappingType.THROUGH) wrapXml = wrapThroughStr(rawWrap, floating.margins, cx, cy);
|
|
1616
|
+
else if (rawWrap?.type === TextWrappingType.TOP_AND_BOTTOM) wrapXml = wrapTopAndBottomStr(floating.margins);
|
|
1617
|
+
else wrapXml = "<wp:wrapNone/>";
|
|
1618
|
+
const graphicDataXml = stringifyGraphicDataContent(mediaData, opts, hlIds, ctx);
|
|
1619
|
+
return `<w:drawing><wp:anchor ${attrParts.join(" ")}><wp:simplePos x="0" y="0"/>` + stringifyPositionH(floating.horizontalPosition) + stringifyPositionV(floating.verticalPosition) + `<wp:extent cx="${cx}" cy="${cy}"/><wp:effectExtent l="0" t="0" r="0" b="0"/>` + wrapXml + stringifyDocPr(docProperties, hlIds) + `<wp:cNvGraphicFramePr><a:graphicFrameLocks noChangeAspect="1" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"/></wp:cNvGraphicFramePr><a:graphic ${GRAPHIC_NS}>${graphicDataXml}</a:graphic></wp:anchor></w:drawing>`;
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* Drawing descriptor for DOCX `<w:drawing>` elements.
|
|
1623
|
+
*
|
|
1624
|
+
* Eliminates the Drawing/Inline/Anchor/Graphic/GraphicData/Pic XmlComponent
|
|
1625
|
+
* class chain. Inline images, charts, and smartarts produce XML via pure
|
|
1626
|
+
* string concatenation — zero XmlComponent instances.
|
|
1627
|
+
*
|
|
1628
|
+
* @example
|
|
1629
|
+
* ```typescript
|
|
1630
|
+
* const xml = drawingDesc.stringify({ mediaData, docProperties: opts.altText, floating: opts.floating }, ctx);
|
|
1631
|
+
* ```
|
|
1632
|
+
*/
|
|
1633
|
+
const drawingDesc = {
|
|
1634
|
+
kind: "custom",
|
|
1635
|
+
stringify(opts, ctx) {
|
|
1636
|
+
if (opts.fill) {
|
|
1637
|
+
const media = extractBlipFillMedia(opts.fill);
|
|
1638
|
+
if (media) ctx.file.media.addImage(media.fileName, {
|
|
1639
|
+
data: media.data,
|
|
1640
|
+
fileName: media.fileName,
|
|
1641
|
+
type: media.type,
|
|
1642
|
+
transformation: {
|
|
1643
|
+
pixels: {
|
|
1644
|
+
x: 0,
|
|
1645
|
+
y: 0
|
|
1646
|
+
},
|
|
1647
|
+
emus: {
|
|
1648
|
+
x: 0,
|
|
1649
|
+
y: 0
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
});
|
|
1653
|
+
}
|
|
1654
|
+
const hlIds = registerHyperlinks(opts.docProperties?.hyperlink, ctx);
|
|
1655
|
+
if (opts.floating) return stringifyAnchor(opts, hlIds, ctx);
|
|
1656
|
+
return stringifyInline(opts, hlIds, ctx);
|
|
1657
|
+
},
|
|
1658
|
+
parse(el, ctx) {
|
|
1659
|
+
return parseDrawingRun(el, ctx) ?? {};
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
//#endregion
|
|
1663
|
+
//#region src/parts/paragraph/math/stringify.ts
|
|
1664
|
+
/**
|
|
1665
|
+
* Direct XML string builders for Office MathML (OMML).
|
|
1666
|
+
*
|
|
1667
|
+
* Replaces `coerceMathInput()` + `new Math().toXml()` recursive class chain
|
|
1668
|
+
* with direct string concatenation — zero XmlComponent instances.
|
|
1669
|
+
*
|
|
1670
|
+
* Processes `MathInput` discriminated union directly to XML strings.
|
|
1671
|
+
*
|
|
1672
|
+
* @module
|
|
1673
|
+
*/
|
|
1674
|
+
function mathRunPropsStr(opts) {
|
|
1675
|
+
const parts = [];
|
|
1676
|
+
if (opts.lit) parts.push("<m:lit m:val=\"1\"/>");
|
|
1677
|
+
if (opts.normal) parts.push("<m:nor m:val=\"1\"/>");
|
|
1678
|
+
if (opts.script) parts.push(`<m:scr m:val="${opts.script}"/>`);
|
|
1679
|
+
if (opts.style) parts.push(`<m:sty m:val="${opts.style}"/>`);
|
|
1680
|
+
if (opts.breakAlignment) parts.push(`<m:brk m:alnAt="${opts.breakAlignment}"/>`);
|
|
1681
|
+
if (opts.align) parts.push("<m:aln m:val=\"1\"/>");
|
|
1682
|
+
return parts.length ? `<m:rPr>${parts.join("")}</m:rPr>` : "";
|
|
1683
|
+
}
|
|
1684
|
+
function stringifyChildren(items) {
|
|
1685
|
+
return items.map(stringifyMathInput).join("");
|
|
1686
|
+
}
|
|
1687
|
+
function stringifyMathInput(value) {
|
|
1688
|
+
if (typeof value === "string") return `<m:r><m:t>${escapeXml(value)}</m:t></m:r>`;
|
|
1689
|
+
if (typeof value !== "object" || value === null) return "";
|
|
1690
|
+
if ("subSuperScript" in value) {
|
|
1691
|
+
const opts = value.subSuperScript;
|
|
1692
|
+
return `<m:sSubSup><m:sSubSupPr/><m:e>${stringifyChildren(opts.children)}</m:e><m:sub>${stringifyChildren(opts.subScript)}</m:sub><m:sup>${stringifyChildren(opts.superScript)}</m:sup></m:sSubSup>`;
|
|
1693
|
+
}
|
|
1694
|
+
if ("preSubSuperScript" in value) {
|
|
1695
|
+
const opts = value.preSubSuperScript;
|
|
1696
|
+
return `<m:sPre><m:sPrePr/><m:sub>${stringifyChildren(opts.subScript)}</m:sub><m:sup>${stringifyChildren(opts.superScript)}</m:sup><m:e>${stringifyChildren(opts.children)}</m:e></m:sPre>`;
|
|
1697
|
+
}
|
|
1698
|
+
if ("superScript" in value) {
|
|
1699
|
+
const opts = value.superScript;
|
|
1700
|
+
return `<m:sSup><m:sSupPr/><m:e>${stringifyChildren(opts.children)}</m:e><m:sup>${stringifyChildren(opts.superScript)}</m:sup></m:sSup>`;
|
|
1701
|
+
}
|
|
1702
|
+
if ("subScript" in value) {
|
|
1703
|
+
const opts = value.subScript;
|
|
1704
|
+
return `<m:sSub><m:sSubPr/><m:e>${stringifyChildren(opts.children)}</m:e><m:sub>${stringifyChildren(opts.subScript)}</m:sub></m:sSub>`;
|
|
1705
|
+
}
|
|
1706
|
+
if ("fraction" in value) {
|
|
1707
|
+
const opts = value.fraction;
|
|
1708
|
+
return `<m:f>${opts.fractionType ? `<m:fPr><m:type m:val="${opts.fractionType}"/></m:fPr>` : ""}<m:num>${stringifyChildren(opts.numerator)}</m:num><m:den>${stringifyChildren(opts.denominator)}</m:den></m:f>`;
|
|
1709
|
+
}
|
|
1710
|
+
if ("radical" in value) {
|
|
1711
|
+
const opts = value.radical;
|
|
1712
|
+
const hasDegree = opts.degree && opts.degree.length > 0;
|
|
1713
|
+
return `<m:rad>${!hasDegree ? "<m:radPr><m:degHide m:val=\"1\"/></m:radPr>" : "<m:radPr/>"}${hasDegree ? `<m:deg>${stringifyChildren(opts.degree)}</m:deg>` : "<m:deg/>"}<m:e>${stringifyChildren(opts.children)}</m:e></m:rad>`;
|
|
1714
|
+
}
|
|
1715
|
+
if ("sum" in value) return stringifyNAry(value.sum, "∑");
|
|
1716
|
+
if ("integral" in value) return stringifyNAry(value.integral, "∫");
|
|
1717
|
+
if ("limitLower" in value) {
|
|
1718
|
+
const opts = value.limitLower;
|
|
1719
|
+
return `<m:limLow>${opts.properties ? "" : ""}<m:e>${stringifyChildren(opts.children)}</m:e><m:lim>${stringifyChildren(opts.limit)}</m:lim></m:limLow>`;
|
|
1720
|
+
}
|
|
1721
|
+
if ("limitUpper" in value) {
|
|
1722
|
+
const opts = value.limitUpper;
|
|
1723
|
+
return `<m:limUpp>${opts.properties ? "" : ""}<m:e>${stringifyChildren(opts.children)}</m:e><m:lim>${stringifyChildren(opts.limit)}</m:lim></m:limUpp>`;
|
|
1724
|
+
}
|
|
1725
|
+
if ("function" in value) {
|
|
1726
|
+
const opts = value.function;
|
|
1727
|
+
return `<m:func>${opts.properties ? "" : ""}<m:fName>${stringifyChildren(opts.name)}</m:fName><m:e>${stringifyChildren(opts.children)}</m:e></m:func>`;
|
|
1728
|
+
}
|
|
1729
|
+
if ("matrix" in value) {
|
|
1730
|
+
const opts = value.matrix;
|
|
1731
|
+
const rows = opts.rows.map((row) => `<m:mr>${row.map((cell) => `<m:e>${stringifyMathInput(cell)}</m:e>`).join("")}</m:mr>`).join("");
|
|
1732
|
+
let pr = "";
|
|
1733
|
+
if (opts.properties) {
|
|
1734
|
+
const p = opts.properties;
|
|
1735
|
+
const prParts = [];
|
|
1736
|
+
if (p.baseJc) prParts.push(`<m:baseJc m:val="${p.baseJc}"/>`);
|
|
1737
|
+
if (p.plcHide) prParts.push("<m:plcHide m:val=\"1\"/>");
|
|
1738
|
+
if (p.rSpRule) prParts.push(`<m:rSpRule m:val="${p.rSpRule}"/>`);
|
|
1739
|
+
if (p.cGpRule) prParts.push(`<m:cGpRule m:val="${p.cGpRule}"/>`);
|
|
1740
|
+
if (p.rSp) prParts.push(`<m:rSp m:val="${p.rSp}"/>`);
|
|
1741
|
+
if (p.cSp) prParts.push(`<m:cSp m:val="${p.cSp}"/>`);
|
|
1742
|
+
if (p.cGp) prParts.push(`<m:cGp m:val="${p.cGp}"/>`);
|
|
1743
|
+
if (p.mcs) {
|
|
1744
|
+
const mcItems = p.mcs.map((mc) => `<m:mc><m:mcPr><m:count m:val="${mc.count}"/><m:mcJc m:val="${mc.mcJc}"/></m:mcPr></m:mc>`).join("");
|
|
1745
|
+
prParts.push(`<m:mcs>${mcItems}</m:mcs>`);
|
|
1746
|
+
}
|
|
1747
|
+
if (prParts.length) pr = `<m:mPr>${prParts.join("")}</m:mPr>`;
|
|
1748
|
+
}
|
|
1749
|
+
return `<m:m>${pr}${rows}</m:m>`;
|
|
1750
|
+
}
|
|
1751
|
+
if ("roundBrackets" in value) return stringifyDelimiters(bracketChildren(value.roundBrackets), "(", ")");
|
|
1752
|
+
if ("curlyBrackets" in value) return stringifyDelimiters(bracketChildren(value.curlyBrackets), "{", "}");
|
|
1753
|
+
if ("angledBrackets" in value) return stringifyDelimiters(bracketChildren(value.angledBrackets), "〈", "〉");
|
|
1754
|
+
if ("squareBrackets" in value) return stringifyDelimiters(bracketChildren(value.squareBrackets), "[", "]");
|
|
1755
|
+
if ("borderBox" in value) {
|
|
1756
|
+
const opts = value.borderBox;
|
|
1757
|
+
let pr = "";
|
|
1758
|
+
if (opts.properties) {
|
|
1759
|
+
const p = opts.properties;
|
|
1760
|
+
const parts = [];
|
|
1761
|
+
if (p.hideTop) parts.push("<m:hideTop m:val=\"1\"/>");
|
|
1762
|
+
if (p.hideBottom) parts.push("<m:hideBot m:val=\"1\"/>");
|
|
1763
|
+
if (p.hideLeft) parts.push("<m:hideLeft m:val=\"1\"/>");
|
|
1764
|
+
if (p.hideRight) parts.push("<m:hideRight m:val=\"1\"/>");
|
|
1765
|
+
if (p.strikeHorizontal) parts.push("<m:strikeH m:val=\"1\"/>");
|
|
1766
|
+
if (p.strikeVertical) parts.push("<m:strikeV m:val=\"1\"/>");
|
|
1767
|
+
if (p.strikeDiagonalUp) parts.push("<m:strikeBLTR m:val=\"1\"/>");
|
|
1768
|
+
if (p.strikeDiagonalDown) parts.push("<m:strikeTLBR m:val=\"1\"/>");
|
|
1769
|
+
if (parts.length) pr = `<m:borderBoxPr>${parts.join("")}</m:borderBoxPr>`;
|
|
1770
|
+
}
|
|
1771
|
+
return `<m:borderBox>${pr}<m:e>${stringifyChildren(opts.children)}</m:e></m:borderBox>`;
|
|
1772
|
+
}
|
|
1773
|
+
if ("box" in value) {
|
|
1774
|
+
const opts = value.box;
|
|
1775
|
+
let pr = "";
|
|
1776
|
+
if (opts.properties) {
|
|
1777
|
+
const p = opts.properties;
|
|
1778
|
+
const parts = [];
|
|
1779
|
+
if (p.opEmu) parts.push("<m:opEmu m:val=\"1\"/>");
|
|
1780
|
+
if (p.noBreak) parts.push("<m:noBreak m:val=\"1\"/>");
|
|
1781
|
+
if (p.diff) parts.push("<m:diff m:val=\"1\"/>");
|
|
1782
|
+
if (p.aln) parts.push("<m:aln m:val=\"1\"/>");
|
|
1783
|
+
if (parts.length) pr = `<m:boxPr>${parts.join("")}</m:boxPr>`;
|
|
1784
|
+
}
|
|
1785
|
+
return `<m:box>${pr}<m:e>${stringifyChildren(opts.children)}</m:e></m:box>`;
|
|
1786
|
+
}
|
|
1787
|
+
if ("groupChr" in value) {
|
|
1788
|
+
const opts = value.groupChr;
|
|
1789
|
+
let pr = "";
|
|
1790
|
+
if (opts.properties) {
|
|
1791
|
+
const p = opts.properties;
|
|
1792
|
+
const parts = [];
|
|
1793
|
+
if (p.chr) parts.push(`<m:chr m:val="${p.chr}"/>`);
|
|
1794
|
+
if (p.pos) parts.push(`<m:pos m:val="${p.pos}"/>`);
|
|
1795
|
+
if (p.vertJc) parts.push(`<m:vertJc m:val="${p.vertJc}"/>`);
|
|
1796
|
+
if (parts.length) pr = `<m:groupChrPr>${parts.join("")}</m:groupChrPr>`;
|
|
1797
|
+
}
|
|
1798
|
+
return `<m:groupChr>${pr}<m:e>${stringifyChildren(opts.children)}</m:e></m:groupChr>`;
|
|
1799
|
+
}
|
|
1800
|
+
if ("phant" in value) {
|
|
1801
|
+
const opts = value.phant;
|
|
1802
|
+
let pr = "";
|
|
1803
|
+
if (opts.properties) {
|
|
1804
|
+
const p = opts.properties;
|
|
1805
|
+
const parts = [];
|
|
1806
|
+
if (p.show !== void 0) parts.push(`<m:show m:val="${p.show ? 1 : 0}"/>`);
|
|
1807
|
+
if (p.zeroWid) parts.push("<m:zeroWid m:val=\"1\"/>");
|
|
1808
|
+
if (p.zeroAsc) parts.push("<m:zeroAsc m:val=\"1\"/>");
|
|
1809
|
+
if (p.zeroDesc) parts.push("<m:zeroDesc m:val=\"1\"/>");
|
|
1810
|
+
if (p.transp) parts.push("<m:transp m:val=\"1\"/>");
|
|
1811
|
+
if (parts.length) pr = `<m:phantPr>${parts.join("")}</m:phantPr>`;
|
|
1812
|
+
}
|
|
1813
|
+
return `<m:phant>${pr}<m:e>${stringifyChildren(opts.children)}</m:e></m:phant>`;
|
|
1814
|
+
}
|
|
1815
|
+
if ("eqArr" in value) {
|
|
1816
|
+
const opts = value.eqArr;
|
|
1817
|
+
let pr = "";
|
|
1818
|
+
if (opts.properties) {
|
|
1819
|
+
const p = opts.properties;
|
|
1820
|
+
const parts = [];
|
|
1821
|
+
if (p.baseJc) parts.push(`<m:baseJc m:val="${p.baseJc}"/>`);
|
|
1822
|
+
if (p.maxDist) parts.push("<m:maxDist m:val=\"1\"/>");
|
|
1823
|
+
if (p.objDist) parts.push("<m:objDist m:val=\"1\"/>");
|
|
1824
|
+
if (p.rSpRule) parts.push(`<m:rSpRule m:val="${p.rSpRule}"/>`);
|
|
1825
|
+
if (p.rSp) parts.push(`<m:rSp m:val="${p.rSp}"/>`);
|
|
1826
|
+
if (parts.length) pr = `<m:eqArrPr>${parts.join("")}</m:eqArrPr>`;
|
|
1827
|
+
}
|
|
1828
|
+
const rows = opts.rows.map((row) => `<m:e>${stringifyChildren(row)}</m:e>`).join("");
|
|
1829
|
+
return `<m:eqArr>${pr}${rows}</m:eqArr>`;
|
|
1830
|
+
}
|
|
1831
|
+
if ("accent" in value) {
|
|
1832
|
+
const opts = value.accent;
|
|
1833
|
+
return `<m:acc>${opts.accentCharacter ? `<m:accPr><m:chr m:val="${opts.accentCharacter}"/></m:accPr>` : ""}<m:e>${stringifyChildren(opts.children)}</m:e></m:acc>`;
|
|
1834
|
+
}
|
|
1835
|
+
if ("bar" in value) {
|
|
1836
|
+
const opts = value.bar;
|
|
1837
|
+
return `<m:bar><m:barPr><m:pos m:val="${opts.type}"/></m:barPr><m:e>${stringifyChildren(opts.children)}</m:e></m:bar>`;
|
|
1838
|
+
}
|
|
1839
|
+
if ("text" in value) return `<m:r>${value.properties ? mathRunPropsStr(value.properties) : ""}<m:t>${escapeXml(value.text)}</m:t></m:r>`;
|
|
1840
|
+
return "";
|
|
1841
|
+
}
|
|
1842
|
+
function stringifyNAry(opts, chr) {
|
|
1843
|
+
const hasSub = opts.subScript && opts.subScript.length > 0;
|
|
1844
|
+
const hasSup = opts.superScript && opts.superScript.length > 0;
|
|
1845
|
+
const prParts = [`<m:chr m:val="${chr}"/>`];
|
|
1846
|
+
if (!hasSub) prParts.push("<m:subHide m:val=\"1\"/>");
|
|
1847
|
+
if (!hasSup) prParts.push("<m:supHide m:val=\"1\"/>");
|
|
1848
|
+
return `<m:nary>${`<m:naryPr>${prParts.join("")}</m:naryPr>`}${hasSub ? `<m:sub>${stringifyChildren(opts.subScript)}</m:sub>` : "<m:sub/>"}${hasSup ? `<m:sup>${stringifyChildren(opts.superScript)}</m:sup>` : "<m:sup/>"}<m:e>${stringifyChildren(opts.children)}</m:e></m:nary>`;
|
|
1849
|
+
}
|
|
1850
|
+
function stringifyDelimiters(children, begChr, endChr) {
|
|
1851
|
+
return `<m:d><m:dPr><m:begChr m:val="${begChr}"/><m:endChr m:val="${endChr}"/></m:dPr><m:e>${stringifyChildren(children)}</m:e></m:d>`;
|
|
1852
|
+
}
|
|
1853
|
+
function bracketChildren(v) {
|
|
1854
|
+
if (Array.isArray(v)) return v;
|
|
1855
|
+
return v.children;
|
|
1856
|
+
}
|
|
1857
|
+
function stringifyMath(children) {
|
|
1858
|
+
return `<m:oMath>${children.map((c) => stringifyMathInput(c)).join("")}</m:oMath>`;
|
|
1859
|
+
}
|
|
1860
|
+
/**
|
|
1861
|
+
* Parse all math children from an m:oMath (or similar container) element.
|
|
1862
|
+
*/
|
|
1863
|
+
function parseMathChildren(el) {
|
|
1864
|
+
const result = [];
|
|
1865
|
+
for (const child of el.elements ?? []) {
|
|
1866
|
+
const parsed = parseMathElement(child);
|
|
1867
|
+
if (parsed !== void 0) result.push(parsed);
|
|
1868
|
+
}
|
|
1869
|
+
return result;
|
|
1870
|
+
}
|
|
1871
|
+
function parseMathElement(el) {
|
|
1872
|
+
switch (el.name) {
|
|
1873
|
+
case "m:r": return parseMathRun(el);
|
|
1874
|
+
case "m:f": return parseMathFraction(el);
|
|
1875
|
+
case "m:rad": return parseMathRadical(el);
|
|
1876
|
+
case "m:sSup": return parseMathSuperScript(el);
|
|
1877
|
+
case "m:sSub": return parseMathSubScript(el);
|
|
1878
|
+
case "m:sSubSup": return parseMathSubSuperScript(el);
|
|
1879
|
+
case "m:nary": return parseMathNAry(el);
|
|
1880
|
+
case "m:func": return parseMathFunction(el);
|
|
1881
|
+
case "m:d": return parseMathDelimiter(el);
|
|
1882
|
+
case "m:m": return parseMathMatrix(el);
|
|
1883
|
+
case "m:acc": return parseMathAccent(el);
|
|
1884
|
+
case "m:bar": return parseMathBar(el);
|
|
1885
|
+
case "m:borderBox": return { borderBox: { children: parseMathArg(el, "m:e") } };
|
|
1886
|
+
case "m:box": return { box: { children: parseMathArg(el, "m:e") } };
|
|
1887
|
+
case "m:groupChr": return { groupChr: { children: parseMathArg(el, "m:e") } };
|
|
1888
|
+
case "m:phant": return { phant: { children: parseMathArg(el, "m:e") } };
|
|
1889
|
+
case "m:eqArr": return parseMathEqArr(el);
|
|
1890
|
+
case "m:limLow": return parseMathLimitLower(el);
|
|
1891
|
+
case "m:limUpp": return parseMathLimitUpper(el);
|
|
1892
|
+
case "m:rPr":
|
|
1893
|
+
case "m:fPr":
|
|
1894
|
+
case "m:radPr":
|
|
1895
|
+
case "m:sSupPr":
|
|
1896
|
+
case "m:sSubPr":
|
|
1897
|
+
case "m:sSubSupPr":
|
|
1898
|
+
case "m:naryPr":
|
|
1899
|
+
case "m:funcPr":
|
|
1900
|
+
case "m:dPr":
|
|
1901
|
+
case "m:mPr":
|
|
1902
|
+
case "m:accPr":
|
|
1903
|
+
case "m:barPr":
|
|
1904
|
+
case "m:borderBoxPr":
|
|
1905
|
+
case "m:boxPr":
|
|
1906
|
+
case "m:groupChrPr":
|
|
1907
|
+
case "m:phantPr":
|
|
1908
|
+
case "m:eqArrPr":
|
|
1909
|
+
case "m:limLowPr":
|
|
1910
|
+
case "m:limUppPr":
|
|
1911
|
+
case "m:ctrlPr": return;
|
|
1912
|
+
default: return;
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
function parseMathRun(el) {
|
|
1916
|
+
return textOf(findChild(el, "m:t")) ?? "";
|
|
1917
|
+
}
|
|
1918
|
+
function parseMathFraction(el) {
|
|
1919
|
+
return { fraction: {
|
|
1920
|
+
numerator: parseMathArg(el, "m:num"),
|
|
1921
|
+
denominator: parseMathArg(el, "m:den")
|
|
1922
|
+
} };
|
|
1923
|
+
}
|
|
1924
|
+
function parseMathRadical(el) {
|
|
1925
|
+
const degree = parseMathArg(el, "m:deg");
|
|
1926
|
+
return { radical: {
|
|
1927
|
+
children: parseMathArg(el, "m:e"),
|
|
1928
|
+
...degree.length > 0 ? { degree } : {}
|
|
1929
|
+
} };
|
|
1930
|
+
}
|
|
1931
|
+
function parseMathSuperScript(el) {
|
|
1932
|
+
return { superScript: {
|
|
1933
|
+
children: parseMathArg(el, "m:e"),
|
|
1934
|
+
superScript: parseMathArg(el, "m:sup")
|
|
1935
|
+
} };
|
|
1936
|
+
}
|
|
1937
|
+
function parseMathSubScript(el) {
|
|
1938
|
+
return { subScript: {
|
|
1939
|
+
children: parseMathArg(el, "m:e"),
|
|
1940
|
+
subScript: parseMathArg(el, "m:sub")
|
|
1941
|
+
} };
|
|
1942
|
+
}
|
|
1943
|
+
function parseMathSubSuperScript(el) {
|
|
1944
|
+
return { subSuperScript: {
|
|
1945
|
+
children: parseMathArg(el, "m:e"),
|
|
1946
|
+
subScript: parseMathArg(el, "m:sub"),
|
|
1947
|
+
superScript: parseMathArg(el, "m:sup")
|
|
1948
|
+
} };
|
|
1949
|
+
}
|
|
1950
|
+
function parseMathNAry(el) {
|
|
1951
|
+
const naryPr = findChild(el, "m:naryPr");
|
|
1952
|
+
const chrEl = naryPr ? findChild(naryPr, "m:chr") : void 0;
|
|
1953
|
+
const chrVal = chrEl ? attr(chrEl, "m:val") : void 0;
|
|
1954
|
+
const baseChildren = parseMathArg(el, "m:e");
|
|
1955
|
+
const sub = parseMathArg(el, "m:sub");
|
|
1956
|
+
const sup = parseMathArg(el, "m:sup");
|
|
1957
|
+
const common = {
|
|
1958
|
+
children: baseChildren,
|
|
1959
|
+
...sub.length > 0 ? { subScript: sub } : {},
|
|
1960
|
+
...sup.length > 0 ? { superScript: sup } : {}
|
|
1961
|
+
};
|
|
1962
|
+
if (chrVal === "∑") return { sum: common };
|
|
1963
|
+
return { integral: common };
|
|
1964
|
+
}
|
|
1965
|
+
function parseMathFunction(el) {
|
|
1966
|
+
return { function: {
|
|
1967
|
+
name: parseMathArg(el, "m:fName"),
|
|
1968
|
+
children: parseMathArg(el, "m:e")
|
|
1969
|
+
} };
|
|
1970
|
+
}
|
|
1971
|
+
function parseMathDelimiter(el) {
|
|
1972
|
+
const dPr = findChild(el, "m:dPr");
|
|
1973
|
+
const begChrEl = dPr ? findChild(dPr, "m:begChr") : void 0;
|
|
1974
|
+
const begChr = begChrEl ? attr(begChrEl, "m:val") : "(";
|
|
1975
|
+
const mathChildren = parseMathArg(el, "m:e");
|
|
1976
|
+
switch (begChr) {
|
|
1977
|
+
case "[": return { squareBrackets: mathChildren };
|
|
1978
|
+
case "{": return { curlyBrackets: mathChildren };
|
|
1979
|
+
case "<":
|
|
1980
|
+
case "⟨": return { angledBrackets: mathChildren };
|
|
1981
|
+
default: return { roundBrackets: mathChildren };
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
function parseMathMatrix(el) {
|
|
1985
|
+
const rows = [];
|
|
1986
|
+
for (const mr of children(el, "m:mr")) rows.push(parseMathArg(mr, "m:e"));
|
|
1987
|
+
return { matrix: { rows } };
|
|
1988
|
+
}
|
|
1989
|
+
function parseMathAccent(el) {
|
|
1990
|
+
const accPr = findChild(el, "m:accPr");
|
|
1991
|
+
const chrEl = accPr ? findChild(accPr, "m:chr") : void 0;
|
|
1992
|
+
const accentChar = chrEl ? attr(chrEl, "m:val") : void 0;
|
|
1993
|
+
return { accent: {
|
|
1994
|
+
children: parseMathArg(el, "m:e"),
|
|
1995
|
+
...accentChar ? { accentCharacter: accentChar } : {}
|
|
1996
|
+
} };
|
|
1997
|
+
}
|
|
1998
|
+
function parseMathBar(el) {
|
|
1999
|
+
const barPr = findChild(el, "m:barPr");
|
|
2000
|
+
const posEl = barPr ? findChild(barPr, "m:pos") : void 0;
|
|
2001
|
+
const pos = posEl ? attr(posEl, "m:val") : "top";
|
|
2002
|
+
return { bar: {
|
|
2003
|
+
children: parseMathArg(el, "m:e"),
|
|
2004
|
+
type: pos ?? "top"
|
|
2005
|
+
} };
|
|
2006
|
+
}
|
|
2007
|
+
function parseMathEqArr(el) {
|
|
2008
|
+
const rows = [];
|
|
2009
|
+
for (const e of children(el, "m:e")) rows.push(parseMathChildren(e));
|
|
2010
|
+
return { eqArr: { rows } };
|
|
2011
|
+
}
|
|
2012
|
+
function parseMathLimitLower(el) {
|
|
2013
|
+
return { limitLower: {
|
|
2014
|
+
children: parseMathArg(el, "m:e"),
|
|
2015
|
+
limit: parseMathArg(el, "m:lim")
|
|
2016
|
+
} };
|
|
2017
|
+
}
|
|
2018
|
+
function parseMathLimitUpper(el) {
|
|
2019
|
+
return { limitUpper: {
|
|
2020
|
+
children: parseMathArg(el, "m:e"),
|
|
2021
|
+
limit: parseMathArg(el, "m:lim")
|
|
2022
|
+
} };
|
|
2023
|
+
}
|
|
2024
|
+
function parseMathArg(parent, childName) {
|
|
2025
|
+
const container = findChild(parent, childName);
|
|
2026
|
+
if (!container) return [];
|
|
2027
|
+
return parseMathChildren(container);
|
|
2028
|
+
}
|
|
2029
|
+
//#endregion
|
|
2030
|
+
//#region src/parts/paragraph/stringify.ts
|
|
2031
|
+
/**
|
|
2032
|
+
* Direct XML string builders for paragraph and run properties.
|
|
2033
|
+
*
|
|
2034
|
+
* Replaces `buildParagraphProperties() + xml()` and `buildRunProperties() + xml()`
|
|
2035
|
+
* with direct string concatenation — zero intermediate IXmlableObject allocation,
|
|
2036
|
+
* zero recursive xml() traversal. Follows PPTX/XLSX pattern.
|
|
2037
|
+
*
|
|
2038
|
+
* @module
|
|
2039
|
+
*/
|
|
2040
|
+
/** On/off: `<w:name/>` for true, `<w:name w:val="0"/>` for false */
|
|
2041
|
+
function onOff(name, val) {
|
|
2042
|
+
return val ? `<${name}/>` : `<${name} w:val="0"/>`;
|
|
2043
|
+
}
|
|
2044
|
+
/** Build attrs string from key-value pairs, skipping undefined */
|
|
2045
|
+
function attrParts(attrs) {
|
|
2046
|
+
const parts = [];
|
|
2047
|
+
for (const [key, val] of Object.entries(attrs)) if (val !== void 0) parts.push(`${key}="${val}"`);
|
|
2048
|
+
return parts.join(" ");
|
|
2049
|
+
}
|
|
2050
|
+
function borderStr(name, opts) {
|
|
2051
|
+
return `<${name} ${attrParts({
|
|
2052
|
+
"w:val": opts.style,
|
|
2053
|
+
"w:color": opts.color !== void 0 ? hexColorValue(opts.color) : void 0,
|
|
2054
|
+
"w:sz": opts.size !== void 0 ? eighthPointMeasureValue(opts.size) : void 0,
|
|
2055
|
+
"w:space": opts.space !== void 0 ? pointMeasureValue(opts.space) : void 0,
|
|
2056
|
+
"w:themeColor": opts.themeColor,
|
|
2057
|
+
"w:themeTint": opts.themeTint !== void 0 ? uCharHexNumber(opts.themeTint) : void 0,
|
|
2058
|
+
"w:themeShade": opts.themeShade !== void 0 ? uCharHexNumber(opts.themeShade) : void 0,
|
|
2059
|
+
"w:shadow": opts.shadow !== void 0 ? opts.shadow ? 1 : 0 : void 0,
|
|
2060
|
+
"w:frame": opts.frame !== void 0 ? opts.frame ? 1 : 0 : void 0
|
|
2061
|
+
})}/>`;
|
|
2062
|
+
}
|
|
2063
|
+
function shadingStr(opts) {
|
|
2064
|
+
return `<w:shd ${attrParts({
|
|
2065
|
+
"w:val": opts.type ?? "clear",
|
|
2066
|
+
"w:color": opts.color !== void 0 ? hexColorValue(opts.color) : void 0,
|
|
2067
|
+
"w:fill": opts.fill !== void 0 ? hexColorValue(opts.fill) : void 0,
|
|
2068
|
+
"w:themeColor": opts.themeColor,
|
|
2069
|
+
"w:themeTint": opts.themeTint !== void 0 ? uCharHexNumber(opts.themeTint) : void 0,
|
|
2070
|
+
"w:themeShade": opts.themeShade !== void 0 ? uCharHexNumber(opts.themeShade) : void 0,
|
|
2071
|
+
"w:themeFill": opts.themeFill,
|
|
2072
|
+
"w:themeFillTint": opts.themeFillTint !== void 0 ? uCharHexNumber(opts.themeFillTint) : void 0,
|
|
2073
|
+
"w:themeFillShade": opts.themeFillShade !== void 0 ? uCharHexNumber(opts.themeFillShade) : void 0
|
|
2074
|
+
})}/>`;
|
|
2075
|
+
}
|
|
2076
|
+
function spacingStr(opts) {
|
|
2077
|
+
return `<w:spacing ${attrParts({
|
|
2078
|
+
"w:after": opts.after,
|
|
2079
|
+
"w:afterAutospacing": opts.afterAutoSpacing !== void 0 ? opts.afterAutoSpacing ? 1 : 0 : void 0,
|
|
2080
|
+
"w:afterLines": opts.afterLines !== void 0 ? decimalNumber(opts.afterLines) : void 0,
|
|
2081
|
+
"w:before": opts.before,
|
|
2082
|
+
"w:beforeAutospacing": opts.beforeAutoSpacing !== void 0 ? opts.beforeAutoSpacing ? 1 : 0 : void 0,
|
|
2083
|
+
"w:beforeLines": opts.beforeLines !== void 0 ? decimalNumber(opts.beforeLines) : void 0,
|
|
2084
|
+
"w:line": opts.line,
|
|
2085
|
+
"w:lineRule": opts.lineRule
|
|
2086
|
+
})}/>`;
|
|
2087
|
+
}
|
|
2088
|
+
function indentStr(opts) {
|
|
2089
|
+
return `<w:ind ${attrParts({
|
|
2090
|
+
"w:start": opts.start !== void 0 ? signedTwipsMeasureValue(opts.start) : void 0,
|
|
2091
|
+
"w:startChars": opts.startChars !== void 0 ? decimalNumber(opts.startChars) : void 0,
|
|
2092
|
+
"w:end": opts.end !== void 0 ? signedTwipsMeasureValue(opts.end) : void 0,
|
|
2093
|
+
"w:endChars": opts.endChars !== void 0 ? decimalNumber(opts.endChars) : void 0,
|
|
2094
|
+
"w:left": opts.left !== void 0 ? signedTwipsMeasureValue(opts.left) : void 0,
|
|
2095
|
+
"w:leftChars": opts.leftChars !== void 0 ? decimalNumber(opts.leftChars) : void 0,
|
|
2096
|
+
"w:right": opts.right !== void 0 ? signedTwipsMeasureValue(opts.right) : void 0,
|
|
2097
|
+
"w:rightChars": opts.rightChars !== void 0 ? decimalNumber(opts.rightChars) : void 0,
|
|
2098
|
+
"w:hanging": opts.hanging !== void 0 ? twipsMeasureValue(opts.hanging) : void 0,
|
|
2099
|
+
"w:hangingChars": opts.hangingChars !== void 0 ? decimalNumber(opts.hangingChars) : void 0,
|
|
2100
|
+
"w:firstLine": opts.firstLine !== void 0 ? twipsMeasureValue(opts.firstLine) : void 0,
|
|
2101
|
+
"w:firstLineChars": opts.firstLineChars !== void 0 ? decimalNumber(opts.firstLineChars) : void 0
|
|
2102
|
+
})}/>`;
|
|
2103
|
+
}
|
|
2104
|
+
function tabStopsStr(defs) {
|
|
2105
|
+
return `<w:tabs>${defs.map(({ type, position, leader }) => {
|
|
2106
|
+
return `<w:tab ${attrParts({
|
|
2107
|
+
"w:val": type,
|
|
2108
|
+
"w:pos": position,
|
|
2109
|
+
"w:leader": leader
|
|
2110
|
+
})}/>`;
|
|
2111
|
+
}).join("")}</w:tabs>`;
|
|
2112
|
+
}
|
|
2113
|
+
function cnfStyleStr(opts) {
|
|
2114
|
+
return `<w:cnfStyle ${attrParts({
|
|
2115
|
+
"w:firstRow": opts.firstRow ? "1" : "0",
|
|
2116
|
+
"w:lastRow": opts.lastRow ? "1" : "0",
|
|
2117
|
+
"w:firstColumn": opts.firstColumn ? "1" : "0",
|
|
2118
|
+
"w:lastColumn": opts.lastColumn ? "1" : "0",
|
|
2119
|
+
"w:oddVBand": opts.oddVBand ? "1" : "0",
|
|
2120
|
+
"w:evenVBand": opts.evenVBand ? "1" : "0",
|
|
2121
|
+
"w:oddHBand": opts.oddHBand ? "1" : "0",
|
|
2122
|
+
"w:evenHBand": opts.evenHBand ? "1" : "0",
|
|
2123
|
+
"w:firstRowFirstColumn": opts.firstRowFirstColumn ? "1" : "0",
|
|
2124
|
+
"w:firstRowLastColumn": opts.firstRowLastColumn ? "1" : "0",
|
|
2125
|
+
"w:lastRowFirstColumn": opts.lastRowFirstColumn ? "1" : "0",
|
|
2126
|
+
"w:lastRowLastColumn": opts.lastRowLastColumn ? "1" : "0"
|
|
2127
|
+
})}/>`;
|
|
2128
|
+
}
|
|
2129
|
+
function framePrStr(opts) {
|
|
2130
|
+
const alignment = opts.alignment;
|
|
2131
|
+
const position = opts.position;
|
|
2132
|
+
return `<w:framePr ${attrParts({
|
|
2133
|
+
"w:xAlign": alignment?.x,
|
|
2134
|
+
"w:yAlign": alignment?.y,
|
|
2135
|
+
"w:hAnchor": opts.anchor?.horizontal,
|
|
2136
|
+
"w:anchorLock": opts.anchorLock,
|
|
2137
|
+
"w:vAnchor": opts.anchor?.vertical,
|
|
2138
|
+
"w:dropCap": opts.dropCap,
|
|
2139
|
+
"w:h": opts.height,
|
|
2140
|
+
"w:lines": opts.lines,
|
|
2141
|
+
"w:hRule": opts.rule,
|
|
2142
|
+
"w:hSpace": opts.space?.horizontal,
|
|
2143
|
+
"w:vSpace": opts.space?.vertical,
|
|
2144
|
+
"w:w": opts.width,
|
|
2145
|
+
"w:wrap": opts.wrap,
|
|
2146
|
+
"w:x": position?.x,
|
|
2147
|
+
"w:y": position?.y
|
|
2148
|
+
})}/>`;
|
|
2149
|
+
}
|
|
2150
|
+
function numPrStr(numberId, indentLevel, numberingChange) {
|
|
2151
|
+
const idVal = typeof numberId === "string" ? `{${numberId}}` : numberId;
|
|
2152
|
+
const parts = [`<w:ilvl w:val="${Math.min(indentLevel, 9)}"/>`, `<w:numId w:val="${idVal}"/>`];
|
|
2153
|
+
if (numberingChange) {
|
|
2154
|
+
const a = attrParts({
|
|
2155
|
+
"w:original": numberingChange.original,
|
|
2156
|
+
"w:id": numberingChange.id,
|
|
2157
|
+
"w:author": numberingChange.author,
|
|
2158
|
+
"w:date": numberingChange.date
|
|
2159
|
+
});
|
|
2160
|
+
parts.push(`<w:numberingChange ${a}/>`);
|
|
2161
|
+
}
|
|
2162
|
+
return `<w:numPr>${parts.join("")}</w:numPr>`;
|
|
2163
|
+
}
|
|
2164
|
+
function colorStr(colorOrOptions) {
|
|
2165
|
+
if (typeof colorOrOptions === "string") return `<w:color w:val="${hexColorValue(colorOrOptions)}"/>`;
|
|
2166
|
+
const opts = colorOrOptions;
|
|
2167
|
+
return `<w:color ${attrParts({
|
|
2168
|
+
"w:val": opts.val !== void 0 ? hexColorValue(opts.val) : void 0,
|
|
2169
|
+
"w:themeColor": opts.themeColor,
|
|
2170
|
+
"w:themeTint": opts.themeTint !== void 0 ? uCharHexNumber(opts.themeTint) : void 0,
|
|
2171
|
+
"w:themeShade": opts.themeShade !== void 0 ? uCharHexNumber(opts.themeShade) : void 0
|
|
2172
|
+
})}/>`;
|
|
2173
|
+
}
|
|
2174
|
+
function runFontsStr(nameOrAttrs, hint) {
|
|
2175
|
+
if (typeof nameOrAttrs === "string") return `<w:rFonts ${attrParts({
|
|
2176
|
+
"w:ascii": nameOrAttrs,
|
|
2177
|
+
"w:cs": nameOrAttrs,
|
|
2178
|
+
"w:eastAsia": nameOrAttrs,
|
|
2179
|
+
"w:hAnsi": nameOrAttrs,
|
|
2180
|
+
"w:hint": hint
|
|
2181
|
+
})}/>`;
|
|
2182
|
+
const attrs = nameOrAttrs;
|
|
2183
|
+
return `<w:rFonts ${attrParts({
|
|
2184
|
+
"w:ascii": attrs.ascii,
|
|
2185
|
+
"w:asciiTheme": attrs.asciiTheme,
|
|
2186
|
+
"w:cs": attrs.cs,
|
|
2187
|
+
"w:cstheme": attrs.cstheme,
|
|
2188
|
+
"w:eastAsia": attrs.eastAsia,
|
|
2189
|
+
"w:eastAsiaTheme": attrs.eastAsiaTheme,
|
|
2190
|
+
"w:hAnsi": attrs.hAnsi,
|
|
2191
|
+
"w:hAnsiTheme": attrs.hAnsiTheme,
|
|
2192
|
+
"w:hint": attrs.hint
|
|
2193
|
+
})}/>`;
|
|
2194
|
+
}
|
|
2195
|
+
function underlineStr(type, color) {
|
|
2196
|
+
return `<w:u ${attrParts({
|
|
2197
|
+
"w:val": type ?? "single",
|
|
2198
|
+
"w:color": color !== void 0 ? hexColorValue(color) : void 0
|
|
2199
|
+
})}/>`;
|
|
2200
|
+
}
|
|
2201
|
+
function eastAsianLayoutStr(opts) {
|
|
2202
|
+
return `<w:eastAsianLayout ${attrParts({
|
|
2203
|
+
"w:id": opts.id !== void 0 ? decimalNumber(opts.id) : void 0,
|
|
2204
|
+
"w:combine": opts.combine !== void 0 ? opts.combine ? 1 : 0 : void 0,
|
|
2205
|
+
"w:combineBrackets": opts.combineBrackets,
|
|
2206
|
+
"w:vert": opts.vert !== void 0 ? opts.vert ? 1 : 0 : void 0,
|
|
2207
|
+
"w:vertCompress": opts.vertCompress !== void 0 ? opts.vertCompress ? 1 : 0 : void 0
|
|
2208
|
+
})}/>`;
|
|
2209
|
+
}
|
|
2210
|
+
function languageStr(opts) {
|
|
2211
|
+
return `<w:lang ${attrParts({
|
|
2212
|
+
"w:val": opts.value,
|
|
2213
|
+
"w:eastAsia": opts.eastAsia,
|
|
2214
|
+
"w:bidi": opts.bidirectional
|
|
2215
|
+
})}/>`;
|
|
2216
|
+
}
|
|
2217
|
+
/**
|
|
2218
|
+
* Build `<w:pPr>` XML string directly from options — zero IXmlableObject allocation.
|
|
2219
|
+
*
|
|
2220
|
+
* Replaces `buildParagraphProperties() + xml()` with a single-pass string builder.
|
|
2221
|
+
*/
|
|
2222
|
+
function stringifyParagraphProperties(options) {
|
|
2223
|
+
const numberingReferences = [];
|
|
2224
|
+
if (!options) return {
|
|
2225
|
+
xml: void 0,
|
|
2226
|
+
numberingReferences
|
|
2227
|
+
};
|
|
2228
|
+
const parts = [];
|
|
2229
|
+
if (options.heading) parts.push(`<w:pStyle w:val="${escapeXml(options.heading)}"/>`);
|
|
2230
|
+
if (options.bullet) parts.push("<w:pStyle w:val=\"ListParagraph\"/>");
|
|
2231
|
+
if (options.numbering) {
|
|
2232
|
+
if (!options.style && !options.heading) {
|
|
2233
|
+
if (!options.numbering.custom) parts.push("<w:pStyle w:val=\"ListParagraph\"/>");
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
if (options.style) parts.push(`<w:pStyle w:val="${escapeXml(options.style)}"/>`);
|
|
2237
|
+
if (options.keepNext !== void 0) parts.push(onOff("w:keepNext", options.keepNext));
|
|
2238
|
+
if (options.keepLines !== void 0) parts.push(onOff("w:keepLines", options.keepLines));
|
|
2239
|
+
if (options.pageBreakBefore) parts.push("<w:pageBreakBefore/>");
|
|
2240
|
+
if (options.frame) parts.push(framePrStr(options.frame));
|
|
2241
|
+
if (options.widowControl !== void 0) parts.push(onOff("w:widowControl", options.widowControl));
|
|
2242
|
+
if (options.bullet) parts.push(`<w:numPr><w:ilvl w:val="${Math.min(options.bullet.level, 9)}"/><w:numId w:val="1"/></w:numPr>`);
|
|
2243
|
+
if (options.numbering) {
|
|
2244
|
+
numberingReferences.push({
|
|
2245
|
+
instance: options.numbering.instance ?? 0,
|
|
2246
|
+
reference: options.numbering.reference
|
|
2247
|
+
});
|
|
2248
|
+
const numId = `${options.numbering.reference}-${options.numbering.instance ?? 0}`;
|
|
2249
|
+
parts.push(numPrStr(numId, options.numbering.level, options.numbering.numberingChange));
|
|
2250
|
+
} else if (options.numbering === false) parts.push(numPrStr(0, 0));
|
|
2251
|
+
if (options.border) {
|
|
2252
|
+
const bParts = [];
|
|
2253
|
+
if (options.border.top) bParts.push(borderStr("w:top", options.border.top));
|
|
2254
|
+
if (options.border.left) bParts.push(borderStr("w:left", options.border.left));
|
|
2255
|
+
if (options.border.bottom) bParts.push(borderStr("w:bottom", options.border.bottom));
|
|
2256
|
+
if (options.border.right) bParts.push(borderStr("w:right", options.border.right));
|
|
2257
|
+
if (options.border.between) bParts.push(borderStr("w:between", options.border.between));
|
|
2258
|
+
if (options.border.bar) bParts.push(borderStr("w:bar", options.border.bar));
|
|
2259
|
+
if (bParts.length) parts.push(`<w:pBdr>${bParts.join("")}</w:pBdr>`);
|
|
2260
|
+
}
|
|
2261
|
+
if (options.thematicBreak) parts.push(`<w:pBdr>${borderStr("w:bottom", {
|
|
2262
|
+
color: "auto",
|
|
2263
|
+
size: 6,
|
|
2264
|
+
space: 1,
|
|
2265
|
+
style: BorderStyle.SINGLE
|
|
2266
|
+
})}</w:pBdr>`);
|
|
2267
|
+
if (options.shading) parts.push(shadingStr(options.shading));
|
|
2268
|
+
if (options.wordWrap) parts.push("<w:wordWrap w:val=\"0\"/>");
|
|
2269
|
+
if (options.overflowPunctuation) parts.push(onOff("w:overflowPunct", options.overflowPunctuation));
|
|
2270
|
+
const tabDefs = [
|
|
2271
|
+
...options.rightTabStop !== void 0 ? [{
|
|
2272
|
+
position: options.rightTabStop,
|
|
2273
|
+
type: "right"
|
|
2274
|
+
}] : [],
|
|
2275
|
+
...options.tabStops ? options.tabStops : [],
|
|
2276
|
+
...options.leftTabStop !== void 0 ? [{
|
|
2277
|
+
position: options.leftTabStop,
|
|
2278
|
+
type: "left"
|
|
2279
|
+
}] : []
|
|
2280
|
+
];
|
|
2281
|
+
if (tabDefs.length > 0) parts.push(tabStopsStr(tabDefs));
|
|
2282
|
+
if (options.bidirectional !== void 0) parts.push(onOff("w:bidi", options.bidirectional));
|
|
2283
|
+
if (options.spacing) parts.push(spacingStr(options.spacing));
|
|
2284
|
+
if (options.indent) parts.push(indentStr(options.indent));
|
|
2285
|
+
if (options.contextualSpacing !== void 0) parts.push(onOff("w:contextualSpacing", options.contextualSpacing));
|
|
2286
|
+
if (options.alignment) parts.push(`<w:jc w:val="${options.alignment}"/>`);
|
|
2287
|
+
if (options.outlineLevel !== void 0) parts.push(`<w:outlineLvl w:val="${options.outlineLevel}"/>`);
|
|
2288
|
+
if (options.divId !== void 0) parts.push(`<w:divId w:val="${options.divId}"/>`);
|
|
2289
|
+
if (options.cnfStyle) parts.push(cnfStyleStr(options.cnfStyle));
|
|
2290
|
+
if (options.suppressLineNumbers !== void 0) parts.push(onOff("w:suppressLineNumbers", options.suppressLineNumbers));
|
|
2291
|
+
if (options.autoSpaceEastAsianText !== void 0) parts.push(onOff("w:autoSpaceDN", options.autoSpaceEastAsianText));
|
|
2292
|
+
if (options.suppressAutoHyphens !== void 0) parts.push(onOff("w:suppressAutoHyphens", options.suppressAutoHyphens));
|
|
2293
|
+
if (options.adjustRightInd !== void 0) parts.push(onOff("w:adjustRightInd", options.adjustRightInd));
|
|
2294
|
+
if (options.snapToGrid !== void 0) parts.push(onOff("w:snapToGrid", options.snapToGrid));
|
|
2295
|
+
if (options.mirrorIndents !== void 0) parts.push(onOff("w:mirrorIndents", options.mirrorIndents));
|
|
2296
|
+
if (options.kinsoku !== void 0) parts.push(onOff("w:kinsoku", options.kinsoku));
|
|
2297
|
+
if (options.topLinePunct !== void 0) parts.push(onOff("w:topLinePunct", options.topLinePunct));
|
|
2298
|
+
if (options.autoSpaceDE !== void 0) parts.push(onOff("w:autoSpaceDE", options.autoSpaceDE));
|
|
2299
|
+
if (options.textAlignment !== void 0) parts.push(`<w:textAlignment w:val="${options.textAlignment}"/>`);
|
|
2300
|
+
if (options.textboxTightWrap !== void 0) parts.push(`<w:textboxTightWrap w:val="${options.textboxTightWrap}"/>`);
|
|
2301
|
+
if (options.textDirection !== void 0) parts.push(`<w:textDirection w:val="${options.textDirection}"/>`);
|
|
2302
|
+
if (options.suppressOverlap !== void 0) parts.push(onOff("w:suppressOverlap", options.suppressOverlap));
|
|
2303
|
+
if (options.run) {
|
|
2304
|
+
const inner = stringifyRunPropertiesInner(options.run);
|
|
2305
|
+
if (inner !== void 0) {
|
|
2306
|
+
const extra = [];
|
|
2307
|
+
const runOpts = options.run;
|
|
2308
|
+
if (runOpts.insertion) {
|
|
2309
|
+
const { id, author, date } = runOpts.insertion;
|
|
2310
|
+
extra.push(`<w:ins w:id="${id}" w:author="${escapeXml(author)}" w:date="${date}"/>`);
|
|
2311
|
+
}
|
|
2312
|
+
if (runOpts.deletion) {
|
|
2313
|
+
const { id, author, date } = runOpts.deletion;
|
|
2314
|
+
extra.push(`<w:del w:id="${id}" w:author="${escapeXml(author)}" w:date="${date}"/>`);
|
|
2315
|
+
}
|
|
2316
|
+
const body = inner + extra.join("");
|
|
2317
|
+
parts.push(`<w:rPr>${body}</w:rPr>`);
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
if (options.revision) {
|
|
2321
|
+
const rev = options.revision;
|
|
2322
|
+
const { author: _a, date: _d, id: _i, ...originalProps } = rev;
|
|
2323
|
+
const inner = stringifyParagraphProperties({
|
|
2324
|
+
...originalProps,
|
|
2325
|
+
includeIfEmpty: true
|
|
2326
|
+
});
|
|
2327
|
+
parts.push(`<w:pPrChange w:author="${escapeXml(rev.author)}" w:date="${rev.date}" w:id="${rev.id}">${inner.xml ?? "<w:pPr/>"}</w:pPrChange>`);
|
|
2328
|
+
}
|
|
2329
|
+
const body = parts.join("");
|
|
2330
|
+
return {
|
|
2331
|
+
xml: options.includeIfEmpty || body.length > 0 ? `<w:pPr>${body}</w:pPr>` : void 0,
|
|
2332
|
+
numberingReferences
|
|
2333
|
+
};
|
|
2334
|
+
}
|
|
2335
|
+
/**
|
|
2336
|
+
* Build the inner content of `<w:rPr>` as a string.
|
|
2337
|
+
* Returns undefined if no properties are set.
|
|
2338
|
+
*/
|
|
2339
|
+
function stringifyRunPropertiesInner(opts) {
|
|
2340
|
+
if (!opts) return void 0;
|
|
2341
|
+
const parts = [];
|
|
2342
|
+
if (opts.style) parts.push(`<w:rStyle w:val="${escapeXml(opts.style)}"/>`);
|
|
2343
|
+
if (opts.font) if (typeof opts.font === "string") parts.push(runFontsStr(opts.font));
|
|
2344
|
+
else if ("name" in opts.font) parts.push(runFontsStr(opts.font.name, opts.font.hint));
|
|
2345
|
+
else parts.push(runFontsStr(opts.font));
|
|
2346
|
+
if (opts.bold !== void 0) parts.push(onOff("w:b", opts.bold));
|
|
2347
|
+
if ((opts.boldComplexScript === void 0 && opts.bold !== void 0 || opts.boldComplexScript) !== void 0) parts.push(onOff("w:bCs", opts.boldComplexScript ?? opts.bold));
|
|
2348
|
+
if (opts.italic !== void 0) parts.push(onOff("w:i", opts.italic));
|
|
2349
|
+
if ((opts.italicComplexScript === void 0 && opts.italic !== void 0 || opts.italicComplexScript) !== void 0) parts.push(onOff("w:iCs", opts.italicComplexScript ?? opts.italic));
|
|
2350
|
+
if (opts.smallCaps !== void 0) parts.push(onOff("w:smallCaps", opts.smallCaps));
|
|
2351
|
+
else if (opts.allCaps !== void 0) parts.push(onOff("w:caps", opts.allCaps));
|
|
2352
|
+
if (opts.strike !== void 0) parts.push(onOff("w:strike", opts.strike));
|
|
2353
|
+
if (opts.doubleStrike !== void 0) parts.push(onOff("w:dstrike", opts.doubleStrike));
|
|
2354
|
+
if (opts.emboss !== void 0) parts.push(onOff("w:emboss", opts.emboss));
|
|
2355
|
+
if (opts.imprint !== void 0) parts.push(onOff("w:imprint", opts.imprint));
|
|
2356
|
+
if (opts.outline !== void 0) parts.push(onOff("w:outline", opts.outline));
|
|
2357
|
+
if (opts.shadow !== void 0) parts.push(onOff("w:shadow", opts.shadow));
|
|
2358
|
+
if (opts.webHidden !== void 0) parts.push(onOff("w:webHidden", opts.webHidden));
|
|
2359
|
+
if (opts.noProof !== void 0) parts.push(onOff("w:noProof", opts.noProof));
|
|
2360
|
+
if (opts.snapToGrid !== void 0) parts.push(onOff("w:snapToGrid", opts.snapToGrid));
|
|
2361
|
+
if (opts.vanish) parts.push(onOff("w:vanish", opts.vanish));
|
|
2362
|
+
if (opts.color) parts.push(colorStr(opts.color));
|
|
2363
|
+
if (opts.characterSpacing) parts.push(`<w:spacing w:val="${signedTwipsMeasureValue(opts.characterSpacing)}"/>`);
|
|
2364
|
+
if (opts.scale !== void 0) parts.push(`<w:w w:val="${opts.scale}"/>`);
|
|
2365
|
+
if (opts.kern) parts.push(`<w:kern w:val="${hpsMeasureValue(opts.kern)}"/>`);
|
|
2366
|
+
if (opts.position) parts.push(`<w:position w:val="${opts.position}"/>`);
|
|
2367
|
+
if (opts.size !== void 0) parts.push(`<w:sz w:val="${hpsMeasureValue(opts.size * 2)}"/>`);
|
|
2368
|
+
const szCs = opts.sizeComplexScript === void 0 || opts.sizeComplexScript === true ? opts.size : opts.sizeComplexScript;
|
|
2369
|
+
if (szCs) parts.push(`<w:szCs w:val="${hpsMeasureValue(szCs * 2)}"/>`);
|
|
2370
|
+
if (opts.highlight) parts.push(`<w:highlight w:val="${opts.highlight}"/>`);
|
|
2371
|
+
if (opts.highlightComplexScript === true) {
|
|
2372
|
+
if (opts.highlight) parts.push(`<w:highlightCs w:val="${opts.highlight}"/>`);
|
|
2373
|
+
} else if (opts.highlightComplexScript !== void 0 && opts.highlightComplexScript !== false) parts.push(`<w:highlightCs w:val="${opts.highlightComplexScript}"/>`);
|
|
2374
|
+
if (opts.underline) parts.push(underlineStr(opts.underline.type, opts.underline.color));
|
|
2375
|
+
if (opts.effect) parts.push(`<w:effect w:val="${opts.effect}"/>`);
|
|
2376
|
+
if (opts.border) parts.push(borderStr("w:bdr", opts.border));
|
|
2377
|
+
if (opts.shading) parts.push(shadingStr(opts.shading));
|
|
2378
|
+
if (opts.subScript) parts.push("<w:vertAlign w:val=\"subscript\"/>");
|
|
2379
|
+
if (opts.superScript) parts.push("<w:vertAlign w:val=\"superscript\"/>");
|
|
2380
|
+
if (opts.rightToLeft !== void 0) parts.push(onOff("w:rtl", opts.rightToLeft));
|
|
2381
|
+
if (opts.emphasisMark) parts.push(`<w:em w:val="${opts.emphasisMark.type ?? "dot"}"/>`);
|
|
2382
|
+
if (opts.language) parts.push(languageStr(opts.language));
|
|
2383
|
+
if (opts.specVanish) parts.push("<w:specVanish/>");
|
|
2384
|
+
if (opts.math) parts.push(onOff("w:oMath", opts.math));
|
|
2385
|
+
if (opts.fitText !== void 0) parts.push(`<w:fitText w:val="${opts.fitText}"/>`);
|
|
2386
|
+
if (opts.complexScript !== void 0) parts.push(onOff("w:cs", opts.complexScript));
|
|
2387
|
+
if (opts.eastAsianLayout) parts.push(eastAsianLayoutStr(opts.eastAsianLayout));
|
|
2388
|
+
if (opts.contentPartRId) parts.push(`<w:contentPart r:id="${opts.contentPartRId}"/>`);
|
|
2389
|
+
if (opts.revision) {
|
|
2390
|
+
const rev = opts.revision;
|
|
2391
|
+
const { author: _a, date: _d, id: _i, ...originalProps } = rev;
|
|
2392
|
+
const inner = stringifyRunPropertiesInner(originalProps);
|
|
2393
|
+
parts.push(`<w:rPrChange w:author="${escapeXml(rev.author)}" w:date="${rev.date}" w:id="${rev.id}"><w:rPr>${inner ?? ""}</w:rPr></w:rPrChange>`);
|
|
2394
|
+
}
|
|
2395
|
+
return parts.length > 0 ? parts.join("") : void 0;
|
|
2396
|
+
}
|
|
2397
|
+
/**
|
|
2398
|
+
* Build `<w:rPr>` XML string directly from options — zero IXmlableObject allocation.
|
|
2399
|
+
*
|
|
2400
|
+
* Replaces `buildRunProperties() + xml()` with a single-pass string builder.
|
|
2401
|
+
*/
|
|
2402
|
+
function stringifyRunProperties(opts) {
|
|
2403
|
+
const inner = stringifyRunPropertiesInner(opts);
|
|
2404
|
+
return inner ? `<w:rPr>${inner}</w:rPr>` : void 0;
|
|
2405
|
+
}
|
|
2406
|
+
//#endregion
|
|
2407
|
+
//#region src/parts/inline.ts
|
|
2408
|
+
/**
|
|
2409
|
+
* Shared inline run/paragraph stringification for DOCX descriptors.
|
|
2410
|
+
*
|
|
2411
|
+
* Used by table.ts, comments.ts, body.ts, and other descriptors that need to
|
|
2412
|
+
* serialize paragraph/run content. Includes JSON child dispatch for all
|
|
2413
|
+
* IParagraphJsonChild variants (image, chart, hyperlink, etc.).
|
|
2414
|
+
*
|
|
2415
|
+
* Pure string concatenation — zero IXmlableObject, zero BaseXmlComponent.
|
|
2416
|
+
*
|
|
2417
|
+
* @module
|
|
2418
|
+
*/
|
|
2419
|
+
function stringifyRunInline(opts, ctx) {
|
|
2420
|
+
const parts = [];
|
|
2421
|
+
const rPr = stringifyRunProperties(opts);
|
|
2422
|
+
if (rPr) parts.push(rPr);
|
|
2423
|
+
if (opts.break) for (let i = 0; i < opts.break; i++) parts.push("<w:br/>");
|
|
2424
|
+
if (opts.children) for (const child of opts.children) if (typeof child === "string") parts.push(`<w:t xml:space="preserve">${escapeXml(child)}</w:t>`);
|
|
2425
|
+
else {
|
|
2426
|
+
const jsonResult = stringifyJsonChild(child, ctx);
|
|
2427
|
+
if (jsonResult !== void 0) if (Array.isArray(jsonResult)) parts.push(...jsonResult);
|
|
2428
|
+
else parts.push(jsonResult);
|
|
2429
|
+
else if ("text" in child || "children" in child || "break" in child) parts.push(stringifyRunInline(child, ctx));
|
|
2430
|
+
}
|
|
2431
|
+
else if (opts.text !== void 0) parts.push(`<w:t xml:space="preserve">${escapeXml(String(opts.text))}</w:t>`);
|
|
2432
|
+
const rsidAttrs = [];
|
|
2433
|
+
if (opts.rsidRPr) rsidAttrs.push(` w:rsidRPr="${opts.rsidRPr}"`);
|
|
2434
|
+
if (opts.rsidDel) rsidAttrs.push(` w:rsidDel="${opts.rsidDel}"`);
|
|
2435
|
+
const attr = rsidAttrs.join("");
|
|
2436
|
+
const body = parts.join("");
|
|
2437
|
+
return body.length === 0 ? attr ? `<w:r${attr}/>` : "<w:r/>" : `<w:r${attr}>${body}</w:r>`;
|
|
2438
|
+
}
|
|
2439
|
+
function createImageData(data, transformation, key, srcRect) {
|
|
2440
|
+
return {
|
|
2441
|
+
data,
|
|
2442
|
+
fileName: key,
|
|
2443
|
+
srcRect,
|
|
2444
|
+
transformation: createTransformation(transformation)
|
|
2445
|
+
};
|
|
2446
|
+
}
|
|
2447
|
+
let nextChartId = 1;
|
|
2448
|
+
function stringifyJsonChild(child, ctx) {
|
|
2449
|
+
if ("pageBreak" in child) return "<w:r><w:br w:type=\"page\"/></w:r>";
|
|
2450
|
+
if ("columnBreak" in child) return "<w:r><w:br w:type=\"column\"/></w:r>";
|
|
2451
|
+
if ("tab" in child) return "<w:r><w:tab/></w:r>";
|
|
2452
|
+
if ("footnoteReference" in child) return `<w:r><w:rPr><w:rStyle w:val="FootnoteReference"/></w:rPr><w:footnoteReference w:id="${child.footnoteReference}"/></w:r>`;
|
|
2453
|
+
if ("endnoteReference" in child) return `<w:r><w:rPr><w:rStyle w:val="EndnoteReference"/></w:rPr><w:endnoteReference w:id="${child.endnoteReference}"/></w:r>`;
|
|
2454
|
+
if ("commentRangeStart" in child) return `<w:commentRangeStart w:id="${child.commentRangeStart}"/>`;
|
|
2455
|
+
if ("commentRangeEnd" in child) return `<w:commentRangeEnd w:id="${child.commentRangeEnd}"/>`;
|
|
2456
|
+
if ("commentReference" in child) return `<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="${child.commentReference}"/></w:r>`;
|
|
2457
|
+
if ("bookmarkStart" in child) return `<w:bookmarkStart w:id="${child.bookmarkStart.id}" w:name="${child.bookmarkStart.name}"/>`;
|
|
2458
|
+
if ("bookmarkEnd" in child) return `<w:bookmarkEnd w:id="${child.bookmarkEnd}"/>`;
|
|
2459
|
+
if ("symbolRun" in child) {
|
|
2460
|
+
const opts = child.symbolRun;
|
|
2461
|
+
return stringifyRunInline({
|
|
2462
|
+
...opts,
|
|
2463
|
+
children: [`<w:sym w:char="${opts.char}" w:font="${opts.symbolfont ?? "Wingdings"}"/>`]
|
|
2464
|
+
}, ctx);
|
|
2465
|
+
}
|
|
2466
|
+
if ("image" in child) {
|
|
2467
|
+
const opts = child.image;
|
|
2468
|
+
const key = `${uniqueId()}.${opts.type}`;
|
|
2469
|
+
const rawData = toUint8Array(opts.data);
|
|
2470
|
+
let mediaData;
|
|
2471
|
+
if (opts.type === "svg") {
|
|
2472
|
+
const fallbackData = toUint8Array(opts.fallback.data);
|
|
2473
|
+
mediaData = {
|
|
2474
|
+
type: "svg",
|
|
2475
|
+
...createImageData(rawData, opts.transformation, key, opts.srcRect),
|
|
2476
|
+
fallback: {
|
|
2477
|
+
type: opts.fallback.type,
|
|
2478
|
+
...createImageData(fallbackData, opts.transformation, `${uniqueId()}.${opts.fallback.type}`)
|
|
2479
|
+
}
|
|
2480
|
+
};
|
|
2481
|
+
} else mediaData = {
|
|
2482
|
+
type: opts.type,
|
|
2483
|
+
...createImageData(rawData, opts.transformation, key, opts.srcRect)
|
|
2484
|
+
};
|
|
2485
|
+
ctx.file.media.addImage(mediaData.fileName, mediaData);
|
|
2486
|
+
if (mediaData.type === "svg") ctx.file.media.addImage(mediaData.fallback.fileName, mediaData.fallback);
|
|
2487
|
+
return `<w:r>${drawingDesc.stringify({
|
|
2488
|
+
mediaData,
|
|
2489
|
+
docProperties: opts.altText,
|
|
2490
|
+
floating: opts.floating
|
|
2491
|
+
}, ctx)}</w:r>`;
|
|
2492
|
+
}
|
|
2493
|
+
if ("chart" in child) {
|
|
2494
|
+
const opts = child.chart;
|
|
2495
|
+
const chartKey = `chart_${nextChartId++}`;
|
|
2496
|
+
const mediaData = {
|
|
2497
|
+
chartKey,
|
|
2498
|
+
transformation: createTransformation(opts.transformation),
|
|
2499
|
+
type: "chart"
|
|
2500
|
+
};
|
|
2501
|
+
const chartXml = chartSpaceDesc.stringify({
|
|
2502
|
+
categories: opts.categories,
|
|
2503
|
+
series: opts.series,
|
|
2504
|
+
showLegend: opts.showLegend,
|
|
2505
|
+
style: opts.style,
|
|
2506
|
+
title: opts.title,
|
|
2507
|
+
type: opts.type,
|
|
2508
|
+
threeD: opts.threeD
|
|
2509
|
+
}, ctx.file);
|
|
2510
|
+
ctx.file.charts.addChart(chartKey, {
|
|
2511
|
+
key: chartKey,
|
|
2512
|
+
chartSpaceXml: chartXml ?? ""
|
|
2513
|
+
});
|
|
2514
|
+
return `<w:r>${drawingDesc.stringify({
|
|
2515
|
+
mediaData,
|
|
2516
|
+
docProperties: opts.altText,
|
|
2517
|
+
floating: opts.floating
|
|
2518
|
+
}, ctx)}</w:r>`;
|
|
2519
|
+
}
|
|
2520
|
+
if ("smartArt" in child) {
|
|
2521
|
+
const opts = child.smartArt;
|
|
2522
|
+
const smartArtKey = `smartart_${hashSmartArtData(opts)}`;
|
|
2523
|
+
const mediaData = {
|
|
2524
|
+
smartArtKey,
|
|
2525
|
+
transformation: createTransformation(opts.transformation),
|
|
2526
|
+
type: "smartart"
|
|
2527
|
+
};
|
|
2528
|
+
const layoutId = opts.layout ?? "default";
|
|
2529
|
+
const styleId = opts.style ?? "simple1";
|
|
2530
|
+
const colorId = opts.color ?? "accent1_2";
|
|
2531
|
+
const dataModelXml = createDataModel(opts.data.nodes, layoutId, styleId, colorId);
|
|
2532
|
+
ctx.file.smartArts.addSmartArt(smartArtKey, {
|
|
2533
|
+
dataModelXml,
|
|
2534
|
+
key: smartArtKey,
|
|
2535
|
+
layout: layoutId,
|
|
2536
|
+
style: styleId,
|
|
2537
|
+
color: colorId
|
|
2538
|
+
});
|
|
2539
|
+
return `<w:r>${drawingDesc.stringify({
|
|
2540
|
+
mediaData,
|
|
2541
|
+
docProperties: opts.altText,
|
|
2542
|
+
floating: opts.floating
|
|
2543
|
+
}, ctx)}</w:r>`;
|
|
2544
|
+
}
|
|
2545
|
+
if ("wpsShape" in child) {
|
|
2546
|
+
const opts = child.wpsShape;
|
|
2547
|
+
const mediaData = {
|
|
2548
|
+
data: opts,
|
|
2549
|
+
transformation: createTransformation(opts.transformation),
|
|
2550
|
+
type: "wps"
|
|
2551
|
+
};
|
|
2552
|
+
return `<w:r>${drawingDesc.stringify({
|
|
2553
|
+
mediaData,
|
|
2554
|
+
docProperties: opts.altText,
|
|
2555
|
+
floating: opts.floating,
|
|
2556
|
+
outline: opts.outline,
|
|
2557
|
+
fill: opts.fill
|
|
2558
|
+
}, ctx)}</w:r>`;
|
|
2559
|
+
}
|
|
2560
|
+
if ("ruby" in child && typeof child.ruby === "object" && child.ruby !== null) {
|
|
2561
|
+
const r = child.ruby;
|
|
2562
|
+
const align = r.alignment ?? "center";
|
|
2563
|
+
const hps = (r.fontSize ?? 10) * 2;
|
|
2564
|
+
const hpsRaise = (r.raise ?? 10) * 2;
|
|
2565
|
+
const hpsBaseText = (r.baseFontSize ?? 20) * 2;
|
|
2566
|
+
const lid = r.languageId ?? "ja-JP";
|
|
2567
|
+
const prParts = [
|
|
2568
|
+
`<w:rubyAlign w:val="${align}"/>`,
|
|
2569
|
+
`<w:hps w:val="${hps}"/>`,
|
|
2570
|
+
`<w:hpsRaise w:val="${hpsRaise}"/>`,
|
|
2571
|
+
`<w:hpsBaseText w:val="${hpsBaseText}"/>`,
|
|
2572
|
+
`<w:lid w:val="${lid}"/>`
|
|
2573
|
+
];
|
|
2574
|
+
if (r.dirty) prParts.push("<w:dirty/>");
|
|
2575
|
+
const rt = `<w:rt><w:r><w:t xml:space="preserve">${escapeXml(r.text)}</w:t></w:r></w:rt>`;
|
|
2576
|
+
const rubyBase = `<w:rubyBase><w:r><w:t xml:space="preserve">${escapeXml(r.base)}</w:t></w:r></w:rubyBase>`;
|
|
2577
|
+
return `<w:ruby><w:rubyPr>${prParts.join("")}</w:rubyPr>${rt}${rubyBase}</w:ruby>`;
|
|
2578
|
+
}
|
|
2579
|
+
if ("math" in child && typeof child.math === "object" && child.math !== null) return stringifyMath(child.math.children ?? []);
|
|
2580
|
+
if ("insertion" in child) {
|
|
2581
|
+
const { id, author, date, ...runOpts } = child.insertion;
|
|
2582
|
+
const runXml = stringifyRunInline(runOpts, ctx);
|
|
2583
|
+
return `<w:ins w:id="${id}" w:author="${escapeXml(String(author))}" w:date="${date}">${runXml}</w:ins>`;
|
|
2584
|
+
}
|
|
2585
|
+
if ("deletion" in child) {
|
|
2586
|
+
const { id, author, date, ...runOpts } = child.deletion;
|
|
2587
|
+
const parts = [];
|
|
2588
|
+
const rPr = stringifyRunProperties(runOpts);
|
|
2589
|
+
if (rPr) parts.push(rPr);
|
|
2590
|
+
if (runOpts.break) for (let i = 0; i < runOpts.break; i++) parts.push("<w:br/>");
|
|
2591
|
+
if (runOpts.children) {
|
|
2592
|
+
for (const c of runOpts.children) if (typeof c === "string") {
|
|
2593
|
+
const instrText = {
|
|
2594
|
+
CURRENT: "PAGE",
|
|
2595
|
+
TOTAL_PAGES: "NUMPAGES",
|
|
2596
|
+
TOTAL_PAGES_IN_SECTION: "SECTIONPAGES"
|
|
2597
|
+
}[c];
|
|
2598
|
+
if (instrText) parts.push(`<w:fldChar w:fldCharType="begin"/><w:delInstrText xml:space="preserve">${instrText}</w:delInstrText><w:fldChar w:fldCharType="separate"/><w:fldChar w:fldCharType="end"/>`);
|
|
2599
|
+
else parts.push(`<w:delText xml:space="preserve">${escapeXml(c)}</w:delText>`);
|
|
2600
|
+
}
|
|
2601
|
+
} else if (runOpts.text) parts.push(`<w:delText xml:space="preserve">${escapeXml(String(runOpts.text))}</w:delText>`);
|
|
2602
|
+
const runBody = parts.join("");
|
|
2603
|
+
return `<w:del w:id="${id}" w:author="${escapeXml(String(author))}" w:date="${date}"><w:r>${runBody}</w:r></w:del>`;
|
|
2604
|
+
}
|
|
2605
|
+
if ("hyperlink" in child) {
|
|
2606
|
+
const hl = child.hyperlink;
|
|
2607
|
+
const childParts = [];
|
|
2608
|
+
if (hl.children) for (const rc of hl.children) if (typeof rc === "string") childParts.push(stringifyRunInline({ text: rc }, ctx));
|
|
2609
|
+
else childParts.push(stringifyRunInline(rc, ctx));
|
|
2610
|
+
const body = childParts.join("");
|
|
2611
|
+
if (hl.link) {
|
|
2612
|
+
const linkId = uniqueId();
|
|
2613
|
+
ctx.viewWrapper.relationships.addRelationship(linkId, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", hl.link, TargetModeType.EXTERNAL);
|
|
2614
|
+
const attrs = [`r:id="rId${linkId}"`, "w:history=\"1\""];
|
|
2615
|
+
if (hl.tooltip) attrs.push(`w:tooltip="${escapeXml(hl.tooltip)}"`);
|
|
2616
|
+
return `<w:hyperlink ${attrs.join(" ")}>${body}</w:hyperlink>`;
|
|
2617
|
+
}
|
|
2618
|
+
if (hl.anchor) {
|
|
2619
|
+
const attrs = [`w:anchor="${escapeXml(hl.anchor)}"`, "w:history=\"1\""];
|
|
2620
|
+
if (hl.tooltip) attrs.push(`w:tooltip="${escapeXml(hl.tooltip)}"`);
|
|
2621
|
+
return `<w:hyperlink ${attrs.join(" ")}>${body}</w:hyperlink>`;
|
|
2622
|
+
}
|
|
2623
|
+
return "";
|
|
2624
|
+
}
|
|
2625
|
+
if ("proofErr" in child) return `<w:proofErr w:type="${child.proofErr}"/>`;
|
|
2626
|
+
if ("positionalTab" in child) {
|
|
2627
|
+
const pt = child.positionalTab;
|
|
2628
|
+
return `<w:ptab w:alignment="${pt.alignment}" w:leader="${pt.leader}" w:relativeTo="${pt.relativeTo}"/>`;
|
|
2629
|
+
}
|
|
2630
|
+
if ("permStart" in child) {
|
|
2631
|
+
const ps = child.permStart;
|
|
2632
|
+
const a = [`w:id="${ps.id}"`];
|
|
2633
|
+
if (ps.ed !== void 0) a.push(`w:ed="${escapeXml(String(ps.ed))}"`);
|
|
2634
|
+
if (ps.editGroup !== void 0) a.push(`w:edGrp="${ps.editGroup}"`);
|
|
2635
|
+
if (ps.colFirst !== void 0) a.push(`w:colFirst="${ps.colFirst}"`);
|
|
2636
|
+
if (ps.colLast !== void 0) a.push(`w:colLast="${ps.colLast}"`);
|
|
2637
|
+
return `<w:permStart ${a.join(" ")}/>`;
|
|
2638
|
+
}
|
|
2639
|
+
if ("permEnd" in child) return `<w:permEnd w:id="${child.permEnd}"/>`;
|
|
2640
|
+
if ("moveFromRangeStart" in child) {
|
|
2641
|
+
const m = child.moveFromRangeStart;
|
|
2642
|
+
const a = [`w:id="${m.id}"`];
|
|
2643
|
+
if (m.name) a.push(`w:name="${escapeXml(m.name)}"`);
|
|
2644
|
+
if (m.author) a.push(`w:author="${escapeXml(m.author)}"`);
|
|
2645
|
+
if (m.date) a.push(`w:date="${m.date}"`);
|
|
2646
|
+
return `<w:moveFromRangeStart ${a.join(" ")}/>`;
|
|
2647
|
+
}
|
|
2648
|
+
if ("moveFromRangeEnd" in child) return `<w:moveFromRangeEnd w:id="${child.moveFromRangeEnd}"/>`;
|
|
2649
|
+
if ("moveToRangeStart" in child) {
|
|
2650
|
+
const m = child.moveToRangeStart;
|
|
2651
|
+
const a = [`w:id="${m.id}"`];
|
|
2652
|
+
if (m.name) a.push(`w:name="${escapeXml(m.name)}"`);
|
|
2653
|
+
if (m.author) a.push(`w:author="${escapeXml(m.author)}"`);
|
|
2654
|
+
if (m.date) a.push(`w:date="${m.date}"`);
|
|
2655
|
+
return `<w:moveToRangeStart ${a.join(" ")}/>`;
|
|
2656
|
+
}
|
|
2657
|
+
if ("moveToRangeEnd" in child) return `<w:moveToRangeEnd w:id="${child.moveToRangeEnd}"/>`;
|
|
2658
|
+
if ("movedFrom" in child) {
|
|
2659
|
+
const { id, author, date, ...runOpts } = child.movedFrom;
|
|
2660
|
+
const runXml = stringifyRunInline(runOpts, ctx);
|
|
2661
|
+
return `<w:moveFrom w:id="${id}" w:author="${escapeXml(String(author))}" w:date="${date}">${runXml}</w:moveFrom>`;
|
|
2662
|
+
}
|
|
2663
|
+
if ("movedTo" in child) {
|
|
2664
|
+
const { id, author, date, ...runOpts } = child.movedTo;
|
|
2665
|
+
const runXml = stringifyRunInline(runOpts, ctx);
|
|
2666
|
+
return `<w:moveTo w:id="${id}" w:author="${escapeXml(String(author))}" w:date="${date}">${runXml}</w:moveTo>`;
|
|
2667
|
+
}
|
|
2668
|
+
if ("customXmlInsRangeStart" in child) {
|
|
2669
|
+
const o = child.customXmlInsRangeStart;
|
|
2670
|
+
return `<w:customXmlInsRangeStart w:id="${o.id}" w:author="${escapeXml(o.author)}"${o.date ? ` w:date="${o.date}"` : ""}/>`;
|
|
2671
|
+
}
|
|
2672
|
+
if ("customXmlInsRangeEnd" in child) return `<w:customXmlInsRangeEnd w:id="${child.customXmlInsRangeEnd}"/>`;
|
|
2673
|
+
if ("customXmlDelRangeStart" in child) {
|
|
2674
|
+
const o = child.customXmlDelRangeStart;
|
|
2675
|
+
return `<w:customXmlDelRangeStart w:id="${o.id}" w:author="${escapeXml(o.author)}"${o.date ? ` w:date="${o.date}"` : ""}/>`;
|
|
2676
|
+
}
|
|
2677
|
+
if ("customXmlDelRangeEnd" in child) return `<w:customXmlDelRangeEnd w:id="${child.customXmlDelRangeEnd}"/>`;
|
|
2678
|
+
if ("customXmlMoveFromRangeStart" in child) {
|
|
2679
|
+
const o = child.customXmlMoveFromRangeStart;
|
|
2680
|
+
return `<w:customXmlMoveFromRangeStart w:id="${o.id}" w:author="${escapeXml(o.author)}"${o.date ? ` w:date="${o.date}"` : ""}/>`;
|
|
2681
|
+
}
|
|
2682
|
+
if ("customXmlMoveFromRangeEnd" in child) return `<w:customXmlMoveFromRangeEnd w:id="${child.customXmlMoveFromRangeEnd}"/>`;
|
|
2683
|
+
if ("customXmlMoveToRangeStart" in child) {
|
|
2684
|
+
const o = child.customXmlMoveToRangeStart;
|
|
2685
|
+
return `<w:customXmlMoveToRangeStart w:id="${o.id}" w:author="${escapeXml(o.author)}"${o.date ? ` w:date="${o.date}"` : ""}/>`;
|
|
2686
|
+
}
|
|
2687
|
+
if ("customXmlMoveToRangeEnd" in child) return `<w:customXmlMoveToRangeEnd w:id="${child.customXmlMoveToRangeEnd}"/>`;
|
|
2688
|
+
if ("simpleField" in child) {
|
|
2689
|
+
const sf = child.simpleField;
|
|
2690
|
+
if (sf.cachedValue !== void 0) return `<w:fldSimple w:instr="${escapeXml(sf.instruction)}"><w:r><w:t>${escapeXml(sf.cachedValue)}</w:t></w:r></w:fldSimple>`;
|
|
2691
|
+
return `<w:fldSimple w:instr="${escapeXml(sf.instruction)}"/>`;
|
|
2692
|
+
}
|
|
2693
|
+
if ("seqIdentifier" in child) {
|
|
2694
|
+
const id = child.seqIdentifier;
|
|
2695
|
+
return `<w:r><w:fldChar w:fldCharType="begin"/><w:instrText xml:space="preserve"> SEQ ${escapeXml(id)} </w:instrText><w:fldChar w:fldCharType="separate"/><w:fldChar w:fldCharType="end"/></w:r>`;
|
|
2696
|
+
}
|
|
2697
|
+
if ("pageReference" in child) {
|
|
2698
|
+
const pr = child.pageReference;
|
|
2699
|
+
let instr = ` PAGEREF ${escapeXml(pr.bookmarkId)} `;
|
|
2700
|
+
if (pr.hyperlink) instr += "\\h ";
|
|
2701
|
+
if (pr.useRelativePosition) instr += "\\p ";
|
|
2702
|
+
return `<w:r><w:fldChar w:fldCharType="begin"/><w:instrText xml:space="preserve">${instr}</w:instrText><w:fldChar w:fldCharType="end"/></w:r>`;
|
|
2703
|
+
}
|
|
2704
|
+
if ("dir" in child) {
|
|
2705
|
+
const d = child.dir;
|
|
2706
|
+
const childXml = serializeDirChildren(d.children, ctx);
|
|
2707
|
+
return `<w:dir w:val="${d.val}">${childXml}</w:dir>`;
|
|
2708
|
+
}
|
|
2709
|
+
if ("bdo" in child) {
|
|
2710
|
+
const b = child.bdo;
|
|
2711
|
+
const childXml = serializeDirChildren(b.children, ctx);
|
|
2712
|
+
return `<w:bdo w:val="${b.val}">${childXml}</w:bdo>`;
|
|
2713
|
+
}
|
|
2714
|
+
if ("smartTag" in child) {
|
|
2715
|
+
const st = child.smartTag;
|
|
2716
|
+
const attrs = [];
|
|
2717
|
+
if (st.uri) attrs.push(`w:uri="${escapeXml(st.uri)}"`);
|
|
2718
|
+
attrs.push(`w:element="${escapeXml(st.element)}"`);
|
|
2719
|
+
const parts = [];
|
|
2720
|
+
if (st.properties?.length) {
|
|
2721
|
+
const propParts = [];
|
|
2722
|
+
for (const p of st.properties) {
|
|
2723
|
+
const pa = [];
|
|
2724
|
+
if (p.uri) pa.push(`w:uri="${escapeXml(p.uri)}"`);
|
|
2725
|
+
pa.push(`w:name="${escapeXml(p.name)}"`, `w:val="${escapeXml(p.val)}"`);
|
|
2726
|
+
propParts.push(`<w:attr ${pa.join(" ")}/>`);
|
|
2727
|
+
}
|
|
2728
|
+
parts.push(`<w:smartTagPr>${propParts.join("")}</w:smartTagPr>`);
|
|
2729
|
+
}
|
|
2730
|
+
if (st.children) for (const c of st.children) parts.push(typeof c === "string" ? stringifyRunInline({ text: c }, ctx) : stringifyRunInline(c, ctx));
|
|
2731
|
+
return `<w:smartTag ${attrs.join(" ")}>${parts.join("")}</w:smartTag>`;
|
|
2732
|
+
}
|
|
2733
|
+
if ("customXml" in child) {
|
|
2734
|
+
const cx = child.customXml;
|
|
2735
|
+
const attrs = [`w:element="${escapeXml(cx.element)}"`];
|
|
2736
|
+
if (cx.uri) attrs.push(`w:uri="${escapeXml(cx.uri)}"`);
|
|
2737
|
+
const parts = [];
|
|
2738
|
+
if (cx.customXmlPr) {
|
|
2739
|
+
const prParts = [];
|
|
2740
|
+
if (cx.customXmlPr.placeholder) prParts.push(`<w:placeholder w:val="${escapeXml(cx.customXmlPr.placeholder)}"/>`);
|
|
2741
|
+
if (cx.customXmlPr.attrs?.length) for (const a of cx.customXmlPr.attrs) {
|
|
2742
|
+
const aa = [`w:name="${escapeXml(a.name)}"`, `w:val="${escapeXml(a.val)}"`];
|
|
2743
|
+
if (a.uri) aa.push(`w:uri="${escapeXml(a.uri)}"`);
|
|
2744
|
+
prParts.push(`<w:attr ${aa.join(" ")}/>`);
|
|
2745
|
+
}
|
|
2746
|
+
if (prParts.length) parts.push(`<w:customXmlPr>${prParts.join("")}</w:customXmlPr>`);
|
|
2747
|
+
}
|
|
2748
|
+
if (cx.children) for (const c of cx.children) if (typeof c === "string") parts.push(stringifyRunInline({ text: c }, ctx));
|
|
2749
|
+
else {
|
|
2750
|
+
const jr = stringifyJsonChild(c, ctx);
|
|
2751
|
+
if (jr !== void 0) parts.push(Array.isArray(jr) ? jr.join("") : jr);
|
|
2752
|
+
else parts.push(stringifyRunInline(c, ctx));
|
|
2753
|
+
}
|
|
2754
|
+
return `<w:customXml ${attrs.join(" ")}>${parts.join("")}</w:customXml>`;
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
/** Serialize children of Dir/Bdo containers. */
|
|
2758
|
+
function serializeDirChildren(children, ctx) {
|
|
2759
|
+
if (!children) return "";
|
|
2760
|
+
const parts = [];
|
|
2761
|
+
for (const c of children) if (typeof c === "string") parts.push(stringifyRunInline({ text: c }, ctx));
|
|
2762
|
+
else parts.push(stringifyRunInline(c, ctx));
|
|
2763
|
+
return parts.join("");
|
|
2764
|
+
}
|
|
2765
|
+
/** Hash SmartArt data for unique key generation (duplicated from SmartArtRun). */
|
|
2766
|
+
function hashSmartArtData(options) {
|
|
2767
|
+
const data = JSON.stringify(options.data);
|
|
2768
|
+
let hash = 0;
|
|
2769
|
+
for (let i = 0; i < data.length; i++) {
|
|
2770
|
+
const char = data.charCodeAt(i);
|
|
2771
|
+
hash = (hash << 5) - hash + char | 0;
|
|
2772
|
+
}
|
|
2773
|
+
return Math.abs(hash);
|
|
2774
|
+
}
|
|
2775
|
+
function stringifyParagraphInline(opts, ctx) {
|
|
2776
|
+
const resolved = typeof opts === "string" ? { text: opts } : opts;
|
|
2777
|
+
const parts = [];
|
|
2778
|
+
const props = stringifyParagraphProperties(resolved);
|
|
2779
|
+
if (props.xml) parts.push(props.xml);
|
|
2780
|
+
if (props.numberingReferences.length > 0) for (const ref of props.numberingReferences) ctx.file.numbering.createConcreteNumberingInstance(ref.reference, ref.instance);
|
|
2781
|
+
if (resolved.text !== void 0) parts.push(stringifyRunInline({ text: resolved.text }, ctx));
|
|
2782
|
+
if (resolved.children) {
|
|
2783
|
+
for (const child of resolved.children) if (typeof child === "string") parts.push(stringifyRunInline({ text: child }, ctx));
|
|
2784
|
+
else if (typeof child === "object" && child !== null) {
|
|
2785
|
+
const jsonResult = stringifyJsonChild(child, ctx);
|
|
2786
|
+
if (jsonResult !== void 0) if (Array.isArray(jsonResult)) parts.push(...jsonResult);
|
|
2787
|
+
else parts.push(jsonResult);
|
|
2788
|
+
else if ("text" in child || "children" in child || "break" in child) parts.push(stringifyRunInline(child, ctx));
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
const body = parts.join("");
|
|
2792
|
+
return body ? `<w:p>${body}</w:p>` : "<w:p/>";
|
|
2793
|
+
}
|
|
2794
|
+
//#endregion
|
|
2795
|
+
//#region src/parts/table/stringify.ts
|
|
2796
|
+
/**
|
|
2797
|
+
* Direct XML string builders for table properties.
|
|
2798
|
+
*
|
|
2799
|
+
* Replaces `buildTableProperties() + xml()`, `buildTableRowProperties() + xml()`,
|
|
2800
|
+
* `buildTableCellProperties() + xml()`, and `new TablePropertyExceptions().toXml()`
|
|
2801
|
+
* with direct string concatenation — zero IXmlableObject allocation.
|
|
2802
|
+
*
|
|
2803
|
+
* @module
|
|
2804
|
+
*/
|
|
2805
|
+
function tableWidthStr(name, opts) {
|
|
2806
|
+
const type = opts.type ?? WidthType.AUTO;
|
|
2807
|
+
let w = opts.size;
|
|
2808
|
+
if (type === WidthType.PERCENTAGE && typeof w === "number") w = `${w}%`;
|
|
2809
|
+
return `<${name} ${attrParts({
|
|
2810
|
+
"w:w": w !== void 0 ? measurementOrPercentValue(w) : void 0,
|
|
2811
|
+
"w:type": type
|
|
2812
|
+
})}/>`;
|
|
2813
|
+
}
|
|
2814
|
+
function cellMarginChildrenStr(opts) {
|
|
2815
|
+
const unitType = opts.marginUnitType ?? WidthType.DXA;
|
|
2816
|
+
const parts = [];
|
|
2817
|
+
if (opts.top !== void 0) parts.push(tableWidthStr("w:top", {
|
|
2818
|
+
size: opts.top,
|
|
2819
|
+
type: unitType
|
|
2820
|
+
}));
|
|
2821
|
+
if (opts.left !== void 0) parts.push(tableWidthStr("w:left", {
|
|
2822
|
+
size: opts.left,
|
|
2823
|
+
type: unitType
|
|
2824
|
+
}));
|
|
2825
|
+
if (opts.bottom !== void 0) parts.push(tableWidthStr("w:bottom", {
|
|
2826
|
+
size: opts.bottom,
|
|
2827
|
+
type: unitType
|
|
2828
|
+
}));
|
|
2829
|
+
if (opts.right !== void 0) parts.push(tableWidthStr("w:right", {
|
|
2830
|
+
size: opts.right,
|
|
2831
|
+
type: unitType
|
|
2832
|
+
}));
|
|
2833
|
+
return parts.join("");
|
|
2834
|
+
}
|
|
2835
|
+
function cellMarginStr(tag, opts) {
|
|
2836
|
+
const inner = cellMarginChildrenStr(opts);
|
|
2837
|
+
return inner ? `<${tag}>${inner}</${tag}>` : void 0;
|
|
2838
|
+
}
|
|
2839
|
+
const DEFAULT_BORDER = {
|
|
2840
|
+
color: "auto",
|
|
2841
|
+
size: 4,
|
|
2842
|
+
style: BorderStyle.SINGLE
|
|
2843
|
+
};
|
|
2844
|
+
function tableBordersStr(opts) {
|
|
2845
|
+
const parts = [];
|
|
2846
|
+
parts.push(borderStr("w:top", opts.top ?? DEFAULT_BORDER));
|
|
2847
|
+
parts.push(borderStr("w:left", opts.left ?? DEFAULT_BORDER));
|
|
2848
|
+
parts.push(borderStr("w:bottom", opts.bottom ?? DEFAULT_BORDER));
|
|
2849
|
+
parts.push(borderStr("w:right", opts.right ?? DEFAULT_BORDER));
|
|
2850
|
+
parts.push(borderStr("w:insideH", opts.insideHorizontal ?? DEFAULT_BORDER));
|
|
2851
|
+
parts.push(borderStr("w:insideV", opts.insideVertical ?? DEFAULT_BORDER));
|
|
2852
|
+
return `<w:tblBorders>${parts.join("")}</w:tblBorders>`;
|
|
2853
|
+
}
|
|
2854
|
+
function cellBordersStr(opts) {
|
|
2855
|
+
const parts = [];
|
|
2856
|
+
if (opts.top) parts.push(borderStr("w:top", opts.top));
|
|
2857
|
+
if (opts.start) parts.push(borderStr("w:start", opts.start));
|
|
2858
|
+
if (opts.left) parts.push(borderStr("w:left", opts.left));
|
|
2859
|
+
if (opts.bottom) parts.push(borderStr("w:bottom", opts.bottom));
|
|
2860
|
+
if (opts.end) parts.push(borderStr("w:end", opts.end));
|
|
2861
|
+
if (opts.right) parts.push(borderStr("w:right", opts.right));
|
|
2862
|
+
if (opts.topLeftToBottomRight) parts.push(borderStr("w:tl2br", opts.topLeftToBottomRight));
|
|
2863
|
+
if (opts.topRightToBottomLeft) parts.push(borderStr("w:tr2bl", opts.topRightToBottomLeft));
|
|
2864
|
+
return parts.length > 0 ? `<w:tcBorders>${parts.join("")}</w:tcBorders>` : void 0;
|
|
2865
|
+
}
|
|
2866
|
+
function floatPropertiesStr(opts) {
|
|
2867
|
+
return `<w:tblpPr ${attrParts({
|
|
2868
|
+
"w:horzAnchor": opts.horizontalAnchor,
|
|
2869
|
+
"w:vertAnchor": opts.verticalAnchor,
|
|
2870
|
+
"w:tblpX": opts.absoluteHorizontalPosition !== void 0 ? signedTwipsMeasureValue(opts.absoluteHorizontalPosition) : void 0,
|
|
2871
|
+
"w:tblpXSpec": opts.relativeHorizontalPosition,
|
|
2872
|
+
"w:tblpY": opts.absoluteVerticalPosition !== void 0 ? signedTwipsMeasureValue(opts.absoluteVerticalPosition) : void 0,
|
|
2873
|
+
"w:tblpYSpec": opts.relativeVerticalPosition,
|
|
2874
|
+
"w:bottomFromText": opts.bottomFromText !== void 0 ? twipsMeasureValue(opts.bottomFromText) : void 0,
|
|
2875
|
+
"w:topFromText": opts.topFromText !== void 0 ? twipsMeasureValue(opts.topFromText) : void 0,
|
|
2876
|
+
"w:leftFromText": opts.leftFromText !== void 0 ? twipsMeasureValue(opts.leftFromText) : void 0,
|
|
2877
|
+
"w:rightFromText": opts.rightFromText !== void 0 ? twipsMeasureValue(opts.rightFromText) : void 0
|
|
2878
|
+
})}/>`;
|
|
2879
|
+
}
|
|
2880
|
+
function tableLookStr(opts) {
|
|
2881
|
+
return `<w:tblLook ${attrParts({
|
|
2882
|
+
"w:firstRow": opts.firstRow,
|
|
2883
|
+
"w:lastRow": opts.lastRow,
|
|
2884
|
+
"w:firstColumn": opts.firstColumn,
|
|
2885
|
+
"w:lastColumn": opts.lastColumn,
|
|
2886
|
+
"w:noHBand": opts.noHBand,
|
|
2887
|
+
"w:noVBand": opts.noVBand
|
|
2888
|
+
})}/>`;
|
|
2889
|
+
}
|
|
2890
|
+
function changeAttrStr(tag, opts) {
|
|
2891
|
+
return `<${tag} ${attrParts({
|
|
2892
|
+
"w:author": opts.author,
|
|
2893
|
+
"w:date": opts.date,
|
|
2894
|
+
"w:id": opts.id
|
|
2895
|
+
})}/>`;
|
|
2896
|
+
}
|
|
2897
|
+
function cellMergeStr(opts) {
|
|
2898
|
+
const attrs = {
|
|
2899
|
+
"w:author": opts.author,
|
|
2900
|
+
"w:date": opts.date,
|
|
2901
|
+
"w:id": opts.id
|
|
2902
|
+
};
|
|
2903
|
+
if (opts.verticalMerge !== void 0) attrs["w:vMerge"] = xsdVerticalMergeRev.to(opts.verticalMerge);
|
|
2904
|
+
if (opts.verticalMergeOriginal !== void 0) attrs["w:vMergeOrig"] = xsdVerticalMergeRev.to(opts.verticalMergeOriginal);
|
|
2905
|
+
return `<w:cellMerge ${attrParts(attrs)}/>`;
|
|
2906
|
+
}
|
|
2907
|
+
function cellSpacingStr(opts) {
|
|
2908
|
+
return `<w:tblCellSpacing ${attrParts({
|
|
2909
|
+
"w:type": opts.type,
|
|
2910
|
+
"w:w": measurementOrPercentValue(opts.value)
|
|
2911
|
+
})}/>`;
|
|
2912
|
+
}
|
|
2913
|
+
function stringifyTablePropertiesChangeInner(options) {
|
|
2914
|
+
const inner = stringifyTablePropertiesInner({
|
|
2915
|
+
...options,
|
|
2916
|
+
includeIfEmpty: true
|
|
2917
|
+
});
|
|
2918
|
+
return `<w:tblPrChange ${attrParts({
|
|
2919
|
+
"w:author": options.author,
|
|
2920
|
+
"w:date": options.date,
|
|
2921
|
+
"w:id": options.id
|
|
2922
|
+
})}><w:tblPr>${inner}</w:tblPr></w:tblPrChange>`;
|
|
2923
|
+
}
|
|
2924
|
+
function stringifyTablePropertiesInner(options) {
|
|
2925
|
+
const parts = [];
|
|
2926
|
+
if (options.style) parts.push(`<w:tblStyle w:val="${options.style}"/>`);
|
|
2927
|
+
if (options.float) {
|
|
2928
|
+
parts.push(floatPropertiesStr(options.float));
|
|
2929
|
+
if (options.float.overlap) parts.push(`<w:tblOverlap w:val="${options.float.overlap}"/>`);
|
|
2930
|
+
}
|
|
2931
|
+
if (options.visuallyRightToLeft !== void 0) parts.push(onOff("w:bidiVisual", options.visuallyRightToLeft));
|
|
2932
|
+
if (options.styleRowBandSize !== void 0) parts.push(`<w:tblStyleRowBandSize w:val="${options.styleRowBandSize}"/>`);
|
|
2933
|
+
if (options.styleColBandSize !== void 0) parts.push(`<w:tblStyleColBandSize w:val="${options.styleColBandSize}"/>`);
|
|
2934
|
+
if (options.width) parts.push(tableWidthStr("w:tblW", options.width));
|
|
2935
|
+
if (options.alignment) parts.push(`<w:jc w:val="${options.alignment}"/>`);
|
|
2936
|
+
if (options.indent) parts.push(tableWidthStr("w:tblInd", options.indent));
|
|
2937
|
+
if (options.borders) parts.push(tableBordersStr(options.borders));
|
|
2938
|
+
if (options.shading) parts.push(shadingStr(options.shading));
|
|
2939
|
+
if (options.layout) parts.push(`<w:tblLayout w:type="${options.layout}"/>`);
|
|
2940
|
+
if (options.cellMargin) {
|
|
2941
|
+
const cm = cellMarginStr("w:tblCellMar", options.cellMargin);
|
|
2942
|
+
if (cm) parts.push(cm);
|
|
2943
|
+
}
|
|
2944
|
+
if (options.tableLook) parts.push(tableLookStr(options.tableLook));
|
|
2945
|
+
if (options.cellSpacing) parts.push(cellSpacingStr(options.cellSpacing));
|
|
2946
|
+
if (options.caption !== void 0) parts.push(`<w:tblCaption w:val="${options.caption}"/>`);
|
|
2947
|
+
if (options.description !== void 0) parts.push(`<w:tblDescription w:val="${options.description}"/>`);
|
|
2948
|
+
if (options.revision) parts.push(stringifyTablePropertiesChangeInner(options.revision));
|
|
2949
|
+
return parts.join("");
|
|
2950
|
+
}
|
|
2951
|
+
function stringifyTableProperties(options) {
|
|
2952
|
+
const inner = stringifyTablePropertiesInner(options);
|
|
2953
|
+
if (options.includeIfEmpty || inner) return `<w:tblPr>${inner}</w:tblPr>`;
|
|
2954
|
+
}
|
|
2955
|
+
function stringifyTableRowPropertiesChangeInner(options) {
|
|
2956
|
+
const inner = stringifyTableRowPropertiesInner({
|
|
2957
|
+
...options,
|
|
2958
|
+
includeIfEmpty: true
|
|
2959
|
+
});
|
|
2960
|
+
return `<w:trPrChange ${attrParts({
|
|
2961
|
+
"w:author": options.author,
|
|
2962
|
+
"w:date": options.date,
|
|
2963
|
+
"w:id": options.id
|
|
2964
|
+
})}><w:trPr>${inner}</w:trPr></w:trPrChange>`;
|
|
2965
|
+
}
|
|
2966
|
+
function stringifyTableRowPropertiesInner(options) {
|
|
2967
|
+
const parts = [];
|
|
2968
|
+
if (options.cnfStyle !== void 0) {
|
|
2969
|
+
const a = attrParts({
|
|
2970
|
+
"w:val": options.cnfStyle.val,
|
|
2971
|
+
"w:changed": options.cnfStyle.changed
|
|
2972
|
+
});
|
|
2973
|
+
parts.push(`<w:cnfStyle ${a}/>`);
|
|
2974
|
+
}
|
|
2975
|
+
if (options.divId !== void 0) parts.push(`<w:divId w:val="${options.divId}"/>`);
|
|
2976
|
+
if (options.gridBefore !== void 0) parts.push(`<w:gridBefore w:val="${options.gridBefore}"/>`);
|
|
2977
|
+
if (options.gridAfter !== void 0) parts.push(`<w:gridAfter w:val="${options.gridAfter}"/>`);
|
|
2978
|
+
if (options.widthBefore) parts.push(tableWidthStr("w:wBefore", options.widthBefore));
|
|
2979
|
+
if (options.widthAfter) parts.push(tableWidthStr("w:wAfter", options.widthAfter));
|
|
2980
|
+
if (options.cantSplit !== void 0) parts.push(onOff("w:cantSplit", options.cantSplit));
|
|
2981
|
+
if (options.tableHeader !== void 0) parts.push(onOff("w:tblHeader", options.tableHeader));
|
|
2982
|
+
if (options.height) {
|
|
2983
|
+
const a = attrParts({
|
|
2984
|
+
"w:val": twipsMeasureValue(options.height.value),
|
|
2985
|
+
"w:hRule": options.height.rule
|
|
2986
|
+
});
|
|
2987
|
+
parts.push(`<w:trHeight ${a}/>`);
|
|
2988
|
+
}
|
|
2989
|
+
if (options.cellSpacing) parts.push(cellSpacingStr(options.cellSpacing));
|
|
2990
|
+
if (options.rowAlignment) parts.push(`<w:jc w:val="${options.rowAlignment}"/>`);
|
|
2991
|
+
if (options.hidden !== void 0) parts.push(onOff("w:hidden", options.hidden));
|
|
2992
|
+
if (options.insertion) parts.push(changeAttrStr("w:ins", options.insertion));
|
|
2993
|
+
if (options.deletion) parts.push(changeAttrStr("w:del", options.deletion));
|
|
2994
|
+
if (options.revision) parts.push(stringifyTableRowPropertiesChangeInner(options.revision));
|
|
2995
|
+
return parts.join("");
|
|
2996
|
+
}
|
|
2997
|
+
function stringifyTableRowProperties(options) {
|
|
2998
|
+
const inner = stringifyTableRowPropertiesInner(options);
|
|
2999
|
+
if (options.includeIfEmpty || inner) return `<w:trPr>${inner}</w:trPr>`;
|
|
3000
|
+
}
|
|
3001
|
+
function stringifyTableCellPropertiesChangeInner(options) {
|
|
3002
|
+
const inner = stringifyTableCellPropertiesInner({
|
|
3003
|
+
...options,
|
|
3004
|
+
includeIfEmpty: true
|
|
3005
|
+
});
|
|
3006
|
+
return `<w:tcPrChange ${attrParts({
|
|
3007
|
+
"w:author": options.author,
|
|
3008
|
+
"w:date": options.date,
|
|
3009
|
+
"w:id": options.id
|
|
3010
|
+
})}><w:tcPr>${inner}</w:tcPr></w:tcPrChange>`;
|
|
3011
|
+
}
|
|
3012
|
+
function stringifyTableCellPropertiesInner(options) {
|
|
3013
|
+
const parts = [];
|
|
3014
|
+
if (options.cnfStyle !== void 0) {
|
|
3015
|
+
const a = attrParts({
|
|
3016
|
+
"w:val": options.cnfStyle.val,
|
|
3017
|
+
"w:changed": options.cnfStyle.changed
|
|
3018
|
+
});
|
|
3019
|
+
parts.push(`<w:cnfStyle ${a}/>`);
|
|
3020
|
+
}
|
|
3021
|
+
if (options.width) parts.push(tableWidthStr("w:tcW", options.width));
|
|
3022
|
+
if (options.columnSpan) parts.push(`<w:gridSpan w:val="${options.columnSpan}"/>`);
|
|
3023
|
+
if (options.verticalMerge) parts.push(`<w:vMerge w:val="${options.verticalMerge}"/>`);
|
|
3024
|
+
else if (options.rowSpan && options.rowSpan > 1) parts.push(`<w:vMerge w:val="${VerticalMergeType.RESTART}"/>`);
|
|
3025
|
+
if (options.borders) {
|
|
3026
|
+
const bs = cellBordersStr(options.borders);
|
|
3027
|
+
if (bs) parts.push(bs);
|
|
3028
|
+
}
|
|
3029
|
+
if (options.shading) parts.push(shadingStr(options.shading));
|
|
3030
|
+
if (options.margins) {
|
|
3031
|
+
const cm = cellMarginStr("w:tcMar", options.margins);
|
|
3032
|
+
if (cm) parts.push(cm);
|
|
3033
|
+
}
|
|
3034
|
+
if (options.textDirection) parts.push(`<w:textDirection w:val="${options.textDirection}"/>`);
|
|
3035
|
+
if (options.verticalAlign) parts.push(`<w:vAlign w:val="${options.verticalAlign}"/>`);
|
|
3036
|
+
if (options.horizontalMerge !== void 0) if (options.horizontalMerge === "restart") parts.push(`<w:hMerge w:val="restart"/>`);
|
|
3037
|
+
else parts.push(`<w:hMerge/>`);
|
|
3038
|
+
if (options.noWrap !== void 0) parts.push(onOff("w:noWrap", options.noWrap));
|
|
3039
|
+
if (options.fitText !== void 0) parts.push(onOff("w:tcFitText", options.fitText));
|
|
3040
|
+
if (options.hideMark !== void 0) parts.push(onOff("w:hideMark", options.hideMark));
|
|
3041
|
+
if (options.headers !== void 0) {
|
|
3042
|
+
const headerParts = options.headers.map((h) => `<w:header w:val="${h}"/>`).join("");
|
|
3043
|
+
parts.push(`<w:headers>${headerParts}</w:headers>`);
|
|
3044
|
+
}
|
|
3045
|
+
if (options.insertion) parts.push(changeAttrStr("w:cellIns", options.insertion));
|
|
3046
|
+
if (options.deletion) parts.push(changeAttrStr("w:cellDel", options.deletion));
|
|
3047
|
+
if (options.revision) parts.push(stringifyTableCellPropertiesChangeInner(options.revision));
|
|
3048
|
+
if (options.cellMerge) parts.push(cellMergeStr(options.cellMerge));
|
|
3049
|
+
return parts.join("");
|
|
3050
|
+
}
|
|
3051
|
+
function stringifyTableCellProperties(options) {
|
|
3052
|
+
const inner = stringifyTableCellPropertiesInner(options);
|
|
3053
|
+
if (options.includeIfEmpty || inner) return `<w:tcPr>${inner}</w:tcPr>`;
|
|
3054
|
+
}
|
|
3055
|
+
function stringifyTablePropertyExceptions(options) {
|
|
3056
|
+
const parts = [];
|
|
3057
|
+
if (options.width) parts.push(tableWidthStr("w:tblW", options.width));
|
|
3058
|
+
if (options.alignment) parts.push(`<w:jc w:val="${options.alignment}"/>`);
|
|
3059
|
+
if (options.cellSpacing) parts.push(cellSpacingStr(options.cellSpacing));
|
|
3060
|
+
if (options.indent) parts.push(tableWidthStr("w:tblInd", options.indent));
|
|
3061
|
+
if (options.borders) parts.push(tableBordersStr(options.borders));
|
|
3062
|
+
if (options.shading) parts.push(shadingStr(options.shading));
|
|
3063
|
+
if (options.layout) parts.push(`<w:tblLayout w:type="${options.layout}"/>`);
|
|
3064
|
+
if (options.cellMargin) {
|
|
3065
|
+
const cm = cellMarginStr("w:tblCellMar", options.cellMargin);
|
|
3066
|
+
if (cm) parts.push(cm);
|
|
3067
|
+
}
|
|
3068
|
+
if (options.tableLook) parts.push(tableLookStr(options.tableLook));
|
|
3069
|
+
if (options.tblPrExChange) {
|
|
3070
|
+
const change = options.tblPrExChange;
|
|
3071
|
+
const attrs = {
|
|
3072
|
+
"w:author": change.author,
|
|
3073
|
+
"w:id": change.id
|
|
3074
|
+
};
|
|
3075
|
+
if (change.date !== void 0) attrs["w:date"] = change.date;
|
|
3076
|
+
const a = attrParts(attrs);
|
|
3077
|
+
parts.push(`<w:tblPrExChange ${a}/>`);
|
|
3078
|
+
}
|
|
3079
|
+
return `<w:tblPrEx>${parts.join("")}</w:tblPrEx>`;
|
|
3080
|
+
}
|
|
3081
|
+
//#endregion
|
|
3082
|
+
//#region src/parts/table/descriptor.ts
|
|
3083
|
+
function buildTableGridXml(widths, revision) {
|
|
3084
|
+
const cols = widths.map((w) => `<w:gridCol w:w="${w}"/>`).join("");
|
|
3085
|
+
if (revision) {
|
|
3086
|
+
const revCols = revision.columnWidths.map((w) => `<w:gridCol w:w="${w}"/>`).join("");
|
|
3087
|
+
return `<w:tblGrid>${cols}<w:tblGridChange w:id="${revision.id}"><w:tblGrid>${revCols}</w:tblGrid></w:tblGridChange></w:tblGrid>`;
|
|
3088
|
+
}
|
|
3089
|
+
return `<w:tblGrid>${cols}</w:tblGrid>`;
|
|
3090
|
+
}
|
|
3091
|
+
/** Extract column/row span from a plain-object cell. */
|
|
3092
|
+
function getCellSpans(cell) {
|
|
3093
|
+
return {
|
|
3094
|
+
columnSpan: cell.columnSpan ?? 1,
|
|
3095
|
+
rowSpan: cell.rowSpan ?? 1
|
|
3096
|
+
};
|
|
3097
|
+
}
|
|
3098
|
+
/**
|
|
3099
|
+
* Stringify a cell child (SectionChild) inline.
|
|
3100
|
+
* Handles strings and plain objects (paragraph/table).
|
|
3101
|
+
*/
|
|
3102
|
+
function stringifyCellChild(child, ctx) {
|
|
3103
|
+
if (typeof child === "string") return stringifyParagraphInline(child, ctx);
|
|
3104
|
+
if ("paragraph" in child) return stringifyParagraphInline(child.paragraph, ctx);
|
|
3105
|
+
if ("table" in child) return tableDesc.stringify(child.table, ctx) ?? "";
|
|
3106
|
+
return "";
|
|
3107
|
+
}
|
|
3108
|
+
function stringifyTableCell(cell, ctx) {
|
|
3109
|
+
const parts = [];
|
|
3110
|
+
const tcPr = stringifyTableCellProperties(cell);
|
|
3111
|
+
if (tcPr) parts.push(tcPr);
|
|
3112
|
+
const children = cell.children;
|
|
3113
|
+
if (children) for (const child of children) parts.push(stringifyCellChild(child, ctx));
|
|
3114
|
+
const last = children?.[children.length - 1];
|
|
3115
|
+
if (!(last && typeof last !== "string" && ("paragraph" in last || "table" in last))) parts.push("<w:p/>");
|
|
3116
|
+
return `<w:tc>${parts.join("")}</w:tc>`;
|
|
3117
|
+
}
|
|
3118
|
+
function stringifyTableRow(row, ctx, extraCells) {
|
|
3119
|
+
const parts = [];
|
|
3120
|
+
if (row.propertyExceptions) parts.push(stringifyTablePropertyExceptions(row.propertyExceptions));
|
|
3121
|
+
const trPr = stringifyTableRowProperties(row);
|
|
3122
|
+
if (trPr) parts.push(trPr);
|
|
3123
|
+
const prefixCount = parts.length;
|
|
3124
|
+
for (const cell of row.cells) parts.push(stringifyTableCell(cell, ctx));
|
|
3125
|
+
if (extraCells && extraCells.length > 0) for (const { cell, columnIndex } of extraCells) {
|
|
3126
|
+
const insertIdx = findInsertIndex(row.cells, columnIndex, prefixCount);
|
|
3127
|
+
parts.splice(insertIdx, 0, stringifyTableCell(cell, ctx));
|
|
3128
|
+
}
|
|
3129
|
+
const rsidAttrs = [];
|
|
3130
|
+
if (row.rsidRPr) rsidAttrs.push(` w:rsidRPr="${row.rsidRPr}"`);
|
|
3131
|
+
if (row.rsidR) rsidAttrs.push(` w:rsidR="${row.rsidR}"`);
|
|
3132
|
+
if (row.rsidDel) rsidAttrs.push(` w:rsidDel="${row.rsidDel}"`);
|
|
3133
|
+
if (row.rsidTr) rsidAttrs.push(` w:rsidTr="${row.rsidTr}"`);
|
|
3134
|
+
const attr = rsidAttrs.join("");
|
|
3135
|
+
const body = parts.join("");
|
|
3136
|
+
return body ? `<w:tr${attr}>${body}</w:tr>` : attr ? `<w:tr${attr}/>` : "<w:tr/>";
|
|
3137
|
+
}
|
|
3138
|
+
function findInsertIndex(cells, columnIndex, prefixCount) {
|
|
3139
|
+
let colIdx = 0;
|
|
3140
|
+
for (let i = 0; i < cells.length; i++) {
|
|
3141
|
+
const { columnSpan } = getCellSpans(cells[i]);
|
|
3142
|
+
colIdx += columnSpan;
|
|
3143
|
+
if (colIdx > columnIndex) return i + prefixCount;
|
|
3144
|
+
}
|
|
3145
|
+
return cells.length + prefixCount;
|
|
3146
|
+
}
|
|
3147
|
+
/**
|
|
3148
|
+
* Pre-process rows to compute CONTINUE cells for vertical merge.
|
|
3149
|
+
*/
|
|
3150
|
+
function computeVerticalMergeCells(rows) {
|
|
3151
|
+
const extraMap = /* @__PURE__ */ new Map();
|
|
3152
|
+
for (let ri = 0; ri < rows.length - 1; ri++) {
|
|
3153
|
+
const cells = rows[ri].cells;
|
|
3154
|
+
let colIdx = 0;
|
|
3155
|
+
for (const cell of cells) {
|
|
3156
|
+
const typedCell = cell;
|
|
3157
|
+
const { columnSpan, rowSpan } = getCellSpans(typedCell);
|
|
3158
|
+
if (rowSpan > 1) {
|
|
3159
|
+
const continueCell = {
|
|
3160
|
+
borders: typedCell.borders,
|
|
3161
|
+
children: [],
|
|
3162
|
+
columnSpan,
|
|
3163
|
+
rowSpan: rowSpan - 1,
|
|
3164
|
+
verticalMerge: VerticalMergeType.CONTINUE
|
|
3165
|
+
};
|
|
3166
|
+
if (!extraMap.has(ri + 1)) extraMap.set(ri + 1, []);
|
|
3167
|
+
extraMap.get(ri + 1).push({
|
|
3168
|
+
cell: continueCell,
|
|
3169
|
+
columnIndex: colIdx
|
|
3170
|
+
});
|
|
3171
|
+
}
|
|
3172
|
+
colIdx += columnSpan;
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
return extraMap;
|
|
3176
|
+
}
|
|
3177
|
+
const tableDesc = {
|
|
3178
|
+
kind: "custom",
|
|
3179
|
+
stringify(opts, ctx) {
|
|
3180
|
+
const parts = [];
|
|
3181
|
+
const tblPr = stringifyTableProperties({
|
|
3182
|
+
alignment: opts.alignment,
|
|
3183
|
+
borders: opts.borders ?? {},
|
|
3184
|
+
caption: opts.caption,
|
|
3185
|
+
cellMargin: opts.margins,
|
|
3186
|
+
cellSpacing: opts.cellSpacing,
|
|
3187
|
+
description: opts.description,
|
|
3188
|
+
float: opts.float,
|
|
3189
|
+
indent: opts.indent,
|
|
3190
|
+
layout: opts.layout,
|
|
3191
|
+
revision: opts.revision,
|
|
3192
|
+
style: opts.style,
|
|
3193
|
+
styleColBandSize: opts.styleColBandSize,
|
|
3194
|
+
styleRowBandSize: opts.styleRowBandSize,
|
|
3195
|
+
tableLook: opts.tableLook,
|
|
3196
|
+
visuallyRightToLeft: opts.visuallyRightToLeft,
|
|
3197
|
+
width: opts.width ?? { size: 100 }
|
|
3198
|
+
});
|
|
3199
|
+
if (tblPr) parts.push(tblPr);
|
|
3200
|
+
const columnWidths = opts.columnWidths ?? Array(Math.max(...opts.rows.map((r) => r.cells.length))).fill(100);
|
|
3201
|
+
parts.push(buildTableGridXml(columnWidths, opts.columnWidthsRevision));
|
|
3202
|
+
const extraCells = computeVerticalMergeCells(opts.rows);
|
|
3203
|
+
for (let ri = 0; ri < opts.rows.length; ri++) {
|
|
3204
|
+
const row = opts.rows[ri];
|
|
3205
|
+
const extras = extraCells.get(ri);
|
|
3206
|
+
parts.push(stringifyTableRow(row, ctx, extras));
|
|
3207
|
+
}
|
|
3208
|
+
return `<w:tbl>${parts.join("")}</w:tbl>`;
|
|
3209
|
+
},
|
|
3210
|
+
parse(el, ctx) {
|
|
3211
|
+
return parseTableEl(el, ctx);
|
|
3212
|
+
}
|
|
3213
|
+
};
|
|
3214
|
+
/** Callback used by table parser to parse body children. */
|
|
3215
|
+
let _parseChild;
|
|
3216
|
+
/** Set the child parser callback (called from parseBody). */
|
|
3217
|
+
function setTableParseChild(fn) {
|
|
3218
|
+
_parseChild = fn;
|
|
3219
|
+
}
|
|
3220
|
+
function parseTablePropertiesEl(el) {
|
|
3221
|
+
const opts = {};
|
|
3222
|
+
const style = findChild(el, "w:tblStyle");
|
|
3223
|
+
if (style) {
|
|
3224
|
+
const val = attr(style, "w:val");
|
|
3225
|
+
if (val) opts.style = val;
|
|
3226
|
+
}
|
|
3227
|
+
const tblW = findChild(el, "w:tblW");
|
|
3228
|
+
if (tblW) {
|
|
3229
|
+
const rawSize = attr(tblW, "w:w");
|
|
3230
|
+
const type = attr(tblW, "w:type");
|
|
3231
|
+
const size = type === "pct" ? rawSize : attrNum(tblW, "w:w");
|
|
3232
|
+
if (size !== void 0 || type) opts.width = {
|
|
3233
|
+
size: size ?? 0,
|
|
3234
|
+
...type ? { type } : {}
|
|
3235
|
+
};
|
|
3236
|
+
}
|
|
3237
|
+
const jc = findChild(el, "w:jc");
|
|
3238
|
+
if (jc) {
|
|
3239
|
+
const val = attr(jc, "w:val");
|
|
3240
|
+
if (val) opts.alignment = val;
|
|
3241
|
+
}
|
|
3242
|
+
const layout = findChild(el, "w:tblLayout");
|
|
3243
|
+
if (layout) {
|
|
3244
|
+
const val = attr(layout, "w:type");
|
|
3245
|
+
if (val === "autofit" || val === "fixed") opts.layout = val;
|
|
3246
|
+
}
|
|
3247
|
+
const tblBorders = findChild(el, "w:tblBorders");
|
|
3248
|
+
if (tblBorders) {
|
|
3249
|
+
const borders = {};
|
|
3250
|
+
for (const side of [
|
|
3251
|
+
"top",
|
|
3252
|
+
"bottom",
|
|
3253
|
+
"left",
|
|
3254
|
+
"right",
|
|
3255
|
+
"insideH",
|
|
3256
|
+
"insideV"
|
|
3257
|
+
]) {
|
|
3258
|
+
const sideEl = findChild(tblBorders, `w:${side}`);
|
|
3259
|
+
if (sideEl) {
|
|
3260
|
+
const b = {};
|
|
3261
|
+
const val = attr(sideEl, "w:val");
|
|
3262
|
+
if (val) b.style = val;
|
|
3263
|
+
const color = attr(sideEl, "w:color");
|
|
3264
|
+
if (color) b.color = color;
|
|
3265
|
+
const sz = attrNum(sideEl, "w:sz");
|
|
3266
|
+
if (sz !== void 0) b.size = sz;
|
|
3267
|
+
const space = attrNum(sideEl, "w:space");
|
|
3268
|
+
if (space !== void 0) b.space = space;
|
|
3269
|
+
borders[side] = b;
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
if (Object.keys(borders).length > 0) opts.borders = borders;
|
|
3273
|
+
}
|
|
3274
|
+
const tblCellMar = findChild(el, "w:tblCellMar");
|
|
3275
|
+
if (tblCellMar) {
|
|
3276
|
+
const margins = {};
|
|
3277
|
+
for (const side of [
|
|
3278
|
+
"top",
|
|
3279
|
+
"bottom",
|
|
3280
|
+
"left",
|
|
3281
|
+
"right"
|
|
3282
|
+
]) {
|
|
3283
|
+
const sideEl = findChild(tblCellMar, `w:${side}`);
|
|
3284
|
+
if (sideEl) {
|
|
3285
|
+
const size = attrNum(sideEl, "w:w");
|
|
3286
|
+
const type = attr(sideEl, "w:type");
|
|
3287
|
+
if (size !== void 0) margins[side] = {
|
|
3288
|
+
size,
|
|
3289
|
+
type: type ?? "dxa"
|
|
3290
|
+
};
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3293
|
+
if (Object.keys(margins).length > 0) opts.margins = margins;
|
|
3294
|
+
}
|
|
3295
|
+
const shd = findChild(el, "w:shd");
|
|
3296
|
+
if (shd) {
|
|
3297
|
+
const shading = {};
|
|
3298
|
+
const fill = attr(shd, "w:fill");
|
|
3299
|
+
if (fill) shading.fill = fill;
|
|
3300
|
+
const color = attr(shd, "w:color");
|
|
3301
|
+
if (color) shading.color = color;
|
|
3302
|
+
const val = attr(shd, "w:val");
|
|
3303
|
+
if (val) shading.type = val;
|
|
3304
|
+
if (Object.keys(shading).length > 0) opts.shading = shading;
|
|
3305
|
+
}
|
|
3306
|
+
return opts;
|
|
3307
|
+
}
|
|
3308
|
+
function parseColumnWidthsEl(el) {
|
|
3309
|
+
const cols = [];
|
|
3310
|
+
const tblGrid = findChild(el, "w:tblGrid");
|
|
3311
|
+
if (!tblGrid) return cols;
|
|
3312
|
+
for (const col of children(tblGrid, "w:gridCol")) {
|
|
3313
|
+
const w = attrNum(col, "w:w");
|
|
3314
|
+
cols.push(w ?? 100);
|
|
3315
|
+
}
|
|
3316
|
+
return cols;
|
|
3317
|
+
}
|
|
3318
|
+
function parseTableRowPropertiesEl(el) {
|
|
3319
|
+
const opts = {};
|
|
3320
|
+
const trHeight = findChild(el, "w:trHeight");
|
|
3321
|
+
if (trHeight) {
|
|
3322
|
+
const val = attrNum(trHeight, "w:val");
|
|
3323
|
+
const rule = attr(trHeight, "w:hRule");
|
|
3324
|
+
if (val !== void 0) opts.height = {
|
|
3325
|
+
value: val,
|
|
3326
|
+
rule: rule ?? "atLeast"
|
|
3327
|
+
};
|
|
3328
|
+
}
|
|
3329
|
+
const tblHeader = findChild(el, "w:tblHeader");
|
|
3330
|
+
if (tblHeader) opts.tableHeader = attrBool(tblHeader, "w:val") ?? true;
|
|
3331
|
+
const cantSplit = findChild(el, "w:cantSplit");
|
|
3332
|
+
if (cantSplit) opts.cantSplit = attrBool(cantSplit, "w:val") ?? true;
|
|
3333
|
+
return opts;
|
|
3334
|
+
}
|
|
3335
|
+
function parseTableCellPropertiesEl(el) {
|
|
3336
|
+
const opts = {};
|
|
3337
|
+
const tcW = findChild(el, "w:tcW");
|
|
3338
|
+
if (tcW) {
|
|
3339
|
+
const size = attrNum(tcW, "w:w");
|
|
3340
|
+
const type = attr(tcW, "w:type");
|
|
3341
|
+
if (size !== void 0) opts.width = {
|
|
3342
|
+
size,
|
|
3343
|
+
type: type ?? "dxa"
|
|
3344
|
+
};
|
|
3345
|
+
}
|
|
3346
|
+
const gridSpan = findChild(el, "w:gridSpan");
|
|
3347
|
+
if (gridSpan) {
|
|
3348
|
+
const val = attrNum(gridSpan, "w:val");
|
|
3349
|
+
if (val !== void 0) opts.columnSpan = val;
|
|
3350
|
+
}
|
|
3351
|
+
const vMerge = findChild(el, "w:vMerge");
|
|
3352
|
+
if (vMerge) opts.verticalMerge = attr(vMerge, "w:val") === "restart" ? "restart" : "continue";
|
|
3353
|
+
const vAlign = findChild(el, "w:vAlign");
|
|
3354
|
+
if (vAlign) {
|
|
3355
|
+
const val = attr(vAlign, "w:val");
|
|
3356
|
+
if (val) opts.verticalAlign = val;
|
|
3357
|
+
}
|
|
3358
|
+
const shd = findChild(el, "w:shd");
|
|
3359
|
+
if (shd) {
|
|
3360
|
+
const shading = {};
|
|
3361
|
+
const fill = attr(shd, "w:fill");
|
|
3362
|
+
if (fill) shading.fill = fill;
|
|
3363
|
+
const color = attr(shd, "w:color");
|
|
3364
|
+
if (color) shading.color = color;
|
|
3365
|
+
const val = attr(shd, "w:val");
|
|
3366
|
+
if (val) shading.type = val;
|
|
3367
|
+
if (Object.keys(shading).length > 0) opts.shading = shading;
|
|
3368
|
+
}
|
|
3369
|
+
const tcBorders = findChild(el, "w:tcBorders");
|
|
3370
|
+
if (tcBorders) {
|
|
3371
|
+
const borders = {};
|
|
3372
|
+
for (const side of [
|
|
3373
|
+
"top",
|
|
3374
|
+
"bottom",
|
|
3375
|
+
"left",
|
|
3376
|
+
"right"
|
|
3377
|
+
]) {
|
|
3378
|
+
const sideEl = findChild(tcBorders, `w:${side}`);
|
|
3379
|
+
if (sideEl) {
|
|
3380
|
+
const b = {};
|
|
3381
|
+
const val = attr(sideEl, "w:val");
|
|
3382
|
+
if (val) b.style = val;
|
|
3383
|
+
const color = attr(sideEl, "w:color");
|
|
3384
|
+
if (color) b.color = color;
|
|
3385
|
+
const sz = attrNum(sideEl, "w:sz");
|
|
3386
|
+
if (sz !== void 0) b.size = sz;
|
|
3387
|
+
borders[side] = b;
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
if (Object.keys(borders).length > 0) opts.borders = borders;
|
|
3391
|
+
}
|
|
3392
|
+
if (findChild(el, "w:noWrap")) opts.noWrap = true;
|
|
3393
|
+
const tcMar = findChild(el, "w:tcMar");
|
|
3394
|
+
if (tcMar) {
|
|
3395
|
+
const margins = {};
|
|
3396
|
+
let marginUnitType;
|
|
3397
|
+
for (const side of [
|
|
3398
|
+
"top",
|
|
3399
|
+
"bottom",
|
|
3400
|
+
"left",
|
|
3401
|
+
"right"
|
|
3402
|
+
]) {
|
|
3403
|
+
const sideEl = findChild(tcMar, `w:${side}`);
|
|
3404
|
+
if (sideEl) {
|
|
3405
|
+
const size = attrNum(sideEl, "w:w");
|
|
3406
|
+
const type = attr(sideEl, "w:type");
|
|
3407
|
+
if (size !== void 0) {
|
|
3408
|
+
margins[side] = size;
|
|
3409
|
+
if (type && !marginUnitType) marginUnitType = type;
|
|
3410
|
+
}
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
if (marginUnitType) margins.marginUnitType = marginUnitType;
|
|
3414
|
+
if (Object.keys(margins).length > 0) opts.margins = margins;
|
|
3415
|
+
}
|
|
3416
|
+
const textDirection = findChild(el, "w:textDirection");
|
|
3417
|
+
if (textDirection) {
|
|
3418
|
+
const val = attr(textDirection, "w:val");
|
|
3419
|
+
if (val) opts.textDirection = val;
|
|
3420
|
+
}
|
|
3421
|
+
return opts;
|
|
3422
|
+
}
|
|
3423
|
+
function parseTableCellEl(el, ctx) {
|
|
3424
|
+
const opts = {};
|
|
3425
|
+
const tcPr = findChild(el, "w:tcPr");
|
|
3426
|
+
if (tcPr) Object.assign(opts, parseTableCellPropertiesEl(tcPr));
|
|
3427
|
+
const childElements = [];
|
|
3428
|
+
for (const child of el.elements ?? []) switch (child.name) {
|
|
3429
|
+
case "w:tcPr": break;
|
|
3430
|
+
case "w:p":
|
|
3431
|
+
case "w:tbl":
|
|
3432
|
+
if (_parseChild) childElements.push(_parseChild(child, ctx));
|
|
3433
|
+
break;
|
|
3434
|
+
default: break;
|
|
3435
|
+
}
|
|
3436
|
+
opts.children = childElements;
|
|
3437
|
+
return opts;
|
|
3438
|
+
}
|
|
3439
|
+
function parseTableRowEl(el, ctx) {
|
|
3440
|
+
const opts = {};
|
|
3441
|
+
const trPr = findChild(el, "w:trPr");
|
|
3442
|
+
if (trPr) Object.assign(opts, parseTableRowPropertiesEl(trPr));
|
|
3443
|
+
const childCells = [];
|
|
3444
|
+
for (const child of el.elements ?? []) if (child.name === "w:tc") childCells.push(parseTableCellEl(child, ctx));
|
|
3445
|
+
opts.cells = childCells;
|
|
3446
|
+
return opts;
|
|
3447
|
+
}
|
|
3448
|
+
function parseTableEl(el, ctx) {
|
|
3449
|
+
const opts = {};
|
|
3450
|
+
const tblPr = findChild(el, "w:tblPr");
|
|
3451
|
+
if (tblPr) Object.assign(opts, parseTablePropertiesEl(tblPr));
|
|
3452
|
+
const colWidths = parseColumnWidthsEl(el);
|
|
3453
|
+
if (colWidths.length > 0) opts.columnWidths = colWidths;
|
|
3454
|
+
const rows = [];
|
|
3455
|
+
for (const child of el.elements ?? []) if (child.name === "w:tr") rows.push(parseTableRowEl(child, ctx));
|
|
3456
|
+
opts.rows = rows;
|
|
3457
|
+
return opts;
|
|
3458
|
+
}
|
|
3459
|
+
//#endregion
|
|
3460
|
+
//#region src/parts/document/document-attributes.ts
|
|
3461
|
+
/**
|
|
3462
|
+
* Document attributes module for WordprocessingML documents.
|
|
3463
|
+
*
|
|
3464
|
+
* This module defines the XML namespace declarations used in OOXML documents.
|
|
3465
|
+
* These namespaces are required for proper document parsing and generation.
|
|
3466
|
+
*
|
|
3467
|
+
* Reference: http://officeopenxml.com/anatomyofOOXML.php
|
|
3468
|
+
*
|
|
3469
|
+
* @module
|
|
3470
|
+
*/
|
|
3471
|
+
/**
|
|
3472
|
+
* XML namespace URIs used in WordprocessingML documents.
|
|
3473
|
+
*
|
|
3474
|
+
* These namespaces define the various XML schemas that can be referenced
|
|
3475
|
+
* in a document, including WordprocessingML, DrawingML, VML, and others.
|
|
3476
|
+
*/
|
|
3477
|
+
const DocumentAttributeNamespaces = {
|
|
3478
|
+
aink: "http://schemas.microsoft.com/office/drawing/2016/ink",
|
|
3479
|
+
am3d: "http://schemas.microsoft.com/office/drawing/2017/model3d",
|
|
3480
|
+
cp: "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
|
|
3481
|
+
cx: "http://schemas.microsoft.com/office/drawing/2014/chartex",
|
|
3482
|
+
cx1: "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex",
|
|
3483
|
+
cx2: "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex",
|
|
3484
|
+
cx3: "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex",
|
|
3485
|
+
cx4: "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex",
|
|
3486
|
+
cx5: "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex",
|
|
3487
|
+
cx6: "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex",
|
|
3488
|
+
cx7: "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex",
|
|
3489
|
+
cx8: "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex",
|
|
3490
|
+
dc: "http://purl.org/dc/elements/1.1/",
|
|
3491
|
+
dcmitype: "http://purl.org/dc/dcmitype/",
|
|
3492
|
+
dcterms: "http://purl.org/dc/terms/",
|
|
3493
|
+
m: "http://schemas.openxmlformats.org/officeDocument/2006/math",
|
|
3494
|
+
mc: "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
|
3495
|
+
o: "urn:schemas-microsoft-com:office:office",
|
|
3496
|
+
r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
3497
|
+
v: "urn:schemas-microsoft-com:vml",
|
|
3498
|
+
w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
|
3499
|
+
w10: "urn:schemas-microsoft-com:office:word",
|
|
3500
|
+
w14: "http://schemas.microsoft.com/office/word/2010/wordml",
|
|
3501
|
+
w15: "http://schemas.microsoft.com/office/word/2012/wordml",
|
|
3502
|
+
w16: "http://schemas.microsoft.com/office/word/2018/wordml",
|
|
3503
|
+
w16cex: "http://schemas.microsoft.com/office/word/2018/wordml/cex",
|
|
3504
|
+
w16cid: "http://schemas.microsoft.com/office/word/2016/wordml/cid",
|
|
3505
|
+
w16sdtdh: "http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash",
|
|
3506
|
+
w16se: "http://schemas.microsoft.com/office/word/2015/wordml/symex",
|
|
3507
|
+
wne: "http://schemas.microsoft.com/office/word/2006/wordml",
|
|
3508
|
+
wp: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
|
|
3509
|
+
wp14: "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
|
|
3510
|
+
wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
|
|
3511
|
+
wpg: "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
|
|
3512
|
+
wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
|
|
3513
|
+
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
|
|
3514
|
+
xsi: "http://www.w3.org/2001/XMLSchema-instance"
|
|
3515
|
+
};
|
|
3516
|
+
//#endregion
|
|
3517
|
+
//#region src/parts/document/body/section-properties/properties/page-size.ts
|
|
3518
|
+
/**
|
|
3519
|
+
* This simple type specifies the orientation of all pages in the parent section. This information is used to determine the actual paper size to use when printing the file.
|
|
3520
|
+
*
|
|
3521
|
+
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_PageOrientation_topic_ID0EKBK3.html
|
|
3522
|
+
*
|
|
3523
|
+
* ## XSD Schema
|
|
3524
|
+
*
|
|
3525
|
+
* ```xml
|
|
3526
|
+
* <xsd:simpleType name="ST_PageOrientation">
|
|
3527
|
+
* <xsd:restriction base="xsd:string">
|
|
3528
|
+
* <xsd:enumeration value="portrait"/>
|
|
3529
|
+
* <xsd:enumeration value="landscape"/>
|
|
3530
|
+
* </xsd:restriction>
|
|
3531
|
+
* </xsd:simpleType>
|
|
3532
|
+
* ```
|
|
3533
|
+
*
|
|
3534
|
+
* @publicApi
|
|
3535
|
+
*/
|
|
3536
|
+
const PageOrientation = {
|
|
3537
|
+
/**
|
|
3538
|
+
* ## Portrait Mode
|
|
3539
|
+
*
|
|
3540
|
+
* Specifies that pages in this section shall be printed in portrait mode.
|
|
3541
|
+
*/
|
|
3542
|
+
PORTRAIT: "portrait",
|
|
3543
|
+
/**
|
|
3544
|
+
* ## Landscape Mode
|
|
3545
|
+
*
|
|
3546
|
+
* Specifies that pages in this section shall be printed in landscape mode, which prints the page contents with a 90 degree rotation with respect to the normal page orientation.
|
|
3547
|
+
*/
|
|
3548
|
+
LANDSCAPE: "landscape"
|
|
3549
|
+
};
|
|
3550
|
+
/**
|
|
3551
|
+
* This element specifies the properties (size and orientation) for all pages in the current section.
|
|
3552
|
+
*
|
|
3553
|
+
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_pgSz_topic_ID0ENEDT.html?hl=pgsz%2Cpage%2Csize
|
|
3554
|
+
*
|
|
3555
|
+
* ## XSD Schema
|
|
3556
|
+
*
|
|
3557
|
+
* ```xml
|
|
3558
|
+
* <xsd:complexType name="CT_PageSz">
|
|
3559
|
+
* <xsd:attribute name="w" type="s:ST_TwipsMeasure"/>
|
|
3560
|
+
* <xsd:attribute name="h" type="s:ST_TwipsMeasure"/>
|
|
3561
|
+
* <xsd:attribute name="orient" type="ST_PageOrientation" use="optional"/>
|
|
3562
|
+
* <xsd:attribute name="code" type="ST_DecimalNumber" use="optional"/>
|
|
3563
|
+
* </xsd:complexType>
|
|
3564
|
+
* ```
|
|
3565
|
+
*/
|
|
3566
|
+
const createPageSize = ({ width, height, orientation, code }) => {
|
|
3567
|
+
const widthTwips = twipsMeasureValue(width);
|
|
3568
|
+
const heightTwips = twipsMeasureValue(height);
|
|
3569
|
+
return element("w:pgSz", {
|
|
3570
|
+
"w:code": code,
|
|
3571
|
+
"w:h": orientation === PageOrientation.LANDSCAPE ? widthTwips : heightTwips,
|
|
3572
|
+
"w:orient": orientation,
|
|
3573
|
+
"w:w": orientation === PageOrientation.LANDSCAPE ? heightTwips : widthTwips
|
|
3574
|
+
});
|
|
3575
|
+
};
|
|
3576
|
+
//#endregion
|
|
3577
|
+
//#region src/parts/document/body/section-properties/properties/page-text-direction.ts
|
|
3578
|
+
/**
|
|
3579
|
+
* Page text direction module for WordprocessingML section properties.
|
|
3580
|
+
*
|
|
3581
|
+
* Defines text flow direction for pages in a section.
|
|
3582
|
+
*
|
|
3583
|
+
* Reference: http://officeopenxml.com/WPsectionPr.php
|
|
3584
|
+
*
|
|
3585
|
+
* @module
|
|
3586
|
+
*/
|
|
3587
|
+
/**
|
|
3588
|
+
* Specifies the text flow direction for pages in a section.
|
|
3589
|
+
*
|
|
3590
|
+
* This controls whether text flows horizontally (left-to-right) or
|
|
3591
|
+
* vertically (top-to-bottom), commonly used for East Asian languages.
|
|
3592
|
+
*/
|
|
3593
|
+
const PageTextDirectionType = {
|
|
3594
|
+
/** Left-to-right, top-to-bottom (standard Western text flow) */
|
|
3595
|
+
LEFT_TO_RIGHT_TOP_TO_BOTTOM: "lrTb",
|
|
3596
|
+
/** Top-to-bottom, right-to-left (vertical East Asian text flow) */
|
|
3597
|
+
TOP_TO_BOTTOM_RIGHT_TO_LEFT: "tbRl"
|
|
3598
|
+
};
|
|
3599
|
+
//#endregion
|
|
3600
|
+
//#region src/parts/document/body/section-properties/section-properties.ts
|
|
3601
|
+
const sectionMarginDefaults = {
|
|
3602
|
+
TOP: 1440,
|
|
3603
|
+
RIGHT: 1800,
|
|
3604
|
+
BOTTOM: 1440,
|
|
3605
|
+
LEFT: 1800,
|
|
3606
|
+
HEADER: 851,
|
|
3607
|
+
FOOTER: 992,
|
|
3608
|
+
GUTTER: 0
|
|
3609
|
+
};
|
|
3610
|
+
const sectionPageSizeDefaults = {
|
|
3611
|
+
WIDTH: 11906,
|
|
3612
|
+
HEIGHT: 16838,
|
|
3613
|
+
ORIENTATION: PageOrientation.PORTRAIT
|
|
3614
|
+
};
|
|
3615
|
+
//#endregion
|
|
3616
|
+
//#region src/parts/document/body/section-properties/properties/doc-grid.ts
|
|
3617
|
+
/**
|
|
3618
|
+
* Specifies the type of the current document grid, which defines the grid behavior.
|
|
3619
|
+
*
|
|
3620
|
+
* The grid can define a grid which snaps all East Asian characters to grid positions, but leaves Latin text with its default spacing; a grid which adds the specified character pitch to all characters on each row; or a grid which affects only the line pitch for the current section.
|
|
3621
|
+
*
|
|
3622
|
+
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_DocGrid_topic_ID0ELYP2.html
|
|
3623
|
+
*
|
|
3624
|
+
* ## XSD Schema
|
|
3625
|
+
* ```xml
|
|
3626
|
+
* <xsd:simpleType name="ST_DocGrid">
|
|
3627
|
+
* <xsd:restriction base="xsd:string">
|
|
3628
|
+
* <xsd:enumeration value="default"/>
|
|
3629
|
+
* <xsd:enumeration value="lines"/>
|
|
3630
|
+
* <xsd:enumeration value="linesAndChars"/>
|
|
3631
|
+
* <xsd:enumeration value="snapToChars"/>
|
|
3632
|
+
* </xsd:restriction>
|
|
3633
|
+
* </xsd:simpleType>
|
|
3634
|
+
* ```
|
|
3635
|
+
*/
|
|
3636
|
+
const DocumentGridType = {
|
|
3637
|
+
/**
|
|
3638
|
+
* Specifies that no document grid shall be applied to the contents of the current section in the document.
|
|
3639
|
+
*/
|
|
3640
|
+
DEFAULT: "default",
|
|
3641
|
+
/**
|
|
3642
|
+
* Specifies that the parent section shall have additional line pitch added to each line within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain the specified number of lines per page.
|
|
3643
|
+
*/
|
|
3644
|
+
LINES: "lines",
|
|
3645
|
+
/**
|
|
3646
|
+
* Specifies that the parent section shall have both the additional line pitch and character pitch added to each line and character within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain a specific number of lines per page and characters per line.
|
|
3647
|
+
*
|
|
3648
|
+
* When this value is set, the input specified via the user interface may be allowed in exact number of line/character pitch units. */
|
|
3649
|
+
LINES_AND_CHARS: "linesAndChars",
|
|
3650
|
+
/**
|
|
3651
|
+
* Specifies that the parent section shall have both the additional line pitch and character pitch added to each line and character within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain a specific number of lines per page and characters per line.
|
|
3652
|
+
*
|
|
3653
|
+
* When this value is set, the input specified via the user interface may be restricted to the number of lines per page and characters per line, with the consumer or producer translating this information based on the current font data to get the resulting line and character pitch values
|
|
3654
|
+
*/
|
|
3655
|
+
SNAP_TO_CHARS: "snapToChars"
|
|
3656
|
+
};
|
|
3657
|
+
/**
|
|
3658
|
+
* This element specifies the settings for the document grid, which enables precise layout of full-width East Asian language characters within a document by specifying the desired number of characters per line and lines per page for all East Asian text content in this section.
|
|
3659
|
+
*
|
|
3660
|
+
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_docGrid_topic_ID0EHU5S.html
|
|
3661
|
+
*
|
|
3662
|
+
* ```xml
|
|
3663
|
+
* <xsd:complexType name="CT_DocGrid">
|
|
3664
|
+
* <xsd:attribute name="type" type="ST_DocGrid"/>
|
|
3665
|
+
* <xsd:attribute name="linePitch" type="ST_DecimalNumber"/>
|
|
3666
|
+
* <xsd:attribute name="charSpace" type="ST_DecimalNumber"/>
|
|
3667
|
+
* </xsd:complexType>
|
|
3668
|
+
* ```
|
|
3669
|
+
* @returns
|
|
3670
|
+
*/
|
|
3671
|
+
const createDocumentGrid = ({ type, linePitch, charSpace }) => element("w:docGrid", {
|
|
3672
|
+
"w:charSpace": charSpace ? decimalNumber(charSpace) : void 0,
|
|
3673
|
+
"w:linePitch": decimalNumber(linePitch),
|
|
3674
|
+
"w:type": type
|
|
3675
|
+
});
|
|
3676
|
+
//#endregion
|
|
3677
|
+
//#region src/parts/document/body/section-properties/properties/page-number.ts
|
|
3678
|
+
/**
|
|
3679
|
+
* Specifies the separator character between chapter number and page number.
|
|
3680
|
+
*
|
|
3681
|
+
* ## XSD Schema
|
|
3682
|
+
* ```xml
|
|
3683
|
+
* <xsd:simpleType name="ST_ChapterSep">
|
|
3684
|
+
* <xsd:restriction base="xsd:string">
|
|
3685
|
+
* <xsd:enumeration value="hyphen"/>
|
|
3686
|
+
* <xsd:enumeration value="period"/>
|
|
3687
|
+
* <xsd:enumeration value="colon"/>
|
|
3688
|
+
* <xsd:enumeration value="emDash"/>
|
|
3689
|
+
* <xsd:enumeration value="enDash"/>
|
|
3690
|
+
* </xsd:restriction>
|
|
3691
|
+
* </xsd:simpleType>
|
|
3692
|
+
* ```
|
|
3693
|
+
*
|
|
3694
|
+
* @publicApi
|
|
3695
|
+
*/
|
|
3696
|
+
const PageNumberSeparator = {
|
|
3697
|
+
/** Hyphen separator (-) */
|
|
3698
|
+
HYPHEN: "hyphen",
|
|
3699
|
+
/** Period separator (.) */
|
|
3700
|
+
PERIOD: "period",
|
|
3701
|
+
/** Colon separator (:) */
|
|
3702
|
+
COLON: "colon",
|
|
3703
|
+
/** Em dash separator (—) */
|
|
3704
|
+
EM_DASH: "emDash",
|
|
3705
|
+
/** En dash separator (–) */
|
|
3706
|
+
EN_DASH: "enDash"
|
|
3707
|
+
};
|
|
3708
|
+
/**
|
|
3709
|
+
* Creates page numbering settings (pgNumType) for a document section.
|
|
3710
|
+
*
|
|
3711
|
+
* This element specifies the page numbering format and starting value
|
|
3712
|
+
* for all pages in a section.
|
|
3713
|
+
*
|
|
3714
|
+
* Reference: http://officeopenxml.com/WPSectionPgNumType.php
|
|
3715
|
+
*
|
|
3716
|
+
* ## XSD Schema
|
|
3717
|
+
* ```xml
|
|
3718
|
+
* <xsd:complexType name="CT_PageNumber">
|
|
3719
|
+
* <xsd:attribute name="fmt" type="ST_NumberFormat" use="optional" default="decimal"/>
|
|
3720
|
+
* <xsd:attribute name="start" type="ST_DecimalNumber" use="optional"/>
|
|
3721
|
+
* <xsd:attribute name="chapStyle" type="ST_DecimalNumber" use="optional"/>
|
|
3722
|
+
* <xsd:attribute name="chapSep" type="ST_ChapterSep" use="optional" default="hyphen"/>
|
|
3723
|
+
* </xsd:complexType>
|
|
3724
|
+
* ```
|
|
3725
|
+
*
|
|
3726
|
+
* @example
|
|
3727
|
+
* ```typescript
|
|
3728
|
+
* // Start page numbering at 5 with lowercase roman numerals
|
|
3729
|
+
* createPageNumberType({
|
|
3730
|
+
* start: 5,
|
|
3731
|
+
* formatType: NumberFormat.LOWER_ROMAN
|
|
3732
|
+
* });
|
|
3733
|
+
* ```
|
|
3734
|
+
*/
|
|
3735
|
+
const createPageNumberType = ({ start, formatType, separator, chapStyle }) => element("w:pgNumType", {
|
|
3736
|
+
"w:chapStyle": chapStyle === void 0 ? void 0 : decimalNumber(chapStyle),
|
|
3737
|
+
"w:fmt": formatType,
|
|
3738
|
+
"w:chapSep": separator,
|
|
3739
|
+
"w:start": start === void 0 ? void 0 : decimalNumber(start)
|
|
3740
|
+
});
|
|
3741
|
+
//#endregion
|
|
3742
|
+
//#region src/parts/document/body/section-properties/properties/page-borders.ts
|
|
3743
|
+
/**
|
|
3744
|
+
* Specifies which pages display the page border.
|
|
3745
|
+
*
|
|
3746
|
+
* ## XSD Schema
|
|
3747
|
+
* ```xml
|
|
3748
|
+
* <xsd:simpleType name="ST_PageBorderDisplay">
|
|
3749
|
+
* <xsd:restriction base="xsd:string">
|
|
3750
|
+
* <xsd:enumeration value="allPages"/>
|
|
3751
|
+
* <xsd:enumeration value="firstPage"/>
|
|
3752
|
+
* <xsd:enumeration value="notFirstPage"/>
|
|
3753
|
+
* </xsd:restriction>
|
|
3754
|
+
* </xsd:simpleType>
|
|
3755
|
+
* ```
|
|
3756
|
+
*
|
|
3757
|
+
* @publicApi
|
|
3758
|
+
*/
|
|
3759
|
+
const PageBorderDisplay = {
|
|
3760
|
+
/** Display border on all pages */
|
|
3761
|
+
ALL_PAGES: "allPages",
|
|
3762
|
+
/** Display border only on first page */
|
|
3763
|
+
FIRST_PAGE: "firstPage",
|
|
3764
|
+
/** Display border on all pages except first page */
|
|
3765
|
+
NOT_FIRST_PAGE: "notFirstPage"
|
|
3766
|
+
};
|
|
3767
|
+
/**
|
|
3768
|
+
* Specifies whether page border is positioned relative to page edge or text.
|
|
3769
|
+
*
|
|
3770
|
+
* ## XSD Schema
|
|
3771
|
+
* ```xml
|
|
3772
|
+
* <xsd:simpleType name="ST_PageBorderOffset">
|
|
3773
|
+
* <xsd:restriction base="xsd:string">
|
|
3774
|
+
* <xsd:enumeration value="page"/>
|
|
3775
|
+
* <xsd:enumeration value="text"/>
|
|
3776
|
+
* </xsd:restriction>
|
|
3777
|
+
* </xsd:simpleType>
|
|
3778
|
+
* ```
|
|
3779
|
+
*
|
|
3780
|
+
* @publicApi
|
|
3781
|
+
*/
|
|
3782
|
+
const PageBorderOffsetFrom = {
|
|
3783
|
+
/** Position border relative to page edge */
|
|
3784
|
+
PAGE: "page",
|
|
3785
|
+
/** Position border relative to text (default) */
|
|
3786
|
+
TEXT: "text"
|
|
3787
|
+
};
|
|
3788
|
+
/**
|
|
3789
|
+
* Specifies z-order of page border relative to intersecting objects.
|
|
3790
|
+
*
|
|
3791
|
+
* ## XSD Schema
|
|
3792
|
+
* ```xml
|
|
3793
|
+
* <xsd:simpleType name="ST_PageBorderZOrder">
|
|
3794
|
+
* <xsd:restriction base="xsd:string">
|
|
3795
|
+
* <xsd:enumeration value="front"/>
|
|
3796
|
+
* <xsd:enumeration value="back"/>
|
|
3797
|
+
* </xsd:restriction>
|
|
3798
|
+
* </xsd:simpleType>
|
|
3799
|
+
* ```
|
|
3800
|
+
*
|
|
3801
|
+
* @publicApi
|
|
3802
|
+
*/
|
|
3803
|
+
const PageBorderZOrder = {
|
|
3804
|
+
/** Display border behind page contents */
|
|
3805
|
+
BACK: "back",
|
|
3806
|
+
/** Display border in front of page contents (default) */
|
|
3807
|
+
FRONT: "front"
|
|
3808
|
+
};
|
|
3809
|
+
//#endregion
|
|
3810
|
+
//#region src/parts/document/body/section-properties/properties/page-margin.ts
|
|
3811
|
+
/**
|
|
3812
|
+
* Page margin module for WordprocessingML section properties.
|
|
3813
|
+
*
|
|
3814
|
+
* Defines page margins for document sections.
|
|
3815
|
+
*
|
|
3816
|
+
* Reference: http://officeopenxml.com/WPsectionPr.php
|
|
3817
|
+
*
|
|
3818
|
+
* @module
|
|
3819
|
+
*/
|
|
3820
|
+
/**
|
|
3821
|
+
* Creates page margins (pgMar) for a document section.
|
|
3822
|
+
*
|
|
3823
|
+
* This element specifies the page margins for all pages in a section,
|
|
3824
|
+
* including top, bottom, left, right, header, footer, and gutter margins.
|
|
3825
|
+
*
|
|
3826
|
+
* Reference: http://officeopenxml.com/WPsectionPr.php
|
|
3827
|
+
*
|
|
3828
|
+
* ## XSD Schema
|
|
3829
|
+
* ```xml
|
|
3830
|
+
* <xsd:complexType name="CT_PageMar">
|
|
3831
|
+
* <xsd:attribute name="top" type="ST_SignedTwipsMeasure" use="required"/>
|
|
3832
|
+
* <xsd:attribute name="right" type="s:ST_TwipsMeasure" use="required"/>
|
|
3833
|
+
* <xsd:attribute name="bottom" type="ST_SignedTwipsMeasure" use="required"/>
|
|
3834
|
+
* <xsd:attribute name="left" type="s:ST_TwipsMeasure" use="required"/>
|
|
3835
|
+
* <xsd:attribute name="header" type="s:ST_TwipsMeasure" use="required"/>
|
|
3836
|
+
* <xsd:attribute name="footer" type="s:ST_TwipsMeasure" use="required"/>
|
|
3837
|
+
* <xsd:attribute name="gutter" type="s:ST_TwipsMeasure" use="required"/>
|
|
3838
|
+
* </xsd:complexType>
|
|
3839
|
+
* ```
|
|
3840
|
+
*
|
|
3841
|
+
* @example
|
|
3842
|
+
* ```typescript
|
|
3843
|
+
* // Create page margins with 1 inch margins (1440 twips = 1 inch)
|
|
3844
|
+
* createPageMargin(1440, 1440, 1440, 1440, 720, 720, 0);
|
|
3845
|
+
* ```
|
|
3846
|
+
*/
|
|
3847
|
+
const createPageMargin = (top, right, bottom, left, header, footer, gutter) => `<w:pgMar w:bottom="${signedTwipsMeasureValue(bottom)}" w:footer="${twipsMeasureValue(footer)}" w:gutter="${twipsMeasureValue(gutter)}" w:header="${twipsMeasureValue(header)}" w:left="${twipsMeasureValue(left)}" w:right="${twipsMeasureValue(right)}" w:top="${signedTwipsMeasureValue(top)}"/>`;
|
|
3848
|
+
//#endregion
|
|
3849
|
+
//#region src/parts/document/body/section-properties/properties/line-number.ts
|
|
3850
|
+
/**
|
|
3851
|
+
* This simple type specifies when the line numbering in the parent section shall be reset to its restart value. The line numbering increments for each line (even if the line number itself is not displayed) until it reaches the restart point specified by this element.
|
|
3852
|
+
*
|
|
3853
|
+
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_LineNumberRestart_topic_ID0EUS42.html
|
|
3854
|
+
*
|
|
3855
|
+
* ## XSD Schema
|
|
3856
|
+
*
|
|
3857
|
+
* ```xml
|
|
3858
|
+
* <xsd:simpleType name="ST_LineNumberRestart">
|
|
3859
|
+
* <xsd:restriction base="xsd:string">
|
|
3860
|
+
* <xsd:enumeration value="newPage"/>
|
|
3861
|
+
* <xsd:enumeration value="newSection"/>
|
|
3862
|
+
* <xsd:enumeration value="continuous"/>
|
|
3863
|
+
* </xsd:restriction>
|
|
3864
|
+
* </xsd:simpleType>
|
|
3865
|
+
* ```
|
|
3866
|
+
*
|
|
3867
|
+
* @publicApi
|
|
3868
|
+
*/
|
|
3869
|
+
const LineNumberRestartFormat = {
|
|
3870
|
+
/**
|
|
3871
|
+
* ## Restart Line Numbering on Each Page
|
|
3872
|
+
*
|
|
3873
|
+
* Specifies that line numbering for the parent section shall restart to the starting value whenever a new page is displayed.
|
|
3874
|
+
*/
|
|
3875
|
+
NEW_PAGE: "newPage",
|
|
3876
|
+
/**
|
|
3877
|
+
* ## Restart Line Numbering for Each Section
|
|
3878
|
+
*
|
|
3879
|
+
* Specifies that line numbering for the parent section shall restart to the starting value whenever the parent begins.
|
|
3880
|
+
*/
|
|
3881
|
+
NEW_SECTION: "newSection",
|
|
3882
|
+
/**
|
|
3883
|
+
* ## Continue Line Numbering From Previous Section
|
|
3884
|
+
*
|
|
3885
|
+
* Specifies that line numbering for the parent section shall continue from the line numbering from the end of the previous section, if any.
|
|
3886
|
+
*/
|
|
3887
|
+
CONTINUOUS: "continuous"
|
|
3888
|
+
};
|
|
3889
|
+
/**
|
|
3890
|
+
* This element specifies the settings for line numbering to be displayed before each column of text in this section in the document.
|
|
3891
|
+
*
|
|
3892
|
+
* References:
|
|
3893
|
+
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_lnNumType_topic_ID0EVRAT.html
|
|
3894
|
+
* - http://officeopenxml.com/WPsectionLineNumbering.php
|
|
3895
|
+
*
|
|
3896
|
+
* ## XSD Schema
|
|
3897
|
+
*
|
|
3898
|
+
* ```xml
|
|
3899
|
+
* <xsd:complexType name="CT_LineNumber">
|
|
3900
|
+
* <xsd:attribute name="countBy" type="ST_DecimalNumber" use="optional"/>
|
|
3901
|
+
* <xsd:attribute name="start" type="ST_DecimalNumber" use="optional" default="1"/>
|
|
3902
|
+
* <xsd:attribute name="distance" type="s:ST_TwipsMeasure" use="optional"/>
|
|
3903
|
+
* <xsd:attribute name="restart" type="ST_LineNumberRestart" use="optional" default="newPage"/>
|
|
3904
|
+
* </xsd:complexType>
|
|
3905
|
+
* ```
|
|
3906
|
+
*/
|
|
3907
|
+
const createLineNumberType = ({ countBy, start, restart, distance }) => element("w:lnNumType", {
|
|
3908
|
+
"w:countBy": countBy === void 0 ? void 0 : decimalNumber(countBy),
|
|
3909
|
+
"w:distance": distance === void 0 ? void 0 : twipsMeasureValue(distance),
|
|
3910
|
+
"w:restart": restart,
|
|
3911
|
+
"w:start": start === void 0 ? void 0 : decimalNumber(start)
|
|
3912
|
+
});
|
|
3913
|
+
//#endregion
|
|
3914
|
+
//#region src/parts/document/body/section-properties/properties/section-type.ts
|
|
3915
|
+
/**
|
|
3916
|
+
* Section type module for WordprocessingML section properties.
|
|
3917
|
+
*
|
|
3918
|
+
* Defines how a section begins relative to the previous section.
|
|
3919
|
+
*
|
|
3920
|
+
* Reference: http://officeopenxml.com/WPsection.php
|
|
3921
|
+
*
|
|
3922
|
+
* @module
|
|
3923
|
+
*/
|
|
3924
|
+
/**
|
|
3925
|
+
* Specifies the type of section break.
|
|
3926
|
+
*
|
|
3927
|
+
* This determines where the section begins relative to the previous section.
|
|
3928
|
+
*
|
|
3929
|
+
* ## XSD Schema
|
|
3930
|
+
* ```xml
|
|
3931
|
+
* <xsd:simpleType name="ST_SectionMark">
|
|
3932
|
+
* <xsd:restriction base="xsd:string">
|
|
3933
|
+
* <xsd:enumeration value="nextPage"/>
|
|
3934
|
+
* <xsd:enumeration value="nextColumn"/>
|
|
3935
|
+
* <xsd:enumeration value="continuous"/>
|
|
3936
|
+
* <xsd:enumeration value="evenPage"/>
|
|
3937
|
+
* <xsd:enumeration value="oddPage"/>
|
|
3938
|
+
* </xsd:restriction>
|
|
3939
|
+
* </xsd:simpleType>
|
|
3940
|
+
* ```
|
|
3941
|
+
*
|
|
3942
|
+
* @publicApi
|
|
3943
|
+
*/
|
|
3944
|
+
const SectionType = {
|
|
3945
|
+
/** Section begins on the next page */
|
|
3946
|
+
NEXT_PAGE: "nextPage",
|
|
3947
|
+
/** Section begins on the next column */
|
|
3948
|
+
NEXT_COLUMN: "nextColumn",
|
|
3949
|
+
/** Section begins immediately following the previous section */
|
|
3950
|
+
CONTINUOUS: "continuous",
|
|
3951
|
+
/** Section begins on the next even-numbered page */
|
|
3952
|
+
EVEN_PAGE: "evenPage",
|
|
3953
|
+
/** Section begins on the next odd-numbered page */
|
|
3954
|
+
ODD_PAGE: "oddPage"
|
|
3955
|
+
};
|
|
3956
|
+
/**
|
|
3957
|
+
* Creates section type (type) for a document section.
|
|
3958
|
+
*
|
|
3959
|
+
* This element specifies the type of section break, which determines
|
|
3960
|
+
* where the new section begins relative to the previous section.
|
|
3961
|
+
*
|
|
3962
|
+
* Reference: http://officeopenxml.com/WPsection.php
|
|
3963
|
+
*
|
|
3964
|
+
* ## XSD Schema
|
|
3965
|
+
* ```xml
|
|
3966
|
+
* <xsd:complexType name="CT_SectType">
|
|
3967
|
+
* <xsd:attribute name="val" type="ST_SectionMark"/>
|
|
3968
|
+
* </xsd:complexType>
|
|
3969
|
+
* ```
|
|
3970
|
+
*
|
|
3971
|
+
* @example
|
|
3972
|
+
* ```typescript
|
|
3973
|
+
* // Create a continuous section (no page break)
|
|
3974
|
+
* createSectionType(SectionType.CONTINUOUS);
|
|
3975
|
+
*
|
|
3976
|
+
* // Create a section that starts on next odd page
|
|
3977
|
+
* createSectionType(SectionType.ODD_PAGE);
|
|
3978
|
+
* ```
|
|
3979
|
+
*/
|
|
3980
|
+
const createSectionType = (value) => `<w:type w:val="${value}"/>`;
|
|
3981
|
+
//#endregion
|
|
3982
|
+
//#region src/parts/document/body/section-properties/properties/header-footer-reference.ts
|
|
3983
|
+
/**
|
|
3984
|
+
* This simple type specifies the possible types of headers and footers which may be specified for a given header or footer reference in a document. This value determines the page(s) on which the current header or footer shall be displayed.
|
|
3985
|
+
*
|
|
3986
|
+
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_HdrFtr_topic_ID0E2UW2.html
|
|
3987
|
+
*
|
|
3988
|
+
* ## XSD Schema
|
|
3989
|
+
* ```xml
|
|
3990
|
+
* <xsd:simpleType name="ST_HdrFtr">
|
|
3991
|
+
* <xsd:restriction base="xsd:string">
|
|
3992
|
+
* <xsd:enumeration value="even"/>
|
|
3993
|
+
* <xsd:enumeration value="default"/>
|
|
3994
|
+
* <xsd:enumeration value="first"/>
|
|
3995
|
+
* </xsd:restriction>
|
|
3996
|
+
* </xsd:simpleType>
|
|
3997
|
+
* ```
|
|
3998
|
+
*/
|
|
3999
|
+
const HeaderFooterReferenceType = {
|
|
4000
|
+
/** Specifies that this header or footer shall appear on every page in this section which is not overridden with a specific `even` or `first` page header/footer. In a section with all three types specified, this type shall be used on all odd numbered pages (counting from the `first` page in the section, not the section numbering). */
|
|
4001
|
+
DEFAULT: "default",
|
|
4002
|
+
/** Specifies that this header or footer shall appear on the first page in this section. The appearance of this header or footer is contingent on the setting of the `titlePg` element (§2.10.6). */
|
|
4003
|
+
FIRST: "first",
|
|
4004
|
+
/** Specifies that this header or footer shall appear on all even numbered pages in this section (counting from the first page in the section, not the section numbering). The appearance of this header or footer is contingent on the setting of the `evenAndOddHeaders` element (§2.10.1). */
|
|
4005
|
+
EVEN: "even"
|
|
4006
|
+
};
|
|
4007
|
+
const HeaderFooterType = {
|
|
4008
|
+
FOOTER: "w:footerReference",
|
|
4009
|
+
HEADER: "w:headerReference"
|
|
4010
|
+
};
|
|
4011
|
+
const createHeaderFooterReference = (type, options) => `<${type} r:id="rId${options.id}" w:type="${options.type || HeaderFooterReferenceType.DEFAULT}"/>`;
|
|
4012
|
+
//#endregion
|
|
4013
|
+
//#region src/parts/document/body/section-properties/descriptor.ts
|
|
4014
|
+
/**
|
|
4015
|
+
* Section properties descriptor for DOCX documents.
|
|
4016
|
+
*
|
|
4017
|
+
* Produces `<w:sectPr>` XML directly from options, eliminating all
|
|
4018
|
+
* intermediate XmlComponent instances (create* + toXml pattern).
|
|
4019
|
+
*
|
|
4020
|
+
* Reference: ISO/IEC 29500-4, wml.xsd, CT_SectPr
|
|
4021
|
+
*
|
|
4022
|
+
* @module
|
|
4023
|
+
*/
|
|
4024
|
+
function stringifyBorderXml(tag, opts) {
|
|
4025
|
+
const attrs = [];
|
|
4026
|
+
if (opts.style !== void 0) attrs.push(`w:val="${opts.style}"`);
|
|
4027
|
+
if (opts.color !== void 0) attrs.push(`w:color="${opts.color}"`);
|
|
4028
|
+
if (opts.size !== void 0) attrs.push(`w:sz="${opts.size}"`);
|
|
4029
|
+
if (opts.space !== void 0) attrs.push(`w:space="${opts.space}"`);
|
|
4030
|
+
if (opts.themeColor !== void 0) attrs.push(`w:themeColor="${opts.themeColor}"`);
|
|
4031
|
+
if (opts.themeTint !== void 0) attrs.push(`w:themeTint="${opts.themeTint}"`);
|
|
4032
|
+
if (opts.themeShade !== void 0) attrs.push(`w:themeShade="${opts.themeShade}"`);
|
|
4033
|
+
if (opts.shadow !== void 0) attrs.push(`w:shadow="${opts.shadow ? 1 : 0}"`);
|
|
4034
|
+
if (opts.frame !== void 0) attrs.push(`w:frame="${opts.frame ? 1 : 0}"`);
|
|
4035
|
+
return `<${tag} ${attrs.join(" ")}/>`;
|
|
4036
|
+
}
|
|
4037
|
+
function pageSizeXml(w, h, orient, code) {
|
|
4038
|
+
const attrs = [`w:w="${w}"`, `w:h="${h}"`];
|
|
4039
|
+
if (orient) attrs.push(`w:orient="${orient}"`);
|
|
4040
|
+
if (code !== void 0) attrs.push(`w:code="${code}"`);
|
|
4041
|
+
return `<w:pgSz ${attrs.join(" ")}/>`;
|
|
4042
|
+
}
|
|
4043
|
+
function pageMarginXml(top, right, bottom, left, header, footer, gutter) {
|
|
4044
|
+
return `<w:pgMar w:top="${top}" w:right="${right}" w:bottom="${bottom}" w:left="${left}" w:header="${header}" w:footer="${footer}" w:gutter="${gutter}"/>`;
|
|
4045
|
+
}
|
|
4046
|
+
function headerFooterRefXml(tag, id, type) {
|
|
4047
|
+
return `<${tag} r:id="rId${id}" w:type="${type}"/>`;
|
|
4048
|
+
}
|
|
4049
|
+
function sectionTypeXml(val) {
|
|
4050
|
+
return `<w:type w:val="${val}"/>`;
|
|
4051
|
+
}
|
|
4052
|
+
function verticalAlignXml(val) {
|
|
4053
|
+
return `<w:vAlign w:val="${val}"/>`;
|
|
4054
|
+
}
|
|
4055
|
+
function lineNumberXml(opts) {
|
|
4056
|
+
const attrs = [];
|
|
4057
|
+
if (opts.countBy !== void 0) attrs.push(`w:countBy="${opts.countBy}"`);
|
|
4058
|
+
if (opts.start !== void 0) attrs.push(`w:start="${opts.start}"`);
|
|
4059
|
+
if (opts.restart !== void 0) attrs.push(`w:restart="${opts.restart}"`);
|
|
4060
|
+
if (opts.distance !== void 0) attrs.push(`w:distance="${opts.distance}"`);
|
|
4061
|
+
return attrs.length ? `<w:lnNumType ${attrs.join(" ")}/>` : "<w:lnNumType/>";
|
|
4062
|
+
}
|
|
4063
|
+
function pageNumberXml(opts) {
|
|
4064
|
+
const attrs = [];
|
|
4065
|
+
if (opts.start !== void 0) attrs.push(`w:start="${opts.start}"`);
|
|
4066
|
+
if (opts.formatType !== void 0) attrs.push(`w:fmt="${opts.formatType}"`);
|
|
4067
|
+
if (opts.separator !== void 0) attrs.push(`w:chapSep="${opts.separator}"`);
|
|
4068
|
+
if (opts.chapStyle !== void 0) attrs.push(`w:chapStyle="${opts.chapStyle}"`);
|
|
4069
|
+
return attrs.length ? `<w:pgNumType ${attrs.join(" ")}/>` : "<w:pgNumType/>";
|
|
4070
|
+
}
|
|
4071
|
+
function docGridXml(linePitch, charSpace, type) {
|
|
4072
|
+
const attrs = [`w:linePitch="${linePitch}"`];
|
|
4073
|
+
if (charSpace !== void 0) attrs.push(`w:charSpace="${charSpace}"`);
|
|
4074
|
+
if (type !== void 0) attrs.push(`w:type="${type}"`);
|
|
4075
|
+
return `<w:docGrid ${attrs.join(" ")}/>`;
|
|
4076
|
+
}
|
|
4077
|
+
function columnsXml(opts) {
|
|
4078
|
+
const attrs = [];
|
|
4079
|
+
if (opts.space !== void 0) attrs.push(`w:space="${twipsMeasureValue(opts.space)}"`);
|
|
4080
|
+
if (opts.count !== void 0) attrs.push(`w:num="${opts.count}"`);
|
|
4081
|
+
if (opts.separate !== void 0) attrs.push(`w:sep="${opts.separate ? 1 : 0}"`);
|
|
4082
|
+
if (opts.equalWidth !== void 0) attrs.push(`w:equalWidth="${opts.equalWidth ? 1 : 0}"`);
|
|
4083
|
+
const attrStr = attrs.join(" ");
|
|
4084
|
+
if (!opts.equalWidth && opts.children) {
|
|
4085
|
+
const colParts = [];
|
|
4086
|
+
for (const col of opts.children) {
|
|
4087
|
+
const colAttrs = [`w:w="${twipsMeasureValue(col.width)}"`];
|
|
4088
|
+
if (col.space !== void 0) colAttrs.push(`w:space="${twipsMeasureValue(col.space)}"`);
|
|
4089
|
+
colParts.push(`<w:col ${colAttrs.join(" ")}/>`);
|
|
4090
|
+
}
|
|
4091
|
+
return `<w:cols ${attrStr}>${colParts.join("")}</w:cols>`;
|
|
4092
|
+
}
|
|
4093
|
+
return `<w:cols ${attrStr}/>`;
|
|
4094
|
+
}
|
|
4095
|
+
function footnotePrXml(tag, opts) {
|
|
4096
|
+
const parts = [];
|
|
4097
|
+
if (opts.pos !== void 0) parts.push(`<w:pos w:val="${opts.pos}"/>`);
|
|
4098
|
+
if (opts.formatType !== void 0 || opts.format !== void 0) {
|
|
4099
|
+
const fmtAttrs = [];
|
|
4100
|
+
if (opts.formatType !== void 0) fmtAttrs.push(`w:fmt="${opts.formatType}"`);
|
|
4101
|
+
if (opts.format !== void 0) fmtAttrs.push(`w:format="${opts.format}"`);
|
|
4102
|
+
parts.push(`<w:numFmt ${fmtAttrs.join(" ")}/>`);
|
|
4103
|
+
}
|
|
4104
|
+
if (opts.numStart !== void 0) parts.push(`<w:numStart w:val="${opts.numStart}"/>`);
|
|
4105
|
+
if (opts.numRestart !== void 0) parts.push(`<w:numRestart w:val="${opts.numRestart}"/>`);
|
|
4106
|
+
const body = parts.join("");
|
|
4107
|
+
return body ? `<${tag}>${body}</${tag}>` : `<${tag}/>`;
|
|
4108
|
+
}
|
|
4109
|
+
function pageBordersXml(opts) {
|
|
4110
|
+
const attrs = [];
|
|
4111
|
+
if (opts.display !== void 0) attrs.push(`w:display="${opts.display}"`);
|
|
4112
|
+
if (opts.offsetFrom !== void 0) attrs.push(`w:offsetFrom="${opts.offsetFrom}"`);
|
|
4113
|
+
if (opts.zOrder !== void 0) attrs.push(`w:zOrder="${opts.zOrder}"`);
|
|
4114
|
+
const parts = [];
|
|
4115
|
+
if (opts.top) parts.push(stringifyBorderXml("w:top", opts.top));
|
|
4116
|
+
if (opts.left) parts.push(stringifyBorderXml("w:left", opts.left));
|
|
4117
|
+
if (opts.bottom) parts.push(stringifyBorderXml("w:bottom", opts.bottom));
|
|
4118
|
+
if (opts.right) parts.push(stringifyBorderXml("w:right", opts.right));
|
|
4119
|
+
const attrStr = attrs.join(" ");
|
|
4120
|
+
const body = parts.join("");
|
|
4121
|
+
if (!body && !attrStr) return "<w:pgBorders/>";
|
|
4122
|
+
return body ? `<w:pgBorders ${attrStr}>${body}</w:pgBorders>` : `<w:pgBorders ${attrStr}/>`;
|
|
4123
|
+
}
|
|
4124
|
+
function appendHeaderFooterRefs(parts, type, group) {
|
|
4125
|
+
if (!group) return;
|
|
4126
|
+
if (group.default) parts.push(headerFooterRefXml(type, group.default.referenceId, "default"));
|
|
4127
|
+
if (group.first) parts.push(headerFooterRefXml(type, group.first.referenceId, "first"));
|
|
4128
|
+
if (group.even) parts.push(headerFooterRefXml(type, group.even.referenceId, "even"));
|
|
4129
|
+
}
|
|
4130
|
+
function stringifySectionPropertiesChange(opts) {
|
|
4131
|
+
const { author, date, id, ...inner } = opts;
|
|
4132
|
+
return `<w:sectPrChange w:author="${author}" w:date="${date}" w:id="${id}"><w:sectPr>${stringifySectionPropertiesInner(inner)}</w:sectPr></w:sectPrChange>`;
|
|
4133
|
+
}
|
|
4134
|
+
function stringifySectionPropertiesInner(opts) {
|
|
4135
|
+
const parts = [];
|
|
4136
|
+
appendHeaderFooterRefs(parts, "w:headerReference", opts.headerWrapperGroup);
|
|
4137
|
+
appendHeaderFooterRefs(parts, "w:footerReference", opts.footerWrapperGroup);
|
|
4138
|
+
const { size: { width = sectionPageSizeDefaults.WIDTH, height = sectionPageSizeDefaults.HEIGHT, orientation = sectionPageSizeDefaults.ORIENTATION } = {}, margin: { top = sectionMarginDefaults.TOP, right = sectionMarginDefaults.RIGHT, bottom = sectionMarginDefaults.BOTTOM, left = sectionMarginDefaults.LEFT, header = sectionMarginDefaults.HEADER, footer = sectionMarginDefaults.FOOTER, gutter = sectionMarginDefaults.GUTTER } = {}, pageNumbers = {}, borders, textDirection } = opts.page ?? {};
|
|
4139
|
+
const { linePitch = 312, charSpace = 0, type: gridType = "lines" } = opts.grid ?? {};
|
|
4140
|
+
if (opts.footnotePr) parts.push(footnotePrXml("w:footnotePr", opts.footnotePr));
|
|
4141
|
+
if (opts.endnotePr) parts.push(footnotePrXml("w:endnotePr", opts.endnotePr));
|
|
4142
|
+
if (opts.type) parts.push(sectionTypeXml(opts.type));
|
|
4143
|
+
const pgW = orientation === "landscape" ? convertToTwip(height) : width;
|
|
4144
|
+
const pgH = orientation === "landscape" ? convertToTwip(width) : height;
|
|
4145
|
+
parts.push(pageSizeXml(pgW, pgH, orientation));
|
|
4146
|
+
parts.push(pageMarginXml(top, right, bottom, left, header, footer, gutter));
|
|
4147
|
+
if (borders) parts.push(pageBordersXml(borders));
|
|
4148
|
+
if (opts.lineNumbers) parts.push(lineNumberXml(opts.lineNumbers));
|
|
4149
|
+
parts.push(pageNumberXml(pageNumbers));
|
|
4150
|
+
if (opts.column) parts.push(columnsXml(opts.column));
|
|
4151
|
+
if (opts.verticalAlign) parts.push(verticalAlignXml(opts.verticalAlign));
|
|
4152
|
+
if (opts.titlePage !== void 0) parts.push(opts.titlePage ? "<w:titlePg/>" : "<w:titlePg w:val=\"0\"/>");
|
|
4153
|
+
if (textDirection) parts.push(`<w:textDirection w:val="${textDirection}"/>`);
|
|
4154
|
+
if (opts.noEndnote !== void 0) parts.push(opts.noEndnote ? "<w:noEndnote/>" : "<w:noEndnote w:val=\"0\"/>");
|
|
4155
|
+
if (opts.formProtection !== void 0) parts.push(opts.formProtection ? "<w:formProt/>" : "<w:formProt w:val=\"0\"/>");
|
|
4156
|
+
if (opts.bidi !== void 0) parts.push(opts.bidi ? "<w:bidi/>" : "<w:bidi w:val=\"0\"/>");
|
|
4157
|
+
if (opts.rtlGutter !== void 0) parts.push(opts.rtlGutter ? "<w:rtlGutter/>" : "<w:rtlGutter w:val=\"0\"/>");
|
|
4158
|
+
if (opts.paperSrc) {
|
|
4159
|
+
const psAttr = [];
|
|
4160
|
+
if (opts.paperSrc.first !== void 0) psAttr.push(`w:first="${opts.paperSrc.first}"`);
|
|
4161
|
+
if (opts.paperSrc.other !== void 0) psAttr.push(`w:other="${opts.paperSrc.other}"`);
|
|
4162
|
+
parts.push(`<w:paperSrc ${psAttr.join(" ")}/>`);
|
|
4163
|
+
}
|
|
4164
|
+
if (opts.printerSettingsId !== void 0) parts.push(`<w:printerSettings r:id="${opts.printerSettingsId}"/>`);
|
|
4165
|
+
parts.push(docGridXml(linePitch, charSpace, gridType));
|
|
4166
|
+
if (opts.revision) parts.push(stringifySectionPropertiesChange(opts.revision));
|
|
4167
|
+
return parts.join("");
|
|
4168
|
+
}
|
|
4169
|
+
/**
|
|
4170
|
+
* Section properties descriptor for DOCX `<w:sectPr>` elements.
|
|
4171
|
+
*
|
|
4172
|
+
* Produces complete XML directly from options — zero XmlComponent instances
|
|
4173
|
+
* in the hot path. All `create*()` + `.toXml()` calls eliminated in favor
|
|
4174
|
+
* of direct string concatenation.
|
|
4175
|
+
*
|
|
4176
|
+
* @example
|
|
4177
|
+
* ```typescript
|
|
4178
|
+
* const xml = sectionPropertiesDesc.stringify(sectPrOpts, ctx);
|
|
4179
|
+
* ```
|
|
4180
|
+
*/
|
|
4181
|
+
const sectionPropertiesDesc = {
|
|
4182
|
+
kind: "custom",
|
|
4183
|
+
stringify(opts, _ctx) {
|
|
4184
|
+
return stringifySectionPropertiesXml(opts);
|
|
4185
|
+
},
|
|
4186
|
+
parse(el, _ctx) {
|
|
4187
|
+
return parseSectionPropertiesEl(el);
|
|
4188
|
+
}
|
|
4189
|
+
};
|
|
4190
|
+
/** Standalone stringify — no context needed, pure options → XML. */
|
|
4191
|
+
function stringifySectionPropertiesXml(opts) {
|
|
4192
|
+
const inner = stringifySectionPropertiesInner(opts);
|
|
4193
|
+
const attrs = [];
|
|
4194
|
+
if (opts.rsidRPr !== void 0) attrs.push(`w:rsidRPr="${opts.rsidRPr}"`);
|
|
4195
|
+
if (opts.rsidDel !== void 0) attrs.push(`w:rsidDel="${opts.rsidDel}"`);
|
|
4196
|
+
if (opts.rsidR !== void 0) attrs.push(`w:rsidR="${opts.rsidR}"`);
|
|
4197
|
+
if (opts.rsidSect !== void 0) attrs.push(`w:rsidSect="${opts.rsidSect}"`);
|
|
4198
|
+
return `<w:sectPr${attrs.length ? " " + attrs.join(" ") : ""}>${inner}</w:sectPr>`;
|
|
4199
|
+
}
|
|
4200
|
+
/** Parse a w:sectPr element into ISectionPropertiesOptions. */
|
|
4201
|
+
function parseSectionPropertiesEl(el) {
|
|
4202
|
+
const opts = {};
|
|
4203
|
+
for (const [attrName, optKey] of [
|
|
4204
|
+
["w:rsidR", "rsidR"],
|
|
4205
|
+
["w:rsidRPr", "rsidRPr"],
|
|
4206
|
+
["w:rsidDel", "rsidDel"],
|
|
4207
|
+
["w:rsidSect", "rsidSect"]
|
|
4208
|
+
]) {
|
|
4209
|
+
const val = attr(el, attrName);
|
|
4210
|
+
if (val) opts[optKey] = val;
|
|
4211
|
+
}
|
|
4212
|
+
const pgSz = findChild(el, "w:pgSz");
|
|
4213
|
+
if (pgSz) {
|
|
4214
|
+
const page = {};
|
|
4215
|
+
const size = {};
|
|
4216
|
+
const w = attrNum(pgSz, "w:w");
|
|
4217
|
+
const h = attrNum(pgSz, "w:h");
|
|
4218
|
+
const orient = attr(pgSz, "w:orient");
|
|
4219
|
+
if (orient === "landscape" && w !== void 0 && h !== void 0) {
|
|
4220
|
+
size.width = h;
|
|
4221
|
+
size.height = w;
|
|
4222
|
+
} else {
|
|
4223
|
+
if (w !== void 0) size.width = w;
|
|
4224
|
+
if (h !== void 0) size.height = h;
|
|
4225
|
+
}
|
|
4226
|
+
if (orient) size.orientation = orient;
|
|
4227
|
+
if (Object.keys(size).length > 0) page.size = size;
|
|
4228
|
+
const pgMar = findChild(el, "w:pgMar");
|
|
4229
|
+
if (pgMar) {
|
|
4230
|
+
const margin = {};
|
|
4231
|
+
for (const [a, o] of [
|
|
4232
|
+
["w:top", "top"],
|
|
4233
|
+
["w:right", "right"],
|
|
4234
|
+
["w:bottom", "bottom"],
|
|
4235
|
+
["w:left", "left"],
|
|
4236
|
+
["w:header", "header"],
|
|
4237
|
+
["w:footer", "footer"],
|
|
4238
|
+
["w:gutter", "gutter"]
|
|
4239
|
+
]) {
|
|
4240
|
+
const val = attrNum(pgMar, a);
|
|
4241
|
+
if (val !== void 0) margin[o] = val;
|
|
4242
|
+
}
|
|
4243
|
+
if (Object.keys(margin).length > 0) page.margin = margin;
|
|
4244
|
+
}
|
|
4245
|
+
const pgNumType = findChild(el, "w:pgNumType");
|
|
4246
|
+
if (pgNumType) {
|
|
4247
|
+
const pageNumbers = {};
|
|
4248
|
+
const start = attrNum(pgNumType, "w:start");
|
|
4249
|
+
if (start !== void 0) pageNumbers.start = start;
|
|
4250
|
+
const fmt = attr(pgNumType, "w:fmt");
|
|
4251
|
+
if (fmt) pageNumbers.formatType = fmt;
|
|
4252
|
+
if (Object.keys(pageNumbers).length > 0) page.pageNumbers = pageNumbers;
|
|
4253
|
+
}
|
|
4254
|
+
if (Object.keys(page).length > 0) opts.page = page;
|
|
4255
|
+
}
|
|
4256
|
+
const cols = findChild(el, "w:cols");
|
|
4257
|
+
if (cols) {
|
|
4258
|
+
const column = {};
|
|
4259
|
+
const count = attrNum(cols, "w:num");
|
|
4260
|
+
if (count !== void 0) column.count = count;
|
|
4261
|
+
const space = attrNum(cols, "w:space");
|
|
4262
|
+
if (space !== void 0) column.space = space;
|
|
4263
|
+
if (attrBool(cols, "w:sep")) column.separator = true;
|
|
4264
|
+
if (Object.keys(column).length > 0) opts.column = column;
|
|
4265
|
+
}
|
|
4266
|
+
const type = findChild(el, "w:type");
|
|
4267
|
+
if (type) {
|
|
4268
|
+
const val = attr(type, "w:val");
|
|
4269
|
+
if (val) opts.type = val;
|
|
4270
|
+
}
|
|
4271
|
+
const titlePg = findChild(el, "w:titlePg");
|
|
4272
|
+
if (titlePg) opts.titlePage = attrBool(titlePg, "w:val") ?? true;
|
|
4273
|
+
for (const [name, optKey] of [
|
|
4274
|
+
["w:noEndnote", "noEndnote"],
|
|
4275
|
+
["w:formProt", "formProtection"],
|
|
4276
|
+
["w:bidi", "bidi"],
|
|
4277
|
+
["w:rtlGutter", "rtlGutter"]
|
|
4278
|
+
]) {
|
|
4279
|
+
const child = findChild(el, name);
|
|
4280
|
+
if (child) opts[optKey] = attrBool(child, "w:val") ?? true;
|
|
4281
|
+
}
|
|
4282
|
+
const docGrid = findChild(el, "w:docGrid");
|
|
4283
|
+
if (docGrid) {
|
|
4284
|
+
const grid = {};
|
|
4285
|
+
const type = attr(docGrid, "w:type");
|
|
4286
|
+
if (type) grid.type = type;
|
|
4287
|
+
const linePitch = attrNum(docGrid, "w:linePitch");
|
|
4288
|
+
if (linePitch !== void 0) grid.linePitch = linePitch;
|
|
4289
|
+
const charSpace = attrNum(docGrid, "w:charSpace");
|
|
4290
|
+
if (charSpace !== void 0) grid.charSpace = charSpace;
|
|
4291
|
+
if (Object.keys(grid).length > 0) opts.grid = grid;
|
|
4292
|
+
}
|
|
4293
|
+
const lnNumType = findChild(el, "w:lnNumType");
|
|
4294
|
+
if (lnNumType) {
|
|
4295
|
+
const lineNumbers = {};
|
|
4296
|
+
const countBy = attrNum(lnNumType, "w:countBy");
|
|
4297
|
+
if (countBy !== void 0) lineNumbers.countBy = countBy;
|
|
4298
|
+
const start = attrNum(lnNumType, "w:start");
|
|
4299
|
+
if (start !== void 0) lineNumbers.start = start;
|
|
4300
|
+
const restart = attr(lnNumType, "w:restart");
|
|
4301
|
+
if (restart) lineNumbers.restart = restart;
|
|
4302
|
+
const distance = attrNum(lnNumType, "w:distance");
|
|
4303
|
+
if (distance !== void 0) lineNumbers.distance = distance;
|
|
4304
|
+
if (Object.keys(lineNumbers).length > 0) opts.lineNumbers = lineNumbers;
|
|
4305
|
+
}
|
|
4306
|
+
const pgBorders = findChild(el, "w:pgBorders");
|
|
4307
|
+
if (pgBorders) {
|
|
4308
|
+
const borders = {};
|
|
4309
|
+
for (const side of [
|
|
4310
|
+
"top",
|
|
4311
|
+
"left",
|
|
4312
|
+
"bottom",
|
|
4313
|
+
"right"
|
|
4314
|
+
]) {
|
|
4315
|
+
const sideEl = findChild(pgBorders, `w:${side}`);
|
|
4316
|
+
if (sideEl) {
|
|
4317
|
+
const b = {};
|
|
4318
|
+
const val = attr(sideEl, "w:val");
|
|
4319
|
+
if (val) b.style = val;
|
|
4320
|
+
const color = attr(sideEl, "w:color");
|
|
4321
|
+
if (color) b.color = color;
|
|
4322
|
+
const sz = attrNum(sideEl, "w:sz");
|
|
4323
|
+
if (sz !== void 0) b.size = sz;
|
|
4324
|
+
const space = attrNum(sideEl, "w:space");
|
|
4325
|
+
if (space !== void 0) b.space = space;
|
|
4326
|
+
borders[side] = b;
|
|
4327
|
+
}
|
|
4328
|
+
}
|
|
4329
|
+
const display = attr(pgBorders, "w:display");
|
|
4330
|
+
if (display) borders.display = display;
|
|
4331
|
+
const offsetFrom = attr(pgBorders, "w:offsetFrom");
|
|
4332
|
+
if (offsetFrom) borders.offsetFrom = offsetFrom;
|
|
4333
|
+
const zOrder = attr(pgBorders, "w:zOrder");
|
|
4334
|
+
if (zOrder) borders.zOrder = zOrder;
|
|
4335
|
+
if (Object.keys(borders).length > 0) {
|
|
4336
|
+
const page = opts.page ?? {};
|
|
4337
|
+
page.borders = borders;
|
|
4338
|
+
opts.page = page;
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
const vAlign = findChild(el, "w:vAlign");
|
|
4342
|
+
if (vAlign) {
|
|
4343
|
+
const val = attr(vAlign, "w:val");
|
|
4344
|
+
if (val) opts.verticalAlign = val;
|
|
4345
|
+
}
|
|
4346
|
+
const textDirection = findChild(el, "w:textDirection");
|
|
4347
|
+
if (textDirection) {
|
|
4348
|
+
const val = attr(textDirection, "w:val");
|
|
4349
|
+
if (val) {
|
|
4350
|
+
const page = opts.page ?? {};
|
|
4351
|
+
page.textDirection = val;
|
|
4352
|
+
opts.page = page;
|
|
4353
|
+
}
|
|
4354
|
+
}
|
|
4355
|
+
const footnotePr = findChild(el, "w:footnotePr");
|
|
4356
|
+
if (footnotePr) opts.footnotePr = parseNotePropertiesEl(footnotePr);
|
|
4357
|
+
const endnotePr = findChild(el, "w:endnotePr");
|
|
4358
|
+
if (endnotePr) opts.endnotePr = parseNotePropertiesEl(endnotePr);
|
|
4359
|
+
const paperSrc = findChild(el, "w:paperSrc");
|
|
4360
|
+
if (paperSrc) {
|
|
4361
|
+
const ps = {};
|
|
4362
|
+
const first = attrNum(paperSrc, "w:first");
|
|
4363
|
+
if (first !== void 0) ps.first = first;
|
|
4364
|
+
const other = attrNum(paperSrc, "w:other");
|
|
4365
|
+
if (other !== void 0) ps.other = other;
|
|
4366
|
+
if (Object.keys(ps).length > 0) opts.paperSrc = ps;
|
|
4367
|
+
}
|
|
4368
|
+
const printerSettings = findChild(el, "w:printerSettings");
|
|
4369
|
+
if (printerSettings) {
|
|
4370
|
+
const rId = attr(printerSettings, "r:id");
|
|
4371
|
+
if (rId) opts.printerSettingsId = rId;
|
|
4372
|
+
}
|
|
4373
|
+
return opts;
|
|
4374
|
+
}
|
|
4375
|
+
function parseNotePropertiesEl(el) {
|
|
4376
|
+
const opts = {};
|
|
4377
|
+
const posEl = findChild(el, "w:pos");
|
|
4378
|
+
if (posEl) {
|
|
4379
|
+
const val = attr(posEl, "w:val");
|
|
4380
|
+
if (val) opts.pos = val;
|
|
4381
|
+
}
|
|
4382
|
+
const numFmt = findChild(el, "w:numFmt");
|
|
4383
|
+
if (numFmt) {
|
|
4384
|
+
const fmt = attr(numFmt, "w:fmt");
|
|
4385
|
+
if (fmt) opts.formatType = fmt;
|
|
4386
|
+
const format = attr(numFmt, "w:format");
|
|
4387
|
+
if (format) opts.format = format;
|
|
4388
|
+
}
|
|
4389
|
+
const numStart = findChild(el, "w:numStart");
|
|
4390
|
+
if (numStart) {
|
|
4391
|
+
const val = attrNum(numStart, "w:val");
|
|
4392
|
+
if (val !== void 0) opts.numStart = val;
|
|
4393
|
+
}
|
|
4394
|
+
const numRestart = findChild(el, "w:numRestart");
|
|
4395
|
+
if (numRestart) {
|
|
4396
|
+
const val = attr(numRestart, "w:val");
|
|
4397
|
+
if (val) opts.numRestart = val;
|
|
4398
|
+
}
|
|
4399
|
+
return opts;
|
|
4400
|
+
}
|
|
4401
|
+
//#endregion
|
|
4402
|
+
export { TextHorzOverflowType as $, stringifyParagraphProperties as A, HorizontalPositionAlign as B, createPageSize as C, stringifyJsonChild as D, tableDesc as E, parseDrawingRun as F, createWrapTight as G, SpaceType as H, createVerticalPosition as I, WidthType as J, TextWrappingSide as K, createHorizontalPosition as L, parseMathChildren as M, drawingDesc as N, stringifyParagraphInline as O, resetDrawingIdGen as P, TextBodyWrappingType as Q, HorizontalPositionRelativeFrom as R, PageOrientation as S, setTableParseChild as T, VerticalPositionAlign as U, NumberFormat as V, createWrapThrough as W, TextDirection as X, BorderStyle as Y, VerticalMergeType as Z, DocumentGridType as _, HeaderFooterType as a, Media as at, sectionPageSizeDefaults as b, createSectionType as c, createPageMargin as d, TextVertOverflowType as et, PageBorderDisplay as f, createPageNumberType as g, PageNumberSeparator as h, HeaderFooterReferenceType as i, WORKAROUND2 as it, stringifyRunProperties as j, stringifyRunInline as k, LineNumberRestartFormat as l, PageBorderZOrder as m, sectionPropertiesDesc as n, VerticalAnchor as nt, createHeaderFooterReference as o, createTransformation as ot, PageBorderOffsetFrom as p, TextWrappingType as q, stringifySectionPropertiesXml as r, createBodyProperties as rt, SectionType as s, parseSectionPropertiesEl as t, TextVerticalType as tt, createLineNumberType as u, createDocumentGrid as v, DocumentAttributeNamespaces as w, PageTextDirectionType as x, sectionMarginDefaults as y, VerticalPositionRelativeFrom as z };
|
|
4403
|
+
|
|
4404
|
+
//# sourceMappingURL=document-CWr8C_OX.mjs.map
|