@shbernal/pptxgenjs 5.0.2 → 5.2.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/dist/{browser-CbSvYzvo.js → browser-DraPrTLD.js} +5 -5
- package/dist/browser-DraPrTLD.js.map +1 -0
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +4 -4
- package/dist/{core-enums-CZn5br4v.js → core-interfaces-vUc0ElZs.js} +107 -3
- package/dist/core-interfaces-vUc0ElZs.js.map +1 -0
- package/dist/core.d.ts +2 -2
- package/dist/core.js +3 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -4
- package/dist/inspect.js +1 -1
- package/dist/node.d.ts +3 -3
- package/dist/node.js +5 -5
- package/dist/node.js.map +1 -1
- package/dist/{pptxgen-1VITjpGE.js → pptxgen--5RWzhb4.js} +705 -247
- package/dist/pptxgen--5RWzhb4.js.map +1 -0
- package/dist/{pptxgen-BqDpIYsq.d.ts → pptxgen-DzBNFPxG.d.ts} +33 -3
- package/dist/pptxgen-DzBNFPxG.d.ts.map +1 -0
- package/dist/standalone.d.ts +520 -78
- package/dist/standalone.d.ts.map +1 -1
- package/dist/standalone.js +811 -247
- package/dist/standalone.js.map +1 -1
- package/dist/{units-Bmst2HBb.js → units-DmzbVUNp.js} +3 -1
- package/dist/units-DmzbVUNp.js.map +1 -0
- package/dist/{units-CpDIQgsT.d.ts → units-y594YyBo.d.ts} +460 -48
- package/dist/units-y594YyBo.d.ts.map +1 -0
- package/package.json +3 -1
- package/dist/browser-CbSvYzvo.js.map +0 -1
- package/dist/core-enums-CZn5br4v.js.map +0 -1
- package/dist/pptxgen-1VITjpGE.js.map +0 -1
- package/dist/pptxgen-BqDpIYsq.d.ts.map +0 -1
- package/dist/units-Bmst2HBb.js.map +0 -1
- package/dist/units-CpDIQgsT.d.ts.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as inchesToEmu, i as STANDARD_LAYOUTS } from "./units-
|
|
2
|
-
import { A as
|
|
1
|
+
import { a as emuToInches, c as inchesToEmu, i as STANDARD_LAYOUTS } from "./units-DmzbVUNp.js";
|
|
2
|
+
import { A as DEF_TEXT_GLOW, B as ONEPT, D as DEF_SHAPE_SHADOW, G as SCHEME_COLOR_NAMES, H as PIECHART_COLORS, I as LAYOUT_IDX_SERIES_BASE, K as SHAPE_TYPE, L as LETTERS, M as EMU, N as IMG_BROKEN, R as LINEH_MODIFIER, T as DEF_PRES_LAYOUT_NAME, U as PLACEHOLDER_TYPES, V as OutputType, W as REGEX_HEX_COLOR, X as ShapeType, Y as SchemeColor, _ as DEF_CELL_MARGIN_IN, a as AXIS_ID_SERIES_PRIMARY, b as DEF_CHART_GRIDLINE, c as AlignH, f as CHART_TYPE, g as DEF_CELL_BORDER, i as AXIS_ID_CATEGORY_SECONDARY, j as DEF_TEXT_SHADOW, k as DEF_SLIDE_MARGIN_IN, l as AlignV, m as ChartType, o as AXIS_ID_VALUE_PRIMARY, q as SLDNUMFLDID, r as AXIS_ID_CATEGORY_PRIMARY, s as AXIS_ID_VALUE_SECONDARY, u as BARCHART_COLORS, w as DEF_PRES_LAYOUT, x as DEF_FONT_COLOR, y as DEF_CHART_BORDER } from "./core-interfaces-vUc0ElZs.js";
|
|
3
3
|
import JSZip from "jszip";
|
|
4
4
|
//#region src/gen-utils.ts
|
|
5
5
|
/**
|
|
@@ -18,6 +18,7 @@ import JSZip from "jszip";
|
|
|
18
18
|
*/
|
|
19
19
|
function getSmartParseNumber(size, xyDir, layout) {
|
|
20
20
|
if (typeof size === "string" && !isNaN(Number(size))) size = Number(size);
|
|
21
|
+
if (typeof size === "number" && !isFinite(size)) throw new Error(`Invalid ${xyDir || "coordinate"} value: expected a finite number but received ${String(size)}. This usually means a layout dimension was read from a missing property (e.g. \`layout.width\` returning \`undefined\`). Use \`slide.width\`/\`slide.height\` or \`STANDARD_LAYOUTS.<NAME>.width\`/\`.height\` (inches).`);
|
|
21
22
|
if (typeof size === "number" && size < 100) return inch2Emu(size);
|
|
22
23
|
if (typeof size === "number" && size >= 100) return size;
|
|
23
24
|
if (typeof size === "string" && size.includes("%")) {
|
|
@@ -46,7 +47,56 @@ function getUuid(uuidFormat) {
|
|
|
46
47
|
*/
|
|
47
48
|
function encodeXmlEntities(xml) {
|
|
48
49
|
if (typeof xml === "undefined" || xml == null) return "";
|
|
49
|
-
|
|
50
|
+
const cc = String.fromCharCode;
|
|
51
|
+
const illegalXmlCharsRe = new RegExp(`[${cc(0)}-${cc(8)}${cc(11)}${cc(12)}${cc(14)}-${cc(31)}${cc(127)}]`, "g");
|
|
52
|
+
return xml.toString().replace(illegalXmlCharsRe, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Practical maximum length for a `p:cNvPr` object name. PowerPoint does not
|
|
56
|
+
* enforce a hard spec limit, but very long names are a strong signal of a bug
|
|
57
|
+
* and are unwieldy in the Selection Pane.
|
|
58
|
+
*/
|
|
59
|
+
const MAX_OBJECT_NAME_LENGTH = 255;
|
|
60
|
+
/**
|
|
61
|
+
* Validate a user-supplied object name and warn (does not throw) when the value
|
|
62
|
+
* cannot be preserved as a stable PowerPoint Selection Pane identity. This keeps
|
|
63
|
+
* semantic-identity bugs visible at generation time without breaking existing
|
|
64
|
+
* decks that pass loose names.
|
|
65
|
+
* - Empty/whitespace-only names provide no usable identity.
|
|
66
|
+
* - Control characters are stripped by `encodeXmlEntities`, silently changing
|
|
67
|
+
* the stored name.
|
|
68
|
+
* - Excessively long names may not round-trip through PowerPoint/consumers.
|
|
69
|
+
* @param {string} name - the raw (pre-encoding) object name
|
|
70
|
+
* @param {string} kind - object kind for the warning message (e.g. 'text')
|
|
71
|
+
* @returns {string} the name unchanged (validation only)
|
|
72
|
+
*/
|
|
73
|
+
function validateObjectName(name, kind) {
|
|
74
|
+
if (typeof name !== "string") return name;
|
|
75
|
+
if (name.trim().length === 0) {
|
|
76
|
+
console.warn(`Warning: ${kind} objectName is empty or whitespace-only; it will not provide a stable Selection Pane identity.`);
|
|
77
|
+
return name;
|
|
78
|
+
}
|
|
79
|
+
const cc = String.fromCharCode;
|
|
80
|
+
if (new RegExp(`[${cc(0)}-${cc(8)}${cc(11)}${cc(12)}${cc(14)}-${cc(31)}${cc(127)}]`).test(name)) console.warn(`Warning: ${kind} objectName "${name}" contains control characters that will be stripped, changing the stored name.`);
|
|
81
|
+
if (name.length > MAX_OBJECT_NAME_LENGTH) console.warn(`Warning: ${kind} objectName exceeds ${MAX_OBJECT_NAME_LENGTH} characters and may not be preserved by PowerPoint.`);
|
|
82
|
+
return name;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Return object names that appear more than once in the given list. Used to warn
|
|
86
|
+
* when duplicate Selection Pane identities would be emitted on a single slide,
|
|
87
|
+
* which breaks consumers (e.g. semantic manifests) that rely on unique names.
|
|
88
|
+
* @param {string[]} names - object names emitted on one slide
|
|
89
|
+
* @returns {string[]} the duplicated names (each listed once)
|
|
90
|
+
*/
|
|
91
|
+
function getDuplicateObjectNames(names) {
|
|
92
|
+
const seen = /* @__PURE__ */ new Set();
|
|
93
|
+
const dupes = /* @__PURE__ */ new Set();
|
|
94
|
+
names.forEach((name) => {
|
|
95
|
+
if (typeof name !== "string" || name.length === 0) return;
|
|
96
|
+
if (seen.has(name)) dupes.add(name);
|
|
97
|
+
else seen.add(name);
|
|
98
|
+
});
|
|
99
|
+
return Array.from(dupes);
|
|
50
100
|
}
|
|
51
101
|
/**
|
|
52
102
|
* Convert inches into EMU
|
|
@@ -109,6 +159,10 @@ function rgbToHex(r, g, b) {
|
|
|
109
159
|
* @returns {string} XML string
|
|
110
160
|
*/
|
|
111
161
|
function createColorElement(colorStr, innerElements) {
|
|
162
|
+
if (typeof colorStr !== "string") {
|
|
163
|
+
console.warn(`createColorElement: expected a string color value, got ${typeof colorStr}. "${DEF_FONT_COLOR}" used instead.`);
|
|
164
|
+
colorStr = DEF_FONT_COLOR;
|
|
165
|
+
}
|
|
112
166
|
let colorVal = (colorStr || "").replace("#", "");
|
|
113
167
|
if (/^[0-9a-fA-F]{8}$/.test(colorVal)) {
|
|
114
168
|
const alphaHex = colorVal.slice(6, 8);
|
|
@@ -190,6 +244,17 @@ function genXmlGradientFill(gradient) {
|
|
|
190
244
|
return strXml;
|
|
191
245
|
}
|
|
192
246
|
/**
|
|
247
|
+
* Create a native DrawingML pattern fill.
|
|
248
|
+
* @param {PatternFillProps} pattern pattern fill options
|
|
249
|
+
* @returns XML string
|
|
250
|
+
*/
|
|
251
|
+
function genXmlPatternFill(pattern) {
|
|
252
|
+
if (!pattern) throw new Error("Pattern fill requires a pattern object.");
|
|
253
|
+
const fgColor = pattern.fgColor ?? "000000";
|
|
254
|
+
const bgColor = pattern.bgColor ?? "FFFFFF";
|
|
255
|
+
return `<a:pattFill prst="${pattern.preset}"><a:fgClr>${createColorElement(fgColor)}</a:fgClr><a:bgClr>${createColorElement(bgColor)}</a:bgClr></a:pattFill>`;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
193
258
|
* Create color selection
|
|
194
259
|
* @param {Color | ShapeFillProps | ShapeLineProps} props fill props
|
|
195
260
|
* @returns XML string
|
|
@@ -214,6 +279,9 @@ function genXmlColorSelection(props) {
|
|
|
214
279
|
case "gradient":
|
|
215
280
|
outText += genXmlGradientFill(typeof props === "string" ? void 0 : props.gradient);
|
|
216
281
|
break;
|
|
282
|
+
case "pattern":
|
|
283
|
+
outText += genXmlPatternFill(typeof props === "string" ? void 0 : props.pattern);
|
|
284
|
+
break;
|
|
217
285
|
default:
|
|
218
286
|
outText += "";
|
|
219
287
|
break;
|
|
@@ -266,6 +334,136 @@ function correctShadowOptions(ShadowProps) {
|
|
|
266
334
|
}
|
|
267
335
|
return ShadowProps;
|
|
268
336
|
}
|
|
337
|
+
/**
|
|
338
|
+
* Encode raw SVG markup as a base64 `image/svg+xml` data URI.
|
|
339
|
+
* - lets callers pass inline SVG to `addImage({ svg })` without hand-rolling base64
|
|
340
|
+
* - isomorphic and UTF-8 safe: uses the global `TextEncoder`/`btoa` (Node >=16, browsers)
|
|
341
|
+
* @param {string} svg - SVG markup, e.g. `'<svg ...>...</svg>'`
|
|
342
|
+
* @returns {string} a `data:image/svg+xml;base64,...` URI
|
|
343
|
+
*/
|
|
344
|
+
function svgMarkupToDataUri(svg) {
|
|
345
|
+
const bytes = new TextEncoder().encode(svg);
|
|
346
|
+
let binary = "";
|
|
347
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
348
|
+
return `data:image/svg+xml;base64,${btoa(binary)}`;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Decode a base64 image payload (raw base64 or a `data:` URI) to bytes.
|
|
352
|
+
* - tolerant of the `data:[mime];base64,` prefix and of whitespace in the payload
|
|
353
|
+
* @param {string} b64 - base64 string or data URI
|
|
354
|
+
* @returns {Uint8Array | null} decoded bytes, or `null` when the payload is empty/undecodable
|
|
355
|
+
*/
|
|
356
|
+
function decodeBase64ToBytes(b64) {
|
|
357
|
+
if (!b64) return null;
|
|
358
|
+
const comma = b64.indexOf("base64,");
|
|
359
|
+
const payload = (comma >= 0 ? b64.slice(comma + 7) : b64).replace(/\s/g, "");
|
|
360
|
+
if (!payload) return null;
|
|
361
|
+
try {
|
|
362
|
+
const binary = atob(payload);
|
|
363
|
+
const bytes = new Uint8Array(binary.length);
|
|
364
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
365
|
+
return bytes;
|
|
366
|
+
} catch {
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Read the intrinsic pixel dimensions of a raster image from its header bytes.
|
|
372
|
+
* - synchronous: parses only file-format headers, never decodes pixels
|
|
373
|
+
* - supports PNG, JPEG, GIF, BMP, and WebP (VP8 / VP8L / VP8X)
|
|
374
|
+
* - vector (SVG) and unrecognized formats return `null` (no intrinsic pixel size)
|
|
375
|
+
*
|
|
376
|
+
* Used by image `sizing: 'cover' | 'contain'` to compute an aspect-correct
|
|
377
|
+
* `<a:srcRect>` crop from the *natural* image ratio rather than the displayed box.
|
|
378
|
+
* @param {string} dataB64 - base64 image payload or `data:` URI
|
|
379
|
+
* @returns {{ w: number, h: number } | null} natural pixel size, or `null` when unmeasurable
|
|
380
|
+
*/
|
|
381
|
+
function getImageSizeFromBase64(dataB64) {
|
|
382
|
+
const b = decodeBase64ToBytes(dataB64);
|
|
383
|
+
if (!b || b.length < 24) return null;
|
|
384
|
+
if (b[0] === 137 && b[1] === 80 && b[2] === 78 && b[3] === 71) {
|
|
385
|
+
const w = b[16] << 24 | b[17] << 16 | b[18] << 8 | b[19];
|
|
386
|
+
const h = b[20] << 24 | b[21] << 16 | b[22] << 8 | b[23];
|
|
387
|
+
return w > 0 && h > 0 ? {
|
|
388
|
+
w,
|
|
389
|
+
h
|
|
390
|
+
} : null;
|
|
391
|
+
}
|
|
392
|
+
if (b[0] === 71 && b[1] === 73 && b[2] === 70) {
|
|
393
|
+
const w = b[6] | b[7] << 8;
|
|
394
|
+
const h = b[8] | b[9] << 8;
|
|
395
|
+
return w > 0 && h > 0 ? {
|
|
396
|
+
w,
|
|
397
|
+
h
|
|
398
|
+
} : null;
|
|
399
|
+
}
|
|
400
|
+
if (b[0] === 66 && b[1] === 77) {
|
|
401
|
+
const w = b[18] | b[19] << 8 | b[20] << 16 | b[21] << 24;
|
|
402
|
+
const h = b[22] | b[23] << 8 | b[24] << 16 | b[25] << 24;
|
|
403
|
+
const aw = Math.abs(w);
|
|
404
|
+
const ah = Math.abs(h);
|
|
405
|
+
return aw > 0 && ah > 0 ? {
|
|
406
|
+
w: aw,
|
|
407
|
+
h: ah
|
|
408
|
+
} : null;
|
|
409
|
+
}
|
|
410
|
+
if (b[0] === 82 && b[1] === 73 && b[2] === 70 && b[3] === 70 && b[8] === 87 && b[9] === 69 && b[10] === 66 && b[11] === 80) {
|
|
411
|
+
const fourCC = String.fromCharCode(b[12], b[13], b[14], b[15]);
|
|
412
|
+
if (fourCC === "VP8 " && b.length >= 30) {
|
|
413
|
+
const w = (b[26] | b[27] << 8) & 16383;
|
|
414
|
+
const h = (b[28] | b[29] << 8) & 16383;
|
|
415
|
+
return w > 0 && h > 0 ? {
|
|
416
|
+
w,
|
|
417
|
+
h
|
|
418
|
+
} : null;
|
|
419
|
+
}
|
|
420
|
+
if (fourCC === "VP8L" && b.length >= 25) {
|
|
421
|
+
const bits = b[21] | b[22] << 8 | b[23] << 16 | b[24] << 24;
|
|
422
|
+
const w = (bits & 16383) + 1;
|
|
423
|
+
const h = (bits >> 14 & 16383) + 1;
|
|
424
|
+
return w > 0 && h > 0 ? {
|
|
425
|
+
w,
|
|
426
|
+
h
|
|
427
|
+
} : null;
|
|
428
|
+
}
|
|
429
|
+
if (fourCC === "VP8X" && b.length >= 30) {
|
|
430
|
+
const w = (b[24] | b[25] << 8 | b[26] << 16) + 1;
|
|
431
|
+
const h = (b[27] | b[28] << 8 | b[29] << 16) + 1;
|
|
432
|
+
return w > 0 && h > 0 ? {
|
|
433
|
+
w,
|
|
434
|
+
h
|
|
435
|
+
} : null;
|
|
436
|
+
}
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
if (b[0] === 255 && b[1] === 216) {
|
|
440
|
+
let i = 2;
|
|
441
|
+
while (i + 9 < b.length) {
|
|
442
|
+
if (b[i] !== 255) {
|
|
443
|
+
i++;
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
const marker = b[i + 1];
|
|
447
|
+
if (marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204) {
|
|
448
|
+
const h = b[i + 5] << 8 | b[i + 6];
|
|
449
|
+
const w = b[i + 7] << 8 | b[i + 8];
|
|
450
|
+
return w > 0 && h > 0 ? {
|
|
451
|
+
w,
|
|
452
|
+
h
|
|
453
|
+
} : null;
|
|
454
|
+
}
|
|
455
|
+
if (marker >= 208 && marker <= 217 || marker === 1) {
|
|
456
|
+
i += 2;
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
const segLen = b[i + 2] << 8 | b[i + 3];
|
|
460
|
+
if (segLen < 2) break;
|
|
461
|
+
i += 2 + segLen;
|
|
462
|
+
}
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
269
467
|
//#endregion
|
|
270
468
|
//#region src/gen-tables.ts
|
|
271
469
|
/**
|
|
@@ -319,52 +517,62 @@ function parseTextToLines(cell, colWidth, verbose) {
|
|
|
319
517
|
*/
|
|
320
518
|
let newLine = [];
|
|
321
519
|
inputCells.forEach((cell) => {
|
|
322
|
-
if (typeof cell.text
|
|
323
|
-
|
|
324
|
-
|
|
520
|
+
if (typeof cell.text !== "string") return;
|
|
521
|
+
if (cell.text.includes("\n")) {
|
|
522
|
+
const parts = cell.text.split("\n");
|
|
523
|
+
parts.forEach((part, partIdx) => {
|
|
524
|
+
if (partIdx === parts.length - 1) newLine.push({
|
|
325
525
|
_type: "tablecell",
|
|
326
|
-
text:
|
|
327
|
-
options:
|
|
328
|
-
...cell.options,
|
|
329
|
-
breakLine: true
|
|
330
|
-
}
|
|
526
|
+
text: part,
|
|
527
|
+
options: cell.options
|
|
331
528
|
});
|
|
529
|
+
else {
|
|
530
|
+
newLine.push({
|
|
531
|
+
_type: "tablecell",
|
|
532
|
+
text: part,
|
|
533
|
+
options: {
|
|
534
|
+
...cell.options,
|
|
535
|
+
breakLine: true
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
inputLines1.push(newLine);
|
|
539
|
+
newLine = [];
|
|
540
|
+
}
|
|
332
541
|
});
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
inputLines1.push(newLine);
|
|
341
|
-
newLine = [];
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
if (newLine.length > 0) {
|
|
542
|
+
} else newLine.push({
|
|
543
|
+
_type: "tablecell",
|
|
544
|
+
text: cell.text.trim(),
|
|
545
|
+
options: cell.options
|
|
546
|
+
});
|
|
547
|
+
if (cell.options?.breakLine) {
|
|
548
|
+
if (verbose) console.log(`inputCells: new line > ${JSON.stringify(newLine)}`);
|
|
345
549
|
inputLines1.push(newLine);
|
|
346
550
|
newLine = [];
|
|
347
551
|
}
|
|
348
552
|
});
|
|
553
|
+
if (newLine.length > 0) {
|
|
554
|
+
inputLines1.push(newLine);
|
|
555
|
+
newLine = [];
|
|
556
|
+
}
|
|
349
557
|
if (verbose) {
|
|
350
558
|
console.log(`[2/4] inputLines1 (${inputLines1.length})`);
|
|
351
559
|
inputLines1.forEach((line, idx) => console.log(`[2/4] [${idx + 1}] line: ${JSON.stringify(line)}`));
|
|
352
560
|
}
|
|
353
561
|
inputLines1.forEach((line) => {
|
|
562
|
+
const lineTokens = [];
|
|
354
563
|
line.forEach((cell) => {
|
|
355
|
-
const lineCells = [];
|
|
356
564
|
const lineWords = String(cell.text).split(" ");
|
|
357
565
|
lineWords.forEach((word, idx) => {
|
|
358
566
|
const cellProps = { ...cell.options };
|
|
359
567
|
if (cellProps?.breakLine) cellProps.breakLine = idx + 1 === lineWords.length;
|
|
360
|
-
|
|
568
|
+
lineTokens.push({
|
|
361
569
|
_type: "tablecell",
|
|
362
570
|
text: word + (idx + 1 < lineWords.length ? " " : ""),
|
|
363
571
|
options: cellProps
|
|
364
572
|
});
|
|
365
573
|
});
|
|
366
|
-
inputLines2.push(lineCells);
|
|
367
574
|
});
|
|
575
|
+
inputLines2.push(lineTokens);
|
|
368
576
|
});
|
|
369
577
|
if (verbose) {
|
|
370
578
|
console.log(`[3/4] inputLines2 (${inputLines2.length})`);
|
|
@@ -472,6 +680,7 @@ function getSlidesForTableRows(tableRows = [], tableProps = {}, presLayout, mast
|
|
|
472
680
|
numCols += Number(cellOpts?.colspan ? cellOpts.colspan : 1);
|
|
473
681
|
});
|
|
474
682
|
if (tableProps.verbose) console.log(`| numCols ......................................... = ${numCols}`);
|
|
683
|
+
const colSpanDepths = new Array(numCols).fill(0);
|
|
475
684
|
if (!tablePropW && tableProps.colW) {
|
|
476
685
|
tableCalcW = Array.isArray(tableProps.colW) ? tableProps.colW.reduce((p, n) => p + n) * EMU : tableProps.colW * numCols || 0;
|
|
477
686
|
if (tableProps.verbose) console.log(`| tableCalcW ...................................... = ${tableCalcW / EMU}`);
|
|
@@ -492,6 +701,7 @@ function getSlidesForTableRows(tableRows = [], tableProps = {}, presLayout, mast
|
|
|
492
701
|
}
|
|
493
702
|
let newTableRowSlide = { rows: [] };
|
|
494
703
|
tableRows.forEach((row, iRow) => {
|
|
704
|
+
const hasActiveRowSpan = colSpanDepths.some((d) => d > 0);
|
|
495
705
|
const rowCellLines = [];
|
|
496
706
|
let maxCellMarTopEmu = 0;
|
|
497
707
|
let maxCellMarBtmEmu = 0;
|
|
@@ -588,7 +798,7 @@ function getSlidesForTableRows(tableRows = [], tableProps = {}, presLayout, mast
|
|
|
588
798
|
rowCellLines.forEach((cell) => {
|
|
589
799
|
if (cell._lineHeight >= emuLineMaxH) emuLineMaxH = cell._lineHeight;
|
|
590
800
|
});
|
|
591
|
-
if (emuTabCurrH + emuLineMaxH > emuSlideTabH) {
|
|
801
|
+
if (emuTabCurrH + emuLineMaxH > emuSlideTabH && !hasActiveRowSpan) {
|
|
592
802
|
if (tableProps.verbose) {
|
|
593
803
|
console.log("\n|-----------------------------------------------------------------------|");
|
|
594
804
|
console.log(`|-- NEW SLIDE CREATED (currTabH+currLineH > maxH) => ${(emuTabCurrH / EMU).toFixed(2)} + ${(srcCell._lineHeight / EMU).toFixed(2)} > ${emuSlideTabH / EMU}`);
|
|
@@ -632,6 +842,16 @@ function getSlidesForTableRows(tableRows = [], tableProps = {}, presLayout, mast
|
|
|
632
842
|
if (rowCellLines.map((cell) => cell._lines.length).reduce((prev, next) => prev + next) === 0) isDone = true;
|
|
633
843
|
}
|
|
634
844
|
if (currTableRow.length > 0) newTableRowSlide.rows.push(currTableRow);
|
|
845
|
+
const occupiedBefore = [...colSpanDepths];
|
|
846
|
+
let colCursor = 0;
|
|
847
|
+
row.forEach((cell) => {
|
|
848
|
+
while (colCursor < numCols && occupiedBefore[colCursor] > 0) colCursor++;
|
|
849
|
+
const cellColspan = cell.options?.colspan ?? 1;
|
|
850
|
+
const cellRowspan = cell.options?.rowspan ?? 1;
|
|
851
|
+
if (cellRowspan > 1) for (let c = 0; c < cellColspan && colCursor + c < numCols; c++) colSpanDepths[colCursor + c] = cellRowspan;
|
|
852
|
+
colCursor += cellColspan;
|
|
853
|
+
});
|
|
854
|
+
for (let c = 0; c < numCols; c++) if (colSpanDepths[c] > 0) colSpanDepths[c]--;
|
|
635
855
|
if (tableProps.verbose) console.log(`- SLIDE [${tableRowSlides.length}]: ROW [${iRow}]: ...COMPLETE ...... emuTabCurrH = ${(emuTabCurrH / EMU).toFixed(2)} ( emuSlideTabH = ${(emuSlideTabH / EMU).toFixed(2)} )`);
|
|
636
856
|
});
|
|
637
857
|
tableRowSlides.push(newTableRowSlide);
|
|
@@ -887,6 +1107,7 @@ function createSlideMaster(props, target) {
|
|
|
887
1107
|
else if ("image" in object) addImageDefinition(tgt, object.image);
|
|
888
1108
|
else if ("line" in object) addShapeDefinition(tgt, "line", object.line);
|
|
889
1109
|
else if ("rect" in object) addShapeDefinition(tgt, "rect", object.rect);
|
|
1110
|
+
else if ("roundRect" in object) addShapeDefinition(tgt, "roundRect", object.roundRect);
|
|
890
1111
|
else if ("text" in object) addTextDefinition(tgt, [{ text: object.text.text }], object.text.options || {}, false);
|
|
891
1112
|
else if ("placeholder" in object) {
|
|
892
1113
|
const placeholder = object.placeholder;
|
|
@@ -972,7 +1193,7 @@ function addChartDefinition(target, type, data, opt) {
|
|
|
972
1193
|
options.y = typeof options.y !== "undefined" && options.y != null && !isNaN(Number(options.y)) ? options.y : 1;
|
|
973
1194
|
options.w = options.w || "50%";
|
|
974
1195
|
options.h = options.h || "50%";
|
|
975
|
-
options.objectName = options.objectName ? encodeXmlEntities(options.objectName) : `Chart ${target._slideObjects.filter((obj) => obj._type === "chart").length}`;
|
|
1196
|
+
options.objectName = options.objectName ? encodeXmlEntities(validateObjectName(options.objectName, "chart")) : `Chart ${target._slideObjects.filter((obj) => obj._type === "chart").length}`;
|
|
976
1197
|
if (!["bar", "col"].includes(options.barDir || "")) options.barDir = "col";
|
|
977
1198
|
if (options._type === "area") {
|
|
978
1199
|
if (![
|
|
@@ -1062,7 +1283,11 @@ function addChartDefinition(target, type, data, opt) {
|
|
|
1062
1283
|
"square",
|
|
1063
1284
|
"triangle"
|
|
1064
1285
|
].includes(options.lineDataSymbol || "")) options.lineDataSymbol = "circle";
|
|
1065
|
-
if (![
|
|
1286
|
+
if (![
|
|
1287
|
+
"gap",
|
|
1288
|
+
"span",
|
|
1289
|
+
"zero"
|
|
1290
|
+
].includes(options.displayBlanksAs || "")) options.displayBlanksAs = "gap";
|
|
1066
1291
|
if (![
|
|
1067
1292
|
"standard",
|
|
1068
1293
|
"marker",
|
|
@@ -1185,10 +1410,10 @@ function addImageDefinition(target, opt) {
|
|
|
1185
1410
|
const intHeight = opt.h || 0;
|
|
1186
1411
|
const sizing = opt.sizing;
|
|
1187
1412
|
const objHyperlink = opt.hyperlink || "";
|
|
1188
|
-
const strImageData = opt.data || "";
|
|
1413
|
+
const strImageData = opt.data || (opt.svg && !opt.path ? svgMarkupToDataUri(opt.svg) : "");
|
|
1189
1414
|
const strImagePath = opt.path || "";
|
|
1190
1415
|
let imageRelId = getNewRelId(target);
|
|
1191
|
-
const objectName = opt.objectName ? encodeXmlEntities(opt.objectName) : `Image ${target._slideObjects.filter((obj) => obj._type === "image").length}`;
|
|
1416
|
+
const objectName = opt.objectName ? encodeXmlEntities(validateObjectName(opt.objectName, "image")) : `Image ${target._slideObjects.filter((obj) => obj._type === "image").length}`;
|
|
1192
1417
|
if (!strImagePath && !strImageData) {
|
|
1193
1418
|
console.error("ERROR: addImage() requires either 'data' or 'path' parameter!");
|
|
1194
1419
|
return;
|
|
@@ -1215,16 +1440,21 @@ function addImageDefinition(target, opt) {
|
|
|
1215
1440
|
h: intHeight || 1,
|
|
1216
1441
|
altText: opt.altText || "",
|
|
1217
1442
|
rounding: typeof opt.rounding === "boolean" ? opt.rounding : false,
|
|
1443
|
+
shape: opt.shape,
|
|
1444
|
+
points: opt.points,
|
|
1445
|
+
rectRadius: opt.rectRadius,
|
|
1218
1446
|
sizing,
|
|
1219
1447
|
placeholder: opt.placeholder,
|
|
1220
1448
|
rotate: opt.rotate || 0,
|
|
1221
1449
|
flipV: opt.flipV || false,
|
|
1222
1450
|
flipH: opt.flipH || false,
|
|
1223
1451
|
transparency: opt.transparency || 0,
|
|
1452
|
+
duotone: opt.duotone,
|
|
1224
1453
|
objectName,
|
|
1225
1454
|
shadow: correctShadowOptions(opt.shadow)
|
|
1226
1455
|
};
|
|
1227
1456
|
newObject.options = objectOptions;
|
|
1457
|
+
const mediaSlideKey = target._slideNum == null ? "sm" : target._slideNum >= 1e3 ? `sl-${target._slideNum}` : target._slideNum;
|
|
1228
1458
|
if (strImgExtn === "svg") {
|
|
1229
1459
|
target._relsMedia.push({
|
|
1230
1460
|
path: strImagePath || strImageData + "png",
|
|
@@ -1232,7 +1462,7 @@ function addImageDefinition(target, opt) {
|
|
|
1232
1462
|
extn: "png",
|
|
1233
1463
|
data: strImageData || "",
|
|
1234
1464
|
rId: imageRelId,
|
|
1235
|
-
Target: `../media/image-${
|
|
1465
|
+
Target: `../media/image-${mediaSlideKey}-${target._relsMedia.length + 1}.png`,
|
|
1236
1466
|
isSvgPng: true,
|
|
1237
1467
|
svgSize: {
|
|
1238
1468
|
w: getSmartParseNumber(objectOptions.w, "X", target._presLayout),
|
|
@@ -1246,7 +1476,7 @@ function addImageDefinition(target, opt) {
|
|
|
1246
1476
|
extn: strImgExtn,
|
|
1247
1477
|
data: strImageData || "",
|
|
1248
1478
|
rId: imageRelId + 1,
|
|
1249
|
-
Target: `../media/image-${
|
|
1479
|
+
Target: `../media/image-${mediaSlideKey}-${target._relsMedia.length + 1}.${strImgExtn}`
|
|
1250
1480
|
});
|
|
1251
1481
|
newObject.imageRid = imageRelId + 1;
|
|
1252
1482
|
} else {
|
|
@@ -1258,7 +1488,7 @@ function addImageDefinition(target, opt) {
|
|
|
1258
1488
|
data: strImageData || "",
|
|
1259
1489
|
rId: imageRelId,
|
|
1260
1490
|
isDuplicate: !!dupeItem?.Target,
|
|
1261
|
-
Target: dupeItem?.Target ? dupeItem.Target : `../media/image-${
|
|
1491
|
+
Target: dupeItem?.Target ? dupeItem.Target : `../media/image-${mediaSlideKey}-${target._relsMedia.length + 1}.${strImgExtn}`
|
|
1262
1492
|
});
|
|
1263
1493
|
newObject.imageRid = imageRelId;
|
|
1264
1494
|
}
|
|
@@ -1269,7 +1499,7 @@ function addImageDefinition(target, opt) {
|
|
|
1269
1499
|
type: "hyperlink",
|
|
1270
1500
|
data: objHyperlink.slide ? "slide" : "dummy",
|
|
1271
1501
|
rId: imageRelId,
|
|
1272
|
-
Target: objHyperlink.url
|
|
1502
|
+
Target: objHyperlink.url ? encodeXmlEntities(objHyperlink.url) : String(objHyperlink.slide)
|
|
1273
1503
|
});
|
|
1274
1504
|
objHyperlink._rId = imageRelId;
|
|
1275
1505
|
newObject.hyperlink = objHyperlink;
|
|
@@ -1292,7 +1522,7 @@ function addMediaDefinition(target, opt) {
|
|
|
1292
1522
|
const strType = opt.type || "audio";
|
|
1293
1523
|
let strExtn = "";
|
|
1294
1524
|
const strCover = opt.cover || "data:image/png;base64,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AAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKSEAhgAAAAAAAAgJRTAAAAAAAAAACmhAAYAAAAAAABICQUwAAAAAAAAQEoogAEAAAAAAABSQgEMAAAAAAAAkBIKYAAAAAAAAICUUAADAAAAAAAApIQCGAAAAAAAACAlFMAAAAAAAAAAKaEABgAAAAAAAEgJBTAAAAAAAABASiiAAQAAAAAAAFJCAQwAAAAAAACQEgpgAAAAAAAAgJRQAAMAAAAAAACkhAIYAAAAAAAAICUUwAAAAAAAAAApoQAGAAAAAAAASAkFMAAAAAAAAEBKKIABAAAAAAAAUkIBDAAAAAAAAJASCmAAAAAAAACAlFAAAwAAAAAAAKREkRUAAACwrUpLSwuGDRvWfMCAAS26du3avKysrLiioqKkZcuWzZs1a1bcvHnz0tLS0rJsNtusuLi4ebNmzUoLCgo+8/eijY2N9Zs3b66pra2tqqur21xTU1NdVVVVs2nTptqNGzdWbdiwoeYvf/nL5hUrVlQtWLBgw6xZs6pqamoaJQYAAEDaKYABAACIiIghQ4aUHnTQQW379u3bql27dq3at2/fpkWLFq2bN29eWVpa2qpZs2bNCwsLm2ez2fLCwsLyoqKi8sLCwtKknK+hoaG6vr6+qqGh4S91dXV/aWhoqNq8eXNVTU3NuqqqqvUbNmxYu2rVqjWrV69e99Zbb6177rnnPpgzZ06NTwYAAABJogAGAADIA8OGDWt+xBFHdBwwYECnLl26dGjdunXHFi1adCgtLe1YUlLSvlmzZq0KCgqK07yDwsLCssLCwrKIaPdp/zuNjY21mzdvXrdp06ZVNTU172/YsGHl2rVr31+2bNnKBQsWrHjyySffnzVrVpVPGAAAAE1Fpuexsd9HfaF+ZcSal0ptCAAAIAE6deqUPf744zvtueeeXbp3796lbdu2XSorKzuXlpZ2KS0t7VBYWFhhSztGQ0PDxpqampU1NTXL169fv+yDDz5Y9s477yybPXv2sj/96U8rVqxYUWdLAAAAbE9t9q6Jog4f/TUFMAAAQEJks9nMt7/97Y4jRozo1bdv397t2rXrXl5e3rWsrKxzcXFx+4gosKUmp7G2tnZVTU3Nso0bNy5btWrV0tdff/2tJ598cvG999672noAAADYFgpgAACAhPne977X6a9Fb/v27Xu1bNmyV1lZWa8kvXOXLauvr9/wl7/8ZdG6desWL1u2bNHChQsX/fGPf1w8derUjbYDAADAliiAAQAAmqhsNps59dRTuxx66KH9+/Tp87n27dv3Ly8v719UVOSRzXlq06ZNKzZu3Pj6+++//8abb775xqOPPvrG3XffvcpmAAAA+CsFMAAAQBNx6qmndvniF784qHfv3v3btWv3uYqKis8VFhaW2wxbUl9fv37Dhg1vfPDBB68vXrz4jccee2z+jTfeuNxmAAAA8pMCGAAAYBc45phjWn/rW9/aq3///kPatGnTv6Kiop9HOLO9NDQ0VG/cuPGtNWvWLFy4cOGcO+6445WHHnporc0AAACknwIYAABgJzjjjDO6f+lLX9qrV69eg1u3bj2orKysR0RkbIadJFddXb103bp18xcvXjz30UcffeXqq69+x1oAAADSRwEMAACwnZWWlhb86le/2u3QQw8d1r17931btmw5qLCwsMxmaEoaGhqqP/zww/nvvPPOzGeeeWbW2LFj36ipqWm0GQAAgGRTAAMAAGwHP/7xj7t+9atf3bdXr15D27Ztu1c2m21jKyRJXV3dmg8++OCVRYsWvfznP/95xh/+8IdltgIAAJA8CmAAAIBtcOKJJ7Y75ZRTDujXr9+w1q1bD81ms61shTSpq6tbt3bt2pfffPPNWbfccsvUe++9d7WtAAAANH0KYAAAgE+hoqKi4IILLhg0YsSI/bp27bpfy5YtB2YymUKbIR/kcrmGDz/8cP6777474/nnn59x4YUXvrZx40aPiwYAAGiCFMAAAAAf4/jjj2/7/e9//8D+/fsf2Lp1630KCgpKbAUiGhsbN61fv37eW2+9NeWGG2545u67715lKwAAAE2DAhgAAOB/ZLPZzAUXXPC5I4888sDu3bsfWFFRsVtEFNgMbFl1dfWSd999d8qsWbNmnnvuuS+vW7euwVYAAAB2DQUwAACQ10pLSwsuvfTSQYcccsjBXbt2HVFWVtbDVmDb1dbWrnr//fdfmDp16uRf/vKXL65evbreVgAAAHYeBTAAAJB3Bg0aVHrBBRd8fs899zywQ4cOBxQVFbWwFdj+Ghsba9euXTtrzpw5T59//vmTX3755WpbAQAA2LEUwAAAQF4YNmxY8/POO+/gIUOGHOZ9vrDz/W0ZfNFFFz07a9asKlsBAADY/hTAAABAarVq1arwyiuv3HfEiBEjO3TocFBhYWGZrcCu19DQUP3+++8/O2XKlIk/+clPZm7cuLHRVgAAALYPBTAAAJAqrVq1Kvztb3+7/3777Xd4x44dRxQWFpbbCjRdDQ0NG99///0pM2bMeOqHP/zhC8pgAACAz0YBDAAApMJZZ53V45vf/OaRvXr1GllaWtrVRiB5ampq3l28ePHEO++8c9LVV1/9jo0AAABsPQUwAACQWMOHDy+/6KKLvjB48OCjW7RoMdBGID0+/PDDV+fNmzfhvPPOe3L69Ol/sREAAIBPRwEMAAAkSqtWrQpvuOGGQ/bbb79/atOmzX6ZTCZrK5BeuVyubs2aNTNmzJjx2JgxYyavW7euwVYAAAA+ngIYAABIhB//+Mddv/e9732lZ8+e/1RcXNzWRiD/1NbWfvD2228/dssttzz029/+9l0bAQAA+L8UwAAAQJNVUVFRcO21137+4IMPPrZ169b7ZTKZAlsBIqJxzZo1M59//vnxp5122hR3BQMAAPx/CmAAAKDJOeWUUzqefvrpx/bu3ftL2Wy2jY0AH6e+vn7j0qVLH/vd7373x+uvv36ZjQAAAPlOAQwAADQJ2Ww2c+uttx5wyCGHnNC6deu9I8LdvsDWaFy7du1L06ZN+/OPfvSjZ1evXl1vJQAAQD5SAAMAALtU//79S6655pp/2nPPPY8tLy/vayPAZ1VTU7NswYIF488999wHp06dutFGAACAfKIABgAAdomf//znPU855ZQTu3btemRhYWGZjQDbW2NjY92KFSuevOWWW+689NJLF9kIAACQDxTAAADATuMxz8Cusn79+rlPP/30f5188slT6+rqcjYCAACklQIYAADY4fr27Vv8hz/84a+Pee5nI8CuUlNT8+68efPu/8EPfvDgwoULN9kIAACQNgpgAABghxkyZEjpNddc89XBgwefWFxc3MFGgKaitrZ21dy5c+/5yU9+8uc5c+bU2AgAAJAWWyqAPYoNAADYJqNHj+4wb968n06ZMuXRYcOGnaH8BZqa4uLi9sOGDTtjypQpj86bN++nJ510UntbAQAA0s4dwAAAwFY599xze33/+9//dufOnY/IZDJZGwGSIpfL1S1fvvzJG2644fbLLrvsbRsBAACSyiOgAQCAz+y8887r+53vfOfbHTt2PDyTyRTaCJBUuVyuYcWKFU/cdNNN//XrX/96sY0AAABJowAGAAC22WWXXTboG9/4xg9at249zDaAtFm7du2su++++9pzzjnnNdsAAACSQgEMAABsNcUvkE8UwQAAQJIogAEAgE9N8Qvks7Vr18665557rvv5z38+3zYAAICmaksFcGHlwOj6UV9orIqoWZG1PQAAyBO/+MUvet9xxx3nHHrooT8pLS3tYiNAPiotLe2y7777HvP973+/X1lZ2ZIpU6assxUAAKCpKetcHwXlH/01BTAAAOS5M844o/u99957zpe//OWflZeX94qIjK0AeS5TXl7e8+CDDx71/e9/v3dEvDVjxowPrQUAAGgqFMAAAMD/ceKJJ7a77777fjJq1Kh/KS8v7xOKX4B/lCkvL+99+OGHj/rWt77VfvXq1Qvnz59fbS0AAMCutqUC2DuAAQAgzwwdOrTs+uuvP6l///4nFRYWltkI20NjY2Ns2rQpqquro6amJurr62PTpk2xefPmqK+vj+rq6qivr4/NmzfHpk2boqGhYZv/fxUWFkZJSUk0a9YsioqKoqysLIqKiqJZs2ZRUlISRUVFUVpa+r9/FRQUCIjtoqGhoeq11167a8yYMffMmTOnxkYAAIBdZUvvAFYAAwBAnujUqVP2nnvuGbXXXnudnM1mK22Ej9PQ0BAbN26MDRs2/J+/Nm7cGBs3boyamprYtGlTbNq0KWpqaqK2trbJnqe4uDhKSkqitLT0f/9eUVERFRUV0aJFi//zV0VFRRQWFvog8LHq6urWvvjii7eceOKJf169enW9jQAAADubAhgAAPLcXXfdddAXv/jF00tLS7vZRn7L5XKxYcOGWLt2baxbty7Wrl37d3+tW7cuNmzYkPd7atGiRbRu3TpatWoVrVu3jjZt2vzvf27dunW0aNHCh4morq5e+sgjj1zzne98Z6ptAAAAO5MCGAAA8tTVV189+MQTTzyzoqJioG3kj8bGxli5cmUsX748Pvjgg1i9evX//n3t2rXR2NhoSZ9RYWFhtGrVKtq1axdt27b937937tw5OnTo4LHTeWbDhg3z77333qvOPPPMebYBAADsDApgAADIM1/72tfaXHrppad27979qIjQRKVUQ0NDrFq1KlasWBHvv//+//595cqVTfqRzGlXXFwcHTp0iI4dO0bnzp2jY8eO0alTp2jXrp1HS6dYLpdrfOeddx76+c9/fv2ECRPW2QgAALAjKYABACBP9OrVq9ldd931jT322OM7hYWFZTaSHh9++GG88847sXTp0njvvfdixYoVsXr16mhoaLCchCgsLIz27dtHp06dolu3btG9e/fo3r27x0mnTENDQ9W8efNu++Y3v/nHJUuWbLYRAABgR1AAAwBAHrjrrrtG/NM//dOZJSUlXWwj2davXx9Lly6Nd955539L3w8//NBiUqqysvJ/y+C//tWqVSuLSbiamppljz322G9Gjx49xTYAAIDtTQEMAAAp9qtf/arPD3/4w5+1atVqL9tIno0bN8aSJUvirbfeikWLFsV7770XmzZtspg8V1JSEl27do0+ffpE3759o3fv3lFeXm4xCbRu3bqXr7322ivGjh27yDYAAIDtRQEMAAApNGjQoNI77rjju7vttttJBQUFWRtJhtWrV8ebb74ZixcvjiVLlsTy5cujsbHRYtiigoKC6Ny5c/Tu3Tt69+4d/fr1i7Zt21pMQjQ2Nta98cYbd33rW9+6ff78+TU2AgAAfFYKYAAASJHS0tKCBx988Jj99tvvn7PZbBsbaboaGhri7bffjrfeeisWLFgQS5YscXcv201FRUX06tUr+vbtG3379o2ePXtGYWGhxTRhdXV1a2bMmHHjV77ylYdqamr85gcAALDNFMAAAJASp59+erdf/vKX51ZWVu5jG03T6tWr47XXXouFCxfGm2++GRs3brQUdooWLVpE3759Y8CAATFw4EB3CDdh69evf/E//uM//vPqq69+xzYAAIBtoQAGAICEGzRoUOm99977w969ex+byWTc4teErF+/PubNmxcLFiyIN954Q+FLk9GiRYvo169fDBgwIPbYY4+orKy0lCYkl8s1LF68eNyJJ554rcdCAwAAW0sBDAAACXbNNdcMOemkk35RVlbWyzZ2vVwuF++++27MnTs3XnvttViyZIl3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B7lcrm7y5Mm//vKXv/yIbQAAwK63pXcAK4ABAMg7paWlBTNnzjyzT58+x9vG39uwYUOMGzcuZsyY4VHPQF7KZDKx3377xde//vWoqKiwkH+waNGiP+27775X1dTUeCwEAADsQgpgAAD4H926dctOnjz5V506dRppG/9fLpeLqVOnxp///OfYuHGjhQB5r6KiIkaNGhX777+/x0L/g+XLlz9+6KGHXvLuu+/W2QYAAOwaWyqAvQMYAIC8MXz48PInnnjiynbt2o2wjf/vnXfeiWuvvTaee+652Lx5s4UARMTmzZtjzpw58dprr0XPnj2jRYsWlvI/Kioq+n7rW98aMnXq1Ofee+89f3AAAMAusKV3ACuAAQDIC9/+9rc73n777X9o0aLFANv4b1VVVXHXXXfFvffeG+vXr7cQgI+wbt26eP7552P9+vWx2267RVFRkaVERElJSefjjjvuoA8++GDKK6+88hcbAQCAnUsBDABAXjv//PP7XXzxxX8oKSnpbBv/bfr06XHttdfGokWLLAPgU3jnnXdi2rRp0bp16+jc2R8nERHZbLbyC1/4whElJSUvTp48eY2NAADAzqMABgAgb/3ud7/b60c/+tFVRUVFrWwjYs2aNXHzzTfHpEmTora21kIAtkJtbW289NJL8c4770Tfvn2jtLQ073dSWFhYNnz48C/26dNn4UMPPbTMpwQAAHYOBTAAAHnp1ltv3f+b3/zmfxYWFjbP913kcrl4/vnn4/rrr4/ly5f7cAB8BitXroxp06ZFRUVFdOvWLTKZTF7vo6CgIDto0KBDBw0atOiBBx54xycEAAB2vC0VwJmex8Z+H/WF+pURa17ym6wAACTTww8//KXDDjvsXzKZTN6/rPGDDz6I22+/Pd544w0fDIDtbMCAAfGtb30r2rRpk/e7yOVyjVOmTPn1yJEjH/LJAACAHavN3jVR1OGjv6YABgAgdV555ZXTPve5z30r3/fQ0NAQjz32WDz++ONRV1fngwGwg2Sz2Tj66KPjC1/4QhQUFOT9Pl5//fU79tprr9/7ZAAAwI6jAAYAIC9ks9nMyy+/fFafPn2Oz/ddvPvuu3HbbbfFe++954MBsJN069YtvvOd70S3bt3yfhdLliy5f5999rmypqam0ScDAAC2PwUwAACpV1paWjBr1qyzevfufVw+7yGXy8WTTz4ZDz74oLt+AXaBbDYbxxxzTBxxxBF5fzfw0qVLHxg6dOjlSmAAANj+FMAAAKRar169mk2ePHlsu3btDsrnPaxcuTJuueWWePvtt30oAHaxnj17ximnnBIdOnTI6z2sXr16yiGHHPIvS5Ys2exTAQAA28+WCuDCyoHR9aO+0FgVUbMia3sAADRpQ4cOLXvqqacub9Omzf75uoNcLhfPPPNMXH/99bF27VofCoAmYP369TFlypQoKSmJnj17RiaTycs9NG/evPtJJ500ZPLkyc+sWLHCoykAAGA7KetcHwXlH/01BTAAAIk1ZMiQ0kceeeSKVq1a7Z2vO6iuro7bb789nnjiiWhs9IRNgKaksbEx5s+fH++//34MGDAgstn8/DlLaWlpp6997WuDn3rqqadXrlxZ75MBAACfnQIYAIDUOfTQQ1s8+OCDv2/ZsuUe+bqDOXPmxNVXX+2RzwBN3PLly+OFF16Ijh075u0joUtLSzudcMIJ+7/00ktPv/3227U+FQAA8NkogAEASJVhw4Y1v++++37TsmXLQfl4/vr6+hg/fnz88Y9/jNpaP0MHSILNmzfHiy++GJs3b47ddtstCgoK8m4HxcXFbY866qg9n3vuuaeXL1/ucdAAAPAZKIABAEiNI488snLcuHG/b9GixcB8PP97770XV111VcyZM8eHASCBFi1aFC+//HL069cvWrRokXfnLykp6XDcccftP2fOnGcWLVq0yScCAAC2jQIYAIBUOPLIIyvvvPPO35aXl++Wj+d/+umn48Ybb4wPP/zQhwEgwf7yl7/ECy+8ECUlJdGrV6+8O3+zZs3aHHXUUfspgQEAYNspgAEASLxjjz227W233faH5s2b98m3s1dVVcXNN98cTz31VDQ2NvowAKRAY2NjzJ8/P5YtWxYDBgyIZs2a5dX5mzVr1uaYY4458M0333xm4cKFNT4RAACwdRTAAAAk2qGHHtritttuuzofy9+33347rrnmmli8eLEPAkAKvf/++/HKK69Enz59orKyMq/Ons1mK4888sh9Zs6c+dTSpUs3+zQAAMCnpwAGACCxjjjiiJb33nvvteXl5f3y6dy5XC4mTZoUN998c1RVVfkgAKRYVVVVTJ06NbLZbPTp0ycymUzenL24uLjtV7/61c+/8sorTy1evLjWpwEAAD4dBTAAAIl06KGHtrj33nt/l2/lb3V1ddx0000xefLkyOVyPggAeSCXy8WCBQvi3Xffjd133z2y2fz5mUyzZs1aH3300fvNmDHjSXcCAwDAp6MABgAgcYYOHVo2fvz4qysqKgbk07mXLVsWV111lUc+A+SplStXxiuvvBKf+9znoqKiIm/O3axZszZHH3300GeeeebJFStW1PkkAADAlimAAQBIlCFDhpQ++uij17Rs2XL3fDr31KlT49prr42NGzf6EADksaqqqpg+fXq0bds2unTpkjfnLikpaT9q1KihTz755JMrV66s90kAAICPt6UCuMB6AABoSjp16pSdMGHCv1dWVu6RL2dubGyMcePGxR133BF1dW56AiCitrY2br755hg/fnw0NjbmzbkrKyv3mDBhwr9369bNXQkAALCNFMAAADQZrVq1Kpw+ffolbdq02T9fzlxdXR2/+93vYtKkSd73C8DfyeVy8fjjj8fvf//7qK6uzptzt2nTZv8pU6Zc0qpVq0KfAgAA2HoKYAAAmoSKioqC2bNnX9KuXbuD8uXMS5cujYsuuijmz5/vAwDAx3r11VfjoosuiqVLl+bNmdu1a3fQ7Nmz/72iosLPrgAAYCu5iAYAoEmYOXPmz9q1a3dIvpz35ZdfjiuuuCLWrVsnfAA+0bp16+KKK66Il19+OW/O3K5du4Nnzpz5M+kDAMDWUQADALDLvfjii2N69OgxKh/Omsvl4oEHHogbbrghamtrhQ/Ap1ZbWxs33HBDPPDAA3nz2oAePXqMevHFF8dIHwAAPj0FMAAAu9SkSZO+NnDgwFPy4ax1dXVx8803x8SJE73vF4BtksvlYuLEiXHLLbdEXV1dXpx54MCBJ0+aNOlr0gcAgE9HAQwAwC7z6KOPHnXggQeekw9nXbduXfz617+OWbNmCR6Az2zmzJnx61//Ol9eJZA58MADz3n00UePkjwAAHyywsqB0fWjvtBYFVGzImtDAADsEDfeeOO+Rx999EWZTKYw7Wddvnx5XHXVVbFy5UrBA7DdbNiwIWbPnh0DBw6MioqKtB8307179/179uz56sMPP7xc+gAA5LuyzvVRUP7RX1MAAwCw011xxRV7fPe7372qoKCgWdrPOmfOnPjtb38bGzduFDwA2111dXVMmzYtOnfuHB07dkz1WTOZTOHuu+9+eJs2bV6aNGnSKukDAJDPFMAAADQZZ5xxRvef/exnvy0sLCxP+1knTJgQd999d9TX1wsegB2moaEhXnrppchms9G3b99UnzWTyRTttddeB/3lL395dubMmRukDwBAvlIAAwDQJBx00EEVf/jDH64pLi7ulOZz5nK5eOCBB+Kxxx4TOgA77c+eBQsWRF1dXfTv3z8ymUxqz1pQUFBywAEHDJs+ffqkpUuXbpY+AAD5aEsFcIH1AACwMwwaNKj0vvvuu7qsrKxXms9ZV1cX1113XUyaNEnoAOx0EydOjOuvvz7q6upSfc6ysrJef/rTn67u379/idQBAODvKYABANjhKioqCh577LGLKyoqBqb5nNXV1XHNNdfE7NmzhQ7ALvPKK6/ElVdeGVVVVak+Z4sWLQZOnDhxbEVFhZ9vAQDA33CBDADADjdz5syftW3b9sA0n3HdunVx2WWXxRtvvCFwAHa5xYsXx2WXXRZr165N9TnbtWt34MyZM38mcQAA+P8UwAAA7FBPPvnkqB49eoxK8xlXrVoVV1xxRSxfvlzgADQZK1asiCuuuCJWrlyZ6nP26NFj1KRJk0ZJHAAA/lth5cDo+lFfaKyKqFmRtSEAALbZjTfeuO+XvvSlCzOZTGp/8fDdd9+NK6+8MtatWydwAJqc6urqmDVrVvTv3z8qKytTe85u3boN79mz57yHH37Yb2MBAJAXyjrXR0H5R39NAQwAwA5x3nnn9T311FOvLigoKE7rGV977bW45pprorq6WuAANFmbN2+OGTNmRI8ePaJ9+/apPGMmkykYNGjQIYWFhVOee+45v5UFAEDqKYABANipjjrqqFb/8R//8YdmzZq1SusZX3755bj++uujrq5O4AA0eQ0NDfHSSy9Fp06dolOnTqk8Y0FBQXbYsGGfnz9//qQ33nhjk9QBAEizLRXA3gEMAMB21a1bt+wNN9zwnyUlJR3TesYpU6bEjTfeGPX19QIHIDHq6+vjxhtvjKlTp6b2jCUlJZ1uuOGG/+jWrZu7GgAAyFsKYAAAtqunn376XyorK/dI6/kmTZoUd955ZzQ2NgobgMRpbGyMO+64I5588snUnrGysnLw008//UtpAwCQrxTAAABsN88///w3unTp8k9pPd/EiRNj3LhxkcvlhA1AYuVyubj//vtTXQJ36dLlS88+++yJ0gYAIB95BzAAANvFTTfdNPzII488L5PJZNJ4vsceeyzGjx8vaABS47XXXotmzZpF3759U3m+zp0779urV695Dz/88DJpAwCQNlt6B7ACGACAz+wXv/hF7x/+8IdXFxQUNEvj+R544IF45JFHBA1A6ixYsCDq6upiwIABqTtbJpPJDBo06ODGxsbnpk6dul7aAACkiQIYAIAd5oADDqj43e9+99tmzZq1TeP5xo0bF5MmTRI0AKm1aNGi2Lx5cwwcODB1ZysoKMjut99+w5577rnH33vvvc3SBgAgLbZUAHsHMAAA2yybzWbuvPPOfyktLe2exvNNmDBB+QtAXpg0aVI89NBDqTxbaWlpj3vuuedfstlsRtIAAOQDBTAAANvs+eef/06HDh0OTePZHn744Xj44YeFDEDeeOSRR+LPf/5zKs/WoUOHw5599tlvSxkAgHygAAYAYJvcd999hw8ePPjUNJ7t/vvvjwkTJggZgLzz2GOPxX333ZfKs+25554/+NOf/nSYlAEASDvvAAYAYKudccYZ3ceMGXN5QUFBcdrONnHixHjkkUeEDEDeWrx4cWSz2ejbt2/ajpbp06fPvn/5y18mz5w5c4OkAQBIsi29A1gBDADAVhk2bFjzG2+88Q/NmjVrl7azPfroo6l99CUAbI2FCxdGUVFR9OvXL1XnKigoKD7wwAP3e/LJJx9dsWJFnaQBAEiqLRXAHgENAMBWuffee39ZWlraPW3nevzxx+PBBx8UMAD8jz//+c8xceLE1J2rtLS0x3333fdLCQMAkFYKYAAAPrVJkyaN6tSp0xEpPFeMHz9ewADwD8aPHx+TJ09O3bk6der0hUmTJn1VwgAApJFHQAMA8Kmcd955fU888cR/z2QyRWk618yZM+Puu+8WMAB8jNdeey06duwYnTt3TtW5unbtuk9BQcHzzz333DopAwCQNN4BDADAZ3LEEUe0vOKKK67NZrOVaTrXyy+/HDfffHPkcjkhA8DHyOVyMXv27OjSpUt06tQpNefKZDJF++yzz/CpU6c+9u67726WNAAASeIdwAAAbLNsNpu55ZZb/q2kpKRjms61YMGCuPnmm6OxsVHIAPAJGhsb4+abb44333wzVecqLS3tcvfdd5+fzWYzUgYAIC0UwAAAbNGkSZO+3rZt2wPTdKZly5bFDTfcEPX19QIGgE+prq4urr322li+fHmqztWuXbsDH3/88VESBgAgLTwCGgCAj3XZZZcN+upXvzo2k8mk5hcH33///bjyyiujqqpKwACwlerq6uLll1+OIUOGRHl5eWrO1aVLl31LS0unPvPMM2ukDABAEngENAAAW61///4lJ5988q8ymUxRWs60YcOG+P3vfx8bN24UMABso40bN8bvfve7VP15WlBQkP3hD394ft++fYslDABA4q9vrQAAgI/y4IMPnl1WVtYrLeeprq6O3/zmN7Fq1SrhAsBntGrVqrjyyiujuro6NWcqKyvr8/DDD58lXQAAkk4BDADA/zF+/Pgju3XrdnRazlNfX5/KdxYCwK60fPnyuO6666K+vj41Z+rRo8dXx40bd4R0AQBIMgUwAAB/53vf+16nI4444py0nCeXy8Vtt90Wb7zxhnABYDt7/fXX47bbbotcLpeaMx155JHnfvvb3+4oXQAAkkoBDADA/6qoqCi4+OKLLywsLCxPy5nGjx8fs2bNEi4A7CCzZs2Khx56KDXnKSwsrPj1r399QUVFhZ+bAQCQSC5kAQD4XxMnThxdWVk5OC3nef7552PixImCBYAd7LHHHosXXnghNeeprKzc89FHHz1RsgAAJFFh5cDo+lFfaKyKqFmRtSEAgDxxwQUX7DZq1KgLM5lMYRrO8+qrr8Ytt9ySqkdSAkBT/7O3d+/e0a5du1Scp2PHjkNzudxzU6ZMWSddAACamrLO9VHwMc/wcwcwAADRt2/f4h//+McXZzKZVPwG4HvvvRc33HBDNDY2ChcAdpKGhoa47rrrYtmyZak4T0FBQfbss88e27dv32LpAgCQqGtZKwAAYPz48T8qKyvrkYazbNiwIX7/+99HbW2tYAFgJ9u0aVP8/ve/j40bN6biPGVlZb3GjRs3RrIAACSJAhgAIM/ddNNNw/v06XN8Gs5SX18f1157baxdu1awALCLrFmzJq699tqor69PxXn69ev3jd///vdDJQsAQFIogAEA8thBBx1Uceyxx/5rRGTScJ477rgjFi9eLFgA2MUWLVoUd955Z1qOU/CNb3zj34YNG9ZcsgAAJOIC1goAAPLXzTfffFZxcXG7NJxl4sSJMX36dKECQBMxbdq0mDRpUirOUlJS0unOO+88Q6oAACSBAhgAIE/913/914FdunT5UhrO8tprr8Wf//xnoQJAEzN+/PhYsGBBKs7SrVu3o2+66abhUgUAoKlTAAMA5KEvfelLlV/5yld+lYazrFixIq6//vpobGwULAA0MY2NjXHdddfFihUr0nCczHHHHfergw46qEKyAAA0ZQpgAIA8dPXVV5+ezWYrk36OmpqauPbaa2PTpk1CBYAmatOmTXHttddGTU1N4s+SzWbb3njjjT+RKgAATZkCGAAgz9x6663Du3Tp8uWknyOXy8Utt9wSK1euFCoANHErV66MW2+9NXK5XOLP4lHQAAA0dQpgAIA8MnTo0LKvfvWrv0jDWSZMmBBz584VKgAkxJw5c+Kxxx5LxVlGjRr1i6FDh5ZJFQCApkgBDACQR+64444fFRcXd0z6OV5++eV45JFHBAoACfPQQw+l4he4SkpKOt5xxx0/lCgAAE2RAhgAIE9cfvnlu/fs2XNU0s/xwQcfxB133JGKR0gCQL7J5XJx2223xZo1axJ/lp49ex57+eWX7y5VAACaGgUwAEAe6NatW/a73/3uv2YymURf/9XX18cNN9wQ1dXVQgWAhKqqqoobb7wx6uvrE32OTCZT8N3vfvdX3bp1y0oVAICmRAEMAJAHxo8ff0pZWVmvpJ/jnnvuiaVLlwoUABJuyZIlcd999yX+HGVlZT3Hjx9/ikQBAGhKFMAAACn385//vOeAAQNGJ/0c06dPjylTpggUAFJi8uTJMWPGjMSfY8CAAaN//vOf95QoAABNhQIYACDFstls5qyzzjo3k8kk+tGEK1asiLvvvlugAJAyd911V6xYsSLRZ8hkMtmzzjrr3Gw2m5EoAABNgQIYACDFxo0b98XKysq9knyG2trauOGGG6K2tlagAJAyf/1zfvPmzYk+R2Vl5V7jxo0bKVEAAJoCBTAAQEoNHz68/OCDDz4t6ee4//77Y/ny5QIFgJRavnx5jBs3LvHnGDFixI+HDRvWXKIAAOxqCmAAgJS69dZbT8tms22TfIYZM2bEc889J0wASLnJkyfHzJkzE32G4uLitrfffvtp0gQAYFdTAAMApNBVV121R48ePb6S5DOsXLky7rrrLmECQJ64++6744MPPkj0GXr27PnVK664Yg9pAgCwKymAAQBSprS0tOAb3/jGT5N8rdfY2Bi333679/4CQB6pqamJ2267LRobG5N8jIJvfvObZ5aWlvqZGwAAu+6i1AoAANJlwoQJX6uoqBiQ5DOMHz8+Fi1aJEwAyDNvvvlmPPjgg4k+Q4sWLQY9+OCDx0gTAIBdRQEMAJAiRx55ZOWwYcN+kOQzzJ07N5544glhAkCemjhxYixYsCDRZxg+fPiPjjjiiJbSBABgV1AAAwCkyBVXXHFyUVFRRVLnr6qqijvvvDNyuZwwASBP5XK5uP3226O6ujqxZygqKmrxm9/85mRpAgCwKyiAAQBS4vzzz+/Xu3fv45J8httvvz0+/PBDYQJAnlu3bl3cfvvtiT5D7969jz///PP7SRMAgJ1NAQwAkALZbDZz6qmn/jyTyST2+m769OkxZ84cYQIAERExe/bsmDFjRmLnz2QyBaeeeurPs9lsRpoAAOxMCmAAgBT44x//eERlZeXgpM6/du3auPfeewUJAPyde+65J9atW5fY+SsrKwf/6U9/+oIkAQDYmRTAAAAJ17dv3+JDDjnkR0k+w9133x01NTXCBAD+Tk1NTdx9992JPsPBBx/8o759+xZLEwCAnUUBDACQcHfdddc3S0pKOiV1/smTJ8e8efMECQB8pLlz58azzz6b2PlLSko63nPPPd+SJAAAO4sCGAAgwb70pS9VDhw48KSkzr9mzZoYP368IAGALXrggQdizZo1iZ2/f//+Jx111FGtJAkAwM6gAAYASLArrrji1MLCwvIkzp7L5eK2226LTZs2CRIA2KJNmzbFbbfdFrlcLpHzFxYWll1++eU/kCQAADuDAhgAIKF+8Ytf9O7evftXkjr/s88+G2+88YYgAYBP5Y033ojnn38+sfN369bt6F/96ld9JAkAwI6mAAYASKgf/vCHP8pkMom8nvvggw/igQceECIAsFXGjRsX69atS+TsmUym4NRTT/2xFAEA2NEUwAAACXTdddcNa9eu3YFJnD2Xy8Udd9wRtbW1ggQAtsqmTZvizjvvTOz8bdq02f+mm27aT5IAAOxICmAAgIQpLS0t+NrXvnZ6Uud/4YUXYuHChYIEALbJq6++GjNmzEjs/Mccc8zpFRUVfiYHAMAO42ITACBhbr/99oMrKip2S+LsGzZsiHHjxgkRAPhM7r///qiqqkrk7OXl5X3/67/+6wgpAgCwoyiAAQASpKKiouCwww47Nanz33vvvYn9YS0A0HRs2LAh7r///sTOf9BBB/1zq1atCiUJAMCOoAAGAEiQ+++//+iysrKeSZx9zpw58dJLLwkRANguXnjhhViwYEEiZy8tLe32xz/+8StSBABgR1AAAwAkRN++fYv33Xfff07i7LW1tXHvvfcKEQDYru6+++6oq6tL5Oz77bffKf379y+RIgAA25sCGAAgIW6++eZRxcXFbZM4+yOPPBJr164VIgCwXa1atSoee+yxRM6ezWbb3njjjV+TIgAA25sCGAAgAYYOHVq21157fSeJs7/33nvxxBNPCBEA2CEmTpwYK1asSOTsQ4YM+c7QoUPLpAgAwPakAAYASIBrr732xKKiosqkzZ3L5eKee+6JxsZGIQIAO0R9fX3cddddkcvlEjd7UVFR5bXXXnuCFAEA2J4UwAAATdwBBxxQMWDAgG8kcfYZM2bEW2+9JUQAYId6880348UXX0zk7AMGDPjG8OHDy6UIAMD2ogAGAGjirrrqqhOKiooqkjb3pk2b4oEHHhAgALBT3H///VFbW5u4uYuKilpcffXV7gIGAGC7UQADADRhBx10UEX//v0Teffvww8/HB9++KEQAYCdYv369TFhwoREzj5w4MBvHHDAARVSBABge1AAAwA0Yf/5n/95bGFhYfOkzb1q1aqYPHmyAAGAnerpp5+O1atXJ27uwsLC8ssuu2yUBAEA2B4UwAAATdQBBxxQMWjQoNFJnP3uu++O+vp6IQIAO1V9fX3cddddiZx99913/+bQoUPLpAgAwGelAAYAaKIuv/zyYwsLC8uTNvfcuXNjwYIFAgQAdokFCxbE3LlzEzd3UVFRi9/97ndflyAAAJ+VAhgAoAkaOnRo2aBBgxL37t+6urr405/+JEAAYJf605/+FHV1dYmbe/fdd//mkCFDSiUIAMBnoQAGAGiCfvOb33ylqKioZdLmfu655xL53j0AIF1Wr14dzz33XOLmLioqann11VcfLUEAAD4LBTAAQBPTq1evZoMHD/5m0uaurq6ORx55RIAAQJPwyCOPRHV1deLmHjJkyLe6deuWlSAAANtKAQwA0MTcdNNNxxQXF7dN2twTJkyIqqoqAQIATUJVVVUifzmtuLi43a233uouYAAAtpkCGACgCWnVqlXhXnvtdVLS5l61alU8++yzAgQAmpTJkyfHqlWrEjf30KFDR7dq1apQggAAbAsFMABAE3LLLbccXlJS0jlpcz/44INRX18vQACgSamvr48HH3wwcXOXlJR0vummmw6VIAAA20IBDADQRGSz2cwBBxzw7aTNvWjRonjppZcECAA0SS+99FIsXrw4cXOPGDHiO9lsNiNBAAC2lgIYAKCJuOaaa/YuLy/vm7S5H3roocjlcgIEAJqkXC6XyLuAy8vL+1111VV7SRAAgK2lAAYAaCK+8pWvfDdpM8+bNy8WLlwoPACgSVu4cGG8+uqrrg8BAMgLCmAAgCbgsssuG1RZWblPkmbO5XIxfvx44QEAifDAAw8k7qklrVu33veSSy7pLz0AALaGAhgAoAkYNWrUCUmbefbs2bFs2TLhAQCJsGzZsnjllVcSN/cJJ5xwovQAANgaCmAAgF3sn//5nzt37NjxiCTN3NjYGA888IDwAIBEGT9+fDQ0NCRq5k6dOn1h9OjRHaQHAMCnpQAGANjFfvSjH30tk8kk6rps2rRpsWrVKuEBAImyatWqeOGFFxI1cyaTKfzpT386SnoAAHxaCmAAgF1o0KBBpX369Plqkmaur6+PCRMmCA8ASKQJEyZEXV1dombu27fvV/r27VssPQAAPg0FMADALnTZZZcdXlRUVJGkmadOnRpr164VHgCQSOvXr48pU6YkauaioqLK3/zmN0dIDwCAT0MBDACwi2Sz2cy+++57UpJmrqurc/cvAJB4jz76aOLuAt5///1PymazGekBAPBJFMAAALvI1VdfPbSsrKx3kmaeMmVKbNiwQXgAQKJt2LAhnn/++UTNXFZW1ueqq67aS3oAAHwSBTAAwC7y5S9/+bgkzVtfXx8TJ04UHACQCo8//nji7gL+0pe+dLzkAAD4JApgAIBdYPTo0R3atm07IkkzT5s2LdatWyc8ACAVPvzww5g+fXqiZm7fvv2I0aNHd5AeAABbogAGANgFfvrTn47KZDKFSZm3vr4+HnnkEcEBAKnyyCOPRH19fWLmzWQyhT/96U+/JjkAALZEAQwAsJN16tQp26dPn6OTNLO7fwGANFq3bl1MmzYtUTP36dPnmE6dOmWlBwDAx1EAAwDsZFddddUB2Wy2dVLmbWxsjEmTJgmOVOvYsWN06OCJmgD5aNKkSdHY2JiYebPZbOurrrrqAMkBAPBxFMAAADvZiBEjvp6keV988cVYtWqV4Ei1Ll26xIUXXhinnXZadO3a1UIA8siqVavipZdecj0JAEBqKIABAHaiM844o3tlZeXeSZk3l8vFxIkTBUdeyGQyMXjw4PjVr34VY8aMcUcwQB55/PHHI5fLJWbeysrKvc8444zukgMA4KMogAEAdqJTTjnlqxGRScq8CxYsiPfee09w5JVMJhN77713XHjhhTFmzJho3769pQCk3HvvvRcLFy5M1B9X/3NdCQAA/4cCGABgJ+nVq1ezXr16fTlJM3v3L/nsr0XwBRdcECeffHK0bdvWUgBSLGnXPb169fpyr169mkkOAIB/pAAGANhJrrjiioOLiopaJmXeBN4JAztEYWFhDB8+PC688MIYPXp0VFZWWgpACi1YsCCWLVuWmHmLiopaXnnllYdIDgCAf6QABgDYSYYPH/6VJM2btHfhwY5WVFQUI0aMiEsuuSRGjx4dLVu2tBSAFMnlcvH4448naub99tvvK5IDAOAfKYABAHaC0aNHd6isrByalHnXrl0bL7/8suDgI/y1CL744ovjhBNOiBYtWlgKQEq89NJLsW7dusTMW1lZudfo0aM7SA4AgL+lAAYA2AlOP/30o5J07fXMM89EQ0OD4GALiouL47DDDouxY8fGqFGjoqyszFIAEq6hoSGeeeaZJI1c8D/XmQAA8P8vEq0AAGDHymazmX79+n05KfPW1tbGlClTBAefUnFxcYwcOTIuvfTSGDVqVJSWlloKQII9//zzUVtbm5h5+/Xr9+VsNpuRHAAAf6UABgDYwX7zm9/sWVJS0jkp886YMSOqq6sFB1uppKQkRo4cGZdcckkcffTRUVJSYikACVRdXR0zZ85M0p8/na+44orBkgMA4K8UwAAAO9gXvvCFLyVl1lwuF08//bTQ4DNo3rx5HHXUUXHJJZfEyJEjI5vNWgpAwjz11FORy+USM++RRx75ZakBAPBXCmAAgB1oyJAhpZ07dz4iKfO+/vrrsWLFCsHBdlBeXh6jRo2KSy+9VBEMkDArVqyI119/PTHzdunS5fD+/ft79AQAABGhAAYA2KHGjh17aGFhYWJeCOruX9j+KioqYtSoUXHxxRfH4YcfHkVFRZYC4LpouyosLGz+H//xHwdLDQCACAUwAMAOteeeex6ZlFnXrl0b8+bNExrsIK1atYrjjz8+LrroohgxYkQUFPh2DKApmzdvXqxZsyYx8+61115HSg0AgAgFMADADnPMMce0bt269b5Jmfe5556LxsZGwcEO1qZNmxg9enRcfPHFimCAJqyxsTGee+65JP35MvyYY45pLTkAAPykAQBgBznzzDMPz2Qyibje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FpafffbZvaQFAJA+CmAAgE9p//3375+EOV9//XVhAXmjvLw8Ro0aFf/+7/8eI0eOjGw2aymA67FP6fOf//xAaQEApI8CGADgU+rRo8fuTX3G2traePvtt4UF5J2KiooYNWpUXHzxxXH44Yc3+XdvAum2ePHiRLySo1evXoOkBQCQPgpgAIBPqXXr1k3+DoklS5ZEQ0ODsIC81apVqzj++OPj4osvjhEjRkRBgW97gZ2voaEhlixZ0uTnbNOmjQIYACCFfCcMAPApDBkypLR58+a9m/qcb775prAAIqJ169YxevToGDt2rCIYcF32MZo3b95n0KBBpdICAEgX3wEDAHwKp556av9MJtPkr53eeustYQH8jTZt2sTo0aPjvPPOi+HDhyuCAddlfyOTyRT84Ac/+Jy0AADSxXe+AACfwuDBg5v84/Hq6+tj0aJFwgL4CJ06dYqTTz45/u3f/i323nvvyGQylgLsUIsXL07Eqzn23HPPgdICAEgXBTAAwKfQpUuXAU19xnfeeSfq6uqEBbAFnTt3jjFjxiiCgR2utrY23n333SRc53oPMABAyiiAAQA+hZYtW/Zv6jN6/DPAp9elS5cYM2ZMnHvuuTF48GALAfL2+iwJ17kAAGwdBTAAwCcYPnx4eUlJSeemPqfHPwNsvV69esVpp50W55xzTvTvrwMB8u/6rLS0tPPw4cPLpQUAkB4KYACAT/Ctb31rt4ho8s8IXbx4sbAAtlGfPn3irLPOinPOOSd22203CwG2i4T8gl7m29/+dj9pAQCkhwIYAOAT7L777k2+CVi7dm1s2LBBWACfUZ8+feLss8+OM888M3r27GkhwGfy4Ycfxrp165r8nAMHDlQAAwCkSJEVAABsWadOnZr8D8TefvttQQFsRwMGDIgBAwbEggULYvz48bF06VJLAbb5Oq1Vq1audwEA2GkUwAAAn6CyslIBDJCnBgwYEP3794958+bFQw89FO+++66lAFtlyZIlsddeezX1613PvgcASBEFMADAFnTq1CnbvHnzXk19ziVLlggLYAfJZDIxePDg2GOPPeLll1+OBx98MFauXGkxQGqu05o3b967Xbt2RatXr66XGABA8nkHMADAFowZM6ZnJpPJNuUZGxsbPZoUYCfIZDKx9957x4UXXhhjxoyJ9u3bWwrwiZYuXRqNjY1NesaCgoLsqaee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k8nE7NmzY+LEibFmzRoNAXif/VNSzJo161kTAwBongTAAAC70O233/7KOeecszU/P78022sdMGBAtG/f3tWu0My9+uqrMWnSpFi1apVmALyPjh07xgEHHJCIWhsbG6u/8Y1v/NXUAACaJwEwAMAutHLlyob169fP6tat2+hsrzWVSsXhhx8ekyZNMjhohubMmROTJ0+OJUuWaAbAh3D44YdHKpVKRK3r16+fVVFR0WhqAADNU54WAADsWq+++mpirts77LDDDAyamTfffDP+/d//PX7yk58IfwE+pFQqFSNGjEhMva+88sozpgYA0Hw5AQwAsIvddNNNz5166qnV+fn5rbO91m7dukX//v1j4cKFBgc5btmyZfHYY4/F/PnzNQPgIzrggAOic+fOiai1sbFxy4033jjL1AAAmi8BMADALrZy5cqG8vLyGT179vx0Euo9+uijBcCQw5YvXx7jxo0T/AJ8wv1SUpSXlz9TXl7eYGoAAM2XABgAYDeYMWPGUxdccEEiAuAhQ4ZE69ato7q62uAgh6xcuTImTJgQc+fOjUwmoyEAH1ObNm3i0EMPTUy9zz777FOmBgDQvPkGMADAbvDVr371lYaGhk1JqLWgoCCOOOIIQ4McsW7duvj5z38ed955Z8yZM0f4C/AJjRw5MvLz8xNRa0NDw8abbrrpVVMDAGjenAAGANgNKisrm1atWjW9T58+5ySh3qOPPjqefPJJQREk2Pr16+Oxxx6L2bNn+3cZYBdJpVIxatSoxNS7cuXKadXV1WmTAwBo3pwABgDYTaZNm5aY6/c6duwYAwYMMDRIoA0bNsSvf/3r+Nd//dd49dVXhb8Au9CAAQOiY8eOian36aefftLUAAAQAAMA7CZf+9rX5tTX11ckpd6jjjrK0CBBqqqq4v77749vf/vb8eKLL0ZTU5OmAOxiRx55ZGJqra+vX/eNb3zjdVMDAMAV0AAAu0ltbW16xYoVT++///6fT0K9hx56aLRt2zaqqqoMD7LYli1bYsqUKfHcc8/F9u3bNQRgN2nbtm0MGTIkMfUuX778qdraWtc/AwDgBDAAwO70xz/+cUJSas3Pz4/jjjvO0CBL1dTUxKOPPhq33XZb/OUvfxH+Auxmxx57bOTn5yel3Myvf/3rCaYGAECEABgAYLe66667llZXV89PSr1HH310tGjRwuAgi7wd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qATAAABZ4umnn968fPnyxF3xN3r06GjXrp0BAgBZqUOHDnH88ccnru5ly5ZNmD59+hYTBADgoxIAAwBkkbvvvvtPmUymKUk1FxYWxumnn254AEBWOvPMMxP3yYpMJtN41113/dH0AAD4OATAAABZ5Be/+MWatWvXTkta3UcccUT06tXLAAGArNK7d+847LDDEld3eXn5X+6///51JggAwMchAAYAyDIPP/zwn5JWcyqVijPPPNPwAICsMmbMmEilUomr+8EHH/yT6QEA8HEJgAEAsszXv/71NzZs2DAraXUPHDgwDj74YAMEALLCoEGDYsCAAYmru6KiYuatt966wAQBAPi4BMAAAFlo3Lhxv01i3WPGjIm8PFtMAGDvysvLizFjxiSy9j//+c+/NUEAAD7RflgLAACyz/XXXz+nqqrqr0mru1evXnHUUUcZIACwVx1zzDHRvXv3xNW9adOmV2666aa5JggAwCchAAYAyFJ/+tOf7k1i3WPGjInS0lIDBAD2ijZt2sRZZ52VyNofeOCBe00QAIBPSgAMAJClbrrpprlJPAVcXFwcZ555pgECAHvFWWedFS1btkxc3Zs2bXrl5ptvnmeCAAB8UgJgAIAsNm7cuF8lse5Ro0ZF7969DRAA2KP69OkTI0eOTGTtjz322K9MEACAXUEADACQxcaOHTu7qqrqb0mrO5VKxfnnnx+pVMoQAYA9tv/4/Oc/n8j9R2Vl5d+uueaav5kiAAC7ggAYACDLTZ069bdJrLtv374xZMgQAwQA9ojDDjsssTeQTJ48+TcmCADAriIABgDIcpdeeumLVVVVryax9s9//vNRXFxsiADAblVaWhrnn39+Imuvqqr66+WXX/6SKQIAsKsIgAEAEuChhx76WRLrLisri9NPP90AAYDd6qyzzoqSkpIklp753e9+91MTBABgVxIAAwAkwA033DB3w4YNs5JY+3HHHRd9+vQxRABgt+jbt28cddRRiay9oqJi1te//vU3TBEAgF1JAAwAkBA///nPfxoR6aTVnUql4vOf/3zk5dl6AgC7Vn5+flx00UWRSqWSWH76F7/4xX+bIgAAu5q3cAAACXHHHXe8tW7duulJrL13795xzDHHGCIAsEudcMIJ0b1790TWXl5e/pc77rjjLVMEAGBXEwADACTI3XfffW8mk2lKYu1nnXVWtG3b1hAB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onv37vEv//IvccABBzSrdWcymaYnnnji9s997nPPeAoAAODDEQADAJBYDz/88NJjjjlmY+/evY+KiGZzFKq0tDSGDx8eq1evjvXr13sQAHLcwIED45prrol27do1t6VnZsyY8YOzzjprqqcAAAA+PAEwAACJdv/99795zDHHVO6zzz5HRDMKgVu0aBGHHXZYtGzZMhYuXBjpdNrDAJBjCgoK4pxzzonzzz8/WrRo0dyWn37uuefuOuWUUyZ4EgAA4KMRAAMAkHi///3v5w8bNmxF3759j2lO10GnUqno27dvDB06NBYvXhxbtmzxMADkiJ49e8YNN9wQgwcPblbf+434x7XPU6ZM+fbpp58+2ZMAAAAfnQAYAICc8OCDDy4ZNmzYin79+jWrEDgionXr1nHEEUdEfX19LF261MMAkGCpVCpOOOGEuOKKK6JNmzbNbv07wt9vnXPOOX/xNAAAwMcjAAYAIGc89NBDS4YNG7a8X79+xza3EDg/Pz8OPvjg6NWrV8yfPz8aGho8EAAJU1JSEpdffnmccMIJkZ+f3+zWn8lkGp944olvffazn53maQAAgI9PAAwAQE556KGHlo4cOXJdnz59RqWa252ZEdG1a9cYNmxYLFu2LCorKz0QAAnRt2/fuO6662K//fZrluvPZDLpp59++rvnnHPO054GAAD4ZATAAADknD/96U+LDj300KX7779/s7sOOiKiuLg4jjzyyCgpKYk333wz0um0hwIgSxUUFMRnP/vZuPDCC6OkpKRZ9iCdTjc88sgjt5x//vnTPREAAPDJCYABAMhJDz/88NId3wQelUqlmt09mqlUKvr06RMHH3xwLFy4MLZt2+ahAMgynTt3jrFjx8bQoUOjGV5aERH/CH+feOKJ2y+88MLnPBEAALBrCIABAMhZDz300JIePXq8NmjQoGPz8vJaNMcetG3bNkaNGhVNTU2xZMkSDwVAFkilUjF69Oi48soro0OHDs22D01NTdt++9vf/stll132oqcCAAB2HQEwAAA5bdKkSeXdu3efM3jw4GYbAufn58eAAQOiV69esWDBgti+fbsHA2Avad26dVx66aVx/PHHR35+frPtQ2NjY/WvfvWrf7nuuute81QAAMCuJQAGACDnTZ48eW1jY+OMI4444uiCgoKS5tqHrl27xqhRo2Lbtm2xcuVKDwbAHpRKpWLUqFExduzY6NWrV7PuRX19/fo77rjjK9/61rcWejIAAGDXEwADANAsPP/881UbNmx45rjjjjuqsLCwrLn2obCwMAYNGhT77bdfLF68OGpraz0cALtZ+/bt44orrogTTzwxCgub9/uU2tralTfffPPVP/nJT1Z7MgAAYPcQAAMA0Gz87W9/27p27doZJ5xwwsjCwsK2zbkXnTp1ipEjR0Z1dbXTwAC70ciRI+Pqq6+OHj16NPte1NTULL/hhhuu/e1vf7vOkwEAALuPABgAgGbltdde2zpv3rynTznllKFFRUWdmnMvCgsL49BDD4399tsvFi1a5DQwwC709qnfk08+udmf+o2I2Lx587yLL774unHjxm30dAAAwO71fgFwat9zYsTOftC4LmLjq610DwCAxOrVq1fhs88++69du3Y9QTciGhoaYurUqTF58uRobGzUEICPqaCgIE499dQYPXq04HeH8vLyp4499tjvrly5skE3AABg9+swrDYKuuz8ZwJgAAByWuvWrfNeeumlm/fdd9+zdeMfVq9eHffff38sWbJEMwA+ov322y8uuugi1z2/w8KFC38/fPjwnzY0NGR0AwAA9gwBMAAAzd7zzz9/8aGHHnp1RKR0IyKTycTMmTPjz3/+c9TV1WkIwAcoKSmJ8847L0aMGBGplL9Kdki//PLL9xx77LEPagUAAOxZ7xcA+wYwAADNwn333Tfn+OOP39yrV6/DQwgcqVQqevfuHcOHD49169ZFRUWFhwTgPRxyyCExduzY6N+/v/B3h0wm0/jMM8/828knnzxONwAAYM97v28AC4ABAGg2fve7370xePDgJf369Ts6lUrl60hEcXFxjBgxInr06BFLly6N2tpaTQHYoUOHDvGFL3whzjzzzCguLtaQHZqammoeeOCBWz73uc9N1w0AANg7BMAAALDDww8/vKygoOC54cOHH1FQUFCqI//QrVu3OO6446K0tDQWL14cTU1NmgI0Wy1btoxzzjknLr300ujevbuGvENtbe2K22677arbbrvtDd0AAIC9RwAMAADv8Oyzz25avHjx0yeddNKQoqKiTjryD3l5edGnT58YOXJkbN26NVatWqUpQLNz+OGHx1e+8pUYMGBA5OXlacg7VFVV/e3CCy+8/oEHHvDdAAAA2MsEwAAA8C7z58+vefbZZ58+44wz+hcX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OigOOOCAKCoq0pQs0djYuGXmzJk/PvPMMyc2NDS4XgAAAPjQBMAAAJADjjzyyNY/+9nPrujbt++5EZGnI9mluro6Fi5cGPPnz4958+ZFZWWlprBXtGvXLg455JAYMGBA9O/fP1q39nsjWSj91ltv/fmqq676xaxZs6q1AwAA+KgEwAAAkEN++ctfjhgzZsyNrVq16q0b2SmdTsfKlStj0aJFsXDhwli8eHFs27ZNY9gtSkpKol+/ftG/f//Yf//9o1evXpGX53dEslVNTc3yRx999EdXXnnlK7oBAAB8XAJgAADIMd26dSt8+OGHPzd48ODL8vPzbdyzXCaTiTVr1sTChQtj0aJFsWjRotiyZYvG8LGUlZVF//79/xn6du/ePVKplMZkuaampprXXnvtV2PGjHmgoqKiUUcAAIBPQgAMAAA56rjjjiv7r//6r8tdC508mzdvjuXLl8eKFSti+fLlsXjx4qipqdEY/pfi4uLo169f9O7dO/bZZ5/Yd999o6ysTGMSJJPJpJcsWfLn66677pfTp0/3mx8AAMAuIQAGAIAc99Of/nTIueeee3NpaWlf3UimxsbGWLlyZSxdujSWLVsWy5cvj3Xr1kUmk9GcZiKVSkWXLl1in332iT59+kSfPn2iV69eUVBQoDkJtXXr1sUPPvjgj6699tq/6wYAALArCYABAKAZaNeuXf64cePOGTp06BUFBQWtdST56uvrY+XKlf88KbxixYpYu3ZtpNNpzUm4vLy86Nq1a+yzzz7//KdXr17RsmVLzckBjY2NW/7617/+4pxzznm0srKySUcAAIBdTQAMAADNyIknntjmnnvuuXzfffcdk0qlHB3MMdu3b481a9bEmjVrYu3atbF27dooLy+PDRs2CIazUF5eXnTs2DG6desWXbt2jW7dukW3bt2iR48eUVhYqEE5JpPJNC5ZsuRR1z0DAAC7mwAYAACaoa9+9av7Xnfdddd16NDhCN3IfY2Njf8MhNetWxfr1q2LioqKWLduXWzbtk2DdrPS0tLo3LnzP//p0qVLdO3aNbp27eoK52Ziw4YNM//rv/7rxz/60Y+W6wYAALC7CYABAKAZ++UvfznirLPOuq64uNj3gZupmpqaWL9+/T//qaioiMrKyqisrIxNmzZFY2OjJn2AgoKCaN++fbRr1y7at28fHTt2jC5dukSnTp2ic+fOUVxcrEnN1NatW98aP378PVdcccXLugEAAOwpAmAAAGjm2rVrl//ggw+eOWLEiCsLCwvb6gjvtHnz5n+GwZs2bYrKysqorq6OLVu2xJYtW6K6ujqqq6sjk8nk3NpTqVS0bt06WrduHWVlZdGmTZsoLS39X2Fvu3btok2bNh4U/peGhobKl1566efnnHPO+OrqavevAwAAe5QAGAAAiIiIoUOHFt97770XHHjggRfk5+c7ssiHlk6n/xkEV1dXR01Nzfv+k8lkora2NtLpdNTX10dTU1PU1dXt0u8U5+XlRcuWLSM/Pz+KiooiLy8vWrVqFalUKoqLi3f6T0lJSbRq1eqfgW9paWnk5eUZMB9aU1NTzYIFC/745S9/+Y+zZ8+u0REAAGBvEAADAAD/y2mnndb2rrvuurRPnz5n5+XlFeoIe9LbgfDbtm/f/r7XUBcUFESLFi3++b/fDnxhT8pkMg1LliwZd8stt/xq0qRJVToCAADsTQJgAABgp0477bS2d95554X777//5wTBAP9XJpNpWLhw4QO33nrrHwS/AABAtni/ADi/7UHRc2c/SG+LqC33/gcAAHLZokWL6u69995X0un0swcddFCnkpKS3roC8A8VFRUz/7//7/+77aKLLpq6aNGiOh0BAACyRXH3xsgr3fnPBMAAAEDMnDmz8u67736qqalpWr9+/Ypbt27dN5VKpXQGaG4ymUx6zZo1U+65555/Peeccx6cOXNmpa4AAADZRgAMAAB8KDNnzqz88Y9//Gw6nZ4uCAaak7eD37vvvvtfzz///McEvwAAQDYTAAMAAB+JIBhoLgS/AABAEgmAAQCAj+XtILisrOyFvn37diwuLu4VEYJgIBdkKioqnrv33nu/PWbMmEcEvwAAQJK8XwCc2vecGLGzHzSui9j4aivdAwAA/unqq6/u8ZWvfOX8Pn36nJWXl9dCR4CkSafT9UuXLh3/X//1Xw/84he/WKMjAABAEnUYVhsFXXb+MwEwAADwkZ1xxhntb7/99rMPPPDA8/Pz81vrCJDtmpqaqhcsWPDgd77znUcmTpzotC8AAJBoAmAAAGC3GD58eMkPf/jDzwwePPjioqKijjoCZJv6+voNr7322u9vvPHGx2fPnl2jIwAAQC4QAAMAALvV0KFDi++5556zDjnkkPOKioq66giwt9XV1a19/fXXH7z++uvHC34BAIBcIwAGAAD2iFatWuXdc889w0455ZTzO3bseJSOAHtYZsOGDbOmTJny4PXXX/9qbW1tWksAAIBcJAAGAAD2uH/913/tf/7555/dq1ev0/Ly8lroCLC7pNPp+pUrV05+4IEHHvnOd76zSEcAAIBcJwAGAAD2mjPOOKP97bfffvYBBxzw2YKCgjY6AuwqjY2NVW+++eafv/e97z06YcKETToCAAA0FwJgAABgrxs+fHjJ97///dGDBg0aU1paur+OAB9XdXX1wtdee+3Rr371q1Nfe+21Wh0BAACaGwEwAACQVb761a/ue8EFF3y6b9++ZxUUFLTWEeCDNDY2bnnrrbfG/+EPf5j4ox/9aLmOAAAAzZkAGAAAyEpDhw4t/sEPfnDy4MGDz27dunV/HQHerbq6+s2XX375weuuu+7ppUuXbtcRAAAAATAAAJDlCgsLU3ffffeQ0aNHn9G1a9fj8vLyinQFmq90Ol1XXl4+bcqUKROuvfbav+sIAADA/yYABgAAEqNPnz4t/v3f/33UyJEjz2rfvv2nIiKlK9AsZDZt2vTXF1544bGvfe1rzzntCwAA8N4EwAAAQCJddNFFXa6++uqTDzzwwLNbtmzZTUcg99TV1a1ZsGDBuJ/+9KdP3n///et0BAAA4IMJgAEAgETr1q1b4d13333k4YcffmqHDh2OyMvLK9QVSK50Ot2wcePGWbNmzZp8/fXXz6qoqGjUFQAAgA9PAAwAAOSMo48+uvWtt956/CGHHHJKu3btBkdEnq5AIqQrKytfmzdv3uQ777xz+owZM6q1BAAA4OMRAAMAADnpuOOOK/vGN75x/CGHHHJa27ZtB4bvBUO2yVRVVc2dN2/epO9///vTpk+fvkVLAAAAPjkBMAAAkPNuu+22vmedddZJffr0Oa5Vq1a9dQT2ntra2uXLly+f/uijjz51xx13vKUjAAAAu5YAGAAAaFa+9KUvdbv44ouP7t+//wlOBsMekamqqpq7cOHCv/z+97+fcd9995VrCQAAwO4jAAYAAJqtSy65pOtll112jDAYdrl0VVXVvIULF/7lV7/61bO/+93v1moJAADAniEABgAAiIirr766x/nnnz9q//33P7JNmzZDUqlUga7Ah5fJZBoqKyv/vnjx4uf+9Kc/zbr33ntX6woAAMCeJwAGAAB4l379+hV97WtfGzRy5MhRPXv2PLaoqKizrsD/VV9fv37VqlXPvPDCC8/9+7//+5zFixfX6woAAMDeJQAGAAB4H61bt8678847Bx599NFHde/efURpaen+4apomq/M1q1bF69Zs+bF5557btY3v/nNOdXV1WltAQAAyB4CYAAAgI9g8ODBrcaOHXvI8OHDD+vevfvw1q1bHxACYXJXprq6+s01a9a88sorr7z8k5/8ZN5rr71Wqy0AAADZSwAMAADwCVx//fX7nHHGGYf169dvePv27Yfm5+e31hWSrLGxsXrjxo2vvvXWWy+PHz/+lR//+McrdQUAACA5BMAAAAC70Je//OUe55xzzvA+ffoM7tix45CioqKuukI2q6+vX7t27doXFy9ePGfixImv3Xvvvat1BQAAILkEwAAAALvRl7/85R6f+cxnBvfr129Qly5dDm/ZsqVAmL2qrq5u7bp16wS+AAAAOUoADAAAsIe0atUq75prrtnn2GOPPXi//fY7uH379oeUlpb2TaVS+brDbpKuqalZtnHjxnlvvfXW3GeffXbef/3Xfy2vra1Naw0AAEBuEgADAADsRQceeGDLq6+++oAhQ4Yc3LNnz4Pbtm17sGuj+biampqqq6qqXi8vL583Z86ceb/85S/nvfjii1t1BgAAoPkQAAMAAGSZoUOHFn/xi1/cf9CgQQf26NHjwHbt2h3YqlWr3qlUKk932CFdU1OzvLKycsHq1asXzJkzZ8Gf//znJTNmzKjWGgAAgOZNAAwAAJAAxx13XNkFF1xw4MEHH3xA165dDywtLd23pKRkn1QqVag7uS2TyTRs27ZtRXV19dJ169YtfOONNxZOmDBh4YQJEzbpDgAAAO8mAAYAAEiw8847r+OJJ57Yp3///vt16dKlT5s2bfZr3bp1v/z8/GLdSZampqaa6urqxZs3b16ybt26pQsXLlzy9NNPL33ooYc26A4AAAAflgAYAAAgx7Rr1y7/kksu6TFkyJCe++67b89OnTr1Kisr61VcXNyzZcuW3VKpVL4u7R2ZTKaprq6uvKamZtWWLVtWVlRUrFy6dOnK2bNnr7r//vvXVFZWNukSAAAAn4QAGAAAoBnp1KlTwec+97luQ4cO7bnPPvv0aNeuXafWrVt3Li4u7tqyZcvORUVFnfLy8lro1MeTTqe319fXr6+rq6uoqalZW11dvb6ysnL9ihUrVr/66qurHnzwwbUVFRWNOgUAAMDuIgAGAADgfznjjDPaH3bYYZ369OnTuUuXLp3Kysral5SUtC0uLu5YVFTUrqioqG2LFi065OfnlzaXnjQ1NW3dvn37xvr6+qr6+vrKmpqaDdu2bavasmXLpnXr1lUsXbp0/Ysvvrh+4sSJlZ4gAAAA9iYBMAAAAB9Lr169CkeNGtXuoIMOatexY8ey9u3bl7Zp06Z1SUlJWXFxcetWrVq1btGiRVlRUVHrwsLC1hGRX1hYWBoR+QUFBSV5eXkFeXl5u/0/LtPpdG06nW5sbGzcFhFNDQ0NW3f83+r6+vrq7du3b6mtra2uqamp3rZtW/XmzZurN23aVL1hw4YtCxYsqJo1a1bl0qVLt5s4AAAASSAABgAAYK/q169fUffu3Vvss88+xSUlJQVv//8LCwtT3bp1+8BTxuXl5VsbGhoyb//vbdu2Na5YsaJmzZo12xcvXlyvwwAAADQn7xcAF2gPAAAAu9vixYvrdwS11boBAAAAu0+eFgAAAAAAAADkBgEwAAAAAAAAQI4QAAMAAAAAAADkCAEwAAAAAAAAQI4QAAMAAAAAAADkCAEwAAAAAAAAQI4QAAMAAAAAAADkCAEwAAAAAAAAQI4QAAMAAAAAAADkCAEwAAAAAAAAQI4QAAMAAAAAAADkCAEwAAAAAAAAQI4QAAMAAAAAAADkCAEwAAAAAAAAQI4o0AIAAAAAAACA5GhoLIyCxoaIiEilIpNXGE1v/0wADAAAAAAAAJAghQUN/0x6MxGppvT/5L6ugAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAAYAAAAAAADIEQJgAAAAAAAAgBwhAIb/v5272ZHiusM4/FZ1NUkz9sQwOF4EyZJtpJCwysa5jSy4n1xPEqRIuQFvvfGSgIwBOzGRQAQERnx0d1UW0cgWGvKxsMGvnmfVdc7/1OJsf+oCAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoIQADAAAAAAAAlBCAAQAAAAAAAEoIwAAAAAAAAAAlBGAAAAAAAACAEgIwAAAAAAAAQAkBGAAAAAAAAKCEAAwAAAAAAABQQgAGAAAAAAAAKCEAAwAAAAAAAJQQgAEAAAAAAABKCMAAAAAAAAAAJQRgAAAAAAAAgBICMAAAAAAAAEAJARgAAAAAAACghAAMAAAAAAAAUEIABgAAAAAAACghAAMAAAAAAACUEIABAAAAAAAASgjAAAAAAAAAACUEYAAAAAAAAIASAjAAAAAAAABACQEYAAAAAAAAoIQADAAAAAAAAFBCAAYAAAAAAAAoMY3JP//9K8My551lzpAk293a7QAAAAAAAAD8iIw3r+SL7TpPxuSt4/ibJJuz20QDBgAAAAAAAHhzrJPp6NvHYcyyjLl7dJTPbl/Jp6sPLufSsM+5ec7q5YOrF0OeP/SVaAAAAAAAAIA3weH7u6zfm79dWDIMSw6225w785vsx3XyzasOby5ssz69c4sAAAAAAAAAr9n69C6bC9sT93a7rKdnORin5Otxynzi1JQcfiwCAwAAAAAAALxO69O7HH68TaaT98cp85R8vbp3Nfszv8q0LHn7xMF1sjk/ZzUPmZ/MmWefhAYAAAAAAAD4oayPdjn7223Gn7x6ZrXPnetX8mBKkpv3cufDd/Pufn5FL56SzcVtNheT3dNt8tQlAwAAAAAAAHyv1sm0ySv/9XtsNWZ3I/lHkgzHi7/4XY7WYz5yiwAAAAAAAAA/Ivtcv/3nPEyS1fHa42t5+vNLyX7JoRsCAAAAAAAAePPt1/nbV3/KvePn1Xc371/NYxEYAAAAAAAA4M0yTHk2rvNo2WdzvHZqzN9v/SF3vju3evng/at5fPDLPDu1yuGyZHSVAAAAAAAAAK/XOGe4ueSvZ4e8M8xZbVe5ceuPufvy3Oqkw4+v5emDX+fuuTlLhhwsEYIBAAAAAAAAXpclGR8OuXP0TR4cPM/9z/+SRyfNDf/1TZezOp/87KdjzizJZkhO7edMy/w/nAUAAAAAAADg/zaMWcZkP8/ZLsmLacr2/MV8+cnvs/tP5/4FmLjAq1ifcioAAAAASUVORK5CYII=";
|
|
1295
|
-
const objectName = opt.objectName ? encodeXmlEntities(opt.objectName) : `Media ${target._slideObjects.filter((obj) => obj._type === "media").length}`;
|
|
1525
|
+
const objectName = opt.objectName ? encodeXmlEntities(validateObjectName(opt.objectName, "media")) : `Media ${target._slideObjects.filter((obj) => obj._type === "media").length}`;
|
|
1296
1526
|
const slideData = { _type: "media" };
|
|
1297
1527
|
if (!strPath && !strData && strType !== "online") throw new Error("addMedia() error: either `data` or `path` are required!");
|
|
1298
1528
|
else if (strData && !strData.toLowerCase().includes("base64,")) throw new Error("addMedia() error: `data` value lacks a base64 header! Ex: 'video/mpeg;base64,NMP[...]')");
|
|
@@ -1307,6 +1537,7 @@ function addMediaDefinition(target, opt) {
|
|
|
1307
1537
|
slideData.options.w = intSizeX;
|
|
1308
1538
|
slideData.options.h = intSizeY;
|
|
1309
1539
|
slideData.options.objectName = objectName;
|
|
1540
|
+
if (opt.altText) slideData.options.altText = opt.altText;
|
|
1310
1541
|
/**
|
|
1311
1542
|
* NOTE:
|
|
1312
1543
|
* - rId starts at 2 (hence the intRels+1 below) as slideLayout.xml is rId=1!
|
|
@@ -1421,7 +1652,7 @@ function addShapeDefinition(target, shapeName, opts) {
|
|
|
1421
1652
|
options.y = options.y || (options.y === 0 ? 0 : 1);
|
|
1422
1653
|
options.w = options.w || (options.w === 0 ? 0 : 1);
|
|
1423
1654
|
options.h = options.h || (options.h === 0 ? 0 : 1);
|
|
1424
|
-
options.objectName = options.objectName ? encodeXmlEntities(options.objectName) : `Shape ${target._slideObjects.filter((obj) => obj._type === "text").length}`;
|
|
1655
|
+
options.objectName = options.objectName ? encodeXmlEntities(validateObjectName(options.objectName, "shape")) : `Shape ${target._slideObjects.filter((obj) => obj._type === "text").length}`;
|
|
1425
1656
|
if (typeof options.line === "string") {
|
|
1426
1657
|
const tmpOpts = newLineOpts;
|
|
1427
1658
|
tmpOpts.color = String(options.line);
|
|
@@ -1447,7 +1678,7 @@ function addShapeDefinition(target, shapeName, opts) {
|
|
|
1447
1678
|
function addTableDefinition(target, tableRows, options, slideLayout, presLayout, addSlide, getSlide) {
|
|
1448
1679
|
const slides = [target];
|
|
1449
1680
|
const opt = options && typeof options === "object" ? options : {};
|
|
1450
|
-
opt.objectName = opt.objectName ? encodeXmlEntities(opt.objectName) : `Table ${target._slideObjects.filter((obj) => obj._type === "table").length}`;
|
|
1681
|
+
opt.objectName = opt.objectName ? encodeXmlEntities(validateObjectName(opt.objectName, "table")) : `Table ${target._slideObjects.filter((obj) => obj._type === "table").length}`;
|
|
1451
1682
|
if (tableRows === null || tableRows.length === 0 || !Array.isArray(tableRows)) throw new Error("addTable: Array expected! EX: 'slide.addTable( [rows], {options} );' (https://gitbrent.github.io/PptxGenJS/docs/api-tables.html)");
|
|
1452
1683
|
if (!tableRows[0] || !Array.isArray(tableRows[0])) throw new Error("addTable: 'rows' should be an array of cells! EX: 'slide.addTable( [ ['A'], ['B'], {text:'C',options:{align:'center'}} ] );' (https://gitbrent.github.io/PptxGenJS/docs/api-tables.html)");
|
|
1453
1684
|
const arrRows = [];
|
|
@@ -1646,7 +1877,7 @@ function addTextDefinition(target, text, opts, isPlaceholder) {
|
|
|
1646
1877
|
...placeHold.options
|
|
1647
1878
|
};
|
|
1648
1879
|
}
|
|
1649
|
-
itemOpts.objectName = itemOpts.objectName ? encodeXmlEntities(itemOpts.objectName) : `Text ${target._slideObjects.filter((obj) => obj._type === "text").length}`;
|
|
1880
|
+
itemOpts.objectName = itemOpts.objectName ? encodeXmlEntities(validateObjectName(itemOpts.objectName, "text")) : `Text ${target._slideObjects.filter((obj) => obj._type === "text").length}`;
|
|
1650
1881
|
if (itemOpts.shape === "line") {
|
|
1651
1882
|
const itemLine = typeof itemOpts.line === "object" && itemOpts.line ? itemOpts.line : {};
|
|
1652
1883
|
const newLineOpts = {
|
|
@@ -1906,6 +2137,14 @@ var Slide = class {
|
|
|
1906
2137
|
get newAutoPagedSlides() {
|
|
1907
2138
|
return this._newAutoPagedSlides;
|
|
1908
2139
|
}
|
|
2140
|
+
/** Slide width in inches (resolved from the active presentation layout). */
|
|
2141
|
+
get width() {
|
|
2142
|
+
return emuToInches(this._presLayout.width);
|
|
2143
|
+
}
|
|
2144
|
+
/** Slide height in inches (resolved from the active presentation layout). */
|
|
2145
|
+
get height() {
|
|
2146
|
+
return emuToInches(this._presLayout.height);
|
|
2147
|
+
}
|
|
1909
2148
|
addChart(type, dataOrOptions = [], options) {
|
|
1910
2149
|
const optionsWithType = Array.isArray(type) && !Array.isArray(dataOrOptions) ? dataOrOptions : options;
|
|
1911
2150
|
if (optionsWithType) optionsWithType._type = type;
|
|
@@ -2018,7 +2257,7 @@ async function createExcelWorksheet(chartObject, zip) {
|
|
|
2018
2257
|
if (chartObject.opts._type === "bubble" || chartObject.opts._type === "bubble3D") strSharedStrings += `<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="${intBubbleCols}" uniqueCount="${intBubbleCols}">`;
|
|
2019
2258
|
else if (chartObject.opts._type === "scatter") strSharedStrings += `<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="${data.length}" uniqueCount="${data.length}">`;
|
|
2020
2259
|
else if (IS_MULTI_CAT_AXES) {
|
|
2021
|
-
let totCount = data.length;
|
|
2260
|
+
let totCount = data.length + 1;
|
|
2022
2261
|
data[0].labels.forEach((arrLabel) => totCount += arrLabel.filter((label) => label && label !== "").length);
|
|
2023
2262
|
strSharedStrings += `<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="${totCount}" uniqueCount="${totCount}">`;
|
|
2024
2263
|
strSharedStrings += "<si><t/></si>";
|
|
@@ -2067,7 +2306,7 @@ async function createExcelWorksheet(chartObject, zip) {
|
|
|
2067
2306
|
strTableXml += `<tableColumn id="${idx + 1}" name="${idx === 0 ? "X-Values" : "Y-Value "}${idx}"/>`;
|
|
2068
2307
|
});
|
|
2069
2308
|
} else {
|
|
2070
|
-
strTableXml += `<table xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" id="1" name="Table1" displayName="Table1" ref="A1:${getExcelColName(data.length + data[0].labels.length)}${data[0].labels[0].length + 1}
|
|
2309
|
+
strTableXml += `<table xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" id="1" name="Table1" displayName="Table1" ref="A1:${getExcelColName(data.length + data[0].labels.length)}${data[0].labels[0].length + 1}" totalsRowShown="0">`;
|
|
2071
2310
|
strTableXml += `<tableColumns count="${data.length + data[0].labels.length}">`;
|
|
2072
2311
|
data[0].labels.forEach((_labelsGroup, idx) => {
|
|
2073
2312
|
strTableXml += `<tableColumn id="${idx + 1}" name="Column${idx + 1}"/>`;
|
|
@@ -2086,7 +2325,7 @@ async function createExcelWorksheet(chartObject, zip) {
|
|
|
2086
2325
|
strSheetXml += "<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x14ac\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\">";
|
|
2087
2326
|
if (chartObject.opts._type === "bubble" || chartObject.opts._type === "bubble3D") strSheetXml += `<dimension ref="A1:${getExcelColName(intBubbleCols)}${data[0].values.length + 1}"/>`;
|
|
2088
2327
|
else if (chartObject.opts._type === "scatter") strSheetXml += `<dimension ref="A1:${getExcelColName(data.length)}${data[0].values.length + 1}"/>`;
|
|
2089
|
-
else strSheetXml += `<dimension ref="A1:${getExcelColName(data.length +
|
|
2328
|
+
else strSheetXml += `<dimension ref="A1:${getExcelColName(data.length + data[0].labels.length)}${data[0].values.length + 1}"/>`;
|
|
2090
2329
|
strSheetXml += "<sheetViews><sheetView tabSelected=\"1\" workbookViewId=\"0\"><selection activeCell=\"B1\" sqref=\"B1\"/></sheetView></sheetViews>";
|
|
2091
2330
|
strSheetXml += "<sheetFormatPr baseColWidth=\"10\" defaultRowHeight=\"16\"/>";
|
|
2092
2331
|
if (chartObject.opts._type === "bubble" || chartObject.opts._type === "bubble3D") {
|
|
@@ -2100,9 +2339,9 @@ async function createExcelWorksheet(chartObject, zip) {
|
|
|
2100
2339
|
strSheetXml += `<c r="A${idx + 2}"><v>${val}</v></c>`;
|
|
2101
2340
|
let idxColLtr = 2;
|
|
2102
2341
|
for (let idy = 1; idy < data.length; idy++) {
|
|
2103
|
-
strSheetXml += `<c r="${getExcelColName(idxColLtr)}${idx + 2}"><v>${data[idy].values[idx]
|
|
2342
|
+
strSheetXml += `<c r="${getExcelColName(idxColLtr)}${idx + 2}"><v>${data[idy].values[idx] ?? ""}</v></c>`;
|
|
2104
2343
|
idxColLtr++;
|
|
2105
|
-
strSheetXml += `<c r="${getExcelColName(idxColLtr)}${idx + 2}"><v>${data[idy].sizes[idx]
|
|
2344
|
+
strSheetXml += `<c r="${getExcelColName(idxColLtr)}${idx + 2}"><v>${data[idy].sizes[idx] ?? ""}</v></c>`;
|
|
2106
2345
|
idxColLtr++;
|
|
2107
2346
|
}
|
|
2108
2347
|
strSheetXml += "</row>";
|
|
@@ -2134,86 +2373,32 @@ async function createExcelWorksheet(chartObject, zip) {
|
|
|
2134
2373
|
strSheetXml += `<v>${data.length + idx + 1}</v>`;
|
|
2135
2374
|
strSheetXml += "</c>";
|
|
2136
2375
|
}
|
|
2137
|
-
for (let idy = 0; idy < data.length; idy++) strSheetXml += `<c r="${getExcelColName(data[0].labels.length + idy + 1)}${idx + 2}"><v>${data[idy].values[idx]
|
|
2376
|
+
for (let idy = 0; idy < data.length; idy++) strSheetXml += `<c r="${getExcelColName(data[0].labels.length + idy + 1)}${idx + 2}"><v>${data[idy].values[idx] ?? ""}</v></c>`;
|
|
2138
2377
|
strSheetXml += "</row>";
|
|
2139
2378
|
});
|
|
2140
2379
|
} else {
|
|
2141
|
-
strSheetXml += `<row r="1" spans="1:${data.length + data[0].labels.length}">`;
|
|
2142
|
-
for (let idx = 0; idx < data[0].labels.length; idx++) strSheetXml += `<c r="${getExcelColName(idx + 1)}1" t="s"><v>0</v></c>`;
|
|
2143
|
-
for (let idx = data[0].labels.length - 1; idx < data.length + data[0].labels.length - 1; idx++) strSheetXml += `<c r="${getExcelColName(idx + data[0].labels.length)}1" t="s"><v>${idx}</v></c>`;
|
|
2144
|
-
strSheetXml += "</row>";
|
|
2145
|
-
/**
|
|
2146
|
-
* @example INPUT
|
|
2147
|
-
* const LABELS = [
|
|
2148
|
-
* ["Gear", "Berg", "Motr", "Swch", "Plug", "Cord", "Pump", "Leak", "Seal"],
|
|
2149
|
-
* ["Mech", "", "", "Elec", "", "", "Hydr", "", ""],
|
|
2150
|
-
* ];
|
|
2151
|
-
* const arrDataRegions = [
|
|
2152
|
-
* { name: "West", labels: LABELS, values: [11, 8, 3, 0, 11, 3, 0, 0, 0] },
|
|
2153
|
-
* { name: "Ctrl", labels: LABELS, values: [0, 11, 6, 19, 12, 5, 0, 0, 0] },
|
|
2154
|
-
* { name: "East", labels: LABELS, values: [0, 3, 2, 0, 0, 0, 4, 3, 1] },
|
|
2155
|
-
* ];
|
|
2156
|
-
*/
|
|
2157
|
-
/**
|
|
2158
|
-
* @example OUTPUT EXCEL SHEET
|
|
2159
|
-
* |/|---A--|---B--|---C--|---D--|---E--|
|
|
2160
|
-
* |1| | | West | Ctrl | East |
|
|
2161
|
-
* |2| Mech | Gear | ## | ## | ## |
|
|
2162
|
-
* |3| | Brng | ## | ## | ## |
|
|
2163
|
-
* |4| | Motr | ## | ## | ## |
|
|
2164
|
-
* |5| Elec | Swch | ## | ## | ## |
|
|
2165
|
-
* |6| | Plug | ## | ## | ## |
|
|
2166
|
-
* |7| | Cord | ## | ## | ## |
|
|
2167
|
-
* |8| Hydr | Pump | ## | ## | ## |
|
|
2168
|
-
* |9| | Leak | ## | ## | ## |
|
|
2169
|
-
*|10| | Seal | ## | ## | ## |
|
|
2170
|
-
*/
|
|
2171
|
-
/**
|
|
2172
|
-
* @example OUTPUT EXCEL SHEET XML
|
|
2173
|
-
* <row r="1" spans="1:5">
|
|
2174
|
-
* <c r="A1" t="s"><v>0</v></c>
|
|
2175
|
-
* <c r="B1" t="s"><v>0</v></c>
|
|
2176
|
-
* <c r="C1" t="s"><v>1</v></c>
|
|
2177
|
-
* <c r="D1" t="s"><v>2</v></c>
|
|
2178
|
-
* <c r="E1" t="s"><v>3</v></c>
|
|
2179
|
-
* </row>
|
|
2180
|
-
* <row r="2" spans="1:5">
|
|
2181
|
-
* <c r="A2" t="s"><v>4</v></c>
|
|
2182
|
-
* <c r="B2" t="s"><v>7</v></c>
|
|
2183
|
-
* <c r="C2" ><v>###</v></c>
|
|
2184
|
-
* </row>
|
|
2185
|
-
* <row r="3" spans="1:5">
|
|
2186
|
-
* <c r="A3" />
|
|
2187
|
-
* <c r="B3" t="s"><v>8</v></c>
|
|
2188
|
-
* <c r="C3" ><v>###</v></c>
|
|
2189
|
-
* </row>
|
|
2190
|
-
*/
|
|
2191
|
-
/**
|
|
2192
|
-
* @example SHARED-STRINGS
|
|
2193
|
-
* 1=West, 2=Ctrl, 3=East, 4=Mech, 5=Elec, 6=Mydr, 7=Gear, 8=Brng, [...], 15=Seal
|
|
2194
|
-
*/
|
|
2195
|
-
/**
|
|
2196
|
-
* const LABELS = [
|
|
2197
|
-
* ["Gear", "Berg", "Motr", "Swch", "Plug", "Cord", "Pump", "Leak", "Seal"],
|
|
2198
|
-
* ["Mech", "", "", "Elec", "", "", "Hydr", "", ""],
|
|
2199
|
-
* ["2010", "", "", "", "", "", "", "", ""],
|
|
2200
|
-
* ];
|
|
2201
|
-
*/
|
|
2202
2380
|
const TOT_SER = data.length;
|
|
2203
2381
|
const TOT_CAT = data[0].labels[0].length;
|
|
2204
2382
|
const TOT_LVL = data[0].labels.length;
|
|
2383
|
+
const revLabelGroups = data[0].labels.slice().reverse();
|
|
2384
|
+
const ssLabelMap = /* @__PURE__ */ new Map();
|
|
2385
|
+
let ssIdx = TOT_SER + 1;
|
|
2386
|
+
revLabelGroups.forEach((labelsGroup, revLevelIdx) => {
|
|
2387
|
+
labelsGroup.forEach((label, rowIdx) => {
|
|
2388
|
+
if (label && label !== "") ssLabelMap.set(`${revLevelIdx}:${rowIdx}`, ssIdx++);
|
|
2389
|
+
});
|
|
2390
|
+
});
|
|
2391
|
+
strSheetXml += `<row r="1" spans="1:${TOT_SER + TOT_LVL}">`;
|
|
2392
|
+
for (let col = 1; col <= TOT_LVL; col++) strSheetXml += `<c r="${getExcelColName(col)}1" t="s"><v>0</v></c>`;
|
|
2393
|
+
for (let ser = 0; ser < TOT_SER; ser++) strSheetXml += `<c r="${getExcelColName(TOT_LVL + ser + 1)}1" t="s"><v>${ser + 1}</v></c>`;
|
|
2394
|
+
strSheetXml += "</row>";
|
|
2205
2395
|
for (let idx = 0; idx < TOT_CAT; idx++) {
|
|
2206
2396
|
strSheetXml += `<row r="${idx + 2}" spans="1:${TOT_SER + TOT_LVL}">`;
|
|
2207
|
-
let totLabels = TOT_SER;
|
|
2208
|
-
const revLabelGroups = data[0].labels.slice().reverse();
|
|
2209
2397
|
revLabelGroups.forEach((labelsGroup, idy) => {
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
totLabels += totGrpLbls;
|
|
2213
|
-
strSheetXml += `<c r="${getExcelColName(idx + 1 + idy)}${idx + 2}" t="s"><v>${totLabels}</v></c>`;
|
|
2214
|
-
}
|
|
2398
|
+
const colLabel = labelsGroup[idx];
|
|
2399
|
+
if (colLabel && colLabel !== "") strSheetXml += `<c r="${getExcelColName(idy + 1)}${idx + 2}" t="s"><v>${ssLabelMap.get(`${idy}:${idx}`)}</v></c>`;
|
|
2215
2400
|
});
|
|
2216
|
-
for (let idy = 0; idy < TOT_SER; idy++) strSheetXml += `<c r="${getExcelColName(TOT_LVL + idy + 1)}${idx + 2}"><v>${data[idy].values[idx]
|
|
2401
|
+
for (let idy = 0; idy < TOT_SER; idy++) strSheetXml += `<c r="${getExcelColName(TOT_LVL + idy + 1)}${idx + 2}"><v>${data[idy].values[idx] ?? ""}</v></c>`;
|
|
2217
2402
|
strSheetXml += "</row>";
|
|
2218
2403
|
}
|
|
2219
2404
|
}
|
|
@@ -2356,6 +2541,13 @@ function makeXmlCharts(rel) {
|
|
|
2356
2541
|
if (rel.opts.showLegend) {
|
|
2357
2542
|
strXml += "<c:legend>";
|
|
2358
2543
|
strXml += "<c:legendPos val=\"" + rel.opts.legendPos + "\"/>";
|
|
2544
|
+
if (Array.isArray(rel.opts._type)) {
|
|
2545
|
+
let seriesIdx = 0;
|
|
2546
|
+
rel.opts._type.forEach((type) => {
|
|
2547
|
+
if (type.options?.showLegend === false) for (let i = 0; i < type.data.length; i++) strXml += `<c:legendEntry><c:idx val="${seriesIdx + i}"/><c:delete val="1"/></c:legendEntry>`;
|
|
2548
|
+
seriesIdx += type.data.length;
|
|
2549
|
+
});
|
|
2550
|
+
}
|
|
2359
2551
|
strXml += "<c:overlay val=\"0\"/>";
|
|
2360
2552
|
if (rel.opts.legendFontFace || rel.opts.legendFontSize || rel.opts.legendColor) {
|
|
2361
2553
|
strXml += "<c:txPr>";
|
|
@@ -2411,7 +2603,10 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2411
2603
|
case "line":
|
|
2412
2604
|
case "radar":
|
|
2413
2605
|
strXml += `<c:${chartType}Chart>`;
|
|
2414
|
-
if (chartType === "area"
|
|
2606
|
+
if (chartType === "area" || chartType === "line") {
|
|
2607
|
+
const lineGrouping = opts.barGrouping === "stacked" || opts.barGrouping === "percentStacked" ? opts.barGrouping : "standard";
|
|
2608
|
+
strXml += "<c:grouping val=\"" + lineGrouping + "\"/>";
|
|
2609
|
+
}
|
|
2415
2610
|
if (chartType === "bar" || chartType === "bar3D") {
|
|
2416
2611
|
strXml += "<c:barDir val=\"" + opts.barDir + "\"/>";
|
|
2417
2612
|
strXml += "<c:grouping val=\"" + (opts.barGrouping || "clustered") + "\"/>";
|
|
@@ -2428,28 +2623,50 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2428
2623
|
strXml += " <c:strCache><c:ptCount val=\"1\"/><c:pt idx=\"0\"><c:v>" + encodeXmlEntities(obj.name) + "</c:v></c:pt></c:strCache>";
|
|
2429
2624
|
strXml += " </c:strRef>";
|
|
2430
2625
|
strXml += " </c:tx>";
|
|
2431
|
-
const
|
|
2626
|
+
const seriesOverride = opts.seriesOptions?.[obj._dataIndex];
|
|
2627
|
+
const seriesColor = seriesOverride?.color ?? (opts.chartColors ? opts.chartColors[colorIndex % opts.chartColors.length] : null);
|
|
2432
2628
|
strXml += " <c:spPr>";
|
|
2433
2629
|
if (seriesColor === "transparent") strXml += "<a:noFill/>";
|
|
2434
2630
|
else if (opts.chartColorsOpacity) strXml += "<a:solidFill>" + createColorElement(seriesColor, `<a:alpha val="${Math.round(opts.chartColorsOpacity * 1e3)}"/>`) + "</a:solidFill>";
|
|
2435
2631
|
else strXml += "<a:solidFill>" + createColorElement(seriesColor) + "</a:solidFill>";
|
|
2436
|
-
if (chartType === "line" || chartType === "radar")
|
|
2437
|
-
|
|
2438
|
-
strXml +=
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2632
|
+
if (chartType === "line" || chartType === "radar") {
|
|
2633
|
+
const effectiveLineSize = seriesOverride?.lineSize ?? opts.lineSize;
|
|
2634
|
+
if (effectiveLineSize === 0) strXml += "<a:ln><a:noFill/></a:ln>";
|
|
2635
|
+
else {
|
|
2636
|
+
strXml += `<a:ln w="${valToPts(effectiveLineSize)}" cap="${createLineCap(opts.lineCap)}"><a:solidFill>${createColorElement(seriesColor)}</a:solidFill>`;
|
|
2637
|
+
strXml += `<a:prstDash val="${opts.lineDashValues?.[colorIndex] ?? opts.lineDash ?? "solid"}"/><a:round/></a:ln>`;
|
|
2638
|
+
}
|
|
2639
|
+
} else if (opts.dataBorder) strXml += `<a:ln w="${valToPts(opts.dataBorder.pt)}" cap="${createLineCap(opts.lineCap)}"><a:solidFill>${createColorElement(opts.dataBorder.color)}</a:solidFill><a:prstDash val="solid"/><a:round/></a:ln>`;
|
|
2442
2640
|
strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
|
|
2443
2641
|
strXml += " </c:spPr>";
|
|
2444
|
-
strXml += " <c:invertIfNegative val=\"0\"/>";
|
|
2642
|
+
if (chartType !== "line" && chartType !== "radar") strXml += " <c:invertIfNegative val=\"0\"/>";
|
|
2643
|
+
if (chartType === "line" || chartType === "radar") {
|
|
2644
|
+
strXml += "<c:marker>";
|
|
2645
|
+
strXml += " <c:symbol val=\"" + opts.lineDataSymbol + "\"/>";
|
|
2646
|
+
if (opts.lineDataSymbolSize) strXml += `<c:size val="${opts.lineDataSymbolSize}"/>`;
|
|
2647
|
+
strXml += " <c:spPr>";
|
|
2648
|
+
{
|
|
2649
|
+
const markerColor = opts.chartColors[obj._dataIndex + 1 > opts.chartColors.length ? Math.floor(Math.random() * opts.chartColors.length) : obj._dataIndex];
|
|
2650
|
+
strXml += markerColor === "transparent" ? "<a:noFill/>" : `<a:solidFill>${createColorElement(markerColor)}</a:solidFill>`;
|
|
2651
|
+
}
|
|
2652
|
+
strXml += ` <a:ln w="${opts.lineDataSymbolLineSize}" cap="flat"><a:solidFill>${createColorElement(opts.lineDataSymbolLineColor || seriesColor)}</a:solidFill><a:prstDash val="solid"/><a:round/></a:ln>`;
|
|
2653
|
+
strXml += " <a:effectLst/>";
|
|
2654
|
+
strXml += " </c:spPr>";
|
|
2655
|
+
strXml += "</c:marker>";
|
|
2656
|
+
}
|
|
2445
2657
|
if (chartType !== "radar") {
|
|
2658
|
+
const lblColor = seriesOverride?.dataLabelColor ?? opts.dataLabelColor ?? "000000";
|
|
2659
|
+
const lblBold = seriesOverride?.dataLabelFontBold ?? opts.dataLabelFontBold ?? false;
|
|
2660
|
+
const lblItalic = seriesOverride?.dataLabelFontItalic ?? opts.dataLabelFontItalic ?? false;
|
|
2661
|
+
const lblSize = seriesOverride?.dataLabelFontSize ?? opts.dataLabelFontSize ?? 12;
|
|
2662
|
+
const lblFace = seriesOverride?.dataLabelFontFace ?? opts.dataLabelFontFace ?? "Arial";
|
|
2446
2663
|
strXml += "<c:dLbls>";
|
|
2447
2664
|
strXml += `<c:numFmt formatCode="${encodeXmlEntities(opts.dataLabelFormatCode) || "General"}" sourceLinked="0"/>`;
|
|
2448
2665
|
if (opts.dataLabelBkgrdColors) strXml += `<c:spPr><a:solidFill>${createColorElement(seriesColor)}</a:solidFill></c:spPr>`;
|
|
2449
2666
|
strXml += "<c:txPr><a:bodyPr/><a:lstStyle/><a:p><a:pPr>";
|
|
2450
|
-
strXml += `<a:defRPr b="${
|
|
2451
|
-
strXml += `<a:solidFill>${createColorElement(
|
|
2452
|
-
strXml += `<a:latin typeface="${
|
|
2667
|
+
strXml += `<a:defRPr b="${lblBold ? 1 : 0}" i="${lblItalic ? 1 : 0}" strike="noStrike" sz="${Math.round(lblSize * 100)}" u="none">`;
|
|
2668
|
+
strXml += `<a:solidFill>${createColorElement(lblColor)}</a:solidFill>`;
|
|
2669
|
+
strXml += `<a:latin typeface="${lblFace}"/>`;
|
|
2453
2670
|
strXml += "</a:defRPr></a:pPr></a:p></c:txPr>";
|
|
2454
2671
|
if (opts.dataLabelPosition) strXml += `<c:dLblPos val="${opts.dataLabelPosition}"/>`;
|
|
2455
2672
|
strXml += "<c:showLegendKey val=\"0\"/>";
|
|
@@ -2458,17 +2675,6 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2458
2675
|
strXml += `<c:showLeaderLines val="${opts.showLeaderLines ? "1" : "0"}"/>`;
|
|
2459
2676
|
strXml += "</c:dLbls>";
|
|
2460
2677
|
}
|
|
2461
|
-
if (chartType === "line" || chartType === "radar") {
|
|
2462
|
-
strXml += "<c:marker>";
|
|
2463
|
-
strXml += " <c:symbol val=\"" + opts.lineDataSymbol + "\"/>";
|
|
2464
|
-
if (opts.lineDataSymbolSize) strXml += `<c:size val="${opts.lineDataSymbolSize}"/>`;
|
|
2465
|
-
strXml += " <c:spPr>";
|
|
2466
|
-
strXml += ` <a:solidFill>${createColorElement(opts.chartColors[obj._dataIndex + 1 > opts.chartColors.length ? Math.floor(Math.random() * opts.chartColors.length) : obj._dataIndex])}</a:solidFill>`;
|
|
2467
|
-
strXml += ` <a:ln w="${opts.lineDataSymbolLineSize}" cap="flat"><a:solidFill>${createColorElement(opts.lineDataSymbolLineColor || seriesColor)}</a:solidFill><a:prstDash val="solid"/><a:round/></a:ln>`;
|
|
2468
|
-
strXml += " <a:effectLst/>";
|
|
2469
|
-
strXml += " </c:spPr>";
|
|
2470
|
-
strXml += "</c:marker>";
|
|
2471
|
-
}
|
|
2472
2678
|
if ((chartType === "bar" || chartType === "bar3D") && data.length === 1 && (opts.chartColors && opts.chartColors !== BARCHART_COLORS && opts.chartColors.length > 1 || opts.invertedColors?.length)) obj.values.forEach((value, index) => {
|
|
2473
2679
|
const arrColors = value < 0 ? opts.invertedColors || opts.chartColors || BARCHART_COLORS : opts.chartColors || [];
|
|
2474
2680
|
strXml += " <c:dPt>";
|
|
@@ -2502,6 +2708,14 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2502
2708
|
obj.labels[0].forEach((label, idx) => strXml += `<c:pt idx="${idx}"><c:v>${encodeXmlEntities(label)}</c:v></c:pt>`);
|
|
2503
2709
|
strXml += " </c:numCache>";
|
|
2504
2710
|
strXml += " </c:numRef>";
|
|
2711
|
+
} else if (obj.labels.length === 1) {
|
|
2712
|
+
strXml += " <c:strRef>";
|
|
2713
|
+
strXml += ` <c:f>Sheet1!$A$2:$A$${obj.labels[0].length + 1}</c:f>`;
|
|
2714
|
+
strXml += " <c:strCache>";
|
|
2715
|
+
strXml += ` <c:ptCount val="${obj.labels[0].length}"/>`;
|
|
2716
|
+
obj.labels[0].forEach((label, idx) => strXml += `<c:pt idx="${idx}"><c:v>${encodeXmlEntities(label)}</c:v></c:pt>`);
|
|
2717
|
+
strXml += " </c:strCache>";
|
|
2718
|
+
strXml += " </c:strRef>";
|
|
2505
2719
|
} else {
|
|
2506
2720
|
strXml += " <c:multiLvlStrRef>";
|
|
2507
2721
|
strXml += ` <c:f>Sheet1!$A$2:$${getExcelColName(obj.labels.length)}$${obj.labels[0].length + 1}</c:f>`;
|
|
@@ -2522,7 +2736,9 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2522
2736
|
strXml += " <c:numCache>";
|
|
2523
2737
|
strXml += " <c:formatCode>" + (opts.valLabelFormatCode || opts.dataTableFormatCode || "General") + "</c:formatCode>";
|
|
2524
2738
|
strXml += ` <c:ptCount val="${obj.labels[0].length}"/>`;
|
|
2525
|
-
obj.values.forEach((value, idx) =>
|
|
2739
|
+
obj.values.forEach((value, idx) => {
|
|
2740
|
+
if (value != null) strXml += `<c:pt idx="${idx}"><c:v>${value}</c:v></c:pt>`;
|
|
2741
|
+
});
|
|
2526
2742
|
strXml += " </c:numCache>";
|
|
2527
2743
|
strXml += " </c:numRef>";
|
|
2528
2744
|
strXml += "</c:val>";
|
|
@@ -2552,7 +2768,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2552
2768
|
strXml += " </c:dLbls>";
|
|
2553
2769
|
if (chartType === "bar") {
|
|
2554
2770
|
strXml += ` <c:gapWidth val="${opts.barGapWidthPct}"/>`;
|
|
2555
|
-
strXml += ` <c:overlap val="${(opts.barGrouping || "").includes("tacked") ? 100 :
|
|
2771
|
+
strXml += ` <c:overlap val="${opts.barOverlapPct != null ? opts.barOverlapPct : (opts.barGrouping || "").includes("tacked") ? 100 : 0}"/>`;
|
|
2556
2772
|
} else if (chartType === "bar3D") {
|
|
2557
2773
|
strXml += ` <c:gapWidth val="${opts.barGapWidthPct}"/>`;
|
|
2558
2774
|
strXml += ` <c:gapDepth val="${opts.barGapDepthPct}"/>`;
|
|
@@ -2587,7 +2803,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2587
2803
|
if (opts.lineSize === 0) strXml += "<a:ln><a:noFill/></a:ln>";
|
|
2588
2804
|
else {
|
|
2589
2805
|
strXml += `<a:ln w="${valToPts(opts.lineSize)}" cap="${createLineCap(opts.lineCap)}"><a:solidFill>${createColorElement(tmpSerColor)}</a:solidFill>`;
|
|
2590
|
-
strXml += `<a:prstDash val="${opts.lineDash
|
|
2806
|
+
strXml += `<a:prstDash val="${opts.lineDashValues?.[colorIndex] ?? opts.lineDash ?? "solid"}"/><a:round/></a:ln>`;
|
|
2591
2807
|
}
|
|
2592
2808
|
strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
|
|
2593
2809
|
}
|
|
@@ -2596,7 +2812,10 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2596
2812
|
strXml += " <c:symbol val=\"" + opts.lineDataSymbol + "\"/>";
|
|
2597
2813
|
if (opts.lineDataSymbolSize) strXml += `<c:size val="${opts.lineDataSymbolSize}"/>`;
|
|
2598
2814
|
strXml += "<c:spPr>";
|
|
2599
|
-
|
|
2815
|
+
{
|
|
2816
|
+
const markerColor = opts.chartColors[idx + 1 > opts.chartColors.length ? Math.floor(Math.random() * opts.chartColors.length) : idx];
|
|
2817
|
+
strXml += markerColor === "transparent" ? "<a:noFill/>" : `<a:solidFill>${createColorElement(markerColor)}</a:solidFill>`;
|
|
2818
|
+
}
|
|
2600
2819
|
strXml += `<a:ln w="${opts.lineDataSymbolLineSize}" cap="flat"><a:solidFill>${createColorElement(opts.lineDataSymbolLineColor || opts.chartColors[colorIndex % opts.chartColors.length])}</a:solidFill><a:prstDash val="solid"/><a:round/></a:ln>`;
|
|
2601
2820
|
strXml += "<a:effectLst/>";
|
|
2602
2821
|
strXml += "</c:spPr>";
|
|
@@ -2617,10 +2836,16 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2617
2836
|
strXml += " <a:lstStyle/>";
|
|
2618
2837
|
strXml += " <a:p>";
|
|
2619
2838
|
strXml += " <a:pPr>";
|
|
2620
|
-
strXml +=
|
|
2839
|
+
strXml += ` <a:defRPr sz="${Math.round((opts.dataLabelFontSize || 12) * 100)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike">`;
|
|
2840
|
+
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
2841
|
+
strXml += ` <a:latin typeface="${opts.dataLabelFontFace || "Arial"}"/>`;
|
|
2842
|
+
strXml += " </a:defRPr>";
|
|
2621
2843
|
strXml += " </a:pPr>";
|
|
2622
2844
|
strXml += " <a:r>";
|
|
2623
|
-
strXml +=
|
|
2845
|
+
strXml += ` <a:rPr lang="${opts.lang || "en-US"}" sz="${Math.round((opts.dataLabelFontSize || 12) * 100)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike" dirty="0">`;
|
|
2846
|
+
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
2847
|
+
strXml += ` <a:latin typeface="${opts.dataLabelFontFace || "Arial"}"/>`;
|
|
2848
|
+
strXml += " </a:rPr>";
|
|
2624
2849
|
strXml += " <a:t>" + encodeXmlEntities(label) + "</a:t>";
|
|
2625
2850
|
strXml += " </a:r>";
|
|
2626
2851
|
if (opts.dataLabelFormatScatter === "customXY" && !/^ *$/.test(label)) {
|
|
@@ -2697,9 +2922,12 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2697
2922
|
strXml += " <a:lstStyle/>";
|
|
2698
2923
|
strXml += " <a:p>";
|
|
2699
2924
|
strXml += " <a:pPr>";
|
|
2700
|
-
strXml +=
|
|
2925
|
+
strXml += ` <a:defRPr sz="${Math.round((opts.dataLabelFontSize || 12) * 100)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike">`;
|
|
2926
|
+
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
2927
|
+
strXml += ` <a:latin typeface="${opts.dataLabelFontFace || "Arial"}"/>`;
|
|
2928
|
+
strXml += " </a:defRPr>";
|
|
2701
2929
|
strXml += " </a:pPr>";
|
|
2702
|
-
strXml +=
|
|
2930
|
+
strXml += ` <a:endParaRPr lang="${opts.lang || "en-US"}"/>`;
|
|
2703
2931
|
strXml += " </a:p>";
|
|
2704
2932
|
strXml += " </c:txPr>";
|
|
2705
2933
|
if (opts.dataLabelPosition) strXml += " <c:dLblPos val=\"" + opts.dataLabelPosition + "\"/>";
|
|
@@ -2741,7 +2969,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2741
2969
|
strXml += " <c:formatCode>General</c:formatCode>";
|
|
2742
2970
|
strXml += ` <c:ptCount val="${data[0].values.length}"/>`;
|
|
2743
2971
|
data[0].values.forEach((value, idx) => {
|
|
2744
|
-
strXml += `<c:pt idx="${idx}"><c:v>${value
|
|
2972
|
+
if (value != null) strXml += `<c:pt idx="${idx}"><c:v>${value}</c:v></c:pt>`;
|
|
2745
2973
|
});
|
|
2746
2974
|
strXml += " </c:numCache>";
|
|
2747
2975
|
strXml += " </c:numRef>";
|
|
@@ -2753,7 +2981,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2753
2981
|
strXml += " <c:formatCode>General</c:formatCode>";
|
|
2754
2982
|
strXml += ` <c:ptCount val="${data[0].values.length}"/>`;
|
|
2755
2983
|
data[0].values.forEach((_value, idx) => {
|
|
2756
|
-
strXml += `<c:pt idx="${idx}"><c:v>${obj.values[idx]
|
|
2984
|
+
if (obj.values[idx] != null) strXml += `<c:pt idx="${idx}"><c:v>${obj.values[idx]}</c:v></c:pt>`;
|
|
2757
2985
|
});
|
|
2758
2986
|
strXml += " </c:numCache>";
|
|
2759
2987
|
strXml += " </c:numRef>";
|
|
@@ -2810,7 +3038,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2810
3038
|
else if (opts.dataBorder) strXml += `<a:ln w="${valToPts(opts.dataBorder.pt)}" cap="flat"><a:solidFill>${createColorElement(opts.dataBorder.color)}</a:solidFill><a:prstDash val="solid"/><a:round/></a:ln>`;
|
|
2811
3039
|
else {
|
|
2812
3040
|
strXml += `<a:ln w="${valToPts(opts.lineSize)}" cap="flat"><a:solidFill>${createColorElement(tmpSerColor)}</a:solidFill>`;
|
|
2813
|
-
strXml += `<a:prstDash val="${opts.lineDash
|
|
3041
|
+
strXml += `<a:prstDash val="${opts.lineDashValues?.[colorIndex] ?? opts.lineDash ?? "solid"}"/><a:round/></a:ln>`;
|
|
2814
3042
|
}
|
|
2815
3043
|
strXml += createShadowElement(opts.shadow, DEF_SHAPE_SHADOW);
|
|
2816
3044
|
strXml += "</c:spPr>";
|
|
@@ -2848,7 +3076,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2848
3076
|
strXml += " <c:formatCode>General</c:formatCode>";
|
|
2849
3077
|
strXml += ` <c:ptCount val="${obj.sizes.length}"/>`;
|
|
2850
3078
|
obj.sizes.forEach((value, idx) => {
|
|
2851
|
-
strXml += `<c:pt idx="${idx}"><c:v>${value
|
|
3079
|
+
strXml += `<c:pt idx="${idx}"><c:v>${value ?? ""}</c:v></c:pt>`;
|
|
2852
3080
|
});
|
|
2853
3081
|
strXml += " </c:numCache>";
|
|
2854
3082
|
strXml += " </c:numRef>";
|
|
@@ -2939,13 +3167,14 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
2939
3167
|
strXml += " <a:lstStyle/>";
|
|
2940
3168
|
strXml += " <a:p>";
|
|
2941
3169
|
strXml += " <a:pPr>";
|
|
2942
|
-
strXml += ` <a:defRPr sz="
|
|
2943
|
-
strXml += " <a:solidFill
|
|
3170
|
+
strXml += ` <a:defRPr sz="${Math.round((opts.dataLabelFontSize || 12) * 100)}" b="${opts.dataLabelFontBold ? "1" : "0"}" i="${opts.dataLabelFontItalic ? "1" : "0"}" u="none" strike="noStrike">`;
|
|
3171
|
+
strXml += " <a:solidFill>" + createColorElement(opts.dataLabelColor || "000000") + "</a:solidFill>";
|
|
3172
|
+
strXml += ` <a:latin typeface="${opts.dataLabelFontFace || "Arial"}"/>`;
|
|
2944
3173
|
strXml += " </a:defRPr>";
|
|
2945
3174
|
strXml += " </a:pPr>";
|
|
2946
3175
|
strXml += " </a:p>";
|
|
2947
3176
|
strXml += " </c:txPr>";
|
|
2948
|
-
strXml += chartType === "pie" ?
|
|
3177
|
+
strXml += chartType === "pie" ? `<c:dLblPos val="${opts.dataLabelPosition || "ctr"}"/>` : "";
|
|
2949
3178
|
strXml += " <c:showLegendKey val=\"0\"/>";
|
|
2950
3179
|
strXml += " <c:showVal val=\"0\"/>";
|
|
2951
3180
|
strXml += " <c:showCatName val=\"1\"/>";
|
|
@@ -3016,12 +3245,14 @@ function makeCatAxis(opts, axisId, valAxisId) {
|
|
|
3016
3245
|
titleRotate: opts.catAxisTitleRotate,
|
|
3017
3246
|
title: opts.catAxisTitle || "Axis Title"
|
|
3018
3247
|
});
|
|
3019
|
-
if (opts._type === "scatter" || opts._type === "bubble" || opts._type === "bubble3D")
|
|
3020
|
-
|
|
3248
|
+
if (opts._type === "scatter" || opts._type === "bubble" || opts._type === "bubble3D") {
|
|
3249
|
+
const xAxisFmtCode = opts.catAxisLabelFormatCode ?? opts.valAxisLabelFormatCode;
|
|
3250
|
+
strXml += " <c:numFmt formatCode=\"" + (xAxisFmtCode ? encodeXmlEntities(xAxisFmtCode) : "General") + "\" sourceLinked=\"1\"/>";
|
|
3251
|
+
} else strXml += " <c:numFmt formatCode=\"" + (encodeXmlEntities(opts.catLabelFormatCode) || "General") + "\" sourceLinked=\"1\"/>";
|
|
3021
3252
|
if (opts._type === "scatter") {
|
|
3022
3253
|
strXml += " <c:majorTickMark val=\"none\"/>";
|
|
3023
3254
|
strXml += " <c:minorTickMark val=\"none\"/>";
|
|
3024
|
-
strXml += " <c:tickLblPos val=\"nextTo\"/>";
|
|
3255
|
+
strXml += " <c:tickLblPos val=\"" + (opts.catAxisLabelPos || "nextTo") + "\"/>";
|
|
3025
3256
|
} else {
|
|
3026
3257
|
strXml += " <c:majorTickMark val=\"" + (opts.catAxisMajorTickMark || "out") + "\"/>";
|
|
3027
3258
|
strXml += " <c:minorTickMark val=\"" + (opts.catAxisMinorTickMark || "none") + "\"/>";
|
|
@@ -3145,7 +3376,7 @@ function makeValAxis(opts, valAxisId) {
|
|
|
3145
3376
|
if (typeof opts.catAxisCrossesAt === "number") strXml += ` <c:crossesAt val="${opts.catAxisCrossesAt}"/>`;
|
|
3146
3377
|
else if (typeof opts.catAxisCrossesAt === "string") strXml += " <c:crosses val=\"" + opts.catAxisCrossesAt + "\"/>";
|
|
3147
3378
|
else strXml += " <c:crosses val=\"" + (axisPos === "r" || axisPos === "t" ? "max" : "autoZero") + "\"/>";
|
|
3148
|
-
strXml += " <c:crossBetween val=\"" + (opts._type === "scatter" || !!(Array.isArray(opts._type) && opts._type.some((type) => type.type === "area")) ? "midCat" : "between") + "\"/>";
|
|
3379
|
+
strXml += " <c:crossBetween val=\"" + (opts.valAxisCrossBetween ? opts.valAxisCrossBetween : opts._type === "scatter" || !!(Array.isArray(opts._type) && opts._type.some((type) => type.type === "area")) ? "midCat" : "between") + "\"/>";
|
|
3149
3380
|
if (opts.valAxisMajorUnit) strXml += ` <c:majorUnit val="${opts.valAxisMajorUnit}"/>`;
|
|
3150
3381
|
if (opts.valAxisDisplayUnit) strXml += `<c:dispUnits><c:builtInUnit val="${opts.valAxisDisplayUnit}"/>${opts.valAxisDisplayUnitLabel ? "<c:dispUnitsLbl/>" : ""}</c:dispUnits>`;
|
|
3151
3382
|
strXml += "</c:valAx>";
|
|
@@ -3409,9 +3640,95 @@ const ImageSizingXml = {
|
|
|
3409
3640
|
const r = imgSize.w - (boxDim.x + boxDim.w);
|
|
3410
3641
|
const t = boxDim.y;
|
|
3411
3642
|
const b = imgSize.h - (boxDim.y + boxDim.h);
|
|
3643
|
+
if (l < 0 || r < 0 || t < 0 || b < 0) {
|
|
3644
|
+
const over = [
|
|
3645
|
+
l < 0 && `x (${l < 0 ? -l : 0} past left edge)`,
|
|
3646
|
+
r < 0 && `x+w (${-r} past right edge)`,
|
|
3647
|
+
t < 0 && `y (${-t} past top edge)`,
|
|
3648
|
+
b < 0 && `y+h (${-b} past bottom edge)`
|
|
3649
|
+
].filter(Boolean).join(", ");
|
|
3650
|
+
throw new Error(`addImage sizing.type 'crop': crop window overflows image bounds — ${over}. Ensure x≥0, y≥0, x+w≤w, y+h≤h.`);
|
|
3651
|
+
}
|
|
3412
3652
|
return `<a:srcRect l="${Math.round(1e5 * (l / imgSize.w))}" r="${Math.round(1e5 * (r / imgSize.w))}" t="${Math.round(1e5 * (t / imgSize.h))}" b="${Math.round(1e5 * (b / imgSize.h))}"/><a:stretch/>`;
|
|
3413
3653
|
}
|
|
3414
3654
|
};
|
|
3655
|
+
/**
|
|
3656
|
+
* Emit an `<a:prstGeom>` for a preset shape, including any adjust values (`<a:avLst>`).
|
|
3657
|
+
* Shared by the shape and image code paths so that geometry + adjust handling stays in one place.
|
|
3658
|
+
* @param {string} shapeName - preset geometry name (e.g. `rect`, `ellipse`, `roundRect`, `hexagon`)
|
|
3659
|
+
* @param {ObjectOptions} options - object options carrying optional `rectRadius`/`angleRange`/`arcThicknessRatio`
|
|
3660
|
+
* @param {number} cx - shape width (EMU), used to scale `rectRadius`
|
|
3661
|
+
* @param {number} cy - shape height (EMU), used to scale `rectRadius`
|
|
3662
|
+
* @return {string} `<a:prstGeom>` XML
|
|
3663
|
+
*/
|
|
3664
|
+
const RECT_RADIUS_ADJ1_SHAPES = new Set(["round2SameRect", "round2DiagRect"]);
|
|
3665
|
+
function genXmlPresetGeom(shapeName, options, cx, cy) {
|
|
3666
|
+
let strXml = `<a:prstGeom prst="${shapeName}"><a:avLst>`;
|
|
3667
|
+
if (options.rectRadius) {
|
|
3668
|
+
const adjVal = Math.round(options.rectRadius * EMU * 1e5 / Math.min(cx, cy));
|
|
3669
|
+
if (RECT_RADIUS_ADJ1_SHAPES.has(shapeName)) {
|
|
3670
|
+
strXml += `<a:gd name="adj1" fmla="val ${adjVal}"/>`;
|
|
3671
|
+
strXml += "<a:gd name=\"adj2\" fmla=\"val 0\"/>";
|
|
3672
|
+
} else strXml += `<a:gd name="adj" fmla="val ${adjVal}"/>`;
|
|
3673
|
+
} else if (options.angleRange) {
|
|
3674
|
+
for (let i = 0; i < 2; i++) {
|
|
3675
|
+
const angle = options.angleRange[i];
|
|
3676
|
+
strXml += `<a:gd name="adj${i + 1}" fmla="val ${convertRotationDegrees(angle)}" />`;
|
|
3677
|
+
}
|
|
3678
|
+
if (options.arcThicknessRatio) strXml += `<a:gd name="adj3" fmla="val ${Math.round(options.arcThicknessRatio * 5e4)}" />`;
|
|
3679
|
+
}
|
|
3680
|
+
strXml += "</a:avLst></a:prstGeom>";
|
|
3681
|
+
return strXml;
|
|
3682
|
+
}
|
|
3683
|
+
/**
|
|
3684
|
+
* Emit an `<a:custGeom>` for a freeform path built from `points`.
|
|
3685
|
+
* Shared by the shape and image code paths so that path emission stays in one place.
|
|
3686
|
+
* Points are authored in the object's own inch/EMU space (0..cx, 0..cy) — not slide-relative and not normalized.
|
|
3687
|
+
* @param {ObjectOptions['points']} points - freeform path DSL (`moveTo`/`lnTo`/`cubicBezTo`/`quadBezTo`/`arcTo`/`close`)
|
|
3688
|
+
* @param {number} cx - object width (EMU), used as the path viewport width
|
|
3689
|
+
* @param {number} cy - object height (EMU), used as the path viewport height
|
|
3690
|
+
* @param {PresLayout} layout - presentation layout used to resolve point coordinates to EMU
|
|
3691
|
+
* @return {string} `<a:custGeom>` XML
|
|
3692
|
+
*/
|
|
3693
|
+
function genXmlCustGeom(points, cx, cy, layout) {
|
|
3694
|
+
let strXml = "<a:custGeom><a:avLst />";
|
|
3695
|
+
strXml += "<a:gdLst>";
|
|
3696
|
+
strXml += "</a:gdLst>";
|
|
3697
|
+
strXml += "<a:ahLst />";
|
|
3698
|
+
strXml += "<a:cxnLst>";
|
|
3699
|
+
strXml += "</a:cxnLst>";
|
|
3700
|
+
strXml += "<a:rect l=\"l\" t=\"t\" r=\"r\" b=\"b\" />";
|
|
3701
|
+
strXml += "<a:pathLst>";
|
|
3702
|
+
strXml += `<a:path w="${cx}" h="${cy}">`;
|
|
3703
|
+
points?.forEach((point, i) => {
|
|
3704
|
+
if ("curve" in point) switch (point.curve.type) {
|
|
3705
|
+
case "arc":
|
|
3706
|
+
strXml += `<a:arcTo hR="${getSmartParseNumber(point.curve.hR, "Y", layout)}" wR="${getSmartParseNumber(point.curve.wR, "X", layout)}" stAng="${convertRotationDegrees(point.curve.stAng)}" swAng="${convertRotationDegrees(point.curve.swAng)}" />`;
|
|
3707
|
+
break;
|
|
3708
|
+
case "cubic":
|
|
3709
|
+
strXml += `<a:cubicBezTo>
|
|
3710
|
+
<a:pt x="${getSmartParseNumber(point.curve.x1, "X", layout)}" y="${getSmartParseNumber(point.curve.y1, "Y", layout)}" />
|
|
3711
|
+
<a:pt x="${getSmartParseNumber(point.curve.x2, "X", layout)}" y="${getSmartParseNumber(point.curve.y2, "Y", layout)}" />
|
|
3712
|
+
<a:pt x="${getSmartParseNumber(point.x, "X", layout)}" y="${getSmartParseNumber(point.y, "Y", layout)}" />
|
|
3713
|
+
</a:cubicBezTo>`;
|
|
3714
|
+
break;
|
|
3715
|
+
case "quadratic":
|
|
3716
|
+
strXml += `<a:quadBezTo>
|
|
3717
|
+
<a:pt x="${getSmartParseNumber(point.curve.x1, "X", layout)}" y="${getSmartParseNumber(point.curve.y1, "Y", layout)}" />
|
|
3718
|
+
<a:pt x="${getSmartParseNumber(point.x, "X", layout)}" y="${getSmartParseNumber(point.y, "Y", layout)}" />
|
|
3719
|
+
</a:quadBezTo>`;
|
|
3720
|
+
break;
|
|
3721
|
+
default: break;
|
|
3722
|
+
}
|
|
3723
|
+
else if ("close" in point) strXml += "<a:close />";
|
|
3724
|
+
else if (point.moveTo || i === 0) strXml += `<a:moveTo><a:pt x="${getSmartParseNumber(point.x, "X", layout)}" y="${getSmartParseNumber(point.y, "Y", layout)}" /></a:moveTo>`;
|
|
3725
|
+
else strXml += `<a:lnTo><a:pt x="${getSmartParseNumber(point.x, "X", layout)}" y="${getSmartParseNumber(point.y, "Y", layout)}" /></a:lnTo>`;
|
|
3726
|
+
});
|
|
3727
|
+
strXml += "</a:path>";
|
|
3728
|
+
strXml += "</a:pathLst>";
|
|
3729
|
+
strXml += "</a:custGeom>";
|
|
3730
|
+
return strXml;
|
|
3731
|
+
}
|
|
3415
3732
|
const PLACEHOLDER_TYPE_MAP = PLACEHOLDER_TYPES;
|
|
3416
3733
|
/**
|
|
3417
3734
|
* Transforms a slide or slideLayout to resulting XML string - Creates `ppt/slide*.xml`
|
|
@@ -3421,6 +3738,8 @@ const PLACEHOLDER_TYPE_MAP = PLACEHOLDER_TYPES;
|
|
|
3421
3738
|
function slideObjectToXml(slide) {
|
|
3422
3739
|
let strSlideXml = slide._name ? "<p:cSld name=\"" + slide._name + "\">" : "<p:cSld>";
|
|
3423
3740
|
let intTableNum = 1;
|
|
3741
|
+
const duplicateObjectNames = getDuplicateObjectNames(slide._slideObjects.map((obj) => obj.options?.objectName).filter((name) => typeof name === "string"));
|
|
3742
|
+
if (duplicateObjectNames.length > 0) console.warn(`Warning: duplicate objectName value(s) emitted on a single slide: ${duplicateObjectNames.join(", ")}. Selection Pane identities should be unique.`);
|
|
3424
3743
|
if (slide._bkgdImgRid) strSlideXml += `<p:bg><p:bgPr><a:blipFill dpi="0" rotWithShape="1"><a:blip r:embed="rId${slide._bkgdImgRid}"><a:lum/></a:blip><a:srcRect/><a:stretch><a:fillRect/></a:stretch></a:blipFill><a:effectLst/></p:bgPr></p:bg>`;
|
|
3425
3744
|
else if (slide.background?.color || slide.background?.type === "gradient") strSlideXml += `<p:bg><p:bgPr>${genXmlColorSelection(slide.background)}<a:effectLst/></p:bgPr></p:bg>`;
|
|
3426
3745
|
else if (!slide.bkgd && slide._name && slide._name === "DEFAULT") strSlideXml += "<p:bg><p:bgRef idx=\"1001\"><a:schemeClr val=\"bg1\"/></p:bgRef></p:bg>";
|
|
@@ -3462,17 +3781,21 @@ function slideObjectToXml(slide) {
|
|
|
3462
3781
|
if (slideItemObj.options.rotate) locationAttr += ` rot="${convertRotationDegrees(slideItemObj.options.rotate)}"`;
|
|
3463
3782
|
switch (slideItemObj._type) {
|
|
3464
3783
|
case "table":
|
|
3465
|
-
arrTabRows = slideItemObj.arrTabRows;
|
|
3784
|
+
arrTabRows = slideItemObj.arrTabRows.map((row) => [...row]);
|
|
3466
3785
|
objTabOpts = slideItemObj.options;
|
|
3467
3786
|
intColCnt = 0;
|
|
3468
3787
|
arrTabRows[0].forEach((cell) => {
|
|
3469
3788
|
cellOpts = cell.options || null;
|
|
3470
3789
|
intColCnt += cellOpts?.colspan ? Number(cellOpts.colspan) : 1;
|
|
3471
3790
|
});
|
|
3472
|
-
strXml = `<p:graphicFrame><p:nvGraphicFramePr><p:cNvPr id="${intTableNum * slide._slideNum + 1}" name="${slideItemObj.options.objectName}"/>`;
|
|
3791
|
+
strXml = `<p:graphicFrame><p:nvGraphicFramePr><p:cNvPr id="${intTableNum * slide._slideNum + 1}" name="${slideItemObj.options.objectName}" descr="${encodeXmlEntities(slideItemObj.options.altText || "")}"/>`;
|
|
3473
3792
|
strXml += "<p:cNvGraphicFramePr><a:graphicFrameLocks noGrp=\"1\"/></p:cNvGraphicFramePr> <p:nvPr><p:extLst><p:ext uri=\"{D42A27DB-BD31-4B8C-83A1-F6EECF244321}\"><p14:modId xmlns:p14=\"http://schemas.microsoft.com/office/powerpoint/2010/main\" val=\"1579011935\"/></p:ext></p:extLst></p:nvPr></p:nvGraphicFramePr>";
|
|
3474
3793
|
strXml += `<p:xfrm><a:off x="${x || (x === 0 ? 0 : EMU)}" y="${y || (y === 0 ? 0 : EMU)}"/><a:ext cx="${cx || (cx === 0 ? 0 : EMU)}" cy="${cy || EMU}"/></p:xfrm>`;
|
|
3475
|
-
|
|
3794
|
+
{
|
|
3795
|
+
const tblPrAttrs = (objTabOpts.hasHeader ? " firstRow=\"1\"" : "") + (objTabOpts.hasFooter ? " lastRow=\"1\"" : "") + (objTabOpts.hasBandedRows ? " bandRow=\"1\"" : "") + (objTabOpts.hasBandedColumns ? " bandCol=\"1\"" : "") + (objTabOpts.hasFirstColumn ? " firstCol=\"1\"" : "") + (objTabOpts.hasLastColumn ? " lastCol=\"1\"" : "");
|
|
3796
|
+
const tblPr = objTabOpts.tableStyle ? `<a:tblPr${tblPrAttrs}><a:tableStyleId>${objTabOpts.tableStyle}</a:tableStyleId></a:tblPr>` : `<a:tblPr${tblPrAttrs}/>`;
|
|
3797
|
+
strXml += `<a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/table"><a:tbl>${tblPr}`;
|
|
3798
|
+
}
|
|
3476
3799
|
if (Array.isArray(objTabOpts.colW)) {
|
|
3477
3800
|
strXml += "<a:tblGrid>";
|
|
3478
3801
|
for (let col = 0; col < intColCnt; col++) {
|
|
@@ -3641,7 +3964,7 @@ function slideObjectToXml(slide) {
|
|
|
3641
3964
|
slideItemObj.options._bodyProp.tIns = valToPts(slideItemObj.options.margin);
|
|
3642
3965
|
}
|
|
3643
3966
|
strSlideXml += "<p:sp>";
|
|
3644
|
-
strSlideXml += `<p:nvSpPr><p:cNvPr id="${idx + 2}" name="${slideItemObj.options.objectName}">`;
|
|
3967
|
+
strSlideXml += `<p:nvSpPr><p:cNvPr id="${idx + 2}" name="${slideItemObj.options.objectName}" descr="${encodeXmlEntities(slideItemObj.options.altText || "")}">`;
|
|
3645
3968
|
if (slideItemObj.options.hyperlink?.url) strSlideXml += `<a:hlinkClick r:id="rId${slideItemObj.options.hyperlink._rId}" tooltip="${slideItemObj.options.hyperlink.tooltip ? encodeXmlEntities(slideItemObj.options.hyperlink.tooltip) : ""}"/>`;
|
|
3646
3969
|
if (slideItemObj.options.hyperlink?.slide) strSlideXml += `<a:hlinkClick r:id="rId${slideItemObj.options.hyperlink._rId}" tooltip="${slideItemObj.options.hyperlink.tooltip ? encodeXmlEntities(slideItemObj.options.hyperlink.tooltip) : ""}" action="ppaction://hlinksldjump"/>`;
|
|
3647
3970
|
strSlideXml += "</p:cNvPr>";
|
|
@@ -3651,55 +3974,8 @@ function slideObjectToXml(slide) {
|
|
|
3651
3974
|
strSlideXml += `<a:xfrm${locationAttr}>`;
|
|
3652
3975
|
strSlideXml += `<a:off x="${x}" y="${y}"/>`;
|
|
3653
3976
|
strSlideXml += `<a:ext cx="${cx}" cy="${cy}"/></a:xfrm>`;
|
|
3654
|
-
if (slideItemObj.shape === "custGeom")
|
|
3655
|
-
|
|
3656
|
-
strSlideXml += "<a:gdLst>";
|
|
3657
|
-
strSlideXml += "</a:gdLst>";
|
|
3658
|
-
strSlideXml += "<a:ahLst />";
|
|
3659
|
-
strSlideXml += "<a:cxnLst>";
|
|
3660
|
-
strSlideXml += "</a:cxnLst>";
|
|
3661
|
-
strSlideXml += "<a:rect l=\"l\" t=\"t\" r=\"r\" b=\"b\" />";
|
|
3662
|
-
strSlideXml += "<a:pathLst>";
|
|
3663
|
-
strSlideXml += `<a:path w="${cx}" h="${cy}">`;
|
|
3664
|
-
slideItemObj.options.points?.forEach((point, i) => {
|
|
3665
|
-
if ("curve" in point) switch (point.curve.type) {
|
|
3666
|
-
case "arc":
|
|
3667
|
-
strSlideXml += `<a:arcTo hR="${getSmartParseNumber(point.curve.hR, "Y", slide._presLayout)}" wR="${getSmartParseNumber(point.curve.wR, "X", slide._presLayout)}" stAng="${convertRotationDegrees(point.curve.stAng)}" swAng="${convertRotationDegrees(point.curve.swAng)}" />`;
|
|
3668
|
-
break;
|
|
3669
|
-
case "cubic":
|
|
3670
|
-
strSlideXml += `<a:cubicBezTo>
|
|
3671
|
-
<a:pt x="${getSmartParseNumber(point.curve.x1, "X", slide._presLayout)}" y="${getSmartParseNumber(point.curve.y1, "Y", slide._presLayout)}" />
|
|
3672
|
-
<a:pt x="${getSmartParseNumber(point.curve.x2, "X", slide._presLayout)}" y="${getSmartParseNumber(point.curve.y2, "Y", slide._presLayout)}" />
|
|
3673
|
-
<a:pt x="${getSmartParseNumber(point.x, "X", slide._presLayout)}" y="${getSmartParseNumber(point.y, "Y", slide._presLayout)}" />
|
|
3674
|
-
</a:cubicBezTo>`;
|
|
3675
|
-
break;
|
|
3676
|
-
case "quadratic":
|
|
3677
|
-
strSlideXml += `<a:quadBezTo>
|
|
3678
|
-
<a:pt x="${getSmartParseNumber(point.curve.x1, "X", slide._presLayout)}" y="${getSmartParseNumber(point.curve.y1, "Y", slide._presLayout)}" />
|
|
3679
|
-
<a:pt x="${getSmartParseNumber(point.x, "X", slide._presLayout)}" y="${getSmartParseNumber(point.y, "Y", slide._presLayout)}" />
|
|
3680
|
-
</a:quadBezTo>`;
|
|
3681
|
-
break;
|
|
3682
|
-
default: break;
|
|
3683
|
-
}
|
|
3684
|
-
else if ("close" in point) strSlideXml += "<a:close />";
|
|
3685
|
-
else if (point.moveTo || i === 0) strSlideXml += `<a:moveTo><a:pt x="${getSmartParseNumber(point.x, "X", slide._presLayout)}" y="${getSmartParseNumber(point.y, "Y", slide._presLayout)}" /></a:moveTo>`;
|
|
3686
|
-
else strSlideXml += `<a:lnTo><a:pt x="${getSmartParseNumber(point.x, "X", slide._presLayout)}" y="${getSmartParseNumber(point.y, "Y", slide._presLayout)}" /></a:lnTo>`;
|
|
3687
|
-
});
|
|
3688
|
-
strSlideXml += "</a:path>";
|
|
3689
|
-
strSlideXml += "</a:pathLst>";
|
|
3690
|
-
strSlideXml += "</a:custGeom>";
|
|
3691
|
-
} else {
|
|
3692
|
-
strSlideXml += "<a:prstGeom prst=\"" + slideItemObj.shape + "\"><a:avLst>";
|
|
3693
|
-
if (slideItemObj.options.rectRadius) strSlideXml += `<a:gd name="adj" fmla="val ${Math.round(slideItemObj.options.rectRadius * EMU * 1e5 / Math.min(cx, cy))}"/>`;
|
|
3694
|
-
else if (slideItemObj.options.angleRange) {
|
|
3695
|
-
for (let i = 0; i < 2; i++) {
|
|
3696
|
-
const angle = slideItemObj.options.angleRange[i];
|
|
3697
|
-
strSlideXml += `<a:gd name="adj${i + 1}" fmla="val ${convertRotationDegrees(angle)}" />`;
|
|
3698
|
-
}
|
|
3699
|
-
if (slideItemObj.options.arcThicknessRatio) strSlideXml += `<a:gd name="adj3" fmla="val ${Math.round(slideItemObj.options.arcThicknessRatio * 5e4)}" />`;
|
|
3700
|
-
}
|
|
3701
|
-
strSlideXml += "</a:avLst></a:prstGeom>";
|
|
3702
|
-
}
|
|
3977
|
+
if (slideItemObj.shape === "custGeom") strSlideXml += genXmlCustGeom(slideItemObj.options.points, cx, cy, slide._presLayout);
|
|
3978
|
+
else strSlideXml += genXmlPresetGeom(slideItemObj.shape, slideItemObj.options, cx, cy);
|
|
3703
3979
|
strSlideXml += slideItemObj.options.fill ? genXmlColorSelection(slideItemObj.options.fill) : "<a:noFill/>";
|
|
3704
3980
|
if (slideItemObj.options.line) {
|
|
3705
3981
|
strSlideXml += slideItemObj.options.line.width ? `<a:ln w="${valToPts(slideItemObj.options.line.width)}">` : "<a:ln>";
|
|
@@ -3712,10 +3988,10 @@ function slideObjectToXml(slide) {
|
|
|
3712
3988
|
if (slideItemObj.options.shadow && slideItemObj.options.shadow.type !== "none") {
|
|
3713
3989
|
const sh = slideItemObj.options.shadow;
|
|
3714
3990
|
const shadowType = sh.type || "outer";
|
|
3715
|
-
const shadowBlur = valToPts(sh.blur
|
|
3716
|
-
const shadowOffset = valToPts(sh.offset
|
|
3717
|
-
const shadowAngle = Math.round((sh.angle
|
|
3718
|
-
const shadowOpacity = Math.round((sh.opacity
|
|
3991
|
+
const shadowBlur = valToPts(sh.blur ?? 8);
|
|
3992
|
+
const shadowOffset = valToPts(sh.offset ?? 4);
|
|
3993
|
+
const shadowAngle = Math.round((sh.angle ?? 270) * 6e4);
|
|
3994
|
+
const shadowOpacity = Math.round((sh.opacity ?? .75) * 1e5);
|
|
3719
3995
|
const shadowColor = sh.color || DEF_TEXT_SHADOW.color;
|
|
3720
3996
|
strSlideXml += "<a:effectLst>";
|
|
3721
3997
|
strSlideXml += ` <a:${shadowType}Shdw ${shadowType === "outer" ? "sx=\"100000\" sy=\"100000\" kx=\"0\" ky=\"0\" algn=\"bl\" rotWithShape=\"0\"" : ""} blurRad="${shadowBlur}" dist="${shadowOffset}" dir="${shadowAngle}">`;
|
|
@@ -3742,6 +4018,7 @@ function slideObjectToXml(slide) {
|
|
|
3742
4018
|
if ((slide._relsMedia || []).find((rel) => rel.rId === slideItemObj.imageRid)?.extn === "svg") {
|
|
3743
4019
|
strSlideXml += `<a:blip r:embed="rId${slideItemObj.imageRid - 1}">`;
|
|
3744
4020
|
strSlideXml += slideItemObj.options.transparency ? ` <a:alphaModFix amt="${Math.round((100 - slideItemObj.options.transparency) * 1e3)}"/>` : "";
|
|
4021
|
+
strSlideXml += slideItemObj.options.duotone ? `<a:duotone>${createColorElement(slideItemObj.options.duotone.shadow)}${createColorElement(slideItemObj.options.duotone.highlight)}</a:duotone>` : "";
|
|
3745
4022
|
strSlideXml += " <a:extLst>";
|
|
3746
4023
|
strSlideXml += " <a:ext uri=\"{96DAC541-7B7A-43D3-8B79-37D633B846F1}\">";
|
|
3747
4024
|
strSlideXml += ` <asvg:svgBlip xmlns:asvg="http://schemas.microsoft.com/office/drawing/2016/SVG/main" r:embed="rId${slideItemObj.imageRid}"/>`;
|
|
@@ -3751,6 +4028,7 @@ function slideObjectToXml(slide) {
|
|
|
3751
4028
|
} else {
|
|
3752
4029
|
strSlideXml += `<a:blip r:embed="rId${slideItemObj.imageRid}">`;
|
|
3753
4030
|
strSlideXml += slideItemObj.options.transparency ? `<a:alphaModFix amt="${Math.round((100 - slideItemObj.options.transparency) * 1e3)}"/>` : "";
|
|
4031
|
+
strSlideXml += slideItemObj.options.duotone ? `<a:duotone>${createColorElement(slideItemObj.options.duotone.shadow)}${createColorElement(slideItemObj.options.duotone.highlight)}</a:duotone>` : "";
|
|
3754
4032
|
strSlideXml += "</a:blip>";
|
|
3755
4033
|
}
|
|
3756
4034
|
if (sizing?.type) {
|
|
@@ -3758,10 +4036,17 @@ function slideObjectToXml(slide) {
|
|
|
3758
4036
|
const boxH = sizing.h ? getSmartParseNumber(sizing.h, "Y", slide._presLayout) : cy;
|
|
3759
4037
|
const boxX = getSmartParseNumber(sizing.x || 0, "X", slide._presLayout);
|
|
3760
4038
|
const boxY = getSmartParseNumber(sizing.y || 0, "Y", slide._presLayout);
|
|
3761
|
-
|
|
4039
|
+
let cropSize = {
|
|
3762
4040
|
w: imgWidth,
|
|
3763
4041
|
h: imgHeight
|
|
3764
|
-
}
|
|
4042
|
+
};
|
|
4043
|
+
if (sizing.type === "cover" || sizing.type === "contain") {
|
|
4044
|
+
const relData = (slide._relsMedia || []).find((rel) => rel.rId === slideItemObj.imageRid)?.data;
|
|
4045
|
+
const natural = typeof relData === "string" ? getImageSizeFromBase64(relData) : null;
|
|
4046
|
+
if (natural) cropSize = natural;
|
|
4047
|
+
else console.warn(`Warning: sizing '${sizing.type}' could not measure natural dimensions for image "${slideItemObj.options.objectName}"; falling back to displayed aspect ratio (crop may be inexact). Provide a raster image (PNG/JPEG/GIF/BMP/WebP) to enable an aspect-correct crop.`);
|
|
4048
|
+
}
|
|
4049
|
+
strSlideXml += ImageSizingXml[sizing.type](cropSize, {
|
|
3765
4050
|
w: boxW,
|
|
3766
4051
|
h: boxH,
|
|
3767
4052
|
x: boxX,
|
|
@@ -3776,14 +4061,15 @@ function slideObjectToXml(slide) {
|
|
|
3776
4061
|
strSlideXml += ` <a:off x="${x}" y="${y}"/>`;
|
|
3777
4062
|
strSlideXml += ` <a:ext cx="${imgWidth}" cy="${imgHeight}"/>`;
|
|
3778
4063
|
strSlideXml += " </a:xfrm>";
|
|
3779
|
-
strSlideXml +=
|
|
4064
|
+
if (slideItemObj.options.points) strSlideXml += " " + genXmlCustGeom(slideItemObj.options.points, imgWidth, imgHeight, slide._presLayout);
|
|
4065
|
+
else strSlideXml += " " + genXmlPresetGeom(slideItemObj.options.shape ?? (rounding ? "ellipse" : "rect"), slideItemObj.options, imgWidth, imgHeight);
|
|
3780
4066
|
if (slideItemObj.options.shadow && slideItemObj.options.shadow.type !== "none") {
|
|
3781
4067
|
const sh = slideItemObj.options.shadow;
|
|
3782
4068
|
const shadowType = sh.type || "outer";
|
|
3783
|
-
const shadowBlur = valToPts(sh.blur
|
|
3784
|
-
const shadowOffset = valToPts(sh.offset
|
|
3785
|
-
const shadowAngle = Math.round((sh.angle
|
|
3786
|
-
const shadowOpacity = Math.round((sh.opacity
|
|
4069
|
+
const shadowBlur = valToPts(sh.blur ?? 8);
|
|
4070
|
+
const shadowOffset = valToPts(sh.offset ?? 4);
|
|
4071
|
+
const shadowAngle = Math.round((sh.angle ?? 270) * 6e4);
|
|
4072
|
+
const shadowOpacity = Math.round((sh.opacity ?? .75) * 1e5);
|
|
3787
4073
|
const shadowColor = sh.color || DEF_TEXT_SHADOW.color;
|
|
3788
4074
|
strSlideXml += "<a:effectLst>";
|
|
3789
4075
|
strSlideXml += `<a:${shadowType}Shdw ${shadowType === "outer" ? "sx=\"100000\" sy=\"100000\" kx=\"0\" ky=\"0\" algn=\"bl\" rotWithShape=\"0\"" : ""} blurRad="${shadowBlur}" dist="${shadowOffset}" dir="${shadowAngle}">`;
|
|
@@ -3799,7 +4085,7 @@ function slideObjectToXml(slide) {
|
|
|
3799
4085
|
if (slideItemObj.mtype === "online") {
|
|
3800
4086
|
strSlideXml += "<p:pic>";
|
|
3801
4087
|
strSlideXml += " <p:nvPicPr>";
|
|
3802
|
-
strSlideXml += `<p:cNvPr id="${slideItemObj.mediaRid + 2}" name="${slideItemObj.options.objectName}"/>`;
|
|
4088
|
+
strSlideXml += `<p:cNvPr id="${slideItemObj.mediaRid + 2}" name="${slideItemObj.options.objectName}" descr="${encodeXmlEntities(slideItemObj.options.altText || "")}"/>`;
|
|
3803
4089
|
strSlideXml += " <p:cNvPicPr/>";
|
|
3804
4090
|
strSlideXml += " <p:nvPr>";
|
|
3805
4091
|
strSlideXml += ` <a:videoFile r:link="rId${slideItemObj.mediaRid}"/>`;
|
|
@@ -3814,7 +4100,7 @@ function slideObjectToXml(slide) {
|
|
|
3814
4100
|
} else {
|
|
3815
4101
|
strSlideXml += "<p:pic>";
|
|
3816
4102
|
strSlideXml += " <p:nvPicPr>";
|
|
3817
|
-
strSlideXml += `<p:cNvPr id="${slideItemObj.mediaRid + 2}" name="${slideItemObj.options.objectName}"><a:hlinkClick r:id="" action="ppaction://media"/></p:cNvPr>`;
|
|
4103
|
+
strSlideXml += `<p:cNvPr id="${slideItemObj.mediaRid + 2}" name="${slideItemObj.options.objectName}" descr="${encodeXmlEntities(slideItemObj.options.altText || "")}"><a:hlinkClick r:id="" action="ppaction://media"/></p:cNvPr>`;
|
|
3818
4104
|
strSlideXml += " <p:cNvPicPr><a:picLocks noChangeAspect=\"1\"/></p:cNvPicPr>";
|
|
3819
4105
|
strSlideXml += " <p:nvPr>";
|
|
3820
4106
|
strSlideXml += ` <a:videoFile r:link="rId${slideItemObj.mediaRid}"/>`;
|
|
@@ -3944,6 +4230,7 @@ function slideObjectRelationsToXml(slide, defaultRels) {
|
|
|
3944
4230
|
*/
|
|
3945
4231
|
function genXmlParagraphProperties(textObj, isDefault) {
|
|
3946
4232
|
let strXmlBullet = "";
|
|
4233
|
+
let strXmlBulletColor = "";
|
|
3947
4234
|
let strXmlLnSpc = "";
|
|
3948
4235
|
let strXmlParaSpc = "";
|
|
3949
4236
|
let strXmlTabStops = "";
|
|
@@ -3974,6 +4261,7 @@ function genXmlParagraphProperties(textObj, isDefault) {
|
|
|
3974
4261
|
if (textObj.options.paraSpaceAfter && !isNaN(Number(textObj.options.paraSpaceAfter)) && textObj.options.paraSpaceAfter > 0) strXmlParaSpc += `<a:spcAft><a:spcPts val="${Math.round(textObj.options.paraSpaceAfter * 100)}"/></a:spcAft>`;
|
|
3975
4262
|
if (typeof textObj.options.bullet === "object") {
|
|
3976
4263
|
if (textObj?.options?.bullet?.indent) bulletMarL = valToPts(textObj.options.bullet.indent);
|
|
4264
|
+
if (textObj.options.bullet.color) strXmlBulletColor = `<a:buClr>${createColorElement(textObj.options.bullet.color)}</a:buClr>`;
|
|
3977
4265
|
if (textObj.options.bullet.type && textObj.options.bullet.type.toString().toLowerCase() === "number") {
|
|
3978
4266
|
paragraphPropXml += ` marL="${textObj.options.indentLevel && textObj.options.indentLevel > 0 ? bulletMarL + bulletMarL * textObj.options.indentLevel : bulletMarL}" indent="-${bulletMarL}"`;
|
|
3979
4267
|
strXmlBullet = `<a:buSzPct val="100000"/><a:buFont typeface="+mj-lt"/><a:buAutoNum type="${textObj.options.bullet.style || "arabicPeriod"}" startAt="${textObj.options.bullet.numberStartAt || textObj.options.bullet.startAt || "1"}"/>`;
|
|
@@ -4005,7 +4293,7 @@ function genXmlParagraphProperties(textObj, isDefault) {
|
|
|
4005
4293
|
strXmlBullet = "<a:buNone/>";
|
|
4006
4294
|
}
|
|
4007
4295
|
if (textObj.options.tabStops && Array.isArray(textObj.options.tabStops)) strXmlTabStops = `<a:tabLst>${textObj.options.tabStops.map((stop) => `<a:tab pos="${inch2Emu(stop.position || 1)}" algn="${stop.alignment || "l"}"/>`).join("")}</a:tabLst>`;
|
|
4008
|
-
paragraphPropXml += ">" + strXmlLnSpc + strXmlParaSpc + strXmlBullet + strXmlTabStops;
|
|
4296
|
+
paragraphPropXml += ">" + strXmlLnSpc + strXmlParaSpc + strXmlBulletColor + strXmlBullet + strXmlTabStops;
|
|
4009
4297
|
if (isDefault) paragraphPropXml += genXmlTextRunProperties(textObj.options, true);
|
|
4010
4298
|
paragraphPropXml += "</" + tag + ">";
|
|
4011
4299
|
return paragraphPropXml;
|
|
@@ -4024,6 +4312,7 @@ function genXmlTextRunProperties(opts, isDefault) {
|
|
|
4024
4312
|
runProps += opts?.bold ? ` b="${opts.bold ? "1" : "0"}"` : "";
|
|
4025
4313
|
runProps += opts?.italic ? ` i="${opts.italic ? "1" : "0"}"` : "";
|
|
4026
4314
|
runProps += opts?.strike ? ` strike="${typeof opts.strike === "string" ? opts.strike : "sngStrike"}"` : "";
|
|
4315
|
+
runProps += opts?.caps ? ` cap="${opts.caps}"` : "";
|
|
4027
4316
|
if (typeof opts.underline === "object" && opts.underline?.style) runProps += ` u="${opts.underline.style}"`;
|
|
4028
4317
|
else if (typeof opts.underline === "string") runProps += ` u="${String(opts.underline)}"`;
|
|
4029
4318
|
else if (opts.hyperlink) runProps += " u=\"sng\"";
|
|
@@ -4153,14 +4442,19 @@ function genXmlTextBody(slideObj) {
|
|
|
4153
4442
|
itext.options = itext.options || opts || {};
|
|
4154
4443
|
if (idx === 0 && itext.options && !itext.options.bullet && opts.bullet) itext.options.bullet = opts.bullet;
|
|
4155
4444
|
if (typeof itext.text === "string" || typeof itext.text === "number") itext.text = itext.text.toString().replace(/\r*\n/g, "\r\n");
|
|
4156
|
-
if (itext.text.includes("\r\n") && itext.text.match(/\n$/g) === null)
|
|
4157
|
-
itext.
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4445
|
+
if (itext.text.includes("\r\n") && itext.text.match(/\n$/g) === null) {
|
|
4446
|
+
const lines = itext.text.split("\r\n");
|
|
4447
|
+
lines.forEach((line, lineIdx) => {
|
|
4448
|
+
const isLast = lineIdx === lines.length - 1;
|
|
4449
|
+
arrTextObjects.push({
|
|
4450
|
+
text: line,
|
|
4451
|
+
options: {
|
|
4452
|
+
...itext.options,
|
|
4453
|
+
breakLine: isLast ? itext.options.breakLine : true
|
|
4454
|
+
}
|
|
4455
|
+
});
|
|
4161
4456
|
});
|
|
4162
|
-
});
|
|
4163
|
-
else arrTextObjects.push(itext);
|
|
4457
|
+
} else arrTextObjects.push(itext);
|
|
4164
4458
|
});
|
|
4165
4459
|
const arrLines = [];
|
|
4166
4460
|
let arrTexts = [];
|
|
@@ -4262,7 +4556,7 @@ function genXmlPlaceholder(placeholderObj) {
|
|
|
4262
4556
|
* @param {PresSlideInternal} masterSlide - master slide
|
|
4263
4557
|
* @returns XML
|
|
4264
4558
|
*/
|
|
4265
|
-
function makeXmlContTypes(slides, slideLayouts, masterSlide) {
|
|
4559
|
+
function makeXmlContTypes(slides, slideLayouts, masterSlide, hasCustomProps) {
|
|
4266
4560
|
let strXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n";
|
|
4267
4561
|
strXml += "<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">";
|
|
4268
4562
|
strXml += "<Default Extension=\"xml\" ContentType=\"application/xml\"/>";
|
|
@@ -4312,6 +4606,7 @@ function makeXmlContTypes(slides, slideLayouts, masterSlide) {
|
|
|
4312
4606
|
});
|
|
4313
4607
|
strXml += " <Override PartName=\"/docProps/core.xml\" ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\"/>";
|
|
4314
4608
|
strXml += " <Override PartName=\"/docProps/app.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\"/>";
|
|
4609
|
+
if (hasCustomProps) strXml += " <Override PartName=\"/docProps/custom.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.custom-properties+xml\"/>";
|
|
4315
4610
|
strXml += "</Types>";
|
|
4316
4611
|
return strXml;
|
|
4317
4612
|
}
|
|
@@ -4319,13 +4614,15 @@ function makeXmlContTypes(slides, slideLayouts, masterSlide) {
|
|
|
4319
4614
|
* Creates `_rels/.rels`
|
|
4320
4615
|
* @returns XML
|
|
4321
4616
|
*/
|
|
4322
|
-
function makeXmlRootRels() {
|
|
4323
|
-
|
|
4617
|
+
function makeXmlRootRels(hasCustomProps) {
|
|
4618
|
+
let xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
|
|
4324
4619
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
4325
4620
|
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
|
|
4326
4621
|
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
|
|
4327
|
-
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="ppt/presentation.xml"
|
|
4328
|
-
|
|
4622
|
+
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="ppt/presentation.xml"/>`;
|
|
4623
|
+
if (hasCustomProps) xml += "\n <Relationship Id=\"rId4\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties\" Target=\"docProps/custom.xml\"/>";
|
|
4624
|
+
xml += "\n </Relationships>";
|
|
4625
|
+
return xml;
|
|
4329
4626
|
}
|
|
4330
4627
|
/**
|
|
4331
4628
|
* Creates `docProps/app.xml`
|
|
@@ -4391,6 +4688,23 @@ function makeXmlCore(title, subject, author, revision) {
|
|
|
4391
4688
|
<dcterms:modified xsi:type="dcterms:W3CDTF">${(/* @__PURE__ */ new Date()).toISOString().replace(/\.\d\d\dZ/, "Z")}</dcterms:modified>
|
|
4392
4689
|
</cp:coreProperties>`;
|
|
4393
4690
|
}
|
|
4691
|
+
const CUSTOM_PROPS_FMTID = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}";
|
|
4692
|
+
/**
|
|
4693
|
+
* Creates `docProps/custom.xml`
|
|
4694
|
+
* @param props - custom property name/value pairs
|
|
4695
|
+
* @returns XML
|
|
4696
|
+
*/
|
|
4697
|
+
function makeXmlCustomProperties(props) {
|
|
4698
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
|
|
4699
|
+
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">${props.map(({ name, value }, idx) => {
|
|
4700
|
+
let valueXml;
|
|
4701
|
+
if (typeof value === "boolean") valueXml = `<vt:bool>${value}</vt:bool>`;
|
|
4702
|
+
else if (value instanceof Date) valueXml = `<vt:filetime>${value.toISOString().replace(/\.\d{3}Z$/, "Z")}</vt:filetime>`;
|
|
4703
|
+
else if (typeof value === "number") valueXml = Number.isInteger(value) ? `<vt:i4>${value}</vt:i4>` : `<vt:r8>${value}</vt:r8>`;
|
|
4704
|
+
else valueXml = `<vt:lpwstr>${encodeXmlEntities(String(value))}</vt:lpwstr>`;
|
|
4705
|
+
return `<property fmtid="${CUSTOM_PROPS_FMTID}" pid="${idx + 2}" name="${encodeXmlEntities(name)}">${valueXml}</property>`;
|
|
4706
|
+
}).join("")}</Properties>`;
|
|
4707
|
+
}
|
|
4394
4708
|
/**
|
|
4395
4709
|
* Creates `ppt/_rels/presentation.xml.rels`
|
|
4396
4710
|
* @param {PresSlideInternal[]} slides - Presenation Slides
|
|
@@ -4567,7 +4881,7 @@ function makeXmlTheme(pres) {
|
|
|
4567
4881
|
*/
|
|
4568
4882
|
function makeXmlPresentation(pres) {
|
|
4569
4883
|
let strXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
|
|
4570
|
-
<p:presentation xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" ${pres.rtlMode ? "rtl=\"1\"" : ""} saveSubsetFonts="1" autoCompressPictures="0">`;
|
|
4884
|
+
<p:presentation xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" ${pres.rtlMode ? "rtl=\"1\"" : ""} saveSubsetFonts="1" autoCompressPictures="0"${pres.firstSlideNum !== 1 ? ` firstSlideNum="${pres.firstSlideNum}"` : ""}>`;
|
|
4571
4885
|
strXml += "<p:sldMasterIdLst><p:sldMasterId id=\"2147483648\" r:id=\"rId1\"/></p:sldMasterIdLst>";
|
|
4572
4886
|
strXml += `<p:notesMasterIdLst><p:notesMasterId r:id="rId${pres.slides.length + 2}"/></p:notesMasterIdLst>`;
|
|
4573
4887
|
strXml += "<p:sldIdLst>";
|
|
@@ -4606,9 +4920,96 @@ function makeXmlPresProps() {
|
|
|
4606
4920
|
* @see: http://openxmldeveloper.org/discussions/formats/f/13/p/2398/8107.aspx
|
|
4607
4921
|
* @return {string} XML
|
|
4608
4922
|
*/
|
|
4609
|
-
function makeXmlTableStyles() {
|
|
4610
|
-
|
|
4611
|
-
<a:tblStyleLst xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" def="{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}"
|
|
4923
|
+
function makeXmlTableStyles(tableStyles = []) {
|
|
4924
|
+
const open = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
|
|
4925
|
+
<a:tblStyleLst xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" def="{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}"`;
|
|
4926
|
+
if (!tableStyles || tableStyles.length === 0) return `${open}/>`;
|
|
4927
|
+
let strXml = `${open}>`;
|
|
4928
|
+
tableStyles.forEach(({ guid, def }) => {
|
|
4929
|
+
strXml += `<a:tblStyle styleId="${guid}" styleName="${encodeXmlEntities(def.name)}">`;
|
|
4930
|
+
[
|
|
4931
|
+
["wholeTbl", def.wholeTbl],
|
|
4932
|
+
["band1H", def.band1H],
|
|
4933
|
+
["band2H", def.band2H],
|
|
4934
|
+
["band1V", def.band1V],
|
|
4935
|
+
["band2V", def.band2V],
|
|
4936
|
+
["lastCol", def.lastCol],
|
|
4937
|
+
["firstCol", def.firstCol],
|
|
4938
|
+
["lastRow", def.lastRow],
|
|
4939
|
+
["firstRow", def.firstRow]
|
|
4940
|
+
].forEach(([name, region]) => {
|
|
4941
|
+
if (region) strXml += genXmlTableStyleRegion(name, region);
|
|
4942
|
+
});
|
|
4943
|
+
strXml += "</a:tblStyle>";
|
|
4944
|
+
});
|
|
4945
|
+
strXml += "</a:tblStyleLst>";
|
|
4946
|
+
return strXml;
|
|
4947
|
+
}
|
|
4948
|
+
/**
|
|
4949
|
+
* Build one `CT_TablePartStyle` region (e.g. `firstRow`, `band1H`) for a custom table style.
|
|
4950
|
+
* Emits `tcTxStyle` (text) before `tcStyle` (cell fill/borders) per the schema sequence.
|
|
4951
|
+
* @param {string} name - region element name
|
|
4952
|
+
* @param {TableStyleRegionProps} region - region styling
|
|
4953
|
+
* @return {string} XML
|
|
4954
|
+
*/
|
|
4955
|
+
function genXmlTableStyleRegion(name, region) {
|
|
4956
|
+
let xml = `<a:${name}>`;
|
|
4957
|
+
if (region.bold !== void 0 || region.italic !== void 0 || region.color) {
|
|
4958
|
+
const b = region.bold ? " b=\"on\"" : "";
|
|
4959
|
+
const i = region.italic ? " i=\"on\"" : "";
|
|
4960
|
+
xml += `<a:tcTxStyle${b}${i}><a:fontRef idx="minor"/>`;
|
|
4961
|
+
xml += region.color ? createColorElement(region.color) : "";
|
|
4962
|
+
xml += "</a:tcTxStyle>";
|
|
4963
|
+
}
|
|
4964
|
+
if (region.border !== void 0 || region.fill !== void 0) {
|
|
4965
|
+
xml += "<a:tcStyle>";
|
|
4966
|
+
if (region.border !== void 0) xml += genXmlTableStyleBorders(region.border);
|
|
4967
|
+
if (region.fill !== void 0) xml += `<a:fill><a:solidFill>${createColorElement(region.fill)}</a:solidFill></a:fill>`;
|
|
4968
|
+
xml += "</a:tcStyle>";
|
|
4969
|
+
}
|
|
4970
|
+
xml += `</a:${name}>`;
|
|
4971
|
+
return xml;
|
|
4972
|
+
}
|
|
4973
|
+
/**
|
|
4974
|
+
* Build the `tcBdr` border block for a custom table style region.
|
|
4975
|
+
* A single `BorderProps` styles all four sides plus the interior grid lines; a
|
|
4976
|
+
* TRBL array styles only the four outer sides. Sides are emitted in schema order.
|
|
4977
|
+
* @param {BorderProps | BorderProps[]} border - border definition
|
|
4978
|
+
* @return {string} XML
|
|
4979
|
+
*/
|
|
4980
|
+
function genXmlTableStyleBorders(border) {
|
|
4981
|
+
let sides;
|
|
4982
|
+
if (Array.isArray(border)) {
|
|
4983
|
+
const [top, right, bottom, left] = border;
|
|
4984
|
+
sides = [
|
|
4985
|
+
["left", left],
|
|
4986
|
+
["right", right],
|
|
4987
|
+
["top", top],
|
|
4988
|
+
["bottom", bottom]
|
|
4989
|
+
];
|
|
4990
|
+
} else sides = [
|
|
4991
|
+
["left", border],
|
|
4992
|
+
["right", border],
|
|
4993
|
+
["top", border],
|
|
4994
|
+
["bottom", border],
|
|
4995
|
+
["insideH", border],
|
|
4996
|
+
["insideV", border]
|
|
4997
|
+
];
|
|
4998
|
+
let xml = "<a:tcBdr>";
|
|
4999
|
+
sides.forEach(([side, b]) => {
|
|
5000
|
+
if (!b) return;
|
|
5001
|
+
xml += `<a:${side}>`;
|
|
5002
|
+
if (b.type === "none") xml += "<a:ln><a:noFill/></a:ln>";
|
|
5003
|
+
else {
|
|
5004
|
+
xml += `<a:ln w="${valToPts(b.pt ?? 1)}" cap="flat" cmpd="sng" algn="ctr">`;
|
|
5005
|
+
xml += `<a:solidFill>${createColorElement(b.color ?? "666666")}</a:solidFill>`;
|
|
5006
|
+
xml += `<a:prstDash val="${b.type === "dash" ? "sysDash" : "solid"}"/>`;
|
|
5007
|
+
xml += "</a:ln>";
|
|
5008
|
+
}
|
|
5009
|
+
xml += `</a:${side}>`;
|
|
5010
|
+
});
|
|
5011
|
+
xml += "</a:tcBdr>";
|
|
5012
|
+
return xml;
|
|
4612
5013
|
}
|
|
4613
5014
|
/**
|
|
4614
5015
|
* Creates `ppt/viewProps.xml`
|
|
@@ -4678,7 +5079,7 @@ function makeXmlViewProps() {
|
|
|
4678
5079
|
* @see https://docs.microsoft.com/en-us/office/open-xml/structure-of-a-presentationml-document
|
|
4679
5080
|
* @see https://docs.microsoft.com/en-us/previous-versions/office/developer/office-2010/hh273476(v=office.14)
|
|
4680
5081
|
*/
|
|
4681
|
-
const VERSION = "5.0
|
|
5082
|
+
const VERSION = "5.2.0";
|
|
4682
5083
|
function standardLayoutToPresLayout(layout) {
|
|
4683
5084
|
return {
|
|
4684
5085
|
name: layout.name,
|
|
@@ -4701,9 +5102,10 @@ var PptxGenJS = class {
|
|
|
4701
5102
|
*/
|
|
4702
5103
|
_layout;
|
|
4703
5104
|
set layout(value) {
|
|
4704
|
-
const
|
|
5105
|
+
const layoutKey = typeof value === "string" ? value : value?.layout;
|
|
5106
|
+
const newLayout = layoutKey ? this.LAYOUTS[layoutKey] : void 0;
|
|
4705
5107
|
if (newLayout) {
|
|
4706
|
-
this._layout =
|
|
5108
|
+
this._layout = layoutKey;
|
|
4707
5109
|
this._presLayout = newLayout;
|
|
4708
5110
|
} else throw new Error("UNKNOWN-LAYOUT");
|
|
4709
5111
|
}
|
|
@@ -4778,6 +5180,14 @@ var PptxGenJS = class {
|
|
|
4778
5180
|
get title() {
|
|
4779
5181
|
return this._title;
|
|
4780
5182
|
}
|
|
5183
|
+
/** Slide number shown on the first slide (maps to firstSlideNum in presentation.xml) */
|
|
5184
|
+
_firstSlideNum;
|
|
5185
|
+
set firstSlideNum(value) {
|
|
5186
|
+
this._firstSlideNum = value;
|
|
5187
|
+
}
|
|
5188
|
+
get firstSlideNum() {
|
|
5189
|
+
return this._firstSlideNum;
|
|
5190
|
+
}
|
|
4781
5191
|
/**
|
|
4782
5192
|
* Whether Right-to-Left (RTL) mode is enabled
|
|
4783
5193
|
* @type {boolean}
|
|
@@ -4804,6 +5214,9 @@ var PptxGenJS = class {
|
|
|
4804
5214
|
get sections() {
|
|
4805
5215
|
return this._sections;
|
|
4806
5216
|
}
|
|
5217
|
+
/** custom document properties stored in docProps/custom.xml */
|
|
5218
|
+
_customProperties;
|
|
5219
|
+
_tableStyles;
|
|
4807
5220
|
/** slide layout definition objects, used for generating slide layout files */
|
|
4808
5221
|
_slideLayouts;
|
|
4809
5222
|
get slideLayouts() {
|
|
@@ -4813,6 +5226,7 @@ var PptxGenJS = class {
|
|
|
4813
5226
|
return {
|
|
4814
5227
|
author: this.author,
|
|
4815
5228
|
company: this.company,
|
|
5229
|
+
firstSlideNum: this.firstSlideNum,
|
|
4816
5230
|
layout: this.layout,
|
|
4817
5231
|
masterSlide: this._masterSlide,
|
|
4818
5232
|
presLayout: this.presLayout,
|
|
@@ -4897,6 +5311,7 @@ var PptxGenJS = class {
|
|
|
4897
5311
|
width: this.LAYOUTS[DEF_PRES_LAYOUT].width,
|
|
4898
5312
|
height: this.LAYOUTS[DEF_PRES_LAYOUT].height
|
|
4899
5313
|
};
|
|
5314
|
+
this._firstSlideNum = 1;
|
|
4900
5315
|
this._rtlMode = false;
|
|
4901
5316
|
this._slideLayouts = [{
|
|
4902
5317
|
_margin: DEF_SLIDE_MARGIN_IN,
|
|
@@ -4912,6 +5327,8 @@ var PptxGenJS = class {
|
|
|
4912
5327
|
}];
|
|
4913
5328
|
this._slides = [];
|
|
4914
5329
|
this._sections = [];
|
|
5330
|
+
this._customProperties = [];
|
|
5331
|
+
this._tableStyles = [];
|
|
4915
5332
|
this._masterSlide = {
|
|
4916
5333
|
addChart: null,
|
|
4917
5334
|
addImage: null,
|
|
@@ -4940,7 +5357,8 @@ var PptxGenJS = class {
|
|
|
4940
5357
|
*/
|
|
4941
5358
|
addNewSlide = (options) => {
|
|
4942
5359
|
const nextOptions = options || {};
|
|
4943
|
-
|
|
5360
|
+
const lastSlide = this._slides[this._slides.length - 1];
|
|
5361
|
+
nextOptions.sectionTitle = this._sections.find((sect) => sect._slides.some((s) => s._slideNum === lastSlide._slideNum))?.title ?? null;
|
|
4944
5362
|
return this.addSlide(nextOptions);
|
|
4945
5363
|
};
|
|
4946
5364
|
/**
|
|
@@ -5010,16 +5428,18 @@ var PptxGenJS = class {
|
|
|
5010
5428
|
zip.folder("ppt/theme");
|
|
5011
5429
|
zip.folder("ppt/notesMasters").folder("_rels");
|
|
5012
5430
|
zip.folder("ppt/notesSlides").folder("_rels");
|
|
5013
|
-
|
|
5014
|
-
zip.file("
|
|
5431
|
+
const hasCustomProps = this._customProperties.length > 0;
|
|
5432
|
+
zip.file("[Content_Types].xml", makeXmlContTypes(this._slides, this._slideLayouts, this._masterSlide, hasCustomProps));
|
|
5433
|
+
zip.file("_rels/.rels", makeXmlRootRels(hasCustomProps));
|
|
5015
5434
|
zip.file("docProps/app.xml", makeXmlApp(this._slides, this.company));
|
|
5016
5435
|
zip.file("docProps/core.xml", makeXmlCore(this.title, this.subject, this.author, this.revision));
|
|
5436
|
+
if (hasCustomProps) zip.file("docProps/custom.xml", makeXmlCustomProperties(this._customProperties));
|
|
5017
5437
|
zip.file("ppt/_rels/presentation.xml.rels", makeXmlPresentationRels(this._slides));
|
|
5018
5438
|
zip.file("ppt/theme/theme1.xml", makeXmlTheme(this.internalPresentation));
|
|
5019
5439
|
zip.file("ppt/theme/theme2.xml", makeXmlTheme(this.internalPresentation));
|
|
5020
5440
|
zip.file("ppt/presentation.xml", makeXmlPresentation(this.internalPresentation));
|
|
5021
5441
|
zip.file("ppt/presProps.xml", makeXmlPresProps());
|
|
5022
|
-
zip.file("ppt/tableStyles.xml", makeXmlTableStyles());
|
|
5442
|
+
zip.file("ppt/tableStyles.xml", makeXmlTableStyles(this._tableStyles));
|
|
5023
5443
|
zip.file("ppt/viewProps.xml", makeXmlViewProps());
|
|
5024
5444
|
this._slideLayouts.forEach((layout, idx) => {
|
|
5025
5445
|
zip.file(`ppt/slideLayouts/slideLayout${idx + 1}.xml`, makeXmlLayout(layout));
|
|
@@ -5099,6 +5519,19 @@ var PptxGenJS = class {
|
|
|
5099
5519
|
return await this._runtime.writeFile(fileName, data);
|
|
5100
5520
|
}
|
|
5101
5521
|
/**
|
|
5522
|
+
* Set a custom document property stored in `docProps/custom.xml`.
|
|
5523
|
+
* Calling with the same name replaces the existing value.
|
|
5524
|
+
* @param name - property name
|
|
5525
|
+
* @param value - string, integer/float number, boolean, or Date
|
|
5526
|
+
*/
|
|
5527
|
+
setCustomProperty(name, value) {
|
|
5528
|
+
this._customProperties = this._customProperties.filter((p) => p.name !== name);
|
|
5529
|
+
this._customProperties.push({
|
|
5530
|
+
name,
|
|
5531
|
+
value
|
|
5532
|
+
});
|
|
5533
|
+
}
|
|
5534
|
+
/**
|
|
5102
5535
|
* Add a new Section to Presentation
|
|
5103
5536
|
* @param {ISectionProps} section - section properties
|
|
5104
5537
|
* @example pptx.addSection({ title:'Charts' });
|
|
@@ -5207,6 +5640,31 @@ var PptxGenJS = class {
|
|
|
5207
5640
|
if (newLayout._slideNumberProps && !this._masterSlide._slideNumberProps) this._masterSlide._slideNumberProps = newLayout._slideNumberProps;
|
|
5208
5641
|
}
|
|
5209
5642
|
/**
|
|
5643
|
+
* Register a reusable custom table style and return its GUID.
|
|
5644
|
+
* The style is written to `ppt/tableStyles.xml` and is editable in PowerPoint's
|
|
5645
|
+
* Table Styles gallery. Pass the returned GUID as `TableProps.tableStyle`, and use
|
|
5646
|
+
* the `has*` flags (`hasHeader`, `hasBandedRows`, …) to activate the matching regions.
|
|
5647
|
+
* @param {TableStyleProps} props - custom table style definition (requires `name`)
|
|
5648
|
+
* @returns {string} braced GUID to use as `tableStyle`
|
|
5649
|
+
* @example
|
|
5650
|
+
* const brand = pptx.defineTableStyle({
|
|
5651
|
+
* name: 'Brand Banded',
|
|
5652
|
+
* firstRow: { fill:'1A2B3C', color:'FFFFFF', bold:true },
|
|
5653
|
+
* band1H: { fill:'EAF1F8' },
|
|
5654
|
+
* })
|
|
5655
|
+
* slide.addTable(rows, { tableStyle: brand, hasHeader:true, hasBandedRows:true })
|
|
5656
|
+
*/
|
|
5657
|
+
defineTableStyle(props) {
|
|
5658
|
+
if (!props || typeof props !== "object") throw new Error("defineTableStyle() requires a `{ name, ... }` object argument");
|
|
5659
|
+
if (!props.name || typeof props.name !== "string") throw new Error("defineTableStyle() requires a non-empty `name`");
|
|
5660
|
+
const guid = `{${getUuid("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx").toUpperCase()}}`;
|
|
5661
|
+
this._tableStyles.push({
|
|
5662
|
+
guid,
|
|
5663
|
+
def: props
|
|
5664
|
+
});
|
|
5665
|
+
return guid;
|
|
5666
|
+
}
|
|
5667
|
+
/**
|
|
5210
5668
|
* Reproduces an HTML table as a PowerPoint table - including column widths, style, etc. - creates 1 or more slides as needed
|
|
5211
5669
|
* @param {string} eleId - table HTML element ID
|
|
5212
5670
|
* @param {TableToSlidesProps} options - generation options
|
|
@@ -5218,4 +5676,4 @@ var PptxGenJS = class {
|
|
|
5218
5676
|
//#endregion
|
|
5219
5677
|
export { PptxGenJS as t };
|
|
5220
5678
|
|
|
5221
|
-
//# sourceMappingURL=pptxgen
|
|
5679
|
+
//# sourceMappingURL=pptxgen--5RWzhb4.js.map
|