@shbernal/ts-pptx 2.0.0 → 3.0.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 +7 -2
- package/dist/{autopage-tmfjRzL4.js → autopage-MxulehqQ.js} +3 -4
- package/dist/{autopage-tmfjRzL4.js.map → autopage-MxulehqQ.js.map} +1 -1
- package/dist/browser.d.ts +14 -6
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +12 -4
- package/dist/browser.js.map +1 -1
- package/dist/{diagnostics-CQ0JWc9m.d.ts → diagnostics-BqBTmA3a.d.ts} +95 -6
- package/dist/diagnostics-BqBTmA3a.d.ts.map +1 -0
- package/dist/{enums-D3aF4QGb.d.ts → enums-oLLeaSW3.d.ts} +2 -1
- package/dist/{enums-D3aF4QGb.d.ts.map → enums-oLLeaSW3.d.ts.map} +1 -1
- package/dist/{errors-B22h8Qd0.d.ts → errors-BENA-Xuw.d.ts} +3 -3
- package/dist/{errors-B22h8Qd0.d.ts.map → errors-BENA-Xuw.d.ts.map} +1 -1
- package/dist/{fit-BSWY0AYt.js → fit-DGSwMMNs.js} +0 -0
- package/dist/{fit-BSWY0AYt.js.map → fit-DGSwMMNs.js.map} +1 -1
- package/dist/{html-dom-BQLUntho.js → html-dom--J-Xuucf.js} +18 -4
- package/dist/html-dom--J-Xuucf.js.map +1 -0
- package/dist/html.d.ts +3 -3
- package/dist/html.d.ts.map +1 -1
- package/dist/html.js +6 -3
- package/dist/html.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +1 -1
- package/dist/inspect.js +2 -2
- package/dist/inspect.js.map +1 -1
- package/dist/math.d.ts +1 -1
- package/dist/math.js.map +1 -1
- package/dist/measure.d.ts +2 -2
- package/dist/measure.js +1 -1
- package/dist/node.d.ts +14 -6
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +11 -3
- package/dist/node.js.map +1 -1
- package/dist/{pres-GU-jjBEx.d.ts → pres-2WsBGimU.d.ts} +3 -3
- package/dist/{pres-GU-jjBEx.d.ts.map → pres-2WsBGimU.d.ts.map} +1 -1
- package/dist/{presentation-CVaTZw1V.d.ts → presentation-CTVPpiwP.d.ts} +711 -582
- package/dist/presentation-CTVPpiwP.d.ts.map +1 -0
- package/dist/{presentation-MJe9WDi4.js → presentation-DAcOfzsP.js} +861 -341
- package/dist/presentation-DAcOfzsP.js.map +1 -0
- package/dist/read.d.ts +4 -4
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +2 -2
- package/dist/script.d.ts +2 -2
- package/dist/script.d.ts.map +1 -1
- package/dist/script.js +0 -0
- package/dist/script.js.map +1 -1
- package/dist/{shapes-CaOgR0i1.js → shapes-BWifcHDV.js} +670 -1034
- package/dist/shapes-BWifcHDV.js.map +1 -0
- package/dist/{slide-BBlElWr9.d.ts → slide-YuSCGa45.d.ts} +197 -22
- package/dist/slide-YuSCGa45.d.ts.map +1 -0
- package/dist/{image-size-C8uYE8GJ.js → st-enums-CgadEyPM.js} +233 -2
- package/dist/st-enums-CgadEyPM.js.map +1 -0
- package/dist/{text-B1ZrPEeK.js → text-120VFSDm.js} +717 -314
- package/dist/text-120VFSDm.js.map +1 -0
- package/dist/{units-internal-7JcMfYti.js → units-internal-CiFWZWk4.js} +2 -1
- package/dist/units-internal-CiFWZWk4.js.map +1 -0
- package/dist/zip.d.ts +2 -2
- package/dist/zip.js.map +1 -1
- package/package.json +30 -17
- package/dist/diagnostics-CQ0JWc9m.d.ts.map +0 -1
- package/dist/html-dom-BQLUntho.js.map +0 -1
- package/dist/image-size-C8uYE8GJ.js.map +0 -1
- package/dist/presentation-CVaTZw1V.d.ts.map +0 -1
- package/dist/presentation-MJe9WDi4.js.map +0 -1
- package/dist/shapes-CaOgR0i1.js.map +0 -1
- package/dist/slide-BBlElWr9.d.ts.map +0 -1
- package/dist/text-B1ZrPEeK.js.map +0 -1
- package/dist/units-internal-7JcMfYti.js.map +0 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { i as PackageReadError, n as InvalidOptionError, o as UnsupportedFeatureError, t as InternalError } from "./errors-DGE9zh3U.js";
|
|
2
2
|
import { d as emuToInches } from "./units-B-JUKwCS.js";
|
|
3
|
+
import { _ as SLIDE_LAYOUT_REL, b as THEME_REL, d as IMAGE_REL, f as NOTES_MASTER_REL, m as OFFICE_DOCUMENT_REL, p as NOTES_SLIDE_REL, v as SLIDE_MASTER_REL, y as SLIDE_REL } from "./st-enums-CgadEyPM.js";
|
|
3
4
|
import { i as FONT_REL_TYPE, n as FONT_DATA_CONTENT_TYPE, r as FONT_DATA_EXTENSION, t as EMBEDDED_FONT_SLOTS } from "./embedded-fonts-MaynAHa9.js";
|
|
4
5
|
import { ZipWriter, readZip } from "./zip.js";
|
|
5
|
-
import { $ as
|
|
6
|
+
import { $ as resolveColor, A as resolveColorElement, At as getOrAddChild, B as placeholderInheritedColor, Ct as childElements, D as readPatternFill, Dt as firstChild, E as spPrXfrmEmu, Et as escapeXmlAttribute, F as resolveSlideThemeParts, Ft as removeAttr, G as slideDefinesColor, H as placeholderInheritedRunProps, It as removeChildrenByQName, J as fmtEntry, K as slideDefinesProp, L as LST_STYLE_LEVELS, Lt as replaceInParent, M as resolveMasterColorContext, Mt as intValue, N as resolveNotesColorContext, Nt as ownerDocumentOf, O as readPictureFill, Ot as firstChildElement, P as resolveSlideColorContext, Pt as parseXml, Q as parseClrScheme, R as RUN_PROP_NAMES, Rt as serializeXml, St as boolValue, T as TextFrame, Tt as descendantsByTag, U as placeholderInheritedXfrm, V as placeholderInheritedListStyles, W as placeholderOf, X as isA, Y as intAttr, Z as parseClrMap, _t as resolveRelativePartName, at as RPR_FILL_AFTER, b as Picture, bt as OOXML_NS, c as wrapShapeElement, ct as SPPR_EFFECT_AFTER, dt as SPPR_SCENE3D_AFTER, et as resolveSchemeToken, ft as SPPR_SP3D_AFTER, gt as relsPartNameFor, ht as relativePartName, it as FILL_CHOICES, j as resolveLayoutColorContext, jt as insertInOrder, k as readGradientFill, kt as getElements, l as GraphicFrame, lt as SPPR_FILL_AFTER, mt as partNameToZipPath, n as buildShapes, nt as styleRefLine, ot as SHAPE_AFTER_SPPR, pt as partNameExtension, q as SCHEME_SLOTS, rt as substitutePhClr, st as SPPR_AFTER_XFRM, t as GroupShape, tt as styleRefFill, ut as SPPR_LN_AFTER, vt as resolveSingleRel, wt as createElement, x as AutoShape, xt as attr, yt as zipPathToPartName, z as placeholderInheritedAnchor, zt as setAttr } from "./shapes-BWifcHDV.js";
|
|
6
7
|
//#region src/read/opc/content-types.ts
|
|
7
8
|
/**
|
|
8
9
|
* Overlay over `[Content_Types].xml`, used to resolve part content types at
|
|
@@ -420,6 +421,477 @@ var OpcPackage = class OpcPackage {
|
|
|
420
421
|
}
|
|
421
422
|
};
|
|
422
423
|
//#endregion
|
|
424
|
+
//#region src/read/api/ops/flatten.ts
|
|
425
|
+
/**
|
|
426
|
+
* Baking a slide's theme dependencies into the slide itself, for `Presentation.importSlide` /
|
|
427
|
+
* `importShape`.
|
|
428
|
+
*
|
|
429
|
+
* A slide imported into another deck is rebound to the *destination* master, so everything it
|
|
430
|
+
* resolved symbolically against its own theme silently re-resolves against a different one — its
|
|
431
|
+
* scheme colours change, its style-matrix fills change, its placeholders snap to different
|
|
432
|
+
* geometry and type sizes. The `theme: 'preserve'` mode exists to stop that: each pass here
|
|
433
|
+
* resolves a dependency against the **source** theme (via `read/oxml/theme.ts` and
|
|
434
|
+
* `read/oxml/placeholder-inherit.ts`) and writes the answer explicitly onto the slide, so after
|
|
435
|
+
* the rebind there is nothing left to re-resolve.
|
|
436
|
+
*
|
|
437
|
+
* What gets flattened, and why each one matters:
|
|
438
|
+
*
|
|
439
|
+
* 1. **`a:schemeClr` tokens** — rewritten to the literal `a:srgbClr` the source `clrMap` +
|
|
440
|
+
* `clrScheme` produce. Child transforms (`lumMod`/`shade`/`alpha`/…) are carried through
|
|
441
|
+
* untouched, so tints and shades render identically; only the *base* reference is swapped,
|
|
442
|
+
* never the transform math.
|
|
443
|
+
* 2. **Style-matrix refs** — a shape's `p:style` (`lnRef`/`fillRef`/`effectRef`) indexes the
|
|
444
|
+
* theme `fmtScheme`; the indexed entry is resolved into an explicit `spPr` fill/line/effect
|
|
445
|
+
* (with its `phClr` substituted) and the ref neutralized so it cannot re-resolve. The
|
|
446
|
+
* `fontRef` is deliberately left intact so its font can re-bind to the destination theme —
|
|
447
|
+
* the "normalize fonts on attach" bonus.
|
|
448
|
+
* 3. **Placeholder-inherited run colour, size and weight** — a run that sets none of its own
|
|
449
|
+
* takes them from the source placeholder → layout → master text-style chain. Rebinding
|
|
450
|
+
* replaces that chain, so each is resolved from the source styles and written onto the run.
|
|
451
|
+
* Typeface (`a:latin`) is deliberately *not* baked — it re-binds along with `fontRef`.
|
|
452
|
+
* 4. **Placeholder-inherited geometry** — a placeholder with no own `a:xfrm` takes position and
|
|
453
|
+
* size from the matching source layout/master placeholder; without baking it, a title snaps
|
|
454
|
+
* to the destination default and often clips off-canvas.
|
|
455
|
+
*
|
|
456
|
+
* The `restyle` mode is the deliberate inverse ({@link restyleSlide}): it bakes *nothing*, so
|
|
457
|
+
* everything re-resolves against the destination and the slide takes on the new brand.
|
|
458
|
+
*
|
|
459
|
+
* **Why this lives in `api/ops/` and not in `read/oxml/`.** Everything here *mutates* a live
|
|
460
|
+
* part. The modules it calls into resolve and build detached elements but never write, which is
|
|
461
|
+
* what lets the read model's getters share them; keeping the writes on this side of the line is
|
|
462
|
+
* what keeps that true. Callers own marking the part dirty.
|
|
463
|
+
*/
|
|
464
|
+
/**
|
|
465
|
+
* Flatten one slide's theme dependencies in place:
|
|
466
|
+
*
|
|
467
|
+
* 1. carry the background the slide inherited from its source layout/master onto
|
|
468
|
+
* the slide (so it survives rebinding to a different master);
|
|
469
|
+
* 2. materialize `p:bgRef` and style-matrix refs into explicit fills/lines/effects;
|
|
470
|
+
* 3. bake each placeholder's effective geometry (inherited `a:xfrm`) onto the
|
|
471
|
+
* shape so a rebind cannot move or resize it;
|
|
472
|
+
* 4. bake each placeholder run's effective colour and size/weight (inherited from
|
|
473
|
+
* the source layout/master text styles) explicitly onto the run;
|
|
474
|
+
* 5. rewrite every remaining `a:schemeClr` to its literal `a:srgbClr`.
|
|
475
|
+
*
|
|
476
|
+
* Steps run in this order so the inherited/materialized backgrounds are present
|
|
477
|
+
* before the final scheme-colour sweep resolves the colours they carry. The
|
|
478
|
+
* placeholder geometry/colour/size passes have no data dependency on the others.
|
|
479
|
+
* The caller marks the part dirty.
|
|
480
|
+
*/
|
|
481
|
+
function flattenSlide(slideRoot, ctx) {
|
|
482
|
+
applyInheritedBackground(slideRoot, ctx);
|
|
483
|
+
materializeBackground(slideRoot, ctx);
|
|
484
|
+
materializeStyleRefs(slideRoot, ctx);
|
|
485
|
+
resolvePlaceholderGeometry(slideRoot, ctx);
|
|
486
|
+
resolvePlaceholderRunColors(slideRoot, ctx);
|
|
487
|
+
resolvePlaceholderRunSizes(slideRoot, ctx);
|
|
488
|
+
resolveSchemeColors(slideRoot, ctx);
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Flatten a single lifted shape's theme dependencies in place — the shape-scoped
|
|
492
|
+
* subset of {@link flattenSlide} used by `Presentation.importShape` `preserve`
|
|
493
|
+
* mode. It runs every pass that resolves a *shape's* theme references against the
|
|
494
|
+
* source theme (style-matrix refs, placeholder-inherited geometry/colour/size/
|
|
495
|
+
* anchor/list-style, scheme colours) but deliberately **omits** the two
|
|
496
|
+
* slide-scoped background passes (`applyInheritedBackground`/`materializeBackground`):
|
|
497
|
+
* a background belongs to a slide, not to a shape being composed onto a foreign host.
|
|
498
|
+
*
|
|
499
|
+
* Unlike {@link flattenSlide}, this also **demotes** a lifted placeholder to a
|
|
500
|
+
* plain shape ({@link demotePlaceholders}) once everything it inherited is baked.
|
|
501
|
+
* A placeholder makes sense on its own slide, where it resolves against that deck's
|
|
502
|
+
* master/layout; lifted onto a foreign host its surviving `p:ph` would re-resolve
|
|
503
|
+
* against the *host* placeholder of the same type/idx (wrong inheritance, or a
|
|
504
|
+
* fallback when absent) and could collide with the host's own placeholder. The
|
|
505
|
+
* extra bakes here (anchor + list style, on top of the geometry/colour/size the
|
|
506
|
+
* shared passes cover) make the shape self-contained so demotion loses nothing
|
|
507
|
+
* visible. This is why the demotion is scoped to `flattenShape`: `flattenSlide`
|
|
508
|
+
* keeps placeholders as placeholders by design.
|
|
509
|
+
*
|
|
510
|
+
* `shapeRoot` must be an element whose *descendants* include the lifted shape
|
|
511
|
+
* (the passes match via `getElementsByTagNameNS`, which excludes the root element
|
|
512
|
+
* itself) — the caller wraps the imported `p:sp`/`p:pic`/`p:graphicFrame`/`p:grpSp`
|
|
513
|
+
* in a throwaway container before calling. The caller marks the part dirty.
|
|
514
|
+
*/
|
|
515
|
+
function flattenShape(shapeRoot, ctx) {
|
|
516
|
+
materializeStyleRefs(shapeRoot, ctx);
|
|
517
|
+
resolvePlaceholderGeometry(shapeRoot, ctx);
|
|
518
|
+
resolvePlaceholderRunColors(shapeRoot, ctx);
|
|
519
|
+
resolvePlaceholderRunSizes(shapeRoot, ctx);
|
|
520
|
+
resolvePlaceholderBodyPr(shapeRoot, ctx);
|
|
521
|
+
resolvePlaceholderListStyle(shapeRoot, ctx);
|
|
522
|
+
resolveSchemeColors(shapeRoot, ctx);
|
|
523
|
+
demotePlaceholders(shapeRoot);
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Restyle a rebound slide in place (the `theme: 'restyle'` mode): the exact
|
|
527
|
+
* inverse of {@link flattenSlide}. It bakes *nothing* — leaving every
|
|
528
|
+
* `a:schemeClr`/style-matrix ref and `p:bg` `bgRef` symbolic is the whole point,
|
|
529
|
+
* so they re-resolve against the *destination* master's `clrMap` + theme once the
|
|
530
|
+
* slide is rebound. The single mutation is dropping the slide's own colour-map
|
|
531
|
+
* override (`p:clrMapOvr/a:overrideClrMapping`): a source override would keep
|
|
532
|
+
* mapping the slide's scheme-token names the source way and defeat the re-brand,
|
|
533
|
+
* so it must yield to the destination master's `p:clrMap`.
|
|
534
|
+
*
|
|
535
|
+
* Caveat carried from the plan: only *symbolic* colours re-brand. Anything the
|
|
536
|
+
* source authored as a literal `a:srgbClr` has no theme reference to re-resolve
|
|
537
|
+
* and stays exactly that colour. The caller marks the part dirty.
|
|
538
|
+
*/
|
|
539
|
+
function restyleSlide(slideRoot) {
|
|
540
|
+
removeChildrenByQName(slideRoot, ["p:clrMapOvr"]);
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* The optional inverse of {@link resolveSchemeColors}, for `restyle`'s
|
|
544
|
+
* force-remap-literals mode (the `Presentation.importSlide` `remapLiterals`
|
|
545
|
+
* option). Every literal `a:srgbClr` whose value equals a *source* `clrScheme`
|
|
546
|
+
* slot is rewritten back to a symbolic `a:schemeClr` so it re-resolves against the
|
|
547
|
+
* destination theme; a literal matching no slot (the common case) is left exactly
|
|
548
|
+
* as authored. Transform children (`lumMod`/`shade`/`alpha`/…) are carried across.
|
|
549
|
+
*
|
|
550
|
+
* Plain `restyle` cannot re-brand a literal — it carries no theme reference. This
|
|
551
|
+
* re-introduces one by matching the literal's RGB against the slots the *source*
|
|
552
|
+
* theme defined, emitting the scheme token that routes through the source `clrMap`
|
|
553
|
+
* (so a literal equal to the source `accent1` slot becomes `schemeClr accent1`,
|
|
554
|
+
* which the destination `clrMap`/theme then re-resolve). Slots are matched in
|
|
555
|
+
* `clrScheme` order, so the first slot defining a given RGB wins when several share
|
|
556
|
+
* it. Opt-in because it deliberately reinterprets authored literals as theme
|
|
557
|
+
* colours — visual QA territory, the same caveat as the rest of `restyle`.
|
|
558
|
+
*/
|
|
559
|
+
function remapLiteralColors(slideRoot, ctx) {
|
|
560
|
+
const slotByHex = reverseClrScheme(ctx.clrScheme);
|
|
561
|
+
if (slotByHex.size === 0) return;
|
|
562
|
+
const tokenBySlot = reverseClrMap(ctx.clrMap);
|
|
563
|
+
const doc = ownerDocumentOf(slideRoot);
|
|
564
|
+
for (const srgb of descendantsByTag(slideRoot, OOXML_NS.a, "srgbClr")) {
|
|
565
|
+
const hex = attr(srgb, "val");
|
|
566
|
+
const slot = hex ? slotByHex.get(hex.toUpperCase()) : void 0;
|
|
567
|
+
if (!slot) continue;
|
|
568
|
+
const scheme = createElement(doc, "a:schemeClr");
|
|
569
|
+
setAttr(scheme, "val", tokenBySlot.get(slot) ?? slot);
|
|
570
|
+
while (srgb.firstChild) scheme.appendChild(srgb.firstChild);
|
|
571
|
+
replaceInParent(srgb, scheme);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
/** Reverse a slot → RGB `clrScheme` into RGB → slot, in `SCHEME_SLOTS` order (first slot wins on a shared RGB). */
|
|
575
|
+
function reverseClrScheme(clrScheme) {
|
|
576
|
+
const out = /* @__PURE__ */ new Map();
|
|
577
|
+
for (const slot of SCHEME_SLOTS) {
|
|
578
|
+
const hex = clrScheme.get(slot);
|
|
579
|
+
if (hex && !out.has(hex.toUpperCase())) out.set(hex.toUpperCase(), slot);
|
|
580
|
+
}
|
|
581
|
+
return out;
|
|
582
|
+
}
|
|
583
|
+
/** Reverse a token → slot `clrMap` into slot → token (first token wins on a shared slot). */
|
|
584
|
+
function reverseClrMap(clrMap) {
|
|
585
|
+
const out = /* @__PURE__ */ new Map();
|
|
586
|
+
for (const [token, slot] of clrMap) if (!out.has(slot)) out.set(slot, token);
|
|
587
|
+
return out;
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* If the slide has no own `p:bg`, insert (a copy of) the background it inherited
|
|
591
|
+
* from its source layout/master as an explicit `p:cSld/p:bg`. The clone is left
|
|
592
|
+
* unresolved here; the later passes flatten its `bgRef`/`schemeClr` in place.
|
|
593
|
+
*/
|
|
594
|
+
function applyInheritedBackground(slideRoot, ctx) {
|
|
595
|
+
const inherited = ctx.inheritedBackground;
|
|
596
|
+
if (!inherited) return;
|
|
597
|
+
const cSld = firstChild(slideRoot, "p:cSld");
|
|
598
|
+
if (!cSld || firstChild(cSld, "p:bg")) return;
|
|
599
|
+
const bg = ownerDocumentOf(slideRoot).importNode(inherited, true);
|
|
600
|
+
insertInOrder(cSld, bg, [
|
|
601
|
+
"p:spTree",
|
|
602
|
+
"p:custDataLst",
|
|
603
|
+
"p:controls",
|
|
604
|
+
"p:extLst"
|
|
605
|
+
]);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Resolve every `p:bgRef` (theme-indexed background) under the slide into an
|
|
609
|
+
* explicit `p:bgPr` fill, so the background no longer depends on the destination
|
|
610
|
+
* theme's `fmtScheme`. A `bgPr` background is left for the scheme-colour sweep.
|
|
611
|
+
*/
|
|
612
|
+
function materializeBackground(slideRoot, ctx) {
|
|
613
|
+
const doc = ownerDocumentOf(slideRoot);
|
|
614
|
+
for (const bg of descendantsByTag(slideRoot, OOXML_NS.p, "bg")) {
|
|
615
|
+
const bgRef = firstChild(bg, "p:bgRef");
|
|
616
|
+
if (!bgRef) continue;
|
|
617
|
+
const fill = styleRefFill(bgRef, ctx);
|
|
618
|
+
const bgPr = createElement(doc, "p:bgPr");
|
|
619
|
+
bgPr.appendChild(fill ?? createElement(doc, "a:noFill"));
|
|
620
|
+
bg.replaceChild(bgPr, bgRef);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
/** Rewrite every `a:schemeClr` under `root` to a literal `a:srgbClr` when resolvable. */
|
|
624
|
+
function resolveSchemeColors(root, ctx) {
|
|
625
|
+
const doc = ownerDocumentOf(root);
|
|
626
|
+
for (const schemeClr of descendantsByTag(root, OOXML_NS.a, "schemeClr")) {
|
|
627
|
+
const token = attr(schemeClr, "val");
|
|
628
|
+
const hex = token ? resolveSchemeToken(token, ctx) : null;
|
|
629
|
+
if (!hex) continue;
|
|
630
|
+
const srgb = createElement(doc, "a:srgbClr");
|
|
631
|
+
setAttr(srgb, "val", hex);
|
|
632
|
+
while (schemeClr.firstChild) srgb.appendChild(schemeClr.firstChild);
|
|
633
|
+
replaceInParent(schemeClr, srgb);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Bake placeholder-inherited run colours onto the slide. For each placeholder run
|
|
638
|
+
* that defines no colour of its own (nor at paragraph/text-body level on the
|
|
639
|
+
* *slide*), resolve the colour it would inherit from the source
|
|
640
|
+
* `slideLayout`/`slideMaster` text styles and write it explicitly onto the run's
|
|
641
|
+
* `a:rPr`. After this the run's colour cannot change when the slide is rebound to
|
|
642
|
+
* the destination master. `a:fld` runs (dates, slide numbers) are treated like
|
|
643
|
+
* `a:r`. Only colour is resolved; other inheritable run properties are left to
|
|
644
|
+
* re-bind to the destination styles.
|
|
645
|
+
*/
|
|
646
|
+
function resolvePlaceholderRunColors(slideRoot, ctx) {
|
|
647
|
+
if (!ctx.layoutRoot && !ctx.masterRoot) return;
|
|
648
|
+
for (const sp of descendantsByTag(slideRoot, OOXML_NS.p, "sp")) {
|
|
649
|
+
const ph = placeholderOf(sp);
|
|
650
|
+
if (!ph) continue;
|
|
651
|
+
const txBody = firstChild(sp, "p:txBody");
|
|
652
|
+
if (!txBody) continue;
|
|
653
|
+
const type = attr(ph, "type");
|
|
654
|
+
const idx = attr(ph, "idx") ?? "0";
|
|
655
|
+
const slideLst = firstChild(txBody, "a:lstStyle");
|
|
656
|
+
const byLevel = /* @__PURE__ */ new Map();
|
|
657
|
+
for (const p of getElements(txBody, "a:p")) {
|
|
658
|
+
const pPr = firstChild(p, "a:pPr");
|
|
659
|
+
const level = (pPr && intValue(attr(pPr, "lvl"))) ?? 0;
|
|
660
|
+
const runs = [...getElements(p, "a:r"), ...getElements(p, "a:fld")];
|
|
661
|
+
if (runs.length === 0) continue;
|
|
662
|
+
let color = byLevel.get(level);
|
|
663
|
+
if (color === void 0) {
|
|
664
|
+
color = placeholderInheritedColor(type, idx, level, ctx);
|
|
665
|
+
byLevel.set(level, color);
|
|
666
|
+
}
|
|
667
|
+
if (!color) continue;
|
|
668
|
+
for (const run of runs) {
|
|
669
|
+
if (slideDefinesColor(run, pPr, slideLst, level)) continue;
|
|
670
|
+
writeRunColor(run, color);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
/** Write a resolved colour as an explicit `a:solidFill` (with carried transforms) onto a run's `a:rPr`. */
|
|
676
|
+
function writeRunColor(run, color) {
|
|
677
|
+
const doc = ownerDocumentOf(run);
|
|
678
|
+
const rPr = getOrAddChild(run, "a:rPr", ["a:t"]);
|
|
679
|
+
const fill = createElement(doc, "a:solidFill");
|
|
680
|
+
const srgb = createElement(doc, "a:srgbClr");
|
|
681
|
+
setAttr(srgb, "val", color.hex);
|
|
682
|
+
for (const t of color.transforms) srgb.appendChild(t.cloneNode(true));
|
|
683
|
+
fill.appendChild(srgb);
|
|
684
|
+
insertInOrder(rPr, fill, RPR_FILL_AFTER);
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Bake placeholder-inherited geometry onto the slide. A placeholder shape
|
|
688
|
+
* that carries no own `p:spPr/a:xfrm` takes its position/size from the matching
|
|
689
|
+
* source `slideLayout` placeholder, else the `slideMaster` placeholder. Rebinding
|
|
690
|
+
* to the destination master replaces that inheritance, so the placeholder would
|
|
691
|
+
* snap to the destination default (often clipping off-canvas). We deep-clone the
|
|
692
|
+
* effective source `a:xfrm` and write it explicitly onto the shape. Shapes with
|
|
693
|
+
* their own `a:xfrm` are left untouched (explicit geometry is not inherited), and
|
|
694
|
+
* an orphan placeholder with no source match keeps the current fall-back behaviour.
|
|
695
|
+
*/
|
|
696
|
+
function resolvePlaceholderGeometry(slideRoot, ctx) {
|
|
697
|
+
if (!ctx.layoutRoot && !ctx.masterRoot) return;
|
|
698
|
+
for (const sp of descendantsByTag(slideRoot, OOXML_NS.p, "sp")) {
|
|
699
|
+
const ph = placeholderOf(sp);
|
|
700
|
+
if (!ph) continue;
|
|
701
|
+
const spPr = firstChild(sp, "p:spPr");
|
|
702
|
+
if (spPr && firstChild(spPr, "a:xfrm")) continue;
|
|
703
|
+
const found = placeholderInheritedXfrm(attr(ph, "type"), attr(ph, "idx") ?? "0", ctx);
|
|
704
|
+
if (!found) continue;
|
|
705
|
+
const target = getOrAddChild(sp, "p:spPr", SHAPE_AFTER_SPPR);
|
|
706
|
+
insertInOrder(target, found.xfrm.cloneNode(true), SPPR_AFTER_XFRM);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* Bake the placeholder-inherited vertical anchor onto a lifted shape's text body
|
|
711
|
+
* (the {@link flattenShape} placeholder-demotion path). A placeholder whose own
|
|
712
|
+
* `a:bodyPr` sets no `@anchor` inherits it from the source layout/master placeholder;
|
|
713
|
+
* once {@link demotePlaceholders} strips the `p:ph` the shape would lose that
|
|
714
|
+
* inheritance and fall back to top-anchored, so a vertically-centred title jumps.
|
|
715
|
+
* We resolve the effective anchor from the source chain and write it explicitly.
|
|
716
|
+
* Shapes whose `a:bodyPr` already fixes `@anchor`, and placeholders with no
|
|
717
|
+
* resolvable inherited anchor, are left untouched. Other `a:bodyPr` knobs (insets,
|
|
718
|
+
* autofit) are left as authored — they have sane defaults a plain shape keeps.
|
|
719
|
+
*/
|
|
720
|
+
function resolvePlaceholderBodyPr(shapeRoot, ctx) {
|
|
721
|
+
if (!ctx.layoutRoot && !ctx.masterRoot) return;
|
|
722
|
+
for (const sp of descendantsByTag(shapeRoot, OOXML_NS.p, "sp")) {
|
|
723
|
+
const ph = placeholderOf(sp);
|
|
724
|
+
if (!ph) continue;
|
|
725
|
+
const txBody = firstChild(sp, "p:txBody");
|
|
726
|
+
if (!txBody) continue;
|
|
727
|
+
const bodyPr = firstChild(txBody, "a:bodyPr");
|
|
728
|
+
if (bodyPr && attr(bodyPr, "anchor") != null) continue;
|
|
729
|
+
const anchor = placeholderInheritedAnchor(attr(ph, "type"), attr(ph, "idx") ?? "0", ctx);
|
|
730
|
+
if (!anchor) continue;
|
|
731
|
+
setAttr(bodyPr ?? getOrAddChild(txBody, "a:bodyPr", ["a:lstStyle", "a:p"]), "anchor", anchor);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Bake the placeholder-inherited list style onto a lifted shape's text body (the
|
|
736
|
+
* {@link flattenShape} placeholder-demotion path). A placeholder's per-level
|
|
737
|
+
* *paragraph* formatting — indent (`marL`/`indent`), bullets (`a:buChar`/
|
|
738
|
+
* `a:buAutoNum`/`a:buNone`), alignment, and the level `a:defRPr` — is inherited
|
|
739
|
+
* from the source layout/master placeholder `a:lstStyle` and the master
|
|
740
|
+
* `p:txStyles` category style. Run colour/size are baked onto each run by the
|
|
741
|
+
* sibling passes, but paragraph-level defaults live here; once
|
|
742
|
+
* {@link demotePlaceholders} strips the `p:ph` the shape stops inheriting them, so
|
|
743
|
+
* bullets and indents would vanish. We materialize the effective list style onto
|
|
744
|
+
* the shape's `p:txBody/a:lstStyle`.
|
|
745
|
+
*
|
|
746
|
+
* Resolution is per *level*, most specific tier wins whole: the slide's own level
|
|
747
|
+
* (if it defines one) is kept verbatim, else the first source tier that defines it
|
|
748
|
+
* (layout placeholder, then master placeholder, then master category style) is
|
|
749
|
+
* cloned. This is a whole-element overlay, not the per-attribute merge PowerPoint
|
|
750
|
+
* does — but explicit paragraph `a:pPr` on the slide's own runs travels with the
|
|
751
|
+
* shape and still wins, so this only supplies defaults for the inherited case
|
|
752
|
+
* (paragraphs that set no `a:pPr` of their own). Scheme colours in the cloned
|
|
753
|
+
* levels are resolved by the later `resolveSchemeColors` pass.
|
|
754
|
+
*/
|
|
755
|
+
function resolvePlaceholderListStyle(shapeRoot, ctx) {
|
|
756
|
+
if (!ctx.layoutRoot && !ctx.masterRoot) return;
|
|
757
|
+
for (const sp of descendantsByTag(shapeRoot, OOXML_NS.p, "sp")) {
|
|
758
|
+
const ph = placeholderOf(sp);
|
|
759
|
+
if (!ph) continue;
|
|
760
|
+
const txBody = firstChild(sp, "p:txBody");
|
|
761
|
+
if (!txBody) continue;
|
|
762
|
+
const tiers = placeholderInheritedListStyles(attr(ph, "type"), attr(ph, "idx") ?? "0", ctx);
|
|
763
|
+
if (tiers.length === 0) continue;
|
|
764
|
+
const slideLst = firstChild(txBody, "a:lstStyle");
|
|
765
|
+
const merged = createElement(ownerDocumentOf(txBody), "a:lstStyle");
|
|
766
|
+
let any = false;
|
|
767
|
+
for (const level of LST_STYLE_LEVELS) {
|
|
768
|
+
const src = (slideLst && firstChild(slideLst, level)) ?? tiers.map((t) => firstChild(t, level)).find((e) => !!e) ?? null;
|
|
769
|
+
if (!src) continue;
|
|
770
|
+
merged.appendChild(src.cloneNode(true));
|
|
771
|
+
any = true;
|
|
772
|
+
}
|
|
773
|
+
if (!any) continue;
|
|
774
|
+
if (slideLst) txBody.replaceChild(merged, slideLst);
|
|
775
|
+
else insertInOrder(txBody, merged, ["a:p"]);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Strip the `p:ph` marker from every placeholder shape in a lifted subtree so it
|
|
780
|
+
* becomes a self-contained ordinary shape (the {@link flattenShape} path only). By
|
|
781
|
+
* the time this runs, the shape's inherited geometry, colour, run size, anchor, and
|
|
782
|
+
* list style are all baked explicitly, so it no longer needs — and must not keep —
|
|
783
|
+
* its placeholder identity: a surviving `p:ph` would re-resolve against the *host*
|
|
784
|
+
* deck's layout/master placeholder of the same type/idx (wrong inheritance, or a
|
|
785
|
+
* fallback when the host has none) and could collide with the host slide's own
|
|
786
|
+
* placeholder of that type. Removing the marker severs both. The `p:nvPr` itself is
|
|
787
|
+
* kept (it can carry media/custom-data children); only the `p:ph` child goes.
|
|
788
|
+
*/
|
|
789
|
+
function demotePlaceholders(shapeRoot) {
|
|
790
|
+
for (const sp of descendantsByTag(shapeRoot, OOXML_NS.p, "sp")) {
|
|
791
|
+
const nvSpPr = firstChild(sp, "p:nvSpPr");
|
|
792
|
+
const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
|
|
793
|
+
if (nvPr) removeChildrenByQName(nvPr, ["p:ph"]);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Bake placeholder-inherited run size/weight onto the slide. Mirrors
|
|
798
|
+
* {@link resolvePlaceholderRunColors}: for each placeholder run that sets no
|
|
799
|
+
* `sz`/`b`/`i` of its own (nor at paragraph/text-body level on the *slide*),
|
|
800
|
+
* resolve the value it would inherit from the source `slideLayout`/`slideMaster`
|
|
801
|
+
* text styles — per paragraph list level — and write it explicitly onto the run's
|
|
802
|
+
* `a:rPr`. Each property resolves independently up the chain. Typeface (`a:latin`)
|
|
803
|
+
* is left to re-bind to the destination theme, as the colour pass does for the `fontRef`.
|
|
804
|
+
*/
|
|
805
|
+
function resolvePlaceholderRunSizes(slideRoot, ctx) {
|
|
806
|
+
if (!ctx.layoutRoot && !ctx.masterRoot) return;
|
|
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
|
+
}
|
|
830
|
+
}
|
|
831
|
+
/** Write each resolved run property onto a run's `a:rPr`, skipping ones the slide already fixes. */
|
|
832
|
+
function writeRunProps(run, props, pPr, slideLst, level) {
|
|
833
|
+
let rPr = null;
|
|
834
|
+
for (const name of RUN_PROP_NAMES) {
|
|
835
|
+
const value = props[name];
|
|
836
|
+
if (value == null) continue;
|
|
837
|
+
if (slideDefinesProp(name, run, pPr, slideLst, level)) continue;
|
|
838
|
+
rPr ??= getOrAddChild(run, "a:rPr", ["a:t"]);
|
|
839
|
+
setAttr(rPr, name, value);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Resolve each shape's `p:style` `lnRef`/`fillRef`/`effectRef` into explicit
|
|
844
|
+
* `spPr` children (using the theme `fmtScheme`), then neutralize the ref. The
|
|
845
|
+
* `fontRef` is intentionally left for the destination theme to re-resolve.
|
|
846
|
+
*/
|
|
847
|
+
function materializeStyleRefs(root, ctx) {
|
|
848
|
+
if (!ctx.fmtScheme) return;
|
|
849
|
+
for (const style of descendantsByTag(root, OOXML_NS.p, "style")) {
|
|
850
|
+
const shape = style.parentNode;
|
|
851
|
+
if (!shape) continue;
|
|
852
|
+
const spPr = getOrAddChild(shape, "p:spPr", SHAPE_AFTER_SPPR);
|
|
853
|
+
materializeFill(spPr, firstChild(style, "a:fillRef"), ctx);
|
|
854
|
+
materializeLine(spPr, firstChild(style, "a:lnRef"), ctx);
|
|
855
|
+
materializeEffect(spPr, firstChild(style, "a:effectRef"), ctx);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
function materializeFill(spPr, fillRef, ctx) {
|
|
859
|
+
if (!fillRef) return;
|
|
860
|
+
if (!FILL_CHOICES.some((q) => firstChild(spPr, q))) {
|
|
861
|
+
const fill = styleRefFill(fillRef, ctx);
|
|
862
|
+
if (fill) insertInOrder(spPr, fill, SPPR_FILL_AFTER);
|
|
863
|
+
}
|
|
864
|
+
neutralizeRef(fillRef);
|
|
865
|
+
}
|
|
866
|
+
function materializeLine(spPr, lnRef, ctx) {
|
|
867
|
+
if (!lnRef) return;
|
|
868
|
+
if (!firstChild(spPr, "a:ln")) {
|
|
869
|
+
const ln = styleRefLine(lnRef, ctx);
|
|
870
|
+
if (ln) insertInOrder(spPr, ln, SPPR_LN_AFTER);
|
|
871
|
+
}
|
|
872
|
+
neutralizeRef(lnRef);
|
|
873
|
+
}
|
|
874
|
+
function materializeEffect(spPr, effectRef, ctx) {
|
|
875
|
+
if (!effectRef) return;
|
|
876
|
+
const idx = intAttr(effectRef, "idx");
|
|
877
|
+
if (idx !== null && idx > 0 && !firstChild(spPr, "a:effectLst") && !firstChild(spPr, "a:effectDag")) {
|
|
878
|
+
const style = fmtEntry(ctx, "a:effectStyleLst", idx);
|
|
879
|
+
const ref = resolveColor(firstChildElement(effectRef), ctx);
|
|
880
|
+
if (style && ref) {
|
|
881
|
+
substitutePhClr(style, ref);
|
|
882
|
+
for (const child of childElements(style)) if (isA(child, "effectLst") || isA(child, "effectDag")) insertInOrder(spPr, child, SPPR_EFFECT_AFTER);
|
|
883
|
+
else if (isA(child, "scene3d")) insertInOrder(spPr, child, SPPR_SCENE3D_AFTER);
|
|
884
|
+
else if (isA(child, "sp3d")) insertInOrder(spPr, child, SPPR_SP3D_AFTER);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
neutralizeRef(effectRef);
|
|
888
|
+
}
|
|
889
|
+
/** Strip a style-matrix ref to `idx="0"` with no colour child so it contributes nothing. */
|
|
890
|
+
function neutralizeRef(ref) {
|
|
891
|
+
setAttr(ref, "idx", "0");
|
|
892
|
+
for (const child of childElements(ref)) ref.removeChild(child);
|
|
893
|
+
}
|
|
894
|
+
//#endregion
|
|
423
895
|
//#region src/read/api/slide-background.ts
|
|
424
896
|
/**
|
|
425
897
|
* Read a slide's effective background (`p:cSld/p:bg`), decoded into a typed union.
|
|
@@ -521,13 +993,6 @@ function readSlideBackground(bg, source, ctx, rels, themeRels) {
|
|
|
521
993
|
}
|
|
522
994
|
//#endregion
|
|
523
995
|
//#region src/read/api/notes.ts
|
|
524
|
-
/** One EMU coordinate from a placeholder's `p:spPr/a:xfrm` child, or `null` when absent. */
|
|
525
|
-
function xfrmEmu$1(sp, container, axis) {
|
|
526
|
-
const spPr = firstChild(sp, "p:spPr");
|
|
527
|
-
const xfrm = spPr && firstChild(spPr, "a:xfrm");
|
|
528
|
-
const el = xfrm && firstChild(xfrm, container);
|
|
529
|
-
return el ? intValue(attr(el, axis)) : null;
|
|
530
|
-
}
|
|
531
996
|
/**
|
|
532
997
|
* One placeholder shape (`p:sp`) of a notes slide. A notes slide holds a fixed set:
|
|
533
998
|
* the slide thumbnail (`type="sldImg"`), the notes body (`type="body"`), and the
|
|
@@ -577,19 +1042,19 @@ var NotesPlaceholder = class {
|
|
|
577
1042
|
}
|
|
578
1043
|
/** Left edge in EMU (`a:off/@x`), or `null` when geometry is inherited (no own `a:xfrm`). */
|
|
579
1044
|
get left() {
|
|
580
|
-
return
|
|
1045
|
+
return spPrXfrmEmu(this.sp, "a:off", "x");
|
|
581
1046
|
}
|
|
582
1047
|
/** Top edge in EMU (`a:off/@y`), or `null` when geometry is inherited. */
|
|
583
1048
|
get top() {
|
|
584
|
-
return
|
|
1049
|
+
return spPrXfrmEmu(this.sp, "a:off", "y");
|
|
585
1050
|
}
|
|
586
1051
|
/** Width in EMU (`a:ext/@cx`), or `null` when geometry is inherited. */
|
|
587
1052
|
get width() {
|
|
588
|
-
return
|
|
1053
|
+
return spPrXfrmEmu(this.sp, "a:ext", "cx");
|
|
589
1054
|
}
|
|
590
1055
|
/** Height in EMU (`a:ext/@cy`), or `null` when geometry is inherited. */
|
|
591
1056
|
get height() {
|
|
592
|
-
return
|
|
1057
|
+
return spPrXfrmEmu(this.sp, "a:ext", "cy");
|
|
593
1058
|
}
|
|
594
1059
|
/**
|
|
595
1060
|
* The placeholder's text as a navigable {@link TextFrame} (`p:txBody`), or `null`
|
|
@@ -855,8 +1320,6 @@ function readTagsForPart(opc, ownerPartName) {
|
|
|
855
1320
|
}
|
|
856
1321
|
//#endregion
|
|
857
1322
|
//#region src/read/api/chrome.ts
|
|
858
|
-
const SLIDE_MASTER_REL$4 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
|
|
859
|
-
const THEME_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
|
|
860
1323
|
const THEME_COLOR_SLOTS = [
|
|
861
1324
|
"dk1",
|
|
862
1325
|
"lt1",
|
|
@@ -966,23 +1429,10 @@ var Theme = class {
|
|
|
966
1429
|
return themeElements ? firstChild(themeElements, "a:clrScheme") : null;
|
|
967
1430
|
}
|
|
968
1431
|
};
|
|
969
|
-
/** One EMU coordinate from a placeholder's `p:spPr/a:xfrm` child, or `null` when absent. */
|
|
970
|
-
function xfrmEmu(sp, container, axis) {
|
|
971
|
-
const spPr = firstChild(sp, "p:spPr");
|
|
972
|
-
const xfrm = spPr && firstChild(spPr, "a:xfrm");
|
|
973
|
-
const el = xfrm && firstChild(xfrm, container);
|
|
974
|
-
return el ? intValue(attr(el, axis)) : null;
|
|
975
|
-
}
|
|
976
|
-
/** The `p:ph` element of a shape (`p:sp/p:nvSpPr/p:nvPr/p:ph`), or `null` when it is not a placeholder. */
|
|
977
|
-
function placeholderElement(sp) {
|
|
978
|
-
const nvSpPr = firstChild(sp, "p:nvSpPr");
|
|
979
|
-
const nvPr = nvSpPr && firstChild(nvSpPr, "p:nvPr");
|
|
980
|
-
return nvPr ? firstChild(nvPr, "p:ph") : null;
|
|
981
|
-
}
|
|
982
1432
|
/** The placeholder shapes (`p:sp` carrying a `p:ph`) of a master/layout `p:spTree`, in document order. */
|
|
983
1433
|
function placeholderShapes(spTree) {
|
|
984
1434
|
if (!spTree) return [];
|
|
985
|
-
return getElements(spTree, "p:sp").filter((sp) =>
|
|
1435
|
+
return getElements(spTree, "p:sp").filter((sp) => placeholderOf(sp) !== null);
|
|
986
1436
|
}
|
|
987
1437
|
/**
|
|
988
1438
|
* One placeholder shape (`p:sp` with a `p:ph`) of a slide master or slide layout —
|
|
@@ -1008,12 +1458,12 @@ var Placeholder = class {
|
|
|
1008
1458
|
}
|
|
1009
1459
|
/** Placeholder type (`p:ph/@type`: `title` | `body` | `sldNum` | …), or `null` when absent (a body placeholder). */
|
|
1010
1460
|
get type() {
|
|
1011
|
-
const ph =
|
|
1461
|
+
const ph = placeholderOf(this.sp);
|
|
1012
1462
|
return ph ? attr(ph, "type") : null;
|
|
1013
1463
|
}
|
|
1014
1464
|
/** Placeholder index (`p:ph/@idx`), or `null` when unset. */
|
|
1015
1465
|
get idx() {
|
|
1016
|
-
const ph =
|
|
1466
|
+
const ph = placeholderOf(this.sp);
|
|
1017
1467
|
return ph ? attr(ph, "idx") : null;
|
|
1018
1468
|
}
|
|
1019
1469
|
/** Shape name (`p:cNvPr/@name`), or `''` when unnamed. */
|
|
@@ -1028,19 +1478,19 @@ var Placeholder = class {
|
|
|
1028
1478
|
}
|
|
1029
1479
|
/** Left edge in EMU (`a:off/@x`), or `null` when the placeholder carries no own `a:xfrm`. */
|
|
1030
1480
|
get left() {
|
|
1031
|
-
return
|
|
1481
|
+
return spPrXfrmEmu(this.sp, "a:off", "x");
|
|
1032
1482
|
}
|
|
1033
1483
|
/** Top edge in EMU (`a:off/@y`), or `null` when the placeholder carries no own `a:xfrm`. */
|
|
1034
1484
|
get top() {
|
|
1035
|
-
return
|
|
1485
|
+
return spPrXfrmEmu(this.sp, "a:off", "y");
|
|
1036
1486
|
}
|
|
1037
1487
|
/** Width in EMU (`a:ext/@cx`), or `null` when the placeholder carries no own `a:xfrm`. */
|
|
1038
1488
|
get width() {
|
|
1039
|
-
return
|
|
1489
|
+
return spPrXfrmEmu(this.sp, "a:ext", "cx");
|
|
1040
1490
|
}
|
|
1041
1491
|
/** Height in EMU (`a:ext/@cy`), or `null` when the placeholder carries no own `a:xfrm`. */
|
|
1042
1492
|
get height() {
|
|
1043
|
-
return
|
|
1493
|
+
return spPrXfrmEmu(this.sp, "a:ext", "cy");
|
|
1044
1494
|
}
|
|
1045
1495
|
/**
|
|
1046
1496
|
* The placeholder's text as a navigable {@link TextFrame} (`p:txBody`), or `null`
|
|
@@ -1086,7 +1536,7 @@ var SlideMaster = class {
|
|
|
1086
1536
|
}
|
|
1087
1537
|
/** The master's theme (via its `theme` relationship), or `null` when absent. */
|
|
1088
1538
|
get theme() {
|
|
1089
|
-
const themePart = this.#relTarget(THEME_REL
|
|
1539
|
+
const themePart = this.#relTarget(THEME_REL);
|
|
1090
1540
|
return themePart ? new Theme(themePart) : null;
|
|
1091
1541
|
}
|
|
1092
1542
|
/**
|
|
@@ -1130,7 +1580,7 @@ var SlideMaster = class {
|
|
|
1130
1580
|
get background() {
|
|
1131
1581
|
const bg = backgroundElementOf(this.part.dom.documentElement);
|
|
1132
1582
|
if (!bg) return null;
|
|
1133
|
-
const themePart = this.#relTarget(THEME_REL
|
|
1583
|
+
const themePart = this.#relTarget(THEME_REL);
|
|
1134
1584
|
return readSlideBackground(bg, "master", this.themeContext(), this.opc.relationshipsFor(this.partName), themePart ? this.opc.relationshipsFor(themePart.partName) : null);
|
|
1135
1585
|
}
|
|
1136
1586
|
/**
|
|
@@ -1190,7 +1640,7 @@ var SlideLayout = class {
|
|
|
1190
1640
|
/** The master this layout is built on (via its `slideMaster` relationship), or `null` when absent. */
|
|
1191
1641
|
get master() {
|
|
1192
1642
|
const rels = this.opc.relationshipsFor(this.partName);
|
|
1193
|
-
const rel = rels.byType(SLIDE_MASTER_REL
|
|
1643
|
+
const rel = rels.byType(SLIDE_MASTER_REL)[0];
|
|
1194
1644
|
const part = rel ? this.opc.part(rels.resolveTarget(rel.id)) : null;
|
|
1195
1645
|
return part ? new SlideMaster(this.opc, part) : null;
|
|
1196
1646
|
}
|
|
@@ -1665,9 +2115,6 @@ function carryShapeAnimations(sourceRoot, targetRoot, spidMap) {
|
|
|
1665
2115
|
}
|
|
1666
2116
|
//#endregion
|
|
1667
2117
|
//#region src/read/api/slide.ts
|
|
1668
|
-
const IMAGE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
|
1669
|
-
const NOTES_SLIDE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide";
|
|
1670
|
-
const SLIDE_LAYOUT_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
|
|
1671
2118
|
/** Recognize a handful of common raster formats from their leading bytes. */
|
|
1672
2119
|
function sniffImageType(bytes) {
|
|
1673
2120
|
const b = bytes;
|
|
@@ -1942,7 +2389,7 @@ var Slide = class {
|
|
|
1942
2389
|
* slide-number field round-trip either way.
|
|
1943
2390
|
*/
|
|
1944
2391
|
get notesSlide() {
|
|
1945
|
-
const notesRel = this.relationships.byType(
|
|
2392
|
+
const notesRel = this.relationships.byType(NOTES_SLIDE_REL)[0];
|
|
1946
2393
|
if (!notesRel) return null;
|
|
1947
2394
|
const notesPart = this.presentation.opc.part(this.relationships.resolveTarget(notesRel.id));
|
|
1948
2395
|
if (!notesPart) return null;
|
|
@@ -1955,7 +2402,7 @@ var Slide = class {
|
|
|
1955
2402
|
* {@link master} and {@link theme} through it (`slide.layout.master.theme`).
|
|
1956
2403
|
*/
|
|
1957
2404
|
get layout() {
|
|
1958
|
-
const rel = this.relationships.byType(
|
|
2405
|
+
const rel = this.relationships.byType(SLIDE_LAYOUT_REL)[0];
|
|
1959
2406
|
if (!rel) return null;
|
|
1960
2407
|
const part = this.presentation.opc.part(this.relationships.resolveTarget(rel.id));
|
|
1961
2408
|
return part ? new SlideLayout(this.presentation.opc, part) : null;
|
|
@@ -2162,7 +2609,7 @@ var Slide = class {
|
|
|
2162
2609
|
const opc = this.presentation.opc;
|
|
2163
2610
|
const mediaPartName = opc.reserveMediaPartName(extension);
|
|
2164
2611
|
opc.addPart(mediaPartName, contentType, image);
|
|
2165
|
-
const relId = this.relationships.add(
|
|
2612
|
+
const relId = this.relationships.add(IMAGE_REL, relativePartName(this.partName, mediaPartName)).id;
|
|
2166
2613
|
const id = this.#nextShapeId();
|
|
2167
2614
|
const pic = buildPicture(doc, {
|
|
2168
2615
|
id,
|
|
@@ -2402,7 +2849,7 @@ function readCustomProperties(opc) {
|
|
|
2402
2849
|
return out;
|
|
2403
2850
|
}
|
|
2404
2851
|
//#endregion
|
|
2405
|
-
//#region src/read/
|
|
2852
|
+
//#region src/read/oxml/slide-dom.ts
|
|
2406
2853
|
/** The `p:cSld@name` of a slide/layout/master part (`''` when absent). */
|
|
2407
2854
|
function cSldName(part) {
|
|
2408
2855
|
const root = part?.dom.documentElement;
|
|
@@ -2466,7 +2913,7 @@ function collectElements(node, out) {
|
|
|
2466
2913
|
for (let child = node.firstChild; child; child = child.nextSibling) if (child.nodeType === 1) collectElements(child, out);
|
|
2467
2914
|
}
|
|
2468
2915
|
//#endregion
|
|
2469
|
-
//#region src/read/api/rescale.ts
|
|
2916
|
+
//#region src/read/api/ops/rescale.ts
|
|
2470
2917
|
/** Build the EMU transform mapping source-canvas coordinates onto the target canvas (see {@link ImportSlideOptions.rescale}). */
|
|
2471
2918
|
function computeRescale(source, target, mode) {
|
|
2472
2919
|
if (mode === "stretch") return {
|
|
@@ -2554,7 +3001,7 @@ function rescaleTableGrid(graphicFrame, t) {
|
|
|
2554
3001
|
}
|
|
2555
3002
|
}
|
|
2556
3003
|
//#endregion
|
|
2557
|
-
//#region src/read/api/table-styles.ts
|
|
3004
|
+
//#region src/read/api/ops/table-styles.ts
|
|
2558
3005
|
const TABLE_STYLES_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/tableStyles";
|
|
2559
3006
|
const TABLE_STYLES_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml";
|
|
2560
3007
|
const TABLE_STYLES_DEFAULT_GUID = "{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}";
|
|
@@ -2659,7 +3106,7 @@ function ensureTableStylesPart(dest) {
|
|
|
2659
3106
|
return part;
|
|
2660
3107
|
}
|
|
2661
3108
|
//#endregion
|
|
2662
|
-
//#region src/read/api/master-registry.ts
|
|
3109
|
+
//#region src/read/api/ops/master-registry.ts
|
|
2663
3110
|
/**
|
|
2664
3111
|
* Slide-master bookkeeping in `presentation.xml` and in a master's own
|
|
2665
3112
|
* `p:sldLayoutIdLst`: registering a master so renderers treat it as active,
|
|
@@ -2671,8 +3118,6 @@ function ensureTableStylesPart(dest) {
|
|
|
2671
3118
|
* they take a structural {@link DeckTarget} rather than a `Presentation`. The
|
|
2672
3119
|
* source-side half that drives most of them is `part-copy.ts`.
|
|
2673
3120
|
*/
|
|
2674
|
-
const SLIDE_MASTER_REL$3 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
|
|
2675
|
-
const SLIDE_LAYOUT_REL$3 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
|
|
2676
3121
|
/**
|
|
2677
3122
|
* Wire a freshly-copied slide master into `presentation.xml`: add a
|
|
2678
3123
|
* presentation→master relationship and a `p:sldMasterId` entry in
|
|
@@ -2684,8 +3129,8 @@ const SLIDE_LAYOUT_REL$3 = "http://schemas.openxmlformats.org/officeDocument/200
|
|
|
2684
3129
|
function registerMaster(dest, masterPartName) {
|
|
2685
3130
|
const presPart = dest.presentationPart;
|
|
2686
3131
|
const presRels = dest.opc.relationshipsFor(presPart.partName);
|
|
2687
|
-
for (const rel of presRels.byType(SLIDE_MASTER_REL
|
|
2688
|
-
const relId = presRels.add(SLIDE_MASTER_REL
|
|
3132
|
+
for (const rel of presRels.byType(SLIDE_MASTER_REL)) if (presRels.resolveTarget(rel.id) === masterPartName) return;
|
|
3133
|
+
const relId = presRels.add(SLIDE_MASTER_REL, relativePartName(presPart.partName, masterPartName)).id;
|
|
2689
3134
|
const root = presPart.dom.documentElement;
|
|
2690
3135
|
if (!root) throw new PackageReadError("package/part-has-no-root", "presentation.xml has no document element to register a master in");
|
|
2691
3136
|
const lst = getOrAddChild(root, "p:sldMasterIdLst", [
|
|
@@ -2756,7 +3201,7 @@ function nextMasterLayoutId(dest) {
|
|
|
2756
3201
|
if (id !== null && id > max) max = id;
|
|
2757
3202
|
}
|
|
2758
3203
|
const presRels = dest.opc.relationshipsFor(presPart.partName);
|
|
2759
|
-
for (const rel of presRels.byType(SLIDE_MASTER_REL
|
|
3204
|
+
for (const rel of presRels.byType(SLIDE_MASTER_REL)) {
|
|
2760
3205
|
const masterRoot = dest.opc.part(presRels.resolveTarget(rel.id))?.dom.documentElement;
|
|
2761
3206
|
const layoutLst = masterRoot && firstChild(masterRoot, "p:sldLayoutIdLst");
|
|
2762
3207
|
if (!layoutLst) continue;
|
|
@@ -2786,7 +3231,7 @@ function addLayoutToMaster(dest, masterPartName, layoutPartName) {
|
|
|
2786
3231
|
const masterPart = dest.opc.part(masterPartName);
|
|
2787
3232
|
const root = masterPart?.dom.documentElement;
|
|
2788
3233
|
if (!masterPart || !root) return;
|
|
2789
|
-
const relId = dest.opc.relationshipsFor(masterPartName).add(SLIDE_LAYOUT_REL
|
|
3234
|
+
const relId = dest.opc.relationshipsFor(masterPartName).add(SLIDE_LAYOUT_REL, relativePartName(masterPartName, layoutPartName)).id;
|
|
2790
3235
|
const lst = getOrAddChild(root, "p:sldLayoutIdLst", [
|
|
2791
3236
|
"p:transition",
|
|
2792
3237
|
"p:timing",
|
|
@@ -2801,10 +3246,7 @@ function addLayoutToMaster(dest, masterPartName, layoutPartName) {
|
|
|
2801
3246
|
masterPart.markDirty();
|
|
2802
3247
|
}
|
|
2803
3248
|
//#endregion
|
|
2804
|
-
//#region src/read/api/part-copy.ts
|
|
2805
|
-
const SLIDE_LAYOUT_REL$2 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
|
|
2806
|
-
const SLIDE_MASTER_REL$2 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
|
|
2807
|
-
const NOTES_SLIDE_REL$2 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide";
|
|
3249
|
+
//#region src/read/api/ops/part-copy.ts
|
|
2808
3250
|
const SLIDE_MASTER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml";
|
|
2809
3251
|
const SLIDE_LAYOUT_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml";
|
|
2810
3252
|
/**
|
|
@@ -2829,8 +3271,8 @@ function copyPart(ctx, sourcePartName) {
|
|
|
2829
3271
|
const sourceRels = ctx.source.relationshipsFor(sourcePartName);
|
|
2830
3272
|
const targetRels = ctx.dest.opc.relationshipsFor(newPartName);
|
|
2831
3273
|
for (const rel of sourceRels) {
|
|
2832
|
-
if (rel.type ===
|
|
2833
|
-
if (isMaster && rel.type ===
|
|
3274
|
+
if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide") continue;
|
|
3275
|
+
if (isMaster && rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout") continue;
|
|
2834
3276
|
if (rel.targetMode === "External") {
|
|
2835
3277
|
targetRels.addWithId(rel.id, rel.type, rel.target, "External");
|
|
2836
3278
|
continue;
|
|
@@ -2853,13 +3295,76 @@ function copyPart(ctx, sourcePartName) {
|
|
|
2853
3295
|
* accumulates exactly the imported layouts.
|
|
2854
3296
|
*/
|
|
2855
3297
|
function linkLayoutIntoMaster(ctx, layoutSourceRels, layoutPartName) {
|
|
2856
|
-
const masterRel = layoutSourceRels.byType(SLIDE_MASTER_REL
|
|
3298
|
+
const masterRel = layoutSourceRels.byType(SLIDE_MASTER_REL)[0];
|
|
2857
3299
|
if (!masterRel) return;
|
|
2858
3300
|
const masterPartName = ctx.registry.get(layoutSourceRels.resolveTarget(masterRel.id));
|
|
2859
3301
|
if (!masterPartName) return;
|
|
2860
3302
|
addLayoutToMaster(ctx.dest, masterPartName, layoutPartName);
|
|
2861
3303
|
}
|
|
2862
3304
|
//#endregion
|
|
3305
|
+
//#region src/read/api/ops/carried-rels.ts
|
|
3306
|
+
/**
|
|
3307
|
+
* Relationship rewriting for content carried between packages.
|
|
3308
|
+
*
|
|
3309
|
+
* When a shape or decoration is deep-copied out of a source deck, every relationship
|
|
3310
|
+
* reference it carries (`r:embed` on a picture fill, `r:id` on a chart frame, `r:link` on a
|
|
3311
|
+
* linked image, …) still names an id in the *source* part's relationship list. Left alone
|
|
3312
|
+
* those ids either dangle or — worse — silently resolve to whatever the destination part
|
|
3313
|
+
* happens to have under the same id. This rewrites each one to a fresh relationship on the
|
|
3314
|
+
* destination part, copying the referenced part into the destination package on first sight.
|
|
3315
|
+
*
|
|
3316
|
+
* Both functions are pure with respect to the deck: everything they touch arrives as an
|
|
3317
|
+
* argument. They were private methods on `Presentation` and used no instance state, which
|
|
3318
|
+
* made the import subsystem look more entangled with the read model than it is.
|
|
3319
|
+
*/
|
|
3320
|
+
/**
|
|
3321
|
+
* Rewrite every relationship reference inside a carried subtree to a fresh destination-local id.
|
|
3322
|
+
* @param {Element} node - root of the carried subtree (rewritten in place)
|
|
3323
|
+
* @param {ImportContext} ctx - the open import (destination deck + source package + copy registry)
|
|
3324
|
+
* @param {Relationships} sourceRels - relationships of the source part the subtree came from
|
|
3325
|
+
* @param {string} destPartName - partname of the destination part the subtree is being placed in
|
|
3326
|
+
* @param {Relationships} destRels - relationships of that destination part
|
|
3327
|
+
* @param {Map<string, string>} relIdMap - per-call cache (source part + source id → new id) deduping references shared within one import
|
|
3328
|
+
*/
|
|
3329
|
+
function rewriteCarriedRels(node, ctx, sourceRels, destPartName, destRels, relIdMap) {
|
|
3330
|
+
const elements = [];
|
|
3331
|
+
collectElements(node, elements);
|
|
3332
|
+
for (const el of elements) {
|
|
3333
|
+
const refs = [];
|
|
3334
|
+
const attrs = el.attributes;
|
|
3335
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
3336
|
+
const a = attrs.item(i);
|
|
3337
|
+
if (!a || a.namespaceURI !== OOXML_NS.r || !a.value) continue;
|
|
3338
|
+
if (!sourceRels.get(a.value)) continue;
|
|
3339
|
+
refs.push({
|
|
3340
|
+
local: a.localName ?? a.name,
|
|
3341
|
+
id: a.value
|
|
3342
|
+
});
|
|
3343
|
+
}
|
|
3344
|
+
for (const { local, id } of refs) setAttr(el, `r:${local}`, carryRel(ctx, sourceRels, id, destPartName, destRels, relIdMap));
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
/**
|
|
3348
|
+
* Resolve one carried relationship to a fresh destination-local id, copying its internal target.
|
|
3349
|
+
* @param {ImportContext} ctx - the open import
|
|
3350
|
+
* @param {Relationships} sourceRels - relationships of the source part
|
|
3351
|
+
* @param {string} id - the source relationship id to carry
|
|
3352
|
+
* @param {string} destPartName - partname of the destination part
|
|
3353
|
+
* @param {Relationships} destRels - relationships of that destination part
|
|
3354
|
+
* @param {Map<string, string>} relIdMap - per-call dedupe cache
|
|
3355
|
+
* @return {string} the new relationship id on the destination part
|
|
3356
|
+
*/
|
|
3357
|
+
function carryRel(ctx, sourceRels, id, destPartName, destRels, relIdMap) {
|
|
3358
|
+
const key = `${sourceRels.sourcePartName}|${id}`;
|
|
3359
|
+
const cached = relIdMap.get(key);
|
|
3360
|
+
if (cached) return cached;
|
|
3361
|
+
const rel = sourceRels.get(id);
|
|
3362
|
+
if (!rel) throw new InvalidOptionError("relationship/not-found", `Relationships of ${sourceRels.sourcePartName}: no relationship with id ${id}`);
|
|
3363
|
+
const newId = rel.targetMode === "External" ? destRels.add(rel.type, rel.target, "External").id : destRels.add(rel.type, relativePartName(destPartName, copyPart(ctx, sourceRels.resolveTarget(id)))).id;
|
|
3364
|
+
relIdMap.set(key, newId);
|
|
3365
|
+
return newId;
|
|
3366
|
+
}
|
|
3367
|
+
//#endregion
|
|
2863
3368
|
//#region src/read/api/ops/embedded-fonts.ts
|
|
2864
3369
|
/**
|
|
2865
3370
|
* Merging embedded font faces into a deck's `p:embeddedFontLst`.
|
|
@@ -3043,6 +3548,277 @@ function mergeEmbeddedFontEntries(dest, entries) {
|
|
|
3043
3548
|
if (copiedAny) presPart.markDirty();
|
|
3044
3549
|
}
|
|
3045
3550
|
//#endregion
|
|
3551
|
+
//#region src/read/api/ops/flatten-context.ts
|
|
3552
|
+
/**
|
|
3553
|
+
* The theme context a source slide is flattened against.
|
|
3554
|
+
*
|
|
3555
|
+
* `preserve`-mode import bakes a slide's *source* look into its XML — scheme colours and
|
|
3556
|
+
* style-matrix fills resolved to literals — so it keeps that look after being attached to a
|
|
3557
|
+
* different deck's master. Doing so needs the source subgraph's colour map, colour scheme,
|
|
3558
|
+
* format scheme, and the background the slide inherits but does not itself carry. This
|
|
3559
|
+
* gathers exactly that.
|
|
3560
|
+
*
|
|
3561
|
+
* Pure with respect to the destination deck: it reads only the source package. It was a
|
|
3562
|
+
* private method on `Presentation` that used no instance state.
|
|
3563
|
+
*/
|
|
3564
|
+
/** The `p:cSld/p:bg` element of a slide/layout/master root, or `null`. */
|
|
3565
|
+
function backgroundOf(root) {
|
|
3566
|
+
const cSld = firstChild(root, "p:cSld");
|
|
3567
|
+
return cSld ? firstChild(cSld, "p:bg") : null;
|
|
3568
|
+
}
|
|
3569
|
+
/**
|
|
3570
|
+
* The background the slide effectively inherits from its source subgraph: the layout's
|
|
3571
|
+
* `p:bg`, else the master's. Returns `null` when the slide carries its own `p:bg` (it stays
|
|
3572
|
+
* on the slide and is flattened directly) or when none exists.
|
|
3573
|
+
*/
|
|
3574
|
+
function effectiveBackground(sourceOpc, slideRoot, layoutPartName, masterPartName) {
|
|
3575
|
+
if (slideRoot && backgroundOf(slideRoot)) return null;
|
|
3576
|
+
const layoutRoot = layoutPartName ? sourceOpc.part(layoutPartName)?.dom.documentElement ?? null : null;
|
|
3577
|
+
const masterRoot = masterPartName ? sourceOpc.part(masterPartName)?.dom.documentElement ?? null : null;
|
|
3578
|
+
return (layoutRoot && backgroundOf(layoutRoot)) ?? (masterRoot && backgroundOf(masterRoot)) ?? null;
|
|
3579
|
+
}
|
|
3580
|
+
/**
|
|
3581
|
+
* Gather the flatten context for a source slide: walk slide → layout → master → theme,
|
|
3582
|
+
* reading the effective colour map (the slide's `clrMapOvr` override, or the master
|
|
3583
|
+
* `clrMap`), the theme `clrScheme`, and the theme `fmtScheme`.
|
|
3584
|
+
* @param {OpcPackage} sourceOpc - the source package to read
|
|
3585
|
+
* @param {string} slidePartName - partname of the source slide
|
|
3586
|
+
* @return {FlattenContext} the context {@link flattenSlide} / {@link flattenShape} resolve against
|
|
3587
|
+
*/
|
|
3588
|
+
function sourceFlattenContext(sourceOpc, slidePartName) {
|
|
3589
|
+
const parts = resolveSlideThemeParts(sourceOpc, slidePartName);
|
|
3590
|
+
const themeElements = parts.themeElements;
|
|
3591
|
+
return {
|
|
3592
|
+
clrMap: parts.clrMap,
|
|
3593
|
+
clrScheme: parts.clrScheme,
|
|
3594
|
+
fmtScheme: themeElements ? firstChild(themeElements, "a:fmtScheme") : null,
|
|
3595
|
+
inheritedBackground: effectiveBackground(sourceOpc, parts.slideRoot, parts.layoutPartName, parts.masterPartName),
|
|
3596
|
+
layoutRoot: parts.layoutRoot,
|
|
3597
|
+
masterRoot: parts.masterRoot
|
|
3598
|
+
};
|
|
3599
|
+
}
|
|
3600
|
+
//#endregion
|
|
3601
|
+
//#region src/read/api/ops/part-index.ts
|
|
3602
|
+
/**
|
|
3603
|
+
* Walking a deck's master/layout spine by partname.
|
|
3604
|
+
*
|
|
3605
|
+
* The `p:sldMasterIdLst` / `p:sldLayoutIdLst` entries hold relationship ids, not partnames, so
|
|
3606
|
+
* every traversal has to resolve through the owning part's relationships. These are the
|
|
3607
|
+
* source-side reads that do it — used against a *foreign* presentation as often as against this
|
|
3608
|
+
* one, which is why they take the deck rather than living on it.
|
|
3609
|
+
*/
|
|
3610
|
+
/** Master partnames in `p:sldMasterIdLst` order. */
|
|
3611
|
+
function slideMasterPartNames(pres) {
|
|
3612
|
+
const root = pres.presentationPart.dom.documentElement;
|
|
3613
|
+
const lst = root && firstChild(root, "p:sldMasterIdLst");
|
|
3614
|
+
if (!lst) return [];
|
|
3615
|
+
const rels = pres.opc.relationshipsFor(pres.presentationPart.partName);
|
|
3616
|
+
const out = [];
|
|
3617
|
+
for (const entry of getElements(lst, "p:sldMasterId")) {
|
|
3618
|
+
const relId = attr(entry, "r:id");
|
|
3619
|
+
if (relId) out.push(rels.resolveTarget(relId));
|
|
3620
|
+
}
|
|
3621
|
+
return out;
|
|
3622
|
+
}
|
|
3623
|
+
/** A master's layout partnames in `p:sldLayoutIdLst` order. */
|
|
3624
|
+
function layoutPartNamesOf(pres, masterPartName) {
|
|
3625
|
+
const root = pres.opc.part(masterPartName)?.dom.documentElement;
|
|
3626
|
+
const lst = root && firstChild(root, "p:sldLayoutIdLst");
|
|
3627
|
+
if (!lst) return [];
|
|
3628
|
+
const rels = pres.opc.relationshipsFor(masterPartName);
|
|
3629
|
+
const out = [];
|
|
3630
|
+
for (const entry of getElements(lst, "p:sldLayoutId")) {
|
|
3631
|
+
const relId = attr(entry, "r:id");
|
|
3632
|
+
if (relId) out.push(rels.resolveTarget(relId));
|
|
3633
|
+
}
|
|
3634
|
+
return out;
|
|
3635
|
+
}
|
|
3636
|
+
//#endregion
|
|
3637
|
+
//#region src/read/api/ops/import-slide.ts
|
|
3638
|
+
/**
|
|
3639
|
+
* The three ways a slide can be brought across from another deck.
|
|
3640
|
+
*
|
|
3641
|
+
* {@link Presentation.importSlide} picks one by `options.theme`, and the difference between
|
|
3642
|
+
* them is entirely about what happens to the slide's *look*:
|
|
3643
|
+
*
|
|
3644
|
+
* - **`copy`** — not here. It copies the source theme subgraph wholesale via `copyPart`, so
|
|
3645
|
+
* the slide keeps its look by keeping its own theme; nothing needs rewriting.
|
|
3646
|
+
* - **`preserve`** ({@link importSlidePreserve}) — rebind to this deck's master, then bake
|
|
3647
|
+
* the source theme into the slide XML. The slide looks the same as it did; it just no
|
|
3648
|
+
* longer depends on the theme it came from.
|
|
3649
|
+
* - **`restyle`** ({@link importSlideRestyle}) — rebind and bake *nothing*, so the slide's
|
|
3650
|
+
* symbolic theme references re-resolve against the destination theme and it re-brands.
|
|
3651
|
+
*
|
|
3652
|
+
* The two share {@link importSlideRebind} and are exact inverses on top of it: preserve
|
|
3653
|
+
* resolves every reference it can, restyle resolves none. Any baking added to the shared
|
|
3654
|
+
* rebind would break restyle by pinning the slide to its source look, which is why the
|
|
3655
|
+
* rebind carries no theme handling of its own — not even the inherited background.
|
|
3656
|
+
*
|
|
3657
|
+
* These were private methods on `Presentation`, where they made the read model's own surface
|
|
3658
|
+
* (open a deck, walk slides, read shapes) hard to see: the import machinery was roughly two
|
|
3659
|
+
* thirds of the class. They live here as free functions taking the destination deck, matching
|
|
3660
|
+
* the other `ops/` modules.
|
|
3661
|
+
*/
|
|
3662
|
+
/**
|
|
3663
|
+
* Import a slide in `preserve` mode: rebind it to this deck's master/layout, then flatten its
|
|
3664
|
+
* source theme into the slide XML (scheme colours + style-matrix fills baked to literals).
|
|
3665
|
+
*
|
|
3666
|
+
* The flatten context is gathered from the *source* subgraph, so it can be read before or
|
|
3667
|
+
* after the rebind; the rebind injects any carried decorations before we flatten, so a single
|
|
3668
|
+
* sweep resolves the theme references on the slide's own content and on the carried
|
|
3669
|
+
* decorations together.
|
|
3670
|
+
* @param {Presentation} dest - the destination deck
|
|
3671
|
+
* @param {ImportContext} ctx - the open import out of the source package
|
|
3672
|
+
* @param {Presentation} source - the source deck
|
|
3673
|
+
* @param {Slide} sourceSlide - the slide being imported
|
|
3674
|
+
* @param {boolean} carryGraphics - bake the source master/layout decorations onto the slide
|
|
3675
|
+
* @return {string} partname of the new slide part in the destination package
|
|
3676
|
+
*/
|
|
3677
|
+
function importSlidePreserve(dest, ctx, source, sourceSlide, carryGraphics) {
|
|
3678
|
+
const flattenCtx = sourceFlattenContext(source.opc, sourceSlide.partName);
|
|
3679
|
+
const { newPartName, slideRoot, newPart } = importSlideRebind(dest, ctx, source, sourceSlide, carryGraphics);
|
|
3680
|
+
flattenSlide(slideRoot, flattenCtx);
|
|
3681
|
+
newPart.markDirty();
|
|
3682
|
+
return newPartName;
|
|
3683
|
+
}
|
|
3684
|
+
/**
|
|
3685
|
+
* Import a slide in `restyle` mode: rebind it to this deck's master/layout and then
|
|
3686
|
+
* {@link restyleSlide} it — drop its colour map override but bake *nothing*, so its symbolic
|
|
3687
|
+
* theme references re-resolve against the destination theme and the slide re-brands.
|
|
3688
|
+
*
|
|
3689
|
+
* The deliberate inverse of `preserve`: no flatten, no inherited-background bake, no
|
|
3690
|
+
* placeholder colour/size/geometry bake — every one of those would pin the slide to its
|
|
3691
|
+
* source look, the opposite of re-branding. Carried decorations are left symbolic too, so
|
|
3692
|
+
* they re-brand along with the slide.
|
|
3693
|
+
*
|
|
3694
|
+
* With `remapLiterals` it additionally force-remaps the slide's source-theme literal colours
|
|
3695
|
+
* back to symbolic scheme colours and copies any referenced source table style into this deck
|
|
3696
|
+
* — the two things plain `restyle` cannot re-brand.
|
|
3697
|
+
* @param {Presentation} dest - the destination deck
|
|
3698
|
+
* @param {ImportContext} ctx - the open import out of the source package
|
|
3699
|
+
* @param {Presentation} source - the source deck
|
|
3700
|
+
* @param {Slide} sourceSlide - the slide being imported
|
|
3701
|
+
* @param {boolean} carryGraphics - bake the source master/layout decorations onto the slide
|
|
3702
|
+
* @param {boolean} remapLiterals - additionally remap source-theme literal colours to scheme tokens
|
|
3703
|
+
* @return {string} partname of the new slide part in the destination package
|
|
3704
|
+
*/
|
|
3705
|
+
function importSlideRestyle(dest, ctx, source, sourceSlide, carryGraphics, remapLiterals) {
|
|
3706
|
+
const { newPartName, slideRoot, newPart } = importSlideRebind(dest, ctx, source, sourceSlide, carryGraphics);
|
|
3707
|
+
restyleSlide(slideRoot);
|
|
3708
|
+
if (remapLiterals) {
|
|
3709
|
+
const parts = resolveSlideThemeParts(source.opc, sourceSlide.partName);
|
|
3710
|
+
remapLiteralColors(slideRoot, {
|
|
3711
|
+
clrMap: parts.clrMap,
|
|
3712
|
+
clrScheme: parts.clrScheme
|
|
3713
|
+
});
|
|
3714
|
+
copySourceTableStyles(dest, source.opc, slideRoot);
|
|
3715
|
+
}
|
|
3716
|
+
newPart.markDirty();
|
|
3717
|
+
return newPartName;
|
|
3718
|
+
}
|
|
3719
|
+
/**
|
|
3720
|
+
* The rebind shared by `preserve` and `restyle`: copy the slide bytes into a fresh part,
|
|
3721
|
+
* rebuild its relationships (drop notes, repoint the `slideLayout` rel at this deck's
|
|
3722
|
+
* existing layout, copy every other internal target — media/charts — and pass externals
|
|
3723
|
+
* through), and optionally bake the source master/layout decorations onto the slide. Returns
|
|
3724
|
+
* the new part, its name, and its live root element for the caller's mode-specific pass.
|
|
3725
|
+
*
|
|
3726
|
+
* This carries *no* theme baking of its own — not even the inherited background.
|
|
3727
|
+
* `preserve` adds that via {@link flattenSlide}'s context; `restyle` must not, so the
|
|
3728
|
+
* background stays symbolic and re-brands.
|
|
3729
|
+
* @param {Presentation} dest - the destination deck
|
|
3730
|
+
* @param {ImportContext} ctx - the open import out of the source package
|
|
3731
|
+
* @param {Presentation} source - the source deck
|
|
3732
|
+
* @param {Slide} sourceSlide - the slide being imported
|
|
3733
|
+
* @param {boolean} carryGraphics - bake the source master/layout decorations onto the slide
|
|
3734
|
+
* @return {RebindResult} the new part, its partname, and its live root element
|
|
3735
|
+
*/
|
|
3736
|
+
function importSlideRebind(dest, ctx, source, sourceSlide, carryGraphics) {
|
|
3737
|
+
const destLayout = destinationLayoutPartName(dest);
|
|
3738
|
+
const sourcePart = source.opc.part(sourceSlide.partName);
|
|
3739
|
+
if (!sourcePart) throw new PackageReadError("package/part-missing", `importSlide: source package has no part ${sourceSlide.partName}`);
|
|
3740
|
+
const newPartName = dest.opc.reservePartNameLike(sourceSlide.partName);
|
|
3741
|
+
const newPart = dest.opc.addPart(newPartName, sourcePart.contentType, sourcePart.bytes);
|
|
3742
|
+
const slideRoot = newPart.dom.documentElement;
|
|
3743
|
+
if (!slideRoot) throw new PackageReadError("package/part-has-no-root", `Imported slide ${newPartName} has no root element`);
|
|
3744
|
+
const sourceRels = source.opc.relationshipsFor(sourceSlide.partName);
|
|
3745
|
+
const targetRels = dest.opc.relationshipsFor(newPartName);
|
|
3746
|
+
for (const rel of sourceRels) {
|
|
3747
|
+
if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide") continue;
|
|
3748
|
+
if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout") {
|
|
3749
|
+
targetRels.addWithId(rel.id, SLIDE_LAYOUT_REL, relativePartName(newPartName, destLayout));
|
|
3750
|
+
continue;
|
|
3751
|
+
}
|
|
3752
|
+
if (rel.targetMode === "External") {
|
|
3753
|
+
targetRels.addWithId(rel.id, rel.type, rel.target, "External");
|
|
3754
|
+
continue;
|
|
3755
|
+
}
|
|
3756
|
+
const newTarget = copyPart(ctx, sourceRels.resolveTarget(rel.id));
|
|
3757
|
+
targetRels.addWithId(rel.id, rel.type, relativePartName(newPartName, newTarget));
|
|
3758
|
+
}
|
|
3759
|
+
if (carryGraphics) carryMasterGraphics(dest, ctx, slideRoot, newPartName, sourceSlide.partName);
|
|
3760
|
+
return {
|
|
3761
|
+
newPartName,
|
|
3762
|
+
slideRoot,
|
|
3763
|
+
newPart
|
|
3764
|
+
};
|
|
3765
|
+
}
|
|
3766
|
+
/**
|
|
3767
|
+
* Bake the source `slideLayout`/`slideMaster` shape-tree decorations onto the imported slide
|
|
3768
|
+
* (the `carryMasterGraphics` path). Every shape on those trees *except* placeholders is
|
|
3769
|
+
* deep-copied into the slide's `p:spTree` ahead of its own content — master decorations
|
|
3770
|
+
* first, then layout, then the slide's shapes — so document (z-)order keeps the master
|
|
3771
|
+
* furthest back. Each decoration's media and other relationship targets are copied into this
|
|
3772
|
+
* package and its `r:embed`/`r:id`/… references rewritten to fresh slide-local ids. The
|
|
3773
|
+
* injected shapes are left for the caller's {@link flattenSlide} pass to resolve any theme
|
|
3774
|
+
* references they carry.
|
|
3775
|
+
* @param {Presentation} dest - the destination deck
|
|
3776
|
+
* @param {ImportContext} ctx - the open import out of the source package
|
|
3777
|
+
* @param {Element} slideRoot - root element of the new slide part (mutated in place)
|
|
3778
|
+
* @param {string} newPartName - partname of the new slide part
|
|
3779
|
+
* @param {string} slidePartName - partname of the source slide, for resolving its layout/master
|
|
3780
|
+
*/
|
|
3781
|
+
function carryMasterGraphics(dest, ctx, slideRoot, newPartName, slidePartName) {
|
|
3782
|
+
const sourceOpc = ctx.source;
|
|
3783
|
+
const layoutPartName = resolveSingleRel(sourceOpc, slidePartName, SLIDE_LAYOUT_REL);
|
|
3784
|
+
const masterPartName = layoutPartName ? resolveSingleRel(sourceOpc, layoutPartName, SLIDE_MASTER_REL) : null;
|
|
3785
|
+
const cSld = firstChild(slideRoot, "p:cSld");
|
|
3786
|
+
const spTree = cSld && firstChild(cSld, "p:spTree");
|
|
3787
|
+
if (!spTree) return;
|
|
3788
|
+
const doc = ownerDocumentOf(slideRoot);
|
|
3789
|
+
const slideRels = dest.opc.relationshipsFor(newPartName);
|
|
3790
|
+
const relIdMap = /* @__PURE__ */ new Map();
|
|
3791
|
+
const anchor = firstShapeChild(spTree);
|
|
3792
|
+
for (const partName of [masterPartName, layoutPartName]) {
|
|
3793
|
+
if (!partName) continue;
|
|
3794
|
+
const decorations = carriedDecorations(sourceOpc.part(partName)?.dom.documentElement ?? null);
|
|
3795
|
+
if (decorations.length === 0) continue;
|
|
3796
|
+
const sourceRels = sourceOpc.relationshipsFor(partName);
|
|
3797
|
+
for (const deco of decorations) {
|
|
3798
|
+
const imported = doc.importNode(deco, true);
|
|
3799
|
+
rewriteCarriedRels(imported, ctx, sourceRels, newPartName, slideRels, relIdMap);
|
|
3800
|
+
spTree.insertBefore(imported, anchor);
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
/**
|
|
3805
|
+
* The partname of the layout this deck's slides should attach to in `preserve` mode: the
|
|
3806
|
+
* first layout of the first slide master. Throws when the deck has no master/layout to attach
|
|
3807
|
+
* to (a deck ts-pptx always provides).
|
|
3808
|
+
* @param {Presentation} dest - the destination deck
|
|
3809
|
+
* @return {string} partname of the destination layout
|
|
3810
|
+
*/
|
|
3811
|
+
function destinationLayoutPartName(dest) {
|
|
3812
|
+
const presRels = dest.opc.relationshipsFor(dest.presentationPart.partName);
|
|
3813
|
+
const masterRel = presRels.byType(SLIDE_MASTER_REL)[0];
|
|
3814
|
+
if (!masterRel) throw new InvalidOptionError("import/destination-missing-master", "importSlide preserve mode requires a slide master in the destination deck");
|
|
3815
|
+
const masterPartName = presRels.resolveTarget(masterRel.id);
|
|
3816
|
+
const masterRels = dest.opc.relationshipsFor(masterPartName);
|
|
3817
|
+
const layoutRel = masterRels.byType(SLIDE_LAYOUT_REL)[0];
|
|
3818
|
+
if (!layoutRel) throw new InvalidOptionError("import/destination-missing-layout", "importSlide preserve mode requires a slide layout in the destination deck");
|
|
3819
|
+
return masterRels.resolveTarget(layoutRel.id);
|
|
3820
|
+
}
|
|
3821
|
+
//#endregion
|
|
3046
3822
|
//#region src/read/api/ops/notes-master.ts
|
|
3047
3823
|
/**
|
|
3048
3824
|
* Carrying speaker notes and the deck's single notes master across an import or an append.
|
|
@@ -3054,10 +3830,6 @@ function mergeEmbeddedFontEntries(dest, entries) {
|
|
|
3054
3830
|
* `Presentation`-to-`Presentation` path and the generator-XML path funnel through
|
|
3055
3831
|
* `registerNotesMaster`: they differ only in how the *part* comes into being.
|
|
3056
3832
|
*/
|
|
3057
|
-
const SLIDE_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
|
|
3058
|
-
const NOTES_SLIDE_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide";
|
|
3059
|
-
const NOTES_MASTER_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster";
|
|
3060
|
-
const THEME_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
|
|
3061
3833
|
const NOTES_MASTER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml";
|
|
3062
3834
|
const THEME_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.theme+xml";
|
|
3063
3835
|
const textEncoder$1 = new TextEncoder();
|
|
@@ -3080,24 +3852,24 @@ const textEncoder$1 = new TextEncoder();
|
|
|
3080
3852
|
*/
|
|
3081
3853
|
function carryNotes(dest, source, ctx, sourceSlidePartName, newSlidePartName) {
|
|
3082
3854
|
const sourceSlideRels = source.opc.relationshipsFor(sourceSlidePartName);
|
|
3083
|
-
const notesRel = sourceSlideRels.byType(NOTES_SLIDE_REL
|
|
3855
|
+
const notesRel = sourceSlideRels.byType(NOTES_SLIDE_REL)[0];
|
|
3084
3856
|
if (!notesRel) return;
|
|
3085
3857
|
const sourceNotesPartName = sourceSlideRels.resolveTarget(notesRel.id);
|
|
3086
3858
|
const sourceNotesPart = source.opc.part(sourceNotesPartName);
|
|
3087
3859
|
if (!sourceNotesPart) return;
|
|
3088
3860
|
const newNotesPartName = dest.opc.reservePartNameLike(sourceNotesPartName);
|
|
3089
3861
|
dest.opc.addPart(newNotesPartName, sourceNotesPart.contentType, sourceNotesPart.bytes);
|
|
3090
|
-
dest.opc.relationshipsFor(newSlidePartName).add(NOTES_SLIDE_REL
|
|
3862
|
+
dest.opc.relationshipsFor(newSlidePartName).add(NOTES_SLIDE_REL, relativePartName(newSlidePartName, newNotesPartName));
|
|
3091
3863
|
const notesSourceRels = source.opc.relationshipsFor(sourceNotesPartName);
|
|
3092
3864
|
const notesTargetRels = dest.opc.relationshipsFor(newNotesPartName);
|
|
3093
3865
|
for (const rel of notesSourceRels) {
|
|
3094
|
-
if (rel.type ===
|
|
3095
|
-
notesTargetRels.addWithId(rel.id, SLIDE_REL
|
|
3866
|
+
if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide") {
|
|
3867
|
+
notesTargetRels.addWithId(rel.id, SLIDE_REL, relativePartName(newNotesPartName, newSlidePartName));
|
|
3096
3868
|
continue;
|
|
3097
3869
|
}
|
|
3098
|
-
if (rel.type ===
|
|
3870
|
+
if (rel.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster") {
|
|
3099
3871
|
const notesMaster = ensureNotesMaster(dest, ctx, notesSourceRels.resolveTarget(rel.id));
|
|
3100
|
-
notesTargetRels.addWithId(rel.id, NOTES_MASTER_REL
|
|
3872
|
+
notesTargetRels.addWithId(rel.id, NOTES_MASTER_REL, relativePartName(newNotesPartName, notesMaster));
|
|
3101
3873
|
continue;
|
|
3102
3874
|
}
|
|
3103
3875
|
if (rel.targetMode === "External") {
|
|
@@ -3119,7 +3891,7 @@ function carryNotes(dest, source, ctx, sourceSlidePartName, newSlidePartName) {
|
|
|
3119
3891
|
function ensureNotesMaster(dest, ctx, sourceNotesMasterPartName) {
|
|
3120
3892
|
const presPart = dest.presentationPart;
|
|
3121
3893
|
const presRels = dest.opc.relationshipsFor(presPart.partName);
|
|
3122
|
-
const existing = presRels.byType(NOTES_MASTER_REL
|
|
3894
|
+
const existing = presRels.byType(NOTES_MASTER_REL)[0];
|
|
3123
3895
|
if (existing) return presRels.resolveTarget(existing.id);
|
|
3124
3896
|
return registerNotesMaster(dest, copyPart(ctx, sourceNotesMasterPartName));
|
|
3125
3897
|
}
|
|
@@ -3135,7 +3907,7 @@ function ensureNotesMaster(dest, ctx, sourceNotesMasterPartName) {
|
|
|
3135
3907
|
*/
|
|
3136
3908
|
function registerNotesMaster(dest, notesMasterPartName) {
|
|
3137
3909
|
const presPart = dest.presentationPart;
|
|
3138
|
-
const relId = dest.opc.relationshipsFor(presPart.partName).add(NOTES_MASTER_REL
|
|
3910
|
+
const relId = dest.opc.relationshipsFor(presPart.partName).add(NOTES_MASTER_REL, relativePartName(presPart.partName, notesMasterPartName)).id;
|
|
3139
3911
|
const root = presPart.dom.documentElement;
|
|
3140
3912
|
if (!root) throw new PackageReadError("package/part-has-no-root", "presentation.xml has no document element to register a notes master in");
|
|
3141
3913
|
const lst = getOrAddChild(root, "p:notesMasterIdLst", [
|
|
@@ -3169,7 +3941,7 @@ function registerNotesMaster(dest, notesMasterPartName) {
|
|
|
3169
3941
|
function ensureNotesMasterFromXml(dest, master) {
|
|
3170
3942
|
const presPart = dest.presentationPart;
|
|
3171
3943
|
const presRels = dest.opc.relationshipsFor(presPart.partName);
|
|
3172
|
-
const existing = presRels.byType(NOTES_MASTER_REL
|
|
3944
|
+
const existing = presRels.byType(NOTES_MASTER_REL)[0];
|
|
3173
3945
|
if (existing) return presRels.resolveTarget(existing.id);
|
|
3174
3946
|
const masterPartName = dest.opc.reservePartNameLike("/ppt/notesMasters/notesMaster1.xml");
|
|
3175
3947
|
dest.opc.addPart(masterPartName, NOTES_MASTER_CONTENT_TYPE, textEncoder$1.encode(master.xml));
|
|
@@ -3179,48 +3951,6 @@ function ensureNotesMasterFromXml(dest, master) {
|
|
|
3179
3951
|
return registerNotesMaster(dest, masterPartName);
|
|
3180
3952
|
}
|
|
3181
3953
|
//#endregion
|
|
3182
|
-
//#region src/read/api/ops/part-index.ts
|
|
3183
|
-
/**
|
|
3184
|
-
* Walking a deck's master/layout spine by partname.
|
|
3185
|
-
*
|
|
3186
|
-
* The `p:sldMasterIdLst` / `p:sldLayoutIdLst` entries hold relationship ids, not partnames, so
|
|
3187
|
-
* every traversal has to resolve through the owning part's relationships. These are the
|
|
3188
|
-
* source-side reads that do it — used against a *foreign* presentation as often as against this
|
|
3189
|
-
* one, which is why they take the deck rather than living on it.
|
|
3190
|
-
*/
|
|
3191
|
-
/** Master partnames in `p:sldMasterIdLst` order. */
|
|
3192
|
-
function slideMasterPartNames(pres) {
|
|
3193
|
-
const root = pres.presentationPart.dom.documentElement;
|
|
3194
|
-
const lst = root && firstChild(root, "p:sldMasterIdLst");
|
|
3195
|
-
if (!lst) return [];
|
|
3196
|
-
const rels = pres.opc.relationshipsFor(pres.presentationPart.partName);
|
|
3197
|
-
const out = [];
|
|
3198
|
-
for (const entry of getElements(lst, "p:sldMasterId")) {
|
|
3199
|
-
const relId = attr(entry, "r:id");
|
|
3200
|
-
if (relId) out.push(rels.resolveTarget(relId));
|
|
3201
|
-
}
|
|
3202
|
-
return out;
|
|
3203
|
-
}
|
|
3204
|
-
/** A master's layout partnames in `p:sldLayoutIdLst` order. */
|
|
3205
|
-
function layoutPartNamesOf(pres, masterPartName) {
|
|
3206
|
-
const root = pres.opc.part(masterPartName)?.dom.documentElement;
|
|
3207
|
-
const lst = root && firstChild(root, "p:sldLayoutIdLst");
|
|
3208
|
-
if (!lst) return [];
|
|
3209
|
-
const rels = pres.opc.relationshipsFor(masterPartName);
|
|
3210
|
-
const out = [];
|
|
3211
|
-
for (const entry of getElements(lst, "p:sldLayoutId")) {
|
|
3212
|
-
const relId = attr(entry, "r:id");
|
|
3213
|
-
if (relId) out.push(rels.resolveTarget(relId));
|
|
3214
|
-
}
|
|
3215
|
-
return out;
|
|
3216
|
-
}
|
|
3217
|
-
/** Resolve the single relationship of `type` owned by `partName`, or `null`. */
|
|
3218
|
-
function resolveSingleRel(opc, partName, type) {
|
|
3219
|
-
const rels = opc.relationshipsFor(partName);
|
|
3220
|
-
const rel = rels.byType(type)[0];
|
|
3221
|
-
return rel ? rels.resolveTarget(rel.id) : null;
|
|
3222
|
-
}
|
|
3223
|
-
//#endregion
|
|
3224
3954
|
//#region src/read/api/ops/prune.ts
|
|
3225
3955
|
/**
|
|
3226
3956
|
* Orphan pruning after a part stops being referenced.
|
|
@@ -3286,8 +4016,6 @@ function isReferenced(pres, partName) {
|
|
|
3286
4016
|
* scales it again on top of the first. It is owned by the calling `Presentation` and threaded
|
|
3287
4017
|
* through here, so it lives as long as the deck does rather than as long as one call.
|
|
3288
4018
|
*/
|
|
3289
|
-
const SLIDE_LAYOUT_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
|
|
3290
|
-
const SLIDE_MASTER_REL$1 = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
|
|
3291
4019
|
/**
|
|
3292
4020
|
* Rescale an imported slide's geometry onto this deck's canvas (the `rescale`
|
|
3293
4021
|
* option of {@link Presentation.importSlide}). Rewrites every top-level shape/group/
|
|
@@ -3302,8 +4030,8 @@ function rescaleImportedGeometry(dest, rescaledParts, slidePartName, theme, sour
|
|
|
3302
4030
|
const transform = computeRescale(source, target, mode);
|
|
3303
4031
|
rescalePartGeometry(dest, rescaledParts, slidePartName, transform);
|
|
3304
4032
|
if (theme === void 0 || theme === "copy") {
|
|
3305
|
-
const layout = resolveSingleRel(dest.opc, slidePartName, SLIDE_LAYOUT_REL
|
|
3306
|
-
const master = layout ? resolveSingleRel(dest.opc, layout, SLIDE_MASTER_REL
|
|
4033
|
+
const layout = resolveSingleRel(dest.opc, slidePartName, SLIDE_LAYOUT_REL);
|
|
4034
|
+
const master = layout ? resolveSingleRel(dest.opc, layout, SLIDE_MASTER_REL) : null;
|
|
3307
4035
|
if (layout) rescalePartGeometry(dest, rescaledParts, layout, transform);
|
|
3308
4036
|
if (master) rescalePartGeometry(dest, rescaledParts, master, transform);
|
|
3309
4037
|
}
|
|
@@ -3330,14 +4058,14 @@ function rescalePartGeometry(dest, rescaledParts, partName, transform) {
|
|
|
3330
4058
|
* Read-model entry point: `Presentation` wraps an `OpcPackage` and exposes a
|
|
3331
4059
|
* navigable, typed view of the deck (slides → shapes → text), backed by the
|
|
3332
4060
|
* live DOM so the same nodes can later be mutated.
|
|
4061
|
+
*
|
|
4062
|
+
* The class holds the model and the deck-level plumbing every operation needs — the part
|
|
4063
|
+
* index, the slide list, the copy registry that lets repeated imports from one source share
|
|
4064
|
+
* what they already copied, and the `p:sldIdLst` wiring. The operations themselves live in
|
|
4065
|
+
* `ops/`, one job per module, taking this deck as an argument. The slide-import machinery
|
|
4066
|
+
* used to sit here as ~280 lines of private methods and made that split hard to see: the
|
|
4067
|
+
* read model's own surface was outnumbered by one feature's internals.
|
|
3333
4068
|
*/
|
|
3334
|
-
const OFFICE_DOCUMENT_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
|
|
3335
|
-
const SLIDE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide";
|
|
3336
|
-
const SLIDE_LAYOUT_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout";
|
|
3337
|
-
const SLIDE_MASTER_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster";
|
|
3338
|
-
const NOTES_SLIDE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide";
|
|
3339
|
-
const NOTES_MASTER_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster";
|
|
3340
|
-
const IMAGE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
|
3341
4069
|
const HYPERLINK_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
|
|
3342
4070
|
const CHART_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
|
|
3343
4071
|
const PACKAGE_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
|
|
@@ -3668,13 +4396,14 @@ var Presentation = class Presentation {
|
|
|
3668
4396
|
throw new InvalidOptionError("import/slide-size-mismatch", `importSlide requires equal slide sizes (pass { rescale: 'fit' | 'stretch' } to rescale); target is ${fmt(target)}, source is ${fmt(incoming)}`);
|
|
3669
4397
|
}
|
|
3670
4398
|
if (sizesDiffer && options.rescale && (!target || !incoming)) throw new InvalidOptionError("import/slide-size-unknown", "importSlide rescale requires both decks to declare a slide size (p:sldSz)");
|
|
3671
|
-
const
|
|
4399
|
+
const importCtx = this.#importContext(source.opc);
|
|
4400
|
+
const newPartName = options.theme === "preserve" ? importSlidePreserve(this, importCtx, source, sourceSlide, options.carryMasterGraphics === true) : options.theme === "restyle" ? importSlideRestyle(this, importCtx, source, sourceSlide, options.carryMasterGraphics === true, options.remapLiterals === true) : copyPart(importCtx, sourceSlide.partName);
|
|
3672
4401
|
const newPart = this.opc.part(newPartName);
|
|
3673
4402
|
if (!newPart) throw new InternalError("import/part-went-missing", `Imported slide part went missing: ${newPartName}`);
|
|
3674
4403
|
if (sizesDiffer && options.rescale && target && incoming) rescaleImportedGeometry(this, this.#rescaledParts, newPartName, options.theme, incoming, target, options.rescale === true ? "fit" : options.rescale);
|
|
3675
4404
|
const slide = this.#insertSlidePart(newPart, options.at);
|
|
3676
|
-
if (options.importNotes) carryNotes(this, source,
|
|
3677
|
-
if (options.embedFonts) carryEmbeddedFonts(this, source,
|
|
4405
|
+
if (options.importNotes) carryNotes(this, source, importCtx, sourceSlide.partName, newPartName);
|
|
4406
|
+
if (options.embedFonts) carryEmbeddedFonts(this, source, importCtx);
|
|
3678
4407
|
return slide;
|
|
3679
4408
|
}
|
|
3680
4409
|
/**
|
|
@@ -3965,14 +4694,14 @@ var Presentation = class Presentation {
|
|
|
3965
4694
|
const sourceRels = sourceOpc.relationshipsFor(source.partName);
|
|
3966
4695
|
const targetRels = this.opc.relationshipsFor(target.partName);
|
|
3967
4696
|
const relIdMap = /* @__PURE__ */ new Map();
|
|
3968
|
-
const ctx = theme === "preserve" ?
|
|
4697
|
+
const ctx = theme === "preserve" ? sourceFlattenContext(sourceOpc, source.partName) : null;
|
|
3969
4698
|
const importCtx = this.#importContext(sourceOpc);
|
|
3970
4699
|
const extLst = firstChild(spTree, "p:extLst");
|
|
3971
4700
|
const anchor = options.at == null ? extLst : nthShapeChild(spTree, options.at) ?? extLst;
|
|
3972
4701
|
const result = [];
|
|
3973
4702
|
for (const shapeEl of sourceElements) {
|
|
3974
4703
|
const imported = targetDoc.importNode(shapeEl, true);
|
|
3975
|
-
|
|
4704
|
+
rewriteCarriedRels(imported, importCtx, sourceRels, target.partName, targetRels, relIdMap);
|
|
3976
4705
|
if (ctx) {
|
|
3977
4706
|
const holder = createElement(targetDoc, "p:spTree");
|
|
3978
4707
|
holder.appendChild(imported);
|
|
@@ -4008,215 +4737,6 @@ var Presentation = class Presentation {
|
|
|
4008
4737
|
return result;
|
|
4009
4738
|
}
|
|
4010
4739
|
/**
|
|
4011
|
-
* Import a slide in `preserve` mode: rebind it to this deck's master/layout
|
|
4012
|
-
* (see {@link #importSlideRebind}), then flatten its source theme into the slide
|
|
4013
|
-
* XML (scheme colours + style-matrix fills baked to literals). Returns the new
|
|
4014
|
-
* partname.
|
|
4015
|
-
*
|
|
4016
|
-
* The flatten context is gathered from the *source* subgraph, so it can be read
|
|
4017
|
-
* before or after the rebind; the rebind injects any carried decorations before
|
|
4018
|
-
* we flatten, so a single sweep resolves the theme references on the slide's own
|
|
4019
|
-
* content and on the carried decorations together.
|
|
4020
|
-
*/
|
|
4021
|
-
#importSlidePreserve(source, sourceSlide, carryGraphics) {
|
|
4022
|
-
const ctx = this.#sourceFlattenContext(source.opc, sourceSlide.partName);
|
|
4023
|
-
const { newPartName, slideRoot, newPart } = this.#importSlideRebind(source, sourceSlide, carryGraphics);
|
|
4024
|
-
flattenSlide(slideRoot, ctx);
|
|
4025
|
-
newPart.markDirty();
|
|
4026
|
-
return newPartName;
|
|
4027
|
-
}
|
|
4028
|
-
/**
|
|
4029
|
-
* Import a slide in `restyle` mode: rebind it to this deck's master/layout (see
|
|
4030
|
-
* {@link #importSlideRebind}) and then {@link restyleSlide} it — drop its colour
|
|
4031
|
-
* map override but bake *nothing*, so its symbolic theme references re-resolve
|
|
4032
|
-
* against the destination theme and the slide re-brands. Returns the new
|
|
4033
|
-
* partname.
|
|
4034
|
-
*
|
|
4035
|
-
* The deliberate inverse of `preserve`: no flatten, no inherited-background
|
|
4036
|
-
* bake, no placeholder colour/size/geometry bake — every one of those would pin
|
|
4037
|
-
* the slide to its source look, the opposite of re-branding. Carried
|
|
4038
|
-
* decorations are left symbolic too, so they re-brand along with the slide.
|
|
4039
|
-
*
|
|
4040
|
-
* With `remapLiterals` it additionally force-remaps the slide's source-theme
|
|
4041
|
-
* literal colours back to symbolic scheme colours and copies any referenced
|
|
4042
|
-
* source table style into this deck — the two things plain `restyle` cannot
|
|
4043
|
-
* re-brand (see {@link ImportSlideOptions.remapLiterals}).
|
|
4044
|
-
*/
|
|
4045
|
-
#importSlideRestyle(source, sourceSlide, carryGraphics, remapLiterals) {
|
|
4046
|
-
const { newPartName, slideRoot, newPart } = this.#importSlideRebind(source, sourceSlide, carryGraphics);
|
|
4047
|
-
restyleSlide(slideRoot);
|
|
4048
|
-
if (remapLiterals) {
|
|
4049
|
-
const parts = resolveSlideThemeParts(source.opc, sourceSlide.partName);
|
|
4050
|
-
remapLiteralColors(slideRoot, {
|
|
4051
|
-
clrMap: parts.clrMap,
|
|
4052
|
-
clrScheme: parts.clrScheme
|
|
4053
|
-
});
|
|
4054
|
-
copySourceTableStyles(this, source.opc, slideRoot);
|
|
4055
|
-
}
|
|
4056
|
-
newPart.markDirty();
|
|
4057
|
-
return newPartName;
|
|
4058
|
-
}
|
|
4059
|
-
/**
|
|
4060
|
-
* The rebind shared by `preserve` and `restyle`: copy the slide bytes into a
|
|
4061
|
-
* fresh part, rebuild its relationships (drop notes, repoint the `slideLayout`
|
|
4062
|
-
* rel at this deck's existing layout, copy every other internal target —
|
|
4063
|
-
* media/charts — and pass externals through), and optionally bake the source
|
|
4064
|
-
* master/layout decorations onto the slide. Returns the new part, its name, and
|
|
4065
|
-
* its live root element for the caller's mode-specific pass (flatten vs restyle).
|
|
4066
|
-
*
|
|
4067
|
-
* This carries *no* theme baking of its own — not even the inherited background.
|
|
4068
|
-
* `preserve` adds that via {@link flattenSlide}'s context; `restyle` must not,
|
|
4069
|
-
* so the background stays symbolic and re-brands.
|
|
4070
|
-
*/
|
|
4071
|
-
#importSlideRebind(source, sourceSlide, carryGraphics) {
|
|
4072
|
-
const destLayout = this.#destinationLayoutPartName();
|
|
4073
|
-
const sourcePart = source.opc.part(sourceSlide.partName);
|
|
4074
|
-
if (!sourcePart) throw new PackageReadError("package/part-missing", `importSlide: source package has no part ${sourceSlide.partName}`);
|
|
4075
|
-
const newPartName = this.opc.reservePartNameLike(sourceSlide.partName);
|
|
4076
|
-
const newPart = this.opc.addPart(newPartName, sourcePart.contentType, sourcePart.bytes);
|
|
4077
|
-
const slideRoot = newPart.dom.documentElement;
|
|
4078
|
-
if (!slideRoot) throw new PackageReadError("package/part-has-no-root", `Imported slide ${newPartName} has no root element`);
|
|
4079
|
-
const ctx = this.#importContext(source.opc);
|
|
4080
|
-
const sourceRels = source.opc.relationshipsFor(sourceSlide.partName);
|
|
4081
|
-
const targetRels = this.opc.relationshipsFor(newPartName);
|
|
4082
|
-
for (const rel of sourceRels) {
|
|
4083
|
-
if (rel.type === NOTES_SLIDE_REL) continue;
|
|
4084
|
-
if (rel.type === SLIDE_LAYOUT_REL) {
|
|
4085
|
-
targetRels.addWithId(rel.id, SLIDE_LAYOUT_REL, relativePartName(newPartName, destLayout));
|
|
4086
|
-
continue;
|
|
4087
|
-
}
|
|
4088
|
-
if (rel.targetMode === "External") {
|
|
4089
|
-
targetRels.addWithId(rel.id, rel.type, rel.target, "External");
|
|
4090
|
-
continue;
|
|
4091
|
-
}
|
|
4092
|
-
const newTarget = copyPart(ctx, sourceRels.resolveTarget(rel.id));
|
|
4093
|
-
targetRels.addWithId(rel.id, rel.type, relativePartName(newPartName, newTarget));
|
|
4094
|
-
}
|
|
4095
|
-
if (carryGraphics) this.#carryMasterGraphics(ctx, slideRoot, newPartName, sourceSlide.partName);
|
|
4096
|
-
return {
|
|
4097
|
-
newPartName,
|
|
4098
|
-
slideRoot,
|
|
4099
|
-
newPart
|
|
4100
|
-
};
|
|
4101
|
-
}
|
|
4102
|
-
/**
|
|
4103
|
-
* Bake the source `slideLayout`/`slideMaster` shape-tree decorations onto the
|
|
4104
|
-
* imported slide (the `carryMasterGraphics` path). Every shape on those trees
|
|
4105
|
-
* *except* placeholders is deep-copied into the slide's `p:spTree` ahead of its
|
|
4106
|
-
* own content — master decorations first, then layout, then the slide's shapes —
|
|
4107
|
-
* so document (z-)order keeps the master furthest back. Each decoration's media
|
|
4108
|
-
* and other relationship targets are copied into this package and its
|
|
4109
|
-
* `r:embed`/`r:id`/… references rewritten to fresh slide-local ids. The injected
|
|
4110
|
-
* shapes are left for the caller's {@link flattenSlide} pass to resolve any
|
|
4111
|
-
* theme references they carry.
|
|
4112
|
-
*/
|
|
4113
|
-
#carryMasterGraphics(ctx, slideRoot, newPartName, slidePartName) {
|
|
4114
|
-
const sourceOpc = ctx.source;
|
|
4115
|
-
const layoutPartName = resolveSingleRel(sourceOpc, slidePartName, SLIDE_LAYOUT_REL);
|
|
4116
|
-
const masterPartName = layoutPartName ? resolveSingleRel(sourceOpc, layoutPartName, SLIDE_MASTER_REL) : null;
|
|
4117
|
-
const cSld = firstChild(slideRoot, "p:cSld");
|
|
4118
|
-
const spTree = cSld && firstChild(cSld, "p:spTree");
|
|
4119
|
-
if (!spTree) return;
|
|
4120
|
-
const doc = ownerDocumentOf(slideRoot);
|
|
4121
|
-
const slideRels = this.opc.relationshipsFor(newPartName);
|
|
4122
|
-
const relIdMap = /* @__PURE__ */ new Map();
|
|
4123
|
-
const anchor = firstShapeChild(spTree);
|
|
4124
|
-
for (const partName of [masterPartName, layoutPartName]) {
|
|
4125
|
-
if (!partName) continue;
|
|
4126
|
-
const decorations = carriedDecorations(sourceOpc.part(partName)?.dom.documentElement ?? null);
|
|
4127
|
-
if (decorations.length === 0) continue;
|
|
4128
|
-
const sourceRels = sourceOpc.relationshipsFor(partName);
|
|
4129
|
-
for (const deco of decorations) {
|
|
4130
|
-
const imported = doc.importNode(deco, true);
|
|
4131
|
-
this.#rewriteCarriedRels(imported, ctx, sourceRels, newPartName, slideRels, relIdMap);
|
|
4132
|
-
spTree.insertBefore(imported, anchor);
|
|
4133
|
-
}
|
|
4134
|
-
}
|
|
4135
|
-
}
|
|
4136
|
-
/**
|
|
4137
|
-
* Rewrite every relationship reference (`r:embed`, `r:id`, `r:link`, …) inside a
|
|
4138
|
-
* carried decoration so it points at a fresh slide-local relationship, copying
|
|
4139
|
-
* the referenced part into this package on first sight. `relIdMap` (keyed by
|
|
4140
|
-
* source part + source rel id) dedupes references shared within one import call.
|
|
4141
|
-
*/
|
|
4142
|
-
#rewriteCarriedRels(node, ctx, sourceRels, newPartName, slideRels, relIdMap) {
|
|
4143
|
-
const elements = [];
|
|
4144
|
-
collectElements(node, elements);
|
|
4145
|
-
for (const el of elements) {
|
|
4146
|
-
const refs = [];
|
|
4147
|
-
const attrs = el.attributes;
|
|
4148
|
-
for (let i = 0; i < attrs.length; i++) {
|
|
4149
|
-
const a = attrs.item(i);
|
|
4150
|
-
if (!a || a.namespaceURI !== OOXML_NS.r || !a.value) continue;
|
|
4151
|
-
if (!sourceRels.get(a.value)) continue;
|
|
4152
|
-
refs.push({
|
|
4153
|
-
local: a.localName ?? a.name,
|
|
4154
|
-
id: a.value
|
|
4155
|
-
});
|
|
4156
|
-
}
|
|
4157
|
-
for (const { local, id } of refs) setAttr(el, `r:${local}`, this.#carryRel(ctx, sourceRels, id, newPartName, slideRels, relIdMap));
|
|
4158
|
-
}
|
|
4159
|
-
}
|
|
4160
|
-
/** Resolve a carried decoration's source relationship to a fresh slide-local id, copying its internal target. */
|
|
4161
|
-
#carryRel(ctx, sourceRels, id, newPartName, slideRels, relIdMap) {
|
|
4162
|
-
const key = `${sourceRels.sourcePartName}|${id}`;
|
|
4163
|
-
const cached = relIdMap.get(key);
|
|
4164
|
-
if (cached) return cached;
|
|
4165
|
-
const rel = sourceRels.get(id);
|
|
4166
|
-
if (!rel) throw new InvalidOptionError("relationship/not-found", `Relationships of ${sourceRels.sourcePartName}: no relationship with id ${id}`);
|
|
4167
|
-
const newId = rel.targetMode === "External" ? slideRels.add(rel.type, rel.target, "External").id : slideRels.add(rel.type, relativePartName(newPartName, copyPart(ctx, sourceRels.resolveTarget(id)))).id;
|
|
4168
|
-
relIdMap.set(key, newId);
|
|
4169
|
-
return newId;
|
|
4170
|
-
}
|
|
4171
|
-
/**
|
|
4172
|
-
* The partname of the layout this deck's slides should attach to in `preserve`
|
|
4173
|
-
* mode: the first layout of the first slide master. Throws when the deck has no
|
|
4174
|
-
* master/layout to attach to (a deck ts-pptx always provides).
|
|
4175
|
-
*/
|
|
4176
|
-
#destinationLayoutPartName() {
|
|
4177
|
-
const presRels = this.opc.relationshipsFor(this.presentationPart.partName);
|
|
4178
|
-
const masterRel = presRels.byType(SLIDE_MASTER_REL)[0];
|
|
4179
|
-
if (!masterRel) throw new InvalidOptionError("import/destination-missing-master", "importSlide preserve mode requires a slide master in the destination deck");
|
|
4180
|
-
const masterPartName = presRels.resolveTarget(masterRel.id);
|
|
4181
|
-
const masterRels = this.opc.relationshipsFor(masterPartName);
|
|
4182
|
-
const layoutRel = masterRels.byType(SLIDE_LAYOUT_REL)[0];
|
|
4183
|
-
if (!layoutRel) throw new InvalidOptionError("import/destination-missing-layout", "importSlide preserve mode requires a slide layout in the destination deck");
|
|
4184
|
-
return masterRels.resolveTarget(layoutRel.id);
|
|
4185
|
-
}
|
|
4186
|
-
/**
|
|
4187
|
-
* Gather the flatten context for a source slide: walk slide → layout → master →
|
|
4188
|
-
* theme, reading the effective colour map (the slide's `clrMapOvr` override, or
|
|
4189
|
-
* the master `clrMap`), the theme `clrScheme`, and the theme `fmtScheme`.
|
|
4190
|
-
*/
|
|
4191
|
-
#sourceFlattenContext(sourceOpc, slidePartName) {
|
|
4192
|
-
const parts = resolveSlideThemeParts(sourceOpc, slidePartName);
|
|
4193
|
-
const themeElements = parts.themeElements;
|
|
4194
|
-
return {
|
|
4195
|
-
clrMap: parts.clrMap,
|
|
4196
|
-
clrScheme: parts.clrScheme,
|
|
4197
|
-
fmtScheme: themeElements ? firstChild(themeElements, "a:fmtScheme") : null,
|
|
4198
|
-
inheritedBackground: this.#effectiveBackground(sourceOpc, parts.slideRoot, parts.layoutPartName, parts.masterPartName),
|
|
4199
|
-
layoutRoot: parts.layoutRoot,
|
|
4200
|
-
masterRoot: parts.masterRoot
|
|
4201
|
-
};
|
|
4202
|
-
}
|
|
4203
|
-
/**
|
|
4204
|
-
* The background the slide effectively inherits from its source subgraph: the
|
|
4205
|
-
* layout's `p:bg`, else the master's. Returns `null` when the slide carries its
|
|
4206
|
-
* own `p:bg` (it stays on the slide and is flattened directly) or none exists.
|
|
4207
|
-
*/
|
|
4208
|
-
#effectiveBackground(sourceOpc, slideRoot, layoutPartName, masterPartName) {
|
|
4209
|
-
if (slideRoot && this.#backgroundOf(slideRoot)) return null;
|
|
4210
|
-
const layoutRoot = layoutPartName ? sourceOpc.part(layoutPartName)?.dom.documentElement ?? null : null;
|
|
4211
|
-
const masterRoot = masterPartName ? sourceOpc.part(masterPartName)?.dom.documentElement ?? null : null;
|
|
4212
|
-
return (layoutRoot && this.#backgroundOf(layoutRoot)) ?? (masterRoot && this.#backgroundOf(masterRoot)) ?? null;
|
|
4213
|
-
}
|
|
4214
|
-
/** The `p:cSld/p:bg` element of a slide/layout/master root, or `null`. */
|
|
4215
|
-
#backgroundOf(root) {
|
|
4216
|
-
const cSld = firstChild(root, "p:cSld");
|
|
4217
|
-
return cSld ? firstChild(cSld, "p:bg") : null;
|
|
4218
|
-
}
|
|
4219
|
-
/**
|
|
4220
4740
|
* Open an import out of `source`: this deck as the destination, paired with the
|
|
4221
4741
|
* copy registry for that package (created on first use). The registry is held on
|
|
4222
4742
|
* the class rather than in the context because it must outlive any one call —
|
|
@@ -4277,4 +4797,4 @@ var Presentation = class Presentation {
|
|
|
4277
4797
|
//#endregion
|
|
4278
4798
|
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 };
|
|
4279
4799
|
|
|
4280
|
-
//# sourceMappingURL=presentation-
|
|
4800
|
+
//# sourceMappingURL=presentation-DAcOfzsP.js.map
|