@shbernal/ts-pptx 3.1.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -20
- package/dist/{autopage-QQyfRtoK.js → autopage-D1sqK6j7.js} +16 -15
- package/dist/{autopage-QQyfRtoK.js.map → autopage-D1sqK6j7.js.map} +1 -1
- package/dist/browser.d.ts +6 -6
- package/dist/browser.js +5 -6
- package/dist/browser.js.map +1 -1
- package/dist/{diagnostics-PMINsVP6.d.ts → diagnostics-B2yWpcjB.d.ts} +31 -14
- package/dist/{diagnostics-PMINsVP6.d.ts.map → diagnostics-B2yWpcjB.d.ts.map} +1 -1
- package/dist/{diagnostics-DYQC7xLV.js → diagnostics-H1QzgRSw.js} +0 -0
- package/dist/{diagnostics-DYQC7xLV.js.map → diagnostics-H1QzgRSw.js.map} +1 -1
- package/dist/{enums-CoXnxiCI.d.ts → enums-CvRYniUA.d.ts} +13 -3
- package/dist/{enums-CoXnxiCI.d.ts.map → enums-CvRYniUA.d.ts.map} +1 -1
- package/dist/{errors-BeUEkNWL.d.ts → errors-fB1KDJKQ.d.ts} +5 -5
- package/dist/{errors-BeUEkNWL.d.ts.map → errors-fB1KDJKQ.d.ts.map} +1 -1
- package/dist/{fit-DhMbQG5O.js → fit-CYJ1jkQI.js} +0 -0
- package/dist/fit-CYJ1jkQI.js.map +1 -0
- package/dist/{html-dom-DajBuobe.js → html-dom-CzewEdE1.js} +4 -5
- package/dist/{html-dom-DajBuobe.js.map → html-dom-CzewEdE1.js.map} +1 -1
- package/dist/html.d.ts +3 -3
- package/dist/html.js +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +1 -1
- package/dist/inspect.js +4 -4
- package/dist/math.d.ts +1 -1
- package/dist/measure.d.ts +96 -6
- package/dist/measure.d.ts.map +1 -1
- package/dist/measure.js +2 -2
- package/dist/node.d.ts +6 -6
- package/dist/node.js +4 -5
- package/dist/node.js.map +1 -1
- package/dist/notes-SCvpJz0l.js +1646 -0
- package/dist/notes-SCvpJz0l.js.map +1 -0
- package/dist/{pres-BgvxhQ_m.d.ts → pres-Cb-1xDne.d.ts} +4 -4
- package/dist/{pres-BgvxhQ_m.d.ts.map → pres-Cb-1xDne.d.ts.map} +1 -1
- package/dist/{presentation-BP1B8PCF.js → presentation-DeKTJGHf.js} +1096 -440
- package/dist/presentation-DeKTJGHf.js.map +1 -0
- package/dist/{presentation-DyIRDKkp.d.ts → presentation-types-B50aOUFI.d.ts} +804 -39
- package/dist/presentation-types-B50aOUFI.d.ts.map +1 -0
- package/dist/read.d.ts +4 -5
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +2 -2
- package/dist/script.d.ts +32 -4
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +0 -0
- package/dist/script.js.map +1 -1
- package/dist/{shapes-DMThLsZN.js → shapes-BXVgsk0F.js} +81 -63
- package/dist/shapes-BXVgsk0F.js.map +1 -0
- package/dist/{slide-BRAtT8Dl.d.ts → slide-DWw9UoI6.d.ts} +130 -11
- package/dist/slide-DWw9UoI6.d.ts.map +1 -0
- package/dist/{st-enums-evQG2A7Z.js → st-enums-bVnezkMJ.js} +33 -12
- package/dist/{st-enums-evQG2A7Z.js.map → st-enums-bVnezkMJ.js.map} +1 -1
- package/dist/{text-B6PbMFih.js → text-uM-zGton.js} +242 -1611
- package/dist/text-uM-zGton.js.map +1 -0
- package/dist/{units-internal-CR8s8YQa.js → units-internal-CGf4VrXy.js} +156 -4
- package/dist/units-internal-CGf4VrXy.js.map +1 -0
- package/dist/zip.d.ts +2 -2
- package/package.json +40 -28
- package/skills/ts-pptx-upstream/SKILL.md +107 -14
- package/dist/embedded-fonts-MaynAHa9.js +0 -94
- package/dist/embedded-fonts-MaynAHa9.js.map +0 -1
- package/dist/fit-DhMbQG5O.js.map +0 -1
- package/dist/presentation-BP1B8PCF.js.map +0 -1
- package/dist/presentation-DyIRDKkp.d.ts.map +0 -1
- package/dist/presentation-types-Dj4riuDs.d.ts +0 -538
- package/dist/presentation-types-Dj4riuDs.d.ts.map +0 -1
- package/dist/shapes-DMThLsZN.js.map +0 -1
- package/dist/slide-BRAtT8Dl.d.ts.map +0 -1
- package/dist/text-B6PbMFih.js.map +0 -1
- package/dist/units-C7QM1KgH.js +0 -144
- package/dist/units-C7QM1KgH.js.map +0 -1
- package/dist/units-internal-CR8s8YQa.js.map +0 -1
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { n as warn, r as warnOnce } from "./diagnostics-
|
|
1
|
+
import { n as warn, r as warnOnce } from "./diagnostics-H1QzgRSw.js";
|
|
2
2
|
import { n as InvalidOptionError, o as UnsupportedFeatureError, r as MediaError, t as InternalError } from "./errors-Bvln0H-7.js";
|
|
3
|
-
import { a as
|
|
4
|
-
import {
|
|
5
|
-
import { E as svgMarkupToDataUri, S as getImageSizeFromBase64, T as decodeBase64ToBytes, a as PRESET_MATERIALS, g as PACKAGE_REL_NS, h as OFFICE_REL, i as PRESET_LINE_DASHES, n as LIGHT_RIGS, r as LIGHT_RIG_DIRECTIONS, s as TEXT_HORZ_OVERFLOW, t as BEVEL_PRESETS, u as checkEnumOrWarn, x as fitSrcRectPercents } from "./st-enums-
|
|
6
|
-
import { t as getSlidesForTableRows } from "./autopage-
|
|
7
|
-
import { _ as parseFontMetrics, m as FontMetricsRegistry, n as measureText, r as computeTableLayout, t as applyMeasuredFit } from "./fit-
|
|
8
|
-
import { a as flattenEmbeddedFaces, i as FONT_REL_TYPE, n as FONT_DATA_CONTENT_TYPE, o as serializeEmbeddedFontLst, r as FONT_DATA_EXTENSION, t as EMBEDDED_FONT_SLOTS } from "./embedded-fonts-MaynAHa9.js";
|
|
3
|
+
import { $ as connectorPresetFor, C as DEF_PRES_LAYOUT_NAME, E as DEF_SLIDE_MARGIN_IN, F as PIECHART_COLORS, G as PlaceholderType, I as REGEX_HEX_COLOR, K as SchemeColor, L as SLDNUMFLDID, M as LAYOUT_IDX_SERIES_BASE, N as LETTERS, O as DEF_TEXT_SHADOW, Q as asChartType, R as XML_DECL, S as DEF_PRES_LAYOUT, T as DEF_SHAPE_SHADOW, U as ChartType, Z as VALID_SHAPE_PRESETS, _ as DEF_CELL_BORDER, _t as pixelsToEmu, a as lineWidthToEmu, at as EMU_PER_POINT, b as DEF_CHART_GRIDLINE, c as resolveTableColWidthsEmu, ct as PERCENT_SCALE, d as AXIS_ID_CATEGORY_PRIMARY, et as isChartExType, f as AXIS_ID_CATEGORY_SECONDARY, ft as emuToInches, g as BARCHART_COLORS, h as AXIS_ID_VALUE_SECONDARY, ht as inchesToEmu, i as inch2Emu, it as EMU_PER_INCH, k as IMG_BROKEN, m as AXIS_ID_VALUE_PRIMARY, n as convertRotationDegrees, o as marginToEmu, ot as FIXED_PCT_PER_PERCENT, p as AXIS_ID_SERIES_PRIMARY, r as getSmartParseNumber, t as convertArcAngle, tt as isChartType, u as valToPts, ut as STANDARD_LAYOUTS, v as DEF_CELL_MARGIN_IN, x as DEF_FONT_COLOR, y as DEF_CHART_BORDER, yt as ptToHundredths } from "./units-internal-CGf4VrXy.js";
|
|
4
|
+
import { A as getNewRelId, C as createColorElement, D as encodeXmlAttrValue, E as voidEl, M as isHyperlinkRel, N as validateObjectName, O as encodeXmlEntities, S as createShadowEffectLst, T as raw, _ as FONT_DATA_EXTENSION, a as makeXmlNotesSlideRel, b as serializeEmbeddedFontLst, c as genXmlParagraphProperties, d as clampFontSizeSz, f as genXmlColorSelection, g as FONT_DATA_CONTENT_TYPE, h as EMBEDDED_FONT_SLOTS, i as makeXmlNotesSlide, j as getUuid, k as getDuplicateObjectNames, l as groupRunsIntoLines, m as genXmlPatternFill, n as makeXmlNotesMaster, p as genXmlGradientFill, r as makeXmlNotesMasterRel, s as genXmlNormAutofit, t as buildNotesSlideRels, u as renderTextParagraphsXml, v as FONT_REL_TYPE, w as el, x as correctShadowOptions, y as flattenEmbeddedFaces } from "./notes-SCvpJz0l.js";
|
|
5
|
+
import { E as svgMarkupToDataUri, S as getImageSizeFromBase64, T as decodeBase64ToBytes, a as PRESET_MATERIALS, g as PACKAGE_REL_NS, h as OFFICE_REL, i as PRESET_LINE_DASHES, n as LIGHT_RIGS, r as LIGHT_RIG_DIRECTIONS, s as TEXT_HORZ_OVERFLOW, t as BEVEL_PRESETS, u as checkEnumOrWarn, x as fitSrcRectPercents } from "./st-enums-bVnezkMJ.js";
|
|
6
|
+
import { t as getSlidesForTableRows } from "./autopage-D1sqK6j7.js";
|
|
7
|
+
import { _ as parseFontMetrics, m as FontMetricsRegistry, n as measureText, r as computeTableLayout, t as applyMeasuredFit, v as isFontCollection } from "./fit-CYJ1jkQI.js";
|
|
9
8
|
import { ZipWriter } from "./zip.js";
|
|
10
9
|
//#region src/media/content-type.ts
|
|
11
10
|
/**
|
|
@@ -164,400 +163,6 @@ function addBackgroundDefinition(props, target) {
|
|
|
164
163
|
}
|
|
165
164
|
}
|
|
166
165
|
//#endregion
|
|
167
|
-
//#region src/gen/utils.ts
|
|
168
|
-
/**
|
|
169
|
-
* ts-pptx: shared generator helpers.
|
|
170
|
-
*
|
|
171
|
-
* The small cross-cutting pieces the OOXML writers all need and that belong to
|
|
172
|
-
* no single part:
|
|
173
|
-
* - XML text encodeXmlEntities
|
|
174
|
-
* - Identifiers & naming getUuid, validateObjectName, getDuplicateObjectNames
|
|
175
|
-
* - Slide relationships getNewRelId, isHyperlinkRel
|
|
176
|
-
*
|
|
177
|
-
* DrawingML fragment builders moved to `gen/drawingml/{color,effect,fill,line}.ts`;
|
|
178
|
-
* unit conversion to `units-internal.ts` (over the public primitives in `units.ts`);
|
|
179
|
-
* base64/image-header decoding and media content types to `media/`.
|
|
180
|
-
*/
|
|
181
|
-
/**
|
|
182
|
-
* Basic UUID Generator Adapted
|
|
183
|
-
* @link https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript#answer-2117523
|
|
184
|
-
* @param {string} uuidFormat - UUID format
|
|
185
|
-
* @returns {string} UUID
|
|
186
|
-
*/
|
|
187
|
-
function getUuid(uuidFormat) {
|
|
188
|
-
return uuidFormat.replace(/[xy]/g, function(c) {
|
|
189
|
-
const r = Math.random() * 16 | 0;
|
|
190
|
-
return (c === "x" ? r : r & 3 | 8).toString(16);
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* Replace special XML characters with HTML-encoded strings.
|
|
195
|
-
*
|
|
196
|
-
* ELEMENT TEXT ONLY. A literal tab, carriage return or line feed is left alone here because in
|
|
197
|
-
* character data it *is* the content (`<a:t>` line breaks depend on it). Inside an attribute value
|
|
198
|
-
* the same three characters are destroyed by the parser rather than preserved — see
|
|
199
|
-
* {@link encodeXmlAttrValue}, which every attribute-emitting path must use instead.
|
|
200
|
-
* @param {string | number} xml - value to encode (numbers are stringified, as callers pass counts/sizes)
|
|
201
|
-
* @returns {string} escaped XML
|
|
202
|
-
*/
|
|
203
|
-
function encodeXmlEntities(xml) {
|
|
204
|
-
if (typeof xml === "undefined" || xml == null) return "";
|
|
205
|
-
const cc = String.fromCharCode;
|
|
206
|
-
const illegalXmlCharsRe = new RegExp(`[${cc(0)}-${cc(8)}${cc(11)}${cc(12)}${cc(14)}-${cc(31)}${cc(127)}]`, "g");
|
|
207
|
-
return xml.toString().replace(illegalXmlCharsRe, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
208
|
-
}
|
|
209
|
-
/**
|
|
210
|
-
* Escape a value destined for an XML **attribute**.
|
|
211
|
-
*
|
|
212
|
-
* Everything {@link encodeXmlEntities} does, plus the three whitespace characters that survive in
|
|
213
|
-
* element text but not in an attribute: XML 1.0 section 3.3.3 requires a parser to normalise a
|
|
214
|
-
* literal tab, carriage return or line feed inside an attribute value to a single space *before any
|
|
215
|
-
* consumer sees it*. Carrying one across therefore requires a character reference, so a caller's
|
|
216
|
-
* `objectName: 'Abschnitts-\nuberschrift'` reads back with its line break rather than a space.
|
|
217
|
-
*
|
|
218
|
-
* Deliberately a separate function rather than a widening of `encodeXmlEntities`: that helper also
|
|
219
|
-
* escapes element text, where a raw newline is meaningful content emitted as-is, and escaping it
|
|
220
|
-
* there would change bytes across every text-bearing part in the package.
|
|
221
|
-
* @param {string | number} xml - value to encode (numbers are stringified, as callers pass ids/sizes)
|
|
222
|
-
* @returns {string} escaped XML, safe to place between attribute quotes
|
|
223
|
-
*/
|
|
224
|
-
function encodeXmlAttrValue(xml) {
|
|
225
|
-
return encodeXmlEntities(xml).replace(/\t/g, "	").replace(/\n/g, " ").replace(/\r/g, " ");
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Practical maximum length for a `p:cNvPr` object name. PowerPoint does not
|
|
229
|
-
* enforce a hard spec limit, but very long names are a strong signal of a bug
|
|
230
|
-
* and are unwieldy in the Selection Pane.
|
|
231
|
-
*/
|
|
232
|
-
const MAX_OBJECT_NAME_LENGTH = 255;
|
|
233
|
-
/**
|
|
234
|
-
* Validate a user-supplied object name and warn (does not throw) when the value
|
|
235
|
-
* cannot be preserved as a stable PowerPoint Selection Pane identity. This keeps
|
|
236
|
-
* semantic-identity bugs visible at generation time without breaking existing
|
|
237
|
-
* decks that pass loose names.
|
|
238
|
-
* - Empty/whitespace-only names provide no usable identity.
|
|
239
|
-
* - Control characters are stripped by `encodeXmlEntities`, silently changing
|
|
240
|
-
* the stored name.
|
|
241
|
-
* - Excessively long names may not round-trip through PowerPoint/consumers.
|
|
242
|
-
* @param {string} name - the raw (pre-encoding) object name
|
|
243
|
-
* @param {string} kind - object kind for the warning message (e.g. 'text')
|
|
244
|
-
* @returns {string} the name unchanged (validation only)
|
|
245
|
-
*/
|
|
246
|
-
function validateObjectName(name, kind) {
|
|
247
|
-
if (typeof name !== "string") return name;
|
|
248
|
-
if (name.trim().length === 0) {
|
|
249
|
-
warn("object-name/empty", `${kind} objectName is empty or whitespace-only; it will not provide a stable Selection Pane identity.`);
|
|
250
|
-
return name;
|
|
251
|
-
}
|
|
252
|
-
const cc = String.fromCharCode;
|
|
253
|
-
if (new RegExp(`[${cc(0)}-${cc(8)}${cc(11)}${cc(12)}${cc(14)}-${cc(31)}${cc(127)}]`).test(name)) warn("object-name/control-characters", `${kind} objectName "${name}" contains control characters that will be stripped, changing the stored name.`);
|
|
254
|
-
if (name.length > MAX_OBJECT_NAME_LENGTH) warn("object-name/too-long", `${kind} objectName exceeds ${MAX_OBJECT_NAME_LENGTH} characters and may not be preserved by PowerPoint.`);
|
|
255
|
-
return name;
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* Return object names that appear more than once in the given list. Used to warn
|
|
259
|
-
* when duplicate Selection Pane identities would be emitted on a single slide,
|
|
260
|
-
* which breaks consumers (e.g. semantic manifests) that rely on unique names.
|
|
261
|
-
* @param {string[]} names - object names emitted on one slide
|
|
262
|
-
* @returns {string[]} the duplicated names (each listed once)
|
|
263
|
-
*/
|
|
264
|
-
function getDuplicateObjectNames(names) {
|
|
265
|
-
const seen = /* @__PURE__ */ new Set();
|
|
266
|
-
const dupes = /* @__PURE__ */ new Set();
|
|
267
|
-
names.forEach((name) => {
|
|
268
|
-
if (typeof name !== "string" || name.length === 0) return;
|
|
269
|
-
if (seen.has(name)) dupes.add(name);
|
|
270
|
-
else seen.add(name);
|
|
271
|
-
});
|
|
272
|
-
return Array.from(dupes);
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Get a new rel ID (rId) for charts, media, etc.
|
|
276
|
-
*
|
|
277
|
-
* Counting is the normal case: a slide's rels are minted in order, so one past the
|
|
278
|
-
* total is free. It is not enough on its own, because a rel can arrive on a slide
|
|
279
|
-
* carrying an id minted somewhere else — auto-paging re-registers a repeated header
|
|
280
|
-
* row's hyperlink on each overflow slide under the id stamped on the shared
|
|
281
|
-
* hyperlink object (`gen/define/hyperlinks.ts`). That id is then held but not
|
|
282
|
-
* counted-to, so the next mint could hand out the same number and the part would
|
|
283
|
-
* declare two `Relationship` elements sharing an `Id` — invalid OPC, and PowerPoint
|
|
284
|
-
* resolves such a reference to whichever comes first. Hence the scan: start where
|
|
285
|
-
* the count says, then step over anything the slide already holds.
|
|
286
|
-
* @param {PresSlideInternal} target - the slide to use
|
|
287
|
-
* @returns {number} the lowest free rId at or above the current rel count plus 1
|
|
288
|
-
*/
|
|
289
|
-
function getNewRelId(target) {
|
|
290
|
-
const held = /* @__PURE__ */ new Set();
|
|
291
|
-
target._rels.forEach((rel) => held.add(rel.rId));
|
|
292
|
-
target._relsChart.forEach((rel) => held.add(rel.rId));
|
|
293
|
-
target._relsMedia.forEach((rel) => held.add(rel.rId));
|
|
294
|
-
let rId = target._rels.length + target._relsChart.length + target._relsMedia.length + 1;
|
|
295
|
-
while (held.has(rId)) rId++;
|
|
296
|
-
return rId;
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* Whether a slide relationship is a hyperlink (external URL or internal slide
|
|
300
|
-
* link). The relationship `type` is stringly-typed (`'hyperlink'`, `'online'`,
|
|
301
|
-
* mixed-case variants), so this centralizes the case-insensitive predicate that
|
|
302
|
-
* was duplicated across the slide-rels writer (`gen/slide/slide.ts`) and the inspect path
|
|
303
|
-
* (presentation.ts). For an internal slide-to-slide link, `rel.data === 'slide'` and
|
|
304
|
-
* `rel.Target` is the 1-based target slide number.
|
|
305
|
-
* @param {{ type: string }} rel - a slide relationship
|
|
306
|
-
* @returns {boolean} true if the rel is any kind of hyperlink
|
|
307
|
-
*/
|
|
308
|
-
function isHyperlinkRel(rel) {
|
|
309
|
-
return rel.type.toLowerCase().includes("hyperlink");
|
|
310
|
-
}
|
|
311
|
-
//#endregion
|
|
312
|
-
//#region src/gen/oxml/el.ts
|
|
313
|
-
/**
|
|
314
|
-
* ts-pptx: XML element builder (write-side substrate)
|
|
315
|
-
*
|
|
316
|
-
* The write path historically concatenated template strings and called
|
|
317
|
-
* `encodeXmlEntities` by hand at every interpolation — the source of escaping,
|
|
318
|
-
* attribute-order and child-sequence bugs. This builder centralizes escaping
|
|
319
|
-
* while reproducing today's exact byte layout, so a migration onto it can be
|
|
320
|
-
* gated on strict byte-identity (`pnpm run byte-identity:check`) rather than on
|
|
321
|
-
* looser schema equivalence.
|
|
322
|
-
*
|
|
323
|
-
* Mirrors `src/read/oxml/dom.ts` on the write side.
|
|
324
|
-
*
|
|
325
|
-
* Two rules make byte-identity achievable:
|
|
326
|
-
*
|
|
327
|
-
* 1. Self-closing is decided by ARITY, never by child value. `el()` always emits
|
|
328
|
-
* a paired tag; `voidEl()` always self-closes. This matters because
|
|
329
|
-
* `encodeXmlEntities(undefined)` returns `''`, so a value-based rule would
|
|
330
|
-
* turn today's `<dc:title></dc:title>` into `<dc:title/>` — a silent byte
|
|
331
|
-
* regression on every optional-text element in the tree.
|
|
332
|
-
*
|
|
333
|
-
* Escaping is split to match: attribute values go through `encodeXmlAttrValue`
|
|
334
|
-
* (which adds the `	`/` `/` ` character references an XML parser
|
|
335
|
-
* would otherwise normalise to a space), text children through
|
|
336
|
-
* `encodeXmlEntities`, where those same characters are content.
|
|
337
|
-
*
|
|
338
|
-
* 2. Whitespace is explicit, per element, via `fmt`. Most emitted parts are flat
|
|
339
|
-
* (no `fmt` needed at all); the pretty-printed ones carry indentation that is
|
|
340
|
-
* not always depth-regular, so it is described rather than derived. Quirks
|
|
341
|
-
* like a misindented closing tag stay visible in the call site instead of
|
|
342
|
-
* being hidden inside a template literal.
|
|
343
|
-
*/
|
|
344
|
-
/** Wrap already-serialized XML so it is interpolated verbatim. */
|
|
345
|
-
function raw(xml) {
|
|
346
|
-
return { raw: xml };
|
|
347
|
-
}
|
|
348
|
-
function isRaw(child) {
|
|
349
|
-
return typeof child === "object" && child !== null && typeof child.raw === "string";
|
|
350
|
-
}
|
|
351
|
-
function openTag(name, attrs, fmt) {
|
|
352
|
-
let out = (fmt?.openPrefix ?? "") + "<" + name;
|
|
353
|
-
for (const [key, value] of Object.entries(attrs ?? {})) {
|
|
354
|
-
if (value === void 0 || value === null) continue;
|
|
355
|
-
out += " " + key + "=\"" + encodeXmlAttrValue(value) + "\"";
|
|
356
|
-
}
|
|
357
|
-
return out;
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* Paired element: `<name …>children</name>` — emitted even when `children` is
|
|
361
|
-
* empty or `undefined`. Text children are escaped; `raw()` children are not.
|
|
362
|
-
*/
|
|
363
|
-
function el(name, attrs, children, fmt) {
|
|
364
|
-
let out = openTag(name, attrs, fmt) + ">";
|
|
365
|
-
const childPrefix = fmt?.childPrefix ?? "";
|
|
366
|
-
for (const child of Array.isArray(children) ? children : [children]) {
|
|
367
|
-
if (child === void 0 || child === null) continue;
|
|
368
|
-
out += childPrefix + (isRaw(child) ? child.raw : encodeXmlEntities(child));
|
|
369
|
-
}
|
|
370
|
-
return out + (fmt?.closePrefix ?? "") + "</" + name + ">";
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* Self-closing element: `<name …/>`. `fmt.closePrefix` goes before the `/>` — a
|
|
374
|
-
* handful of emitters write `<a:avLst />` with a space there, and that space is
|
|
375
|
-
* byte-significant like any other.
|
|
376
|
-
*/
|
|
377
|
-
function voidEl(name, attrs, fmt) {
|
|
378
|
-
return openTag(name, attrs, fmt) + (fmt?.closePrefix ?? "") + "/>";
|
|
379
|
-
}
|
|
380
|
-
//#endregion
|
|
381
|
-
//#region src/gen/drawingml/color.ts
|
|
382
|
-
/**
|
|
383
|
-
* ts-pptx: DrawingML color elements
|
|
384
|
-
*
|
|
385
|
-
* Emit the bare `<a:srgbClr>` / `<a:schemeClr>` color element that every other
|
|
386
|
-
* color context builds on (solid fills, gradient stops, effect alphas, line
|
|
387
|
-
* fills, highlights, patterns).
|
|
388
|
-
*
|
|
389
|
-
* The RGB->hex helpers this module used to carry now live in
|
|
390
|
-
* `gen/table/html-dom.ts`, their only caller: they are reachable exclusively from
|
|
391
|
-
* the browser-only `tableToSlides` path, so keeping them here made them permanent
|
|
392
|
-
* dead weight in the Node chunk's coverage report (33% functions on a file that is
|
|
393
|
-
* otherwise fully exercised) while html-dom.ts is coverage-excluded wholesale.
|
|
394
|
-
*/
|
|
395
|
-
/**
|
|
396
|
-
* Opening delimiter of an `<a:alpha>` child, for detecting one a caller already
|
|
397
|
-
* supplied. A prefix rather than a whole element: the value is the caller's, and
|
|
398
|
-
* this asks only whether the element is present.
|
|
399
|
-
*/
|
|
400
|
-
const ALPHA_TAG = "<a:alpha";
|
|
401
|
-
/**
|
|
402
|
-
* Emit a bare DrawingML color element — either `<a:schemeClr>` (scheme color) or `<a:srgbClr>`
|
|
403
|
-
* (hex RGB). This is a low-level primitive: it is the shared building block for every color
|
|
404
|
-
* context (solid fills, gradient stops, `<a:alpha>` on shadows/glow, line fills, highlight,
|
|
405
|
-
* underline, patterns, …), so it is intentionally NOT limited to solid fills and cannot be
|
|
406
|
-
* folded into `genXmlColorSelection`.
|
|
407
|
-
*
|
|
408
|
-
* When you specifically want a *solid fill*, prefer `genXmlColorSelection` (`fill.ts`), which
|
|
409
|
-
* wraps this in `<a:solidFill>…</a:solidFill>` and also handles `alpha`/`transparency` and the
|
|
410
|
-
* gradient/pattern/image fill types — reach for `createColorElement` directly only when you
|
|
411
|
-
* need the raw color element (e.g. inside `<a:ln>`, `<a:gs>`, an effect, or a highlight).
|
|
412
|
-
* @param {string|SCHEME_COLORS} colorStr - hex RGB (e.g. "FFFF00") or a scheme color constant (e.g. SchemeColor.ACCENT1)
|
|
413
|
-
* @param {string} [innerElements] - additional elements that adjust the color, nested inside the color element
|
|
414
|
-
* @returns {string} XML string
|
|
415
|
-
*/
|
|
416
|
-
function createColorElement(colorStr, innerElements) {
|
|
417
|
-
if (typeof colorStr !== "string") {
|
|
418
|
-
warn("color/not-a-string", `createColorElement: expected a string color value, got ${typeof colorStr}. "${DEF_FONT_COLOR}" used instead.`);
|
|
419
|
-
colorStr = DEF_FONT_COLOR;
|
|
420
|
-
}
|
|
421
|
-
let colorVal = (colorStr || "").replace("#", "");
|
|
422
|
-
if (/^[0-9a-fA-F]{8}$/.test(colorVal)) {
|
|
423
|
-
if (!innerElements?.includes(ALPHA_TAG)) {
|
|
424
|
-
const alphaHex = colorVal.slice(6, 8);
|
|
425
|
-
innerElements = voidEl("a:alpha", { val: Math.round(parseInt(alphaHex, 16) / 255 * PERCENT_SCALE) }) + (innerElements || "");
|
|
426
|
-
}
|
|
427
|
-
colorVal = colorVal.slice(0, 6);
|
|
428
|
-
}
|
|
429
|
-
if (!REGEX_HEX_COLOR.test(colorVal) && !Object.values(SchemeColor).includes(colorVal)) {
|
|
430
|
-
warn("color/invalid-value", `"${colorVal}" is not a valid scheme color or hex RGB! "${DEF_FONT_COLOR}" used instead. Only provide 6-digit RGB or 'SchemeColor' values!`);
|
|
431
|
-
colorVal = DEF_FONT_COLOR;
|
|
432
|
-
}
|
|
433
|
-
const isHex = REGEX_HEX_COLOR.test(colorVal);
|
|
434
|
-
const name = isHex ? "a:srgbClr" : "a:schemeClr";
|
|
435
|
-
const attrs = { val: isHex ? colorVal.toUpperCase() : colorVal };
|
|
436
|
-
return innerElements ? el(name, attrs, raw(innerElements)) : voidEl(name, attrs);
|
|
437
|
-
}
|
|
438
|
-
//#endregion
|
|
439
|
-
//#region src/gen/drawingml/effect.ts
|
|
440
|
-
/**
|
|
441
|
-
* ts-pptx: DrawingML effects (glow and shadow)
|
|
442
|
-
*
|
|
443
|
-
* Emit the `<a:glow>` / `<a:outerShdw>` / `<a:innerShdw>` children of an
|
|
444
|
-
* `<a:effectLst>`, and normalize the user-facing `shadow` options into the
|
|
445
|
-
* internal shape every emit site reads.
|
|
446
|
-
* @see http://officeopenxml.com/drwSp-effects.php
|
|
447
|
-
*/
|
|
448
|
-
/**
|
|
449
|
-
* Creates `a:glow` element
|
|
450
|
-
* @param {TextGlowProps} options glow properties
|
|
451
|
-
* @param {TextGlowProps} defaults defaults for unspecified properties in `opts`
|
|
452
|
-
* @see http://officeopenxml.com/drwSp-effects.php
|
|
453
|
-
* { size: 8, color: 'FFFFFF', opacity: 0.75 };
|
|
454
|
-
*/
|
|
455
|
-
function createGlowElement(options, defaults) {
|
|
456
|
-
const opts = {
|
|
457
|
-
...defaults,
|
|
458
|
-
...options
|
|
459
|
-
};
|
|
460
|
-
const size = Math.round(opts.size * EMU_PER_POINT);
|
|
461
|
-
const color = opts.color || "000000";
|
|
462
|
-
const opacity = opacityToAlpha(opts.opacity ?? 0);
|
|
463
|
-
return el("a:glow", { rad: size }, raw(createColorElement(color, alpha(opacity))));
|
|
464
|
-
}
|
|
465
|
-
/** The `<a:alpha>` child both effects hang off their color element. */
|
|
466
|
-
function alpha(value) {
|
|
467
|
-
return voidEl("a:alpha", { val: value });
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Creates an `a:outerShdw`/`a:innerShdw` element for a text run, shape, image, or chart.
|
|
471
|
-
* Returns the shadow element only (no wrapping `a:effectLst`) so callers can either combine
|
|
472
|
-
* it with other effects (e.g. glow) inside one `a:effectLst`, or wrap a lone shadow via
|
|
473
|
-
* {@link createShadowEffectLst}.
|
|
474
|
-
*
|
|
475
|
-
* Colors go through {@link createColorElement}, so scheme colors (e.g. `accent1`) are honored
|
|
476
|
-
* — earlier per-site copies hardcoded `a:srgbClr` and silently emitted invalid OOXML for them.
|
|
477
|
-
* @param {ShadowPropsInternal} options shadow properties
|
|
478
|
-
* @param {ShadowPropsInternal} defaults defaults for unspecified properties in `options`
|
|
479
|
-
* @see http://officeopenxml.com/drwSp-effects.php
|
|
480
|
-
* @returns {string} XML string, or '' when type is 'none'
|
|
481
|
-
*/
|
|
482
|
-
function createShadowElement(options, defaults) {
|
|
483
|
-
const opts = {
|
|
484
|
-
...defaults,
|
|
485
|
-
...options
|
|
486
|
-
};
|
|
487
|
-
if (opts.type === "none") return "";
|
|
488
|
-
const type = opts.type || "outer";
|
|
489
|
-
const blur = valToPts(opts.blur ?? 0);
|
|
490
|
-
const offset = valToPts(opts.offset ?? 0);
|
|
491
|
-
const angle = Math.round((opts.angle ?? 0) * ANGLE_UNITS_PER_DEGREE);
|
|
492
|
-
const opacity = Math.round((opts._alpha ?? .75) * PERCENT_SCALE);
|
|
493
|
-
const color = opts.color || "000000";
|
|
494
|
-
const attrs = {
|
|
495
|
-
...type === "outer" ? {
|
|
496
|
-
sx: 1e5,
|
|
497
|
-
sy: 1e5,
|
|
498
|
-
kx: 0,
|
|
499
|
-
ky: 0,
|
|
500
|
-
algn: "bl",
|
|
501
|
-
rotWithShape: opts.rotateWithShape ? 1 : 0
|
|
502
|
-
} : {},
|
|
503
|
-
blurRad: blur,
|
|
504
|
-
dist: offset,
|
|
505
|
-
dir: angle
|
|
506
|
-
};
|
|
507
|
-
return el(`a:${type}Shdw`, attrs, raw(createColorElement(color, alpha(opacity))));
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Wraps a lone shadow in the `a:effectLst` that CT_ShapeProperties (shapes/images) and chart
|
|
511
|
-
* marker/data-point properties require. Returns a self-closing `<a:effectLst/>` when there is
|
|
512
|
-
* no shadow (missing/non-object options, or `type: 'none'`), matching the "no effects" element
|
|
513
|
-
* PowerPoint emits. Use this instead of {@link createShadowElement} when the shadow is the only
|
|
514
|
-
* effect; use `createShadowElement` directly when combining with other effects (e.g. glow).
|
|
515
|
-
* @param {ShadowPropsInternal} options shadow properties
|
|
516
|
-
* @param {ShadowPropsInternal} defaults defaults for unspecified properties in `options`
|
|
517
|
-
* @returns {string} `<a:effectLst>…</a:effectLst>` or `<a:effectLst/>`
|
|
518
|
-
*/
|
|
519
|
-
function createShadowEffectLst(options, defaults) {
|
|
520
|
-
if (!options || typeof options !== "object") return voidEl("a:effectLst");
|
|
521
|
-
const inner = createShadowElement(options, defaults);
|
|
522
|
-
return inner ? el("a:effectLst", null, raw(inner)) : voidEl("a:effectLst");
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
* Checks shadow options passed by user and performs corrections if needed.
|
|
526
|
-
* @param {ShadowProps} ShadowProps - shadow options
|
|
527
|
-
*/
|
|
528
|
-
function correctShadowOptions(ShadowProps) {
|
|
529
|
-
if (!ShadowProps || typeof ShadowProps !== "object") return;
|
|
530
|
-
const corrected = ShadowProps;
|
|
531
|
-
if (corrected.type !== "outer" && corrected.type !== "inner" && corrected.type !== "none") {
|
|
532
|
-
warn("shadow/invalid-type", "shadow.type options are `outer`, `inner` or `none`.");
|
|
533
|
-
corrected.type = "outer";
|
|
534
|
-
}
|
|
535
|
-
if (corrected.angle) {
|
|
536
|
-
if (isNaN(Number(corrected.angle)) || corrected.angle < 0 || corrected.angle > 359) {
|
|
537
|
-
warn("shadow/angle-out-of-range", "shadow.angle can only be 0-359");
|
|
538
|
-
corrected.angle = 270;
|
|
539
|
-
}
|
|
540
|
-
corrected.angle = Math.round(Number(corrected.angle));
|
|
541
|
-
}
|
|
542
|
-
if (corrected.transparency !== void 0) {
|
|
543
|
-
const pct = Number(corrected.transparency);
|
|
544
|
-
if (isNaN(pct) || pct < 0 || pct > 100) warn("shadow/transparency-out-of-range", "shadow.transparency can only be 0-100");
|
|
545
|
-
else corrected._alpha = 1 - pct / 100;
|
|
546
|
-
}
|
|
547
|
-
if (corrected.color) {
|
|
548
|
-
if (corrected.color.startsWith("#")) {
|
|
549
|
-
warn("shadow/color-has-hash", "shadow.color should not include hash (#) character, , e.g. \"FF0000\"");
|
|
550
|
-
corrected.color = corrected.color.replace("#", "");
|
|
551
|
-
}
|
|
552
|
-
if (/^[0-9a-fA-F]{8}$/.test(corrected.color)) {
|
|
553
|
-
const alphaHex = corrected.color.slice(6, 8);
|
|
554
|
-
if (corrected._alpha === void 0) corrected._alpha = parseInt(alphaHex, 16) / 255;
|
|
555
|
-
corrected.color = corrected.color.slice(0, 6);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
return corrected;
|
|
559
|
-
}
|
|
560
|
-
//#endregion
|
|
561
166
|
//#region src/gen/define/chart.ts
|
|
562
167
|
/**
|
|
563
168
|
* ts-pptx: Chart Definition
|
|
@@ -937,6 +542,7 @@ function addChartDefinition(target, type, data, opt) {
|
|
|
937
542
|
}
|
|
938
543
|
const options = copyChartOptions(tmpOpt && typeof tmpOpt === "object" ? tmpOpt : {});
|
|
939
544
|
const callerSetBarGapWidthPct = typeof options.barGapWidthPct === "number" && !isNaN(options.barGapWidthPct);
|
|
545
|
+
for (const name of tmpTypes ? tmpTypes.map((sub) => sub.type) : [type]) if (!isChartType(name)) throw new InvalidOptionError("chart/unknown-type", `addChart: "${String(name)}" is not a chart type. Valid types are: ${Object.values(ChartType).join(", ")}.`, { detail: { type: name } });
|
|
940
546
|
options._type = tmpTypes ?? asChartType(type);
|
|
941
547
|
options.x = typeof options.x !== "undefined" && options.x != null && !isNaN(Number(options.x)) ? options.x : 1;
|
|
942
548
|
options.y = typeof options.y !== "undefined" && options.y != null && !isNaN(Number(options.y)) ? options.y : 1;
|
|
@@ -1409,17 +1015,19 @@ function addImageDefinition(target, opt) {
|
|
|
1409
1015
|
});
|
|
1410
1016
|
newObject.imageRid = imageRelId;
|
|
1411
1017
|
}
|
|
1412
|
-
if (typeof objHyperlink === "object")
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1018
|
+
if (typeof objHyperlink === "object") {
|
|
1019
|
+
if (!objHyperlink.url && !objHyperlink.slide) throw new InvalidOptionError("hyperlink/missing-target", "addImage: `hyperlink` requires either `url` or `slide`");
|
|
1020
|
+
else {
|
|
1021
|
+
imageRelId++;
|
|
1022
|
+
target._rels.push({
|
|
1023
|
+
type: "hyperlink",
|
|
1024
|
+
data: objHyperlink.slide ? "slide" : "dummy",
|
|
1025
|
+
rId: imageRelId,
|
|
1026
|
+
Target: objHyperlink.url ? objHyperlink.url : String(objHyperlink.slide)
|
|
1027
|
+
});
|
|
1028
|
+
objHyperlink._rId = imageRelId;
|
|
1029
|
+
newObject.hyperlink = objHyperlink;
|
|
1030
|
+
}
|
|
1423
1031
|
}
|
|
1424
1032
|
target._slideObjects.push(newObject);
|
|
1425
1033
|
}
|
|
@@ -1580,10 +1188,14 @@ function addTextDefinition(target, text, opts, isPlaceholder) {
|
|
|
1580
1188
|
itemOpts._bodyProp.vert = itemOpts.textDirection ?? itemOpts.vert;
|
|
1581
1189
|
itemOpts._bodyProp.wrap = typeof itemOpts.wrap === "boolean" ? itemOpts.wrap : true;
|
|
1582
1190
|
itemOpts._bodyProp.prstTxWarp = itemOpts.textWarp;
|
|
1583
|
-
if (itemOpts.columns !== void 0)
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1191
|
+
if (itemOpts.columns !== void 0) {
|
|
1192
|
+
if (typeof itemOpts.columns !== "number" || isNaN(itemOpts.columns) || itemOpts.columns < 1 || itemOpts.columns > 16) warn("text/invalid-columns", "text `columns` must be a number 1-16 (ignoring value)");
|
|
1193
|
+
else itemOpts._bodyProp.numCol = Math.round(itemOpts.columns);
|
|
1194
|
+
}
|
|
1195
|
+
if (itemOpts.columnSpacing !== void 0) {
|
|
1196
|
+
if (typeof itemOpts.columnSpacing !== "number" || isNaN(itemOpts.columnSpacing) || itemOpts.columnSpacing < 0) warn("text/invalid-column-spacing", "text `columnSpacing` must be a number >= 0 (ignoring value)");
|
|
1197
|
+
else itemOpts._bodyProp.spcCol = valToPts(itemOpts.columnSpacing);
|
|
1198
|
+
}
|
|
1587
1199
|
if (typeof itemOpts.underline === "boolean" && itemOpts.underline === true) itemOpts.underline = { style: "sng" };
|
|
1588
1200
|
{
|
|
1589
1201
|
const align = (itemOpts.align || "").toLowerCase();
|
|
@@ -2123,6 +1735,7 @@ function addNotesDefinition(target, notes) {
|
|
|
2123
1735
|
}
|
|
2124
1736
|
//#endregion
|
|
2125
1737
|
//#region src/gen/define/ole.ts
|
|
1738
|
+
const OD$1 = "application/vnd.openxmlformats-officedocument.";
|
|
2126
1739
|
/** Rel type for an embedded OPC package (an Office file, itself a zip). */
|
|
2127
1740
|
const PACKAGE_REL = OFFICE_REL + "package";
|
|
2128
1741
|
/** Rel type for a generic OLE-server blob — a compound-file `.bin` (ECMA-376 Part 1 §15.2.10). */
|
|
@@ -2134,7 +1747,7 @@ const OLE_OBJECT_REL = OFFICE_REL + "oleObject";
|
|
|
2134
1747
|
*/
|
|
2135
1748
|
const OLE_FORMATS = {
|
|
2136
1749
|
xlsx: {
|
|
2137
|
-
contentType: "
|
|
1750
|
+
contentType: OD$1 + "spreadsheetml.sheet",
|
|
2138
1751
|
relType: PACKAGE_REL,
|
|
2139
1752
|
progId: "Excel.Sheet.12",
|
|
2140
1753
|
name: "Worksheet"
|
|
@@ -2146,7 +1759,7 @@ const OLE_FORMATS = {
|
|
|
2146
1759
|
name: "Worksheet"
|
|
2147
1760
|
},
|
|
2148
1761
|
docx: {
|
|
2149
|
-
contentType: "
|
|
1762
|
+
contentType: OD$1 + "wordprocessingml.document",
|
|
2150
1763
|
relType: PACKAGE_REL,
|
|
2151
1764
|
progId: "Word.Document.12",
|
|
2152
1765
|
name: "Document"
|
|
@@ -2158,7 +1771,7 @@ const OLE_FORMATS = {
|
|
|
2158
1771
|
name: "Document"
|
|
2159
1772
|
},
|
|
2160
1773
|
pptx: {
|
|
2161
|
-
contentType: "
|
|
1774
|
+
contentType: OD$1 + "presentationml.presentation",
|
|
2162
1775
|
relType: PACKAGE_REL,
|
|
2163
1776
|
progId: "PowerPoint.Show.12",
|
|
2164
1777
|
name: "Presentation"
|
|
@@ -2172,7 +1785,7 @@ const OLE_FORMATS = {
|
|
|
2172
1785
|
};
|
|
2173
1786
|
/** Fallback for any payload that is not one of the {@link OLE_FORMATS} Office packages. */
|
|
2174
1787
|
const BIN_FORMAT = {
|
|
2175
|
-
contentType: "
|
|
1788
|
+
contentType: OD$1 + "oleObject",
|
|
2176
1789
|
relType: OLE_OBJECT_REL,
|
|
2177
1790
|
progId: "Package",
|
|
2178
1791
|
name: "Object"
|
|
@@ -3095,137 +2708,6 @@ var SlideBuilder = class {
|
|
|
3095
2708
|
}
|
|
3096
2709
|
};
|
|
3097
2710
|
//#endregion
|
|
3098
|
-
//#region src/gen/drawingml/fill.ts
|
|
3099
|
-
/**
|
|
3100
|
-
* ts-pptx: DrawingML fills
|
|
3101
|
-
*
|
|
3102
|
-
* Emit the fill group a shape, cell, chart element, or line paint can carry:
|
|
3103
|
-
* `<a:solidFill>`, `<a:gradFill>`, `<a:pattFill>`, `<a:blipFill>`.
|
|
3104
|
-
* {@link genXmlColorSelection} is the dispatch every caller should reach for;
|
|
3105
|
-
* the per-kind builders are exported for the few sites that know their fill kind.
|
|
3106
|
-
*/
|
|
3107
|
-
function boolToXml(value) {
|
|
3108
|
-
return value ? "1" : "0";
|
|
3109
|
-
}
|
|
3110
|
-
function normalizeGradientAngle(angle) {
|
|
3111
|
-
const degrees = angle ?? 0;
|
|
3112
|
-
if (typeof degrees !== "number" || !Number.isFinite(degrees)) throw new InvalidOptionError("gradient/angle-non-finite", "Gradient angle must be a finite number.");
|
|
3113
|
-
return convertRotationDegrees((degrees % 360 + 360) % 360);
|
|
3114
|
-
}
|
|
3115
|
-
function alphaFromTransparency(transparency) {
|
|
3116
|
-
return transparency ? voidEl("a:alpha", { val: transparencyToAlpha(transparency) }) : "";
|
|
3117
|
-
}
|
|
3118
|
-
function normalizeGradientStops(stops) {
|
|
3119
|
-
if (!Array.isArray(stops) || stops.length < 2) throw new InvalidOptionError("gradient/too-few-stops", "Gradient fill requires at least two stops.");
|
|
3120
|
-
return stops.map((stop) => {
|
|
3121
|
-
if (!stop || typeof stop.position !== "number" || !Number.isFinite(stop.position)) throw new InvalidOptionError("gradient/stop-position-non-finite", "Gradient stop position must be a finite number from 0 to 100.");
|
|
3122
|
-
if (stop.position < 0 || stop.position > 100) throw new InvalidOptionError("gradient/stop-position-out-of-range", "Gradient stop position must be from 0 to 100.");
|
|
3123
|
-
return stop;
|
|
3124
|
-
}).sort((a, b) => a.position - b.position);
|
|
3125
|
-
}
|
|
3126
|
-
/**
|
|
3127
|
-
* Create a native DrawingML gradient fill.
|
|
3128
|
-
* @param {GradientFillProps} gradient gradient fill options
|
|
3129
|
-
* @returns XML string
|
|
3130
|
-
*/
|
|
3131
|
-
function genXmlGradientFill(gradient) {
|
|
3132
|
-
if (!gradient || gradient.kind !== "linear" && gradient.kind !== "radial") throw new UnsupportedFeatureError("gradient/type-unsupported", "Gradient fill currently supports only linear and radial gradients.");
|
|
3133
|
-
if (typeof gradient.rotateWithShape !== "undefined" && typeof gradient.rotateWithShape !== "boolean") throw new InvalidOptionError("gradient/rotate-with-shape-not-boolean", "Gradient rotateWithShape must be a boolean.");
|
|
3134
|
-
const stops = normalizeGradientStops(gradient.stops);
|
|
3135
|
-
const rotWithShape = gradient.rotateWithShape ?? true;
|
|
3136
|
-
const gsLst = el("a:gsLst", null, stops.map((stop) => raw(el("a:gs", { pos: Math.round(stop.position * FIXED_PCT_PER_PERCENT) }, raw(createColorElement(stop.color, alphaFromTransparency(stop.transparency)))))));
|
|
3137
|
-
let shape;
|
|
3138
|
-
if (gradient.kind === "radial") {
|
|
3139
|
-
const cx = Math.max(0, Math.min(100, gradient.center?.x ?? 50));
|
|
3140
|
-
const cy = Math.max(0, Math.min(100, gradient.center?.y ?? 50));
|
|
3141
|
-
shape = el("a:path", { path: "circle" }, raw(voidEl("a:fillToRect", {
|
|
3142
|
-
l: Math.round(cx * FIXED_PCT_PER_PERCENT),
|
|
3143
|
-
t: Math.round(cy * FIXED_PCT_PER_PERCENT),
|
|
3144
|
-
r: Math.round((100 - cx) * FIXED_PCT_PER_PERCENT),
|
|
3145
|
-
b: Math.round((100 - cy) * FIXED_PCT_PER_PERCENT)
|
|
3146
|
-
})));
|
|
3147
|
-
} else {
|
|
3148
|
-
if (typeof gradient.scaled !== "undefined" && typeof gradient.scaled !== "boolean") throw new InvalidOptionError("gradient/scaled-not-boolean", "Gradient scaled must be a boolean.");
|
|
3149
|
-
shape = voidEl("a:lin", {
|
|
3150
|
-
ang: normalizeGradientAngle(gradient.angle),
|
|
3151
|
-
scaled: typeof gradient.scaled === "boolean" ? boolToXml(gradient.scaled) : void 0
|
|
3152
|
-
});
|
|
3153
|
-
}
|
|
3154
|
-
return el("a:gradFill", { rotWithShape: boolToXml(rotWithShape) }, [raw(gsLst), raw(shape)]);
|
|
3155
|
-
}
|
|
3156
|
-
/**
|
|
3157
|
-
* Create a native DrawingML pattern fill.
|
|
3158
|
-
* @param {PatternFillProps} pattern pattern fill options
|
|
3159
|
-
* @returns XML string
|
|
3160
|
-
*/
|
|
3161
|
-
function genXmlPatternFill(pattern) {
|
|
3162
|
-
if (!pattern) throw new InvalidOptionError("pattern-fill/missing-pattern", "Pattern fill requires a pattern object.");
|
|
3163
|
-
const fgColor = pattern.fgColor ?? "000000";
|
|
3164
|
-
const bgColor = pattern.bgColor ?? "FFFFFF";
|
|
3165
|
-
return el("a:pattFill", { prst: pattern.preset }, [raw(el("a:fgClr", null, raw(createColorElement(fgColor)))), raw(el("a:bgClr", null, raw(createColorElement(bgColor))))]);
|
|
3166
|
-
}
|
|
3167
|
-
/**
|
|
3168
|
-
* Create a native DrawingML picture (image) fill.
|
|
3169
|
-
* The media relationship is registered when the object is added; this only emits
|
|
3170
|
-
* the `<a:blipFill>` referencing the pre-resolved rId.
|
|
3171
|
-
* @param {ShapeFillProps} props fill props (must carry a resolved `_imgRid`)
|
|
3172
|
-
* @returns XML string
|
|
3173
|
-
*/
|
|
3174
|
-
function genXmlImageFill(props) {
|
|
3175
|
-
if (!props || typeof props._imgRid !== "number") {
|
|
3176
|
-
warn("image-fill/unresolved-media", "image fill is missing its resolved media reference; falling back to no fill. Provide `image: { path }` or `image: { data }`.");
|
|
3177
|
-
return voidEl("a:noFill");
|
|
3178
|
-
}
|
|
3179
|
-
const alpha = props.transparency;
|
|
3180
|
-
const blipInner = alpha ? voidEl("a:alphaModFix", { amt: Math.round((100 - alpha) * FIXED_PCT_PER_PERCENT) }) : "";
|
|
3181
|
-
return el("a:blipFill", {
|
|
3182
|
-
dpi: 0,
|
|
3183
|
-
rotWithShape: 1
|
|
3184
|
-
}, [
|
|
3185
|
-
raw(el("a:blip", { "r:embed": `rId${props._imgRid}` }, raw(blipInner))),
|
|
3186
|
-
raw(voidEl("a:srcRect")),
|
|
3187
|
-
raw(el("a:stretch", null, raw(voidEl("a:fillRect"))))
|
|
3188
|
-
]);
|
|
3189
|
-
}
|
|
3190
|
-
/**
|
|
3191
|
-
* Create color selection
|
|
3192
|
-
* @param {Color | ShapeFillProps | ShapeLineProps} props fill props
|
|
3193
|
-
* @returns XML string
|
|
3194
|
-
*/
|
|
3195
|
-
function genXmlColorSelection(props) {
|
|
3196
|
-
let fillType = "solid";
|
|
3197
|
-
let colorVal = "";
|
|
3198
|
-
let internalElements = "";
|
|
3199
|
-
let outText = "";
|
|
3200
|
-
if (props) {
|
|
3201
|
-
if (typeof props === "string") colorVal = props;
|
|
3202
|
-
else {
|
|
3203
|
-
if (props.type) fillType = props.type;
|
|
3204
|
-
if (props.color) colorVal = props.color;
|
|
3205
|
-
internalElements += alphaFromTransparency(props.transparency);
|
|
3206
|
-
}
|
|
3207
|
-
switch (fillType) {
|
|
3208
|
-
case "none":
|
|
3209
|
-
outText += voidEl("a:noFill");
|
|
3210
|
-
break;
|
|
3211
|
-
case "solid":
|
|
3212
|
-
outText += el("a:solidFill", null, raw(createColorElement(colorVal, internalElements)));
|
|
3213
|
-
break;
|
|
3214
|
-
case "gradient":
|
|
3215
|
-
outText += genXmlGradientFill(typeof props === "string" ? void 0 : props.gradient);
|
|
3216
|
-
break;
|
|
3217
|
-
case "pattern":
|
|
3218
|
-
outText += genXmlPatternFill(typeof props === "string" ? void 0 : props.pattern);
|
|
3219
|
-
break;
|
|
3220
|
-
case "image":
|
|
3221
|
-
outText += genXmlImageFill(typeof props === "string" ? void 0 : props);
|
|
3222
|
-
break;
|
|
3223
|
-
default: outText += "";
|
|
3224
|
-
}
|
|
3225
|
-
}
|
|
3226
|
-
return outText;
|
|
3227
|
-
}
|
|
3228
|
-
//#endregion
|
|
3229
2711
|
//#region src/gen/drawingml/line.ts
|
|
3230
2712
|
/** Every key `BorderProps` defines. Keep in step with the interface in `types/style.ts`. */
|
|
3231
2713
|
const BORDER_KEYS = [
|
|
@@ -3477,13 +2959,14 @@ function genXmlTitle(opts, chartX, chartY) {
|
|
|
3477
2959
|
* @return {string} XML
|
|
3478
2960
|
*/
|
|
3479
2961
|
function createGridLineElement(glOpts) {
|
|
3480
|
-
|
|
2962
|
+
const line = el("a:ln", {
|
|
3481
2963
|
w: valToPts(glOpts.size || DEF_CHART_GRIDLINE.size || 1),
|
|
3482
2964
|
cap: createLineCap(glOpts.cap || DEF_CHART_GRIDLINE.cap)
|
|
3483
2965
|
}, [raw(" " + el("a:solidFill", null, raw(createColorElement(glOpts.color || DEF_GRIDLINE_COLOR)))), raw(" " + voidEl("a:prstDash", { val: glOpts.style || DEF_CHART_GRIDLINE.style }) + voidEl("a:round"))], {
|
|
3484
2966
|
openPrefix: " ",
|
|
3485
2967
|
closePrefix: " "
|
|
3486
|
-
})
|
|
2968
|
+
});
|
|
2969
|
+
return el("c:majorGridlines", null, raw(el("c:spPr", null, raw(line), {
|
|
3487
2970
|
openPrefix: " ",
|
|
3488
2971
|
closePrefix: " "
|
|
3489
2972
|
})));
|
|
@@ -3577,10 +3060,11 @@ function createSerLinesElement(opt) {
|
|
|
3577
3060
|
if (!opt) return "";
|
|
3578
3061
|
if (opt === true) return "<c:serLines/>";
|
|
3579
3062
|
if (opt.style === "none") return "";
|
|
3580
|
-
|
|
3063
|
+
const line = el("a:ln", {
|
|
3581
3064
|
w: valToPts(opt.size || DEF_CHART_GRIDLINE.size || 1),
|
|
3582
3065
|
cap: createLineCap(opt.cap || DEF_CHART_GRIDLINE.cap)
|
|
3583
|
-
}, [raw(el("a:solidFill", null, raw(createColorElement(opt.color || DEF_GRIDLINE_COLOR)))), raw(voidEl("a:prstDash", { val: opt.style || DEF_CHART_GRIDLINE.style }) + voidEl("a:round"))])
|
|
3066
|
+
}, [raw(el("a:solidFill", null, raw(createColorElement(opt.color || DEF_GRIDLINE_COLOR)))), raw(voidEl("a:prstDash", { val: opt.style || DEF_CHART_GRIDLINE.style }) + voidEl("a:round"))]);
|
|
3067
|
+
return el("c:serLines", null, raw(el("c:spPr", null, raw(line))));
|
|
3584
3068
|
}
|
|
3585
3069
|
/**
|
|
3586
3070
|
* Build the `<c:leaderLines>` element for pie/doughnut data labels.
|
|
@@ -3598,7 +3082,9 @@ function createSerLinesElement(opt) {
|
|
|
3598
3082
|
function createLeaderLinesElement(opts) {
|
|
3599
3083
|
if (!opts.showLeaderLines) return "";
|
|
3600
3084
|
if (!opts.leaderLineColor && opts.leaderLineSize == null) return "";
|
|
3601
|
-
|
|
3085
|
+
const w = valToPts(opts.leaderLineSize ?? .75);
|
|
3086
|
+
const color = opts.leaderLineColor || "808080";
|
|
3087
|
+
return `<c:leaderLines><c:spPr><a:ln w="${w}" cap="flat">${genXmlColorSelection(color)}<a:prstDash val="solid"/><a:round/></a:ln><a:effectLst/></c:spPr></c:leaderLines>`;
|
|
3602
3088
|
}
|
|
3603
3089
|
/**
|
|
3604
3090
|
* Build a single custom `<c:dLbl>` (rich-text data label) overriding one data point's label.
|
|
@@ -3674,8 +3160,10 @@ function makeSeriesDataPointsXml(chartType, obj, opts, varyColors) {
|
|
|
3674
3160
|
...pattern,
|
|
3675
3161
|
fgColor: fillColor
|
|
3676
3162
|
} : pattern);
|
|
3677
|
-
else if (fillColor)
|
|
3678
|
-
|
|
3163
|
+
else if (fillColor) {
|
|
3164
|
+
if (chartType === "bar3D") xml += `<a:ln>${genXmlColorSelection(fillColor)}</a:ln>`;
|
|
3165
|
+
else xml += genXmlColorSelection(fillColor);
|
|
3166
|
+
}
|
|
3679
3167
|
if (border) xml += createChartBorderLine(border);
|
|
3680
3168
|
}
|
|
3681
3169
|
xml += createShadowEffectLst(opts.shadow, DEF_SHAPE_SHADOW);
|
|
@@ -4825,6 +4313,27 @@ function makeSurfaceScene(opts) {
|
|
|
4825
4313
|
* {@link ./data-refs}.
|
|
4826
4314
|
*/
|
|
4827
4315
|
/**
|
|
4316
|
+
* Whether a chart-area/plot-area `fill` says anything the fill dispatch can act on.
|
|
4317
|
+
*
|
|
4318
|
+
* `c:spPr` is `a:CT_ShapeProperties` — the same optional `EG_FillProperties` group the
|
|
4319
|
+
* shape path writes into — so gradient, pattern and an omitted fill child are all legal
|
|
4320
|
+
* here. The gate used to be `fill?.color`, which meant every spelling carrying no colour
|
|
4321
|
+
* (`gradient`, `pattern`, `image`, `inherit`) fell to the no-fill arm and did nothing.
|
|
4322
|
+
*
|
|
4323
|
+
* The gate cannot simply be `fill != null`. `normalizeChartOptions` defaults
|
|
4324
|
+
* `plotArea.fill` to `{}`, so every chart in existence arrives here with a fill object,
|
|
4325
|
+
* and a presence check would paint each one a default grey. The same is true of the one
|
|
4326
|
+
* input a caller can write by hand: `{ transparency: 50 }` alone is not a fill, since
|
|
4327
|
+
* there is no colour for the alpha to apply to. Both stay no-fill.
|
|
4328
|
+
*
|
|
4329
|
+
* A payload with no `type` (`{ gradient }`, `{ pattern }`) is likewise not stated, which
|
|
4330
|
+
* matches the shape path: only `line` infers its type from a bare `gradient`, fills have
|
|
4331
|
+
* always wanted `type: 'gradient'` spelled out.
|
|
4332
|
+
*/
|
|
4333
|
+
function isStatedFill(fill) {
|
|
4334
|
+
return Boolean(fill?.color || fill?.type);
|
|
4335
|
+
}
|
|
4336
|
+
/**
|
|
4828
4337
|
* Build the chartSpace/chart header: chartSpace open, title (or autoTitleDeleted),
|
|
4829
4338
|
* optional 3D view, and the plotArea open with optional manual layout.
|
|
4830
4339
|
*/
|
|
@@ -4980,7 +4489,7 @@ function makeChartPlotAreaPropsXml(rel) {
|
|
|
4980
4489
|
strXml += "</c:dTable>";
|
|
4981
4490
|
}
|
|
4982
4491
|
strXml += " <c:spPr>";
|
|
4983
|
-
strXml += plotArea.fill
|
|
4492
|
+
strXml += isStatedFill(plotArea.fill) ? genXmlColorSelection(plotArea.fill) : "<a:noFill/>";
|
|
4984
4493
|
strXml += plotArea.border ? `<a:ln w="${valToPts(resolveBorderWidth(plotArea.border, 1))}" cap="flat">${genXmlColorSelection({
|
|
4985
4494
|
color: plotArea.border.color ?? "363636",
|
|
4986
4495
|
transparency: plotArea.border.transparency
|
|
@@ -5065,9 +4574,10 @@ function makeXmlCharts(rel) {
|
|
|
5065
4574
|
usesSecondaryCatAxis = usesSecondaryCatAxis || (options.secondaryCatAxis ?? false);
|
|
5066
4575
|
const subType = asChartType(type.type);
|
|
5067
4576
|
const usesValueXAxis = subType === "scatter" || subType === "bubble" || subType === "bubble3D";
|
|
5068
|
-
if (options.secondaryCatAxis)
|
|
5069
|
-
|
|
5070
|
-
|
|
4577
|
+
if (options.secondaryCatAxis) {
|
|
4578
|
+
if (usesValueXAxis) secondaryCatAxisValType = subType;
|
|
4579
|
+
else secondaryCatAxisHasCategoryChart = true;
|
|
4580
|
+
} else if (usesValueXAxis) primaryCatAxisValType = subType;
|
|
5071
4581
|
else primaryCatAxisHasCategoryChart = true;
|
|
5072
4582
|
strXml += makeChartType(subType, type.data, options, valAxisId, catAxisId);
|
|
5073
4583
|
});
|
|
@@ -5079,7 +4589,7 @@ function makeXmlCharts(rel) {
|
|
|
5079
4589
|
if (rel.opts._type === "scatter") strXml += "<c:showDLblsOverMax val=\"1\"/>";
|
|
5080
4590
|
strXml += "</c:chart>";
|
|
5081
4591
|
strXml += "<c:spPr>";
|
|
5082
|
-
strXml += chartArea.fill
|
|
4592
|
+
strXml += isStatedFill(chartArea.fill) ? genXmlColorSelection(chartArea.fill) : "<a:noFill/>";
|
|
5083
4593
|
strXml += chartArea.border ? `<a:ln w="${valToPts(resolveBorderWidth(chartArea.border, 1))}" cap="flat">${genXmlColorSelection({
|
|
5084
4594
|
color: chartArea.border.color ?? "363636",
|
|
5085
4595
|
transparency: chartArea.border.transparency
|
|
@@ -5158,7 +4668,7 @@ function makeChartType(chartType, data, opts, valAxisId, catAxisId) {
|
|
|
5158
4668
|
case "surface": return makeSurfacePlot(chartType, data, opts, valAxisId, catAxisId, valFmtCode);
|
|
5159
4669
|
case "doughnut":
|
|
5160
4670
|
case "pie": return makePiePlot(chartType, data, opts, valFmtCode);
|
|
5161
|
-
default:
|
|
4671
|
+
default: throw new InternalError("chart/type-not-routed", `makeChartType: "${String(chartType)}" has no <c:...Chart> plot — the chartEx catalog is built by makeXmlChartEx, and a newly added classic type needs an arm here`, { detail: { chartType } });
|
|
5162
4672
|
}
|
|
5163
4673
|
}
|
|
5164
4674
|
//#endregion
|
|
@@ -5221,7 +4731,8 @@ function makeChartExData(rel) {
|
|
|
5221
4731
|
formatCode: "General"
|
|
5222
4732
|
}, raw(valPts)))]);
|
|
5223
4733
|
const data = el("cx:data", { id: 0 }, [raw(catDim), raw(valDim)]);
|
|
5224
|
-
|
|
4734
|
+
const externalData = voidEl("cx:externalData", { "r:id": "rId1" });
|
|
4735
|
+
return el("cx:chartData", null, [raw(externalData), raw(data)]);
|
|
5225
4736
|
}
|
|
5226
4737
|
/**
|
|
5227
4738
|
* The `Sheet1` cell holding the series name (the numeric dimension's header) — column immediately
|
|
@@ -5240,7 +4751,8 @@ const A_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
|
|
|
5240
4751
|
const R_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
5241
4752
|
/**
|
|
5242
4753
|
* Map a chartEx {@link ChartType} to its `<cx:series layoutId>` token (the CT_SeriesLayout value
|
|
5243
|
-
* PowerPoint keys the chart geometry on).
|
|
4754
|
+
* PowerPoint keys the chart geometry on). Throws on anything it does not own — see the `default`
|
|
4755
|
+
* arm for which members those are and why reaching it is a routing bug.
|
|
5244
4756
|
*/
|
|
5245
4757
|
function chartExLayoutId(type) {
|
|
5246
4758
|
switch (type) {
|
|
@@ -5251,7 +4763,7 @@ function chartExLayoutId(type) {
|
|
|
5251
4763
|
case "histogram": return "clusteredColumn";
|
|
5252
4764
|
case "boxWhisker": return "boxWhisker";
|
|
5253
4765
|
case "regionMap": return "regionMap";
|
|
5254
|
-
default:
|
|
4766
|
+
default: throw new InternalError("chart/type-not-routed", `chartExLayoutId: "${String(type)}" has no <cx:series> layoutId — classic chart types belong to makeXmlCharts, pareto is built by makeParetoSeries, and a newly added chartEx type needs an arm here`, { detail: { chartType: type } });
|
|
5255
4767
|
}
|
|
5256
4768
|
}
|
|
5257
4769
|
/**
|
|
@@ -5329,11 +4841,12 @@ function makeBoxWhiskerLayoutPr(stats) {
|
|
|
5329
4841
|
* renders blank if the names don't match PowerPoint's geography database.
|
|
5330
4842
|
*/
|
|
5331
4843
|
function makeGeographyLayoutPr(geo) {
|
|
5332
|
-
|
|
4844
|
+
const geography = voidEl("cx:geography", {
|
|
5333
4845
|
cultureLanguage: geo?.cultureLanguage || "en-US",
|
|
5334
4846
|
cultureRegion: geo?.cultureRegion || "US",
|
|
5335
4847
|
attribution: "Powered by Bing"
|
|
5336
|
-
})
|
|
4848
|
+
});
|
|
4849
|
+
return el("cx:layoutPr", null, raw(geography));
|
|
5337
4850
|
}
|
|
5338
4851
|
/** The `<cx:tx>` series-name cell/value block (shared by every layout that names its series). */
|
|
5339
4852
|
function makeChartExSeriesName(rel) {
|
|
@@ -5379,8 +4892,10 @@ function makeChartExSeries(rel) {
|
|
|
5379
4892
|
const type = opts._type;
|
|
5380
4893
|
if (type === "pareto") return makeParetoSeries(rel);
|
|
5381
4894
|
let layoutPr = "";
|
|
5382
|
-
if (type === "waterfall" && Array.isArray(opts.subtotals) && opts.subtotals.length > 0)
|
|
5383
|
-
|
|
4895
|
+
if (type === "waterfall" && Array.isArray(opts.subtotals) && opts.subtotals.length > 0) {
|
|
4896
|
+
const idxs = opts.subtotals.map((idx) => voidEl("cx:idx", { val: idx })).join("");
|
|
4897
|
+
layoutPr = el("cx:layoutPr", null, raw(el("cx:subtotals", null, raw(idxs))));
|
|
4898
|
+
} else if (type === "treemap") layoutPr = el("cx:layoutPr", null, raw(voidEl("cx:parentLabelLayout", { val: "overlapping" })));
|
|
5384
4899
|
else if (type === "histogram") layoutPr = el("cx:layoutPr", null, raw(makeChartExBinning(opts.binning)));
|
|
5385
4900
|
else if (type === "boxWhisker") layoutPr = makeBoxWhiskerLayoutPr(opts.statistics);
|
|
5386
4901
|
else if (type === "regionMap") layoutPr = makeGeographyLayoutPr(opts.geography);
|
|
@@ -5449,15 +4964,16 @@ function makeChartExTitle(rel) {
|
|
|
5449
4964
|
const color = rel.opts.titleColor || "000000";
|
|
5450
4965
|
const face = rel.opts.titleFontFace || "Calibri";
|
|
5451
4966
|
const rPr = el("a:defRPr", null, [raw(genXmlColorSelection(color)), raw(createChartTextFonts(face))]);
|
|
4967
|
+
const rich = el("cx:rich", null, [
|
|
4968
|
+
raw(voidEl("a:bodyPr")),
|
|
4969
|
+
raw(voidEl("a:lstStyle")),
|
|
4970
|
+
raw(el("a:p", null, [raw(el("a:pPr", null, raw(rPr))), raw(el("a:r", null, [raw(voidEl("a:rPr", { lang: rel.opts.lang || "en-US" })), raw(el("a:t", null, rel.opts.title || "Chart Title"))]))]))
|
|
4971
|
+
]);
|
|
5452
4972
|
return el("cx:title", {
|
|
5453
4973
|
pos: "t",
|
|
5454
4974
|
align: "ctr",
|
|
5455
4975
|
overlay: 0
|
|
5456
|
-
}, raw(el("cx:tx", null, raw(
|
|
5457
|
-
raw(voidEl("a:bodyPr")),
|
|
5458
|
-
raw(voidEl("a:lstStyle")),
|
|
5459
|
-
raw(el("a:p", null, [raw(el("a:pPr", null, raw(rPr))), raw(el("a:r", null, [raw(voidEl("a:rPr", { lang: rel.opts.lang || "en-US" })), raw(el("a:t", null, rel.opts.title || "Chart Title"))]))]))
|
|
5460
|
-
])))));
|
|
4976
|
+
}, raw(el("cx:tx", null, raw(rich))));
|
|
5461
4977
|
}
|
|
5462
4978
|
/**
|
|
5463
4979
|
* Assemble the full `<cx:chartSpace>` for a chartEx chart part.
|
|
@@ -5468,7 +4984,8 @@ function makeChartExTitle(rel) {
|
|
|
5468
4984
|
*/
|
|
5469
4985
|
function makeXmlChartEx(rel) {
|
|
5470
4986
|
const type = rel.opts._type;
|
|
5471
|
-
const
|
|
4987
|
+
const plotAreaRegion = el("cx:plotAreaRegion", null, raw(makeChartExSeries(rel)));
|
|
4988
|
+
const plotArea = el("cx:plotArea", null, [raw(plotAreaRegion), raw(makeChartExAxes(type))]);
|
|
5472
4989
|
const legend = rel.opts.showLegend ? voidEl("cx:legend", {
|
|
5473
4990
|
pos: chartExLegendPos(rel.opts.legendPos),
|
|
5474
4991
|
align: "ctr",
|
|
@@ -5522,6 +5039,8 @@ function makeChartExStyleXml() {
|
|
|
5522
5039
|
}
|
|
5523
5040
|
//#endregion
|
|
5524
5041
|
//#region src/gen/chart/embed-xlsx.ts
|
|
5042
|
+
/** MS chart-extension relationship types (chartEx style + color-style sidecar parts). */
|
|
5043
|
+
const MS_CHART_REL = "http://schemas.microsoft.com/office/2011/relationships/";
|
|
5525
5044
|
function relationship$2(id, type, target) {
|
|
5526
5045
|
return voidEl("Relationship", {
|
|
5527
5046
|
Id: id,
|
|
@@ -5759,8 +5278,8 @@ function buildChartRelsXml(embeddingTarget) {
|
|
|
5759
5278
|
function buildChartExRelsXml(embeddingTarget, colorsTarget, styleTarget) {
|
|
5760
5279
|
return XML_DECL + relationships([
|
|
5761
5280
|
relationship$2("rId1", OFFICE_REL + "package", embeddingTarget),
|
|
5762
|
-
relationship$2("rId2", "
|
|
5763
|
-
relationship$2("rId3", "
|
|
5281
|
+
relationship$2("rId2", MS_CHART_REL + "chartColorStyle", colorsTarget),
|
|
5282
|
+
relationship$2("rId3", MS_CHART_REL + "chartStyle", styleTarget)
|
|
5764
5283
|
]);
|
|
5765
5284
|
}
|
|
5766
5285
|
/**
|
|
@@ -6230,6 +5749,7 @@ function buildAnimationSeq(animations, next) {
|
|
|
6230
5749
|
fill: "hold"
|
|
6231
5750
|
}, [raw(el("p:stCondLst", null, raw(voidEl("p:cond", { delay: "indefinite" })))), raw(el("p:childTnLst", null, raw(subs)))])));
|
|
6232
5751
|
};
|
|
5752
|
+
const clickGroups = groups.map(emitGroup).join("");
|
|
6233
5753
|
return el("p:seq", {
|
|
6234
5754
|
concurrent: 1,
|
|
6235
5755
|
nextAc: "seek"
|
|
@@ -6238,7 +5758,7 @@ function buildAnimationSeq(animations, next) {
|
|
|
6238
5758
|
id: 2,
|
|
6239
5759
|
dur: "indefinite",
|
|
6240
5760
|
nodeType: "mainSeq"
|
|
6241
|
-
}, raw(el("p:childTnLst", null, raw(
|
|
5761
|
+
}, raw(el("p:childTnLst", null, raw(clickGroups))))),
|
|
6242
5762
|
raw(el("p:prevCondLst", null, raw(el("p:cond", {
|
|
6243
5763
|
evt: "onPrev",
|
|
6244
5764
|
delay: 0
|
|
@@ -6286,7 +5806,8 @@ function slideTimingToXml(slide) {
|
|
|
6286
5806
|
const mediaNode = (obj, nodeId) => {
|
|
6287
5807
|
const spid = slide._slideObjects.indexOf(obj) + 2;
|
|
6288
5808
|
const repeatCount = obj.loop === true ? "indefinite" : String(Math.round(obj.loopCount * 1e3));
|
|
6289
|
-
|
|
5809
|
+
const mediaTag = obj.mtype === "audio" ? "p:audio" : "p:video";
|
|
5810
|
+
return el(mediaTag, null, raw(el("p:cMediaNode", null, [raw(el("p:cTn", {
|
|
6290
5811
|
id: nodeId,
|
|
6291
5812
|
repeatCount,
|
|
6292
5813
|
fill: "hold",
|
|
@@ -6296,12 +5817,13 @@ function slideTimingToXml(slide) {
|
|
|
6296
5817
|
if (animations.length === 0) {
|
|
6297
5818
|
if (loopMedia.length === 0) return "";
|
|
6298
5819
|
let nodeId = 1;
|
|
5820
|
+
const mediaNodes = loopMedia.map((obj) => mediaNode(obj, nodeId += 1)).join("");
|
|
6299
5821
|
return el("p:timing", null, raw(el("p:tnLst", null, raw(el("p:par", null, raw(el("p:cTn", {
|
|
6300
5822
|
id: 1,
|
|
6301
5823
|
dur: "indefinite",
|
|
6302
5824
|
restart: "never",
|
|
6303
5825
|
nodeType: "tmRoot"
|
|
6304
|
-
}, raw(el("p:childTnLst", null, raw(
|
|
5826
|
+
}, raw(el("p:childTnLst", null, raw(mediaNodes))))))))));
|
|
6305
5827
|
}
|
|
6306
5828
|
let id = 2;
|
|
6307
5829
|
const next = () => id += 1;
|
|
@@ -6370,40 +5892,6 @@ function slideTransitionToXml(slide) {
|
|
|
6370
5892
|
}, [raw(typeEl), raw(sndAc)])))), raw(el("mc:Fallback", null, raw(el("p:transition", baseAttrs, [raw(typeEl), raw(sndAc)]))))]);
|
|
6371
5893
|
}
|
|
6372
5894
|
//#endregion
|
|
6373
|
-
//#region src/gen/drawingml/clamp.ts
|
|
6374
|
-
/**
|
|
6375
|
-
* ts-pptx: DrawingML value clamps
|
|
6376
|
-
*
|
|
6377
|
-
* Clamp font/character/line spacing values (points) into their ST_* schema
|
|
6378
|
-
* ranges and convert to the hundredths-of-a-point units the attributes expect.
|
|
6379
|
-
* Out-of-range values make PowerPoint report the package as needing repair.
|
|
6380
|
-
*/
|
|
6381
|
-
/**
|
|
6382
|
-
* Clamp a font size (points) into ST_TextFontSize (1-4000pt) and return it in
|
|
6383
|
-
* hundredths of a point for the `sz` attribute. Out-of-range sizes make
|
|
6384
|
-
* PowerPoint report the package as needing repair (e.g. `sz` > 400000 or < 100).
|
|
6385
|
-
*/
|
|
6386
|
-
function clampFontSizeSz(fontSizePts) {
|
|
6387
|
-
const raw = ptToHundredths(fontSizePts);
|
|
6388
|
-
const clamped = Math.min(4e5, Math.max(100, raw));
|
|
6389
|
-
if (clamped !== raw) warnOnce("font/size-out-of-range", `fontSize ${fontSizePts} is outside the valid range 1-4000pt; using ${clamped / 100}.`);
|
|
6390
|
-
return clamped;
|
|
6391
|
-
}
|
|
6392
|
-
/** Clamp character spacing (points) into ST_TextPoint (-4000..4000pt); returns hundredths for the `spc` attribute. */
|
|
6393
|
-
function clampCharSpacingSpc(charSpacingPts) {
|
|
6394
|
-
const raw = ptToHundredths(charSpacingPts);
|
|
6395
|
-
const clamped = Math.min(4e5, Math.max(-4e5, raw));
|
|
6396
|
-
if (clamped !== raw) warnOnce("text/char-spacing-out-of-range", `charSpacing ${charSpacingPts} is outside the valid range -4000..4000pt; using ${clamped / 100}.`);
|
|
6397
|
-
return clamped;
|
|
6398
|
-
}
|
|
6399
|
-
/** Clamp line spacing (points) into ST_TextSpacingPoint (0..1584pt); returns hundredths for `<a:spcPts val>`. */
|
|
6400
|
-
function clampLineSpacingPts(lineSpacingPts) {
|
|
6401
|
-
const raw = ptToHundredths(lineSpacingPts);
|
|
6402
|
-
const clamped = Math.min(158400, Math.max(0, raw));
|
|
6403
|
-
if (clamped !== raw) warnOnce("text/line-spacing-out-of-range", `lineSpacing ${lineSpacingPts} is outside the valid range 0-1584pt; using ${clamped / 100}.`);
|
|
6404
|
-
return clamped;
|
|
6405
|
-
}
|
|
6406
|
-
//#endregion
|
|
6407
5895
|
//#region src/gen/drawingml/locks.ts
|
|
6408
5896
|
const SHAPE_LOCK_ATTRS = [
|
|
6409
5897
|
"noGrp",
|
|
@@ -6539,396 +6027,6 @@ function genXmlShapeLine(ln) {
|
|
|
6539
6027
|
]);
|
|
6540
6028
|
}
|
|
6541
6029
|
//#endregion
|
|
6542
|
-
//#region src/gen/drawingml/math.ts
|
|
6543
|
-
/**
|
|
6544
|
-
* ts-pptx: DrawingML native equations (OMML)
|
|
6545
|
-
*
|
|
6546
|
-
* Wrap raw OMML markup into the `<a14:m>` marker PowerPoint uses for editable
|
|
6547
|
-
* equations — as a standalone display paragraph (`genXmlMathParagraph`) or as an
|
|
6548
|
-
* inline run that flows between the surrounding `<a:r>` runs (`genXmlInlineMath`).
|
|
6549
|
-
*/
|
|
6550
|
-
const M_NS = "http://schemas.openxmlformats.org/officeDocument/2006/math";
|
|
6551
|
-
const A14_NS = "http://schemas.microsoft.com/office/drawing/2010/main";
|
|
6552
|
-
/** The `<a14:m>` marker, carrying both namespace declarations so the supplied OMML needs none. */
|
|
6553
|
-
function a14Math(mathXml) {
|
|
6554
|
-
return el("a14:m", {
|
|
6555
|
-
"xmlns:a14": A14_NS,
|
|
6556
|
-
"xmlns:m": M_NS
|
|
6557
|
-
}, raw(mathXml));
|
|
6558
|
-
}
|
|
6559
|
-
/**
|
|
6560
|
-
* Build a native-equation paragraph (`<a:p>`) from raw OMML.
|
|
6561
|
-
*
|
|
6562
|
-
* PowerPoint stores an editable equation inside a text body as an `<a14:m>` marker wrapping
|
|
6563
|
-
* `<m:oMathPara><m:oMath>…`. We declare both the `a14` (drawing-2010) and `m` (math) namespaces
|
|
6564
|
-
* on the `<a14:m>` element so the supplied OMML needs no namespace declarations of its own, then
|
|
6565
|
-
* accept three input shapes: a full `<m:oMathPara>`, a full `<m:oMath>`, or the inner OMML
|
|
6566
|
-
* (children of `<m:oMath>`). A trailing `<a:endParaRPr>` matches what PowerPoint authors.
|
|
6567
|
-
*
|
|
6568
|
-
* @param {string} omml - raw OMML markup for the equation
|
|
6569
|
-
* @returns {string} an `<a:p>` math paragraph
|
|
6570
|
-
*/
|
|
6571
|
-
function genXmlMathParagraph(omml) {
|
|
6572
|
-
const trimmed = (omml || "").trim();
|
|
6573
|
-
const paraPr = el("m:oMathParaPr", null, raw(voidEl("m:jc", { "m:val": "centerGroup" })));
|
|
6574
|
-
return el("a:p", null, [a14Math(trimmed.startsWith("<m:oMathPara") ? trimmed : trimmed.includes("<m:oMath") ? el("m:oMathPara", null, [paraPr, trimmed].map(raw)) : el("m:oMathPara", null, [paraPr, el("m:oMath", null, raw(trimmed))].map(raw))), voidEl("a:endParaRPr", { lang: "en-US" })].map(raw));
|
|
6575
|
-
}
|
|
6576
|
-
/**
|
|
6577
|
-
* Build an INLINE native-equation run (dn-inline-math) from raw OMML.
|
|
6578
|
-
*
|
|
6579
|
-
* Unlike the display form ({@link genXmlMathParagraph}), an inline equation is *not* its own
|
|
6580
|
-
* paragraph: PowerPoint authors an `<a14:m>` marker wrapping a bare `<m:oMath>` (no `<m:oMathPara>`,
|
|
6581
|
-
* no `<m:oMathParaPr>`/`<m:jc>`) that flows between the surrounding `<a:r>` runs in one `<a:p>` —
|
|
6582
|
-
* pinned by the `math-omml-inline.pptx` oracle. The `mc:AlternateContent` envelope stays at the
|
|
6583
|
-
* shape level (see `objectHasMath`), so nothing wraps the run itself. We declare the `a14` and `m`
|
|
6584
|
-
* namespaces on the `<a14:m>` element so the supplied OMML needs none of its own, and accept the
|
|
6585
|
-
* same three input shapes as the display helper: a full `<m:oMathPara>` (its inner `<m:oMath>` is
|
|
6586
|
-
* unwrapped, since a paragraph block cannot flow inline), a full `<m:oMath>`, or the inner OMML.
|
|
6587
|
-
*
|
|
6588
|
-
* @param {string} omml - raw OMML markup for the equation
|
|
6589
|
-
* @returns {string} an `<a14:m>` inline equation run
|
|
6590
|
-
*/
|
|
6591
|
-
function genXmlInlineMath(omml) {
|
|
6592
|
-
const trimmed = (omml || "").trim();
|
|
6593
|
-
const oMathMatch = trimmed.match(/<m:oMath[\s>][\s\S]*<\/m:oMath>/);
|
|
6594
|
-
return a14Math(oMathMatch ? oMathMatch[0] : el("m:oMath", null, raw(trimmed)));
|
|
6595
|
-
}
|
|
6596
|
-
//#endregion
|
|
6597
|
-
//#region src/gen/drawingml/text-run.ts
|
|
6598
|
-
/** The 2018 hyperlink-color extension namespace, written on the `<ahyp:hlinkClr>` element itself. */
|
|
6599
|
-
const AHYP_NS = "http://schemas.microsoft.com/office/drawing/2018/hyperlinkcolor";
|
|
6600
|
-
/**
|
|
6601
|
-
* `<a:buChar>` cannot go through the element builder. Its `char` attribute carries a *pre-escaped*
|
|
6602
|
-
* numeric character reference (`•` — see `BulletType`), and the builder escapes every
|
|
6603
|
-
* attribute value, which would emit `&#x2022;` and render that text literally as the bullet.
|
|
6604
|
-
* There is no raw-attribute escape hatch, so this one stays a template.
|
|
6605
|
-
*/
|
|
6606
|
-
function buChar(char) {
|
|
6607
|
-
return `<a:buChar char="${char}"/>`;
|
|
6608
|
-
}
|
|
6609
|
-
/**
|
|
6610
|
-
* `<a:extLst>` marking a hyperlink whose color should follow the text color rather than the
|
|
6611
|
-
* theme's hyperlink color. The leading spaces are byte-significant: this block was authored as
|
|
6612
|
-
* indented string concatenation and that indentation reaches the file, so it is described here
|
|
6613
|
-
* with `openPrefix`/`closePrefix` rather than being tidied away.
|
|
6614
|
-
*/
|
|
6615
|
-
const HLINK_TEXT_COLOR_EXT = el("a:extLst", null, raw(el("a:ext", { uri: "{A12FA001-AC4F-418D-AE19-62706E023703}" }, raw(voidEl("ahyp:hlinkClr", {
|
|
6616
|
-
"xmlns:ahyp": AHYP_NS,
|
|
6617
|
-
val: "tx"
|
|
6618
|
-
}, { openPrefix: " " })), {
|
|
6619
|
-
openPrefix: " ",
|
|
6620
|
-
closePrefix: " "
|
|
6621
|
-
})), {
|
|
6622
|
-
openPrefix: " ",
|
|
6623
|
-
closePrefix: " "
|
|
6624
|
-
});
|
|
6625
|
-
/**
|
|
6626
|
-
* Generate XML Paragraph Properties
|
|
6627
|
-
* @param {SlideObject|TextProps} textObj - text object
|
|
6628
|
-
* @param {boolean} isDefault - array of default relations
|
|
6629
|
-
* @return {string} XML
|
|
6630
|
-
*/
|
|
6631
|
-
function genXmlParagraphProperties(textObj, isDefault) {
|
|
6632
|
-
const opts = textObj.options ?? {};
|
|
6633
|
-
let strXmlBullet = "";
|
|
6634
|
-
let strXmlBulletColor = "";
|
|
6635
|
-
let strXmlLnSpc = "";
|
|
6636
|
-
let strXmlParaSpc = "";
|
|
6637
|
-
let strXmlTabStops = "";
|
|
6638
|
-
const tag = isDefault ? "a:lvl1pPr" : "a:pPr";
|
|
6639
|
-
let bulletMarL = valToPts(27);
|
|
6640
|
-
let paragraphPropXml = `<${tag}${opts.rtlMode ? " rtl=\"1\" " : ""}`;
|
|
6641
|
-
if (opts.align) switch (opts.align) {
|
|
6642
|
-
case "left":
|
|
6643
|
-
paragraphPropXml += " algn=\"l\"";
|
|
6644
|
-
break;
|
|
6645
|
-
case "right":
|
|
6646
|
-
paragraphPropXml += " algn=\"r\"";
|
|
6647
|
-
break;
|
|
6648
|
-
case "center":
|
|
6649
|
-
paragraphPropXml += " algn=\"ctr\"";
|
|
6650
|
-
break;
|
|
6651
|
-
case "justify":
|
|
6652
|
-
paragraphPropXml += " algn=\"just\"";
|
|
6653
|
-
break;
|
|
6654
|
-
default: paragraphPropXml += "";
|
|
6655
|
-
}
|
|
6656
|
-
if (opts.lineSpacing) strXmlLnSpc = el("a:lnSpc", null, raw(voidEl("a:spcPts", { val: clampLineSpacingPts(opts.lineSpacing) })));
|
|
6657
|
-
else if (opts.lineSpacingMultiple) strXmlLnSpc = el("a:lnSpc", null, raw(voidEl("a:spcPct", { val: Math.round(opts.lineSpacingMultiple * PERCENT_SCALE) })));
|
|
6658
|
-
if (opts.indentLevel && !isNaN(Number(opts.indentLevel)) && opts.indentLevel > 0) paragraphPropXml += ` lvl="${opts.indentLevel}"`;
|
|
6659
|
-
if (opts.paraSpaceBefore && !isNaN(Number(opts.paraSpaceBefore)) && opts.paraSpaceBefore > 0) strXmlParaSpc += el("a:spcBef", null, raw(voidEl("a:spcPts", { val: ptToHundredths(opts.paraSpaceBefore) })));
|
|
6660
|
-
if (opts.paraSpaceAfter && !isNaN(Number(opts.paraSpaceAfter)) && opts.paraSpaceAfter > 0) strXmlParaSpc += el("a:spcAft", null, raw(voidEl("a:spcPts", { val: ptToHundredths(opts.paraSpaceAfter) })));
|
|
6661
|
-
if (typeof opts.bullet === "object") {
|
|
6662
|
-
const bulletImage = opts.bullet.image;
|
|
6663
|
-
const isPictureBullet = !!(bulletImage && (bulletImage.path || bulletImage.data));
|
|
6664
|
-
if (opts.bullet?.indent) bulletMarL = valToPts(opts.bullet.indent);
|
|
6665
|
-
if (opts.bullet.color && !isPictureBullet) strXmlBulletColor = el("a:buClr", null, raw(createColorElement(opts.bullet.color)));
|
|
6666
|
-
let bulletSizePct;
|
|
6667
|
-
if (opts.bullet.size !== void 0) {
|
|
6668
|
-
const bulletSize = Number(opts.bullet.size);
|
|
6669
|
-
if (isNaN(bulletSize) || bulletSize < 25 || bulletSize > 400) warn("bullet/size-out-of-range", "`bullet.size` must be a percentage between 25 and 400!");
|
|
6670
|
-
else bulletSizePct = Math.round(bulletSize * FIXED_PCT_PER_PERCENT);
|
|
6671
|
-
}
|
|
6672
|
-
const strXmlBulletSize = bulletSizePct === void 0 ? "" : voidEl("a:buSzPct", { val: bulletSizePct });
|
|
6673
|
-
const strXmlBulletFont = opts.bullet.fontFace ? voidEl("a:buFont", { typeface: opts.bullet.fontFace }) : "";
|
|
6674
|
-
const bulletIndentAttrs = () => ` marL="${opts.indentLevel && opts.indentLevel > 0 ? bulletMarL + bulletMarL * opts.indentLevel : bulletMarL}" indent="-${bulletMarL}"`;
|
|
6675
|
-
if (isPictureBullet) {
|
|
6676
|
-
paragraphPropXml += bulletIndentAttrs();
|
|
6677
|
-
if (opts.bullet._rId) {
|
|
6678
|
-
const svgExt = opts.bullet._rIdSvg ? el("a:extLst", null, raw(el("a:ext", { uri: "{96DAC541-7B7A-43D3-8B79-37D633B846F1}" }, raw(voidEl("asvg:svgBlip", {
|
|
6679
|
-
"xmlns:asvg": "http://schemas.microsoft.com/office/drawing/2016/SVG/main",
|
|
6680
|
-
"r:embed": `rId${opts.bullet._rIdSvg}`
|
|
6681
|
-
}))))) : "";
|
|
6682
|
-
strXmlBullet = strXmlBulletSize + el("a:buBlip", null, raw(svgExt ? el("a:blip", { "r:embed": `rId${opts.bullet._rId}` }, raw(svgExt)) : voidEl("a:blip", { "r:embed": `rId${opts.bullet._rId}` })));
|
|
6683
|
-
} else {
|
|
6684
|
-
warn("bullet/image-embed-failed", "picture `bullet.image` could not be embedded; using a default bullet glyph");
|
|
6685
|
-
strXmlBullet = strXmlBulletSize + strXmlBulletFont + buChar("•");
|
|
6686
|
-
}
|
|
6687
|
-
} else if (opts.bullet.type && opts.bullet.type.toString().toLowerCase() === "number") {
|
|
6688
|
-
paragraphPropXml += bulletIndentAttrs();
|
|
6689
|
-
strXmlBullet = strXmlBulletSize + (strXmlBulletFont || voidEl("a:buFont", { typeface: "+mj-lt" })) + voidEl("a:buAutoNum", {
|
|
6690
|
-
type: opts.bullet.numberType || "arabicPeriod",
|
|
6691
|
-
startAt: opts.bullet.numberStartAt || "1"
|
|
6692
|
-
});
|
|
6693
|
-
} else if (opts.bullet.characterCode) {
|
|
6694
|
-
let bulletCode = `&#x${opts.bullet.characterCode};`;
|
|
6695
|
-
if (!/^[0-9A-Fa-f]{4}$/.test(opts.bullet.characterCode)) {
|
|
6696
|
-
warn("bullet/invalid-character-code", "`bullet.characterCode` should be a 4-digit unicode character (ex: 22AB)!");
|
|
6697
|
-
bulletCode = "•";
|
|
6698
|
-
}
|
|
6699
|
-
paragraphPropXml += bulletIndentAttrs();
|
|
6700
|
-
strXmlBullet = strXmlBulletSize + strXmlBulletFont + buChar(bulletCode);
|
|
6701
|
-
} else {
|
|
6702
|
-
paragraphPropXml += bulletIndentAttrs();
|
|
6703
|
-
strXmlBullet = strXmlBulletSize + strXmlBulletFont + buChar("•");
|
|
6704
|
-
}
|
|
6705
|
-
} else if (opts.bullet) {
|
|
6706
|
-
paragraphPropXml += ` marL="${opts.indentLevel && opts.indentLevel > 0 ? bulletMarL + bulletMarL * opts.indentLevel : bulletMarL}" indent="-${bulletMarL}"`;
|
|
6707
|
-
strXmlBullet = buChar("•");
|
|
6708
|
-
} else if (!opts.bullet) {
|
|
6709
|
-
paragraphPropXml += " indent=\"0\" marL=\"0\"";
|
|
6710
|
-
strXmlBullet = voidEl("a:buNone");
|
|
6711
|
-
}
|
|
6712
|
-
if (opts.tabStops && Array.isArray(opts.tabStops)) strXmlTabStops = el("a:tabLst", null, raw(opts.tabStops.map((stop) => voidEl("a:tab", {
|
|
6713
|
-
pos: inch2Emu(stop.position || 1),
|
|
6714
|
-
algn: stop.alignment || "l"
|
|
6715
|
-
})).join("")));
|
|
6716
|
-
paragraphPropXml += ">" + strXmlLnSpc + strXmlParaSpc + strXmlBulletColor + strXmlBullet + strXmlTabStops;
|
|
6717
|
-
if (isDefault) paragraphPropXml += genXmlTextRunProperties(opts, true);
|
|
6718
|
-
paragraphPropXml += "</" + tag + ">";
|
|
6719
|
-
return paragraphPropXml;
|
|
6720
|
-
}
|
|
6721
|
-
/**
|
|
6722
|
-
* Generate XML Text Run Properties (`a:rPr`)
|
|
6723
|
-
* @param {ObjectOptions|TextPropsOptions} opts - text options
|
|
6724
|
-
* @param {boolean} isDefault - whether these are the default text run properties
|
|
6725
|
-
* @return {string} XML
|
|
6726
|
-
*/
|
|
6727
|
-
function genXmlTextRunProperties(opts, isDefault) {
|
|
6728
|
-
let runProps = "";
|
|
6729
|
-
const runPropsTag = isDefault ? "a:defRPr" : "a:rPr";
|
|
6730
|
-
const underline = typeof opts.underline === "object" && opts.underline?.style ? opts.underline.style : opts.hyperlink ? "sng" : null;
|
|
6731
|
-
const baseline = opts.baseline ? Math.round(opts.baseline * 50) : opts.subscript ? -4e4 : opts.superscript ? 3e4 : null;
|
|
6732
|
-
const attrs = {
|
|
6733
|
-
lang: opts.lang ? opts.lang : "en-US",
|
|
6734
|
-
altLang: opts.lang ? "en-US" : null,
|
|
6735
|
-
sz: opts.fontSize ? clampFontSizeSz(opts.fontSize) : null,
|
|
6736
|
-
b: opts?.bold ? "1" : null,
|
|
6737
|
-
i: opts?.italic ? "1" : null,
|
|
6738
|
-
strike: opts?.strike ? typeof opts.strike === "string" ? opts.strike : "sngStrike" : null,
|
|
6739
|
-
cap: opts?.caps ? opts.caps : null,
|
|
6740
|
-
u: underline,
|
|
6741
|
-
baseline,
|
|
6742
|
-
spc: opts.charSpacing ? clampCharSpacingSpc(opts.charSpacing) : null,
|
|
6743
|
-
kern: opts.charSpacing ? 0 : null,
|
|
6744
|
-
dirty: "0"
|
|
6745
|
-
};
|
|
6746
|
-
const hasShadow = !!opts.shadow && opts.shadow.type !== "none";
|
|
6747
|
-
if (opts.color || opts.fontFace || opts.outline || opts.glow || hasShadow || typeof opts.underline === "object" && opts.underline.color) {
|
|
6748
|
-
if (opts.outline && typeof opts.outline === "object") runProps += el("a:ln", { w: lineWidthToEmu(opts.outline.size || .75) }, raw(genXmlColorSelection(opts.outline.color || "FFFFFF")));
|
|
6749
|
-
if (opts.color) runProps += genXmlColorSelection({
|
|
6750
|
-
color: opts.color,
|
|
6751
|
-
transparency: opts.transparency
|
|
6752
|
-
});
|
|
6753
|
-
if (opts.glow || hasShadow) runProps += el("a:effectLst", null, [opts.glow ? raw(createGlowElement(opts.glow, DEF_TEXT_GLOW)) : null, hasShadow ? raw(createShadowElement(opts.shadow, DEF_TEXT_SHADOW)) : null]);
|
|
6754
|
-
if (opts.highlight) runProps += el("a:highlight", null, raw(createColorElement(opts.highlight)));
|
|
6755
|
-
if (typeof opts.underline === "object" && opts.underline.color) runProps += el("a:uFill", null, raw(genXmlColorSelection(opts.underline.color)));
|
|
6756
|
-
if (opts.fontFace) {
|
|
6757
|
-
runProps += voidEl("a:latin", {
|
|
6758
|
-
typeface: opts.fontFace,
|
|
6759
|
-
pitchFamily: "34",
|
|
6760
|
-
charset: "0"
|
|
6761
|
-
});
|
|
6762
|
-
if (opts.fontFaceEA) runProps += voidEl("a:ea", { typeface: opts.fontFaceEA });
|
|
6763
|
-
runProps += voidEl("a:cs", { typeface: opts.fontFace });
|
|
6764
|
-
}
|
|
6765
|
-
}
|
|
6766
|
-
if (opts.hyperlink) {
|
|
6767
|
-
if (typeof opts.hyperlink !== "object") throw new InvalidOptionError("hyperlink/not-an-object", "text `hyperlink` option should be an object. Ex: `hyperlink:{url:'https://github.com'}` ");
|
|
6768
|
-
else if (!opts.hyperlink.url && !opts.hyperlink.slide && !opts.hyperlink.action) throw new InvalidOptionError("hyperlink/missing-target", "text `hyperlink` requires either `url`, `slide`, or `action`");
|
|
6769
|
-
else if (opts.hyperlink.url || opts.hyperlink.slide) {
|
|
6770
|
-
const linkAttrs = opts.hyperlink.url ? {
|
|
6771
|
-
"r:id": `rId${opts.hyperlink._rId}`,
|
|
6772
|
-
invalidUrl: "",
|
|
6773
|
-
action: "",
|
|
6774
|
-
tgtFrame: "",
|
|
6775
|
-
tooltip: opts.hyperlink.tooltip ?? "",
|
|
6776
|
-
history: "1",
|
|
6777
|
-
highlightClick: "0",
|
|
6778
|
-
endSnd: "0"
|
|
6779
|
-
} : {
|
|
6780
|
-
"r:id": `rId${opts.hyperlink._rId}`,
|
|
6781
|
-
action: "ppaction://hlinksldjump",
|
|
6782
|
-
tooltip: opts.hyperlink.tooltip ?? ""
|
|
6783
|
-
};
|
|
6784
|
-
runProps += opts.color ? el("a:hlinkClick", linkAttrs, raw(HLINK_TEXT_COLOR_EXT)) : voidEl("a:hlinkClick", linkAttrs);
|
|
6785
|
-
}
|
|
6786
|
-
}
|
|
6787
|
-
return el(runPropsTag, attrs, raw(runProps));
|
|
6788
|
-
}
|
|
6789
|
-
/**
|
|
6790
|
-
* Build textBody text runs [`<a:r></a:r>`] for paragraphs [`<a:p>`]
|
|
6791
|
-
* @param {TextProps} textObj - Text object
|
|
6792
|
-
* @return {string} XML string
|
|
6793
|
-
*/
|
|
6794
|
-
function genXmlTextRun(textObj) {
|
|
6795
|
-
if (textObj.text === void 0 || textObj.text === null) return "";
|
|
6796
|
-
return el("a:r", null, [raw(genXmlTextRunProperties(textObj.options ?? {}, false)), raw(el("a:t", null, String(textObj.text)))]);
|
|
6797
|
-
}
|
|
6798
|
-
/**
|
|
6799
|
-
* Builds `<a:normAutofit>` with explicit fontScale/lnSpcReduction for "shrink text on overflow"
|
|
6800
|
-
* @param {TextFitShrinkProps} fit - shrink fit options
|
|
6801
|
-
* @return {string} XML string (`<a:normAutofit .../>`)
|
|
6802
|
-
* @see ECMA-376 CT_TextNormAutofit (attributes in 1000ths of a percent)
|
|
6803
|
-
*/
|
|
6804
|
-
function genXmlNormAutofit(fit) {
|
|
6805
|
-
const pct = (val, name) => {
|
|
6806
|
-
if (val === void 0 || val === null) return null;
|
|
6807
|
-
if (typeof val !== "number" || isNaN(val) || val < 0 || val > 100) {
|
|
6808
|
-
warn("text/invalid-fit-percentage", `fit.${name} must be a number between 0 and 100 (percent); received ${String(val)} - attribute ignored.`);
|
|
6809
|
-
return null;
|
|
6810
|
-
}
|
|
6811
|
-
return Math.round(val * FIXED_PCT_PER_PERCENT);
|
|
6812
|
-
};
|
|
6813
|
-
return voidEl("a:normAutofit", {
|
|
6814
|
-
fontScale: pct(fit.fontScale, "fontScale"),
|
|
6815
|
-
lnSpcReduction: pct(fit.lnSpcReduction, "lnSpcReduction")
|
|
6816
|
-
});
|
|
6817
|
-
}
|
|
6818
|
-
/**
|
|
6819
|
-
* Group the flat run list into paragraphs (lines): a new line starts on a display-math run,
|
|
6820
|
-
* an alignment change, or a bullet, and closes after a breakLine. Returns the per-line run arrays.
|
|
6821
|
-
*/
|
|
6822
|
-
function groupRunsIntoLines(arrTextObjects, opts) {
|
|
6823
|
-
const arrLines = [];
|
|
6824
|
-
let arrTexts = [];
|
|
6825
|
-
arrTextObjects.forEach((textObj, idx) => {
|
|
6826
|
-
if (textObj.math && !textObj.inline) {
|
|
6827
|
-
if (arrTexts.length > 0) {
|
|
6828
|
-
arrLines.push(arrTexts);
|
|
6829
|
-
arrTexts = [];
|
|
6830
|
-
}
|
|
6831
|
-
arrLines.push([textObj]);
|
|
6832
|
-
return;
|
|
6833
|
-
}
|
|
6834
|
-
if (arrTexts.length > 0 && (textObj.options.align || opts.align)) {
|
|
6835
|
-
if (textObj.options.align !== arrTextObjects[idx - 1]?.options.align) {
|
|
6836
|
-
arrLines.push(arrTexts);
|
|
6837
|
-
arrTexts = [];
|
|
6838
|
-
}
|
|
6839
|
-
} else if (arrTexts.length > 0 && textObj.options.bullet) {
|
|
6840
|
-
arrLines.push(arrTexts);
|
|
6841
|
-
arrTexts = [];
|
|
6842
|
-
textObj.options.breakLine = false;
|
|
6843
|
-
}
|
|
6844
|
-
arrTexts.push(textObj);
|
|
6845
|
-
if (arrTexts.length > 0 && textObj.options.breakLine) {
|
|
6846
|
-
if (idx + 1 < arrTextObjects.length) {
|
|
6847
|
-
arrLines.push(arrTexts);
|
|
6848
|
-
arrTexts = [];
|
|
6849
|
-
}
|
|
6850
|
-
}
|
|
6851
|
-
if (idx + 1 === arrTextObjects.length) arrLines.push(arrTexts);
|
|
6852
|
-
});
|
|
6853
|
-
return arrLines;
|
|
6854
|
-
}
|
|
6855
|
-
/**
|
|
6856
|
-
* Render each grouped line to an `<a:p>` paragraph: paragraph props, inherited run options,
|
|
6857
|
-
* text runs (and inline/display math), and the closing endParaRPr.
|
|
6858
|
-
*/
|
|
6859
|
-
function renderTextParagraphsXml(arrLines, slideObj, opts) {
|
|
6860
|
-
let strSlideXml = "";
|
|
6861
|
-
arrLines.forEach((line) => {
|
|
6862
|
-
const firstRun = line[0];
|
|
6863
|
-
if (line.length === 1 && firstRun?.math && !firstRun.inline) {
|
|
6864
|
-
strSlideXml += genXmlMathParagraph(firstRun.math);
|
|
6865
|
-
return;
|
|
6866
|
-
}
|
|
6867
|
-
let reqsClosingFontSize = false;
|
|
6868
|
-
let paraXml = "";
|
|
6869
|
-
let paragraphPropXml = `<a:pPr ${line[0]?.options?.rtlMode ? " rtl=\"1\" " : ""}`;
|
|
6870
|
-
let paragraphPropEmitted = false;
|
|
6871
|
-
line.forEach((textObj, idx) => {
|
|
6872
|
-
textObj.options._lineIdx = idx;
|
|
6873
|
-
if (idx > 0 && textObj.options.softBreakBefore) paraXml += voidEl("a:br");
|
|
6874
|
-
textObj.options.align = textObj.options.align || opts.align;
|
|
6875
|
-
textObj.options.lineSpacing = textObj.options.lineSpacing || opts.lineSpacing;
|
|
6876
|
-
textObj.options.lineSpacingMultiple = textObj.options.lineSpacingMultiple || opts.lineSpacingMultiple;
|
|
6877
|
-
textObj.options.indentLevel = textObj.options.indentLevel || opts.indentLevel;
|
|
6878
|
-
textObj.options.paraSpaceBefore = textObj.options.paraSpaceBefore || opts.paraSpaceBefore;
|
|
6879
|
-
textObj.options.paraSpaceAfter = textObj.options.paraSpaceAfter || opts.paraSpaceAfter;
|
|
6880
|
-
if (!paragraphPropEmitted) {
|
|
6881
|
-
paragraphPropXml = genXmlParagraphProperties(textObj, false);
|
|
6882
|
-
const cleaned = paragraphPropXml.replace("<a:pPr></a:pPr>", "");
|
|
6883
|
-
if (cleaned) {
|
|
6884
|
-
paraXml += cleaned;
|
|
6885
|
-
paragraphPropEmitted = true;
|
|
6886
|
-
}
|
|
6887
|
-
}
|
|
6888
|
-
const textOptions = textObj.options;
|
|
6889
|
-
Object.entries(opts).filter(([key]) => !(textObj.options.hyperlink && key === "color")).forEach(([key, val]) => {
|
|
6890
|
-
if (key !== "bullet" && !textOptions[key]) textOptions[key] = val;
|
|
6891
|
-
});
|
|
6892
|
-
let _textRunObj = textObj;
|
|
6893
|
-
if (idx === 0 && line[0]?.options.bullet && typeof textObj.text === "string") {
|
|
6894
|
-
const _stripped = textObj.text.replace(/^[\u2022\u25E6\u25AA\u25AB\u25CF\u25CB\u2023\u2043\u2219]\s*/, "");
|
|
6895
|
-
if (_stripped !== textObj.text) _textRunObj = {
|
|
6896
|
-
text: _stripped,
|
|
6897
|
-
options: textObj.options
|
|
6898
|
-
};
|
|
6899
|
-
}
|
|
6900
|
-
const isEmptyBreakArtifact = _textRunObj.text === "" && line.length > 1;
|
|
6901
|
-
if (_textRunObj.math) paraXml += genXmlInlineMath(_textRunObj.math);
|
|
6902
|
-
else if (!isEmptyBreakArtifact) paraXml += genXmlTextRun(_textRunObj);
|
|
6903
|
-
if (!textObj.text && opts.fontSize || textObj.options.fontSize) {
|
|
6904
|
-
reqsClosingFontSize = true;
|
|
6905
|
-
opts.fontSize = opts.fontSize || textObj.options.fontSize;
|
|
6906
|
-
}
|
|
6907
|
-
});
|
|
6908
|
-
const sizedAttrs = () => ({
|
|
6909
|
-
lang: opts.lang || "en-US",
|
|
6910
|
-
sz: opts.fontSize ? clampFontSizeSz(opts.fontSize) : null,
|
|
6911
|
-
dirty: "0"
|
|
6912
|
-
});
|
|
6913
|
-
if (slideObj._type === "tablecell" && (opts.fontSize || opts.fontFace)) if (opts.fontFace) paraXml += el("a:endParaRPr", sizedAttrs(), [
|
|
6914
|
-
raw(voidEl("a:latin", {
|
|
6915
|
-
typeface: opts.fontFace,
|
|
6916
|
-
charset: "0"
|
|
6917
|
-
})),
|
|
6918
|
-
opts.fontFaceEA ? raw(voidEl("a:ea", { typeface: opts.fontFaceEA })) : null,
|
|
6919
|
-
raw(voidEl("a:cs", { typeface: opts.fontFace }))
|
|
6920
|
-
]);
|
|
6921
|
-
else paraXml += voidEl("a:endParaRPr", sizedAttrs());
|
|
6922
|
-
else if (reqsClosingFontSize) paraXml += voidEl("a:endParaRPr", sizedAttrs());
|
|
6923
|
-
else paraXml += voidEl("a:endParaRPr", {
|
|
6924
|
-
lang: opts.lang || "en-US",
|
|
6925
|
-
dirty: "0"
|
|
6926
|
-
});
|
|
6927
|
-
strSlideXml += el("a:p", null, raw(paraXml));
|
|
6928
|
-
});
|
|
6929
|
-
return strSlideXml;
|
|
6930
|
-
}
|
|
6931
|
-
//#endregion
|
|
6932
6030
|
//#region src/gen/drawingml/text-body.ts
|
|
6933
6031
|
/**
|
|
6934
6032
|
* ts-pptx: DrawingML text body
|
|
@@ -7434,29 +6532,32 @@ function genXmlCustGeom(options, cx, cy, layout) {
|
|
|
7434
6532
|
if (cxnEls.length) cxnLst = el("a:cxnLst", null, cxnEls.map(raw));
|
|
7435
6533
|
}
|
|
7436
6534
|
let ahLst = voidEl("a:ahLst", null, SPACE_BEFORE_SLASH);
|
|
7437
|
-
if (options.adjustHandles?.length)
|
|
7438
|
-
const
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
gdRefR
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
6535
|
+
if (options.adjustHandles?.length) {
|
|
6536
|
+
const ahEls = options.adjustHandles.map((h) => {
|
|
6537
|
+
const pos = raw(voidEl("a:pos", {
|
|
6538
|
+
x: adjCoord(h.x, "X"),
|
|
6539
|
+
y: adjCoord(h.y, "Y")
|
|
6540
|
+
}));
|
|
6541
|
+
if ("gdRefR" in h || "minR" in h || "maxR" in h || "gdRefAng" in h || "minAng" in h || "maxAng" in h) return el("a:ahPolar", {
|
|
6542
|
+
gdRefR: h.gdRefR,
|
|
6543
|
+
minR: adjCoord(h.minR, "X"),
|
|
6544
|
+
maxR: adjCoord(h.maxR, "X"),
|
|
6545
|
+
gdRefAng: h.gdRefAng,
|
|
6546
|
+
minAng: h.minAng == null ? void 0 : convertRotationDegrees(h.minAng),
|
|
6547
|
+
maxAng: h.maxAng == null ? void 0 : convertRotationDegrees(h.maxAng)
|
|
6548
|
+
}, pos);
|
|
6549
|
+
const xy = h;
|
|
6550
|
+
return el("a:ahXY", {
|
|
6551
|
+
gdRefX: xy.gdRefX,
|
|
6552
|
+
minX: adjCoord(xy.minX, "X"),
|
|
6553
|
+
maxX: adjCoord(xy.maxX, "X"),
|
|
6554
|
+
gdRefY: xy.gdRefY,
|
|
6555
|
+
minY: adjCoord(xy.minY, "Y"),
|
|
6556
|
+
maxY: adjCoord(xy.maxY, "Y")
|
|
6557
|
+
}, pos);
|
|
6558
|
+
});
|
|
6559
|
+
ahLst = el("a:ahLst", null, ahEls.map(raw));
|
|
6560
|
+
}
|
|
7460
6561
|
return el("a:custGeom", null, [
|
|
7461
6562
|
voidEl("a:avLst", null, SPACE_BEFORE_SLASH),
|
|
7462
6563
|
gdLst,
|
|
@@ -7520,11 +6621,15 @@ const ImageSizingXml = {
|
|
|
7520
6621
|
].filter(Boolean).join(", ");
|
|
7521
6622
|
throw new InvalidOptionError("image/crop-window-overflows", `addImage sizing.type 'crop': crop window overflows image bounds — ${over}. Ensure x≥0, y≥0, x+w≤w, y+h≤h.`);
|
|
7522
6623
|
}
|
|
6624
|
+
const lPerc = Math.round(1e5 * (l / imgSize.w));
|
|
6625
|
+
const rPerc = Math.round(1e5 * (r / imgSize.w));
|
|
6626
|
+
const tPerc = Math.round(1e5 * (t / imgSize.h));
|
|
6627
|
+
const bPerc = Math.round(1e5 * (b / imgSize.h));
|
|
7523
6628
|
return voidEl("a:srcRect", {
|
|
7524
|
-
l:
|
|
7525
|
-
r:
|
|
7526
|
-
t:
|
|
7527
|
-
b:
|
|
6629
|
+
l: lPerc,
|
|
6630
|
+
r: rPerc,
|
|
6631
|
+
t: tPerc,
|
|
6632
|
+
b: bPerc
|
|
7528
6633
|
}) + STRETCH;
|
|
7529
6634
|
}
|
|
7530
6635
|
};
|
|
@@ -8886,7 +7991,11 @@ function slideObjectToXml(slide) {
|
|
|
8886
7991
|
strSlideXml += "</p:grpSp>";
|
|
8887
7992
|
break;
|
|
8888
7993
|
}
|
|
8889
|
-
|
|
7994
|
+
case "notes": break;
|
|
7995
|
+
case "tablecell": break;
|
|
7996
|
+
case "hyperlink": break;
|
|
7997
|
+
case "online": break;
|
|
7998
|
+
default: slideItemObj._type;
|
|
8890
7999
|
}
|
|
8891
8000
|
return strSlideXml;
|
|
8892
8001
|
};
|
|
@@ -8981,17 +8090,19 @@ function slideObjectRelationsToXml(slide, defaultRels) {
|
|
|
8981
8090
|
const hasTarget = (target) => rels.some((xml) => xml.includes(` Target="${target}"`));
|
|
8982
8091
|
slide._rels.forEach((rel) => {
|
|
8983
8092
|
lastRid = Math.max(lastRid, rel.rId);
|
|
8984
|
-
if (isHyperlinkRel(rel))
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
8093
|
+
if (isHyperlinkRel(rel)) {
|
|
8094
|
+
if (rel.data === "slide") rels.push(voidEl("Relationship", {
|
|
8095
|
+
Id: `rId${rel.rId}`,
|
|
8096
|
+
Type: OFFICE_REL + "slide",
|
|
8097
|
+
Target: `slide${rel.Target}.xml`
|
|
8098
|
+
}));
|
|
8099
|
+
else rels.push(voidEl("Relationship", {
|
|
8100
|
+
Id: `rId${rel.rId}`,
|
|
8101
|
+
Type: OFFICE_REL + "hyperlink",
|
|
8102
|
+
Target: rel.Target,
|
|
8103
|
+
TargetMode: "External"
|
|
8104
|
+
}));
|
|
8105
|
+
}
|
|
8995
8106
|
});
|
|
8996
8107
|
(slide._relsChart || []).forEach((rel) => {
|
|
8997
8108
|
lastRid = Math.max(lastRid, rel.rId);
|
|
@@ -9102,527 +8213,6 @@ function getLayoutIdxForSlide(slides, slideLayouts, slideNumber) {
|
|
|
9102
8213
|
return 1;
|
|
9103
8214
|
}
|
|
9104
8215
|
//#endregion
|
|
9105
|
-
//#region src/gen/slide/notes.ts
|
|
9106
|
-
/**
|
|
9107
|
-
* Collect the speaker-notes runs for a slide (flattened across any number of `addNotes()` calls).
|
|
9108
|
-
* @param {PresSlideInternal} slide - the slide object
|
|
9109
|
-
* @return {TextProps[]} notes text runs in document order
|
|
9110
|
-
*/
|
|
9111
|
-
function getNotesRuns(slide) {
|
|
9112
|
-
const runs = [];
|
|
9113
|
-
slide._slideObjects.forEach((obj) => {
|
|
9114
|
-
if (obj._type === "notes" && obj.text) runs.push(...obj.text);
|
|
9115
|
-
});
|
|
9116
|
-
return runs;
|
|
9117
|
-
}
|
|
9118
|
-
/**
|
|
9119
|
-
* Build (and cache) the hyperlink relationships for a slide's notes part (`notesSlideN.xml.rels`).
|
|
9120
|
-
*
|
|
9121
|
-
* Notes rels use their own namespace, independent of `slide._rels` (which serialize to
|
|
9122
|
-
* `slideN.xml.rels`). The notes part always reserves rId1=notesMaster and rId2=slide, so
|
|
9123
|
-
* dynamic hyperlink rels are allocated starting at rId3. Each notes hyperlink run is tagged
|
|
9124
|
-
* with its `_rId` so the body serializer and the rels file agree.
|
|
9125
|
-
*
|
|
9126
|
-
* Idempotent: the result is cached on `slide._relsNotes` and reused by both callers.
|
|
9127
|
-
* Only external `url` hyperlinks are supported; `slide` targets are ignored with a warning.
|
|
9128
|
-
* @param {PresSlideInternal} slide - the slide object
|
|
9129
|
-
* @return {SlideRel[]} notes hyperlink relationships
|
|
9130
|
-
*/
|
|
9131
|
-
function buildNotesSlideRels(slide) {
|
|
9132
|
-
if (slide._relsNotes) return slide._relsNotes;
|
|
9133
|
-
const NOTES_REL_RESERVED = 2;
|
|
9134
|
-
const rels = [];
|
|
9135
|
-
let lastRid = NOTES_REL_RESERVED;
|
|
9136
|
-
getNotesRuns(slide).forEach((run) => {
|
|
9137
|
-
const hyperlink = run.options?.hyperlink;
|
|
9138
|
-
if (!hyperlink) return;
|
|
9139
|
-
if (!hyperlink.url) {
|
|
9140
|
-
if (hyperlink.slide) warn("notes/hyperlink-slide-unsupported", "notes hyperlinks support `url` only (ignoring `slide` target)");
|
|
9141
|
-
if (run.options) delete run.options.hyperlink;
|
|
9142
|
-
return;
|
|
9143
|
-
}
|
|
9144
|
-
lastRid++;
|
|
9145
|
-
hyperlink._rId = lastRid;
|
|
9146
|
-
rels.push({
|
|
9147
|
-
type: "hyperlink",
|
|
9148
|
-
data: "dummy",
|
|
9149
|
-
rId: lastRid,
|
|
9150
|
-
Target: hyperlink.url
|
|
9151
|
-
});
|
|
9152
|
-
});
|
|
9153
|
-
slide._relsNotes = rels;
|
|
9154
|
-
return rels;
|
|
9155
|
-
}
|
|
9156
|
-
/**
|
|
9157
|
-
* Build the `<p:txBody>` paragraphs for the notes placeholder.
|
|
9158
|
-
* Runs are split into `<a:p>` paragraphs on newlines; each run is serialized with the standard
|
|
9159
|
-
* text-run generator so inline formatting and `<a:hlinkClick>` markup are emitted consistently.
|
|
9160
|
-
* @param {PresSlideInternal} slide - the slide object
|
|
9161
|
-
* @return {string} XML string of `<a:p>` paragraphs
|
|
9162
|
-
*/
|
|
9163
|
-
function genXmlNotesParagraphs(slide) {
|
|
9164
|
-
const paragraphs = [[]];
|
|
9165
|
-
getNotesRuns(slide).forEach((run) => {
|
|
9166
|
-
String(run.text ?? "").split("\n").forEach((segment, idx) => {
|
|
9167
|
-
if (idx > 0) paragraphs.push([]);
|
|
9168
|
-
const text = segment.replace(/\r/g, "");
|
|
9169
|
-
if (text !== "") paragraphs[paragraphs.length - 1]?.push({
|
|
9170
|
-
text,
|
|
9171
|
-
options: run.options || {}
|
|
9172
|
-
});
|
|
9173
|
-
});
|
|
9174
|
-
});
|
|
9175
|
-
return paragraphs.map((runs) => el("a:p", null, [raw(runs.map((run) => genXmlTextRun(run)).join("")), raw(voidEl("a:endParaRPr", {
|
|
9176
|
-
lang: "en-US",
|
|
9177
|
-
dirty: 0
|
|
9178
|
-
}))])).join("");
|
|
9179
|
-
}
|
|
9180
|
-
/**
|
|
9181
|
-
* Generate XML for Notes Master (notesMaster1.xml)
|
|
9182
|
-
* @returns {string} XML
|
|
9183
|
-
*/
|
|
9184
|
-
function makeXmlNotesMaster() {
|
|
9185
|
-
const xfrmOffExt = (x, y, cx, cy) => el("a:xfrm", null, [raw(voidEl("a:off", {
|
|
9186
|
-
x,
|
|
9187
|
-
y
|
|
9188
|
-
})), raw(voidEl("a:ext", {
|
|
9189
|
-
cx,
|
|
9190
|
-
cy
|
|
9191
|
-
}))]);
|
|
9192
|
-
const prstGeomRect = el("a:prstGeom", { prst: "rect" }, raw(voidEl("a:avLst")));
|
|
9193
|
-
const spLocks = (attrs) => el("p:cNvSpPr", null, raw(voidEl("a:spLocks", attrs)));
|
|
9194
|
-
const nvPr = (phAttrs) => el("p:nvPr", null, raw(voidEl("p:ph", phAttrs)));
|
|
9195
|
-
const bodyPr = (attrs) => voidEl("a:bodyPr", attrs);
|
|
9196
|
-
const lstStyleLvl1 = (algn) => el("a:lstStyle", null, raw(el("a:lvl1pPr", { algn }, raw(voidEl("a:defRPr", { sz: 1200 })))));
|
|
9197
|
-
const emptyPara = el("a:p", null, raw(voidEl("a:endParaRPr", { lang: "en-US" })));
|
|
9198
|
-
const header = el("p:sp", null, [
|
|
9199
|
-
raw(el("p:nvSpPr", null, [
|
|
9200
|
-
raw(voidEl("p:cNvPr", {
|
|
9201
|
-
id: 2,
|
|
9202
|
-
name: "Header Placeholder 1"
|
|
9203
|
-
})),
|
|
9204
|
-
raw(spLocks({ noGrp: 1 })),
|
|
9205
|
-
raw(nvPr({
|
|
9206
|
-
type: "hdr",
|
|
9207
|
-
sz: "quarter"
|
|
9208
|
-
}))
|
|
9209
|
-
])),
|
|
9210
|
-
raw(el("p:spPr", null, [raw(xfrmOffExt(0, 0, 2971800, 458788)), raw(prstGeomRect)])),
|
|
9211
|
-
raw(el("p:txBody", null, [
|
|
9212
|
-
raw(bodyPr({
|
|
9213
|
-
vert: "horz",
|
|
9214
|
-
lIns: 91440,
|
|
9215
|
-
tIns: 45720,
|
|
9216
|
-
rIns: 91440,
|
|
9217
|
-
bIns: 45720,
|
|
9218
|
-
rtlCol: 0
|
|
9219
|
-
})),
|
|
9220
|
-
raw(lstStyleLvl1("l")),
|
|
9221
|
-
raw(emptyPara)
|
|
9222
|
-
]))
|
|
9223
|
-
]);
|
|
9224
|
-
const date = el("p:sp", null, [
|
|
9225
|
-
raw(el("p:nvSpPr", null, [
|
|
9226
|
-
raw(voidEl("p:cNvPr", {
|
|
9227
|
-
id: 3,
|
|
9228
|
-
name: "Date Placeholder 2"
|
|
9229
|
-
})),
|
|
9230
|
-
raw(spLocks({ noGrp: 1 })),
|
|
9231
|
-
raw(nvPr({
|
|
9232
|
-
type: "dt",
|
|
9233
|
-
idx: 1
|
|
9234
|
-
}))
|
|
9235
|
-
])),
|
|
9236
|
-
raw(el("p:spPr", null, [raw(xfrmOffExt(3884613, 0, 2971800, 458788)), raw(prstGeomRect)])),
|
|
9237
|
-
raw(el("p:txBody", null, [
|
|
9238
|
-
raw(bodyPr({
|
|
9239
|
-
vert: "horz",
|
|
9240
|
-
lIns: 91440,
|
|
9241
|
-
tIns: 45720,
|
|
9242
|
-
rIns: 91440,
|
|
9243
|
-
bIns: 45720,
|
|
9244
|
-
rtlCol: 0
|
|
9245
|
-
})),
|
|
9246
|
-
raw(lstStyleLvl1("r")),
|
|
9247
|
-
raw(el("a:p", null, [raw(el("a:fld", {
|
|
9248
|
-
id: "{5282F153-3F37-0F45-9E97-73ACFA13230C}",
|
|
9249
|
-
type: "datetimeFigureOut"
|
|
9250
|
-
}, [raw(voidEl("a:rPr", { lang: "en-US" })), raw(el("a:t", null, "7/23/19"))])), raw(voidEl("a:endParaRPr", { lang: "en-US" }))]))
|
|
9251
|
-
]))
|
|
9252
|
-
]);
|
|
9253
|
-
const slideImg = el("p:sp", null, [
|
|
9254
|
-
raw(el("p:nvSpPr", null, [
|
|
9255
|
-
raw(voidEl("p:cNvPr", {
|
|
9256
|
-
id: 4,
|
|
9257
|
-
name: "Slide Image Placeholder 3"
|
|
9258
|
-
})),
|
|
9259
|
-
raw(spLocks({
|
|
9260
|
-
noGrp: 1,
|
|
9261
|
-
noRot: 1,
|
|
9262
|
-
noChangeAspect: 1
|
|
9263
|
-
})),
|
|
9264
|
-
raw(nvPr({
|
|
9265
|
-
type: "sldImg",
|
|
9266
|
-
idx: 2
|
|
9267
|
-
}))
|
|
9268
|
-
])),
|
|
9269
|
-
raw(el("p:spPr", null, [
|
|
9270
|
-
raw(xfrmOffExt(685800, 1143e3, 5486400, 3086100)),
|
|
9271
|
-
raw(prstGeomRect),
|
|
9272
|
-
raw(voidEl("a:noFill")),
|
|
9273
|
-
raw(el("a:ln", { w: 12700 }, raw(el("a:solidFill", null, raw(voidEl("a:prstClr", { val: "black" }))))))
|
|
9274
|
-
])),
|
|
9275
|
-
raw(el("p:txBody", null, [
|
|
9276
|
-
raw(bodyPr({
|
|
9277
|
-
vert: "horz",
|
|
9278
|
-
lIns: 91440,
|
|
9279
|
-
tIns: 45720,
|
|
9280
|
-
rIns: 91440,
|
|
9281
|
-
bIns: 45720,
|
|
9282
|
-
rtlCol: 0,
|
|
9283
|
-
anchor: "ctr"
|
|
9284
|
-
})),
|
|
9285
|
-
raw(voidEl("a:lstStyle")),
|
|
9286
|
-
raw(emptyPara)
|
|
9287
|
-
]))
|
|
9288
|
-
]);
|
|
9289
|
-
const notesPlaceholder = el("p:sp", null, [
|
|
9290
|
-
raw(el("p:nvSpPr", null, [
|
|
9291
|
-
raw(voidEl("p:cNvPr", {
|
|
9292
|
-
id: 5,
|
|
9293
|
-
name: "Notes Placeholder 4"
|
|
9294
|
-
})),
|
|
9295
|
-
raw(spLocks({ noGrp: 1 })),
|
|
9296
|
-
raw(nvPr({
|
|
9297
|
-
type: "body",
|
|
9298
|
-
sz: "quarter",
|
|
9299
|
-
idx: 3
|
|
9300
|
-
}))
|
|
9301
|
-
])),
|
|
9302
|
-
raw(el("p:spPr", null, [raw(xfrmOffExt(685800, 4400550, 5486400, 3600450)), raw(prstGeomRect)])),
|
|
9303
|
-
raw(el("p:txBody", null, [
|
|
9304
|
-
raw(bodyPr({
|
|
9305
|
-
vert: "horz",
|
|
9306
|
-
lIns: 91440,
|
|
9307
|
-
tIns: 45720,
|
|
9308
|
-
rIns: 91440,
|
|
9309
|
-
bIns: 45720,
|
|
9310
|
-
rtlCol: 0
|
|
9311
|
-
})),
|
|
9312
|
-
raw(voidEl("a:lstStyle")),
|
|
9313
|
-
raw([
|
|
9314
|
-
"Click to edit Master text styles",
|
|
9315
|
-
"Second level",
|
|
9316
|
-
"Third level",
|
|
9317
|
-
"Fourth level",
|
|
9318
|
-
"Fifth level"
|
|
9319
|
-
].map((text, lvl) => el("a:p", null, [raw(voidEl("a:pPr", { lvl })), raw(el("a:r", null, [raw(voidEl("a:rPr", { lang: "en-US" })), raw(el("a:t", null, text))]))])).join(""))
|
|
9320
|
-
]))
|
|
9321
|
-
]);
|
|
9322
|
-
const footer = el("p:sp", null, [
|
|
9323
|
-
raw(el("p:nvSpPr", null, [
|
|
9324
|
-
raw(voidEl("p:cNvPr", {
|
|
9325
|
-
id: 6,
|
|
9326
|
-
name: "Footer Placeholder 5"
|
|
9327
|
-
})),
|
|
9328
|
-
raw(spLocks({ noGrp: 1 })),
|
|
9329
|
-
raw(nvPr({
|
|
9330
|
-
type: "ftr",
|
|
9331
|
-
sz: "quarter",
|
|
9332
|
-
idx: 4
|
|
9333
|
-
}))
|
|
9334
|
-
])),
|
|
9335
|
-
raw(el("p:spPr", null, [raw(xfrmOffExt(0, 8685213, 2971800, 458787)), raw(prstGeomRect)])),
|
|
9336
|
-
raw(el("p:txBody", null, [
|
|
9337
|
-
raw(bodyPr({
|
|
9338
|
-
vert: "horz",
|
|
9339
|
-
lIns: 91440,
|
|
9340
|
-
tIns: 45720,
|
|
9341
|
-
rIns: 91440,
|
|
9342
|
-
bIns: 45720,
|
|
9343
|
-
rtlCol: 0,
|
|
9344
|
-
anchor: "b"
|
|
9345
|
-
})),
|
|
9346
|
-
raw(lstStyleLvl1("l")),
|
|
9347
|
-
raw(emptyPara)
|
|
9348
|
-
]))
|
|
9349
|
-
]);
|
|
9350
|
-
const slideNum = el("p:sp", null, [
|
|
9351
|
-
raw(el("p:nvSpPr", null, [
|
|
9352
|
-
raw(voidEl("p:cNvPr", {
|
|
9353
|
-
id: 7,
|
|
9354
|
-
name: "Slide Number Placeholder 6"
|
|
9355
|
-
})),
|
|
9356
|
-
raw(spLocks({ noGrp: 1 })),
|
|
9357
|
-
raw(nvPr({
|
|
9358
|
-
type: "sldNum",
|
|
9359
|
-
sz: "quarter",
|
|
9360
|
-
idx: 5
|
|
9361
|
-
}))
|
|
9362
|
-
])),
|
|
9363
|
-
raw(el("p:spPr", null, [raw(xfrmOffExt(3884613, 8685213, 2971800, 458787)), raw(prstGeomRect)])),
|
|
9364
|
-
raw(el("p:txBody", null, [
|
|
9365
|
-
raw(bodyPr({
|
|
9366
|
-
vert: "horz",
|
|
9367
|
-
lIns: 91440,
|
|
9368
|
-
tIns: 45720,
|
|
9369
|
-
rIns: 91440,
|
|
9370
|
-
bIns: 45720,
|
|
9371
|
-
rtlCol: 0,
|
|
9372
|
-
anchor: "b"
|
|
9373
|
-
})),
|
|
9374
|
-
raw(lstStyleLvl1("r")),
|
|
9375
|
-
raw(el("a:p", null, [raw(el("a:fld", {
|
|
9376
|
-
id: "{CE5E9CC1-C706-0F49-92D6-E571CC5EEA8F}",
|
|
9377
|
-
type: "slidenum"
|
|
9378
|
-
}, [raw(voidEl("a:rPr", { lang: "en-US" })), raw(el("a:t", null, "‹#›"))])), raw(voidEl("a:endParaRPr", { lang: "en-US" }))]))
|
|
9379
|
-
]))
|
|
9380
|
-
]);
|
|
9381
|
-
const spTree = el("p:spTree", null, [
|
|
9382
|
-
raw(el("p:nvGrpSpPr", null, [
|
|
9383
|
-
raw(voidEl("p:cNvPr", {
|
|
9384
|
-
id: 1,
|
|
9385
|
-
name: ""
|
|
9386
|
-
})),
|
|
9387
|
-
raw(voidEl("p:cNvGrpSpPr")),
|
|
9388
|
-
raw(voidEl("p:nvPr"))
|
|
9389
|
-
])),
|
|
9390
|
-
raw(el("p:grpSpPr", null, raw(el("a:xfrm", null, [
|
|
9391
|
-
raw(voidEl("a:off", {
|
|
9392
|
-
x: 0,
|
|
9393
|
-
y: 0
|
|
9394
|
-
})),
|
|
9395
|
-
raw(voidEl("a:ext", {
|
|
9396
|
-
cx: 0,
|
|
9397
|
-
cy: 0
|
|
9398
|
-
})),
|
|
9399
|
-
raw(voidEl("a:chOff", {
|
|
9400
|
-
x: 0,
|
|
9401
|
-
y: 0
|
|
9402
|
-
})),
|
|
9403
|
-
raw(voidEl("a:chExt", {
|
|
9404
|
-
cx: 0,
|
|
9405
|
-
cy: 0
|
|
9406
|
-
}))
|
|
9407
|
-
])))),
|
|
9408
|
-
raw(header),
|
|
9409
|
-
raw(date),
|
|
9410
|
-
raw(slideImg),
|
|
9411
|
-
raw(notesPlaceholder),
|
|
9412
|
-
raw(footer),
|
|
9413
|
-
raw(slideNum)
|
|
9414
|
-
]);
|
|
9415
|
-
const extLst = el("p:extLst", null, raw(el("p:ext", { uri: "{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}" }, raw(voidEl("p14:creationId", {
|
|
9416
|
-
"xmlns:p14": "http://schemas.microsoft.com/office/powerpoint/2010/main",
|
|
9417
|
-
val: 1024086991
|
|
9418
|
-
})))));
|
|
9419
|
-
const cSld = el("p:cSld", null, [
|
|
9420
|
-
raw(el("p:bg", null, raw(el("p:bgRef", { idx: 1001 }, raw(voidEl("a:schemeClr", { val: "bg1" })))))),
|
|
9421
|
-
raw(spTree),
|
|
9422
|
-
raw(extLst)
|
|
9423
|
-
]);
|
|
9424
|
-
const clrMap = voidEl("p:clrMap", {
|
|
9425
|
-
bg1: "lt1",
|
|
9426
|
-
tx1: "dk1",
|
|
9427
|
-
bg2: "lt2",
|
|
9428
|
-
tx2: "dk2",
|
|
9429
|
-
accent1: "accent1",
|
|
9430
|
-
accent2: "accent2",
|
|
9431
|
-
accent3: "accent3",
|
|
9432
|
-
accent4: "accent4",
|
|
9433
|
-
accent5: "accent5",
|
|
9434
|
-
accent6: "accent6",
|
|
9435
|
-
hlink: "hlink",
|
|
9436
|
-
folHlink: "folHlink"
|
|
9437
|
-
});
|
|
9438
|
-
const notesStyleLevel = (n, marL) => el(`a:lvl${n}pPr`, {
|
|
9439
|
-
marL,
|
|
9440
|
-
algn: "l",
|
|
9441
|
-
defTabSz: 914400,
|
|
9442
|
-
rtl: 0,
|
|
9443
|
-
eaLnBrk: 1,
|
|
9444
|
-
latinLnBrk: 0,
|
|
9445
|
-
hangingPunct: 1
|
|
9446
|
-
}, raw(el("a:defRPr", {
|
|
9447
|
-
sz: 1200,
|
|
9448
|
-
kern: 1200
|
|
9449
|
-
}, [
|
|
9450
|
-
raw(el("a:solidFill", null, raw(voidEl("a:schemeClr", { val: "tx1" })))),
|
|
9451
|
-
raw(voidEl("a:latin", { typeface: "+mn-lt" })),
|
|
9452
|
-
raw(voidEl("a:ea", { typeface: "+mn-ea" })),
|
|
9453
|
-
raw(voidEl("a:cs", { typeface: "+mn-cs" }))
|
|
9454
|
-
])));
|
|
9455
|
-
const notesStyle = el("p:notesStyle", null, raw([
|
|
9456
|
-
0,
|
|
9457
|
-
457200,
|
|
9458
|
-
914400,
|
|
9459
|
-
1371600,
|
|
9460
|
-
1828800,
|
|
9461
|
-
2286e3,
|
|
9462
|
-
2743200,
|
|
9463
|
-
3200400,
|
|
9464
|
-
3657600
|
|
9465
|
-
].map((marL, i) => notesStyleLevel(i + 1, marL)).join("")));
|
|
9466
|
-
return XML_DECL + "\r\n" + el("p:notesMaster", {
|
|
9467
|
-
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
|
9468
|
-
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
9469
|
-
"xmlns:p": "http://schemas.openxmlformats.org/presentationml/2006/main"
|
|
9470
|
-
}, [
|
|
9471
|
-
raw(cSld),
|
|
9472
|
-
raw(clrMap),
|
|
9473
|
-
raw(notesStyle)
|
|
9474
|
-
]);
|
|
9475
|
-
}
|
|
9476
|
-
/**
|
|
9477
|
-
* Creates Notes Slide (`ppt/notesSlides/notesSlide1.xml`)
|
|
9478
|
-
* @param {PresSlideInternal} slide - the slide object to transform into XML
|
|
9479
|
-
* @return {string} XML
|
|
9480
|
-
*/
|
|
9481
|
-
function makeXmlNotesSlide(slide) {
|
|
9482
|
-
buildNotesSlideRels(slide);
|
|
9483
|
-
const slideImgPh = el("p:sp", null, [raw(el("p:nvSpPr", null, [
|
|
9484
|
-
raw(voidEl("p:cNvPr", {
|
|
9485
|
-
id: 2,
|
|
9486
|
-
name: "Slide Image Placeholder 1"
|
|
9487
|
-
})),
|
|
9488
|
-
raw(el("p:cNvSpPr", null, raw(voidEl("a:spLocks", {
|
|
9489
|
-
noGrp: 1,
|
|
9490
|
-
noRot: 1,
|
|
9491
|
-
noChangeAspect: 1
|
|
9492
|
-
})))),
|
|
9493
|
-
raw(el("p:nvPr", null, raw(voidEl("p:ph", { type: "sldImg" }))))
|
|
9494
|
-
])), raw(voidEl("p:spPr"))]);
|
|
9495
|
-
const notesPh = el("p:sp", null, [
|
|
9496
|
-
raw(el("p:nvSpPr", null, [
|
|
9497
|
-
raw(voidEl("p:cNvPr", {
|
|
9498
|
-
id: 3,
|
|
9499
|
-
name: "Notes Placeholder 2"
|
|
9500
|
-
})),
|
|
9501
|
-
raw(el("p:cNvSpPr", null, raw(voidEl("a:spLocks", { noGrp: 1 })))),
|
|
9502
|
-
raw(el("p:nvPr", null, raw(voidEl("p:ph", {
|
|
9503
|
-
type: "body",
|
|
9504
|
-
idx: 1
|
|
9505
|
-
}))))
|
|
9506
|
-
])),
|
|
9507
|
-
raw(voidEl("p:spPr")),
|
|
9508
|
-
raw(el("p:txBody", null, [
|
|
9509
|
-
raw(voidEl("a:bodyPr")),
|
|
9510
|
-
raw(voidEl("a:lstStyle")),
|
|
9511
|
-
raw(genXmlNotesParagraphs(slide))
|
|
9512
|
-
]))
|
|
9513
|
-
]);
|
|
9514
|
-
const slideNumPh = el("p:sp", null, [
|
|
9515
|
-
raw(el("p:nvSpPr", null, [
|
|
9516
|
-
raw(voidEl("p:cNvPr", {
|
|
9517
|
-
id: 4,
|
|
9518
|
-
name: "Slide Number Placeholder 3"
|
|
9519
|
-
})),
|
|
9520
|
-
raw(el("p:cNvSpPr", null, raw(voidEl("a:spLocks", { noGrp: 1 })))),
|
|
9521
|
-
raw(el("p:nvPr", null, raw(voidEl("p:ph", {
|
|
9522
|
-
type: "sldNum",
|
|
9523
|
-
sz: "quarter",
|
|
9524
|
-
idx: 10
|
|
9525
|
-
}))))
|
|
9526
|
-
])),
|
|
9527
|
-
raw(voidEl("p:spPr")),
|
|
9528
|
-
raw(el("p:txBody", null, [
|
|
9529
|
-
raw(voidEl("a:bodyPr")),
|
|
9530
|
-
raw(voidEl("a:lstStyle")),
|
|
9531
|
-
raw(el("a:p", null, [raw(el("a:fld", {
|
|
9532
|
-
id: SLDNUMFLDID,
|
|
9533
|
-
type: "slidenum"
|
|
9534
|
-
}, [raw(voidEl("a:rPr", { lang: "en-US" })), raw(el("a:t", null, slide._slideNum))])), raw(voidEl("a:endParaRPr", { lang: "en-US" }))]))
|
|
9535
|
-
]))
|
|
9536
|
-
]);
|
|
9537
|
-
const spTree = el("p:spTree", null, [
|
|
9538
|
-
raw(el("p:nvGrpSpPr", null, [
|
|
9539
|
-
raw(voidEl("p:cNvPr", {
|
|
9540
|
-
id: 1,
|
|
9541
|
-
name: ""
|
|
9542
|
-
})),
|
|
9543
|
-
raw(voidEl("p:cNvGrpSpPr")),
|
|
9544
|
-
raw(voidEl("p:nvPr"))
|
|
9545
|
-
])),
|
|
9546
|
-
raw(el("p:grpSpPr", null, raw(el("a:xfrm", null, [
|
|
9547
|
-
raw(voidEl("a:off", {
|
|
9548
|
-
x: 0,
|
|
9549
|
-
y: 0
|
|
9550
|
-
})),
|
|
9551
|
-
raw(voidEl("a:ext", {
|
|
9552
|
-
cx: 0,
|
|
9553
|
-
cy: 0
|
|
9554
|
-
})),
|
|
9555
|
-
raw(voidEl("a:chOff", {
|
|
9556
|
-
x: 0,
|
|
9557
|
-
y: 0
|
|
9558
|
-
})),
|
|
9559
|
-
raw(voidEl("a:chExt", {
|
|
9560
|
-
cx: 0,
|
|
9561
|
-
cy: 0
|
|
9562
|
-
}))
|
|
9563
|
-
])))),
|
|
9564
|
-
raw(slideImgPh),
|
|
9565
|
-
raw(notesPh),
|
|
9566
|
-
raw(slideNumPh)
|
|
9567
|
-
]);
|
|
9568
|
-
const extLst = el("p:extLst", null, raw(el("p:ext", { uri: "{BB962C8B-B14F-4D97-AF65-F5344CB8AC3E}" }, raw(voidEl("p14:creationId", {
|
|
9569
|
-
"xmlns:p14": "http://schemas.microsoft.com/office/powerpoint/2010/main",
|
|
9570
|
-
val: 1024086991
|
|
9571
|
-
})))));
|
|
9572
|
-
const cSld = el("p:cSld", null, [raw(spTree), raw(extLst)]);
|
|
9573
|
-
return XML_DECL + "\r\n" + el("p:notes", {
|
|
9574
|
-
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
|
|
9575
|
-
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
9576
|
-
"xmlns:p": "http://schemas.openxmlformats.org/presentationml/2006/main"
|
|
9577
|
-
}, [raw(cSld), raw(el("p:clrMapOvr", null, raw(voidEl("a:masterClrMapping"))))]);
|
|
9578
|
-
}
|
|
9579
|
-
/**
|
|
9580
|
-
* Generates XML string for a notes-slide relation file (`ppt/notesSlides/_rels/notesSlideN.xml.rels`).
|
|
9581
|
-
* rId1=notesMaster and rId2=slide are always reserved; any notes hyperlink rels follow (rId3+).
|
|
9582
|
-
* @param {PresSlideInternal} slide - the slide whose notes part is being related
|
|
9583
|
-
* @param {number} slideNumber - 1-indexed slide number the notes part belongs to
|
|
9584
|
-
* @return {string} XML
|
|
9585
|
-
*/
|
|
9586
|
-
function makeXmlNotesSlideRel(slide, slideNumber) {
|
|
9587
|
-
const hlinkRels = buildNotesSlideRels(slide).map((rel) => voidEl("Relationship", {
|
|
9588
|
-
Id: `rId${rel.rId}`,
|
|
9589
|
-
Type: OFFICE_REL + "hyperlink",
|
|
9590
|
-
Target: rel.Target,
|
|
9591
|
-
TargetMode: "External"
|
|
9592
|
-
})).join("");
|
|
9593
|
-
return XML_DECL + el("Relationships", { xmlns: PACKAGE_REL_NS }, [
|
|
9594
|
-
raw(voidEl("Relationship", {
|
|
9595
|
-
Id: "rId1",
|
|
9596
|
-
Type: OFFICE_REL + "notesMaster",
|
|
9597
|
-
Target: "../notesMasters/notesMaster1.xml"
|
|
9598
|
-
})),
|
|
9599
|
-
raw(voidEl("Relationship", {
|
|
9600
|
-
Id: "rId2",
|
|
9601
|
-
Type: OFFICE_REL + "slide",
|
|
9602
|
-
Target: `../slides/slide${slideNumber}.xml`
|
|
9603
|
-
})),
|
|
9604
|
-
raw(hlinkRels)
|
|
9605
|
-
], {
|
|
9606
|
-
openPrefix: "\n ",
|
|
9607
|
-
childPrefix: "\n ",
|
|
9608
|
-
closePrefix: ""
|
|
9609
|
-
});
|
|
9610
|
-
}
|
|
9611
|
-
/**
|
|
9612
|
-
* Creates `ppt/notesMasters/_rels/notesMaster1.xml.rels`
|
|
9613
|
-
* @return {string} XML
|
|
9614
|
-
*/
|
|
9615
|
-
function makeXmlNotesMasterRel() {
|
|
9616
|
-
return XML_DECL + "\r\n" + el("Relationships", { xmlns: PACKAGE_REL_NS }, raw(voidEl("Relationship", {
|
|
9617
|
-
Id: "rId1",
|
|
9618
|
-
Type: OFFICE_REL + "theme",
|
|
9619
|
-
Target: "../theme/theme2.xml"
|
|
9620
|
-
})), {
|
|
9621
|
-
childPrefix: "\n ",
|
|
9622
|
-
closePrefix: "\n "
|
|
9623
|
-
});
|
|
9624
|
-
}
|
|
9625
|
-
//#endregion
|
|
9626
8216
|
//#region src/gen/pres/theme.ts
|
|
9627
8217
|
/**
|
|
9628
8218
|
* ts-pptx: `ppt/theme/theme1.xml`
|
|
@@ -9914,11 +8504,14 @@ function makeXmlApp(slides, company) {
|
|
|
9914
8504
|
* actually used by the deck (plus xlsx/font defaults when present) and Override
|
|
9915
8505
|
* entries for every written part.
|
|
9916
8506
|
*/
|
|
9917
|
-
|
|
8507
|
+
/** Content-type prefixes; spelled out per part below so each entry stays greppable by its suffix. */
|
|
8508
|
+
const OD = "application/vnd.openxmlformats-officedocument.";
|
|
8509
|
+
const PKG = "application/vnd.openxmlformats-package.";
|
|
8510
|
+
const CT_CHART = OD + "drawingml.chart+xml";
|
|
9918
8511
|
const CT_CHARTEX = "application/vnd.ms-office.chartex+xml";
|
|
9919
8512
|
const CT_CHARTEX_STYLE = "application/vnd.ms-office.chartstyle+xml";
|
|
9920
8513
|
const CT_CHARTEX_COLORS = "application/vnd.ms-office.chartcolorstyle+xml";
|
|
9921
|
-
const CT_THEME = "
|
|
8514
|
+
const CT_THEME = OD + "theme+xml";
|
|
9922
8515
|
/**
|
|
9923
8516
|
* Some Override entries have always been emitted with a leading space. It is insignificant
|
|
9924
8517
|
* whitespace, but it is in the bytes this library has shipped for years, so it is reproduced
|
|
@@ -9958,7 +8551,7 @@ function chartOverrides(rel, fmt) {
|
|
|
9958
8551
|
* @returns XML
|
|
9959
8552
|
*/
|
|
9960
8553
|
function makeXmlContTypes(slides, slideLayouts, masterSlide, hasCustomProps, embeddedFonts) {
|
|
9961
|
-
const parts = [contentDefault("xml", "application/xml"), contentDefault("rels", "
|
|
8554
|
+
const parts = [contentDefault("xml", "application/xml"), contentDefault("rels", PKG + "relationships+xml")];
|
|
9962
8555
|
const extnTypeMap = /* @__PURE__ */ new Map();
|
|
9963
8556
|
const ctTargets = [];
|
|
9964
8557
|
(slides || []).forEach((s) => ctTargets.push(s));
|
|
@@ -9976,45 +8569,45 @@ function makeXmlContTypes(slides, slideLayouts, masterSlide, hasCustomProps, emb
|
|
|
9976
8569
|
extnTypeMap.forEach((type, extn) => {
|
|
9977
8570
|
parts.push(contentDefault(extn, type));
|
|
9978
8571
|
});
|
|
9979
|
-
if (ctHasChart && !extnTypeMap.has("xlsx")) parts.push(contentDefault("xlsx", "
|
|
8572
|
+
if (ctHasChart && !extnTypeMap.has("xlsx")) parts.push(contentDefault("xlsx", OD + "spreadsheetml.sheet"));
|
|
9980
8573
|
if ((embeddedFonts || []).some((font) => font.faces.some((face) => face.bytes))) parts.push(contentDefault(FONT_DATA_EXTENSION, FONT_DATA_CONTENT_TYPE));
|
|
9981
|
-
parts.push(override("/ppt/presentation.xml", "
|
|
9982
|
-
parts.push(override("/ppt/notesMasters/notesMaster1.xml", "
|
|
9983
|
-
parts.push(override("/ppt/slideMasters/slideMaster1.xml", "
|
|
8574
|
+
parts.push(override("/ppt/presentation.xml", OD + "presentationml.presentation.main+xml"));
|
|
8575
|
+
parts.push(override("/ppt/notesMasters/notesMaster1.xml", OD + "presentationml.notesMaster+xml"));
|
|
8576
|
+
parts.push(override("/ppt/slideMasters/slideMaster1.xml", OD + "presentationml.slideMaster+xml"));
|
|
9984
8577
|
slides.forEach((slide, idx) => {
|
|
9985
|
-
parts.push(override(`/ppt/slides/slide${idx + 1}.xml`, "
|
|
8578
|
+
parts.push(override(`/ppt/slides/slide${idx + 1}.xml`, OD + "presentationml.slide+xml"));
|
|
9986
8579
|
slide._relsChart.forEach((rel) => {
|
|
9987
8580
|
parts.push(...chartOverrides(rel));
|
|
9988
8581
|
});
|
|
9989
8582
|
});
|
|
9990
|
-
parts.push(override("/ppt/presProps.xml", "
|
|
9991
|
-
parts.push(override("/ppt/viewProps.xml", "
|
|
8583
|
+
parts.push(override("/ppt/presProps.xml", OD + "presentationml.presProps+xml"));
|
|
8584
|
+
parts.push(override("/ppt/viewProps.xml", OD + "presentationml.viewProps+xml"));
|
|
9992
8585
|
parts.push(override("/ppt/theme/theme1.xml", CT_THEME));
|
|
9993
8586
|
parts.push(override("/ppt/theme/theme2.xml", CT_THEME));
|
|
9994
|
-
parts.push(override("/ppt/tableStyles.xml", "
|
|
8587
|
+
parts.push(override("/ppt/tableStyles.xml", OD + "presentationml.tableStyles+xml"));
|
|
9995
8588
|
slideLayouts.forEach((layout, idx) => {
|
|
9996
|
-
parts.push(override(`/ppt/slideLayouts/slideLayout${idx + 1}.xml`, "
|
|
8589
|
+
parts.push(override(`/ppt/slideLayouts/slideLayout${idx + 1}.xml`, OD + "presentationml.slideLayout+xml"));
|
|
9997
8590
|
(layout._relsChart || []).forEach((rel) => {
|
|
9998
8591
|
parts.push(...chartOverrides(rel, LEADING_SPACE));
|
|
9999
8592
|
});
|
|
10000
8593
|
});
|
|
10001
8594
|
slides.forEach((_slide, idx) => {
|
|
10002
|
-
parts.push(override(`/ppt/notesSlides/notesSlide${idx + 1}.xml`, "
|
|
8595
|
+
parts.push(override(`/ppt/notesSlides/notesSlide${idx + 1}.xml`, OD + "presentationml.notesSlide+xml"));
|
|
10003
8596
|
});
|
|
10004
8597
|
let hasAnyComment = false;
|
|
10005
8598
|
slides.forEach((slide, idx) => {
|
|
10006
8599
|
if ((slide._comments || []).length > 0) {
|
|
10007
8600
|
hasAnyComment = true;
|
|
10008
|
-
parts.push(override(`/ppt/comments/comment${idx + 1}.xml`, "
|
|
8601
|
+
parts.push(override(`/ppt/comments/comment${idx + 1}.xml`, OD + "presentationml.comments+xml"));
|
|
10009
8602
|
}
|
|
10010
8603
|
});
|
|
10011
|
-
if (hasAnyComment) parts.push(override("/ppt/commentAuthors.xml", "
|
|
8604
|
+
if (hasAnyComment) parts.push(override("/ppt/commentAuthors.xml", OD + "presentationml.commentAuthors+xml"));
|
|
10012
8605
|
masterSlide?._relsChart.forEach((rel) => {
|
|
10013
8606
|
parts.push(...chartOverrides(rel, LEADING_SPACE));
|
|
10014
8607
|
});
|
|
10015
|
-
parts.push(override("/docProps/core.xml", "
|
|
10016
|
-
parts.push(override("/docProps/app.xml", "
|
|
10017
|
-
if (hasCustomProps) parts.push(override("/docProps/custom.xml", "
|
|
8608
|
+
parts.push(override("/docProps/core.xml", PKG + "core-properties+xml", LEADING_SPACE));
|
|
8609
|
+
parts.push(override("/docProps/app.xml", OD + "extended-properties+xml", LEADING_SPACE));
|
|
8610
|
+
if (hasCustomProps) parts.push(override("/docProps/custom.xml", OD + "custom-properties+xml", LEADING_SPACE));
|
|
10018
8611
|
return XML_DECL + "\r\n" + el("Types", { xmlns: "http://schemas.openxmlformats.org/package/2006/content-types" }, parts.map(raw));
|
|
10019
8612
|
}
|
|
10020
8613
|
//#endregion
|
|
@@ -10563,7 +9156,7 @@ function masterAlignAttr(align) {
|
|
|
10563
9156
|
case "right": return "r";
|
|
10564
9157
|
case "center": return "ctr";
|
|
10565
9158
|
case "justify": return "just";
|
|
10566
|
-
|
|
9159
|
+
case void 0: return "";
|
|
10567
9160
|
}
|
|
10568
9161
|
}
|
|
10569
9162
|
/** Build the bullet element for a master level: caller override wins over the level default. */
|
|
@@ -10571,10 +9164,14 @@ function masterBulletXml(bulletOverride, base) {
|
|
|
10571
9164
|
if (bulletOverride === false) return voidEl("a:buNone");
|
|
10572
9165
|
if (bulletOverride && typeof bulletOverride === "object") {
|
|
10573
9166
|
const font = bulletOverride.fontFace ? voidEl("a:buFont", { typeface: bulletOverride.fontFace }) : "";
|
|
10574
|
-
if (bulletOverride.type === "number")
|
|
10575
|
-
type
|
|
10576
|
-
startAt
|
|
10577
|
-
|
|
9167
|
+
if (bulletOverride.type === "number") {
|
|
9168
|
+
const type = bulletOverride.numberType || "arabicPeriod";
|
|
9169
|
+
const startAt = typeof bulletOverride.numberStartAt === "number" ? Math.round(bulletOverride.numberStartAt) : null;
|
|
9170
|
+
return font + voidEl("a:buAutoNum", {
|
|
9171
|
+
type,
|
|
9172
|
+
startAt
|
|
9173
|
+
});
|
|
9174
|
+
}
|
|
10578
9175
|
const char = bulletOverride.characterCode ? `&#x${bulletOverride.characterCode};` : "•";
|
|
10579
9176
|
return `${bulletOverride.fontFace ? font : voidEl("a:buFont", {
|
|
10580
9177
|
typeface: "Arial",
|
|
@@ -10596,8 +9193,10 @@ function masterLevelXml(levelNum, base, levelOverride = {}) {
|
|
|
10596
9193
|
const indentEmu = typeof levelOverride.indent === "number" && !isNaN(levelOverride.indent) ? inch2Emu(levelOverride.indent) : base.indent;
|
|
10597
9194
|
const algn = levelOverride.align && masterAlignAttr(levelOverride.align) || base.algn;
|
|
10598
9195
|
let sz = base.sz;
|
|
10599
|
-
if (typeof levelOverride.fontSize === "number")
|
|
10600
|
-
|
|
9196
|
+
if (typeof levelOverride.fontSize === "number") {
|
|
9197
|
+
if (isNaN(levelOverride.fontSize) || levelOverride.fontSize <= 0) warn("master/invalid-text-style-font-size", `master textStyles fontSize "${levelOverride.fontSize}" is invalid; keeping default ${base.sz / 100}pt.`);
|
|
9198
|
+
else sz = ptToHundredths(levelOverride.fontSize);
|
|
9199
|
+
}
|
|
10601
9200
|
const colorXml = levelOverride.color ? createColorElement(levelOverride.color) : voidEl("a:schemeClr", { val: "tx1" });
|
|
10602
9201
|
const latinXml = levelOverride.fontFace ? voidEl("a:latin", { typeface: levelOverride.fontFace }) : voidEl("a:latin", { typeface: `+${base.font}-lt` });
|
|
10603
9202
|
return el(`a:lvl${levelNum}pPr`, {
|
|
@@ -10980,8 +9579,7 @@ async function zipPackageParts(parts, props) {
|
|
|
10980
9579
|
const zip = new ZipWriter();
|
|
10981
9580
|
for (const part of parts) zip.add(part.path, part.data, { store: part.store });
|
|
10982
9581
|
const compression = props.compression !== false;
|
|
10983
|
-
if (props.outputType
|
|
10984
|
-
else if (props.outputType) return await zip.generate(props.outputType, { compression });
|
|
9582
|
+
if (props.outputType) return await zip.generate(props.outputType, { compression });
|
|
10985
9583
|
else return await zip.generate("blob", { compression });
|
|
10986
9584
|
}
|
|
10987
9585
|
/**
|
|
@@ -11008,7 +9606,7 @@ async function writePackage(source, props) {
|
|
|
11008
9606
|
* the OfficeGen project (Copyright 2013 Ziv Barber). This project is likewise MIT; the full
|
|
11009
9607
|
* license text is in `LICENSE` at the repository root.
|
|
11010
9608
|
*/
|
|
11011
|
-
const VERSION = "3.
|
|
9609
|
+
const VERSION = "3.3.0";
|
|
11012
9610
|
function standardLayoutToPresLayout(layout) {
|
|
11013
9611
|
return {
|
|
11014
9612
|
name: layout.name,
|
|
@@ -11389,11 +9987,23 @@ var PresentationCore = class {
|
|
|
11389
9987
|
rId: rel.rId,
|
|
11390
9988
|
sourceSlideNumber: Number(rel.Target)
|
|
11391
9989
|
}));
|
|
11392
|
-
const charts = (slide._relsChart || []).map((rel) =>
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
9990
|
+
const charts = (slide._relsChart || []).map((rel) => {
|
|
9991
|
+
const base = {
|
|
9992
|
+
rId: rel.rId,
|
|
9993
|
+
embeddingBytes: buildEmbeddedWorksheet(rel)
|
|
9994
|
+
};
|
|
9995
|
+
return rel.isChartEx ? {
|
|
9996
|
+
...base,
|
|
9997
|
+
chartXml: makeXmlChartEx(rel),
|
|
9998
|
+
chartEx: {
|
|
9999
|
+
styleXml: makeChartExStyleXml(),
|
|
10000
|
+
colorsXml: makeChartExColorsXml()
|
|
10001
|
+
}
|
|
10002
|
+
} : {
|
|
10003
|
+
...base,
|
|
10004
|
+
chartXml: makeXmlCharts(rel)
|
|
10005
|
+
};
|
|
10006
|
+
});
|
|
11397
10007
|
const notes = slide._slideObjects.some((obj) => obj._type === "notes") ? {
|
|
11398
10008
|
xml: makeXmlNotesSlide(slide),
|
|
11399
10009
|
hyperlinks: buildNotesSlideRels(slide).filter((rel) => typeof rel.Target === "string" && rel.Target).map((rel) => ({
|
|
@@ -11432,19 +10042,36 @@ var PresentationCore = class {
|
|
|
11432
10042
|
* Without registered metrics, `fit:'shrink'` keeps its current behavior (a bare
|
|
11433
10043
|
* `<a:normAutofit/>` that only PowerPoint recomputes on edit). Register the same
|
|
11434
10044
|
* face once per weight/style you use; bold/italic advances differ.
|
|
10045
|
+
*
|
|
10046
|
+
* **Font collections** (`.ttc`/`.otc`, how MS Gothic, Yu Gothic, SimSun, Microsoft
|
|
10047
|
+
* YaHei and Cambria ship on Windows) hold several fonts in one file, so one has to be
|
|
10048
|
+
* chosen. With no `font` option, `face` is used as the selector, which is usually what
|
|
10049
|
+
* you meant; a `face` that names no font in the collection throws rather than falling
|
|
10050
|
+
* back to the first, since measuring the wrong member is invisible downstream. Pass
|
|
10051
|
+
* `font` when the deck-side name differs from the name inside the file, and use
|
|
10052
|
+
* `listFontFaces` from `ts-pptx/measure` to see what a file holds.
|
|
11435
10053
|
* @param {string} face - font family name as used in `fontFace` (e.g. 'Aptos')
|
|
11436
|
-
* @param {string | Uint8Array | ArrayBuffer} source - font file path/URL (Node/web) or raw TTF/OTF bytes
|
|
11437
|
-
* @param {object} [opts] - variant flags
|
|
10054
|
+
* @param {string | Uint8Array | ArrayBuffer} source - font file path/URL (Node/web) or raw TTF/OTF/TTC bytes
|
|
10055
|
+
* @param {object} [opts] - variant flags (advances differ per weight/style) and collection selection
|
|
10056
|
+
* @param {boolean} [opts.bold] - these are the bold advances
|
|
10057
|
+
* @param {boolean} [opts.italic] - these are the italic advances
|
|
10058
|
+
* @param {number | string} [opts.font] - which font inside a collection: 0-based index, or a name
|
|
11438
10059
|
* @example await pptx.registerFontMetrics('Aptos', '/usr/share/fonts/Aptos.ttf')
|
|
11439
10060
|
* @example await pptx.registerFontMetrics('Aptos', aptosBoldBytes, { bold: true })
|
|
10061
|
+
* @example await pptx.registerFontMetrics('MS PGothic', 'C:/Windows/Fonts/msgothic.ttc')
|
|
10062
|
+
* @example await pptx.registerFontMetrics('Cambria Math', 'C:/Windows/Fonts/cambria.ttc', { font: 1 })
|
|
11440
10063
|
*/
|
|
11441
10064
|
async registerFontMetrics(face, source, opts) {
|
|
11442
10065
|
let bytes;
|
|
11443
10066
|
if (typeof source === "string") bytes = await this._runtime.loadFontData(source);
|
|
11444
10067
|
else if (source instanceof Uint8Array) bytes = source;
|
|
11445
10068
|
else bytes = new Uint8Array(source);
|
|
11446
|
-
const
|
|
11447
|
-
|
|
10069
|
+
const font = opts?.font ?? (isFontCollection(bytes) ? face : void 0);
|
|
10070
|
+
const metrics = await parseFontMetrics(bytes, font === void 0 ? void 0 : { font });
|
|
10071
|
+
this._fontMetrics.set(face, metrics, {
|
|
10072
|
+
bold: opts?.bold,
|
|
10073
|
+
italic: opts?.italic
|
|
10074
|
+
});
|
|
11448
10075
|
}
|
|
11449
10076
|
/**
|
|
11450
10077
|
* Embed a font face so the deck renders with it even on machines that do not
|
|
@@ -11500,7 +10127,7 @@ var PresentationCore = class {
|
|
|
11500
10127
|
* Measure how tall text wraps at a given width, using the **same** calibrated wrap
|
|
11501
10128
|
* model the export-time autofit bake uses — so a layout-time prediction matches the
|
|
11502
10129
|
* value `fit:'shrink'`/`'resize'` would bake. Synchronous: register the face's metrics
|
|
11503
|
-
* first with {@link
|
|
10130
|
+
* first with {@link TsPptx.registerFontMetrics} (lookup is sync).
|
|
11504
10131
|
*
|
|
11505
10132
|
* Lets a consumer size its own geometry before export — grow a card to fit its text,
|
|
11506
10133
|
* reflow a grid, or detect overflow at layout time. Heights err **tall** (conservative),
|
|
@@ -11534,8 +10161,8 @@ var PresentationCore = class {
|
|
|
11534
10161
|
* cells. Column widths (cell `x`/`w`) are exact, derived from the same logic the
|
|
11535
10162
|
* writer uses. Row heights (`y`/`h`) are exact when pinned by `rowH` (array or
|
|
11536
10163
|
* scalar) or table `h`; an auto-height row is estimated with the same conservative
|
|
11537
|
-
* (tall) text model as {@link
|
|
11538
|
-
* (register the cell font via {@link
|
|
10164
|
+
* (tall) text model as {@link TsPptx.measureText} and flagged `heightExact:false`
|
|
10165
|
+
* (register the cell font via {@link TsPptx.registerFontMetrics} for an exact
|
|
11539
10166
|
* estimate). Geometry is for a single, un-paginated table — `autoPage` paging is
|
|
11540
10167
|
* not modeled.
|
|
11541
10168
|
* @param {TableRow[]} rows - the same `rows` passed to `slide.addTable`
|
|
@@ -11550,14 +10177,18 @@ var PresentationCore = class {
|
|
|
11550
10177
|
return computeTableLayout(rows, opts, this._presLayout, this._fontMetrics);
|
|
11551
10178
|
}
|
|
11552
10179
|
/**
|
|
11553
|
-
* Export the current
|
|
10180
|
+
* Export the current presentation as portable ZIP bytes. Unlike the former
|
|
10181
|
+
* `stream()` method, this does not imply incremental output or convert the
|
|
10182
|
+
* archive to a Node `Buffer`: package assembly is synchronous and the returned
|
|
10183
|
+
* `Uint8Array` works unchanged in Node, browsers, and workers.
|
|
11554
10184
|
* @param {WriteBaseProps} props - output properties
|
|
11555
|
-
* @returns {Promise<
|
|
10185
|
+
* @returns {Promise<Uint8Array>} complete `.pptx` archive bytes
|
|
11556
10186
|
*/
|
|
11557
|
-
async
|
|
10187
|
+
async toBytes(props) {
|
|
11558
10188
|
return await writePackage(this.packageSource(), {
|
|
11559
10189
|
compression: props?.compression,
|
|
11560
|
-
outputType: "
|
|
10190
|
+
outputType: "uint8array",
|
|
10191
|
+
onMediaError: props?.onMediaError
|
|
11561
10192
|
});
|
|
11562
10193
|
}
|
|
11563
10194
|
/**
|
|
@@ -11896,4 +10527,4 @@ function textRuns(runs) {
|
|
|
11896
10527
|
//#endregion
|
|
11897
10528
|
export { PresentationCore as i, textRuns as n, clipPath as r, textRun as t };
|
|
11898
10529
|
|
|
11899
|
-
//# sourceMappingURL=text-
|
|
10530
|
+
//# sourceMappingURL=text-uM-zGton.js.map
|