@shbernal/ts-pptx 3.3.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{autopage-D1sqK6j7.js → autopage-BYlTzX-l.js} +8 -5
- package/dist/autopage-BYlTzX-l.js.map +1 -0
- package/dist/browser.d.ts +5 -5
- package/dist/browser.js +11 -11
- package/dist/browser.js.map +1 -1
- package/dist/{diagnostics-B2yWpcjB.d.ts → diagnostics-BDuR8UkG.d.ts} +39 -7
- package/dist/diagnostics-BDuR8UkG.d.ts.map +1 -0
- package/dist/{diagnostics-H1QzgRSw.js → diagnostics-CPVADSL1.js} +29 -3
- package/dist/{diagnostics-H1QzgRSw.js.map → diagnostics-CPVADSL1.js.map} +1 -1
- package/dist/{errors-fB1KDJKQ.d.ts → errors-CgnueTYL.d.ts} +3 -3
- package/dist/{errors-fB1KDJKQ.d.ts.map → errors-CgnueTYL.d.ts.map} +1 -1
- package/dist/{fit-CYJ1jkQI.js → fit-TjpNbMru.js} +3 -3
- package/dist/{fit-CYJ1jkQI.js.map → fit-TjpNbMru.js.map} +1 -1
- package/dist/{html-dom-CzewEdE1.js → html-dom-yUSdCExA.js} +5 -5
- package/dist/html-dom-yUSdCExA.js.map +1 -0
- package/dist/html.d.ts +3 -3
- package/dist/html.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +16 -33
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +28 -4
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +43 -10
- package/dist/inspect.js.map +1 -1
- package/dist/math.d.ts +1 -1
- package/dist/measure.d.ts +2 -2
- package/dist/measure.js +1 -1
- package/dist/{st-enums-bVnezkMJ.js → namespaces-CcKuzeuE.js} +291 -200
- package/dist/namespaces-CcKuzeuE.js.map +1 -0
- package/dist/node.d.ts +5 -5
- package/dist/node.js +7 -19
- package/dist/node.js.map +1 -1
- package/dist/{notes-SCvpJz0l.js → notes-DNqAggXx.js} +221 -140
- package/dist/notes-DNqAggXx.js.map +1 -0
- package/dist/{pres-Cb-1xDne.d.ts → pres-Dybf7ZUl.d.ts} +2 -2
- package/dist/{pres-Cb-1xDne.d.ts.map → pres-Dybf7ZUl.d.ts.map} +1 -1
- package/dist/{presentation-DeKTJGHf.js → presentation-VfJ_FT7E.js} +306 -234
- package/dist/presentation-VfJ_FT7E.js.map +1 -0
- package/dist/{presentation-types-B50aOUFI.d.ts → presentation-types-CpkTx9Xa.d.ts} +352 -16
- package/dist/presentation-types-CpkTx9Xa.d.ts.map +1 -0
- package/dist/read.d.ts +4 -4
- package/dist/read.js +3 -3
- package/dist/script.d.ts +2 -2
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +128 -63
- package/dist/script.js.map +1 -1
- package/dist/{shapes-BXVgsk0F.js → shapes-Kt51vry6.js} +717 -54
- package/dist/shapes-Kt51vry6.js.map +1 -0
- package/dist/{slide-DWw9UoI6.d.ts → slide-B_aInw3N.d.ts} +208 -180
- package/dist/slide-B_aInw3N.d.ts.map +1 -0
- package/dist/{text-uM-zGton.js → text-D04NUMvA.js} +3563 -3437
- package/dist/text-D04NUMvA.js.map +1 -0
- package/dist/{units-internal-CGf4VrXy.js → units-internal-DNvK2I6o.js} +54 -34
- package/dist/{units-internal-CGf4VrXy.js.map → units-internal-DNvK2I6o.js.map} +1 -1
- package/dist/zip.d.ts +1 -1
- package/package.json +4 -4
- package/dist/autopage-D1sqK6j7.js.map +0 -1
- package/dist/diagnostics-B2yWpcjB.d.ts.map +0 -1
- package/dist/html-dom-CzewEdE1.js.map +0 -1
- package/dist/notes-SCvpJz0l.js.map +0 -1
- package/dist/presentation-DeKTJGHf.js.map +0 -1
- package/dist/presentation-types-B50aOUFI.d.ts.map +0 -1
- package/dist/shapes-BXVgsk0F.js.map +0 -1
- package/dist/slide-DWw9UoI6.d.ts.map +0 -1
- package/dist/st-enums-bVnezkMJ.js.map +0 -1
- package/dist/text-uM-zGton.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError } from "./errors-Bvln0H-7.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { _ as
|
|
2
|
+
import { mt as emuToInches } from "./units-internal-DNvK2I6o.js";
|
|
3
|
+
import { D as voidEl, E as raw, T as el, g as FONT_REL_TYPE, h as FONT_DATA_EXTENSION, m as FONT_DATA_CONTENT_TYPE, n as makeXmlNotesMaster, o as makeXmlNotesSlideSkeleton, p as EMBEDDED_FONT_SLOTS } from "./notes-DNqAggXx.js";
|
|
4
|
+
import { _ as THEME_CONTENT_TYPE, a as NOTES_MASTER_REL, c as OFFICE_DOCUMENT_REL, d as SLIDE_CONTENT_TYPE, f as SLIDE_LAYOUT_CONTENT_TYPE, g as SLIDE_REL, h as SLIDE_MASTER_REL, i as NOTES_MASTER_CONTENT_TYPE, l as OFFICE_REL, m as SLIDE_MASTER_CONTENT_TYPE, o as NOTES_SLIDE_CONTENT_TYPE, p as SLIDE_LAYOUT_REL, r as IMAGE_REL, s as NOTES_SLIDE_REL, t as OOXML_NS, v as THEME_REL } from "./namespaces-CcKuzeuE.js";
|
|
5
5
|
import { ZipWriter, readZip } from "./zip.js";
|
|
6
|
-
import { $ as
|
|
6
|
+
import { $ as carriedDecorations, A as spPrXfrmEmu, At as resolveSingleRel, Bt as getElements, Ct as SPPR_SCENE3D_AFTER, Dt as relativePartName, Et as partNameToZipPath, F as resolveLayoutColorContext, Ft as createElement, G as placeholderInheritedListStyles, Gt as parseXml, H as RUN_PROP_NAMES, Ht as insertInOrder, I as resolveMasterColorContext, It as descendantsByTag, J as placeholderOf, Jt as replaceInParent, K as placeholderInheritedRunProps, Kt as removeAttr, L as resolveNotesColorContext, Lt as escapeXmlAttribute, M as readPictureFill, Mt as attr, N as readGradientFill, Nt as boolValue, Ot as relsPartNameFor, P as resolveColorElement, Pt as childElements, Q as cSldOf, R as resolveSlideColorContext, Rt as firstChild, St as SPPR_LN_AFTER, T as AutoShape, Tt as partNameExtension, U as placeholderInheritedAnchor, Ut as intValue, V as LST_STYLE_LEVELS, Vt as getOrAddChild, W as placeholderInheritedColor, Wt as ownerDocumentOf, X as slideDefinesProp, Xt as setAttr, Y as slideDefinesColor, Yt as serializeXml, Z as cSldName, _t as RPR_FILL_AFTER, at as SCHEME_SLOTS, bt as SPPR_EFFECT_AFTER, ct as isA, dt as resolveColor, et as collectElements, ft as resolveSchemeToken, gt as FILL_CHOICES, ht as substitutePhClr, it as spTreeOf, j as readPatternFill, jt as zipPathToPartName, k as TextFrame, kt as resolveRelativePartName, l as wrapShapeElement, lt as parseClrMap, mt as styleRefLine, n as buildShapes, nt as nthShapeChild, ot as fmtEntry, pt as styleRefFill, q as placeholderInheritedXfrm, qt as removeChildrenByQName, r as findShapeByIdDeep, rt as nvPrOf, st as intAttr, t as GroupShape, tt as firstShapeChild, u as GraphicFrame, ut as parseClrScheme, vt as SHAPE_AFTER_SPPR, w as Picture, wt as SPPR_SP3D_AFTER, xt as SPPR_FILL_AFTER, yt as SPPR_AFTER_XFRM, z as resolveSlideThemeParts, zt as firstChildElement } from "./shapes-Kt51vry6.js";
|
|
7
7
|
//#region src/read/opc/content-types.ts
|
|
8
8
|
/**
|
|
9
9
|
* Overlay over `[Content_Types].xml`, used to resolve part content types at
|
|
@@ -594,7 +594,7 @@ function reverseClrMap(clrMap) {
|
|
|
594
594
|
function applyInheritedBackground(slideRoot, ctx) {
|
|
595
595
|
const inherited = ctx.inheritedBackground;
|
|
596
596
|
if (!inherited) return;
|
|
597
|
-
const cSld =
|
|
597
|
+
const cSld = cSldOf(slideRoot);
|
|
598
598
|
if (!cSld || firstChild(cSld, "p:bg")) return;
|
|
599
599
|
const bg = ownerDocumentOf(slideRoot).importNode(inherited, true);
|
|
600
600
|
insertInOrder(cSld, bg, [
|
|
@@ -644,6 +644,28 @@ function resolveSchemeColors(root, ctx) {
|
|
|
644
644
|
* re-bind to the destination styles.
|
|
645
645
|
*/
|
|
646
646
|
function resolvePlaceholderRunColors(slideRoot, ctx) {
|
|
647
|
+
bakePlaceholderRunProperty(slideRoot, ctx, placeholderInheritedColor, (run, color, pPr, slideLst, level) => {
|
|
648
|
+
if (slideDefinesColor(run, pPr, slideLst, level)) return;
|
|
649
|
+
writeRunColor(run, color);
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* The traversal both run-property passes share: every placeholder shape's text body, every
|
|
654
|
+
* paragraph in it, every `a:r` and `a:fld` in that paragraph.
|
|
655
|
+
*
|
|
656
|
+
* `resolve` is asked once per *list level* per shape and memoized, because walking the
|
|
657
|
+
* layout/master style chain is the expensive half and every paragraph at the same level gets
|
|
658
|
+
* the same answer. `write` then runs per run, and owns the decision to skip a run the slide
|
|
659
|
+
* already fixes — the two passes ask that question differently (one colour check versus three
|
|
660
|
+
* independent property checks), so it stays on their side of the boundary rather than becoming
|
|
661
|
+
* a predicate parameter only one caller could use.
|
|
662
|
+
*
|
|
663
|
+
* @param slideRoot - the slide part's root element
|
|
664
|
+
* @param ctx - the flatten context, carrying the source layout/master roots
|
|
665
|
+
* @param resolve - the inherited value for a placeholder type/idx at a list level, or `null`
|
|
666
|
+
* @param write - apply a resolved value to one run
|
|
667
|
+
*/
|
|
668
|
+
function bakePlaceholderRunProperty(slideRoot, ctx, resolve, write) {
|
|
647
669
|
if (!ctx.layoutRoot && !ctx.masterRoot) return;
|
|
648
670
|
for (const sp of descendantsByTag(slideRoot, OOXML_NS.p, "sp")) {
|
|
649
671
|
const ph = placeholderOf(sp);
|
|
@@ -659,16 +681,13 @@ function resolvePlaceholderRunColors(slideRoot, ctx) {
|
|
|
659
681
|
const level = (pPr && intValue(attr(pPr, "lvl"))) ?? 0;
|
|
660
682
|
const runs = [...getElements(p, "a:r"), ...getElements(p, "a:fld")];
|
|
661
683
|
if (runs.length === 0) continue;
|
|
662
|
-
let
|
|
663
|
-
if (
|
|
664
|
-
|
|
665
|
-
byLevel.set(level,
|
|
666
|
-
}
|
|
667
|
-
if (!color) continue;
|
|
668
|
-
for (const run of runs) {
|
|
669
|
-
if (slideDefinesColor(run, pPr, slideLst, level)) continue;
|
|
670
|
-
writeRunColor(run, color);
|
|
684
|
+
let value = byLevel.get(level);
|
|
685
|
+
if (value === void 0) {
|
|
686
|
+
value = resolve(type, idx, level, ctx);
|
|
687
|
+
byLevel.set(level, value);
|
|
671
688
|
}
|
|
689
|
+
if (!value) continue;
|
|
690
|
+
for (const run of runs) write(run, value, pPr, slideLst, level);
|
|
672
691
|
}
|
|
673
692
|
}
|
|
674
693
|
}
|
|
@@ -788,8 +807,7 @@ function resolvePlaceholderListStyle(shapeRoot, ctx) {
|
|
|
788
807
|
*/
|
|
789
808
|
function demotePlaceholders(shapeRoot) {
|
|
790
809
|
for (const sp of descendantsByTag(shapeRoot, OOXML_NS.p, "sp")) {
|
|
791
|
-
const
|
|
792
|
-
const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
|
|
810
|
+
const nvPr = nvPrOf(sp);
|
|
793
811
|
if (nvPr) removeChildrenByQName(nvPr, ["p:ph"]);
|
|
794
812
|
}
|
|
795
813
|
}
|
|
@@ -803,30 +821,7 @@ function demotePlaceholders(shapeRoot) {
|
|
|
803
821
|
* is left to re-bind to the destination theme, as the colour pass does for the `fontRef`.
|
|
804
822
|
*/
|
|
805
823
|
function resolvePlaceholderRunSizes(slideRoot, ctx) {
|
|
806
|
-
|
|
807
|
-
for (const sp of descendantsByTag(slideRoot, OOXML_NS.p, "sp")) {
|
|
808
|
-
const ph = placeholderOf(sp);
|
|
809
|
-
if (!ph) continue;
|
|
810
|
-
const txBody = firstChild(sp, "p:txBody");
|
|
811
|
-
if (!txBody) continue;
|
|
812
|
-
const type = attr(ph, "type");
|
|
813
|
-
const idx = attr(ph, "idx") ?? "0";
|
|
814
|
-
const slideLst = firstChild(txBody, "a:lstStyle");
|
|
815
|
-
const byLevel = /* @__PURE__ */ new Map();
|
|
816
|
-
for (const p of getElements(txBody, "a:p")) {
|
|
817
|
-
const pPr = firstChild(p, "a:pPr");
|
|
818
|
-
const level = (pPr && intValue(attr(pPr, "lvl"))) ?? 0;
|
|
819
|
-
const runs = [...getElements(p, "a:r"), ...getElements(p, "a:fld")];
|
|
820
|
-
if (runs.length === 0) continue;
|
|
821
|
-
let props = byLevel.get(level);
|
|
822
|
-
if (props === void 0) {
|
|
823
|
-
props = placeholderInheritedRunProps(type, idx, level, ctx);
|
|
824
|
-
byLevel.set(level, props);
|
|
825
|
-
}
|
|
826
|
-
if (!props) continue;
|
|
827
|
-
for (const run of runs) writeRunProps(run, props, pPr, slideLst, level);
|
|
828
|
-
}
|
|
829
|
-
}
|
|
824
|
+
bakePlaceholderRunProperty(slideRoot, ctx, placeholderInheritedRunProps, writeRunProps);
|
|
830
825
|
}
|
|
831
826
|
/** Write each resolved run property onto a run's `a:rPr`, skipping ones the slide already fixes. */
|
|
832
827
|
function writeRunProps(run, props, pPr, slideLst, level) {
|
|
@@ -907,7 +902,7 @@ function neutralizeRef(ref) {
|
|
|
907
902
|
*/
|
|
908
903
|
/** The `p:cSld/p:bg` element of a slide/layout/master root, or `null`. */
|
|
909
904
|
function backgroundElementOf(root) {
|
|
910
|
-
const cSld =
|
|
905
|
+
const cSld = cSldOf(root);
|
|
911
906
|
return cSld ? firstChild(cSld, "p:bg") : null;
|
|
912
907
|
}
|
|
913
908
|
/**
|
|
@@ -1012,8 +1007,7 @@ var NotesPlaceholder = class {
|
|
|
1012
1007
|
this.relationships = relationships;
|
|
1013
1008
|
}
|
|
1014
1009
|
#ph() {
|
|
1015
|
-
const
|
|
1016
|
-
const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
|
|
1010
|
+
const nvPr = nvPrOf(this.sp);
|
|
1017
1011
|
return nvPr ? firstChild(nvPr, "p:ph") : null;
|
|
1018
1012
|
}
|
|
1019
1013
|
#cNvPr() {
|
|
@@ -1147,12 +1141,26 @@ var NotesSlide = class {
|
|
|
1147
1141
|
return this.placeholders.find((ph) => ph.type === type) ?? null;
|
|
1148
1142
|
}
|
|
1149
1143
|
#spTree() {
|
|
1150
|
-
|
|
1151
|
-
const cSld = root && firstChild(root, "p:cSld");
|
|
1152
|
-
return cSld ? firstChild(cSld, "p:spTree") : null;
|
|
1144
|
+
return spTreeOf(this.part.dom.documentElement);
|
|
1153
1145
|
}
|
|
1154
1146
|
};
|
|
1155
1147
|
//#endregion
|
|
1148
|
+
//#region src/read/api/ops/deck-target.ts
|
|
1149
|
+
/**
|
|
1150
|
+
* `ppt/_rels/presentation.xml.rels` -- the deck's own relationship part.
|
|
1151
|
+
*
|
|
1152
|
+
* Every part that masters, layouts, the notes master and embedded fonts hang off
|
|
1153
|
+
* is reached through here, so the two-step `dest.presentationPart` ->
|
|
1154
|
+
* `dest.opc.relationshipsFor(part.partName)` was written out at every one of
|
|
1155
|
+
* those wiring sites. Naming it once means a call site says which rels it wants
|
|
1156
|
+
* rather than how to find them.
|
|
1157
|
+
* @param {DeckTarget} dest - the destination deck
|
|
1158
|
+
* @returns {Relationships} the presentation part's relationships
|
|
1159
|
+
*/
|
|
1160
|
+
function presentationRels(dest) {
|
|
1161
|
+
return dest.opc.relationshipsFor(dest.presentationPart.partName);
|
|
1162
|
+
}
|
|
1163
|
+
//#endregion
|
|
1156
1164
|
//#region src/read/api/ops/master-registry.ts
|
|
1157
1165
|
/**
|
|
1158
1166
|
* Slide-master bookkeeping in `presentation.xml` and in a master's own
|
|
@@ -1175,7 +1183,7 @@ var NotesSlide = class {
|
|
|
1175
1183
|
*/
|
|
1176
1184
|
function registerMaster(dest, masterPartName) {
|
|
1177
1185
|
const presPart = dest.presentationPart;
|
|
1178
|
-
const presRels = dest
|
|
1186
|
+
const presRels = presentationRels(dest);
|
|
1179
1187
|
for (const rel of presRels.byType(SLIDE_MASTER_REL)) if (presRels.resolveTarget(rel.id) === masterPartName) return;
|
|
1180
1188
|
const relId = presRels.add(SLIDE_MASTER_REL, relativePartName(presPart.partName, masterPartName)).id;
|
|
1181
1189
|
const root = presPart.dom.documentElement;
|
|
@@ -1214,7 +1222,7 @@ function promoteMasters(dest, masterPartNames) {
|
|
|
1214
1222
|
const root = presPart.dom.documentElement;
|
|
1215
1223
|
const lst = root && firstChild(root, "p:sldMasterIdLst");
|
|
1216
1224
|
if (!lst) return;
|
|
1217
|
-
const rels = dest
|
|
1225
|
+
const rels = presentationRels(dest);
|
|
1218
1226
|
const promote = new Set(masterPartNames);
|
|
1219
1227
|
const entries = getElements(lst, "p:sldMasterId");
|
|
1220
1228
|
const isPromoted = (entry) => {
|
|
@@ -1240,14 +1248,13 @@ function promoteMasters(dest, masterPartNames) {
|
|
|
1240
1248
|
*/
|
|
1241
1249
|
function nextMasterLayoutId(dest) {
|
|
1242
1250
|
let max = 2147483647;
|
|
1243
|
-
const
|
|
1244
|
-
const root = presPart.dom.documentElement;
|
|
1251
|
+
const root = dest.presentationPart.dom.documentElement;
|
|
1245
1252
|
const masterLst = root && firstChild(root, "p:sldMasterIdLst");
|
|
1246
1253
|
if (masterLst) for (const entry of getElements(masterLst, "p:sldMasterId")) {
|
|
1247
1254
|
const id = intValue(attr(entry, "id"));
|
|
1248
1255
|
if (id !== null && id > max) max = id;
|
|
1249
1256
|
}
|
|
1250
|
-
const presRels = dest
|
|
1257
|
+
const presRels = presentationRels(dest);
|
|
1251
1258
|
for (const rel of presRels.byType(SLIDE_MASTER_REL)) {
|
|
1252
1259
|
const masterRoot = dest.opc.part(presRels.resolveTarget(rel.id))?.dom.documentElement;
|
|
1253
1260
|
const layoutLst = masterRoot && firstChild(masterRoot, "p:sldLayoutIdLst");
|
|
@@ -1384,10 +1391,149 @@ function duplicateSubtree(opc, partName, copies) {
|
|
|
1384
1391
|
return fresh;
|
|
1385
1392
|
}
|
|
1386
1393
|
//#endregion
|
|
1394
|
+
//#region src/read/api/ops/part-reuse.ts
|
|
1395
|
+
/**
|
|
1396
|
+
* Recognising a part the destination deck **already holds**, so an import binds to it
|
|
1397
|
+
* instead of copying it in again.
|
|
1398
|
+
*
|
|
1399
|
+
* The case this exists for is the deck templated from its own source. `fromTemplate`
|
|
1400
|
+
* keeps a package's masters, layouts and theme byte-identical and strips only its
|
|
1401
|
+
* slides, so a script that then imports a slide back out of that same file hands
|
|
1402
|
+
* `copyPart` a `slideLayout -> slideMaster -> theme` subgraph whose every part is
|
|
1403
|
+
* already in the destination under its own partname. The copy registry maps *source*
|
|
1404
|
+
* partnames to copies this import made and knows nothing about what the destination
|
|
1405
|
+
* arrived with, so each of those parts was copied again: the output grew a duplicate
|
|
1406
|
+
* layout and master per imported slide, visible in PowerPoint's layout picker and
|
|
1407
|
+
* enough to make a later `appendSlides({ layout: <name> })` ambiguous.
|
|
1408
|
+
*
|
|
1409
|
+
* The test is deliberately strict, because the cost of getting it wrong is a slide
|
|
1410
|
+
* bound to chrome that only resembles what it asked for. A part is reusable only when
|
|
1411
|
+
* the destination holds it at the *same partname*, with the same content type, the same
|
|
1412
|
+
* bytes (as they would be written, so an edited destination part disqualifies itself),
|
|
1413
|
+
* the same relationships, and the same rule applied recursively to everything those
|
|
1414
|
+
* relationships reach. Byte-equality all the way down means "reuse" and "copy" produce
|
|
1415
|
+
* the same rendering; anything less falls back to the copy, which is always correct and
|
|
1416
|
+
* merely wasteful.
|
|
1417
|
+
*
|
|
1418
|
+
* Two further conditions have nothing to do with identity and everything to do with the
|
|
1419
|
+
* destination being a real deck: a reused master must already be registered in
|
|
1420
|
+
* `presentation.xml`, and a reused layout must already sit in a registered master's
|
|
1421
|
+
* `p:sldLayoutIdLst`. An identical part that is an orphan in the destination is not
|
|
1422
|
+
* something to bind a slide to, and the copy path (which registers and links what it
|
|
1423
|
+
* copies) is the right answer there.
|
|
1424
|
+
*
|
|
1425
|
+
* Reuse mutates nothing, which is what lets it hold across repeated imports: the
|
|
1426
|
+
* destination's chrome stays byte-identical, so the second import recognises it exactly
|
|
1427
|
+
* as the first one did.
|
|
1428
|
+
*/
|
|
1429
|
+
/**
|
|
1430
|
+
* Whether the destination already holds `sourcePartName`'s subgraph, part for part and
|
|
1431
|
+
* byte for byte, in a state an imported slide can bind to.
|
|
1432
|
+
*
|
|
1433
|
+
* @param dest the deck being imported into
|
|
1434
|
+
* @param source the package being imported out of
|
|
1435
|
+
* @param sourcePartName the part the copy is about to make
|
|
1436
|
+
* @return `true` when the copy can be skipped and the existing part used
|
|
1437
|
+
*/
|
|
1438
|
+
function destinationAlreadyHolds(dest, source, sourcePartName) {
|
|
1439
|
+
const part = dest.opc.part(sourcePartName);
|
|
1440
|
+
if (!part || part.contentType === "application/vnd.openxmlformats-officedocument.presentationml.slide+xml") return false;
|
|
1441
|
+
if (!identicalSubgraph(dest.opc, source, sourcePartName, /* @__PURE__ */ new Set())) return false;
|
|
1442
|
+
return wiredIntoDeck(dest, sourcePartName);
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* `partName` and everything it reaches are the same in both packages: same content type,
|
|
1446
|
+
* same body bytes, same relationships, recursively.
|
|
1447
|
+
*
|
|
1448
|
+
* The destination side is compared as it would be **written** (`serialize()`), not as it
|
|
1449
|
+
* was read, so a part some earlier edit marked dirty is treated as different even when
|
|
1450
|
+
* the edit was a no-op. Under-reusing costs a duplicated part; over-reusing binds a slide
|
|
1451
|
+
* to something else's chrome.
|
|
1452
|
+
*
|
|
1453
|
+
* The traversal skips exactly what `copyPart` skips — the notes relationship, and a
|
|
1454
|
+
* master's relationships to its layouts — so it asks about the subgraph the copy would
|
|
1455
|
+
* actually have made. Skipping the master's layout list is what keeps one edited layout
|
|
1456
|
+
* from disqualifying every *other* layout that shares its master.
|
|
1457
|
+
*/
|
|
1458
|
+
function identicalSubgraph(dest, source, partName, visited) {
|
|
1459
|
+
if (visited.has(partName)) return true;
|
|
1460
|
+
visited.add(partName);
|
|
1461
|
+
const sourcePart = source.part(partName);
|
|
1462
|
+
const destPart = dest.part(partName);
|
|
1463
|
+
if (!sourcePart || !destPart) return false;
|
|
1464
|
+
if (sourcePart.contentType !== destPart.contentType) return false;
|
|
1465
|
+
if (!bytesEqual(sourcePart.bytes, destPart.serialize())) return false;
|
|
1466
|
+
const sourceRels = [...source.relationshipsFor(partName)];
|
|
1467
|
+
const destRels = [...dest.relationshipsFor(partName)];
|
|
1468
|
+
if (sourceRels.length !== destRels.length) return false;
|
|
1469
|
+
const isMaster = sourcePart.contentType === SLIDE_MASTER_CONTENT_TYPE;
|
|
1470
|
+
const destById = new Map(destRels.map((rel) => [rel.id, rel]));
|
|
1471
|
+
for (const rel of sourceRels) {
|
|
1472
|
+
const counterpart = destById.get(rel.id);
|
|
1473
|
+
if (!counterpart) return false;
|
|
1474
|
+
if (counterpart.type !== rel.type || counterpart.targetMode !== rel.targetMode) return false;
|
|
1475
|
+
if (rel.targetMode === "External") {
|
|
1476
|
+
if (counterpart.target !== rel.target) return false;
|
|
1477
|
+
continue;
|
|
1478
|
+
}
|
|
1479
|
+
const target = source.relationshipsFor(partName).resolveTarget(rel.id);
|
|
1480
|
+
if (dest.relationshipsFor(partName).resolveTarget(rel.id) !== target) return false;
|
|
1481
|
+
if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide") continue;
|
|
1482
|
+
if (isMaster && rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout") continue;
|
|
1483
|
+
if (!identicalSubgraph(dest, source, target, visited)) return false;
|
|
1484
|
+
}
|
|
1485
|
+
return true;
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Whether the destination's copy of this part is wired into the deck, for the two kinds
|
|
1489
|
+
* where "present in the package" is not the same as "usable".
|
|
1490
|
+
*
|
|
1491
|
+
* A master absent from `p:sldMasterIdLst` is inert: renderers ignore its background and
|
|
1492
|
+
* shape tree, so a slide bound through it renders blank. A layout absent from a
|
|
1493
|
+
* registered master's `p:sldLayoutIdLst` is not in the deck's gallery, so `layouts()`
|
|
1494
|
+
* cannot name it and `appendSlides` cannot bind to it. Every other kind (theme, media,
|
|
1495
|
+
* table styles) is reached by relationship alone and needs no registration.
|
|
1496
|
+
*/
|
|
1497
|
+
function wiredIntoDeck(dest, partName) {
|
|
1498
|
+
const contentType = dest.opc.part(partName)?.contentType;
|
|
1499
|
+
if (contentType === "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml") return registeredMasters(dest).includes(partName);
|
|
1500
|
+
if (contentType === "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml") return registeredMasters(dest).some((master) => galleryOf(dest, master).includes(partName));
|
|
1501
|
+
return true;
|
|
1502
|
+
}
|
|
1503
|
+
/** The destination's masters in `p:sldMasterIdLst` order — the ones renderers treat as active. */
|
|
1504
|
+
function registeredMasters(dest) {
|
|
1505
|
+
const root = dest.presentationPart.dom.documentElement;
|
|
1506
|
+
const lst = root && firstChild(root, "p:sldMasterIdLst");
|
|
1507
|
+
if (!lst) return [];
|
|
1508
|
+
const rels = presentationRels(dest);
|
|
1509
|
+
return idListTargets(lst, "p:sldMasterId", (relId) => rels.resolveTarget(relId));
|
|
1510
|
+
}
|
|
1511
|
+
/** One master's layouts in `p:sldLayoutIdLst` order — its slice of the deck's gallery. */
|
|
1512
|
+
function galleryOf(dest, masterPartName) {
|
|
1513
|
+
const root = dest.opc.part(masterPartName)?.dom.documentElement;
|
|
1514
|
+
const lst = root && firstChild(root, "p:sldLayoutIdLst");
|
|
1515
|
+
if (!lst) return [];
|
|
1516
|
+
const rels = dest.opc.relationshipsFor(masterPartName);
|
|
1517
|
+
return idListTargets(lst, "p:sldLayoutId", (relId) => rels.resolveTarget(relId));
|
|
1518
|
+
}
|
|
1519
|
+
/** Resolve every `@r:id` in an id list to its partname, skipping entries that carry none. */
|
|
1520
|
+
function idListTargets(lst, qname, resolve) {
|
|
1521
|
+
const out = [];
|
|
1522
|
+
for (const entry of getElements(lst, qname)) {
|
|
1523
|
+
const relId = attr(entry, "r:id");
|
|
1524
|
+
if (relId) out.push(resolve(relId));
|
|
1525
|
+
}
|
|
1526
|
+
return out;
|
|
1527
|
+
}
|
|
1528
|
+
/** Byte-for-byte equality of two part bodies. */
|
|
1529
|
+
function bytesEqual(a, b) {
|
|
1530
|
+
if (a === b) return true;
|
|
1531
|
+
if (a.length !== b.length) return false;
|
|
1532
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
1533
|
+
return true;
|
|
1534
|
+
}
|
|
1535
|
+
//#endregion
|
|
1387
1536
|
//#region src/read/api/ops/part-copy.ts
|
|
1388
|
-
const SLIDE_MASTER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml";
|
|
1389
|
-
const SLIDE_LAYOUT_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml";
|
|
1390
|
-
const NOTES_SLIDE_CONTENT_TYPE$2 = "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml";
|
|
1391
1537
|
/** Open an ownership scope for one page copy. */
|
|
1392
1538
|
function newOwnedScope() {
|
|
1393
1539
|
return /* @__PURE__ */ new Map();
|
|
@@ -1444,7 +1590,7 @@ function copySlidePart(ctx, sourcePartName) {
|
|
|
1444
1590
|
* from outside, as the rebinding import paths do for the page they build
|
|
1445
1591
|
* themselves.
|
|
1446
1592
|
*/
|
|
1447
|
-
function copyPart(ctx, sourcePartName, owned) {
|
|
1593
|
+
function copyPart(ctx, sourcePartName, owned, allowReuse = false) {
|
|
1448
1594
|
if (owned) {
|
|
1449
1595
|
const alreadyOwned = owned.get(sourcePartName);
|
|
1450
1596
|
if (alreadyOwned !== void 0) return alreadyOwned;
|
|
@@ -1453,6 +1599,12 @@ function copyPart(ctx, sourcePartName, owned) {
|
|
|
1453
1599
|
const selectedDest = ctx.selection?.destinations.get(sourcePartName);
|
|
1454
1600
|
if (existing && (selectedDest === void 0 || existing === selectedDest)) return existing;
|
|
1455
1601
|
}
|
|
1602
|
+
if (allowReuse && !owned && !ctx.selection?.destinations.has(sourcePartName)) {
|
|
1603
|
+
if (destinationAlreadyHolds(ctx.dest, ctx.source, sourcePartName)) {
|
|
1604
|
+
ctx.registry.set(sourcePartName, sourcePartName);
|
|
1605
|
+
return sourcePartName;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1456
1608
|
const sourcePart = ctx.source.part(sourcePartName);
|
|
1457
1609
|
if (!sourcePart) throw new PackageReadError("package/part-missing", `importSlide: source package has no part ${sourcePartName}`);
|
|
1458
1610
|
const newPartName = owned ? ctx.dest.opc.reservePartNameLike(sourcePartName) : ctx.selection?.destinations.get(sourcePartName) ?? ctx.dest.opc.reservePartNameLike(sourcePartName);
|
|
@@ -1461,6 +1613,7 @@ function copyPart(ctx, sourcePartName, owned) {
|
|
|
1461
1613
|
else ctx.registry.set(sourcePartName, newPartName);
|
|
1462
1614
|
const scope = owned ?? (ctx.selection?.destinations.has(sourcePartName) ? newOwnedScope() : void 0);
|
|
1463
1615
|
const isMaster = sourcePart.contentType === SLIDE_MASTER_CONTENT_TYPE;
|
|
1616
|
+
const isPage = sourcePart.contentType === SLIDE_CONTENT_TYPE;
|
|
1464
1617
|
const sourceRels = ctx.source.relationshipsFor(sourcePartName);
|
|
1465
1618
|
const targetRels = ctx.dest.opc.relationshipsFor(newPartName);
|
|
1466
1619
|
for (const rel of sourceRels) {
|
|
@@ -1470,14 +1623,14 @@ function copyPart(ctx, sourcePartName, owned) {
|
|
|
1470
1623
|
targetRels.addWithId(rel.id, rel.type, rel.target, "External");
|
|
1471
1624
|
continue;
|
|
1472
1625
|
}
|
|
1473
|
-
const newTargetPartName = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : scope);
|
|
1626
|
+
const newTargetPartName = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : scope, isPage);
|
|
1474
1627
|
targetRels.addWithId(rel.id, rel.type, relativePartName(newPartName, newTargetPartName));
|
|
1475
1628
|
}
|
|
1476
1629
|
if (isMaster) {
|
|
1477
1630
|
clearLayoutIdList(ctx.dest, newPartName);
|
|
1478
1631
|
registerMaster(ctx.dest, newPartName);
|
|
1479
1632
|
}
|
|
1480
|
-
if (sourcePart.contentType ===
|
|
1633
|
+
if (sourcePart.contentType === "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml") linkLayoutIntoMaster(ctx, sourceRels, newPartName);
|
|
1481
1634
|
return newPartName;
|
|
1482
1635
|
}
|
|
1483
1636
|
const NO_NOTES = {
|
|
@@ -1516,8 +1669,8 @@ function checkSelectionCopyable(source, registry, selected, notes = NO_NOTES) {
|
|
|
1516
1669
|
const part = source.part(partName);
|
|
1517
1670
|
if (!part) throw new PackageReadError("package/part-missing", `importSlides: source package has no part ${partName}`);
|
|
1518
1671
|
const isMaster = part.contentType === SLIDE_MASTER_CONTENT_TYPE;
|
|
1519
|
-
const isNotesSlide = part.contentType === NOTES_SLIDE_CONTENT_TYPE
|
|
1520
|
-
if (isMaster || part.contentType ===
|
|
1672
|
+
const isNotesSlide = part.contentType === NOTES_SLIDE_CONTENT_TYPE;
|
|
1673
|
+
if (isMaster || part.contentType === "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml") part.dom;
|
|
1521
1674
|
const rels = source.relationshipsFor(partName);
|
|
1522
1675
|
for (const rel of rels) {
|
|
1523
1676
|
if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide") {
|
|
@@ -1563,8 +1716,6 @@ function linkLayoutIntoMaster(ctx, layoutSourceRels, layoutPartName) {
|
|
|
1563
1716
|
* `Presentation`-to-`Presentation` path and the generator-XML path funnel through
|
|
1564
1717
|
* `registerNotesMaster`: they differ only in how the *part* comes into being.
|
|
1565
1718
|
*/
|
|
1566
|
-
const NOTES_MASTER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml";
|
|
1567
|
-
const THEME_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.theme+xml";
|
|
1568
1719
|
const textEncoder$3 = new TextEncoder();
|
|
1569
1720
|
/**
|
|
1570
1721
|
* Carry the source slide's speaker notes onto the just-imported slide (the
|
|
@@ -1625,8 +1776,7 @@ function carryNotes(dest, source, ctx, sourceSlidePartName, newSlidePartName) {
|
|
|
1625
1776
|
* registered in `presentation.xml`. Returns the destination notesMaster partname.
|
|
1626
1777
|
*/
|
|
1627
1778
|
function ensureNotesMaster(dest, ctx, sourceNotesMasterPartName) {
|
|
1628
|
-
const
|
|
1629
|
-
const presRels = dest.opc.relationshipsFor(presPart.partName);
|
|
1779
|
+
const presRels = presentationRels(dest);
|
|
1630
1780
|
const existing = presRels.byType(NOTES_MASTER_REL)[0];
|
|
1631
1781
|
if (existing) return presRels.resolveTarget(existing.id);
|
|
1632
1782
|
return registerNotesMaster(dest, copyPart(ctx, sourceNotesMasterPartName));
|
|
@@ -1643,7 +1793,7 @@ function ensureNotesMaster(dest, ctx, sourceNotesMasterPartName) {
|
|
|
1643
1793
|
*/
|
|
1644
1794
|
function registerNotesMaster(dest, notesMasterPartName) {
|
|
1645
1795
|
const presPart = dest.presentationPart;
|
|
1646
|
-
const relId = dest
|
|
1796
|
+
const relId = presentationRels(dest).add(NOTES_MASTER_REL, relativePartName(presPart.partName, notesMasterPartName)).id;
|
|
1647
1797
|
const root = presPart.dom.documentElement;
|
|
1648
1798
|
if (!root) throw new PackageReadError("package/part-has-no-root", "presentation.xml has no document element to register a notes master in");
|
|
1649
1799
|
const lst = getOrAddChild(root, "p:notesMasterIdLst", [
|
|
@@ -1675,8 +1825,7 @@ function registerNotesMaster(dest, notesMasterPartName) {
|
|
|
1675
1825
|
* theme its `.rels` requires (the normal write path emits that as `theme2.xml`).
|
|
1676
1826
|
*/
|
|
1677
1827
|
function ensureNotesMasterFromXml(dest, master) {
|
|
1678
|
-
const
|
|
1679
|
-
const presRels = dest.opc.relationshipsFor(presPart.partName);
|
|
1828
|
+
const presRels = presentationRels(dest);
|
|
1680
1829
|
const existing = presRels.byType(NOTES_MASTER_REL)[0];
|
|
1681
1830
|
if (existing) return presRels.resolveTarget(existing.id);
|
|
1682
1831
|
const masterPartName = dest.opc.reservePartNameLike("/ppt/notesMasters/notesMaster1.xml");
|
|
@@ -1712,8 +1861,7 @@ function ensureNotesMasterFromXml(dest, master) {
|
|
|
1712
1861
|
* @return {string} the destination notesMaster partname
|
|
1713
1862
|
*/
|
|
1714
1863
|
function ensureNotesMasterForAuthoring(dest, slidePartName) {
|
|
1715
|
-
const
|
|
1716
|
-
const presRels = dest.opc.relationshipsFor(presPart.partName);
|
|
1864
|
+
const presRels = presentationRels(dest);
|
|
1717
1865
|
const existing = presRels.byType(NOTES_MASTER_REL)[0];
|
|
1718
1866
|
if (existing) return presRels.resolveTarget(existing.id);
|
|
1719
1867
|
const themePartName = resolveSlideThemeParts(dest.opc, slidePartName).themePartName;
|
|
@@ -1755,8 +1903,6 @@ function ensureNotesMasterForAuthoring(dest, slidePartName) {
|
|
|
1755
1903
|
* multi-run paragraphs are reached afterwards through `slide.notesTextFrame`, which
|
|
1756
1904
|
* is the read model's normal text-editing surface.
|
|
1757
1905
|
*/
|
|
1758
|
-
const NOTES_SLIDE_CONTENT_TYPE$1 = "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml";
|
|
1759
|
-
const A_NS = "http://schemas.openxmlformats.org/drawingml/2006/main";
|
|
1760
1906
|
const textEncoder$2 = new TextEncoder();
|
|
1761
1907
|
/**
|
|
1762
1908
|
* The `a:p` children of a notes body, one per `\n`-separated line: the write path's
|
|
@@ -1791,7 +1937,7 @@ function replaceNotesParagraphs(txBody, text) {
|
|
|
1791
1937
|
const doc = txBody.ownerDocument;
|
|
1792
1938
|
if (!doc) throw new InternalError("oxml/node-has-no-document", "Notes body has no owner document");
|
|
1793
1939
|
removeChildrenByQName(txBody, ["a:p"]);
|
|
1794
|
-
const wrapper = parseXml(`<w xmlns:a="${
|
|
1940
|
+
const wrapper = parseXml(`<w xmlns:a="${OOXML_NS.a}">${notesParagraphsXml(text)}</w>`).documentElement;
|
|
1795
1941
|
if (!wrapper) throw new InternalError("oxml/node-has-no-document", "Authored notes paragraphs did not parse to a root");
|
|
1796
1942
|
for (const paragraph of Array.from(wrapper.childNodes)) txBody.appendChild(doc.importNode(paragraph, true));
|
|
1797
1943
|
}
|
|
@@ -1804,12 +1950,10 @@ function replaceNotesParagraphs(txBody, text) {
|
|
|
1804
1950
|
* @return {Element | null} the body placeholder's text body
|
|
1805
1951
|
*/
|
|
1806
1952
|
function notesBodyTxBody(root) {
|
|
1807
|
-
const
|
|
1808
|
-
const spTree = cSld && firstChild(cSld, "p:spTree");
|
|
1953
|
+
const spTree = spTreeOf(root);
|
|
1809
1954
|
if (!spTree) return null;
|
|
1810
1955
|
for (const sp of getElements(spTree, "p:sp")) {
|
|
1811
|
-
const
|
|
1812
|
-
const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
|
|
1956
|
+
const nvPr = nvPrOf(sp);
|
|
1813
1957
|
const ph = nvPr && firstChild(nvPr, "p:ph");
|
|
1814
1958
|
if (ph && attr(ph, "type") === "body") return firstChild(sp, "p:txBody");
|
|
1815
1959
|
}
|
|
@@ -1848,7 +1992,7 @@ function authorNotes(slide, text) {
|
|
|
1848
1992
|
}
|
|
1849
1993
|
const slideNum = slide.index + 1;
|
|
1850
1994
|
const partName = opc.reservePartNameLike("/ppt/notesSlides/notesSlide1.xml");
|
|
1851
|
-
opc.addPart(partName, NOTES_SLIDE_CONTENT_TYPE
|
|
1995
|
+
opc.addPart(partName, NOTES_SLIDE_CONTENT_TYPE, textEncoder$2.encode(makeXmlNotesSlideSkeleton(notesParagraphsXml(text), slideNum)));
|
|
1852
1996
|
slide.relationships.add(NOTES_SLIDE_REL, relativePartName(slide.partName, partName));
|
|
1853
1997
|
const notesRels = opc.relationshipsFor(partName);
|
|
1854
1998
|
const masterPartName = ensureNotesMasterForAuthoring(slide.presentation, slide.partName);
|
|
@@ -2328,12 +2472,10 @@ var SlideMaster = class {
|
|
|
2328
2472
|
return rel ? this.opc.part(rels.resolveTarget(rel.id)) ?? null : null;
|
|
2329
2473
|
}
|
|
2330
2474
|
#cSld() {
|
|
2331
|
-
|
|
2332
|
-
return root ? firstChild(root, "p:cSld") : null;
|
|
2475
|
+
return cSldOf(this.part.dom.documentElement);
|
|
2333
2476
|
}
|
|
2334
2477
|
#spTree() {
|
|
2335
|
-
|
|
2336
|
-
return cSld ? firstChild(cSld, "p:spTree") : null;
|
|
2478
|
+
return spTreeOf(this.part.dom.documentElement);
|
|
2337
2479
|
}
|
|
2338
2480
|
};
|
|
2339
2481
|
/**
|
|
@@ -2439,12 +2581,10 @@ var SlideLayout = class {
|
|
|
2439
2581
|
return this.#themeContext ??= resolveLayoutColorContext(this.opc, this.partName);
|
|
2440
2582
|
}
|
|
2441
2583
|
#cSld() {
|
|
2442
|
-
|
|
2443
|
-
return root ? firstChild(root, "p:cSld") : null;
|
|
2584
|
+
return cSldOf(this.part.dom.documentElement);
|
|
2444
2585
|
}
|
|
2445
2586
|
#spTree() {
|
|
2446
|
-
|
|
2447
|
-
return cSld ? firstChild(cSld, "p:spTree") : null;
|
|
2587
|
+
return spTreeOf(this.part.dom.documentElement);
|
|
2448
2588
|
}
|
|
2449
2589
|
};
|
|
2450
2590
|
//#endregion
|
|
@@ -3103,9 +3243,14 @@ var Slide = class {
|
|
|
3103
3243
|
* All text on the slide, flattened in document order — the read-model
|
|
3104
3244
|
* counterpart to {@link TextFrame.text} one level up. Every text-bearing shape
|
|
3105
3245
|
* contributes its text, recursing into groups ({@link GroupShape}) and reading
|
|
3106
|
-
* table cells ({@link GraphicFrame.table})
|
|
3107
|
-
*
|
|
3108
|
-
*
|
|
3246
|
+
* table cells ({@link GraphicFrame.table}) and SmartArt node text
|
|
3247
|
+
* ({@link GraphicFrame.diagram}); text-free shapes (pictures, connectors, empty
|
|
3248
|
+
* boxes) contribute nothing. Blocks are joined by `\n`; within a table, cells in
|
|
3249
|
+
* a row are joined by `\t` and rows by `\n`.
|
|
3250
|
+
*
|
|
3251
|
+
* A diagram contributes for the same reason a table does: its nodes are body text
|
|
3252
|
+
* PowerPoint itself searches and spell-checks, so a slide whose whole message is a
|
|
3253
|
+
* SmartArt graphic would otherwise flatten to the empty string.
|
|
3109
3254
|
*
|
|
3110
3255
|
* This is deliberately scoped to the slide's own shape tree. It does **not**
|
|
3111
3256
|
* include speaker notes (read those via {@link notesText}) or chart data labels
|
|
@@ -3119,11 +3264,16 @@ var Slide = class {
|
|
|
3119
3264
|
for (const shape of shapes) if (shape instanceof GroupShape) walk(shape.shapes);
|
|
3120
3265
|
else if (shape instanceof GraphicFrame) {
|
|
3121
3266
|
const table = shape.table;
|
|
3122
|
-
if (
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3267
|
+
if (table) {
|
|
3268
|
+
for (const row of table.rows) {
|
|
3269
|
+
const cells = row.cells.map((cell) => cell.text);
|
|
3270
|
+
if (cells.some((cell) => cell.length > 0)) blocks.push(cells.join(" "));
|
|
3271
|
+
}
|
|
3272
|
+
continue;
|
|
3126
3273
|
}
|
|
3274
|
+
const diagram = shape.diagram;
|
|
3275
|
+
const diagramText = diagram ? diagram.text : "";
|
|
3276
|
+
if (diagramText.length > 0) blocks.push(diagramText);
|
|
3127
3277
|
} else {
|
|
3128
3278
|
const text = shape.text;
|
|
3129
3279
|
if (text.length > 0) blocks.push(text);
|
|
@@ -3462,12 +3612,10 @@ var Slide = class {
|
|
|
3462
3612
|
return max + 1;
|
|
3463
3613
|
}
|
|
3464
3614
|
#cSld() {
|
|
3465
|
-
|
|
3466
|
-
return root ? firstChild(root, "p:cSld") : null;
|
|
3615
|
+
return cSldOf(this.part.dom.documentElement);
|
|
3467
3616
|
}
|
|
3468
3617
|
#spTree() {
|
|
3469
|
-
|
|
3470
|
-
return cSld ? firstChild(cSld, "p:spTree") : null;
|
|
3618
|
+
return spTreeOf(this.part.dom.documentElement);
|
|
3471
3619
|
}
|
|
3472
3620
|
};
|
|
3473
3621
|
function requireFinite(value, name) {
|
|
@@ -3477,39 +3625,53 @@ function requirePositive(value, name) {
|
|
|
3477
3625
|
requireFinite(value, name);
|
|
3478
3626
|
if (value <= 0) throw new InvalidOptionError("coord/not-positive", `${name} must be positive, got ${value}`);
|
|
3479
3627
|
}
|
|
3480
|
-
/**
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
const
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
const
|
|
3498
|
-
const
|
|
3628
|
+
/**
|
|
3629
|
+
* Create `qname` in the parent's document and append it.
|
|
3630
|
+
*
|
|
3631
|
+
* The builders below are uniformly parent-then-child, so this is the only shape
|
|
3632
|
+
* of element creation they need; `ownerDocumentOf` is what lets it take the
|
|
3633
|
+
* parent alone rather than threading a `Document` through every call.
|
|
3634
|
+
*/
|
|
3635
|
+
function appendEl(parent, qname) {
|
|
3636
|
+
const child = createElement(ownerDocumentOf(parent), qname);
|
|
3637
|
+
parent.appendChild(child);
|
|
3638
|
+
return child;
|
|
3639
|
+
}
|
|
3640
|
+
/**
|
|
3641
|
+
* Append the `p:spPr` a built `p:sp` and `p:pic` share: the spec's box as an
|
|
3642
|
+
* `a:xfrm`, then a rect `prstGeom` with the empty `a:avLst` the schema requires.
|
|
3643
|
+
*/
|
|
3644
|
+
function appendSpPr(parent, spec) {
|
|
3645
|
+
const spPr = appendEl(parent, "p:spPr");
|
|
3646
|
+
const xfrm = appendEl(spPr, "a:xfrm");
|
|
3647
|
+
const off = appendEl(xfrm, "a:off");
|
|
3499
3648
|
setAttr(off, "x", String(spec.left));
|
|
3500
3649
|
setAttr(off, "y", String(spec.top));
|
|
3501
|
-
const ext =
|
|
3650
|
+
const ext = appendEl(xfrm, "a:ext");
|
|
3502
3651
|
setAttr(ext, "cx", String(spec.width));
|
|
3503
3652
|
setAttr(ext, "cy", String(spec.height));
|
|
3504
|
-
const prstGeom =
|
|
3653
|
+
const prstGeom = appendEl(spPr, "a:prstGeom");
|
|
3505
3654
|
setAttr(prstGeom, "prst", "rect");
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3655
|
+
appendEl(prstGeom, "a:avLst");
|
|
3656
|
+
return spPr;
|
|
3657
|
+
}
|
|
3658
|
+
/** Build a minimal, schema-valid text-box `p:sp` element (not yet attached). */
|
|
3659
|
+
function buildTextBox(doc, spec) {
|
|
3660
|
+
const sp = createElement(doc, "p:sp");
|
|
3661
|
+
const nvSpPr = appendEl(sp, "p:nvSpPr");
|
|
3662
|
+
const cNvPr = appendEl(nvSpPr, "p:cNvPr");
|
|
3663
|
+
setAttr(cNvPr, "id", String(spec.id));
|
|
3664
|
+
setAttr(cNvPr, "name", spec.name);
|
|
3665
|
+
const cNvSpPr = appendEl(nvSpPr, "p:cNvSpPr");
|
|
3666
|
+
setAttr(cNvSpPr, "txBox", "1");
|
|
3667
|
+
appendEl(nvSpPr, "p:nvPr");
|
|
3668
|
+
appendSpPr(sp, spec);
|
|
3669
|
+
const txBody = appendEl(sp, "p:txBody");
|
|
3670
|
+
appendEl(txBody, "a:bodyPr");
|
|
3671
|
+
appendEl(txBody, "a:lstStyle");
|
|
3672
|
+
const p = appendEl(txBody, "a:p");
|
|
3511
3673
|
if (spec.text !== "") {
|
|
3512
|
-
const t =
|
|
3674
|
+
const t = appendEl(appendEl(p, "a:r"), "a:t");
|
|
3513
3675
|
t.textContent = spec.text;
|
|
3514
3676
|
if (spec.text !== spec.text.trim()) setAttr(t, "xml:space", "preserve");
|
|
3515
3677
|
}
|
|
@@ -3517,35 +3679,19 @@ function buildTextBox(doc, spec) {
|
|
|
3517
3679
|
}
|
|
3518
3680
|
/** Build a minimal, schema-valid `p:pic` element (not yet attached). */
|
|
3519
3681
|
function buildPicture(doc, spec) {
|
|
3520
|
-
const
|
|
3521
|
-
const
|
|
3522
|
-
|
|
3523
|
-
parent.appendChild(child);
|
|
3524
|
-
return child;
|
|
3525
|
-
};
|
|
3526
|
-
const pic = make("p:pic");
|
|
3527
|
-
const nvPicPr = append(pic, "p:nvPicPr");
|
|
3528
|
-
const cNvPr = append(nvPicPr, "p:cNvPr");
|
|
3682
|
+
const pic = createElement(doc, "p:pic");
|
|
3683
|
+
const nvPicPr = appendEl(pic, "p:nvPicPr");
|
|
3684
|
+
const cNvPr = appendEl(nvPicPr, "p:cNvPr");
|
|
3529
3685
|
setAttr(cNvPr, "id", String(spec.id));
|
|
3530
3686
|
setAttr(cNvPr, "name", spec.name);
|
|
3531
|
-
const picLocks =
|
|
3687
|
+
const picLocks = appendEl(appendEl(nvPicPr, "p:cNvPicPr"), "a:picLocks");
|
|
3532
3688
|
setAttr(picLocks, "noChangeAspect", "1");
|
|
3533
|
-
|
|
3534
|
-
const blipFill =
|
|
3535
|
-
const blip =
|
|
3689
|
+
appendEl(nvPicPr, "p:nvPr");
|
|
3690
|
+
const blipFill = appendEl(pic, "p:blipFill");
|
|
3691
|
+
const blip = appendEl(blipFill, "a:blip");
|
|
3536
3692
|
setAttr(blip, "r:embed", spec.relId);
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
const xfrm = append(spPr, "a:xfrm");
|
|
3540
|
-
const off = append(xfrm, "a:off");
|
|
3541
|
-
setAttr(off, "x", String(spec.left));
|
|
3542
|
-
setAttr(off, "y", String(spec.top));
|
|
3543
|
-
const ext = append(xfrm, "a:ext");
|
|
3544
|
-
setAttr(ext, "cx", String(spec.width));
|
|
3545
|
-
setAttr(ext, "cy", String(spec.height));
|
|
3546
|
-
const prstGeom = append(spPr, "a:prstGeom");
|
|
3547
|
-
setAttr(prstGeom, "prst", "rect");
|
|
3548
|
-
append(prstGeom, "a:avLst");
|
|
3693
|
+
appendEl(appendEl(blipFill, "a:stretch"), "a:fillRect");
|
|
3694
|
+
appendSpPr(pic, spec);
|
|
3549
3695
|
return pic;
|
|
3550
3696
|
}
|
|
3551
3697
|
//#endregion
|
|
@@ -3657,70 +3803,6 @@ function readCustomProperties(opc) {
|
|
|
3657
3803
|
return out;
|
|
3658
3804
|
}
|
|
3659
3805
|
//#endregion
|
|
3660
|
-
//#region src/read/oxml/slide-dom.ts
|
|
3661
|
-
/** The `p:cSld@name` of a slide/layout/master part (`''` when absent). */
|
|
3662
|
-
function cSldName(part) {
|
|
3663
|
-
const root = part?.dom.documentElement;
|
|
3664
|
-
const cSld = root && firstChild(root, "p:cSld");
|
|
3665
|
-
return (cSld && attr(cSld, "name")) ?? "";
|
|
3666
|
-
}
|
|
3667
|
-
/** Whether `el` is a `p:spTree`'s own group properties (`p:nvGrpSpPr`/`p:grpSpPr`), not a shape. */
|
|
3668
|
-
function isSpTreeProperty(el) {
|
|
3669
|
-
return el.namespaceURI === OOXML_NS.p && (el.localName === "nvGrpSpPr" || el.localName === "grpSpPr");
|
|
3670
|
-
}
|
|
3671
|
-
/** Whether a `p:spTree` child is a placeholder shape (its `*nvPr` carries a `p:ph`). */
|
|
3672
|
-
function isPlaceholderShape(shape) {
|
|
3673
|
-
const nv = firstChildElement(shape);
|
|
3674
|
-
const nvPr = nv && firstChild(nv, "p:nvPr");
|
|
3675
|
-
return !!(nvPr && firstChild(nvPr, "p:ph"));
|
|
3676
|
-
}
|
|
3677
|
-
/** The decorative shapes on a layout/master `p:spTree`: every shape child except placeholders. */
|
|
3678
|
-
function carriedDecorations(root) {
|
|
3679
|
-
if (!root) return [];
|
|
3680
|
-
const cSld = firstChild(root, "p:cSld");
|
|
3681
|
-
const spTree = cSld && firstChild(cSld, "p:spTree");
|
|
3682
|
-
if (!spTree) return [];
|
|
3683
|
-
const out = [];
|
|
3684
|
-
for (let node = spTree.firstChild; node; node = node.nextSibling) {
|
|
3685
|
-
if (node.nodeType !== 1) continue;
|
|
3686
|
-
const el = node;
|
|
3687
|
-
if (isSpTreeProperty(el) || isPlaceholderShape(el)) continue;
|
|
3688
|
-
out.push(el);
|
|
3689
|
-
}
|
|
3690
|
-
return out;
|
|
3691
|
-
}
|
|
3692
|
-
/**
|
|
3693
|
-
* The `n`-th shape child of a `p:spTree` in document (z-)order, skipping the
|
|
3694
|
-
* tree's own `nvGrpSpPr`/`grpSpPr` and any trailing `p:extLst`. Returns `null`
|
|
3695
|
-
* when `n` is past the last shape (the caller then appends).
|
|
3696
|
-
*/
|
|
3697
|
-
function nthShapeChild(spTree, n) {
|
|
3698
|
-
let i = 0;
|
|
3699
|
-
for (let node = spTree.firstChild; node; node = node.nextSibling) {
|
|
3700
|
-
if (node.nodeType !== 1) continue;
|
|
3701
|
-
const el = node;
|
|
3702
|
-
if (isSpTreeProperty(el)) continue;
|
|
3703
|
-
if (el.namespaceURI === OOXML_NS.p && el.localName === "extLst") continue;
|
|
3704
|
-
if (i === n) return el;
|
|
3705
|
-
i++;
|
|
3706
|
-
}
|
|
3707
|
-
return null;
|
|
3708
|
-
}
|
|
3709
|
-
/** The first shape child of a `p:spTree` (skipping `nvGrpSpPr`/`grpSpPr`), or `null`. */
|
|
3710
|
-
function firstShapeChild(spTree) {
|
|
3711
|
-
for (let node = spTree.firstChild; node; node = node.nextSibling) {
|
|
3712
|
-
if (node.nodeType !== 1) continue;
|
|
3713
|
-
const el = node;
|
|
3714
|
-
if (!isSpTreeProperty(el)) return el;
|
|
3715
|
-
}
|
|
3716
|
-
return null;
|
|
3717
|
-
}
|
|
3718
|
-
/** Collect `node` and all its descendant elements (document order) into `out`. */
|
|
3719
|
-
function collectElements(node, out) {
|
|
3720
|
-
out.push(node);
|
|
3721
|
-
for (let child = node.firstChild; child; child = child.nextSibling) if (child.nodeType === 1) collectElements(child, out);
|
|
3722
|
-
}
|
|
3723
|
-
//#endregion
|
|
3724
3806
|
//#region src/read/api/ops/rescale.ts
|
|
3725
3807
|
/** Build the EMU transform mapping source-canvas coordinates onto the target canvas (see {@link ImportSlideOptions.rescale}). */
|
|
3726
3808
|
function computeRescale(source, target, mode) {
|
|
@@ -4131,7 +4213,7 @@ function mergeEmbeddedFontEntries(dest, entries) {
|
|
|
4131
4213
|
const presPart = dest.presentationPart;
|
|
4132
4214
|
const presRoot = presPart.dom.documentElement;
|
|
4133
4215
|
if (!presRoot) throw new PackageReadError("package/part-has-no-root", "presentation.xml has no document element to carry embedded fonts into");
|
|
4134
|
-
const presRels = dest
|
|
4216
|
+
const presRels = presentationRels(dest);
|
|
4135
4217
|
const targetLst = getOrAddChild(presRoot, "p:embeddedFontLst", PRESENTATION_EMBEDDED_FONT_LST_SUCCESSORS);
|
|
4136
4218
|
const targetByTypeface = /* @__PURE__ */ new Map();
|
|
4137
4219
|
for (const entry of getElements(targetLst, "p:embeddedFont")) {
|
|
@@ -4178,21 +4260,16 @@ function mergeEmbeddedFontEntries(dest, entries) {
|
|
|
4178
4260
|
* Pure with respect to the destination deck: it reads only the source package. It was a
|
|
4179
4261
|
* private method on `Presentation` that used no instance state.
|
|
4180
4262
|
*/
|
|
4181
|
-
/** The `p:cSld/p:bg` element of a slide/layout/master root, or `null`. */
|
|
4182
|
-
function backgroundOf(root) {
|
|
4183
|
-
const cSld = firstChild(root, "p:cSld");
|
|
4184
|
-
return cSld ? firstChild(cSld, "p:bg") : null;
|
|
4185
|
-
}
|
|
4186
4263
|
/**
|
|
4187
4264
|
* The background the slide effectively inherits from its source subgraph: the layout's
|
|
4188
4265
|
* `p:bg`, else the master's. Returns `null` when the slide carries its own `p:bg` (it stays
|
|
4189
4266
|
* on the slide and is flattened directly) or when none exists.
|
|
4190
4267
|
*/
|
|
4191
4268
|
function effectiveBackground(sourceOpc, slideRoot, layoutPartName, masterPartName) {
|
|
4192
|
-
if (slideRoot &&
|
|
4269
|
+
if (slideRoot && backgroundElementOf(slideRoot)) return null;
|
|
4193
4270
|
const layoutRoot = layoutPartName ? sourceOpc.part(layoutPartName)?.dom.documentElement ?? null : null;
|
|
4194
4271
|
const masterRoot = masterPartName ? sourceOpc.part(masterPartName)?.dom.documentElement ?? null : null;
|
|
4195
|
-
return (layoutRoot &&
|
|
4272
|
+
return (layoutRoot && backgroundElementOf(layoutRoot)) ?? (masterRoot && backgroundElementOf(masterRoot)) ?? null;
|
|
4196
4273
|
}
|
|
4197
4274
|
/**
|
|
4198
4275
|
* Gather the flatten context for a source slide: walk slide → layout → master → theme,
|
|
@@ -4371,7 +4448,7 @@ function importSlideRebind(dest, ctx, source, sourceSlide, carryGraphics) {
|
|
|
4371
4448
|
targetRels.addWithId(rel.id, rel.type, rel.target, "External");
|
|
4372
4449
|
continue;
|
|
4373
4450
|
}
|
|
4374
|
-
const newTarget = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : owned);
|
|
4451
|
+
const newTarget = copyPart(ctx, sourceRels.resolveTarget(rel.id), isSharedByPageCopies(rel.type) ? void 0 : owned, true);
|
|
4375
4452
|
targetRels.addWithId(rel.id, rel.type, relativePartName(newPartName, newTarget));
|
|
4376
4453
|
}
|
|
4377
4454
|
if (carryGraphics) carryMasterGraphics(dest, ctx, slideRoot, newPartName, sourceSlide.partName, owned);
|
|
@@ -4401,8 +4478,7 @@ function carryMasterGraphics(dest, ctx, slideRoot, newPartName, slidePartName, o
|
|
|
4401
4478
|
const sourceOpc = ctx.source;
|
|
4402
4479
|
const layoutPartName = resolveSingleRel(sourceOpc, slidePartName, SLIDE_LAYOUT_REL);
|
|
4403
4480
|
const masterPartName = layoutPartName ? resolveSingleRel(sourceOpc, layoutPartName, SLIDE_MASTER_REL) : null;
|
|
4404
|
-
const
|
|
4405
|
-
const spTree = cSld && firstChild(cSld, "p:spTree");
|
|
4481
|
+
const spTree = spTreeOf(slideRoot);
|
|
4406
4482
|
if (!spTree) return;
|
|
4407
4483
|
const doc = ownerDocumentOf(slideRoot);
|
|
4408
4484
|
const slideRels = dest.opc.relationshipsFor(newPartName);
|
|
@@ -4455,11 +4531,11 @@ function destinationLayoutPartName(dest) {
|
|
|
4455
4531
|
* orphan, even while momentarily unreferenced.
|
|
4456
4532
|
*/
|
|
4457
4533
|
const SHARED_CHROME_CONTENT_TYPES = /* @__PURE__ */ new Set([
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4534
|
+
SLIDE_MASTER_CONTENT_TYPE,
|
|
4535
|
+
SLIDE_LAYOUT_CONTENT_TYPE,
|
|
4536
|
+
THEME_CONTENT_TYPE,
|
|
4461
4537
|
"application/vnd.openxmlformats-officedocument.themeOverride+xml",
|
|
4462
|
-
|
|
4538
|
+
NOTES_MASTER_CONTENT_TYPE,
|
|
4463
4539
|
"application/vnd.openxmlformats-officedocument.presentationml.handoutMaster+xml",
|
|
4464
4540
|
"application/vnd.openxmlformats-officedocument.presentationml.presProps+xml",
|
|
4465
4541
|
"application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml",
|
|
@@ -4532,9 +4608,7 @@ function rescalePartGeometry(dest, rescaledParts, partName, transform) {
|
|
|
4532
4608
|
if (rescaledParts.has(partName)) return;
|
|
4533
4609
|
rescaledParts.add(partName);
|
|
4534
4610
|
const part = dest.opc.part(partName);
|
|
4535
|
-
const
|
|
4536
|
-
const cSld = root && firstChild(root, "p:cSld");
|
|
4537
|
-
const spTree = cSld && firstChild(cSld, "p:spTree");
|
|
4611
|
+
const spTree = spTreeOf(part?.dom.documentElement);
|
|
4538
4612
|
if (!part || !spTree) return;
|
|
4539
4613
|
rescaleSpTree(spTree, transform);
|
|
4540
4614
|
part.markDirty();
|
|
@@ -4562,8 +4636,6 @@ const PACKAGE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relat
|
|
|
4562
4636
|
const AUDIO_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/audio";
|
|
4563
4637
|
const VIDEO_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video";
|
|
4564
4638
|
const MS_MEDIA_REL = "http://schemas.microsoft.com/office/2007/relationships/media";
|
|
4565
|
-
const SLIDE_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slide+xml";
|
|
4566
|
-
const NOTES_SLIDE_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml";
|
|
4567
4639
|
const CHART_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml";
|
|
4568
4640
|
const CHARTEX_CONTENT_TYPE = "application/vnd.ms-office.chartex+xml";
|
|
4569
4641
|
const CHART_STYLE_CONTENT_TYPE = "application/vnd.ms-office.chartstyle+xml";
|
|
@@ -4841,7 +4913,7 @@ var Presentation = class Presentation {
|
|
|
4841
4913
|
const slideRels = this.opc.relationshipsFor(partName);
|
|
4842
4914
|
const formerTargets = [...slideRels].filter((rel) => rel.targetMode !== "External").map((rel) => slideRels.resolveTarget(rel.id));
|
|
4843
4915
|
const presPart = this.presentationPart;
|
|
4844
|
-
const presRels = this
|
|
4916
|
+
const presRels = presentationRels(this);
|
|
4845
4917
|
const root = presPart.dom.documentElement;
|
|
4846
4918
|
const sldIdLst = root && firstChild(root, "p:sldIdLst");
|
|
4847
4919
|
if (sldIdLst) for (const sldId of getElements(sldIdLst, "p:sldId")) {
|
|
@@ -5413,7 +5485,7 @@ var Presentation = class Presentation {
|
|
|
5413
5485
|
*/
|
|
5414
5486
|
#insertSlidePart(newPart, at) {
|
|
5415
5487
|
const presPart = this.presentationPart;
|
|
5416
|
-
const presRels = this
|
|
5488
|
+
const presRels = presentationRels(this);
|
|
5417
5489
|
for (const rel of presRels) {
|
|
5418
5490
|
if (rel.type !== "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" || rel.targetMode === "External") continue;
|
|
5419
5491
|
if (presRels.resolveTarget(rel.id) !== newPart.partName) continue;
|
|
@@ -5453,4 +5525,4 @@ var Presentation = class Presentation {
|
|
|
5453
5525
|
//#endregion
|
|
5454
5526
|
export { Placeholder as a, Theme as c, NotesSlide as d, OpcPackage as f, ContentTypes as h, Slide as i, readTagsForPart as l, Part as m, readCoreProperties as n, SlideLayout as o, Relationships as p, readCustomProperties as r, SlideMaster as s, Presentation as t, NotesPlaceholder as u };
|
|
5455
5527
|
|
|
5456
|
-
//# sourceMappingURL=presentation-
|
|
5528
|
+
//# sourceMappingURL=presentation-VfJ_FT7E.js.map
|