pptx-angular-viewer 2.12.0 → 2.12.1
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/CHANGELOG.md +2 -0
- package/fesm2022/{pptx-angular-viewer-chat-history-idb-DdlrIrmU.mjs → pptx-angular-viewer-chat-history-idb-GPhhg6RN.mjs} +2 -2
- package/fesm2022/{pptx-angular-viewer-chat-history-idb-DdlrIrmU.mjs.map → pptx-angular-viewer-chat-history-idb-GPhhg6RN.mjs.map} +1 -1
- package/fesm2022/{pptx-angular-viewer-pptx-angular-viewer-y5x5Ro5v.mjs → pptx-angular-viewer-pptx-angular-viewer-DYqQlNxt.mjs} +1875 -308
- package/fesm2022/{pptx-angular-viewer-pptx-angular-viewer-y5x5Ro5v.mjs.map → pptx-angular-viewer-pptx-angular-viewer-DYqQlNxt.mjs.map} +1 -1
- package/fesm2022/pptx-angular-viewer.mjs +1 -1
- package/package.json +1 -1
- package/pptx-angular-viewer.css +1 -1
- package/types/pptx-angular-viewer.d.ts +157 -51
|
@@ -7,7 +7,7 @@ import DOMPurify from 'dompurify';
|
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import * as mcp from 'pptx-viewer-mcp';
|
|
9
9
|
import * as mcpSchemas from 'pptx-viewer-mcp/schemas';
|
|
10
|
-
import { LucideX, LucideSquare, LucideCircle, LucideSlash, LucideCopy, LucideTrash2, LucideChevronsUp, LucideChevronsDown, LucideArrowUp, LucideArrowDown, LucideGroup, LucideUngroup, LucideTextAlignStart, LucideTextAlignCenter, LucideTextAlignEnd, LucideChevronUp, LucideChevronDown, LucideAlignHorizontalSpaceAround, LucideAlignVerticalSpaceAround, LucideLayers, LucideMessageSquare, LucidePlus, LucideSettings2, LucideStickyNote, LucideDownload, LucideMenu, LucidePresentation, LucideRedo, LucideShare2, LucideSparkles, LucideUndo, LucideChevronRight, LucideChevronLeft, LucideEraser, LucideHighlighter, LucideMousePointer2, LucidePanelRight, LucidePenTool, LucideTimer, LucideStar, LucideMoveRight, LucidePlay, LucideMousePointerClick, LucidePaintbrush, LucideClock3, LucidePencil, LucideType, LucideMinus, LucideSpline, LucideArrowLeft, LucideFilePlus2, LucideFolderOpen, LucideHome, LucideInfo, LucidePrinter, LucideSave, LucideSettings, LucideUpload, LucideUserRound, LucideAArrowUp, LucideAArrowDown, LucideRemoveFormatting, LucideList, LucideListOrdered, LucideListIndentDecrease, LucideListIndentIncrease, LucideTextAlignJustify, LucideClipboardPaste, LucideFolderPlus, LucideLayoutGrid,
|
|
10
|
+
import { LucideX, LucideSquare, LucideCircle, LucideSlash, LucideCopy, LucideTrash2, LucideChevronsUp, LucideChevronsDown, LucideArrowUp, LucideArrowDown, LucideGroup, LucideUngroup, LucideTextAlignStart, LucideTextAlignCenter, LucideTextAlignEnd, LucideChevronUp, LucideChevronDown, LucideAlignHorizontalSpaceAround, LucideAlignVerticalSpaceAround, LucideLayers, LucideMessageSquare, LucidePlus, LucideSettings2, LucideStickyNote, LucideDownload, LucideMenu, LucidePresentation, LucideRedo, LucideShare2, LucideSparkles, LucideUndo, LucideChevronRight, LucideChevronLeft, LucideEraser, LucideHighlighter, LucideMousePointer2, LucidePanelRight, LucidePenTool, LucideTimer, LucideArrowLeftRight, LucideCaptions, LucideCirclePause, LucideCirclePlay, LucideGrid2x2, LucideMonitor, LucideMonitorOff, LucideRotateCcw, LucideScan, LucideZoomIn, LucideZoomOut, LucideStar, LucideMoveRight, LucidePlay, LucideMousePointerClick, LucidePaintbrush, LucideClock3, LucidePencil, LucideType, LucideMinus, LucideSpline, LucideArrowLeft, LucideFilePlus2, LucideFolderOpen, LucideHome, LucideInfo, LucidePrinter, LucideSave, LucideSettings, LucideUpload, LucideUserRound, LucideAArrowUp, LucideAArrowDown, LucideRemoveFormatting, LucideList, LucideListOrdered, LucideListIndentDecrease, LucideListIndentIncrease, LucideTextAlignJustify, LucideClipboardPaste, LucideFolderPlus, LucideLayoutGrid, LucideScissors, LucideLink, LucideImage, LucideVideo, LucideDatabase, LucidePanelLeft, LucideEllipsis, LucideEye, LucideEyeOff, LucideColumns2, LucideCheck, LucideFileDown, LucideSearch, LucideBug, LucideSend, LucideCrosshair, LucideGitMerge, LucidePin, LucidePinOff, LucideWrench, LucideLoaderCircle, LucideTriangleAlert, LucideShapes, LucidePalette, LucideTable, LucideLayoutTemplate, LucideChartColumn, LucideMove, LucideNavigation, LucideFilm, LucideBot, LucideUser } from '@lucide/angular';
|
|
11
11
|
import { XMLParser } from 'fast-xml-parser';
|
|
12
12
|
import JSZip from 'jszip';
|
|
13
13
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
@@ -16832,6 +16832,10 @@ function normalizeDelay(delay) {
|
|
|
16832
16832
|
}
|
|
16833
16833
|
return { ms: delay, indefinite: false };
|
|
16834
16834
|
}
|
|
16835
|
+
/** Triggers that only fire once the viewer does something. */
|
|
16836
|
+
function isInteractiveTrigger(trigger) {
|
|
16837
|
+
return trigger === 'onClick' || trigger === 'onShapeClick' || trigger === 'onHover';
|
|
16838
|
+
}
|
|
16835
16839
|
function classifyCondition(cond) {
|
|
16836
16840
|
const evt = cond.event;
|
|
16837
16841
|
if (evt && CLICK_EVENTS.has(evt)) {
|
|
@@ -16869,6 +16873,7 @@ function resolveEffectiveStartCondition(conditions, fallbackTrigger) {
|
|
|
16869
16873
|
hasClickAlternative: false,
|
|
16870
16874
|
hasHoverAlternative: false,
|
|
16871
16875
|
indefinite: false,
|
|
16876
|
+
requiresInteraction: isInteractiveTrigger(fallbackTrigger),
|
|
16872
16877
|
};
|
|
16873
16878
|
if (!conditions || conditions.length === 0) {
|
|
16874
16879
|
return base;
|
|
@@ -16917,6 +16922,8 @@ function resolveEffectiveStartCondition(conditions, fallbackTrigger) {
|
|
|
16917
16922
|
base.indefinite = indefinite;
|
|
16918
16923
|
base.dependsOnTimeNodeId = timenode.targetTimeNodeId;
|
|
16919
16924
|
base.dependsOnEvent = timenode.event;
|
|
16925
|
+
// Chained off another node's begin/end: the timeline starts it, not a click.
|
|
16926
|
+
base.requiresInteraction = false;
|
|
16920
16927
|
return base;
|
|
16921
16928
|
}
|
|
16922
16929
|
// 2. Pure delay governs.
|
|
@@ -16926,15 +16933,21 @@ function resolveEffectiveStartCondition(conditions, fallbackTrigger) {
|
|
|
16926
16933
|
base.trigger = clickCond ? 'onClick' : 'afterDelay';
|
|
16927
16934
|
base.delayMs = ms;
|
|
16928
16935
|
base.indefinite = indefinite;
|
|
16936
|
+
// The delay fires on its own; a coexisting click only brings it forward,
|
|
16937
|
+
// so this node does not WAIT for the viewer even when `trigger` says
|
|
16938
|
+
// `onClick` (that spelling exists so the engine offers the early-out).
|
|
16939
|
+
base.requiresInteraction = indefinite;
|
|
16929
16940
|
return base;
|
|
16930
16941
|
}
|
|
16931
16942
|
// 3. Interactive trigger governs.
|
|
16932
16943
|
if (clickCond) {
|
|
16933
16944
|
base.trigger = clickCond.targetShapeId ? 'onShapeClick' : 'onClick';
|
|
16945
|
+
base.requiresInteraction = true;
|
|
16934
16946
|
return base;
|
|
16935
16947
|
}
|
|
16936
16948
|
if (hoverCond) {
|
|
16937
16949
|
base.trigger = 'onHover';
|
|
16950
|
+
base.requiresInteraction = true;
|
|
16938
16951
|
return base;
|
|
16939
16952
|
}
|
|
16940
16953
|
// 4. Zero-delay-only condition (onBegin / @_delay="0"): keep fallback but
|
|
@@ -16942,6 +16955,7 @@ function resolveEffectiveStartCondition(conditions, fallbackTrigger) {
|
|
|
16942
16955
|
if (delayCond) {
|
|
16943
16956
|
base.trigger = fallbackTrigger;
|
|
16944
16957
|
base.delayMs = 0;
|
|
16958
|
+
base.requiresInteraction = false;
|
|
16945
16959
|
}
|
|
16946
16960
|
return base;
|
|
16947
16961
|
}
|
|
@@ -17654,7 +17668,12 @@ function parsePlayFrom(raw) {
|
|
|
17654
17668
|
* - `play` / `resume` -> resume playback.
|
|
17655
17669
|
* - `pause` -> pause playback.
|
|
17656
17670
|
* - `stop` / `stopMedia` -> pause and rewind to the start.
|
|
17657
|
-
* - `togglePlay` -> pause if playing, else play.
|
|
17671
|
+
* - `togglePlay` / `togglePause` -> pause if playing, else play.
|
|
17672
|
+
*
|
|
17673
|
+
* `togglePause` is PowerPoint's own spelling: a video authored with "click to
|
|
17674
|
+
* pause" emits `<p:cmd type="call" cmd="togglePause"/>` in its interactiveSeq,
|
|
17675
|
+
* never `togglePlay`. Both name the same two-way toggle, so they map to one
|
|
17676
|
+
* verb; missing the alias made clicking such a video silently do nothing.
|
|
17658
17677
|
*
|
|
17659
17678
|
* Any other command string (including non-media `evt` / `verb` commands, or a
|
|
17660
17679
|
* numeric verb code with no browser analogue) returns `undefined` so the caller
|
|
@@ -17679,7 +17698,7 @@ function parseMediaCommand(commandString) {
|
|
|
17679
17698
|
if (lower === 'stop' || lower === 'stopmedia') {
|
|
17680
17699
|
return { verb: 'stop' };
|
|
17681
17700
|
}
|
|
17682
|
-
if (lower === 'toggleplay') {
|
|
17701
|
+
if (lower === 'toggleplay' || lower === 'togglepause') {
|
|
17683
17702
|
return { verb: 'togglePlay' };
|
|
17684
17703
|
}
|
|
17685
17704
|
return undefined;
|
|
@@ -17922,7 +17941,16 @@ function buildTimeline(nativeAnimations) {
|
|
|
17922
17941
|
// is how PowerPoint renders a deck whose opening effects are "With
|
|
17923
17942
|
// Previous"; without it the first group was always click-gated and
|
|
17924
17943
|
// the slide showed nothing until the viewer clicked.
|
|
17925
|
-
|
|
17944
|
+
// `isOnClick` alone is the wrong test: `resolveAnimationStart` keeps
|
|
17945
|
+
// the node's fallback trigger (`onClick`) whenever its condition list
|
|
17946
|
+
// carries no actionable semantics, so a step the deck marks as
|
|
17947
|
+
// auto-starting AND whose only condition is `<p:cond delay="0"/>`
|
|
17948
|
+
// looked click-gated. `requiresInteraction` distinguishes the two,
|
|
17949
|
+
// which is what makes a slide-entry `p:cmd` media command (the
|
|
17950
|
+
// `playFrom(0.0)` on solution-explorer slide 2) start with the slide
|
|
17951
|
+
// instead of waiting for a Next press.
|
|
17952
|
+
currentGroupAutoStart =
|
|
17953
|
+
singleAnim.groupAutoStart === true && !effective.requiresInteraction;
|
|
17926
17954
|
subGroupIndex = singleAnim.parGroupIndex;
|
|
17927
17955
|
subGroupStartMs = 0;
|
|
17928
17956
|
}
|
|
@@ -18057,27 +18085,35 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
|
|
|
18057
18085
|
for (const anim of anims) {
|
|
18058
18086
|
let effect = resolveEffect(anim);
|
|
18059
18087
|
const dynamic = effect ? undefined : buildDynamicKeyframe(anim, dynamicUid++);
|
|
18060
|
-
|
|
18088
|
+
// An interactive sequence can hold a `p:cmd` media command just as the
|
|
18089
|
+
// main sequence can (PowerPoint's "click the video to pause it" is
|
|
18090
|
+
// authored exactly that way). Without this branch the step fell through
|
|
18091
|
+
// to the unmapped-preset safety net, and because a `mediacall` effect
|
|
18092
|
+
// carries no whitelisted `presetClass` the net returned nothing and the
|
|
18093
|
+
// command was dropped in silence.
|
|
18094
|
+
const isCommand = !effect && !dynamic && isMediaCommandAnimation(anim);
|
|
18095
|
+
if (!effect && !dynamic && !isCommand) {
|
|
18061
18096
|
// Same unmapped-preset safety net as the main timeline loop.
|
|
18062
18097
|
effect = fallbackEffectForClass(anim.presetClass);
|
|
18063
18098
|
if (!effect) {
|
|
18064
18099
|
continue;
|
|
18065
18100
|
}
|
|
18066
18101
|
}
|
|
18067
|
-
const keyframe = effect ? cssKeyframeName(effect) : dynamic.keyframeName;
|
|
18102
|
+
const keyframe = isCommand ? '' : effect ? cssKeyframeName(effect) : dynamic.keyframeName;
|
|
18068
18103
|
if (effect) {
|
|
18069
18104
|
neededKeyframes.add(effect);
|
|
18070
18105
|
}
|
|
18071
18106
|
if (dynamic) {
|
|
18072
18107
|
dynamicBlocks.push(dynamic.css);
|
|
18073
18108
|
}
|
|
18074
|
-
|
|
18109
|
+
// Command steps carry no element visibility semantics; see the main loop.
|
|
18110
|
+
const elementId = isCommand ? '' : (anim.targetId ?? '');
|
|
18075
18111
|
const seqTrigger = anim.trigger ?? 'onShapeClick';
|
|
18076
|
-
const duration = anim.durationMs ?? defaultDuration(anim.presetClass);
|
|
18112
|
+
const duration = isCommand ? 0 : (anim.durationMs ?? defaultDuration(anim.presetClass));
|
|
18077
18113
|
// Same single-quantity rule as the main sequence: never sum the two.
|
|
18078
18114
|
const animDelay = Math.max(anim.delayMs ?? 0, anim.triggerDelayMs ?? 0);
|
|
18079
18115
|
const triggerDelay = 0;
|
|
18080
|
-
const presetClass = anim.presetClass ?? 'entr';
|
|
18116
|
+
const presetClass = isCommand ? 'emph' : (anim.presetClass ?? 'entr');
|
|
18081
18117
|
const fill = fillModeForClass(anim.presetClass);
|
|
18082
18118
|
const iterCount = anim.repeatCount ?? 1;
|
|
18083
18119
|
const direction = anim.autoReverse ? 'alternate' : 'normal';
|
|
@@ -18104,7 +18140,9 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
|
|
|
18104
18140
|
}
|
|
18105
18141
|
const iterStr = iterCount === Infinity ? 'infinite' : String(iterCount);
|
|
18106
18142
|
const easing = cssEasingForAnimation(anim);
|
|
18107
|
-
const cssAnimation =
|
|
18143
|
+
const cssAnimation = isCommand
|
|
18144
|
+
? ''
|
|
18145
|
+
: `${keyframe} ${duration}ms ${easing} ${delayMs}ms ${iterStr} ${direction} ${fill}`;
|
|
18108
18146
|
seqGroup.push({
|
|
18109
18147
|
elementId,
|
|
18110
18148
|
cssAnimation,
|
|
@@ -18116,8 +18154,9 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
|
|
|
18116
18154
|
presetClass: presetClass,
|
|
18117
18155
|
soundPath: anim.soundPath,
|
|
18118
18156
|
stopSound: anim.stopSound,
|
|
18119
|
-
|
|
18120
|
-
|
|
18157
|
+
command: isCommand ? buildStepCommand(anim) : undefined,
|
|
18158
|
+
build: isCommand ? undefined : resolveStepBuildDescriptor(anim),
|
|
18159
|
+
colorTargets: isCommand ? undefined : stepColorTargets(anim),
|
|
18121
18160
|
});
|
|
18122
18161
|
}
|
|
18123
18162
|
if (seqGroup.length > 0) {
|
|
@@ -31905,6 +31944,131 @@ function applyReroutedConnectors(elements, rerouted) {
|
|
|
31905
31944
|
});
|
|
31906
31945
|
}
|
|
31907
31946
|
|
|
31947
|
+
/**
|
|
31948
|
+
* Dash patterns for connector lines.
|
|
31949
|
+
*
|
|
31950
|
+
* Split out of `connector-path.ts` alongside the arrow markers: a connector's
|
|
31951
|
+
* stroke decoration is a separate concern from where the line is routed, and
|
|
31952
|
+
* both are configured independently in the inspector.
|
|
31953
|
+
*
|
|
31954
|
+
* Pure and framework-agnostic.
|
|
31955
|
+
*/
|
|
31956
|
+
/**
|
|
31957
|
+
* Return the SVG `stroke-dasharray` string for a given OOXML stroke dash preset
|
|
31958
|
+
* and width, or `undefined` for solid lines (no attribute needed).
|
|
31959
|
+
*
|
|
31960
|
+
* Produces a distinct pattern per preset (`dash`, `lgDash`, `dashDot`,
|
|
31961
|
+
* `sysDashDotDot`, etc.) rather than collapsing every non-dot preset to a single
|
|
31962
|
+
* `3w/w` approximation, and honours a `custDash` segment list (`a:custDash/a:ds`)
|
|
31963
|
+
* when supplied. This delegates to the same {@link getSvgStrokeDasharray} the
|
|
31964
|
+
* shape/border code uses, so connectors and shape outlines stay in lock-step.
|
|
31965
|
+
*
|
|
31966
|
+
* @param dash Raw `a:ln/@prstDash` token (e.g. `"lgDashDot"`).
|
|
31967
|
+
* @param strokeWidth Resolved stroke width in px.
|
|
31968
|
+
* @param customDashSegments Optional `custDash` segments; when present they take
|
|
31969
|
+
* precedence and are rendered as an explicit pattern.
|
|
31970
|
+
*/
|
|
31971
|
+
function buildDashArray(dash, strokeWidth, customDashSegments) {
|
|
31972
|
+
const segments = customDashSegments && customDashSegments.length > 0
|
|
31973
|
+
? customDashSegments.map((seg) => ({ dash: seg.dash, space: seg.space }))
|
|
31974
|
+
: undefined;
|
|
31975
|
+
// A `custDash` implies the `custom` dash family even when no `@prstDash`
|
|
31976
|
+
// token was authored alongside it.
|
|
31977
|
+
const dashType = segments ? 'custom' : normalizeStrokeDashType(dash);
|
|
31978
|
+
return getSvgStrokeDasharray(dashType, strokeWidth, segments);
|
|
31979
|
+
}
|
|
31980
|
+
|
|
31981
|
+
/**
|
|
31982
|
+
* connector-hit-target.ts: how wide a connector's pointer target has to be.
|
|
31983
|
+
*
|
|
31984
|
+
* WHY this exists at all: a connector's wrapper is `pointer-events: none`, so
|
|
31985
|
+
* an empty bounding box (connectors are usually large and mostly empty) never
|
|
31986
|
+
* swallows clicks meant for the shapes it spans. That also left the LINE
|
|
31987
|
+
* unclickable, so no pointer route reached a connector and the inspector's
|
|
31988
|
+
* connector card could only be opened from the Elements list. Every binding
|
|
31989
|
+
* therefore paints a transparent stroke along the path that opts back INTO hit
|
|
31990
|
+
* testing with `pointer-events: stroke`, keeping the target on the line and off
|
|
31991
|
+
* the box.
|
|
31992
|
+
*
|
|
31993
|
+
* WHY its own module: `buildConnectorGeometry` hands the width to the three
|
|
31994
|
+
* bindings that consume the geometry object, but Vanilla renders a connector
|
|
31995
|
+
* without ever building one, so it needs the rule and nothing else. Four
|
|
31996
|
+
* bindings agreeing on a magic number by copying it is how they drifted the
|
|
31997
|
+
* first time.
|
|
31998
|
+
*
|
|
31999
|
+
* @module render/connector-hit-target
|
|
32000
|
+
*/
|
|
32001
|
+
/**
|
|
32002
|
+
* Narrowest a connector's pointer target may be, in px.
|
|
32003
|
+
*
|
|
32004
|
+
* WHY a floor: a hairline connector is one or two px of ink, and a target that
|
|
32005
|
+
* thin cannot be hit with a mouse, never mind a finger. PowerPoint shows the
|
|
32006
|
+
* same generosity around a line.
|
|
32007
|
+
*/
|
|
32008
|
+
const CONNECTOR_HIT_MIN_WIDTH = 14;
|
|
32009
|
+
/**
|
|
32010
|
+
* Width of the transparent stroke that makes a connector clickable.
|
|
32011
|
+
*
|
|
32012
|
+
* WHY 3x: the target has to be comfortably wider than the ink so a near miss
|
|
32013
|
+
* still lands, while staying proportional for a thick line.
|
|
32014
|
+
*/
|
|
32015
|
+
function connectorHitStrokeWidth(strokeWidth) {
|
|
32016
|
+
return Math.max(strokeWidth * 3, CONNECTOR_HIT_MIN_WIDTH);
|
|
32017
|
+
}
|
|
32018
|
+
|
|
32019
|
+
/**
|
|
32020
|
+
* Arrow-head marker shapes for connectors.
|
|
32021
|
+
*
|
|
32022
|
+
* A connector's line geometry and its end decorations are independent concerns:
|
|
32023
|
+
* routing answers "where does the line go", this module answers "what is drawn
|
|
32024
|
+
* at each end and how big is it". Splitting them keeps `connector-path.ts`
|
|
32025
|
+
* within the file-size rule and gives the arrow-size mapping a home of its own,
|
|
32026
|
+
* since it is the part users actually configure (the inspector's six arrowhead
|
|
32027
|
+
* controls all resolve to values consumed here).
|
|
32028
|
+
*
|
|
32029
|
+
* Pure and framework-agnostic: the `<marker>` element itself is emitted by each
|
|
32030
|
+
* binding's view layer from the {@link MarkerShape} returned here.
|
|
32031
|
+
*/
|
|
32032
|
+
/**
|
|
32033
|
+
* Base `markerWidth`/`markerHeight` (in `strokeWidth` units) for a `med` arrow.
|
|
32034
|
+
* `sm`/`lg` scale relative to this, mirroring PowerPoint's discrete sizes.
|
|
32035
|
+
*/
|
|
32036
|
+
const ARROW_BASE_MARKER_SIZE = 4;
|
|
32037
|
+
const ARROW_SIZE_SCALE = { sm: 0.6, med: 1, lg: 1.5 };
|
|
32038
|
+
/**
|
|
32039
|
+
* Map a `ConnectorArrowType` value to its SVG marker shape, scaling the marker
|
|
32040
|
+
* box by the arrow's width (`@w`) and length (`@len`) size tokens.
|
|
32041
|
+
*
|
|
32042
|
+
* The `<marker>` viewBox stays `0 0 10 10`; the returned {@link MarkerShape}
|
|
32043
|
+
* carries `markerWidth` (length, along the line) and `markerHeight` (width,
|
|
32044
|
+
* perpendicular) so bindings render `sm`/`med`/`lg` arrows at the right size
|
|
32045
|
+
* instead of a single fixed dimension.
|
|
32046
|
+
*
|
|
32047
|
+
* @param type Arrow head shape.
|
|
32048
|
+
* @param arrowWidth `@w` size token (perpendicular thickness). Defaults `med`.
|
|
32049
|
+
* @param arrowLength `@len` size token (length along the line). Defaults `med`.
|
|
32050
|
+
*/
|
|
32051
|
+
function markerPath(type, arrowWidth, arrowLength) {
|
|
32052
|
+
const markerWidth = ARROW_BASE_MARKER_SIZE * (ARROW_SIZE_SCALE[arrowLength ?? 'med'] ?? 1);
|
|
32053
|
+
const markerHeight = ARROW_BASE_MARKER_SIZE * (ARROW_SIZE_SCALE[arrowWidth ?? 'med'] ?? 1);
|
|
32054
|
+
const box = { markerWidth, markerHeight };
|
|
32055
|
+
switch (type) {
|
|
32056
|
+
case 'diamond':
|
|
32057
|
+
return { shape: 'path', d: 'M5 0 L10 5 L5 10 L0 5 Z', ...box };
|
|
32058
|
+
case 'oval':
|
|
32059
|
+
return { shape: 'circle', ...box };
|
|
32060
|
+
case 'stealth':
|
|
32061
|
+
return { shape: 'path', d: 'M0 0 L10 5 L0 10 L3 5 Z', ...box };
|
|
32062
|
+
// triangle / arrow / fallback
|
|
32063
|
+
default:
|
|
32064
|
+
return { shape: 'path', d: 'M0 0 L10 5 L0 10 Z', ...box };
|
|
32065
|
+
}
|
|
32066
|
+
}
|
|
32067
|
+
/** Normalise a raw arrow type value: coerce `"none"` / `undefined` to `undefined`. */
|
|
32068
|
+
function normalizeArrow(a) {
|
|
32069
|
+
return a && a !== 'none' ? a : undefined;
|
|
32070
|
+
}
|
|
32071
|
+
|
|
31908
32072
|
/**
|
|
31909
32073
|
* Pure, framework-agnostic connector-geometry helpers shared across bindings.
|
|
31910
32074
|
*
|
|
@@ -31994,33 +32158,14 @@ function buildConnectorGeometry(element, zIndex, routing) {
|
|
|
31994
32158
|
endMarker,
|
|
31995
32159
|
startMarkerRef,
|
|
31996
32160
|
endMarkerRef,
|
|
32161
|
+
// A straight connector has no `pathD`, so the hit target falls back to its
|
|
32162
|
+
// endpoints; both forms are a `path`, which keeps the binding templates to
|
|
32163
|
+
// a single node instead of a line/path branch of their own.
|
|
32164
|
+
hitPathD: pathD ?? `M${x1},${y1} L${x2},${y2}`,
|
|
32165
|
+
hitStrokeWidth: connectorHitStrokeWidth(strokeWidth),
|
|
31997
32166
|
wrapperStyle,
|
|
31998
32167
|
};
|
|
31999
32168
|
}
|
|
32000
|
-
/**
|
|
32001
|
-
* Return the SVG `stroke-dasharray` string for a given OOXML stroke dash preset
|
|
32002
|
-
* and width, or `undefined` for solid lines (no attribute needed).
|
|
32003
|
-
*
|
|
32004
|
-
* Produces a distinct pattern per preset (`dash`, `lgDash`, `dashDot`,
|
|
32005
|
-
* `sysDashDotDot`, etc.) rather than collapsing every non-dot preset to a single
|
|
32006
|
-
* `3w/w` approximation, and honours a `custDash` segment list (`a:custDash/a:ds`)
|
|
32007
|
-
* when supplied. This delegates to the same {@link getSvgStrokeDasharray} the
|
|
32008
|
-
* shape/border code uses, so connectors and shape outlines stay in lock-step.
|
|
32009
|
-
*
|
|
32010
|
-
* @param dash Raw `a:ln/@prstDash` token (e.g. `"lgDashDot"`).
|
|
32011
|
-
* @param strokeWidth Resolved stroke width in px.
|
|
32012
|
-
* @param customDashSegments Optional `custDash` segments; when present they take
|
|
32013
|
-
* precedence and are rendered as an explicit pattern.
|
|
32014
|
-
*/
|
|
32015
|
-
function buildDashArray(dash, strokeWidth, customDashSegments) {
|
|
32016
|
-
const segments = customDashSegments && customDashSegments.length > 0
|
|
32017
|
-
? customDashSegments.map((seg) => ({ dash: seg.dash, space: seg.space }))
|
|
32018
|
-
: undefined;
|
|
32019
|
-
// A `custDash` implies the `custom` dash family even when no `@prstDash`
|
|
32020
|
-
// token was authored alongside it.
|
|
32021
|
-
const dashType = segments ? 'custom' : normalizeStrokeDashType(dash);
|
|
32022
|
-
return getSvgStrokeDasharray(dashType, strokeWidth, segments);
|
|
32023
|
-
}
|
|
32024
32169
|
/**
|
|
32025
32170
|
* Normalise a connector's first adjustment value (`adj1`/`adj`) to a 0..1
|
|
32026
32171
|
* fraction that positions the elbow / curve mid-axis. OOXML stores these in
|
|
@@ -32067,46 +32212,6 @@ function buildConnectorPathD(shapeType, x1, y1, x2, y2, bend) {
|
|
|
32067
32212
|
}
|
|
32068
32213
|
return `M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}`;
|
|
32069
32214
|
}
|
|
32070
|
-
/**
|
|
32071
|
-
* Base `markerWidth`/`markerHeight` (in `strokeWidth` units) for a `med` arrow.
|
|
32072
|
-
* `sm`/`lg` scale relative to this, mirroring PowerPoint's discrete sizes and
|
|
32073
|
-
* the React binding's `ARROW_SIZE_SCALE`.
|
|
32074
|
-
*/
|
|
32075
|
-
const ARROW_BASE_MARKER_SIZE = 4;
|
|
32076
|
-
const ARROW_SIZE_SCALE = { sm: 0.6, med: 1, lg: 1.5 };
|
|
32077
|
-
/**
|
|
32078
|
-
* Map a `ConnectorArrowType` value to its SVG marker shape, scaling the marker
|
|
32079
|
-
* box by the arrow's width (`@w`) and length (`@len`) size tokens.
|
|
32080
|
-
*
|
|
32081
|
-
* The `<marker>` viewBox stays `0 0 10 10`; the returned {@link MarkerShape}
|
|
32082
|
-
* carries `markerWidth` (length, along the line) and `markerHeight` (width,
|
|
32083
|
-
* perpendicular) so bindings render `sm`/`med`/`lg` arrows at the right size
|
|
32084
|
-
* instead of a single fixed dimension.
|
|
32085
|
-
*
|
|
32086
|
-
* @param type Arrow head shape.
|
|
32087
|
-
* @param arrowWidth `@w` size token (perpendicular thickness). Defaults `med`.
|
|
32088
|
-
* @param arrowLength `@len` size token (length along the line). Defaults `med`.
|
|
32089
|
-
*/
|
|
32090
|
-
function markerPath(type, arrowWidth, arrowLength) {
|
|
32091
|
-
const markerWidth = ARROW_BASE_MARKER_SIZE * (ARROW_SIZE_SCALE[arrowLength ?? 'med'] ?? 1);
|
|
32092
|
-
const markerHeight = ARROW_BASE_MARKER_SIZE * (ARROW_SIZE_SCALE[arrowWidth ?? 'med'] ?? 1);
|
|
32093
|
-
const box = { markerWidth, markerHeight };
|
|
32094
|
-
switch (type) {
|
|
32095
|
-
case 'diamond':
|
|
32096
|
-
return { shape: 'path', d: 'M5 0 L10 5 L5 10 L0 5 Z', ...box };
|
|
32097
|
-
case 'oval':
|
|
32098
|
-
return { shape: 'circle', ...box };
|
|
32099
|
-
case 'stealth':
|
|
32100
|
-
return { shape: 'path', d: 'M0 0 L10 5 L0 10 L3 5 Z', ...box };
|
|
32101
|
-
// triangle / arrow / fallback
|
|
32102
|
-
default:
|
|
32103
|
-
return { shape: 'path', d: 'M0 0 L10 5 L0 10 Z', ...box };
|
|
32104
|
-
}
|
|
32105
|
-
}
|
|
32106
|
-
/** Normalise a raw arrow type value: coerce `"none"` / `undefined` → `undefined`. */
|
|
32107
|
-
function normalizeArrow(a) {
|
|
32108
|
-
return a && a !== 'none' ? a : undefined;
|
|
32109
|
-
}
|
|
32110
32215
|
/**
|
|
32111
32216
|
* Build the inline `style` string for the connector wrapper `<div>`.
|
|
32112
32217
|
* Position, size, z-index, rotation, opacity, and visibility.
|
|
@@ -40864,25 +40969,21 @@ function mobileSlideCounter(currentIndex, total) {
|
|
|
40864
40969
|
}
|
|
40865
40970
|
return `${currentIndex + 1} / ${total}`;
|
|
40866
40971
|
}
|
|
40867
|
-
|
|
40868
|
-
|
|
40869
|
-
|
|
40870
|
-
|
|
40871
|
-
|
|
40872
|
-
|
|
40873
|
-
|
|
40874
|
-
|
|
40875
|
-
|
|
40876
|
-
|
|
40877
|
-
*/
|
|
40878
|
-
function isLastSlide(currentIndex, total) {
|
|
40879
|
-
return currentIndex >= total - 1;
|
|
40880
|
-
}
|
|
40972
|
+
// The phone layout deliberately owns NO first/last predicates of its own.
|
|
40973
|
+
//
|
|
40974
|
+
// It used to: an `isFirstSlide` / `isLastSlide` pair lived here, and all three
|
|
40975
|
+
// phone consoles wired Next's `disabled` to `isLastSlide`. The desktop console
|
|
40976
|
+
// answers the same question with `presenterNextDisabled` in `presenter-chrome`,
|
|
40977
|
+
// which is always false because PowerPoint advances from the last slide to the
|
|
40978
|
+
// end-of-show screen and then out of the show. So the same deck stranded a
|
|
40979
|
+
// presenter on a phone and let them finish on a laptop. Both consoles now read
|
|
40980
|
+
// `presenterPrevDisabled` / `presenterNextDisabled` from `presenter-chrome`, and
|
|
40981
|
+
// there is no near-miss duplicate here for a fourth port to reach for.
|
|
40881
40982
|
// ---------------------------------------------------------------------------
|
|
40882
40983
|
// Elapsed-time formatting
|
|
40883
40984
|
// ---------------------------------------------------------------------------
|
|
40884
40985
|
/** Zero-pad a non-negative integer to at least two digits. */
|
|
40885
|
-
function pad2
|
|
40986
|
+
function pad2(value) {
|
|
40886
40987
|
return String(value).padStart(2, '0');
|
|
40887
40988
|
}
|
|
40888
40989
|
/**
|
|
@@ -40910,9 +41011,9 @@ function formatMobileElapsed(elapsedMs) {
|
|
|
40910
41011
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
40911
41012
|
const seconds = totalSeconds % 60;
|
|
40912
41013
|
if (hours > 0) {
|
|
40913
|
-
return `${pad2
|
|
41014
|
+
return `${pad2(hours)}:${pad2(minutes)}:${pad2(seconds)}`;
|
|
40914
41015
|
}
|
|
40915
|
-
return `${pad2
|
|
41016
|
+
return `${pad2(minutes)}:${pad2(seconds)}`;
|
|
40916
41017
|
}
|
|
40917
41018
|
|
|
40918
41019
|
/**
|
|
@@ -41382,7 +41483,7 @@ function formatTime(date) {
|
|
|
41382
41483
|
* Format a millisecond duration as `MM:SS`, or `HH:MM:SS` once the elapsed time
|
|
41383
41484
|
* reaches one hour.
|
|
41384
41485
|
*/
|
|
41385
|
-
function formatElapsed
|
|
41486
|
+
function formatElapsed(elapsedMs) {
|
|
41386
41487
|
const totalSeconds = Math.floor(elapsedMs / 1000);
|
|
41387
41488
|
const hours = Math.floor(totalSeconds / 3600);
|
|
41388
41489
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
@@ -42560,6 +42661,414 @@ function presentToolbarStyleAttr() {
|
|
|
42560
42661
|
.join(';');
|
|
42561
42662
|
}
|
|
42562
42663
|
|
|
42664
|
+
/**
|
|
42665
|
+
* The presenter view (PowerPoint's "presenter console"), described once for all
|
|
42666
|
+
* five bindings.
|
|
42667
|
+
*
|
|
42668
|
+
* `presenter-view.ts` already shares the presenter console's ARITHMETIC (elapsed
|
|
42669
|
+
* formatting, notes font-size clamping, rich-notes -> span spec) and
|
|
42670
|
+
* `presenter-console.ts` its STATE helpers (timer, zoom, pointer, ink). What was
|
|
42671
|
+
* never shared is the console's CONTENT, and that is what drifted, in exactly
|
|
42672
|
+
* the way `present-chrome.ts` documents for the show toolbar:
|
|
42673
|
+
*
|
|
42674
|
+
* - React ships a 16-slot strip whose accessible names are hard-coded English
|
|
42675
|
+
* `title` attributes, so the console is untranslatable in every locale.
|
|
42676
|
+
* - Vue renders its strip ONLY in the empty-deck branch, so with a real deck
|
|
42677
|
+
* the console has no timer, zoom, annotation, blackout, captions or end
|
|
42678
|
+
* control at all.
|
|
42679
|
+
* - Angular re-labels the same strip in a component with no `translate` pipe,
|
|
42680
|
+
* orders zoom `-` before `+` (React orders `+` first), and calls reset-zoom
|
|
42681
|
+
* "Fit".
|
|
42682
|
+
* - Vanilla has no presenter view whatsoever: `mountPresenterConsole` lays a
|
|
42683
|
+
* button strip over the live show, with no current slide, next-slide
|
|
42684
|
+
* preview, notes, clock or timer.
|
|
42685
|
+
* - Svelte drops the timer progress bar, renders notes as plain text (losing
|
|
42686
|
+
* every `notesSegments` run style) and clamps the notes font size to its own
|
|
42687
|
+
* 12..36 instead of the shared 10..32.
|
|
42688
|
+
*
|
|
42689
|
+
* So the inventory, the order, the label KEYS and the measurements live here,
|
|
42690
|
+
* and every binding derives its console from these constants:
|
|
42691
|
+
*
|
|
42692
|
+
* - React, Vue and Angular apply {@link PRESENTER_CONSOLE_CLASSES} (Tailwind).
|
|
42693
|
+
* - Vanilla interpolates {@link PRESENTER_LAYOUT_METRICS} into its CSS-in-TS.
|
|
42694
|
+
* - Svelte reads {@link presenterConsoleCssVars} off an inline `style`
|
|
42695
|
+
* attribute, because its scoped `<style>` is compiled and cannot see a
|
|
42696
|
+
* TypeScript value.
|
|
42697
|
+
*
|
|
42698
|
+
* `presenter-chrome.test.ts` asserts the Tailwind tokens still encode exactly
|
|
42699
|
+
* the numbers here, which is what stops the two representations drifting.
|
|
42700
|
+
*
|
|
42701
|
+
* @module render/presenter-chrome
|
|
42702
|
+
*/
|
|
42703
|
+
/**
|
|
42704
|
+
* The presenter console strip, in order.
|
|
42705
|
+
*
|
|
42706
|
+
* Order and ids follow React, which is the binding the parity specs measure
|
|
42707
|
+
* against. The label KEYS are new: React's strings were hard-coded English, so
|
|
42708
|
+
* adopting a key per slot is what makes the console translatable at all. Where
|
|
42709
|
+
* an existing key already carried the exact English React rendered, it is
|
|
42710
|
+
* reused rather than duplicated (`pptx.presentation.pen` and friends), because
|
|
42711
|
+
* a near-miss duplicate is precisely how `pptx.presenter.elapsed` and
|
|
42712
|
+
* `pptx.mpresenter.elapsed` came to coexist.
|
|
42713
|
+
*/
|
|
42714
|
+
const PRESENTER_CONSOLE_CONTROLS = [
|
|
42715
|
+
{
|
|
42716
|
+
id: 'timer-toggle',
|
|
42717
|
+
kind: 'button',
|
|
42718
|
+
labelKey: 'pptx.presenter.toggleTimer',
|
|
42719
|
+
icon: 'circle-pause',
|
|
42720
|
+
activeIcon: 'circle-play',
|
|
42721
|
+
},
|
|
42722
|
+
{ id: 'timer-reset', kind: 'button', labelKey: 'pptx.presenter.resetTimer', icon: 'rotate-ccw' },
|
|
42723
|
+
{ id: 'divider-timer', kind: 'divider' },
|
|
42724
|
+
{
|
|
42725
|
+
id: 'all-slides',
|
|
42726
|
+
kind: 'button',
|
|
42727
|
+
labelKey: 'pptx.presenter.seeAllSlides',
|
|
42728
|
+
icon: 'grid-2x2',
|
|
42729
|
+
},
|
|
42730
|
+
{ id: 'zoom-in', kind: 'button', labelKey: 'pptx.presenter.zoomIn', icon: 'zoom-in' },
|
|
42731
|
+
{ id: 'zoom-out', kind: 'button', labelKey: 'pptx.presenter.zoomOut', icon: 'zoom-out' },
|
|
42732
|
+
{ id: 'zoom-reset', kind: 'button', labelKey: 'pptx.presenter.resetZoom', icon: 'scan' },
|
|
42733
|
+
{ id: 'divider-zoom', kind: 'divider' },
|
|
42734
|
+
{
|
|
42735
|
+
id: 'laser',
|
|
42736
|
+
kind: 'toggle',
|
|
42737
|
+
labelKey: 'pptx.presentation.laserPointer',
|
|
42738
|
+
icon: 'mouse-pointer-2',
|
|
42739
|
+
},
|
|
42740
|
+
{ id: 'pen', kind: 'toggle', labelKey: 'pptx.presentation.pen', icon: 'pen-tool' },
|
|
42741
|
+
{
|
|
42742
|
+
id: 'highlighter',
|
|
42743
|
+
kind: 'toggle',
|
|
42744
|
+
labelKey: 'pptx.presentation.highlighter',
|
|
42745
|
+
icon: 'highlighter',
|
|
42746
|
+
},
|
|
42747
|
+
{ id: 'eraser', kind: 'toggle', labelKey: 'pptx.presentation.eraser', icon: 'eraser' },
|
|
42748
|
+
{ id: 'divider-tools', kind: 'divider' },
|
|
42749
|
+
{ id: 'blackout-black', kind: 'toggle', labelKey: 'pptx.presenter.blackScreen', glyph: 'B' },
|
|
42750
|
+
{ id: 'blackout-white', kind: 'toggle', labelKey: 'pptx.presenter.whiteScreen', glyph: 'W' },
|
|
42751
|
+
{
|
|
42752
|
+
id: 'captions',
|
|
42753
|
+
kind: 'toggle',
|
|
42754
|
+
labelKey: 'pptx.slideShow.subtitlesTooltip',
|
|
42755
|
+
icon: 'captions',
|
|
42756
|
+
},
|
|
42757
|
+
{ id: 'spacer', kind: 'spacer' },
|
|
42758
|
+
{
|
|
42759
|
+
id: 'audience',
|
|
42760
|
+
kind: 'toggle',
|
|
42761
|
+
labelKey: 'pptx.presenter.openAudienceWindow',
|
|
42762
|
+
activeLabelKey: 'pptx.presenter.closeAudienceWindow',
|
|
42763
|
+
icon: 'monitor',
|
|
42764
|
+
activeIcon: 'monitor-off',
|
|
42765
|
+
},
|
|
42766
|
+
{
|
|
42767
|
+
id: 'swap-displays',
|
|
42768
|
+
kind: 'button',
|
|
42769
|
+
labelKey: 'pptx.presenter.swapDisplays',
|
|
42770
|
+
icon: 'arrow-left-right',
|
|
42771
|
+
},
|
|
42772
|
+
{ id: 'end', kind: 'button', labelKey: 'pptx.presenter.endPresentation', icon: 'x' },
|
|
42773
|
+
];
|
|
42774
|
+
/** The strip's control ids in render order, for tests and parity specs. */
|
|
42775
|
+
const PRESENTER_CONSOLE_ORDER = PRESENTER_CONSOLE_CONTROLS.map((control) => control.id);
|
|
42776
|
+
/**
|
|
42777
|
+
* The strip's accessible-name i18n keys, in order, skipping the slots that have
|
|
42778
|
+
* none. A parity spec resolves these through the dictionary rather than
|
|
42779
|
+
* hard-coding English, so the inventory survives a translation change.
|
|
42780
|
+
*/
|
|
42781
|
+
const PRESENTER_CONSOLE_LABEL_KEYS = PRESENTER_CONSOLE_CONTROLS.flatMap((control) => (control.labelKey === undefined ? [] : [control.labelKey]));
|
|
42782
|
+
/**
|
|
42783
|
+
* The rail's navigation and notes controls, in order.
|
|
42784
|
+
*
|
|
42785
|
+
* `next` is deliberately absent from any "disabled on the last slide" rule; see
|
|
42786
|
+
* {@link presenterNextDisabled}.
|
|
42787
|
+
*/
|
|
42788
|
+
const PRESENTER_RAIL_CONTROLS = [
|
|
42789
|
+
{ id: 'prev', labelKey: 'pptx.presenter.prev', icon: 'chevron-left' },
|
|
42790
|
+
{ id: 'next', labelKey: 'pptx.presenter.next', icon: 'chevron-right' },
|
|
42791
|
+
{ id: 'notes-font-decrease', labelKey: 'pptx.presenter.decreaseFontSize', icon: 'minus' },
|
|
42792
|
+
{ id: 'notes-font-increase', labelKey: 'pptx.presenter.increaseFontSize', icon: 'plus' },
|
|
42793
|
+
];
|
|
42794
|
+
/** Static headings and read-only readouts in the rail, keyed for translation. */
|
|
42795
|
+
const PRESENTER_RAIL_LABEL_KEYS = {
|
|
42796
|
+
currentTime: 'pptx.presenter.currentTime',
|
|
42797
|
+
elapsed: 'pptx.presenter.elapsed',
|
|
42798
|
+
nextSlidePreview: 'pptx.presenter.nextSlidePreview',
|
|
42799
|
+
endOfPresentation: 'pptx.presenter.endOfPresentation',
|
|
42800
|
+
speakerNotes: 'pptx.presenter.speakerNotes',
|
|
42801
|
+
noNotes: 'pptx.presenter.noNotes',
|
|
42802
|
+
slideLabel: 'pptx.presenter.slideLabel',
|
|
42803
|
+
timerProgress: 'pptx.presenter.timerProgress',
|
|
42804
|
+
noSlides: 'pptx.presenter.noSlides',
|
|
42805
|
+
};
|
|
42806
|
+
/** Headings and controls of the "all slides" navigator overlay. */
|
|
42807
|
+
const PRESENTER_NAVIGATOR_LABEL_KEYS = {
|
|
42808
|
+
title: 'pptx.presenter.slideNavigator',
|
|
42809
|
+
subtitle: 'pptx.presenter.seeAllSlides',
|
|
42810
|
+
close: 'pptx.presenter.closeNavigator',
|
|
42811
|
+
};
|
|
42812
|
+
/**
|
|
42813
|
+
* Whether the rail's Next button should be disabled.
|
|
42814
|
+
*
|
|
42815
|
+
* Always `false`, and it is a function rather than a constant so the rule has
|
|
42816
|
+
* one place to be read and cited. PowerPoint's console advances from the last
|
|
42817
|
+
* slide to the end-of-show screen and then out of the show. Vue, Angular and
|
|
42818
|
+
* Svelte each independently added `disabled={current >= slides.length - 1}`,
|
|
42819
|
+
* which strands the presenter on the final slide with no way to finish, so the
|
|
42820
|
+
* audience display never closes either. React's `PresenterNotesRail` carries a
|
|
42821
|
+
* comment saying exactly this; the comment was not enough to stop three ports
|
|
42822
|
+
* making the same call, so the rule is now code.
|
|
42823
|
+
*/
|
|
42824
|
+
function presenterNextDisabled() {
|
|
42825
|
+
return false;
|
|
42826
|
+
}
|
|
42827
|
+
/**
|
|
42828
|
+
* Whether the rail's Previous button should be disabled: only on the first
|
|
42829
|
+
* slide, where there is genuinely nowhere to go back to.
|
|
42830
|
+
*/
|
|
42831
|
+
function presenterPrevDisabled(currentIndex) {
|
|
42832
|
+
return currentIndex <= 0;
|
|
42833
|
+
}
|
|
42834
|
+
/**
|
|
42835
|
+
* How much elapsed time one fill of the console's progress bar represents.
|
|
42836
|
+
*
|
|
42837
|
+
* Five minutes, the interval PowerPoint's own console paces a talk in. It was
|
|
42838
|
+
* inlined in React, re-derived in Vue and given a helper of its own in Angular,
|
|
42839
|
+
* while Vanilla and Svelte had no bar at all.
|
|
42840
|
+
*/
|
|
42841
|
+
const PRESENTER_TIMER_SEGMENT_MS = 5 * 60 * 1000;
|
|
42842
|
+
/**
|
|
42843
|
+
* Split an elapsed duration into the console's progress-bar reading.
|
|
42844
|
+
*
|
|
42845
|
+
* Negative input is clamped: a snapshot restored from a peer can arrive with a
|
|
42846
|
+
* start time in the future, and a negative `aria-valuenow` is invalid ARIA.
|
|
42847
|
+
*/
|
|
42848
|
+
function presenterTimerProgress(elapsedMs) {
|
|
42849
|
+
const elapsed = Math.max(0, elapsedMs);
|
|
42850
|
+
return {
|
|
42851
|
+
percent: Math.min(100, ((elapsed % PRESENTER_TIMER_SEGMENT_MS) / PRESENTER_TIMER_SEGMENT_MS) * 100),
|
|
42852
|
+
segment: Math.floor(elapsed / PRESENTER_TIMER_SEGMENT_MS),
|
|
42853
|
+
};
|
|
42854
|
+
}
|
|
42855
|
+
|
|
42856
|
+
/**
|
|
42857
|
+
* `presenter-chrome-metrics` - the presenter console's measurements, in the two
|
|
42858
|
+
* representations the five bindings can consume.
|
|
42859
|
+
*
|
|
42860
|
+
* Split out of `presenter-chrome.ts` purely to keep both files inside the
|
|
42861
|
+
* repo's 300-line ceiling; the inventory lives there, the geometry lives here,
|
|
42862
|
+
* and `presenter-chrome.test.ts` asserts the Tailwind strings below still
|
|
42863
|
+
* encode the numbers in {@link PRESENTER_LAYOUT_METRICS}.
|
|
42864
|
+
*
|
|
42865
|
+
* Every number here was a magic constant in at least three bindings before this
|
|
42866
|
+
* module: the rail was 260..440 wide in React and Vue but 300..460 in Svelte,
|
|
42867
|
+
* the navigator grid used three different track sizes and gaps, and the console
|
|
42868
|
+
* root sat at `z-index` 50, 100 and 120 depending on which file you opened.
|
|
42869
|
+
*
|
|
42870
|
+
* @module render/presenter-chrome-metrics
|
|
42871
|
+
*/
|
|
42872
|
+
/** Presenter-console measurements, in CSS pixels unless the name says otherwise. */
|
|
42873
|
+
const PRESENTER_LAYOUT_METRICS = {
|
|
42874
|
+
/**
|
|
42875
|
+
* Flex growth of the current-slide pane against the rail (`flex-[7]` /
|
|
42876
|
+
* `flex-[3]`), i.e. PowerPoint's roughly 70/30 console split.
|
|
42877
|
+
*/
|
|
42878
|
+
mainFlex: 7,
|
|
42879
|
+
railFlex: 3,
|
|
42880
|
+
/** Rail width bounds (`min-w-[260px] max-w-[440px]`). */
|
|
42881
|
+
railMinWidth: 260,
|
|
42882
|
+
railMaxWidth: 440,
|
|
42883
|
+
/** Padding around the current-slide pane (`p-6`). */
|
|
42884
|
+
mainPadding: 24,
|
|
42885
|
+
/** Stacking order of the console over the show stage (`z-50`). */
|
|
42886
|
+
zIndex: 50,
|
|
42887
|
+
/** Stacking order of the "all slides" navigator over the console (`z-[120]`). */
|
|
42888
|
+
navigatorZIndex: 120,
|
|
42889
|
+
/** Console strip control edge length (`h-9 min-w-9`). */
|
|
42890
|
+
controlSize: 36,
|
|
42891
|
+
/** Icon edge length inside a strip control. */
|
|
42892
|
+
controlIconSize: 16,
|
|
42893
|
+
/** Flex gap between strip children (`gap-1`). */
|
|
42894
|
+
stripGap: 4,
|
|
42895
|
+
/** Strip padding (`px-3 py-2`). */
|
|
42896
|
+
stripPaddingX: 12,
|
|
42897
|
+
stripPaddingY: 8,
|
|
42898
|
+
/** Control corner radius (`rounded-md`). */
|
|
42899
|
+
controlRadius: 6,
|
|
42900
|
+
/** Divider width / height / margin (`w-px h-6 mx-1`). */
|
|
42901
|
+
dividerWidth: 1,
|
|
42902
|
+
dividerHeight: 24,
|
|
42903
|
+
dividerMarginX: 4,
|
|
42904
|
+
/** Timer progress bar height (`h-1.5`). */
|
|
42905
|
+
progressHeight: 6,
|
|
42906
|
+
/** Next-slide preview target width, before aspect-ratio scaling. */
|
|
42907
|
+
nextPreviewWidth: 240,
|
|
42908
|
+
/** Navigator grid track minimum and gap (`minmax(220px,1fr)`, `gap-5`). */
|
|
42909
|
+
navigatorTrackMin: 220,
|
|
42910
|
+
navigatorGap: 20,
|
|
42911
|
+
/** Navigator tile preview width. */
|
|
42912
|
+
navigatorTileWidth: 200,
|
|
42913
|
+
/** Opacity of a hidden slide's navigator tile: dimmed, never omitted. */
|
|
42914
|
+
hiddenSlideOpacity: 0.45,
|
|
42915
|
+
};
|
|
42916
|
+
/**
|
|
42917
|
+
* Tailwind tokens for the presenter console, applied by React, Vue and Angular.
|
|
42918
|
+
*
|
|
42919
|
+
* Whole class strings rather than per-call-site assembly, for the reason
|
|
42920
|
+
* `present-chrome.ts` gives: three bindings hand-writing `h-9 min-w-9 rounded-md
|
|
42921
|
+
* ...` is how one of them ended up with a differently sized strip.
|
|
42922
|
+
*/
|
|
42923
|
+
const PRESENTER_CONSOLE_CLASSES = {
|
|
42924
|
+
/** The console root, laid over the show stage. */
|
|
42925
|
+
root: 'absolute inset-0 z-50 flex flex-col bg-card text-foreground',
|
|
42926
|
+
/** The control strip across the top. */
|
|
42927
|
+
strip: 'flex flex-wrap items-center gap-1 border-b border-border bg-card px-3 py-2',
|
|
42928
|
+
/** A strip control, inactive. */
|
|
42929
|
+
control: 'inline-flex h-9 min-w-9 items-center justify-center gap-2 rounded-md px-2 text-xs transition-colors bg-muted text-foreground hover:bg-accent',
|
|
42930
|
+
/** A strip control, active. */
|
|
42931
|
+
controlActive: 'inline-flex h-9 min-w-9 items-center justify-center gap-2 rounded-md px-2 text-xs transition-colors bg-primary text-primary-foreground',
|
|
42932
|
+
/** Vertical hairline between strip groups. */
|
|
42933
|
+
divider: 'mx-1 h-6 w-px bg-border',
|
|
42934
|
+
/** Flexible gap pushing the trailing group right. */
|
|
42935
|
+
spacer: 'flex-1',
|
|
42936
|
+
/** The body row: current-slide pane plus rail. */
|
|
42937
|
+
body: 'flex flex-1 min-h-0',
|
|
42938
|
+
/** The current-slide pane. */
|
|
42939
|
+
main: 'relative flex-[7] flex flex-col items-center justify-center bg-black p-6 min-w-0 overflow-hidden',
|
|
42940
|
+
/** The right-hand rail. */
|
|
42941
|
+
rail: 'flex flex-[3] min-w-[260px] max-w-[440px] flex-col border-l border-border bg-background',
|
|
42942
|
+
/** Rail section heading (Current Time / Next Slide / Speaker Notes). */
|
|
42943
|
+
railHeading: 'text-[10px] uppercase tracking-wider text-muted-foreground',
|
|
42944
|
+
/** Timer progress bar track. */
|
|
42945
|
+
progressTrack: 'h-1.5 w-full bg-muted/60 flex-shrink-0',
|
|
42946
|
+
/** Timer progress bar fill. */
|
|
42947
|
+
progressFill: 'h-full bg-primary transition-[width] duration-1000 ease-linear',
|
|
42948
|
+
/** The "all slides" navigator overlay. */
|
|
42949
|
+
navigator: 'absolute inset-0 z-[120] overflow-auto bg-card p-6',
|
|
42950
|
+
/** The navigator's tile grid. */
|
|
42951
|
+
navigatorGrid: 'grid gap-5 [grid-template-columns:repeat(auto-fill,minmax(220px,1fr))]',
|
|
42952
|
+
};
|
|
42953
|
+
/**
|
|
42954
|
+
* The console metrics as CSS custom properties, for the two bindings that
|
|
42955
|
+
* cannot read a Tailwind class (Vanilla's CSS-in-TS, Svelte's scoped style).
|
|
42956
|
+
*/
|
|
42957
|
+
function presenterConsoleCssVars() {
|
|
42958
|
+
const m = PRESENTER_LAYOUT_METRICS;
|
|
42959
|
+
return {
|
|
42960
|
+
'--pptx-pv-main-flex': String(m.mainFlex),
|
|
42961
|
+
'--pptx-pv-rail-flex': String(m.railFlex),
|
|
42962
|
+
'--pptx-pv-rail-min': `${String(m.railMinWidth)}px`,
|
|
42963
|
+
'--pptx-pv-rail-max': `${String(m.railMaxWidth)}px`,
|
|
42964
|
+
'--pptx-pv-main-pad': `${String(m.mainPadding)}px`,
|
|
42965
|
+
'--pptx-pv-z': String(m.zIndex),
|
|
42966
|
+
'--pptx-pv-nav-z': String(m.navigatorZIndex),
|
|
42967
|
+
'--pptx-pv-control': `${String(m.controlSize)}px`,
|
|
42968
|
+
'--pptx-pv-control-icon': `${String(m.controlIconSize)}px`,
|
|
42969
|
+
'--pptx-pv-strip-gap': `${String(m.stripGap)}px`,
|
|
42970
|
+
'--pptx-pv-strip-pad-x': `${String(m.stripPaddingX)}px`,
|
|
42971
|
+
'--pptx-pv-strip-pad-y': `${String(m.stripPaddingY)}px`,
|
|
42972
|
+
'--pptx-pv-control-radius': `${String(m.controlRadius)}px`,
|
|
42973
|
+
'--pptx-pv-divider-w': `${String(m.dividerWidth)}px`,
|
|
42974
|
+
'--pptx-pv-divider-h': `${String(m.dividerHeight)}px`,
|
|
42975
|
+
'--pptx-pv-divider-mx': `${String(m.dividerMarginX)}px`,
|
|
42976
|
+
'--pptx-pv-progress-h': `${String(m.progressHeight)}px`,
|
|
42977
|
+
'--pptx-pv-next-preview-w': `${String(m.nextPreviewWidth)}px`,
|
|
42978
|
+
'--pptx-pv-nav-track-min': `${String(m.navigatorTrackMin)}px`,
|
|
42979
|
+
'--pptx-pv-nav-gap': `${String(m.navigatorGap)}px`,
|
|
42980
|
+
'--pptx-pv-nav-tile-w': `${String(m.navigatorTileWidth)}px`,
|
|
42981
|
+
'--pptx-pv-hidden-opacity': String(m.hiddenSlideOpacity),
|
|
42982
|
+
};
|
|
42983
|
+
}
|
|
42984
|
+
/** {@link presenterConsoleCssVars} flattened into an inline `style` attribute. */
|
|
42985
|
+
function presenterConsoleStyleAttr() {
|
|
42986
|
+
return Object.entries(presenterConsoleCssVars())
|
|
42987
|
+
.map(([name, value]) => `${name}:${value}`)
|
|
42988
|
+
.join(';');
|
|
42989
|
+
}
|
|
42990
|
+
|
|
42991
|
+
/**
|
|
42992
|
+
* `presenter-show-lifecycle` - keeping a slide show alive across the fullscreen
|
|
42993
|
+
* bounce that opening the audience display causes.
|
|
42994
|
+
*
|
|
42995
|
+
* WHY this exists at all. A running show holds the Fullscreen API on the
|
|
42996
|
+
* presenter's own screen. Opening the audience display is a `window.open` with
|
|
42997
|
+
* `popup=yes`, and every engine drops the opener out of fullscreen when a popup
|
|
42998
|
+
* takes focus. The `fullscreenchange` that announces it is dispatched on a
|
|
42999
|
+
* later task, which puts a binding in a bind:
|
|
43000
|
+
*
|
|
43001
|
+
* - Reading its own "am I presenting" state right after `window.open` reads a
|
|
43002
|
+
* value the pending event has not updated yet, so the code concludes the
|
|
43003
|
+
* show is still running and does not re-assert it. The event then lands,
|
|
43004
|
+
* the generic "the user left fullscreen, so end the show" handler fires,
|
|
43005
|
+
* and the presenter's deck collapses back to the editor the instant they
|
|
43006
|
+
* ask for presenter view. That is exactly the Vanilla defect: the console
|
|
43007
|
+
* mounts correctly and the show underneath it is torn down.
|
|
43008
|
+
* - Reading `document.fullscreenElement` instead is no better. It is
|
|
43009
|
+
* authoritative but it is sampled at a moment when the browser may or may
|
|
43010
|
+
* not have released fullscreen yet, so the answer is a coin toss.
|
|
43011
|
+
*
|
|
43012
|
+
* Neither reading is wrong; the mistake is asking a state question at all. The
|
|
43013
|
+
* only thing that distinguishes "the popup stole fullscreen" from "the
|
|
43014
|
+
* presenter pressed Escape" is INTENT, and intent is known at the call site
|
|
43015
|
+
* that opened the popup. So the opener arms a one-shot latch here and the
|
|
43016
|
+
* fullscreen handler asks this module what the exit meant.
|
|
43017
|
+
*
|
|
43018
|
+
* React already had a private version of this (`switchingToPresenterRef` in
|
|
43019
|
+
* `usePresentationMode`), which is why React alone never lost its show. This
|
|
43020
|
+
* module is that latch, made shared, time-bounded and testable, so all five
|
|
43021
|
+
* bindings answer the question the same way.
|
|
43022
|
+
*
|
|
43023
|
+
* DOM-free by design: it holds no window, registers no listener, and only ever
|
|
43024
|
+
* answers a question. Each binding keeps its own fullscreen plumbing.
|
|
43025
|
+
*
|
|
43026
|
+
* @module render/presenter-show-lifecycle
|
|
43027
|
+
*/
|
|
43028
|
+
/**
|
|
43029
|
+
* How long after opening the audience display a fullscreen exit is still
|
|
43030
|
+
* attributed to the popup rather than to the presenter.
|
|
43031
|
+
*
|
|
43032
|
+
* The latch is one-shot, so this bound only matters when the popup never
|
|
43033
|
+
* triggers a bounce at all (a popup blocker, or an engine that keeps the opener
|
|
43034
|
+
* fullscreen). Without it the latch would sit armed forever and silently
|
|
43035
|
+
* swallow the presenter's next real Escape. A second is far longer than the
|
|
43036
|
+
* event needs and far shorter than any deliberate follow-up action.
|
|
43037
|
+
*/
|
|
43038
|
+
const AUDIENCE_FULLSCREEN_BOUNCE_MS = 1000;
|
|
43039
|
+
/**
|
|
43040
|
+
* Create a {@link PresenterShowGuard}.
|
|
43041
|
+
*
|
|
43042
|
+
* @param options.graceMs - Override {@link AUDIENCE_FULLSCREEN_BOUNCE_MS}; tests
|
|
43043
|
+
* pass a tiny value to prove the latch expires.
|
|
43044
|
+
*/
|
|
43045
|
+
function createPresenterShowGuard(options) {
|
|
43046
|
+
const graceMs = options?.graceMs ?? AUDIENCE_FULLSCREEN_BOUNCE_MS;
|
|
43047
|
+
let armedAt;
|
|
43048
|
+
const stillArmed = (now) => armedAt !== undefined && now - armedAt >= 0 && now - armedAt <= graceMs;
|
|
43049
|
+
return {
|
|
43050
|
+
expectAudienceBounce(now = Date.now()) {
|
|
43051
|
+
armedAt = now;
|
|
43052
|
+
},
|
|
43053
|
+
classifyFullscreenExit(now = Date.now()) {
|
|
43054
|
+
if (!stillArmed(now)) {
|
|
43055
|
+
armedAt = undefined;
|
|
43056
|
+
return 'end-show';
|
|
43057
|
+
}
|
|
43058
|
+
// One-shot: a popup causes exactly one bounce, and a second exit in the
|
|
43059
|
+
// same window is the presenter reacting to what they now see.
|
|
43060
|
+
armedAt = undefined;
|
|
43061
|
+
return 'restore-show';
|
|
43062
|
+
},
|
|
43063
|
+
isExpectingBounce(now = Date.now()) {
|
|
43064
|
+
return stillArmed(now);
|
|
43065
|
+
},
|
|
43066
|
+
disarm() {
|
|
43067
|
+
armedAt = undefined;
|
|
43068
|
+
},
|
|
43069
|
+
};
|
|
43070
|
+
}
|
|
43071
|
+
|
|
42563
43072
|
/**
|
|
42564
43073
|
* PowerPoint-accurate slide-show keyboard map.
|
|
42565
43074
|
*
|
|
@@ -45902,6 +46411,361 @@ function isElementActionable(element, options = {}) {
|
|
|
45902
46411
|
return element.type === 'zoom' && hasZoomHandler;
|
|
45903
46412
|
}
|
|
45904
46413
|
|
|
46414
|
+
/**
|
|
46415
|
+
* On-canvas affordances for an element that carries a PowerPoint Action Setting.
|
|
46416
|
+
*
|
|
46417
|
+
* PowerPoint's editing view tells the author, without a click, which shapes are
|
|
46418
|
+
* wired up: an action shape gets a marker, and hovering one shows where it goes.
|
|
46419
|
+
* The viewer mirrors that with two affordances:
|
|
46420
|
+
*
|
|
46421
|
+
* - the **action indicator**, a small amber lightning badge pinned to the
|
|
46422
|
+
* element's top-right corner whenever it owns an `a:hlinkClick` (click) or
|
|
46423
|
+
* `a:hlinkHover` (mouse-over) action;
|
|
46424
|
+
* - the **link tooltip**, a popover under the element naming the destination
|
|
46425
|
+
* plus how to follow it.
|
|
46426
|
+
*
|
|
46427
|
+
* Both are AUTHORING chrome, so both are gated on the live editing canvas.
|
|
46428
|
+
* Painting them during a slide show would be wrong twice over: the audience
|
|
46429
|
+
* would see editor furniture, and the badge would sit on top of the very shape
|
|
46430
|
+
* the presenter is trying to click. `presenting` is therefore a hard veto, not
|
|
46431
|
+
* merely the absence of `canInteract`, because the four non-React bindings run
|
|
46432
|
+
* their presentation stage through the same renderer as the editing one.
|
|
46433
|
+
*
|
|
46434
|
+
* Only React drew either of them; the tooltip additionally existed in Vue. That
|
|
46435
|
+
* divergence was also the last residual noise in the cross-binding render
|
|
46436
|
+
* fingerprints, since the badge contributes an `<svg>` and the tooltip
|
|
46437
|
+
* contributes text to an otherwise textless element. The rule and the styling
|
|
46438
|
+
* therefore both live here, so the five bindings cannot drift apart again: a
|
|
46439
|
+
* binding supplies only the markup, never the decision or the look.
|
|
46440
|
+
*
|
|
46441
|
+
* @module render/element-action-affordance
|
|
46442
|
+
*/
|
|
46443
|
+
/** Class on the element box that hosts a link tooltip (drives `:hover`). */
|
|
46444
|
+
const LINK_TOOLTIP_HOST_CLASS = 'pptx-link-host';
|
|
46445
|
+
/** Class on the tooltip's outer positioning box. */
|
|
46446
|
+
const LINK_TOOLTIP_CLASS = 'pptx-link-tooltip';
|
|
46447
|
+
/** Class on the tooltip's bordered panel. */
|
|
46448
|
+
const LINK_TOOLTIP_PANEL_CLASS = 'pptx-link-tooltip-panel';
|
|
46449
|
+
/** Class on the tooltip's destination line. */
|
|
46450
|
+
const LINK_TOOLTIP_LABEL_CLASS = 'pptx-link-tooltip-label';
|
|
46451
|
+
/** Class on the tooltip's "how to follow this" hint line. */
|
|
46452
|
+
const LINK_TOOLTIP_HINT_CLASS = 'pptx-link-tooltip-hint';
|
|
46453
|
+
/** Class on the amber action badge. */
|
|
46454
|
+
const ACTION_INDICATOR_CLASS = 'pptx-action-indicator';
|
|
46455
|
+
/**
|
|
46456
|
+
* `d` of the lightning bolt inside the badge, on a `0 0 24 24` viewBox.
|
|
46457
|
+
*
|
|
46458
|
+
* Shared rather than restated per binding so the glyph cannot drift; it is the
|
|
46459
|
+
* same path React has drawn since the badge was introduced.
|
|
46460
|
+
*/
|
|
46461
|
+
const ACTION_INDICATOR_ICON_PATH = 'M13 2L3 14h9l-1 8 10-12h-9l1-8z';
|
|
46462
|
+
/**
|
|
46463
|
+
* Styling for both affordances, injected once per document by each binding.
|
|
46464
|
+
*
|
|
46465
|
+
* Written as plain CSS against the `--pptx-*` theme tokens (rather than as
|
|
46466
|
+
* Tailwind utilities, which only React and Vue can use) so Angular, Vanilla and
|
|
46467
|
+
* Svelte get the identical look for free, and so a theme override reaches all
|
|
46468
|
+
* five.
|
|
46469
|
+
*
|
|
46470
|
+
* `font-family` is stated explicitly and deliberately. Left to inherit, the
|
|
46471
|
+
* tooltip picks up whatever the host app happens to set, which is how React and
|
|
46472
|
+
* Vue ended up rendering the same tooltip in two different stacks and put 80
|
|
46473
|
+
* spurious entries into the render-parity fingerprints. Pinning it here makes
|
|
46474
|
+
* the affordance's typography a property of the affordance.
|
|
46475
|
+
*/
|
|
46476
|
+
const ACTION_AFFORDANCE_CSS = `
|
|
46477
|
+
.${ACTION_INDICATOR_CLASS} {
|
|
46478
|
+
position: absolute;
|
|
46479
|
+
top: -4px;
|
|
46480
|
+
right: -4px;
|
|
46481
|
+
z-index: 20;
|
|
46482
|
+
display: flex;
|
|
46483
|
+
width: 16px;
|
|
46484
|
+
height: 16px;
|
|
46485
|
+
align-items: center;
|
|
46486
|
+
justify-content: center;
|
|
46487
|
+
border-radius: 9999px;
|
|
46488
|
+
background: #f59e0b;
|
|
46489
|
+
/* Left pointer-interactive on purpose: the badge's native title attribute is
|
|
46490
|
+
the only place the deck's screen tip is readable, and a title on a
|
|
46491
|
+
pointer-transparent node never fires. Clicks still reach the element
|
|
46492
|
+
underneath by bubbling, so nothing is swallowed. */
|
|
46493
|
+
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 10%), 0 1px 2px -1px rgb(0 0 0 / 10%);
|
|
46494
|
+
}
|
|
46495
|
+
.${ACTION_INDICATOR_CLASS} svg {
|
|
46496
|
+
width: 10px;
|
|
46497
|
+
height: 10px;
|
|
46498
|
+
color: #fff;
|
|
46499
|
+
}
|
|
46500
|
+
.${LINK_TOOLTIP_CLASS} {
|
|
46501
|
+
position: absolute;
|
|
46502
|
+
top: 100%;
|
|
46503
|
+
left: 4px;
|
|
46504
|
+
z-index: 9999;
|
|
46505
|
+
max-width: 16rem;
|
|
46506
|
+
margin-top: 4px;
|
|
46507
|
+
opacity: 0;
|
|
46508
|
+
transition: opacity 150ms;
|
|
46509
|
+
pointer-events: none;
|
|
46510
|
+
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
46511
|
+
text-align: left;
|
|
46512
|
+
}
|
|
46513
|
+
.${LINK_TOOLTIP_HOST_CLASS}:hover > .${LINK_TOOLTIP_CLASS} {
|
|
46514
|
+
opacity: 1;
|
|
46515
|
+
}
|
|
46516
|
+
.${LINK_TOOLTIP_PANEL_CLASS} {
|
|
46517
|
+
border: 1px solid var(--pptx-border, #374151);
|
|
46518
|
+
border-radius: 0.25rem;
|
|
46519
|
+
background: var(--pptx-popover, #111827);
|
|
46520
|
+
padding: 6px 10px;
|
|
46521
|
+
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -4px rgb(0 0 0 / 10%);
|
|
46522
|
+
}
|
|
46523
|
+
.${LINK_TOOLTIP_LABEL_CLASS} {
|
|
46524
|
+
overflow: hidden;
|
|
46525
|
+
color: var(--pptx-foreground, #f3f4f6);
|
|
46526
|
+
font-size: 12px;
|
|
46527
|
+
font-weight: 400;
|
|
46528
|
+
font-style: normal;
|
|
46529
|
+
line-height: 16px;
|
|
46530
|
+
letter-spacing: normal;
|
|
46531
|
+
text-decoration: none;
|
|
46532
|
+
text-overflow: ellipsis;
|
|
46533
|
+
text-transform: none;
|
|
46534
|
+
white-space: nowrap;
|
|
46535
|
+
}
|
|
46536
|
+
.${LINK_TOOLTIP_HINT_CLASS} {
|
|
46537
|
+
margin-top: 2px;
|
|
46538
|
+
color: var(--pptx-muted-foreground, #9ca3af);
|
|
46539
|
+
font-size: 10px;
|
|
46540
|
+
font-weight: 400;
|
|
46541
|
+
font-style: normal;
|
|
46542
|
+
line-height: 12px;
|
|
46543
|
+
letter-spacing: normal;
|
|
46544
|
+
text-decoration: none;
|
|
46545
|
+
text-transform: none;
|
|
46546
|
+
}
|
|
46547
|
+
`;
|
|
46548
|
+
/** `id` of the once-per-document `<style>` holding {@link ACTION_AFFORDANCE_CSS}. */
|
|
46549
|
+
const AFFORDANCE_STYLE_ELEMENT_ID = 'pptx-action-affordance-styles';
|
|
46550
|
+
/**
|
|
46551
|
+
* Inject {@link ACTION_AFFORDANCE_CSS} into a document exactly once.
|
|
46552
|
+
*
|
|
46553
|
+
* Every binding calls this from its viewer root rather than shipping the rules
|
|
46554
|
+
* in its own stylesheet, because a per-package copy is precisely how the two
|
|
46555
|
+
* existing implementations drifted. Idempotent, and a no-op under SSR.
|
|
46556
|
+
*/
|
|
46557
|
+
function ensureActionAffordanceStyles(doc) {
|
|
46558
|
+
const target = doc ?? (typeof document === 'undefined' ? undefined : document);
|
|
46559
|
+
if (!target || target.getElementById(AFFORDANCE_STYLE_ELEMENT_ID)) {
|
|
46560
|
+
return;
|
|
46561
|
+
}
|
|
46562
|
+
const style = target.createElement('style');
|
|
46563
|
+
style.id = AFFORDANCE_STYLE_ELEMENT_ID;
|
|
46564
|
+
style.textContent = ACTION_AFFORDANCE_CSS;
|
|
46565
|
+
(target.head ?? target.documentElement).appendChild(style);
|
|
46566
|
+
}
|
|
46567
|
+
/**
|
|
46568
|
+
* Build the label set from a binding's translator.
|
|
46569
|
+
*
|
|
46570
|
+
* The four dictionary keys are named once, here, so a binding cannot quietly
|
|
46571
|
+
* hard-code English (which is how React's badge shipped an untranslated "Has
|
|
46572
|
+
* action" while the key for it already existed).
|
|
46573
|
+
*/
|
|
46574
|
+
function actionAffordanceLabels(translate) {
|
|
46575
|
+
return {
|
|
46576
|
+
hasAction: translate('pptx.element.hasAction'),
|
|
46577
|
+
link: translate('pptx.element.linkFallback'),
|
|
46578
|
+
followLink: translate('pptx.linkTooltip.followLink'),
|
|
46579
|
+
presentationMode: translate('pptx.linkTooltip.presentationMode'),
|
|
46580
|
+
};
|
|
46581
|
+
}
|
|
46582
|
+
/** Nothing to draw; shared so the common case allocates one frozen object. */
|
|
46583
|
+
const NO_AFFORDANCE = Object.freeze({
|
|
46584
|
+
showIndicator: false,
|
|
46585
|
+
indicatorTitle: '',
|
|
46586
|
+
showLinkTooltip: false,
|
|
46587
|
+
linkTooltipLabel: '',
|
|
46588
|
+
linkTooltipHint: '',
|
|
46589
|
+
});
|
|
46590
|
+
/**
|
|
46591
|
+
* Decide which action affordances an element gets, and with what text.
|
|
46592
|
+
*
|
|
46593
|
+
* Kept a single call returning both affordances (rather than two predicates)
|
|
46594
|
+
* because they share the same gate and the same fallback chain, and the one
|
|
46595
|
+
* time they were derived separately per binding they immediately diverged.
|
|
46596
|
+
*/
|
|
46597
|
+
function resolveElementActionAffordance(element, context) {
|
|
46598
|
+
const { canInteract, presenting = false, labels } = context;
|
|
46599
|
+
const click = element.actionClick;
|
|
46600
|
+
const hover = element.actionHover;
|
|
46601
|
+
if (!canInteract || presenting || (!click && !hover)) {
|
|
46602
|
+
return NO_AFFORDANCE;
|
|
46603
|
+
}
|
|
46604
|
+
const hasUrl = Boolean(click?.url);
|
|
46605
|
+
return {
|
|
46606
|
+
showIndicator: true,
|
|
46607
|
+
indicatorTitle: click?.tooltip || hover?.tooltip || labels.hasAction,
|
|
46608
|
+
// The tooltip names a CLICK destination, so a hover-only action gets the
|
|
46609
|
+
// badge but no popover: there is nothing to follow and no key to press.
|
|
46610
|
+
showLinkTooltip: Boolean(click),
|
|
46611
|
+
linkTooltipLabel: click?.tooltip || click?.url || click?.action || labels.link,
|
|
46612
|
+
linkTooltipHint: hasUrl ? labels.followLink : labels.presentationMode,
|
|
46613
|
+
};
|
|
46614
|
+
}
|
|
46615
|
+
|
|
46616
|
+
/**
|
|
46617
|
+
* Paint the on-canvas action affordances (see `element-action-affordance`) at a
|
|
46618
|
+
* rendered stage boundary, for the bindings that cannot paint them inline.
|
|
46619
|
+
*
|
|
46620
|
+
* React renders the badge and the tooltip as JSX children of its element
|
|
46621
|
+
* container, which wraps EVERY element type. The other four bindings do not
|
|
46622
|
+
* wrap: their element renderer dispatches straight to a per-type component
|
|
46623
|
+
* (image, chart, table, media, ole, zoom, ...) whose single root IS the element
|
|
46624
|
+
* node, so there is no shared parent to hang extra children off. Reproducing
|
|
46625
|
+
* the affordance inside all twelve per-type components in each of four bindings
|
|
46626
|
+
* would be forty-odd copies of the same markup, which is precisely the drift
|
|
46627
|
+
* this change exists to remove.
|
|
46628
|
+
*
|
|
46629
|
+
* So the four bindings decorate after render instead, exactly as they already
|
|
46630
|
+
* do for the role / name / `data-pptx-action` half of the element contract
|
|
46631
|
+
* (`applyRenderedElementAccessibility`), and call this alongside it. The pass is
|
|
46632
|
+
* idempotent and re-runs on every slide / element-list change, so a framework
|
|
46633
|
+
* re-render that discards the nodes simply gets them back.
|
|
46634
|
+
*
|
|
46635
|
+
* @module render/element-action-affordance-dom
|
|
46636
|
+
*/
|
|
46637
|
+
/** Marks a node this pass owns, so it can be refreshed or removed cleanly. */
|
|
46638
|
+
const AFFORDANCE_ATTRIBUTE = 'data-pptx-affordance';
|
|
46639
|
+
const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
46640
|
+
/**
|
|
46641
|
+
* Element types this pass leaves alone.
|
|
46642
|
+
*
|
|
46643
|
+
* A connector's rendered node is its pointer-transparent bounding box, not the
|
|
46644
|
+
* line itself: only the stroke's hit target takes the pointer. A badge pinned
|
|
46645
|
+
* to that box's corner would float in empty space and could never be hovered,
|
|
46646
|
+
* so React does not draw one there either.
|
|
46647
|
+
*/
|
|
46648
|
+
function skipsAffordance(element) {
|
|
46649
|
+
return element.type === 'connector';
|
|
46650
|
+
}
|
|
46651
|
+
/** Remove any affordance nodes this pass previously added to `node`. */
|
|
46652
|
+
function clearAffordances(node) {
|
|
46653
|
+
node.classList.remove(LINK_TOOLTIP_HOST_CLASS);
|
|
46654
|
+
for (const owned of [...node.children]) {
|
|
46655
|
+
if (owned.hasAttribute(AFFORDANCE_ATTRIBUTE)) {
|
|
46656
|
+
owned.remove();
|
|
46657
|
+
}
|
|
46658
|
+
}
|
|
46659
|
+
}
|
|
46660
|
+
/** The affordance child of `node` with this kind, or `undefined`. */
|
|
46661
|
+
function ownedChild(node, kind) {
|
|
46662
|
+
for (const child of [...node.children]) {
|
|
46663
|
+
if (child.getAttribute(AFFORDANCE_ATTRIBUTE) === kind) {
|
|
46664
|
+
return child;
|
|
46665
|
+
}
|
|
46666
|
+
}
|
|
46667
|
+
return undefined;
|
|
46668
|
+
}
|
|
46669
|
+
/** Build (once) the amber badge, whose only mutable part is its `title`. */
|
|
46670
|
+
function buildIndicator(doc) {
|
|
46671
|
+
const badge = doc.createElement('div');
|
|
46672
|
+
badge.setAttribute(AFFORDANCE_ATTRIBUTE, 'indicator');
|
|
46673
|
+
badge.className = ACTION_INDICATOR_CLASS;
|
|
46674
|
+
const svg = doc.createElementNS(SVG_NAMESPACE, 'svg');
|
|
46675
|
+
svg.setAttribute('viewBox', '0 0 24 24');
|
|
46676
|
+
svg.setAttribute('fill', 'currentColor');
|
|
46677
|
+
svg.setAttribute('aria-hidden', 'true');
|
|
46678
|
+
const path = doc.createElementNS(SVG_NAMESPACE, 'path');
|
|
46679
|
+
path.setAttribute('d', ACTION_INDICATOR_ICON_PATH);
|
|
46680
|
+
svg.appendChild(path);
|
|
46681
|
+
badge.appendChild(svg);
|
|
46682
|
+
return badge;
|
|
46683
|
+
}
|
|
46684
|
+
/** Build (once) the hover tooltip; its two text lines are refreshed in place. */
|
|
46685
|
+
function buildTooltip(doc) {
|
|
46686
|
+
const tooltip = doc.createElement('div');
|
|
46687
|
+
tooltip.setAttribute(AFFORDANCE_ATTRIBUTE, 'tooltip');
|
|
46688
|
+
tooltip.className = LINK_TOOLTIP_CLASS;
|
|
46689
|
+
const panel = doc.createElement('div');
|
|
46690
|
+
panel.className = LINK_TOOLTIP_PANEL_CLASS;
|
|
46691
|
+
const label = doc.createElement('div');
|
|
46692
|
+
label.className = LINK_TOOLTIP_LABEL_CLASS;
|
|
46693
|
+
const hint = doc.createElement('div');
|
|
46694
|
+
hint.className = LINK_TOOLTIP_HINT_CLASS;
|
|
46695
|
+
panel.appendChild(label);
|
|
46696
|
+
panel.appendChild(hint);
|
|
46697
|
+
tooltip.appendChild(panel);
|
|
46698
|
+
return tooltip;
|
|
46699
|
+
}
|
|
46700
|
+
/** Set `text` only when it changed, so a re-run never dirties the DOM. */
|
|
46701
|
+
function setText(node, text) {
|
|
46702
|
+
if (node.textContent !== text) {
|
|
46703
|
+
node.textContent = text;
|
|
46704
|
+
}
|
|
46705
|
+
}
|
|
46706
|
+
/**
|
|
46707
|
+
* Paint / refresh / remove the action affordances for every top-level element
|
|
46708
|
+
* on `stage`, returning how many elements ended up carrying one.
|
|
46709
|
+
*
|
|
46710
|
+
* Group CHILDREN are deliberately not decorated: PowerPoint treats a group as
|
|
46711
|
+
* one object, the click resolves up to it (`resolveTopLevelElementId`), and
|
|
46712
|
+
* React badges only its top-level container. A grouped child's own action is
|
|
46713
|
+
* still followed, and still announced, it just does not get its own badge.
|
|
46714
|
+
*/
|
|
46715
|
+
function applyElementActionAffordances(stage, elements, options) {
|
|
46716
|
+
let painted = 0;
|
|
46717
|
+
for (const element of elements) {
|
|
46718
|
+
const escapedId = typeof CSS !== 'undefined' && typeof CSS.escape === 'function'
|
|
46719
|
+
? CSS.escape(element.id)
|
|
46720
|
+
: element.id.replace(/["\\]/gu, '\\$&');
|
|
46721
|
+
const node = stage.querySelector(`[data-element-id="${escapedId}"]`);
|
|
46722
|
+
if (!node) {
|
|
46723
|
+
continue;
|
|
46724
|
+
}
|
|
46725
|
+
const affordance = skipsAffordance(element)
|
|
46726
|
+
? undefined
|
|
46727
|
+
: resolveElementActionAffordance(element, options);
|
|
46728
|
+
if (!affordance || (!affordance.showIndicator && !affordance.showLinkTooltip)) {
|
|
46729
|
+
clearAffordances(node);
|
|
46730
|
+
continue;
|
|
46731
|
+
}
|
|
46732
|
+
const doc = node.ownerDocument;
|
|
46733
|
+
ensureActionAffordanceStyles(doc);
|
|
46734
|
+
if (affordance.showIndicator) {
|
|
46735
|
+
let badge = ownedChild(node, 'indicator');
|
|
46736
|
+
if (!badge) {
|
|
46737
|
+
badge = buildIndicator(doc);
|
|
46738
|
+
node.appendChild(badge);
|
|
46739
|
+
}
|
|
46740
|
+
if (badge.getAttribute('title') !== affordance.indicatorTitle) {
|
|
46741
|
+
badge.setAttribute('title', affordance.indicatorTitle);
|
|
46742
|
+
}
|
|
46743
|
+
}
|
|
46744
|
+
else {
|
|
46745
|
+
ownedChild(node, 'indicator')?.remove();
|
|
46746
|
+
}
|
|
46747
|
+
if (affordance.showLinkTooltip) {
|
|
46748
|
+
let tooltip = ownedChild(node, 'tooltip');
|
|
46749
|
+
if (!tooltip) {
|
|
46750
|
+
tooltip = buildTooltip(doc);
|
|
46751
|
+
node.appendChild(tooltip);
|
|
46752
|
+
}
|
|
46753
|
+
const panel = tooltip.firstElementChild;
|
|
46754
|
+
if (panel?.firstElementChild && panel.lastElementChild) {
|
|
46755
|
+
setText(panel.firstElementChild, affordance.linkTooltipLabel);
|
|
46756
|
+
setText(panel.lastElementChild, affordance.linkTooltipHint);
|
|
46757
|
+
}
|
|
46758
|
+
node.classList.add(LINK_TOOLTIP_HOST_CLASS);
|
|
46759
|
+
}
|
|
46760
|
+
else {
|
|
46761
|
+
ownedChild(node, 'tooltip')?.remove();
|
|
46762
|
+
node.classList.remove(LINK_TOOLTIP_HOST_CLASS);
|
|
46763
|
+
}
|
|
46764
|
+
painted += 1;
|
|
46765
|
+
}
|
|
46766
|
+
return painted;
|
|
46767
|
+
}
|
|
46768
|
+
|
|
45905
46769
|
/** Action kinds selectable for an element's click / hover trigger. */
|
|
45906
46770
|
const ELEMENT_ACTION_TYPE_OPTIONS = [
|
|
45907
46771
|
{ value: 'none', labelKey: 'pptx.hyperlink.actionNone' },
|
|
@@ -47489,6 +48353,55 @@ function startMediaAutoplay(el, options) {
|
|
|
47489
48353
|
});
|
|
47490
48354
|
}
|
|
47491
48355
|
}
|
|
48356
|
+
/**
|
|
48357
|
+
* Resolve a media element's authored playback settings into DOM attributes.
|
|
48358
|
+
*
|
|
48359
|
+
* WHY this is shared: the settings live on the parsed element, the mapping is
|
|
48360
|
+
* two clamps and a default, and getting it wrong is invisible in a screenshot.
|
|
48361
|
+
* Vanilla and Svelte both omitted `loop`, so `solution-explorer.pptx` slide 2 -
|
|
48362
|
+
* a 2-second clip the deck marks `loop` and drives with a `playFrom(0.0)` on
|
|
48363
|
+
* slide entry - played once, hit its end and froze on the last frame, which
|
|
48364
|
+
* reads exactly like "the video never started". Volume was worse: only React
|
|
48365
|
+
* applied it, so a deck that says `vol="0"` blared out of the other four.
|
|
48366
|
+
*/
|
|
48367
|
+
function mediaPlaybackAttributes(source) {
|
|
48368
|
+
return {
|
|
48369
|
+
loop: source.loop === true,
|
|
48370
|
+
volume: Math.max(0, Math.min(1, source.volume ?? 1)),
|
|
48371
|
+
playbackRate: Math.max(0.25, Math.min(4, source.playbackSpeed ?? 1)),
|
|
48372
|
+
};
|
|
48373
|
+
}
|
|
48374
|
+
/**
|
|
48375
|
+
* Apply {@link mediaPlaybackAttributes} to a live node.
|
|
48376
|
+
*
|
|
48377
|
+
* `volume` and `playbackRate` are IDL properties with no attribute form, so the
|
|
48378
|
+
* declarative bindings cannot set them from a template the way they set `loop`;
|
|
48379
|
+
* every binding therefore needs this imperative step, not just the DOM ones.
|
|
48380
|
+
*/
|
|
48381
|
+
function applyMediaPlaybackAttributes(el, source) {
|
|
48382
|
+
const attributes = mediaPlaybackAttributes(source);
|
|
48383
|
+
el.loop = attributes.loop;
|
|
48384
|
+
el.volume = attributes.volume;
|
|
48385
|
+
el.playbackRate = attributes.playbackRate;
|
|
48386
|
+
}
|
|
48387
|
+
/**
|
|
48388
|
+
* Whether a media element should carry the browser's native transport.
|
|
48389
|
+
*
|
|
48390
|
+
* PowerPoint paints no control bar during a show, and none on a still of a
|
|
48391
|
+
* slide either. Four bindings got the still wrong: the presenter console's
|
|
48392
|
+
* panes render through a NON-presenting stage, so `controls = !presenting` (and
|
|
48393
|
+
* Angular's `controls = !interactive && !presenting`) turned Chrome's black
|
|
48394
|
+
* scrubber ON inside the console, across the bottom of a slide the presenter
|
|
48395
|
+
* cannot even play. React escaped only by accident - its preview renderer
|
|
48396
|
+
* passes no media map, so the video falls back to a poster image and there is
|
|
48397
|
+
* no `<video>` to put a transport on.
|
|
48398
|
+
*/
|
|
48399
|
+
function mediaTransportVisible(surface) {
|
|
48400
|
+
if (surface.presenting || surface.preview) {
|
|
48401
|
+
return false;
|
|
48402
|
+
}
|
|
48403
|
+
return surface.canvasTransport;
|
|
48404
|
+
}
|
|
47492
48405
|
|
|
47493
48406
|
function clamp(value, minimum, maximum) {
|
|
47494
48407
|
return Math.min(maximum, Math.max(minimum, value));
|
|
@@ -55479,6 +56392,18 @@ const translationsEn = {
|
|
|
55479
56392
|
'pptx.presenter.eraseAllInk': 'Erase All Ink on Slide',
|
|
55480
56393
|
'pptx.presenter.slideLabel': 'Slide {{current}} of {{total}}',
|
|
55481
56394
|
'pptx.presenter.timerProgress': 'Timer Progress',
|
|
56395
|
+
// Presenter console strip (see render/presenter-chrome.ts). React shipped
|
|
56396
|
+
// these as hard-coded English `title` attributes, which is why they arrive
|
|
56397
|
+
// as new keys rather than reused ones.
|
|
56398
|
+
'pptx.presenter.toggleTimer': 'Pause or Resume Timer',
|
|
56399
|
+
'pptx.presenter.resetTimer': 'Reset Timer',
|
|
56400
|
+
'pptx.presenter.zoomIn': 'Zoom In',
|
|
56401
|
+
'pptx.presenter.zoomOut': 'Zoom Out',
|
|
56402
|
+
'pptx.presenter.resetZoom': 'Reset Zoom',
|
|
56403
|
+
'pptx.presenter.swapDisplays': 'Swap Displays',
|
|
56404
|
+
'pptx.presenter.slideNavigator': 'Slide Navigator',
|
|
56405
|
+
'pptx.presenter.closeNavigator': 'Close',
|
|
56406
|
+
'pptx.presenter.timerTitle': '{{elapsed}} (segment {{segment}})',
|
|
55482
56407
|
// Print dialog
|
|
55483
56408
|
'pptx.print.allSlides': 'All Slides',
|
|
55484
56409
|
'pptx.print.blackAndWhite': 'Black and White',
|
|
@@ -56392,6 +57317,7 @@ const translationsEn = {
|
|
|
56392
57317
|
'pptx.editorToolbar.resetZoom': 'Reset zoom',
|
|
56393
57318
|
'pptx.editorToolbar.resetZoomTo100': 'Reset zoom to 100%',
|
|
56394
57319
|
'pptx.effects.innerShadow': 'Inner Shadow',
|
|
57320
|
+
'pptx.element.hasAction': 'Has action',
|
|
56395
57321
|
'pptx.element.linkFallback': 'Link',
|
|
56396
57322
|
'pptx.export.export': 'Export',
|
|
56397
57323
|
'pptx.export.gifAnimated': 'Animated GIF',
|
|
@@ -59476,7 +60402,7 @@ function createLocalStorageBackend(namespace) {
|
|
|
59476
60402
|
/** Try IndexedDB first; fall back to localStorage on any failure. */
|
|
59477
60403
|
async function resolveBackend(dbName, namespace) {
|
|
59478
60404
|
try {
|
|
59479
|
-
const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-
|
|
60405
|
+
const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-GPhhg6RN.mjs');
|
|
59480
60406
|
const db = await openChatDb(dbName);
|
|
59481
60407
|
return createIdbBackend(db);
|
|
59482
60408
|
}
|
|
@@ -69591,6 +70517,23 @@ class ConnectorRendererComponent {
|
|
|
69591
70517
|
</filter>
|
|
69592
70518
|
}
|
|
69593
70519
|
</defs>
|
|
70520
|
+
<!--
|
|
70521
|
+
The only pointer-reachable part of a connector: a transparent stroke
|
|
70522
|
+
along the line that opts back into hit testing. The wrapper is
|
|
70523
|
+
pointer-events:none so a connector's mostly-empty bounding box never
|
|
70524
|
+
swallows clicks meant for the shapes it spans, which left the line
|
|
70525
|
+
itself unclickable until this path existed.
|
|
70526
|
+
-->
|
|
70527
|
+
<path
|
|
70528
|
+
class="pptx-ng-connector-hit"
|
|
70529
|
+
[attr.d]="geo().hitPathD"
|
|
70530
|
+
fill="none"
|
|
70531
|
+
stroke="transparent"
|
|
70532
|
+
[attr.stroke-width]="geo().hitStrokeWidth"
|
|
70533
|
+
stroke-linecap="round"
|
|
70534
|
+
stroke-linejoin="round"
|
|
70535
|
+
style="pointer-events: stroke"
|
|
70536
|
+
/>
|
|
69594
70537
|
@for (strand of strands(); track strand.key) {
|
|
69595
70538
|
@if (geo().pathD) {
|
|
69596
70539
|
<path
|
|
@@ -69703,6 +70646,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
69703
70646
|
</filter>
|
|
69704
70647
|
}
|
|
69705
70648
|
</defs>
|
|
70649
|
+
<!--
|
|
70650
|
+
The only pointer-reachable part of a connector: a transparent stroke
|
|
70651
|
+
along the line that opts back into hit testing. The wrapper is
|
|
70652
|
+
pointer-events:none so a connector's mostly-empty bounding box never
|
|
70653
|
+
swallows clicks meant for the shapes it spans, which left the line
|
|
70654
|
+
itself unclickable until this path existed.
|
|
70655
|
+
-->
|
|
70656
|
+
<path
|
|
70657
|
+
class="pptx-ng-connector-hit"
|
|
70658
|
+
[attr.d]="geo().hitPathD"
|
|
70659
|
+
fill="none"
|
|
70660
|
+
stroke="transparent"
|
|
70661
|
+
[attr.stroke-width]="geo().hitStrokeWidth"
|
|
70662
|
+
stroke-linecap="round"
|
|
70663
|
+
stroke-linejoin="round"
|
|
70664
|
+
style="pointer-events: stroke"
|
|
70665
|
+
/>
|
|
69706
70666
|
@for (strand of strands(); track strand.key) {
|
|
69707
70667
|
@if (geo().pathD) {
|
|
69708
70668
|
<path
|
|
@@ -71198,6 +72158,13 @@ function resolveCaptionTracks(tracks) {
|
|
|
71198
72158
|
* across the bottom of the slide, over the presentation toolbar. PowerPoint
|
|
71199
72159
|
* shows no transport during a show either; React gates on the same condition
|
|
71200
72160
|
* (`controls={!isPresentationMode}`).
|
|
72161
|
+
*
|
|
72162
|
+
* The same `interactive` gate turned it on for every STILL of a slide as well
|
|
72163
|
+
* (the presenter console's current-slide pane and next-slide preview, the
|
|
72164
|
+
* thumbnail rail), so the console painted a scrubber over a slide the speaker
|
|
72165
|
+
* cannot play. {@link showControls} routes the decision through the shared
|
|
72166
|
+
* `mediaTransportVisible`, which owns the show/still rules for all five
|
|
72167
|
+
* bindings and leaves the authoring canvas to each of them.
|
|
71201
72168
|
*/
|
|
71202
72169
|
class MediaRendererComponent {
|
|
71203
72170
|
/** The element to render. Playback only occurs when `type === 'media'`. */
|
|
@@ -71227,7 +72194,13 @@ class MediaRendererComponent {
|
|
|
71227
72194
|
// Presentation autoplay: once the media node is in the DOM and this is the
|
|
71228
72195
|
// live stage, start playback; pause again if it leaves present mode. Reads
|
|
71229
72196
|
// mediaSrc so a source swap re-evaluates. The shared helper owns the
|
|
71230
|
-
// `.play()` + blocked-autoplay handling so all
|
|
72197
|
+
// `.play()` + blocked-autoplay handling so all five bindings match.
|
|
72198
|
+
//
|
|
72199
|
+
// The deck's authored playback settings are applied on the same pass.
|
|
72200
|
+
// `volume` and `playbackRate` are IDL properties with no attribute form,
|
|
72201
|
+
// so the template cannot bind them the way it binds `loop`, and until this
|
|
72202
|
+
// they were simply dropped: `solution-explorer.pptx` slide 2 declares
|
|
72203
|
+
// `vol="0"` and Angular played it at full volume.
|
|
71231
72204
|
effect(() => {
|
|
71232
72205
|
const el = this.mediaElRef()?.nativeElement;
|
|
71233
72206
|
const presenting = this.presenting();
|
|
@@ -71235,14 +72208,33 @@ class MediaRendererComponent {
|
|
|
71235
72208
|
if (!el) {
|
|
71236
72209
|
return;
|
|
71237
72210
|
}
|
|
72211
|
+
const media = asMediaElement(this.element());
|
|
72212
|
+
if (media) {
|
|
72213
|
+
applyMediaPlaybackAttributes(el, media);
|
|
72214
|
+
}
|
|
71238
72215
|
if (presenting) {
|
|
71239
|
-
startMediaAutoplay(el, { trimStartMs:
|
|
72216
|
+
startMediaAutoplay(el, { trimStartMs: media?.trimStartMs });
|
|
71240
72217
|
}
|
|
71241
72218
|
else if (!el.paused) {
|
|
71242
72219
|
el.pause();
|
|
71243
72220
|
}
|
|
71244
72221
|
});
|
|
71245
72222
|
}
|
|
72223
|
+
/**
|
|
72224
|
+
* Whether to paint the browser's native transport.
|
|
72225
|
+
*
|
|
72226
|
+
* `canvasTransport: false` is this binding's own long-standing answer for its
|
|
72227
|
+
* authoring canvas: a click there selects or moves the picture, so a scrubber
|
|
72228
|
+
* would only steal the gesture (the element also carries `pptx-ng-media-inert`
|
|
72229
|
+
* for the same reason). React paints one on its canvas; that difference is
|
|
72230
|
+
* deliberate and is the only thing the shared rule leaves to the binding.
|
|
72231
|
+
*/
|
|
72232
|
+
showControls = computed(() => mediaTransportVisible({
|
|
72233
|
+
presenting: this.presenting(),
|
|
72234
|
+
preview: !this.interactive() && !this.presenting(),
|
|
72235
|
+
canvasTransport: false,
|
|
72236
|
+
}), /* @ts-ignore */
|
|
72237
|
+
...(ngDevMode ? [{ debugName: "showControls" }] : /* istanbul ignore next */ []));
|
|
71246
72238
|
containerStyle = computed(() => getContainerStyle(this.element(), this.zIndex()), /* @ts-ignore */
|
|
71247
72239
|
...(ngDevMode ? [{ debugName: "containerStyle" }] : /* istanbul ignore next */ []));
|
|
71248
72240
|
/** Poster / preview frame data-URL (also used as the `<video poster>`). */
|
|
@@ -71282,7 +72274,7 @@ class MediaRendererComponent {
|
|
|
71282
72274
|
class="pptx-ng-media-el pptx-ng-media-audio"
|
|
71283
72275
|
[class.pptx-ng-media-inert]="interactive()"
|
|
71284
72276
|
[src]="src + trimFragment()"
|
|
71285
|
-
[controls]="
|
|
72277
|
+
[controls]="showControls()"
|
|
71286
72278
|
[loop]="loop()"
|
|
71287
72279
|
preload="metadata"
|
|
71288
72280
|
></audio>
|
|
@@ -71293,7 +72285,7 @@ class MediaRendererComponent {
|
|
|
71293
72285
|
[class.pptx-ng-media-inert]="interactive()"
|
|
71294
72286
|
[src]="src + trimFragment()"
|
|
71295
72287
|
[poster]="poster() ?? null"
|
|
71296
|
-
[controls]="
|
|
72288
|
+
[controls]="showControls()"
|
|
71297
72289
|
[loop]="loop()"
|
|
71298
72290
|
preload="metadata"
|
|
71299
72291
|
playsInline
|
|
@@ -71342,7 +72334,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
71342
72334
|
class="pptx-ng-media-el pptx-ng-media-audio"
|
|
71343
72335
|
[class.pptx-ng-media-inert]="interactive()"
|
|
71344
72336
|
[src]="src + trimFragment()"
|
|
71345
|
-
[controls]="
|
|
72337
|
+
[controls]="showControls()"
|
|
71346
72338
|
[loop]="loop()"
|
|
71347
72339
|
preload="metadata"
|
|
71348
72340
|
></audio>
|
|
@@ -71353,7 +72345,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
71353
72345
|
[class.pptx-ng-media-inert]="interactive()"
|
|
71354
72346
|
[src]="src + trimFragment()"
|
|
71355
72347
|
[poster]="poster() ?? null"
|
|
71356
|
-
[controls]="
|
|
72348
|
+
[controls]="showControls()"
|
|
71357
72349
|
[loop]="loop()"
|
|
71358
72350
|
preload="metadata"
|
|
71359
72351
|
playsInline
|
|
@@ -74231,6 +75223,19 @@ function resolveInteractiveElementId(target, allElements, editTemplateMode) {
|
|
|
74231
75223
|
function isViewportBackgroundPressTarget(target, currentTarget) {
|
|
74232
75224
|
return target === currentTarget;
|
|
74233
75225
|
}
|
|
75226
|
+
/**
|
|
75227
|
+
* Which elements the on-canvas action affordances (amber "has action" badge +
|
|
75228
|
+
* hover link tooltip) may decorate.
|
|
75229
|
+
*
|
|
75230
|
+
* An inherited master/layout shape is inert until edit-template mode is on, so
|
|
75231
|
+
* it must not advertise an action the user cannot reach yet; that mirrors
|
|
75232
|
+
* React's `canInteract` gate, which is off for the template layer until the
|
|
75233
|
+
* mode is enabled. Split out of the component's post-render effect so it is
|
|
75234
|
+
* testable without a TestBed, like the rest of this package.
|
|
75235
|
+
*/
|
|
75236
|
+
function affordanceElements(elements, editTemplateMode, isTemplate) {
|
|
75237
|
+
return editTemplateMode ? elements : elements.filter((element) => !isTemplate(element));
|
|
75238
|
+
}
|
|
74234
75239
|
|
|
74235
75240
|
/**
|
|
74236
75241
|
* Thin re-export shim → vendored `pptx-viewer-shared`.
|
|
@@ -74560,8 +75565,23 @@ class SlideCanvasComponent {
|
|
|
74560
75565
|
const elements = this.allElements();
|
|
74561
75566
|
const interactive = this.interactive();
|
|
74562
75567
|
const presenting = this.presenting();
|
|
75568
|
+
// An inherited master/layout shape only gets the authoring chrome while
|
|
75569
|
+
// it is actually editable, matching React's `canInteract` gate.
|
|
75570
|
+
const decorated = affordanceElements(elements, this.editTemplateMode(), isTemplateElement);
|
|
74563
75571
|
if (stage && (interactive || presenting)) {
|
|
74564
|
-
queueMicrotask(() =>
|
|
75572
|
+
queueMicrotask(() => {
|
|
75573
|
+
applyRenderedElementAccessibility(stage, elements, { presenting });
|
|
75574
|
+
// The on-canvas action affordances (amber badge + hover link
|
|
75575
|
+
// tooltip) ride the same post-render pass: `ElementRendererComponent`
|
|
75576
|
+
// dispatches every non-shape type straight to a per-type component
|
|
75577
|
+
// whose root IS the element node, leaving no wrapper in the template
|
|
75578
|
+
// to hang the chrome off.
|
|
75579
|
+
applyElementActionAffordances(stage, decorated, {
|
|
75580
|
+
canInteract: interactive,
|
|
75581
|
+
presenting,
|
|
75582
|
+
labels: actionAffordanceLabels((key) => this.translate.instant(key)),
|
|
75583
|
+
});
|
|
75584
|
+
});
|
|
74565
75585
|
}
|
|
74566
75586
|
});
|
|
74567
75587
|
// Observe the viewport so the slide re-fits on container resize / rotation.
|
|
@@ -76211,45 +77231,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
76211
77231
|
`, styles: [":host{display:contents}.pptx-ng-mmenu-list{list-style:none;margin:0;padding:.5rem 0}.pptx-ng-mmenu-row{display:flex;align-items:center;gap:.875rem;width:100%;padding:.75rem 1.25rem;border:none;background:transparent;color:#e5e5e5;text-align:left;cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent;transition:background .1s}.pptx-ng-mmenu-row:hover:not([disabled]){background:#ffffff0f}.pptx-ng-mmenu-row:active:not([disabled]){background:#ffffff1a}.pptx-ng-mmenu-row.is-active{color:#3b82f6}.pptx-ng-mmenu-row.is-danger{color:#ef4444}.pptx-ng-mmenu-row[disabled]{opacity:.35;cursor:not-allowed}.pptx-ng-mmenu-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.5rem;opacity:.8}.pptx-ng-mmenu-text{display:flex;flex-direction:column;gap:.125rem;flex:1;min-width:0}.pptx-ng-mmenu-label{font-size:.9375rem;font-weight:500;line-height:1.3}.pptx-ng-mmenu-sublabel{font-size:.75rem;color:#ffffff73;line-height:1.3}.pptx-ng-mmenu-check{color:#3b82f6;font-size:1rem;flex-shrink:0}.pptx-ng-mmenu-divider{height:1px;background:#ffffff14;margin:.375rem 0}\n"] }]
|
|
76212
77232
|
}], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], slideCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideCount", required: false }] }], exporting: [{ type: i0.Input, args: [{ isSignal: true, alias: "exporting", required: false }] }], showNotes: [{ type: i0.Input, args: [{ isSignal: true, alias: "showNotes", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], hiddenActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "hiddenActions", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], openFind: [{ type: i0.Output, args: ["openFind"] }], openSorter: [{ type: i0.Output, args: ["openSorter"] }], toggleNotes: [{ type: i0.Output, args: ["toggleNotes"] }], insertText: [{ type: i0.Output, args: ["insertText"] }], present: [{ type: i0.Output, args: ["present"] }], openFile: [{ type: i0.Output, args: ["openFile"] }], savePptx: [{ type: i0.Output, args: ["savePptx"] }], exportPng: [{ type: i0.Output, args: ["exportPng"] }], exportPdf: [{ type: i0.Output, args: ["exportPdf"] }], exportGif: [{ type: i0.Output, args: ["exportGif"] }], exportVideo: [{ type: i0.Output, args: ["exportVideo"] }], print: [{ type: i0.Output, args: ["print"] }] } });
|
|
76213
77233
|
|
|
76214
|
-
// ---------------------------------------------------------------------------
|
|
76215
|
-
// Time formatting (local: negative-clamping differs from shared)
|
|
76216
|
-
// ---------------------------------------------------------------------------
|
|
76217
|
-
/**
|
|
76218
|
-
* Format a millisecond duration as MM:SS, or HH:MM:SS when the elapsed
|
|
76219
|
-
* time is one hour or longer. Sub-second values are floored; negative inputs
|
|
76220
|
-
* are treated as zero.
|
|
76221
|
-
*/
|
|
76222
|
-
function formatElapsed(elapsedMs) {
|
|
76223
|
-
const safeMs = elapsedMs > 0 ? elapsedMs : 0;
|
|
76224
|
-
const totalSeconds = Math.floor(safeMs / 1000);
|
|
76225
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
76226
|
-
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
76227
|
-
const seconds = totalSeconds % 60;
|
|
76228
|
-
if (hours > 0) {
|
|
76229
|
-
return `${pad2(hours)}:${pad2(minutes)}:${pad2(seconds)}`;
|
|
76230
|
-
}
|
|
76231
|
-
return `${pad2(minutes)}:${pad2(seconds)}`;
|
|
76232
|
-
}
|
|
76233
|
-
/** Zero-pad a non-negative integer to at least two digits. */
|
|
76234
|
-
function pad2(value) {
|
|
76235
|
-
return String(value).padStart(2, '0');
|
|
76236
|
-
}
|
|
76237
|
-
// ---------------------------------------------------------------------------
|
|
76238
|
-
// Timer progress (5-minute segments)
|
|
76239
|
-
// ---------------------------------------------------------------------------
|
|
76240
|
-
/** Milliseconds per timer progress-bar fill (one 5-minute segment). */
|
|
76241
|
-
const TIMER_SEGMENT_MS = 5 * 60 * 1000;
|
|
76242
|
-
/**
|
|
76243
|
-
* Derive the timer progress-bar fill (percent within the current 5-minute
|
|
76244
|
-
* segment) and the segment index from an elapsed duration. Mirrors the React
|
|
76245
|
-
* PresenterView `timerProgress` / `timerSegment` computation.
|
|
76246
|
-
*/
|
|
76247
|
-
function computeTimerProgress(elapsedMs) {
|
|
76248
|
-
const safeMs = elapsedMs > 0 ? elapsedMs : 0;
|
|
76249
|
-
const percent = Math.min(100, ((safeMs % TIMER_SEGMENT_MS) / TIMER_SEGMENT_MS) * 100);
|
|
76250
|
-
const segment = Math.floor(safeMs / TIMER_SEGMENT_MS);
|
|
76251
|
-
return { percent, segment };
|
|
76252
|
-
}
|
|
76253
77234
|
// ---------------------------------------------------------------------------
|
|
76254
77235
|
// Elapsed time from a start timestamp
|
|
76255
77236
|
// ---------------------------------------------------------------------------
|
|
@@ -76257,6 +77238,9 @@ function computeTimerProgress(elapsedMs) {
|
|
|
76257
77238
|
* Compute the elapsed milliseconds between `startTime` (epoch ms, or null when
|
|
76258
77239
|
* the presentation has not started) and `now`. Returns 0 when no start time is
|
|
76259
77240
|
* set or the clock has not advanced past the start.
|
|
77241
|
+
*
|
|
77242
|
+
* This clamp is why shared's `formatElapsed` needs none: a duration handed to
|
|
77243
|
+
* the formatter has already been resolved against a wall clock here.
|
|
76260
77244
|
*/
|
|
76261
77245
|
function elapsedSince(startTime, now) {
|
|
76262
77246
|
if (startTime === null || startTime === undefined) {
|
|
@@ -76278,8 +77262,13 @@ function currentSlideAt(slides, index) {
|
|
|
76278
77262
|
return slides[index];
|
|
76279
77263
|
}
|
|
76280
77264
|
/**
|
|
76281
|
-
* Return the
|
|
76282
|
-
*
|
|
77265
|
+
* Return the slide the show would advance to from `index`, or undefined at the
|
|
77266
|
+
* end of the deck.
|
|
77267
|
+
*
|
|
77268
|
+
* Delegates to the shared `nextPresentedSlide`, which is what makes the
|
|
77269
|
+
* next-slide preview agree with the show itself: it skips hidden slides and
|
|
77270
|
+
* honours custom-show membership, neither of which a naive `slides[index + 1]`
|
|
77271
|
+
* can do.
|
|
76283
77272
|
*/
|
|
76284
77273
|
function nextSlideAfter(slides, index) {
|
|
76285
77274
|
return nextPresentedSlide(slides, index);
|
|
@@ -76296,44 +77285,21 @@ function slideCounter(index, total) {
|
|
|
76296
77285
|
return `${index + 1} / ${total}`;
|
|
76297
77286
|
}
|
|
76298
77287
|
/**
|
|
76299
|
-
* Derive
|
|
76300
|
-
*
|
|
76301
|
-
*
|
|
77288
|
+
* Derive notes view-model tokens from rich-text `TextSegment`s.
|
|
77289
|
+
*
|
|
77290
|
+
* The styling rules (which properties, in which units) belong to shared's
|
|
77291
|
+
* `notesSegmentsToSpans`; all this adds is the camelCase -> kebab-case rewrite
|
|
77292
|
+
* the Angular `ngStyle` binding is written against.
|
|
76302
77293
|
*/
|
|
76303
77294
|
function buildNotesSegments(segments) {
|
|
76304
|
-
return segments.map((
|
|
76305
|
-
|
|
76306
|
-
|
|
76307
|
-
|
|
76308
|
-
|
|
76309
|
-
|
|
76310
|
-
|
|
76311
|
-
|
|
76312
|
-
}
|
|
76313
|
-
if (s.italic) {
|
|
76314
|
-
style['font-style'] = 'italic';
|
|
76315
|
-
}
|
|
76316
|
-
const decorations = [];
|
|
76317
|
-
if (s.underline) {
|
|
76318
|
-
decorations.push('underline');
|
|
76319
|
-
}
|
|
76320
|
-
if (s.strikethrough) {
|
|
76321
|
-
decorations.push('line-through');
|
|
76322
|
-
}
|
|
76323
|
-
if (decorations.length > 0) {
|
|
76324
|
-
style['text-decoration'] = decorations.join(' ');
|
|
76325
|
-
}
|
|
76326
|
-
if (s.color) {
|
|
76327
|
-
style['color'] = s.color;
|
|
76328
|
-
}
|
|
76329
|
-
if (s.fontSize) {
|
|
76330
|
-
style['font-size'] = `${s.fontSize}px`;
|
|
76331
|
-
}
|
|
76332
|
-
if (s.fontFamily) {
|
|
76333
|
-
style['font-family'] = s.fontFamily;
|
|
76334
|
-
}
|
|
76335
|
-
return { key: `seg-${index}`, isBreak: false, text: segment.text, style };
|
|
76336
|
-
});
|
|
77295
|
+
return notesSegmentsToSpans([...segments]).map((span) => span.kind === 'break'
|
|
77296
|
+
? { key: span.key, isBreak: true, text: '', style: {} }
|
|
77297
|
+
: {
|
|
77298
|
+
key: span.key,
|
|
77299
|
+
isBreak: false,
|
|
77300
|
+
text: span.text,
|
|
77301
|
+
style: cssObjectToStyleMap(span.style),
|
|
77302
|
+
});
|
|
76337
77303
|
}
|
|
76338
77304
|
/**
|
|
76339
77305
|
* Resolve the presenter notes for a slide: prefer rich `notesSegments`, else
|
|
@@ -76422,10 +77388,13 @@ class MobilePresenterViewComponent {
|
|
|
76422
77388
|
...(ngDevMode ? [{ debugName: "elapsedLabel" }] : /* istanbul ignore next */ []));
|
|
76423
77389
|
counterLabel = computed(() => mobileSlideCounter(this.currentSlideIndex(), this.slides().length), /* @ts-ignore */
|
|
76424
77390
|
...(ngDevMode ? [{ debugName: "counterLabel" }] : /* istanbul ignore next */ []));
|
|
76425
|
-
|
|
76426
|
-
|
|
76427
|
-
|
|
76428
|
-
|
|
77391
|
+
// The desktop console's rules, not a phone-sized copy of them: Next stays live
|
|
77392
|
+
// on the last slide so the presenter can reach the end-of-show screen and
|
|
77393
|
+
// finish, exactly as the split-screen console does.
|
|
77394
|
+
prevDisabled = computed(() => presenterPrevDisabled(this.currentSlideIndex()), /* @ts-ignore */
|
|
77395
|
+
...(ngDevMode ? [{ debugName: "prevDisabled" }] : /* istanbul ignore next */ []));
|
|
77396
|
+
nextDisabled = computed(() => presenterNextDisabled(), /* @ts-ignore */
|
|
77397
|
+
...(ngDevMode ? [{ debugName: "nextDisabled" }] : /* istanbul ignore next */ []));
|
|
76429
77398
|
/** Next-slide thumbnail box (CSS px); width drives the slide-canvas autoFit. */
|
|
76430
77399
|
thumbStyle = computed(() => {
|
|
76431
77400
|
const size = this.canvasSize();
|
|
@@ -76447,11 +77416,11 @@ class MobilePresenterViewComponent {
|
|
|
76447
77416
|
return { ...slide, elements: [...template, ...slide.elements] };
|
|
76448
77417
|
}
|
|
76449
77418
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: MobilePresenterViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
76450
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: MobilePresenterViewComponent, isStandalone: true, selector: "pptx-mobile-presenter-view", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, currentSlideIndex: { classPropertyName: "currentSlideIndex", publicName: "currentSlideIndex", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, templateElements: { classPropertyName: "templateElements", publicName: "templateElements", isSignal: true, isRequired: false, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, presentationStartTime: { classPropertyName: "presentationStartTime", publicName: "presentationStartTime", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { movePresentationSlide: "movePresentationSlide", exit: "exit" }, ngImport: i0, template: "@if (currentSlide(); as current) {\n\t<!-- Header: elapsed + counter + exit -->\n\t<div class=\"pptx-ng-mpresenter-header\">\n\t\t<div>\n\t\t\t<div class=\"pptx-ng-mpresenter-label\">{{ 'pptx.presenter.elapsed' | translate }}</div>\n\t\t\t<div class=\"pptx-ng-mpresenter-elapsed\">{{ elapsedLabel() }}</div>\n\t\t</div>\n\t\t<span class=\"pptx-ng-mpresenter-counter\">{{ counterLabel() }}</span>\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-mpresenter-exit\"\n\t\t\t(click)=\"exit.emit()\"\n\t\t\t[attr.aria-label]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t[title]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t>\n\t\t\t✕\n\t\t</button>\n\t</div>\n\n\t<!-- Current slide (large) -->\n\t<div class=\"pptx-ng-mpresenter-main\">\n\t\t<div class=\"pptx-ng-mpresenter-main-stage\">\n\t\t\t<pptx-slide-canvas\n\t\t\t\t[slide]=\"currentPreviewSlide()\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t[zoom]=\"1\"\n\t\t\t\t[interactive]=\"false\"\n\t\t\t/>\n\t\t</div>\n\t</div>\n\n\t<!-- Next thumbnail -->\n\t<div class=\"pptx-ng-mpresenter-next\">\n\t\t<span class=\"pptx-ng-mpresenter-label\">{{\n\t\t\t'pptx.presenter.nextSlidePreview' | translate\n\t\t}}</span>\n\t\t@if (nextPreviewSlide(); as next) {\n\t\t\t<div class=\"pptx-ng-mpresenter-thumb\" [ngStyle]=\"thumbStyle()\">\n\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t[slide]=\"next\"\n\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t} @else {\n\t\t\t<div class=\"pptx-ng-mpresenter-next-empty\">\n\t\t\t\t{{ 'pptx.presenter.endOfPresentation' | translate }}\n\t\t\t</div>\n\t\t}\n\t</div>\n\n\t<!-- Speaker notes (scrollable) -->\n\t<div class=\"pptx-ng-mpresenter-notes\">\n\t\t<div class=\"pptx-ng-mpresenter-label\">{{ 'pptx.presenter.speakerNotes' | translate }}</div>\n\t\t<div class=\"pptx-ng-mpresenter-notes-body\">\n\t\t\t@if (notes().hasRichNotes) {\n\t\t\t\t@for (seg of notes().segments; track seg.key) {\n\t\t\t\t\t@if (seg.isBreak) {\n\t\t\t\t\t\t<br />\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span [ngStyle]=\"seg.style\">{{ seg.text }}</span>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} @else if (notes().hasAnyNotes) {\n\t\t\t\t{{ notes().plainText }}\n\t\t\t} @else {\n\t\t\t\t<span class=\"pptx-ng-mpresenter-notes-empty\">{{\n\t\t\t\t\t'pptx.presenter.noNotes' | translate\n\t\t\t\t}}</span>\n\t\t\t}\n\t\t</div>\n\t</div>\n\n\t<!-- Prev / Next controls -->\n\t<div class=\"pptx-ng-mpresenter-ctl\">\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-mpresenter-navbtn\"\n\t\t\t(click)=\"movePresentationSlide.emit(-1)\"\n\t\t\t[disabled]=\"
|
|
77419
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: MobilePresenterViewComponent, isStandalone: true, selector: "pptx-mobile-presenter-view", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, currentSlideIndex: { classPropertyName: "currentSlideIndex", publicName: "currentSlideIndex", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, templateElements: { classPropertyName: "templateElements", publicName: "templateElements", isSignal: true, isRequired: false, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, presentationStartTime: { classPropertyName: "presentationStartTime", publicName: "presentationStartTime", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { movePresentationSlide: "movePresentationSlide", exit: "exit" }, ngImport: i0, template: "@if (currentSlide(); as current) {\n\t<!-- Header: elapsed + counter + exit -->\n\t<div class=\"pptx-ng-mpresenter-header\">\n\t\t<div>\n\t\t\t<div class=\"pptx-ng-mpresenter-label\">{{ 'pptx.presenter.elapsed' | translate }}</div>\n\t\t\t<div class=\"pptx-ng-mpresenter-elapsed\">{{ elapsedLabel() }}</div>\n\t\t</div>\n\t\t<span class=\"pptx-ng-mpresenter-counter\">{{ counterLabel() }}</span>\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-mpresenter-exit\"\n\t\t\t(click)=\"exit.emit()\"\n\t\t\t[attr.aria-label]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t[title]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t>\n\t\t\t✕\n\t\t</button>\n\t</div>\n\n\t<!-- Current slide (large) -->\n\t<div class=\"pptx-ng-mpresenter-main\">\n\t\t<div class=\"pptx-ng-mpresenter-main-stage\">\n\t\t\t<pptx-slide-canvas\n\t\t\t\t[slide]=\"currentPreviewSlide()\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t[zoom]=\"1\"\n\t\t\t\t[interactive]=\"false\"\n\t\t\t/>\n\t\t</div>\n\t</div>\n\n\t<!-- Next thumbnail -->\n\t<div class=\"pptx-ng-mpresenter-next\">\n\t\t<span class=\"pptx-ng-mpresenter-label\">{{\n\t\t\t'pptx.presenter.nextSlidePreview' | translate\n\t\t}}</span>\n\t\t@if (nextPreviewSlide(); as next) {\n\t\t\t<div class=\"pptx-ng-mpresenter-thumb\" [ngStyle]=\"thumbStyle()\">\n\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t[slide]=\"next\"\n\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t} @else {\n\t\t\t<div class=\"pptx-ng-mpresenter-next-empty\">\n\t\t\t\t{{ 'pptx.presenter.endOfPresentation' | translate }}\n\t\t\t</div>\n\t\t}\n\t</div>\n\n\t<!-- Speaker notes (scrollable) -->\n\t<div class=\"pptx-ng-mpresenter-notes\">\n\t\t<div class=\"pptx-ng-mpresenter-label\">{{ 'pptx.presenter.speakerNotes' | translate }}</div>\n\t\t<div class=\"pptx-ng-mpresenter-notes-body\">\n\t\t\t@if (notes().hasRichNotes) {\n\t\t\t\t@for (seg of notes().segments; track seg.key) {\n\t\t\t\t\t@if (seg.isBreak) {\n\t\t\t\t\t\t<br />\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span [ngStyle]=\"seg.style\">{{ seg.text }}</span>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} @else if (notes().hasAnyNotes) {\n\t\t\t\t{{ notes().plainText }}\n\t\t\t} @else {\n\t\t\t\t<span class=\"pptx-ng-mpresenter-notes-empty\">{{\n\t\t\t\t\t'pptx.presenter.noNotes' | translate\n\t\t\t\t}}</span>\n\t\t\t}\n\t\t</div>\n\t</div>\n\n\t<!-- Prev / Next controls -->\n\t<div class=\"pptx-ng-mpresenter-ctl\">\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-mpresenter-navbtn\"\n\t\t\tdata-pptx-presenter-control=\"prev\"\n\t\t\t(click)=\"movePresentationSlide.emit(-1)\"\n\t\t\t[disabled]=\"prevDisabled()\"\n\t\t\t[attr.aria-label]=\"'pptx.presenter.previousSlide' | translate\"\n\t\t\t[title]=\"'pptx.presenter.previousSlide' | translate\"\n\t\t>\n\t\t\t‹ {{ 'pptx.presenter.prev' | translate }}\n\t\t</button>\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-mpresenter-navbtn\"\n\t\t\tdata-pptx-presenter-control=\"next\"\n\t\t\t(click)=\"movePresentationSlide.emit(1)\"\n\t\t\t[disabled]=\"nextDisabled()\"\n\t\t\t[attr.aria-label]=\"'pptx.presenter.nextSlide' | translate\"\n\t\t\t[title]=\"'pptx.presenter.nextSlide' | translate\"\n\t\t>\n\t\t\t{{ 'pptx.presenter.next' | translate }} ›\n\t\t</button>\n\t</div>\n} @else {\n\t<div class=\"pptx-ng-mpresenter-empty\">{{ 'pptx.presenter.noSlides' | translate }}</div>\n}\n", styles: [":host{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;background:#0b0b0c;color:#f5f5f5;font-family:system-ui,sans-serif;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px);padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}.pptx-ng-mpresenter-header,.pptx-ng-mpresenter-next,.pptx-ng-mpresenter-ctl{display:flex;align-items:center;gap:.75rem;padding:.5rem 1rem}.pptx-ng-mpresenter-header{justify-content:space-between;border-bottom:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-label{font-size:.625rem;text-transform:uppercase;letter-spacing:.06em;color:#ffffff8c}.pptx-ng-mpresenter-elapsed{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.125rem;color:#6ea8fe}.pptx-ng-mpresenter-counter{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.875rem}.pptx-ng-mpresenter-exit{display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;min-width:44px;min-height:44px;border:none;border-radius:6px;background:transparent;color:#ffffffbf;cursor:pointer;font-size:1.25rem;line-height:1}.pptx-ng-mpresenter-exit:hover{background:#ffffff1f;color:#fff}.pptx-ng-mpresenter-main{display:flex;align-items:center;justify-content:center;background:#000;padding:.75rem}.pptx-ng-mpresenter-main-stage{width:100%;max-width:640px}.pptx-ng-mpresenter-next{border-bottom:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-thumb{flex:0 0 auto;overflow:hidden;border:1px solid rgba(255,255,255,.15);border-radius:4px}.pptx-ng-mpresenter-next-empty{display:flex;flex:1 1 auto;align-items:center;justify-content:center;height:3rem;border:1px solid rgba(255,255,255,.15);border-radius:4px;background:#ffffff0a;font-size:.625rem;font-style:italic;color:#ffffff80}.pptx-ng-mpresenter-notes{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;padding:.5rem 1rem}.pptx-ng-mpresenter-notes-body{flex:1 1 auto;overflow-y:auto;margin-top:.25rem;border:1px solid rgba(255,255,255,.15);border-radius:6px;background:#ffffff0a;padding:.5rem .75rem;white-space:pre-wrap;line-height:1.5;font-size:15px}.pptx-ng-mpresenter-notes-empty{font-style:italic;color:#ffffff80}.pptx-ng-mpresenter-ctl{justify-content:space-between;border-top:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-navbtn{flex:1 1 0;display:inline-flex;align-items:center;justify-content:center;gap:.375rem;height:44px;border:none;border-radius:6px;background:#ffffff14;color:#f5f5f5;cursor:pointer;font-size:.9rem}.pptx-ng-mpresenter-navbtn:hover:not(:disabled){background:#ffffff29}.pptx-ng-mpresenter-navbtn:disabled{opacity:.4;cursor:not-allowed}.pptx-ng-mpresenter-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff9}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "rulerUnit", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "transparentBackground", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
76451
77420
|
}
|
|
76452
77421
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: MobilePresenterViewComponent, decorators: [{
|
|
76453
77422
|
type: Component,
|
|
76454
|
-
args: [{ selector: 'pptx-mobile-presenter-view', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgStyle, SlideCanvasComponent, TranslatePipe], template: "@if (currentSlide(); as current) {\n\t<!-- Header: elapsed + counter + exit -->\n\t<div class=\"pptx-ng-mpresenter-header\">\n\t\t<div>\n\t\t\t<div class=\"pptx-ng-mpresenter-label\">{{ 'pptx.presenter.elapsed' | translate }}</div>\n\t\t\t<div class=\"pptx-ng-mpresenter-elapsed\">{{ elapsedLabel() }}</div>\n\t\t</div>\n\t\t<span class=\"pptx-ng-mpresenter-counter\">{{ counterLabel() }}</span>\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-mpresenter-exit\"\n\t\t\t(click)=\"exit.emit()\"\n\t\t\t[attr.aria-label]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t[title]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t>\n\t\t\t✕\n\t\t</button>\n\t</div>\n\n\t<!-- Current slide (large) -->\n\t<div class=\"pptx-ng-mpresenter-main\">\n\t\t<div class=\"pptx-ng-mpresenter-main-stage\">\n\t\t\t<pptx-slide-canvas\n\t\t\t\t[slide]=\"currentPreviewSlide()\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t[zoom]=\"1\"\n\t\t\t\t[interactive]=\"false\"\n\t\t\t/>\n\t\t</div>\n\t</div>\n\n\t<!-- Next thumbnail -->\n\t<div class=\"pptx-ng-mpresenter-next\">\n\t\t<span class=\"pptx-ng-mpresenter-label\">{{\n\t\t\t'pptx.presenter.nextSlidePreview' | translate\n\t\t}}</span>\n\t\t@if (nextPreviewSlide(); as next) {\n\t\t\t<div class=\"pptx-ng-mpresenter-thumb\" [ngStyle]=\"thumbStyle()\">\n\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t[slide]=\"next\"\n\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t} @else {\n\t\t\t<div class=\"pptx-ng-mpresenter-next-empty\">\n\t\t\t\t{{ 'pptx.presenter.endOfPresentation' | translate }}\n\t\t\t</div>\n\t\t}\n\t</div>\n\n\t<!-- Speaker notes (scrollable) -->\n\t<div class=\"pptx-ng-mpresenter-notes\">\n\t\t<div class=\"pptx-ng-mpresenter-label\">{{ 'pptx.presenter.speakerNotes' | translate }}</div>\n\t\t<div class=\"pptx-ng-mpresenter-notes-body\">\n\t\t\t@if (notes().hasRichNotes) {\n\t\t\t\t@for (seg of notes().segments; track seg.key) {\n\t\t\t\t\t@if (seg.isBreak) {\n\t\t\t\t\t\t<br />\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span [ngStyle]=\"seg.style\">{{ seg.text }}</span>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} @else if (notes().hasAnyNotes) {\n\t\t\t\t{{ notes().plainText }}\n\t\t\t} @else {\n\t\t\t\t<span class=\"pptx-ng-mpresenter-notes-empty\">{{\n\t\t\t\t\t'pptx.presenter.noNotes' | translate\n\t\t\t\t}}</span>\n\t\t\t}\n\t\t</div>\n\t</div>\n\n\t<!-- Prev / Next controls -->\n\t<div class=\"pptx-ng-mpresenter-ctl\">\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-mpresenter-navbtn\"\n\t\t\t(click)=\"movePresentationSlide.emit(-1)\"\n\t\t\t[disabled]=\"
|
|
77423
|
+
args: [{ selector: 'pptx-mobile-presenter-view', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgStyle, SlideCanvasComponent, TranslatePipe], template: "@if (currentSlide(); as current) {\n\t<!-- Header: elapsed + counter + exit -->\n\t<div class=\"pptx-ng-mpresenter-header\">\n\t\t<div>\n\t\t\t<div class=\"pptx-ng-mpresenter-label\">{{ 'pptx.presenter.elapsed' | translate }}</div>\n\t\t\t<div class=\"pptx-ng-mpresenter-elapsed\">{{ elapsedLabel() }}</div>\n\t\t</div>\n\t\t<span class=\"pptx-ng-mpresenter-counter\">{{ counterLabel() }}</span>\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-mpresenter-exit\"\n\t\t\t(click)=\"exit.emit()\"\n\t\t\t[attr.aria-label]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t[title]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t>\n\t\t\t✕\n\t\t</button>\n\t</div>\n\n\t<!-- Current slide (large) -->\n\t<div class=\"pptx-ng-mpresenter-main\">\n\t\t<div class=\"pptx-ng-mpresenter-main-stage\">\n\t\t\t<pptx-slide-canvas\n\t\t\t\t[slide]=\"currentPreviewSlide()\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t[zoom]=\"1\"\n\t\t\t\t[interactive]=\"false\"\n\t\t\t/>\n\t\t</div>\n\t</div>\n\n\t<!-- Next thumbnail -->\n\t<div class=\"pptx-ng-mpresenter-next\">\n\t\t<span class=\"pptx-ng-mpresenter-label\">{{\n\t\t\t'pptx.presenter.nextSlidePreview' | translate\n\t\t}}</span>\n\t\t@if (nextPreviewSlide(); as next) {\n\t\t\t<div class=\"pptx-ng-mpresenter-thumb\" [ngStyle]=\"thumbStyle()\">\n\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t[slide]=\"next\"\n\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t} @else {\n\t\t\t<div class=\"pptx-ng-mpresenter-next-empty\">\n\t\t\t\t{{ 'pptx.presenter.endOfPresentation' | translate }}\n\t\t\t</div>\n\t\t}\n\t</div>\n\n\t<!-- Speaker notes (scrollable) -->\n\t<div class=\"pptx-ng-mpresenter-notes\">\n\t\t<div class=\"pptx-ng-mpresenter-label\">{{ 'pptx.presenter.speakerNotes' | translate }}</div>\n\t\t<div class=\"pptx-ng-mpresenter-notes-body\">\n\t\t\t@if (notes().hasRichNotes) {\n\t\t\t\t@for (seg of notes().segments; track seg.key) {\n\t\t\t\t\t@if (seg.isBreak) {\n\t\t\t\t\t\t<br />\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span [ngStyle]=\"seg.style\">{{ seg.text }}</span>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} @else if (notes().hasAnyNotes) {\n\t\t\t\t{{ notes().plainText }}\n\t\t\t} @else {\n\t\t\t\t<span class=\"pptx-ng-mpresenter-notes-empty\">{{\n\t\t\t\t\t'pptx.presenter.noNotes' | translate\n\t\t\t\t}}</span>\n\t\t\t}\n\t\t</div>\n\t</div>\n\n\t<!-- Prev / Next controls -->\n\t<div class=\"pptx-ng-mpresenter-ctl\">\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-mpresenter-navbtn\"\n\t\t\tdata-pptx-presenter-control=\"prev\"\n\t\t\t(click)=\"movePresentationSlide.emit(-1)\"\n\t\t\t[disabled]=\"prevDisabled()\"\n\t\t\t[attr.aria-label]=\"'pptx.presenter.previousSlide' | translate\"\n\t\t\t[title]=\"'pptx.presenter.previousSlide' | translate\"\n\t\t>\n\t\t\t‹ {{ 'pptx.presenter.prev' | translate }}\n\t\t</button>\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-mpresenter-navbtn\"\n\t\t\tdata-pptx-presenter-control=\"next\"\n\t\t\t(click)=\"movePresentationSlide.emit(1)\"\n\t\t\t[disabled]=\"nextDisabled()\"\n\t\t\t[attr.aria-label]=\"'pptx.presenter.nextSlide' | translate\"\n\t\t\t[title]=\"'pptx.presenter.nextSlide' | translate\"\n\t\t>\n\t\t\t{{ 'pptx.presenter.next' | translate }} ›\n\t\t</button>\n\t</div>\n} @else {\n\t<div class=\"pptx-ng-mpresenter-empty\">{{ 'pptx.presenter.noSlides' | translate }}</div>\n}\n", styles: [":host{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;background:#0b0b0c;color:#f5f5f5;font-family:system-ui,sans-serif;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px);padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}.pptx-ng-mpresenter-header,.pptx-ng-mpresenter-next,.pptx-ng-mpresenter-ctl{display:flex;align-items:center;gap:.75rem;padding:.5rem 1rem}.pptx-ng-mpresenter-header{justify-content:space-between;border-bottom:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-label{font-size:.625rem;text-transform:uppercase;letter-spacing:.06em;color:#ffffff8c}.pptx-ng-mpresenter-elapsed{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.125rem;color:#6ea8fe}.pptx-ng-mpresenter-counter{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.875rem}.pptx-ng-mpresenter-exit{display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;min-width:44px;min-height:44px;border:none;border-radius:6px;background:transparent;color:#ffffffbf;cursor:pointer;font-size:1.25rem;line-height:1}.pptx-ng-mpresenter-exit:hover{background:#ffffff1f;color:#fff}.pptx-ng-mpresenter-main{display:flex;align-items:center;justify-content:center;background:#000;padding:.75rem}.pptx-ng-mpresenter-main-stage{width:100%;max-width:640px}.pptx-ng-mpresenter-next{border-bottom:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-thumb{flex:0 0 auto;overflow:hidden;border:1px solid rgba(255,255,255,.15);border-radius:4px}.pptx-ng-mpresenter-next-empty{display:flex;flex:1 1 auto;align-items:center;justify-content:center;height:3rem;border:1px solid rgba(255,255,255,.15);border-radius:4px;background:#ffffff0a;font-size:.625rem;font-style:italic;color:#ffffff80}.pptx-ng-mpresenter-notes{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;padding:.5rem 1rem}.pptx-ng-mpresenter-notes-body{flex:1 1 auto;overflow-y:auto;margin-top:.25rem;border:1px solid rgba(255,255,255,.15);border-radius:6px;background:#ffffff0a;padding:.5rem .75rem;white-space:pre-wrap;line-height:1.5;font-size:15px}.pptx-ng-mpresenter-notes-empty{font-style:italic;color:#ffffff80}.pptx-ng-mpresenter-ctl{justify-content:space-between;border-top:1px solid rgba(255,255,255,.08)}.pptx-ng-mpresenter-navbtn{flex:1 1 0;display:inline-flex;align-items:center;justify-content:center;gap:.375rem;height:44px;border:none;border-radius:6px;background:#ffffff14;color:#f5f5f5;cursor:pointer;font-size:.9rem}.pptx-ng-mpresenter-navbtn:hover:not(:disabled){background:#ffffff29}.pptx-ng-mpresenter-navbtn:disabled{opacity:.4;cursor:not-allowed}.pptx-ng-mpresenter-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff9}\n"] }]
|
|
76455
77424
|
}], ctorParameters: () => [], propDecorators: { slides: [{ type: i0.Input, args: [{ isSignal: true, alias: "slides", required: true }] }], currentSlideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentSlideIndex", required: true }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], templateElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateElements", required: false }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], presentationStartTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "presentationStartTime", required: false }] }], movePresentationSlide: [{ type: i0.Output, args: ["movePresentationSlide"] }], exit: [{ type: i0.Output, args: ["exit"] }] } });
|
|
76456
77425
|
|
|
76457
77426
|
/**
|
|
@@ -80692,6 +81661,19 @@ class PresenterWindowService {
|
|
|
80692
81661
|
isAudienceWindowOpen() {
|
|
80693
81662
|
return this.audienceWindow !== null && !this.audienceWindow.closed;
|
|
80694
81663
|
}
|
|
81664
|
+
/**
|
|
81665
|
+
* PowerPoint's "Swap Displays": trade screens with the audience window.
|
|
81666
|
+
* Counterpart of React's `usePresenterWindow().swapDisplays`. False means no
|
|
81667
|
+
* audience window, or no Window Management API to move windows with; that is
|
|
81668
|
+
* a capability report, not a failure, and nothing moves.
|
|
81669
|
+
*/
|
|
81670
|
+
async swapDisplays() {
|
|
81671
|
+
const audience = this.audienceWindow;
|
|
81672
|
+
if (typeof window === 'undefined' || !audience || audience.closed) {
|
|
81673
|
+
return false;
|
|
81674
|
+
}
|
|
81675
|
+
return swapPresentationWindows(window, audience);
|
|
81676
|
+
}
|
|
80695
81677
|
syncSlideToAudience(slideIndex) {
|
|
80696
81678
|
this.updateSnapshot({ slideIndex });
|
|
80697
81679
|
}
|
|
@@ -83276,7 +84258,11 @@ class PresentationToolbarComponent {
|
|
|
83276
84258
|
...(ngDevMode ? [{ debugName: "now" }] : /* istanbul ignore next */ []));
|
|
83277
84259
|
counterLabel = computed(() => formatSlideCounter(this.currentSlideIndex(), this.totalSlides()), /* @ts-ignore */
|
|
83278
84260
|
...(ngDevMode ? [{ debugName: "counterLabel" }] : /* istanbul ignore next */ []));
|
|
83279
|
-
|
|
84261
|
+
// `elapsedSince` clamps a start time in the future to zero before formatting.
|
|
84262
|
+
// The shared `formatElapsed` deliberately does not clamp (a negative duration
|
|
84263
|
+
// is meaningful to some callers), so the guard belongs here, at the point the
|
|
84264
|
+
// duration is derived from the wall clock.
|
|
84265
|
+
elapsedLabel = computed(() => formatElapsed(elapsedSince(this.presentationStartTime() ?? this.mountedAt, this.now())), /* @ts-ignore */
|
|
83280
84266
|
...(ngDevMode ? [{ debugName: "elapsedLabel" }] : /* istanbul ignore next */ []));
|
|
83281
84267
|
atFirstSlide = computed(() => isAtFirstSlide(this.currentSlideIndex()), /* @ts-ignore */
|
|
83282
84268
|
...(ngDevMode ? [{ debugName: "atFirstSlide" }] : /* istanbul ignore next */ []));
|
|
@@ -84202,7 +85188,7 @@ class PresentationOverlayComponent {
|
|
|
84202
85188
|
this.closed.emit();
|
|
84203
85189
|
}
|
|
84204
85190
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresentationOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
84205
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: PresentationOverlayComponent, isStandalone: true, selector: "pptx-presentation-overlay", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, startIndex: { classPropertyName: "startIndex", publicName: "startIndex", isSignal: true, isRequired: false, transformFunction: null }, showWithAnimation: { classPropertyName: "showWithAnimation", publicName: "showWithAnimation", isSignal: true, isRequired: false, transformFunction: null }, useTimings: { classPropertyName: "useTimings", publicName: "useTimings", isSignal: true, isRequired: false, transformFunction: null }, subtitlesVisible: { classPropertyName: "subtitlesVisible", publicName: "subtitlesVisible", isSignal: true, isRequired: false, transformFunction: null }, sessionEnded: { classPropertyName: "sessionEnded", publicName: "sessionEnded", isSignal: true, isRequired: false, transformFunction: null }, endWithBlackSlide: { classPropertyName: "endWithBlackSlide", publicName: "endWithBlackSlide", isSignal: true, isRequired: false, transformFunction: null }, presenterMode: { classPropertyName: "presenterMode", publicName: "presenterMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { indexChange: "indexChange", closed: "closed", subtitlesChange: "subtitlesChange", presenterViewToggle: "presenterViewToggle", annotationsExit: "annotationsExit" }, host: { listeners: { "document:fullscreenchange": "onFullscreenChange()", "window:resize": "onWindowResize()", "document:keydown": "onKeyDown($event)" } }, providers: [AnimationPlaybackService, PresentationAnnotationsService, ZoomNavigationService], viewQueries: [{ propertyName: "stageRef", first: true, predicate: ["stage"], descendants: true, isSignal: true }, { propertyName: "rootRef", first: true, predicate: ["root"], descendants: true, isSignal: true }], ngImport: i0, template: "<div #root class=\"pptx-ng-presentation-root\">\n\t<!--\n\t\tSlide counter, rendered first in DOM (before slide content) so a\n\t\tgeneric \"N / M\" text query resolves to it rather than to any slide-text\n\t\trun that happens to read like \"24 / 7\". Position is fixed, so DOM order\n\t\tdoes not affect its on-screen placement.\n\t-->\n\t<span class=\"pptx-ng-presentation-counter\" [ngStyle]=\"counterStyle\">\n\t\t{{ counterLabel() }}\n\t</span>\n\n\t<!-- Black \"End of slide show\" screen: the show has run past its last\n\t slide. It MUST be visible - while it is up the next input either\n\t goes nowhere (backward) or ends the show (forward), so a deck that\n\t kept painting the last slide looked stuck and swallowed advances. -->\n\t@if (endOfShow()) {\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-presentation-end\"\n\t\t\tdata-pptx-end-of-show\n\t\t\t(click)=\"onEndScreenClick($event)\"\n\t\t>\n\t\t\t<span>{{ 'pptx.presentation.endOfSlideShow' | translate }}</span>\n\t\t</button>\n\t}\n\n\t<div\n\t\t#stage\n\t\tclass=\"pptx-ng-presentation-stage\"\n\t\t[ngStyle]=\"stageContainerStyle()\"\n\t\t(click)=\"onBodyClick($event)\"\n\t\t(mouseover)=\"onStageHover($event)\"\n\t\t(mouseout)=\"onStageHoverEnd($event)\"\n\t\t(contextmenu)=\"$event.preventDefault()\"\n\t>\n\t\t<pptx-slide-canvas\n\t\t\t[slide]=\"currentSlide()\"\n\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zoom]=\"zoom()\"\n\t\t\t[autoFit]=\"false\"\n\t\t\t[interactive]=\"false\"\n\t\t\t[presenting]=\"true\"\n\t\t/>\n\n\t\t@if (activeTransition(); as t) {\n\t\t\t<pptx-presentation-transition-overlay\n\t\t\t\t[outgoingSlide]=\"t.outgoing\"\n\t\t\t\t[incomingSlide]=\"currentSlide()\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t[transition]=\"t.transition\"\n\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t[zoom]=\"zoom()\"\n\t\t\t\t(complete)=\"activeTransition.set(null)\"\n\t\t\t/>\n\t\t}\n\n\t\t<!-- Ink annotation overlay (pen/highlighter/eraser/laser). Ctrl+M\n\t\t hides the markup without discarding the strokes. -->\n\t\t@if (inkMarkupVisible()) {\n\t\t\t<pptx-presentation-annotation-overlay [canvasSize]=\"canvasSize()\" [zoom]=\"zoom()\" />\n\t\t}\n\t</div>\n\t@if (presenterWindow.snapshot().blackout !== 'none') {\n\t\t<div class=\"presenter-blank\" [style.background]=\"presenterWindow.snapshot().blackout\"></div>\n\t}\n\t@if (presenterWindow.snapshot().pointer?.tool === 'laser') {\n\t\t<div\n\t\t\tclass=\"presenter-laser\"\n\t\t\t[style.left.%]=\"(presenterWindow.snapshot().pointer?.x ?? 0.5) * 100\"\n\t\t\t[style.top.%]=\"(presenterWindow.snapshot().pointer?.y ?? 0.5) * 100\"\n\t\t></div>\n\t}\n\t@if (presenterWindow.snapshot().subtitlesVisible && presenterWindow.snapshot().caption) {\n\t\t<div class=\"presenter-caption\">{{ presenterWindow.snapshot().caption }}</div>\n\t}\n\n\t<!-- Live-caption (subtitle) bar. -->\n\t<pptx-presentation-subtitle-bar [visible]=\"subtitlesVisible()\" />\n\n\t<!--\n\t\tThe show toolbar (bottom-centre, auto-hiding): navigation, counter,\n\t\telapsed time, annotation tools, presenter view and end-show, per\n\t\t`PRESENT_TOOLBAR_CONTROLS` in pptx-viewer-shared.\n\t-->\n\t<pptx-presentation-toolbar\n\t\t[currentSlideIndex]=\"currentIndex()\"\n\t\t[totalSlides]=\"slides().length\"\n\t\t[presentationStartTime]=\"showStartedAt\"\n\t\t[presenterMode]=\"presenterMode()\"\n\t\t(move)=\"navigator.navigate($event === 1 ? 'next' : 'prev')\"\n\t\t(presenterViewToggle)=\"presenterViewToggle.emit()\"\n\t\t(endPresentation)=\"onToolbarEnd()\"\n\t/>\n\n\t<!--\n\t\tTouch-only chrome (close button, edge arrows, counter pill). The\n\t\tcomponent stylesheet hides all three unless the device has a coarse\n\t\tpointer, matching React's `PresentationTouchControls`: on a desktop they\n\t\tduplicate the toolbar above and put a SECOND slide counter on screen.\n\t-->\n\t<!-- Always-visible close button (top-right, safe-area aware). -->\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"pptx-ng-presentation-close\"\n\t\t[ngStyle]=\"closeButtonStyle\"\n\t\t(click)=\"onChromeButton($event, 'close')\"\n\t\t(touchend)=\"onChromeButtonTouch($event, 'close')\"\n\t\t[attr.aria-label]=\"'pptx.presenter.endPresentation' | translate\"\n\t>\n\t\t<svg lucideX class=\"h-5 w-5\"></svg>\n\t</button>\n\n\t<!-- Edge navigation buttons (vertically centred, touch-friendly). -->\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"pptx-ng-presentation-nav pptx-ng-presentation-prev\"\n\t\t[ngStyle]=\"prevButtonStyle\"\n\t\t(click)=\"onChromeButton($event, 'prev')\"\n\t\t(touchend)=\"onChromeButtonTouch($event, 'prev')\"\n\t\t[attr.aria-label]=\"'pptx.presenter.previousSlide' | translate\"\n\t>\n\t\t<svg lucideChevronLeft class=\"h-6 w-6\"></svg>\n\t</button>\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"pptx-ng-presentation-nav pptx-ng-presentation-next\"\n\t\t[ngStyle]=\"nextButtonStyle\"\n\t\t(click)=\"onChromeButton($event, 'next')\"\n\t\t(touchend)=\"onChromeButtonTouch($event, 'next')\"\n\t\t[attr.aria-label]=\"'pptx.presenter.nextSlide' | translate\"\n\t>\n\t\t<svg lucideChevronRight class=\"h-6 w-6\"></svg>\n\t</button>\n</div>\n", styles: [":host{display:block;position:fixed;inset:0;z-index:10000;background:#000;cursor:pointer;-webkit-user-select:none;user-select:none}.pptx-ng-presentation-root{position:absolute;inset:0;touch-action:pan-y}.pptx-ng-presentation-close:hover,.pptx-ng-presentation-nav:hover{background:#000000bf}@media not all and (any-pointer:coarse){.pptx-ng-presentation-close,.pptx-ng-presentation-nav,.pptx-ng-presentation-counter{display:none!important}}.presenter-blank{position:absolute;inset:0;z-index:75}.pptx-ng-presentation-end{position:absolute;inset:0;z-index:90;display:flex;align-items:flex-start;border:0;padding:0;background:#000;text-align:left;cursor:default}.pptx-ng-presentation-end span{padding:.75rem 1rem;color:#ffffffb3;font-size:12px}.presenter-laser{position:absolute;z-index:76;width:20px;height:20px;transform:translate(-50%,-50%);border-radius:50%;background:#ef4444;box-shadow:0 0 20px 8px #ef444488;pointer-events:none}.presenter-caption{position:absolute;z-index:77;left:10%;right:10%;bottom:2rem;padding:.75rem 1.5rem;border-radius:.5rem;background:#000c;color:#fff;text-align:center;font-size:1.25rem;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "rulerUnit", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "transparentBackground", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: PresentationTransitionOverlayComponent, selector: "pptx-presentation-transition-overlay", inputs: ["outgoingSlide", "canvasSize", "transition", "templateElements", "mediaDataUrls", "durationMs", "zoom", "incomingSlide"], outputs: ["complete"] }, { kind: "component", type: PresentationAnnotationOverlayComponent, selector: "pptx-presentation-annotation-overlay", inputs: ["canvasSize", "zoom"] }, { kind: "component", type: PresentationSubtitleBarComponent, selector: "pptx-presentation-subtitle-bar", inputs: ["visible"] }, { kind: "component", type: PresentationToolbarComponent, selector: "pptx-presentation-toolbar", inputs: ["currentSlideIndex", "totalSlides", "presentationStartTime", "presenterMode"], outputs: ["move", "endPresentation", "presenterViewToggle"] }, { kind: "component", type: LucideX, selector: "svg[lucideX]" }, { kind: "component", type: LucideChevronLeft, selector: "svg[lucideChevronLeft]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
85191
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: PresentationOverlayComponent, isStandalone: true, selector: "pptx-presentation-overlay", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, startIndex: { classPropertyName: "startIndex", publicName: "startIndex", isSignal: true, isRequired: false, transformFunction: null }, showWithAnimation: { classPropertyName: "showWithAnimation", publicName: "showWithAnimation", isSignal: true, isRequired: false, transformFunction: null }, useTimings: { classPropertyName: "useTimings", publicName: "useTimings", isSignal: true, isRequired: false, transformFunction: null }, subtitlesVisible: { classPropertyName: "subtitlesVisible", publicName: "subtitlesVisible", isSignal: true, isRequired: false, transformFunction: null }, sessionEnded: { classPropertyName: "sessionEnded", publicName: "sessionEnded", isSignal: true, isRequired: false, transformFunction: null }, endWithBlackSlide: { classPropertyName: "endWithBlackSlide", publicName: "endWithBlackSlide", isSignal: true, isRequired: false, transformFunction: null }, presenterMode: { classPropertyName: "presenterMode", publicName: "presenterMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { indexChange: "indexChange", closed: "closed", subtitlesChange: "subtitlesChange", presenterViewToggle: "presenterViewToggle", annotationsExit: "annotationsExit" }, host: { listeners: { "document:fullscreenchange": "onFullscreenChange()", "window:resize": "onWindowResize()", "document:keydown": "onKeyDown($event)" } }, providers: [AnimationPlaybackService, PresentationAnnotationsService, ZoomNavigationService], viewQueries: [{ propertyName: "stageRef", first: true, predicate: ["stage"], descendants: true, isSignal: true }, { propertyName: "rootRef", first: true, predicate: ["root"], descendants: true, isSignal: true }], ngImport: i0, template: "<div #root class=\"pptx-ng-presentation-root\">\n\t<!--\n\t\tSlide counter, rendered first in DOM (before slide content) so a\n\t\tgeneric \"N / M\" text query resolves to it rather than to any slide-text\n\t\trun that happens to read like \"24 / 7\". Position is fixed, so DOM order\n\t\tdoes not affect its on-screen placement.\n\t-->\n\t<span class=\"pptx-ng-presentation-counter\" [ngStyle]=\"counterStyle\">\n\t\t{{ counterLabel() }}\n\t</span>\n\n\t<!-- Black \"End of slide show\" screen: the show has run past its last\n\t slide. It MUST be visible - while it is up the next input either\n\t goes nowhere (backward) or ends the show (forward), so a deck that\n\t kept painting the last slide looked stuck and swallowed advances. -->\n\t@if (endOfShow()) {\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-presentation-end\"\n\t\t\tdata-pptx-end-of-show\n\t\t\t(click)=\"onEndScreenClick($event)\"\n\t\t>\n\t\t\t<span>{{ 'pptx.presentation.endOfSlideShow' | translate }}</span>\n\t\t</button>\n\t}\n\n\t<div\n\t\t#stage\n\t\tclass=\"pptx-ng-presentation-stage\"\n\t\t[ngStyle]=\"stageContainerStyle()\"\n\t\t(click)=\"onBodyClick($event)\"\n\t\t(mouseover)=\"onStageHover($event)\"\n\t\t(mouseout)=\"onStageHoverEnd($event)\"\n\t\t(contextmenu)=\"$event.preventDefault()\"\n\t>\n\t\t<pptx-slide-canvas\n\t\t\t[slide]=\"currentSlide()\"\n\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zoom]=\"zoom()\"\n\t\t\t[autoFit]=\"false\"\n\t\t\t[interactive]=\"false\"\n\t\t\t[presenting]=\"true\"\n\t\t/>\n\n\t\t@if (activeTransition(); as t) {\n\t\t\t<pptx-presentation-transition-overlay\n\t\t\t\t[outgoingSlide]=\"t.outgoing\"\n\t\t\t\t[incomingSlide]=\"currentSlide()\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t[transition]=\"t.transition\"\n\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t[zoom]=\"zoom()\"\n\t\t\t\t(complete)=\"activeTransition.set(null)\"\n\t\t\t/>\n\t\t}\n\n\t\t<!-- Ink annotation overlay (pen/highlighter/eraser/laser). Ctrl+M\n\t\t hides the markup without discarding the strokes. -->\n\t\t@if (inkMarkupVisible()) {\n\t\t\t<pptx-presentation-annotation-overlay [canvasSize]=\"canvasSize()\" [zoom]=\"zoom()\" />\n\t\t}\n\t</div>\n\t@if (presenterWindow.snapshot().blackout !== 'none') {\n\t\t<div class=\"presenter-blank\" [style.background]=\"presenterWindow.snapshot().blackout\"></div>\n\t}\n\t@if (presenterWindow.snapshot().pointer?.tool === 'laser') {\n\t\t<div\n\t\t\tclass=\"presenter-laser\"\n\t\t\t[style.left.%]=\"(presenterWindow.snapshot().pointer?.x ?? 0.5) * 100\"\n\t\t\t[style.top.%]=\"(presenterWindow.snapshot().pointer?.y ?? 0.5) * 100\"\n\t\t></div>\n\t}\n\t@if (presenterWindow.snapshot().subtitlesVisible && presenterWindow.snapshot().caption) {\n\t\t<div class=\"presenter-caption\">{{ presenterWindow.snapshot().caption }}</div>\n\t}\n\n\t<!-- Live-caption (subtitle) bar. -->\n\t<pptx-presentation-subtitle-bar [visible]=\"subtitlesVisible()\" />\n\n\t<!--\n\t\tTouch-only chrome (close button, edge arrows, counter pill). The\n\t\tcomponent stylesheet hides all three unless the device has a coarse\n\t\tpointer, matching React's `PresentationTouchControls`: on a desktop they\n\t\tduplicate the toolbar above and put a SECOND slide counter on screen.\n\n\t\tRendered BEFORE the show toolbar, as React renders its touch controls,\n\t\tbecause both carry the same accessible names (\"Next Slide\", \"Previous\n\t\tSlide\", \"End Presentation\"). On a coarse pointer the toolbar's copies are\n\t\tstill in the DOM but inert (`pointer-events: none`), so whichever comes\n\t\tfirst is what a by-name lookup - a screen reader's, or a spec's `.first()`\n\t\t- resolves to. With the toolbar first, every such lookup landed on a\n\t\tbutton no user could press: it reported itself visible and enabled, and\n\t\tthe tap was swallowed by the overlay. Position is fixed on all of these,\n\t\tso moving them in the DOM does not move them on screen.\n\t-->\n\t<!-- Always-visible close button (top-right, safe-area aware). -->\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"pptx-ng-presentation-close\"\n\t\t[ngStyle]=\"closeButtonStyle\"\n\t\t(click)=\"onChromeButton($event, 'close')\"\n\t\t(touchend)=\"onChromeButtonTouch($event, 'close')\"\n\t\t[attr.aria-label]=\"'pptx.presenter.endPresentation' | translate\"\n\t>\n\t\t<svg lucideX class=\"h-5 w-5\"></svg>\n\t</button>\n\n\t<!-- Edge navigation buttons (vertically centred, touch-friendly). -->\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"pptx-ng-presentation-nav pptx-ng-presentation-prev\"\n\t\t[ngStyle]=\"prevButtonStyle\"\n\t\t(click)=\"onChromeButton($event, 'prev')\"\n\t\t(touchend)=\"onChromeButtonTouch($event, 'prev')\"\n\t\t[attr.aria-label]=\"'pptx.presenter.previousSlide' | translate\"\n\t>\n\t\t<svg lucideChevronLeft class=\"h-6 w-6\"></svg>\n\t</button>\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"pptx-ng-presentation-nav pptx-ng-presentation-next\"\n\t\t[ngStyle]=\"nextButtonStyle\"\n\t\t(click)=\"onChromeButton($event, 'next')\"\n\t\t(touchend)=\"onChromeButtonTouch($event, 'next')\"\n\t\t[attr.aria-label]=\"'pptx.presenter.nextSlide' | translate\"\n\t>\n\t\t<svg lucideChevronRight class=\"h-6 w-6\"></svg>\n\t</button>\n\n\t<!--\n\t\tThe show toolbar (bottom-centre, auto-hiding): navigation, counter,\n\t\telapsed time, annotation tools, presenter view and end-show, per\n\t\t`PRESENT_TOOLBAR_CONTROLS` in pptx-viewer-shared.\n\t-->\n\t<pptx-presentation-toolbar\n\t\t[currentSlideIndex]=\"currentIndex()\"\n\t\t[totalSlides]=\"slides().length\"\n\t\t[presentationStartTime]=\"showStartedAt\"\n\t\t[presenterMode]=\"presenterMode()\"\n\t\t(move)=\"navigator.navigate($event === 1 ? 'next' : 'prev')\"\n\t\t(presenterViewToggle)=\"presenterViewToggle.emit()\"\n\t\t(endPresentation)=\"onToolbarEnd()\"\n\t/>\n</div>\n", styles: [":host{display:block;position:fixed;inset:0;z-index:10000;background:#000;cursor:pointer;-webkit-user-select:none;user-select:none}.pptx-ng-presentation-root{position:absolute;inset:0;touch-action:pan-y}.pptx-ng-presentation-close:hover,.pptx-ng-presentation-nav:hover{background:#000000bf}@media not all and (any-pointer:coarse){.pptx-ng-presentation-close,.pptx-ng-presentation-nav,.pptx-ng-presentation-counter{display:none!important}}.presenter-blank{position:absolute;inset:0;z-index:75}.pptx-ng-presentation-end{position:absolute;inset:0;z-index:90;display:flex;align-items:flex-start;border:0;padding:0;background:#000;text-align:left;cursor:default}.pptx-ng-presentation-end span{padding:.75rem 1rem;color:#ffffffb3;font-size:12px}.presenter-laser{position:absolute;z-index:76;width:20px;height:20px;transform:translate(-50%,-50%);border-radius:50%;background:#ef4444;box-shadow:0 0 20px 8px #ef444488;pointer-events:none}.presenter-caption{position:absolute;z-index:77;left:10%;right:10%;bottom:2rem;padding:.75rem 1.5rem;border-radius:.5rem;background:#000c;color:#fff;text-align:center;font-size:1.25rem;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "rulerUnit", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "transparentBackground", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: PresentationTransitionOverlayComponent, selector: "pptx-presentation-transition-overlay", inputs: ["outgoingSlide", "canvasSize", "transition", "templateElements", "mediaDataUrls", "durationMs", "zoom", "incomingSlide"], outputs: ["complete"] }, { kind: "component", type: PresentationAnnotationOverlayComponent, selector: "pptx-presentation-annotation-overlay", inputs: ["canvasSize", "zoom"] }, { kind: "component", type: PresentationSubtitleBarComponent, selector: "pptx-presentation-subtitle-bar", inputs: ["visible"] }, { kind: "component", type: PresentationToolbarComponent, selector: "pptx-presentation-toolbar", inputs: ["currentSlideIndex", "totalSlides", "presentationStartTime", "presenterMode"], outputs: ["move", "endPresentation", "presenterViewToggle"] }, { kind: "component", type: LucideX, selector: "svg[lucideX]" }, { kind: "component", type: LucideChevronLeft, selector: "svg[lucideChevronLeft]" }, { kind: "component", type: LucideChevronRight, selector: "svg[lucideChevronRight]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
84206
85192
|
}
|
|
84207
85193
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresentationOverlayComponent, decorators: [{
|
|
84208
85194
|
type: Component,
|
|
@@ -84217,7 +85203,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
84217
85203
|
LucideX,
|
|
84218
85204
|
LucideChevronLeft,
|
|
84219
85205
|
LucideChevronRight,
|
|
84220
|
-
], providers: [AnimationPlaybackService, PresentationAnnotationsService, ZoomNavigationService], template: "<div #root class=\"pptx-ng-presentation-root\">\n\t<!--\n\t\tSlide counter, rendered first in DOM (before slide content) so a\n\t\tgeneric \"N / M\" text query resolves to it rather than to any slide-text\n\t\trun that happens to read like \"24 / 7\". Position is fixed, so DOM order\n\t\tdoes not affect its on-screen placement.\n\t-->\n\t<span class=\"pptx-ng-presentation-counter\" [ngStyle]=\"counterStyle\">\n\t\t{{ counterLabel() }}\n\t</span>\n\n\t<!-- Black \"End of slide show\" screen: the show has run past its last\n\t slide. It MUST be visible - while it is up the next input either\n\t goes nowhere (backward) or ends the show (forward), so a deck that\n\t kept painting the last slide looked stuck and swallowed advances. -->\n\t@if (endOfShow()) {\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-presentation-end\"\n\t\t\tdata-pptx-end-of-show\n\t\t\t(click)=\"onEndScreenClick($event)\"\n\t\t>\n\t\t\t<span>{{ 'pptx.presentation.endOfSlideShow' | translate }}</span>\n\t\t</button>\n\t}\n\n\t<div\n\t\t#stage\n\t\tclass=\"pptx-ng-presentation-stage\"\n\t\t[ngStyle]=\"stageContainerStyle()\"\n\t\t(click)=\"onBodyClick($event)\"\n\t\t(mouseover)=\"onStageHover($event)\"\n\t\t(mouseout)=\"onStageHoverEnd($event)\"\n\t\t(contextmenu)=\"$event.preventDefault()\"\n\t>\n\t\t<pptx-slide-canvas\n\t\t\t[slide]=\"currentSlide()\"\n\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zoom]=\"zoom()\"\n\t\t\t[autoFit]=\"false\"\n\t\t\t[interactive]=\"false\"\n\t\t\t[presenting]=\"true\"\n\t\t/>\n\n\t\t@if (activeTransition(); as t) {\n\t\t\t<pptx-presentation-transition-overlay\n\t\t\t\t[outgoingSlide]=\"t.outgoing\"\n\t\t\t\t[incomingSlide]=\"currentSlide()\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t[transition]=\"t.transition\"\n\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t[zoom]=\"zoom()\"\n\t\t\t\t(complete)=\"activeTransition.set(null)\"\n\t\t\t/>\n\t\t}\n\n\t\t<!-- Ink annotation overlay (pen/highlighter/eraser/laser). Ctrl+M\n\t\t hides the markup without discarding the strokes. -->\n\t\t@if (inkMarkupVisible()) {\n\t\t\t<pptx-presentation-annotation-overlay [canvasSize]=\"canvasSize()\" [zoom]=\"zoom()\" />\n\t\t}\n\t</div>\n\t@if (presenterWindow.snapshot().blackout !== 'none') {\n\t\t<div class=\"presenter-blank\" [style.background]=\"presenterWindow.snapshot().blackout\"></div>\n\t}\n\t@if (presenterWindow.snapshot().pointer?.tool === 'laser') {\n\t\t<div\n\t\t\tclass=\"presenter-laser\"\n\t\t\t[style.left.%]=\"(presenterWindow.snapshot().pointer?.x ?? 0.5) * 100\"\n\t\t\t[style.top.%]=\"(presenterWindow.snapshot().pointer?.y ?? 0.5) * 100\"\n\t\t></div>\n\t}\n\t@if (presenterWindow.snapshot().subtitlesVisible && presenterWindow.snapshot().caption) {\n\t\t<div class=\"presenter-caption\">{{ presenterWindow.snapshot().caption }}</div>\n\t}\n\n\t<!-- Live-caption (subtitle) bar. -->\n\t<pptx-presentation-subtitle-bar [visible]=\"subtitlesVisible()\" />\n\n\t<!--\n\t\
|
|
85206
|
+
], providers: [AnimationPlaybackService, PresentationAnnotationsService, ZoomNavigationService], template: "<div #root class=\"pptx-ng-presentation-root\">\n\t<!--\n\t\tSlide counter, rendered first in DOM (before slide content) so a\n\t\tgeneric \"N / M\" text query resolves to it rather than to any slide-text\n\t\trun that happens to read like \"24 / 7\". Position is fixed, so DOM order\n\t\tdoes not affect its on-screen placement.\n\t-->\n\t<span class=\"pptx-ng-presentation-counter\" [ngStyle]=\"counterStyle\">\n\t\t{{ counterLabel() }}\n\t</span>\n\n\t<!-- Black \"End of slide show\" screen: the show has run past its last\n\t slide. It MUST be visible - while it is up the next input either\n\t goes nowhere (backward) or ends the show (forward), so a deck that\n\t kept painting the last slide looked stuck and swallowed advances. -->\n\t@if (endOfShow()) {\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tclass=\"pptx-ng-presentation-end\"\n\t\t\tdata-pptx-end-of-show\n\t\t\t(click)=\"onEndScreenClick($event)\"\n\t\t>\n\t\t\t<span>{{ 'pptx.presentation.endOfSlideShow' | translate }}</span>\n\t\t</button>\n\t}\n\n\t<div\n\t\t#stage\n\t\tclass=\"pptx-ng-presentation-stage\"\n\t\t[ngStyle]=\"stageContainerStyle()\"\n\t\t(click)=\"onBodyClick($event)\"\n\t\t(mouseover)=\"onStageHover($event)\"\n\t\t(mouseout)=\"onStageHoverEnd($event)\"\n\t\t(contextmenu)=\"$event.preventDefault()\"\n\t>\n\t\t<pptx-slide-canvas\n\t\t\t[slide]=\"currentSlide()\"\n\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zoom]=\"zoom()\"\n\t\t\t[autoFit]=\"false\"\n\t\t\t[interactive]=\"false\"\n\t\t\t[presenting]=\"true\"\n\t\t/>\n\n\t\t@if (activeTransition(); as t) {\n\t\t\t<pptx-presentation-transition-overlay\n\t\t\t\t[outgoingSlide]=\"t.outgoing\"\n\t\t\t\t[incomingSlide]=\"currentSlide()\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t[transition]=\"t.transition\"\n\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t[zoom]=\"zoom()\"\n\t\t\t\t(complete)=\"activeTransition.set(null)\"\n\t\t\t/>\n\t\t}\n\n\t\t<!-- Ink annotation overlay (pen/highlighter/eraser/laser). Ctrl+M\n\t\t hides the markup without discarding the strokes. -->\n\t\t@if (inkMarkupVisible()) {\n\t\t\t<pptx-presentation-annotation-overlay [canvasSize]=\"canvasSize()\" [zoom]=\"zoom()\" />\n\t\t}\n\t</div>\n\t@if (presenterWindow.snapshot().blackout !== 'none') {\n\t\t<div class=\"presenter-blank\" [style.background]=\"presenterWindow.snapshot().blackout\"></div>\n\t}\n\t@if (presenterWindow.snapshot().pointer?.tool === 'laser') {\n\t\t<div\n\t\t\tclass=\"presenter-laser\"\n\t\t\t[style.left.%]=\"(presenterWindow.snapshot().pointer?.x ?? 0.5) * 100\"\n\t\t\t[style.top.%]=\"(presenterWindow.snapshot().pointer?.y ?? 0.5) * 100\"\n\t\t></div>\n\t}\n\t@if (presenterWindow.snapshot().subtitlesVisible && presenterWindow.snapshot().caption) {\n\t\t<div class=\"presenter-caption\">{{ presenterWindow.snapshot().caption }}</div>\n\t}\n\n\t<!-- Live-caption (subtitle) bar. -->\n\t<pptx-presentation-subtitle-bar [visible]=\"subtitlesVisible()\" />\n\n\t<!--\n\t\tTouch-only chrome (close button, edge arrows, counter pill). The\n\t\tcomponent stylesheet hides all three unless the device has a coarse\n\t\tpointer, matching React's `PresentationTouchControls`: on a desktop they\n\t\tduplicate the toolbar above and put a SECOND slide counter on screen.\n\n\t\tRendered BEFORE the show toolbar, as React renders its touch controls,\n\t\tbecause both carry the same accessible names (\"Next Slide\", \"Previous\n\t\tSlide\", \"End Presentation\"). On a coarse pointer the toolbar's copies are\n\t\tstill in the DOM but inert (`pointer-events: none`), so whichever comes\n\t\tfirst is what a by-name lookup - a screen reader's, or a spec's `.first()`\n\t\t- resolves to. With the toolbar first, every such lookup landed on a\n\t\tbutton no user could press: it reported itself visible and enabled, and\n\t\tthe tap was swallowed by the overlay. Position is fixed on all of these,\n\t\tso moving them in the DOM does not move them on screen.\n\t-->\n\t<!-- Always-visible close button (top-right, safe-area aware). -->\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"pptx-ng-presentation-close\"\n\t\t[ngStyle]=\"closeButtonStyle\"\n\t\t(click)=\"onChromeButton($event, 'close')\"\n\t\t(touchend)=\"onChromeButtonTouch($event, 'close')\"\n\t\t[attr.aria-label]=\"'pptx.presenter.endPresentation' | translate\"\n\t>\n\t\t<svg lucideX class=\"h-5 w-5\"></svg>\n\t</button>\n\n\t<!-- Edge navigation buttons (vertically centred, touch-friendly). -->\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"pptx-ng-presentation-nav pptx-ng-presentation-prev\"\n\t\t[ngStyle]=\"prevButtonStyle\"\n\t\t(click)=\"onChromeButton($event, 'prev')\"\n\t\t(touchend)=\"onChromeButtonTouch($event, 'prev')\"\n\t\t[attr.aria-label]=\"'pptx.presenter.previousSlide' | translate\"\n\t>\n\t\t<svg lucideChevronLeft class=\"h-6 w-6\"></svg>\n\t</button>\n\t<button\n\t\ttype=\"button\"\n\t\tclass=\"pptx-ng-presentation-nav pptx-ng-presentation-next\"\n\t\t[ngStyle]=\"nextButtonStyle\"\n\t\t(click)=\"onChromeButton($event, 'next')\"\n\t\t(touchend)=\"onChromeButtonTouch($event, 'next')\"\n\t\t[attr.aria-label]=\"'pptx.presenter.nextSlide' | translate\"\n\t>\n\t\t<svg lucideChevronRight class=\"h-6 w-6\"></svg>\n\t</button>\n\n\t<!--\n\t\tThe show toolbar (bottom-centre, auto-hiding): navigation, counter,\n\t\telapsed time, annotation tools, presenter view and end-show, per\n\t\t`PRESENT_TOOLBAR_CONTROLS` in pptx-viewer-shared.\n\t-->\n\t<pptx-presentation-toolbar\n\t\t[currentSlideIndex]=\"currentIndex()\"\n\t\t[totalSlides]=\"slides().length\"\n\t\t[presentationStartTime]=\"showStartedAt\"\n\t\t[presenterMode]=\"presenterMode()\"\n\t\t(move)=\"navigator.navigate($event === 1 ? 'next' : 'prev')\"\n\t\t(presenterViewToggle)=\"presenterViewToggle.emit()\"\n\t\t(endPresentation)=\"onToolbarEnd()\"\n\t/>\n</div>\n", styles: [":host{display:block;position:fixed;inset:0;z-index:10000;background:#000;cursor:pointer;-webkit-user-select:none;user-select:none}.pptx-ng-presentation-root{position:absolute;inset:0;touch-action:pan-y}.pptx-ng-presentation-close:hover,.pptx-ng-presentation-nav:hover{background:#000000bf}@media not all and (any-pointer:coarse){.pptx-ng-presentation-close,.pptx-ng-presentation-nav,.pptx-ng-presentation-counter{display:none!important}}.presenter-blank{position:absolute;inset:0;z-index:75}.pptx-ng-presentation-end{position:absolute;inset:0;z-index:90;display:flex;align-items:flex-start;border:0;padding:0;background:#000;text-align:left;cursor:default}.pptx-ng-presentation-end span{padding:.75rem 1rem;color:#ffffffb3;font-size:12px}.presenter-laser{position:absolute;z-index:76;width:20px;height:20px;transform:translate(-50%,-50%);border-radius:50%;background:#ef4444;box-shadow:0 0 20px 8px #ef444488;pointer-events:none}.presenter-caption{position:absolute;z-index:77;left:10%;right:10%;bottom:2rem;padding:.75rem 1.5rem;border-radius:.5rem;background:#000c;color:#fff;text-align:center;font-size:1.25rem;pointer-events:none}\n"] }]
|
|
84221
85207
|
}], ctorParameters: () => [], propDecorators: { slides: [{ type: i0.Input, args: [{ isSignal: true, alias: "slides", required: true }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], startIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "startIndex", required: false }] }], showWithAnimation: [{ type: i0.Input, args: [{ isSignal: true, alias: "showWithAnimation", required: false }] }], useTimings: [{ type: i0.Input, args: [{ isSignal: true, alias: "useTimings", required: false }] }], subtitlesVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitlesVisible", required: false }] }], sessionEnded: [{ type: i0.Input, args: [{ isSignal: true, alias: "sessionEnded", required: false }] }], endWithBlackSlide: [{ type: i0.Input, args: [{ isSignal: true, alias: "endWithBlackSlide", required: false }] }], presenterMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "presenterMode", required: false }] }], indexChange: [{ type: i0.Output, args: ["indexChange"] }], closed: [{ type: i0.Output, args: ["closed"] }], subtitlesChange: [{ type: i0.Output, args: ["subtitlesChange"] }], presenterViewToggle: [{ type: i0.Output, args: ["presenterViewToggle"] }], annotationsExit: [{ type: i0.Output, args: ["annotationsExit"] }], stageRef: [{ type: i0.ViewChild, args: ['stage', { isSignal: true }] }], rootRef: [{ type: i0.ViewChild, args: ['root', { isSignal: true }] }], onFullscreenChange: [{
|
|
84222
85208
|
type: HostListener,
|
|
84223
85209
|
args: ['document:fullscreenchange']
|
|
@@ -84229,6 +85215,440 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
84229
85215
|
args: ['document:keydown', ['$event']]
|
|
84230
85216
|
}] } });
|
|
84231
85217
|
|
|
85218
|
+
/**
|
|
85219
|
+
* presenter-console-helpers.ts
|
|
85220
|
+
*
|
|
85221
|
+
* Turns the shared presenter-console INVENTORY
|
|
85222
|
+
* (`PRESENTER_CONSOLE_CONTROLS`) into the per-slot view model the Angular strip
|
|
85223
|
+
* binds to.
|
|
85224
|
+
*
|
|
85225
|
+
* WHY this is a helper and not template logic: the strip used to be an inline
|
|
85226
|
+
* template of sixteen hand-written buttons with hard-coded English labels and no
|
|
85227
|
+
* `translate` pipe in sight, so the console was unreadable in every locale but
|
|
85228
|
+
* one and its black-screen switch announced itself to a screen reader as the
|
|
85229
|
+
* letter "B". Deriving the strip from the shared inventory fixes that at the
|
|
85230
|
+
* source, and keeping the derivation here (rather than in the component) keeps
|
|
85231
|
+
* the SFC-equivalent thin and lets the mapping be unit-tested without TestBed.
|
|
85232
|
+
*
|
|
85233
|
+
* Everything except the click handlers comes from `pptx-viewer-shared`: order,
|
|
85234
|
+
* ids, kinds, label keys, icon names and glyphs. Only "what does pressing this
|
|
85235
|
+
* do" stays in the component, because that is the genuinely per-binding half.
|
|
85236
|
+
*/
|
|
85237
|
+
/**
|
|
85238
|
+
* The four strip slots that select an annotation tool, by control id.
|
|
85239
|
+
*
|
|
85240
|
+
* A lookup rather than four `case` arms because the ids and the tool names are
|
|
85241
|
+
* deliberately identical: if the shared inventory ever renames one, the missing
|
|
85242
|
+
* entry is a compile-visible gap instead of a silently inert button.
|
|
85243
|
+
*/
|
|
85244
|
+
const POINTER_TOOLS = {
|
|
85245
|
+
laser: 'laser',
|
|
85246
|
+
pen: 'pen',
|
|
85247
|
+
highlighter: 'highlighter',
|
|
85248
|
+
eraser: 'eraser',
|
|
85249
|
+
};
|
|
85250
|
+
/**
|
|
85251
|
+
* Whether a slot reads as "on" right now.
|
|
85252
|
+
*
|
|
85253
|
+
* `timer-toggle` and `zoom-in` are buttons, not toggles: their activity only
|
|
85254
|
+
* picks the resume glyph / the emphasised zoom style, and
|
|
85255
|
+
* {@link PresenterConsoleSlot.pressed} keeps `aria-pressed` off them.
|
|
85256
|
+
*/
|
|
85257
|
+
function presenterSlotActive(control, snapshot, audienceOpen) {
|
|
85258
|
+
const tool = POINTER_TOOLS[control.id];
|
|
85259
|
+
if (tool !== undefined) {
|
|
85260
|
+
return (snapshot.pointer?.tool ?? 'none') === tool;
|
|
85261
|
+
}
|
|
85262
|
+
switch (control.id) {
|
|
85263
|
+
case 'timer-toggle':
|
|
85264
|
+
return snapshot.paused;
|
|
85265
|
+
case 'zoom-in':
|
|
85266
|
+
return (snapshot.zoom?.scale ?? 1) > 1;
|
|
85267
|
+
case 'blackout-black':
|
|
85268
|
+
return snapshot.blackout === 'black';
|
|
85269
|
+
case 'blackout-white':
|
|
85270
|
+
return snapshot.blackout === 'white';
|
|
85271
|
+
case 'captions':
|
|
85272
|
+
return snapshot.subtitlesVisible === true;
|
|
85273
|
+
case 'audience':
|
|
85274
|
+
return audienceOpen;
|
|
85275
|
+
default:
|
|
85276
|
+
return false;
|
|
85277
|
+
}
|
|
85278
|
+
}
|
|
85279
|
+
/**
|
|
85280
|
+
* Whether a slot is unusable in the current session.
|
|
85281
|
+
*
|
|
85282
|
+
* Only Swap Displays, which needs a second window to swap with. Notably NOT
|
|
85283
|
+
* Next: see `presenterNextDisabled` in the shared module for why disabling it
|
|
85284
|
+
* strands the presenter on the final slide.
|
|
85285
|
+
*/
|
|
85286
|
+
function presenterSlotDisabled(controlId, audienceOpen) {
|
|
85287
|
+
return controlId === 'swap-displays' && !audienceOpen;
|
|
85288
|
+
}
|
|
85289
|
+
/**
|
|
85290
|
+
* Resolve the whole strip, in the shared inventory's order.
|
|
85291
|
+
*
|
|
85292
|
+
* Dividers and spacers come through as slots too (with no label, icon or
|
|
85293
|
+
* handler) so the template renders one list instead of interleaving two.
|
|
85294
|
+
*/
|
|
85295
|
+
function presenterConsoleSlots(snapshot, audienceOpen) {
|
|
85296
|
+
return PRESENTER_CONSOLE_CONTROLS.map((control) => {
|
|
85297
|
+
const active = presenterSlotActive(control, snapshot, audienceOpen);
|
|
85298
|
+
const isToggle = control.kind === 'toggle';
|
|
85299
|
+
return {
|
|
85300
|
+
control,
|
|
85301
|
+
id: control.id,
|
|
85302
|
+
active,
|
|
85303
|
+
disabled: presenterSlotDisabled(control.id, audienceOpen),
|
|
85304
|
+
labelKey: active && control.activeLabelKey ? control.activeLabelKey : control.labelKey,
|
|
85305
|
+
iconName: active && control.activeIcon ? control.activeIcon : control.icon,
|
|
85306
|
+
pressed: isToggle ? active : null,
|
|
85307
|
+
tool: POINTER_TOOLS[control.id],
|
|
85308
|
+
};
|
|
85309
|
+
});
|
|
85310
|
+
}
|
|
85311
|
+
|
|
85312
|
+
/**
|
|
85313
|
+
* presenter-console-icon.component.ts
|
|
85314
|
+
*
|
|
85315
|
+
* Renders one presenter-console glyph from the kebab-case icon NAME the shared
|
|
85316
|
+
* inventory publishes (`PresenterControl.icon` / `.activeIcon`).
|
|
85317
|
+
*
|
|
85318
|
+
* WHY a component and not an inline `@switch` in the strip: `@lucide/angular`
|
|
85319
|
+
* ships one standalone directive per icon (`svg[lucideZoomIn]`) and no
|
|
85320
|
+
* name-driven host, so the mapping is necessarily sixteen static template arms.
|
|
85321
|
+
* Keeping them here leaves `presenter-controls.component.ts` a thin strip and
|
|
85322
|
+
* keeps both files inside the repo's 300-line ceiling. React does the same
|
|
85323
|
+
* mapping with a `Record<string, IconType>`; this is its Angular half.
|
|
85324
|
+
*
|
|
85325
|
+
* An unknown name renders nothing rather than a fallback glyph: the button
|
|
85326
|
+
* still carries its translated `aria-label`, so a slot added to the shared
|
|
85327
|
+
* inventory before its icon is wired here degrades to an empty (but named and
|
|
85328
|
+
* usable) control instead of a wrong picture.
|
|
85329
|
+
*/
|
|
85330
|
+
class PresenterConsoleIconComponent {
|
|
85331
|
+
/** kebab-case Lucide icon name, straight from the shared inventory. */
|
|
85332
|
+
name = input(undefined, /* @ts-ignore */
|
|
85333
|
+
...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
|
|
85334
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresenterConsoleIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
85335
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: PresenterConsoleIconComponent, isStandalone: true, selector: "pptx-presenter-console-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, ngImport: i0, template: `
|
|
85336
|
+
@switch (name()) {
|
|
85337
|
+
@case ('arrow-left-right') {
|
|
85338
|
+
<svg lucideArrowLeftRight class="h-4 w-4"></svg>
|
|
85339
|
+
}
|
|
85340
|
+
@case ('captions') {
|
|
85341
|
+
<svg lucideCaptions class="h-4 w-4"></svg>
|
|
85342
|
+
}
|
|
85343
|
+
@case ('circle-pause') {
|
|
85344
|
+
<svg lucideCirclePause class="h-4 w-4"></svg>
|
|
85345
|
+
}
|
|
85346
|
+
@case ('circle-play') {
|
|
85347
|
+
<svg lucideCirclePlay class="h-4 w-4"></svg>
|
|
85348
|
+
}
|
|
85349
|
+
@case ('eraser') {
|
|
85350
|
+
<svg lucideEraser class="h-4 w-4"></svg>
|
|
85351
|
+
}
|
|
85352
|
+
@case ('grid-2x2') {
|
|
85353
|
+
<svg lucideGrid2x2 class="h-4 w-4"></svg>
|
|
85354
|
+
}
|
|
85355
|
+
@case ('highlighter') {
|
|
85356
|
+
<svg lucideHighlighter class="h-4 w-4"></svg>
|
|
85357
|
+
}
|
|
85358
|
+
@case ('monitor') {
|
|
85359
|
+
<svg lucideMonitor class="h-4 w-4"></svg>
|
|
85360
|
+
}
|
|
85361
|
+
@case ('monitor-off') {
|
|
85362
|
+
<svg lucideMonitorOff class="h-4 w-4"></svg>
|
|
85363
|
+
}
|
|
85364
|
+
@case ('mouse-pointer-2') {
|
|
85365
|
+
<svg lucideMousePointer2 class="h-4 w-4"></svg>
|
|
85366
|
+
}
|
|
85367
|
+
@case ('pen-tool') {
|
|
85368
|
+
<svg lucidePenTool class="h-4 w-4"></svg>
|
|
85369
|
+
}
|
|
85370
|
+
@case ('rotate-ccw') {
|
|
85371
|
+
<svg lucideRotateCcw class="h-4 w-4"></svg>
|
|
85372
|
+
}
|
|
85373
|
+
@case ('scan') {
|
|
85374
|
+
<svg lucideScan class="h-4 w-4"></svg>
|
|
85375
|
+
}
|
|
85376
|
+
@case ('x') {
|
|
85377
|
+
<svg lucideX class="h-4 w-4"></svg>
|
|
85378
|
+
}
|
|
85379
|
+
@case ('zoom-in') {
|
|
85380
|
+
<svg lucideZoomIn class="h-4 w-4"></svg>
|
|
85381
|
+
}
|
|
85382
|
+
@case ('zoom-out') {
|
|
85383
|
+
<svg lucideZoomOut class="h-4 w-4"></svg>
|
|
85384
|
+
}
|
|
85385
|
+
}
|
|
85386
|
+
`, isInline: true, dependencies: [{ kind: "component", type: LucideArrowLeftRight, selector: "svg[lucideArrowLeftRight]" }, { kind: "component", type: LucideCaptions, selector: "svg[lucideCaptions], svg[lucideSubtitles]" }, { kind: "component", type: LucideCirclePause, selector: "svg[lucideCirclePause], svg[lucidePauseCircle]" }, { kind: "component", type: LucideCirclePlay, selector: "svg[lucideCirclePlay], svg[lucidePlayCircle]" }, { kind: "component", type: LucideEraser, selector: "svg[lucideEraser]" }, { kind: "component", type: LucideGrid2x2, selector: "svg[lucideGrid2x2], svg[lucideGrid2X2]" }, { kind: "component", type: LucideHighlighter, selector: "svg[lucideHighlighter]" }, { kind: "component", type: LucideMonitor, selector: "svg[lucideMonitor]" }, { kind: "component", type: LucideMonitorOff, selector: "svg[lucideMonitorOff]" }, { kind: "component", type: LucideMousePointer2, selector: "svg[lucideMousePointer2]" }, { kind: "component", type: LucidePenTool, selector: "svg[lucidePenTool]" }, { kind: "component", type: LucideRotateCcw, selector: "svg[lucideRotateCcw]" }, { kind: "component", type: LucideScan, selector: "svg[lucideScan]" }, { kind: "component", type: LucideX, selector: "svg[lucideX]" }, { kind: "component", type: LucideZoomIn, selector: "svg[lucideZoomIn]" }, { kind: "component", type: LucideZoomOut, selector: "svg[lucideZoomOut]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
85387
|
+
}
|
|
85388
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresenterConsoleIconComponent, decorators: [{
|
|
85389
|
+
type: Component,
|
|
85390
|
+
args: [{
|
|
85391
|
+
selector: 'pptx-presenter-console-icon',
|
|
85392
|
+
standalone: true,
|
|
85393
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
85394
|
+
host: { class: 'contents' },
|
|
85395
|
+
imports: [
|
|
85396
|
+
LucideArrowLeftRight,
|
|
85397
|
+
LucideCaptions,
|
|
85398
|
+
LucideCirclePause,
|
|
85399
|
+
LucideCirclePlay,
|
|
85400
|
+
LucideEraser,
|
|
85401
|
+
LucideGrid2x2,
|
|
85402
|
+
LucideHighlighter,
|
|
85403
|
+
LucideMonitor,
|
|
85404
|
+
LucideMonitorOff,
|
|
85405
|
+
LucideMousePointer2,
|
|
85406
|
+
LucidePenTool,
|
|
85407
|
+
LucideRotateCcw,
|
|
85408
|
+
LucideScan,
|
|
85409
|
+
LucideX,
|
|
85410
|
+
LucideZoomIn,
|
|
85411
|
+
LucideZoomOut,
|
|
85412
|
+
],
|
|
85413
|
+
template: `
|
|
85414
|
+
@switch (name()) {
|
|
85415
|
+
@case ('arrow-left-right') {
|
|
85416
|
+
<svg lucideArrowLeftRight class="h-4 w-4"></svg>
|
|
85417
|
+
}
|
|
85418
|
+
@case ('captions') {
|
|
85419
|
+
<svg lucideCaptions class="h-4 w-4"></svg>
|
|
85420
|
+
}
|
|
85421
|
+
@case ('circle-pause') {
|
|
85422
|
+
<svg lucideCirclePause class="h-4 w-4"></svg>
|
|
85423
|
+
}
|
|
85424
|
+
@case ('circle-play') {
|
|
85425
|
+
<svg lucideCirclePlay class="h-4 w-4"></svg>
|
|
85426
|
+
}
|
|
85427
|
+
@case ('eraser') {
|
|
85428
|
+
<svg lucideEraser class="h-4 w-4"></svg>
|
|
85429
|
+
}
|
|
85430
|
+
@case ('grid-2x2') {
|
|
85431
|
+
<svg lucideGrid2x2 class="h-4 w-4"></svg>
|
|
85432
|
+
}
|
|
85433
|
+
@case ('highlighter') {
|
|
85434
|
+
<svg lucideHighlighter class="h-4 w-4"></svg>
|
|
85435
|
+
}
|
|
85436
|
+
@case ('monitor') {
|
|
85437
|
+
<svg lucideMonitor class="h-4 w-4"></svg>
|
|
85438
|
+
}
|
|
85439
|
+
@case ('monitor-off') {
|
|
85440
|
+
<svg lucideMonitorOff class="h-4 w-4"></svg>
|
|
85441
|
+
}
|
|
85442
|
+
@case ('mouse-pointer-2') {
|
|
85443
|
+
<svg lucideMousePointer2 class="h-4 w-4"></svg>
|
|
85444
|
+
}
|
|
85445
|
+
@case ('pen-tool') {
|
|
85446
|
+
<svg lucidePenTool class="h-4 w-4"></svg>
|
|
85447
|
+
}
|
|
85448
|
+
@case ('rotate-ccw') {
|
|
85449
|
+
<svg lucideRotateCcw class="h-4 w-4"></svg>
|
|
85450
|
+
}
|
|
85451
|
+
@case ('scan') {
|
|
85452
|
+
<svg lucideScan class="h-4 w-4"></svg>
|
|
85453
|
+
}
|
|
85454
|
+
@case ('x') {
|
|
85455
|
+
<svg lucideX class="h-4 w-4"></svg>
|
|
85456
|
+
}
|
|
85457
|
+
@case ('zoom-in') {
|
|
85458
|
+
<svg lucideZoomIn class="h-4 w-4"></svg>
|
|
85459
|
+
}
|
|
85460
|
+
@case ('zoom-out') {
|
|
85461
|
+
<svg lucideZoomOut class="h-4 w-4"></svg>
|
|
85462
|
+
}
|
|
85463
|
+
}
|
|
85464
|
+
`,
|
|
85465
|
+
}]
|
|
85466
|
+
}], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }] } });
|
|
85467
|
+
|
|
85468
|
+
/**
|
|
85469
|
+
* presenter-slide-navigator.component.ts
|
|
85470
|
+
*
|
|
85471
|
+
* PowerPoint's "See All Slides" overlay, reachable from the presenter console's
|
|
85472
|
+
* grid button. Angular port of React's `PresenterSlideNavigator`.
|
|
85473
|
+
*
|
|
85474
|
+
* Split out of {@link PresenterControlsComponent} so the strip stays a strip:
|
|
85475
|
+
* the overlay is a full-viewport surface with its own heading, grid and close
|
|
85476
|
+
* affordance, and folding it back in pushed that file past the repo's 300-line
|
|
85477
|
+
* ceiling.
|
|
85478
|
+
*
|
|
85479
|
+
* Its three strings used to be hard-coded English here, which made the only way
|
|
85480
|
+
* OUT of the overlay ("Close") unreadable in every other locale. They now
|
|
85481
|
+
* resolve through the shared `PRESENTER_NAVIGATOR_LABEL_KEYS`, as in the other
|
|
85482
|
+
* four bindings, and the grid geometry comes from the shared metrics rather
|
|
85483
|
+
* than a magic 220px repeated per binding.
|
|
85484
|
+
*/
|
|
85485
|
+
class PresenterSlideNavigatorComponent {
|
|
85486
|
+
slides = input.required(/* @ts-ignore */
|
|
85487
|
+
...(ngDevMode ? [{ debugName: "slides" }] : /* istanbul ignore next */ []));
|
|
85488
|
+
current = input.required(/* @ts-ignore */
|
|
85489
|
+
...(ngDevMode ? [{ debugName: "current" }] : /* istanbul ignore next */ []));
|
|
85490
|
+
canvasSize = input.required(/* @ts-ignore */
|
|
85491
|
+
...(ngDevMode ? [{ debugName: "canvasSize" }] : /* istanbul ignore next */ []));
|
|
85492
|
+
mediaDataUrls = input.required(/* @ts-ignore */
|
|
85493
|
+
...(ngDevMode ? [{ debugName: "mediaDataUrls" }] : /* istanbul ignore next */ []));
|
|
85494
|
+
/** Master/layout elements drawn behind every tile, as on the live stage. */
|
|
85495
|
+
templateElements = input([], /* @ts-ignore */
|
|
85496
|
+
...(ngDevMode ? [{ debugName: "templateElements" }] : /* istanbul ignore next */ []));
|
|
85497
|
+
select = output();
|
|
85498
|
+
close = output();
|
|
85499
|
+
classes = PRESENTER_CONSOLE_CLASSES;
|
|
85500
|
+
tileWidth = PRESENTER_LAYOUT_METRICS.navigatorTileWidth;
|
|
85501
|
+
/**
|
|
85502
|
+
* Tile scale. `autoFit` is off (as on every other thumbnail in this package)
|
|
85503
|
+
* so this zoom is the ONLY scale; with auto-fit left on, the two compound and
|
|
85504
|
+
* the tiles shrink to a fraction of the 200px the grid reserves for them.
|
|
85505
|
+
*/
|
|
85506
|
+
tileZoom = computed(() => {
|
|
85507
|
+
const width = this.canvasSize().width;
|
|
85508
|
+
return width > 0 ? this.tileWidth / width : 1;
|
|
85509
|
+
}, /* @ts-ignore */
|
|
85510
|
+
...(ngDevMode ? [{ debugName: "tileZoom" }] : /* istanbul ignore next */ []));
|
|
85511
|
+
tiles = computed(() => {
|
|
85512
|
+
const template = this.templateElements();
|
|
85513
|
+
return this.slides().map((slide, index) => ({
|
|
85514
|
+
slide: template.length > 0 ? { ...slide, elements: [...template, ...slide.elements] } : slide,
|
|
85515
|
+
index,
|
|
85516
|
+
key: slide.id || `slide-${String(index)}`,
|
|
85517
|
+
}));
|
|
85518
|
+
}, /* @ts-ignore */
|
|
85519
|
+
...(ngDevMode ? [{ debugName: "tiles" }] : /* istanbul ignore next */ []));
|
|
85520
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresenterSlideNavigatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
85521
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: PresenterSlideNavigatorComponent, isStandalone: true, selector: "pptx-presenter-slide-navigator", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, current: { classPropertyName: "current", publicName: "current", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: true, transformFunction: null }, templateElements: { classPropertyName: "templateElements", publicName: "templateElements", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { select: "select", close: "close" }, ngImport: i0, template: `
|
|
85522
|
+
<div [class]="classes.navigator + ' text-foreground'" data-pptx-presenter-navigator>
|
|
85523
|
+
<header class="mb-4 flex items-center justify-between border-b border-border pb-4">
|
|
85524
|
+
<div>
|
|
85525
|
+
<p class="text-xs uppercase tracking-[0.22em] text-sky-300">
|
|
85526
|
+
{{ 'pptx.presenter.slideNavigator' | translate }}
|
|
85527
|
+
</p>
|
|
85528
|
+
<h2 class="text-xl font-semibold">
|
|
85529
|
+
{{ 'pptx.presenter.seeAllSlides' | translate }}
|
|
85530
|
+
</h2>
|
|
85531
|
+
</div>
|
|
85532
|
+
<button
|
|
85533
|
+
type="button"
|
|
85534
|
+
class="rounded-md bg-muted px-4 py-2 hover:bg-accent"
|
|
85535
|
+
data-pptx-presenter-control="navigator-close"
|
|
85536
|
+
[attr.aria-label]="'pptx.presenter.closeNavigator' | translate"
|
|
85537
|
+
[title]="'pptx.presenter.closeNavigator' | translate"
|
|
85538
|
+
(click)="close.emit()"
|
|
85539
|
+
>
|
|
85540
|
+
{{ 'pptx.presenter.closeNavigator' | translate }}
|
|
85541
|
+
</button>
|
|
85542
|
+
</header>
|
|
85543
|
+
<div [class]="classes.navigatorGrid">
|
|
85544
|
+
@for (tile of tiles(); track tile.key) {
|
|
85545
|
+
<button
|
|
85546
|
+
type="button"
|
|
85547
|
+
class="group text-left"
|
|
85548
|
+
[class.ring-2]="tile.index === current()"
|
|
85549
|
+
[class.ring-sky-400]="tile.index === current()"
|
|
85550
|
+
[class.opacity-45]="tile.slide.hidden"
|
|
85551
|
+
(click)="select.emit(tile.index)"
|
|
85552
|
+
>
|
|
85553
|
+
<div class="overflow-hidden" [style.width.px]="tileWidth">
|
|
85554
|
+
<pptx-slide-canvas
|
|
85555
|
+
[slide]="tile.slide"
|
|
85556
|
+
[canvasSize]="canvasSize()"
|
|
85557
|
+
[mediaDataUrls]="mediaDataUrls()"
|
|
85558
|
+
[zoom]="tileZoom()"
|
|
85559
|
+
[autoFit]="false"
|
|
85560
|
+
[interactive]="false"
|
|
85561
|
+
/>
|
|
85562
|
+
</div>
|
|
85563
|
+
<span class="mt-2 block text-xs tabular-nums text-muted-foreground">
|
|
85564
|
+
{{ tile.index + 1 }}{{ tile.slide.hidden ? ' - hidden' : '' }}
|
|
85565
|
+
</span>
|
|
85566
|
+
</button>
|
|
85567
|
+
}
|
|
85568
|
+
</div>
|
|
85569
|
+
</div>
|
|
85570
|
+
`, isInline: true, dependencies: [{ kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "rulerUnit", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "transparentBackground", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
85571
|
+
}
|
|
85572
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresenterSlideNavigatorComponent, decorators: [{
|
|
85573
|
+
type: Component,
|
|
85574
|
+
args: [{
|
|
85575
|
+
selector: 'pptx-presenter-slide-navigator',
|
|
85576
|
+
standalone: true,
|
|
85577
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
85578
|
+
imports: [SlideCanvasComponent, TranslatePipe],
|
|
85579
|
+
template: `
|
|
85580
|
+
<div [class]="classes.navigator + ' text-foreground'" data-pptx-presenter-navigator>
|
|
85581
|
+
<header class="mb-4 flex items-center justify-between border-b border-border pb-4">
|
|
85582
|
+
<div>
|
|
85583
|
+
<p class="text-xs uppercase tracking-[0.22em] text-sky-300">
|
|
85584
|
+
{{ 'pptx.presenter.slideNavigator' | translate }}
|
|
85585
|
+
</p>
|
|
85586
|
+
<h2 class="text-xl font-semibold">
|
|
85587
|
+
{{ 'pptx.presenter.seeAllSlides' | translate }}
|
|
85588
|
+
</h2>
|
|
85589
|
+
</div>
|
|
85590
|
+
<button
|
|
85591
|
+
type="button"
|
|
85592
|
+
class="rounded-md bg-muted px-4 py-2 hover:bg-accent"
|
|
85593
|
+
data-pptx-presenter-control="navigator-close"
|
|
85594
|
+
[attr.aria-label]="'pptx.presenter.closeNavigator' | translate"
|
|
85595
|
+
[title]="'pptx.presenter.closeNavigator' | translate"
|
|
85596
|
+
(click)="close.emit()"
|
|
85597
|
+
>
|
|
85598
|
+
{{ 'pptx.presenter.closeNavigator' | translate }}
|
|
85599
|
+
</button>
|
|
85600
|
+
</header>
|
|
85601
|
+
<div [class]="classes.navigatorGrid">
|
|
85602
|
+
@for (tile of tiles(); track tile.key) {
|
|
85603
|
+
<button
|
|
85604
|
+
type="button"
|
|
85605
|
+
class="group text-left"
|
|
85606
|
+
[class.ring-2]="tile.index === current()"
|
|
85607
|
+
[class.ring-sky-400]="tile.index === current()"
|
|
85608
|
+
[class.opacity-45]="tile.slide.hidden"
|
|
85609
|
+
(click)="select.emit(tile.index)"
|
|
85610
|
+
>
|
|
85611
|
+
<div class="overflow-hidden" [style.width.px]="tileWidth">
|
|
85612
|
+
<pptx-slide-canvas
|
|
85613
|
+
[slide]="tile.slide"
|
|
85614
|
+
[canvasSize]="canvasSize()"
|
|
85615
|
+
[mediaDataUrls]="mediaDataUrls()"
|
|
85616
|
+
[zoom]="tileZoom()"
|
|
85617
|
+
[autoFit]="false"
|
|
85618
|
+
[interactive]="false"
|
|
85619
|
+
/>
|
|
85620
|
+
</div>
|
|
85621
|
+
<span class="mt-2 block text-xs tabular-nums text-muted-foreground">
|
|
85622
|
+
{{ tile.index + 1 }}{{ tile.slide.hidden ? ' - hidden' : '' }}
|
|
85623
|
+
</span>
|
|
85624
|
+
</button>
|
|
85625
|
+
}
|
|
85626
|
+
</div>
|
|
85627
|
+
</div>
|
|
85628
|
+
`,
|
|
85629
|
+
}]
|
|
85630
|
+
}], propDecorators: { slides: [{ type: i0.Input, args: [{ isSignal: true, alias: "slides", required: true }] }], current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: true }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: true }] }], templateElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateElements", required: false }] }], select: [{ type: i0.Output, args: ["select"] }], close: [{ type: i0.Output, args: ["close"] }] } });
|
|
85631
|
+
|
|
85632
|
+
/**
|
|
85633
|
+
* presenter-controls.component.ts
|
|
85634
|
+
*
|
|
85635
|
+
* PowerPoint's presenter-console strip, rendered from the SHARED inventory
|
|
85636
|
+
* (`PRESENTER_CONSOLE_CONTROLS`) rather than hand-written.
|
|
85637
|
+
*
|
|
85638
|
+
* The hand-written version is what this replaces, and it had drifted in three
|
|
85639
|
+
* separate ways at once: it hard-coded English in an inline template with no
|
|
85640
|
+
* `translate` pipe anywhere (so the console was unreadable in de/es/fr), it
|
|
85641
|
+
* ordered zoom `-` before `+` where every other binding puts `+` first, and it
|
|
85642
|
+
* called reset-zoom "Fit". Worse, the blackout switches were labelled only by
|
|
85643
|
+
* their `B` / `W` glyph, so a screen reader announced the deck's black-screen
|
|
85644
|
+
* control as the letter "B".
|
|
85645
|
+
*
|
|
85646
|
+
* Now the order, ids, kinds, label keys, icon names, glyphs and Tailwind class
|
|
85647
|
+
* tokens all come from `pptx-viewer-shared`; the only thing left here is what a
|
|
85648
|
+
* press DOES, which is the genuinely per-binding half. Every control carries
|
|
85649
|
+
* `data-pptx-presenter-control` so the cross-binding e2e specs can address the
|
|
85650
|
+
* strip by id instead of by (now translated) name.
|
|
85651
|
+
*/
|
|
84232
85652
|
class PresenterControlsComponent {
|
|
84233
85653
|
snapshot = input.required(/* @ts-ignore */
|
|
84234
85654
|
...(ngDevMode ? [{ debugName: "snapshot" }] : /* istanbul ignore next */ []));
|
|
@@ -84242,23 +85662,85 @@ class PresenterControlsComponent {
|
|
|
84242
85662
|
...(ngDevMode ? [{ debugName: "canvasSize" }] : /* istanbul ignore next */ []));
|
|
84243
85663
|
mediaDataUrls = input.required(/* @ts-ignore */
|
|
84244
85664
|
...(ngDevMode ? [{ debugName: "mediaDataUrls" }] : /* istanbul ignore next */ []));
|
|
85665
|
+
/** Master/layout elements drawn behind every navigator tile. */
|
|
85666
|
+
templateElements = input([], /* @ts-ignore */
|
|
85667
|
+
...(ngDevMode ? [{ debugName: "templateElements" }] : /* istanbul ignore next */ []));
|
|
84245
85668
|
patch = output();
|
|
84246
85669
|
navigate = output();
|
|
84247
85670
|
audience = output();
|
|
85671
|
+
swapDisplays = output();
|
|
84248
85672
|
end = output();
|
|
85673
|
+
classes = PRESENTER_CONSOLE_CLASSES;
|
|
84249
85674
|
showSlides = signal(false, /* @ts-ignore */
|
|
84250
85675
|
...(ngDevMode ? [{ debugName: "showSlides" }] : /* istanbul ignore next */ []));
|
|
84251
|
-
|
|
85676
|
+
slots = computed(() => presenterConsoleSlots(this.snapshot(), this.audienceOpen()), /* @ts-ignore */
|
|
85677
|
+
...(ngDevMode ? [{ debugName: "slots" }] : /* istanbul ignore next */ []));
|
|
85678
|
+
/**
|
|
85679
|
+
* Run a slot's action.
|
|
85680
|
+
*
|
|
85681
|
+
* A slot the shared inventory grows before this switch learns it renders
|
|
85682
|
+
* inert rather than firing a neighbour's handler: a missing behaviour shows
|
|
85683
|
+
* up in the parity specs, a wrong one silently ends the show.
|
|
85684
|
+
*/
|
|
85685
|
+
activate(slot) {
|
|
85686
|
+
if (slot.tool !== undefined) {
|
|
85687
|
+
this.setTool(slot.tool, slot.active);
|
|
85688
|
+
return;
|
|
85689
|
+
}
|
|
85690
|
+
switch (slot.id) {
|
|
85691
|
+
case 'timer-toggle':
|
|
85692
|
+
this.patch.emit({ paused: !this.snapshot().paused });
|
|
85693
|
+
break;
|
|
85694
|
+
case 'timer-reset':
|
|
85695
|
+
this.patch.emit({ paused: false, elapsedMs: 0 });
|
|
85696
|
+
break;
|
|
85697
|
+
case 'all-slides':
|
|
85698
|
+
this.showSlides.set(true);
|
|
85699
|
+
break;
|
|
85700
|
+
case 'zoom-in':
|
|
85701
|
+
this.zoom(1);
|
|
85702
|
+
break;
|
|
85703
|
+
case 'zoom-out':
|
|
85704
|
+
this.zoom(-1);
|
|
85705
|
+
break;
|
|
85706
|
+
case 'zoom-reset':
|
|
85707
|
+
this.patch.emit({ zoom: { scale: 1, originX: 0.5, originY: 0.5 } });
|
|
85708
|
+
break;
|
|
85709
|
+
case 'blackout-black':
|
|
85710
|
+
this.toggleBlank('black');
|
|
85711
|
+
break;
|
|
85712
|
+
case 'blackout-white':
|
|
85713
|
+
this.toggleBlank('white');
|
|
85714
|
+
break;
|
|
85715
|
+
case 'captions':
|
|
85716
|
+
this.patch.emit({ subtitlesVisible: !this.snapshot().subtitlesVisible });
|
|
85717
|
+
break;
|
|
85718
|
+
case 'audience':
|
|
85719
|
+
this.audience.emit();
|
|
85720
|
+
break;
|
|
85721
|
+
case 'swap-displays':
|
|
85722
|
+
this.swapDisplays.emit();
|
|
85723
|
+
break;
|
|
85724
|
+
case 'end':
|
|
85725
|
+
this.end.emit();
|
|
85726
|
+
break;
|
|
85727
|
+
default:
|
|
85728
|
+
break;
|
|
85729
|
+
}
|
|
85730
|
+
}
|
|
84252
85731
|
zoom(direction) {
|
|
84253
85732
|
this.patch.emit({
|
|
84254
85733
|
zoom: stepPresenterZoom(this.snapshot().zoom ?? { scale: 1, originX: 0.5, originY: 0.5 }, direction),
|
|
84255
85734
|
});
|
|
84256
85735
|
}
|
|
84257
|
-
setTool(tool) {
|
|
85736
|
+
setTool(tool, active) {
|
|
85737
|
+
if (tool === undefined) {
|
|
85738
|
+
return;
|
|
85739
|
+
}
|
|
84258
85740
|
this.patch.emit({
|
|
84259
85741
|
pointer: {
|
|
84260
85742
|
...(this.snapshot().pointer ?? { x: 0.5, y: 0.5, color: '#ef4444' }),
|
|
84261
|
-
tool:
|
|
85743
|
+
tool: active ? 'none' : tool,
|
|
84262
85744
|
},
|
|
84263
85745
|
});
|
|
84264
85746
|
}
|
|
@@ -84270,38 +85752,88 @@ class PresenterControlsComponent {
|
|
|
84270
85752
|
this.showSlides.set(false);
|
|
84271
85753
|
}
|
|
84272
85754
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresenterControlsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
84273
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: PresenterControlsComponent, isStandalone: true, selector: "pptx-presenter-controls", inputs: { snapshot: { classPropertyName: "snapshot", publicName: "snapshot", isSignal: true, isRequired: true, transformFunction: null }, audienceOpen: { classPropertyName: "audienceOpen", publicName: "audienceOpen", isSignal: true, isRequired: false, transformFunction: null }, slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, current: { classPropertyName: "current", publicName: "current", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { patch: "patch", navigate: "navigate", audience: "audience", end: "end" }, ngImport: i0, template: `
|
|
84274
|
-
<div class="strip">
|
|
84275
|
-
|
|
84276
|
-
|
|
84277
|
-
|
|
84278
|
-
|
|
84279
|
-
|
|
85755
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: PresenterControlsComponent, isStandalone: true, selector: "pptx-presenter-controls", inputs: { snapshot: { classPropertyName: "snapshot", publicName: "snapshot", isSignal: true, isRequired: true, transformFunction: null }, audienceOpen: { classPropertyName: "audienceOpen", publicName: "audienceOpen", isSignal: true, isRequired: false, transformFunction: null }, slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, current: { classPropertyName: "current", publicName: "current", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: true, transformFunction: null }, templateElements: { classPropertyName: "templateElements", publicName: "templateElements", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { patch: "patch", navigate: "navigate", audience: "audience", swapDisplays: "swapDisplays", end: "end" }, ngImport: i0, template: `
|
|
85756
|
+
<div [class]="classes.strip" data-pptx-presenter-toolbar>
|
|
85757
|
+
@for (slot of slots(); track slot.id) {
|
|
85758
|
+
@if (slot.control.kind === 'divider' || slot.control.kind === 'spacer') {
|
|
85759
|
+
<span
|
|
85760
|
+
[attr.data-pptx-presenter-control]="slot.id"
|
|
85761
|
+
[class]="slot.control.kind === 'divider' ? classes.divider : classes.spacer"
|
|
85762
|
+
></span>
|
|
85763
|
+
} @else {
|
|
85764
|
+
<button
|
|
85765
|
+
type="button"
|
|
85766
|
+
[attr.data-pptx-presenter-control]="slot.id"
|
|
85767
|
+
[class]="slot.active ? classes.controlActive : classes.control"
|
|
85768
|
+
[disabled]="slot.disabled"
|
|
85769
|
+
[attr.aria-pressed]="slot.pressed"
|
|
85770
|
+
[attr.aria-label]="slot.labelKey ? (slot.labelKey | translate) : null"
|
|
85771
|
+
[title]="slot.labelKey ? (slot.labelKey | translate) : ''"
|
|
85772
|
+
(click)="activate(slot)"
|
|
85773
|
+
>
|
|
85774
|
+
<pptx-presenter-console-icon [name]="slot.iconName" />
|
|
85775
|
+
@if (slot.control.glyph) {
|
|
85776
|
+
<span aria-hidden="true">{{ slot.control.glyph }}</span>
|
|
85777
|
+
}
|
|
85778
|
+
</button>
|
|
85779
|
+
}
|
|
85780
|
+
}
|
|
84280
85781
|
</div>
|
|
84281
|
-
@if(showSlides()){
|
|
84282
|
-
<
|
|
84283
|
-
|
|
84284
|
-
|
|
85782
|
+
@if (showSlides()) {
|
|
85783
|
+
<pptx-presenter-slide-navigator
|
|
85784
|
+
[slides]="slides()"
|
|
85785
|
+
[current]="current()"
|
|
85786
|
+
[canvasSize]="canvasSize()"
|
|
85787
|
+
[mediaDataUrls]="mediaDataUrls()"
|
|
85788
|
+
[templateElements]="templateElements()"
|
|
85789
|
+
(select)="select($event)"
|
|
85790
|
+
(close)="showSlides.set(false)"
|
|
85791
|
+
/>
|
|
84285
85792
|
}
|
|
84286
|
-
`, isInline: true, styles: [":host{display:block}
|
|
85793
|
+
`, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: PresenterConsoleIconComponent, selector: "pptx-presenter-console-icon", inputs: ["name"] }, { kind: "component", type: PresenterSlideNavigatorComponent, selector: "pptx-presenter-slide-navigator", inputs: ["slides", "current", "canvasSize", "mediaDataUrls", "templateElements"], outputs: ["select", "close"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
84287
85794
|
}
|
|
84288
85795
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresenterControlsComponent, decorators: [{
|
|
84289
85796
|
type: Component,
|
|
84290
|
-
args: [{ selector: 'pptx-presenter-controls', standalone: true, imports: [
|
|
84291
|
-
<div class="strip">
|
|
84292
|
-
|
|
84293
|
-
|
|
84294
|
-
|
|
84295
|
-
|
|
84296
|
-
|
|
85797
|
+
args: [{ selector: 'pptx-presenter-controls', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslatePipe, PresenterConsoleIconComponent, PresenterSlideNavigatorComponent], template: `
|
|
85798
|
+
<div [class]="classes.strip" data-pptx-presenter-toolbar>
|
|
85799
|
+
@for (slot of slots(); track slot.id) {
|
|
85800
|
+
@if (slot.control.kind === 'divider' || slot.control.kind === 'spacer') {
|
|
85801
|
+
<span
|
|
85802
|
+
[attr.data-pptx-presenter-control]="slot.id"
|
|
85803
|
+
[class]="slot.control.kind === 'divider' ? classes.divider : classes.spacer"
|
|
85804
|
+
></span>
|
|
85805
|
+
} @else {
|
|
85806
|
+
<button
|
|
85807
|
+
type="button"
|
|
85808
|
+
[attr.data-pptx-presenter-control]="slot.id"
|
|
85809
|
+
[class]="slot.active ? classes.controlActive : classes.control"
|
|
85810
|
+
[disabled]="slot.disabled"
|
|
85811
|
+
[attr.aria-pressed]="slot.pressed"
|
|
85812
|
+
[attr.aria-label]="slot.labelKey ? (slot.labelKey | translate) : null"
|
|
85813
|
+
[title]="slot.labelKey ? (slot.labelKey | translate) : ''"
|
|
85814
|
+
(click)="activate(slot)"
|
|
85815
|
+
>
|
|
85816
|
+
<pptx-presenter-console-icon [name]="slot.iconName" />
|
|
85817
|
+
@if (slot.control.glyph) {
|
|
85818
|
+
<span aria-hidden="true">{{ slot.control.glyph }}</span>
|
|
85819
|
+
}
|
|
85820
|
+
</button>
|
|
85821
|
+
}
|
|
85822
|
+
}
|
|
84297
85823
|
</div>
|
|
84298
|
-
@if(showSlides()){
|
|
84299
|
-
<
|
|
84300
|
-
|
|
84301
|
-
|
|
85824
|
+
@if (showSlides()) {
|
|
85825
|
+
<pptx-presenter-slide-navigator
|
|
85826
|
+
[slides]="slides()"
|
|
85827
|
+
[current]="current()"
|
|
85828
|
+
[canvasSize]="canvasSize()"
|
|
85829
|
+
[mediaDataUrls]="mediaDataUrls()"
|
|
85830
|
+
[templateElements]="templateElements()"
|
|
85831
|
+
(select)="select($event)"
|
|
85832
|
+
(close)="showSlides.set(false)"
|
|
85833
|
+
/>
|
|
84302
85834
|
}
|
|
84303
|
-
`, styles: [":host{display:block}
|
|
84304
|
-
}], propDecorators: { snapshot: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapshot", required: true }] }], audienceOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "audienceOpen", required: false }] }], slides: [{ type: i0.Input, args: [{ isSignal: true, alias: "slides", required: true }] }], current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: true }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: true }] }], patch: [{ type: i0.Output, args: ["patch"] }], navigate: [{ type: i0.Output, args: ["navigate"] }], audience: [{ type: i0.Output, args: ["audience"] }], end: [{ type: i0.Output, args: ["end"] }] } });
|
|
85835
|
+
`, styles: [":host{display:block}\n"] }]
|
|
85836
|
+
}], propDecorators: { snapshot: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapshot", required: true }] }], audienceOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "audienceOpen", required: false }] }], slides: [{ type: i0.Input, args: [{ isSignal: true, alias: "slides", required: true }] }], current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: true }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: true }] }], templateElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateElements", required: false }] }], patch: [{ type: i0.Output, args: ["patch"] }], navigate: [{ type: i0.Output, args: ["navigate"] }], audience: [{ type: i0.Output, args: ["audience"] }], swapDisplays: [{ type: i0.Output, args: ["swapDisplays"] }], end: [{ type: i0.Output, args: ["end"] }] } });
|
|
84305
85837
|
|
|
84306
85838
|
/** Clock tick interval (ms) for the current-time / elapsed display. */
|
|
84307
85839
|
const CLOCK_TICK_MS = 1000;
|
|
@@ -84400,8 +85932,41 @@ class PresenterViewComponent {
|
|
|
84400
85932
|
...(ngDevMode ? [{ debugName: "elapsedMs" }] : /* istanbul ignore next */ []));
|
|
84401
85933
|
elapsedLabel = computed(() => formatElapsed(this.elapsedMs()), /* @ts-ignore */
|
|
84402
85934
|
...(ngDevMode ? [{ debugName: "elapsedLabel" }] : /* istanbul ignore next */ []));
|
|
84403
|
-
timerProgress = computed(() =>
|
|
85935
|
+
timerProgress = computed(() => presenterTimerProgress(this.elapsedMs()), /* @ts-ignore */
|
|
84404
85936
|
...(ngDevMode ? [{ debugName: "timerProgress" }] : /* istanbul ignore next */ []));
|
|
85937
|
+
/**
|
|
85938
|
+
* Whether Previous / Next are unusable, straight from the shared rule.
|
|
85939
|
+
*
|
|
85940
|
+
* Next is NEVER disabled: PowerPoint's console advances from the last slide
|
|
85941
|
+
* to the end-of-show screen and then out of the show, so gating it on
|
|
85942
|
+
* `index >= slides.length - 1` (as this component used to) strands the
|
|
85943
|
+
* presenter on the final slide with no way to finish, and the audience
|
|
85944
|
+
* display never closes either.
|
|
85945
|
+
*/
|
|
85946
|
+
prevDisabled = computed(() => presenterPrevDisabled(this.currentSlideIndex()), /* @ts-ignore */
|
|
85947
|
+
...(ngDevMode ? [{ debugName: "prevDisabled" }] : /* istanbul ignore next */ []));
|
|
85948
|
+
nextDisabled = computed(() => presenterNextDisabled(), /* @ts-ignore */
|
|
85949
|
+
...(ngDevMode ? [{ debugName: "nextDisabled" }] : /* istanbul ignore next */ []));
|
|
85950
|
+
/**
|
|
85951
|
+
* The console zoom, applied to the current-slide pane.
|
|
85952
|
+
*
|
|
85953
|
+
* The pane used to hard-code `[zoom]="1"`, so the strip's zoom buttons
|
|
85954
|
+
* mutated the snapshot (and the audience display honoured it) while the
|
|
85955
|
+
* presenter's own pane never moved a pixel. Scaling the STAGE wrapper rather
|
|
85956
|
+
* than the canvas mirrors React's `PresenterSlideFrame`: the canvas keeps
|
|
85957
|
+
* auto-fitting its (layout-measured, transform-immune) viewport, and the
|
|
85958
|
+
* zoom rides on top of that fit about the snapshot's focal point.
|
|
85959
|
+
*/
|
|
85960
|
+
previewStageStyle = computed(() => {
|
|
85961
|
+
const zoom = this.presenterWindow.snapshot().zoom;
|
|
85962
|
+
const originX = (zoom?.originX ?? 0.5) * 100;
|
|
85963
|
+
const originY = (zoom?.originY ?? 0.5) * 100;
|
|
85964
|
+
return {
|
|
85965
|
+
transform: `scale(${zoom?.scale ?? 1})`,
|
|
85966
|
+
'transform-origin': `${originX}% ${originY}%`,
|
|
85967
|
+
};
|
|
85968
|
+
}, /* @ts-ignore */
|
|
85969
|
+
...(ngDevMode ? [{ debugName: "previewStageStyle" }] : /* istanbul ignore next */ []));
|
|
84405
85970
|
timerPercent = computed(() => this.timerProgress().percent, /* @ts-ignore */
|
|
84406
85971
|
...(ngDevMode ? [{ debugName: "timerPercent" }] : /* istanbul ignore next */ []));
|
|
84407
85972
|
progressValue = computed(() => Math.round(this.timerProgress().percent), /* @ts-ignore */
|
|
@@ -84445,6 +86010,15 @@ class PresenterViewComponent {
|
|
|
84445
86010
|
this.openAudienceWindow.emit();
|
|
84446
86011
|
}
|
|
84447
86012
|
}
|
|
86013
|
+
/**
|
|
86014
|
+
* Move the console onto the audience's screen and vice versa (PowerPoint's
|
|
86015
|
+
* "Swap Displays"). Best-effort: the underlying Window Management API is not
|
|
86016
|
+
* universally available, so a `false` result is not an error, it is a browser
|
|
86017
|
+
* that will not move windows for us.
|
|
86018
|
+
*/
|
|
86019
|
+
onSwapDisplays() {
|
|
86020
|
+
void this.presenterWindow.swapDisplays();
|
|
86021
|
+
}
|
|
84448
86022
|
// ------------------------------------------------------------------
|
|
84449
86023
|
// Helpers
|
|
84450
86024
|
// ------------------------------------------------------------------
|
|
@@ -84459,11 +86033,11 @@ class PresenterViewComponent {
|
|
|
84459
86033
|
return { ...slide, elements: [...template, ...slide.elements] };
|
|
84460
86034
|
}
|
|
84461
86035
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresenterViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
84462
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: PresenterViewComponent, isStandalone: true, selector: "pptx-presenter-view", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, currentSlideIndex: { classPropertyName: "currentSlideIndex", publicName: "currentSlideIndex", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, templateElements: { classPropertyName: "templateElements", publicName: "templateElements", isSignal: true, isRequired: false, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, presentationStartTime: { classPropertyName: "presentationStartTime", publicName: "presentationStartTime", isSignal: true, isRequired: false, transformFunction: null }, isAudienceWindowOpen: { classPropertyName: "isAudienceWindowOpen", publicName: "isAudienceWindowOpen", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { movePresentationSlide: "movePresentationSlide", exit: "exit", openAudienceWindow: "openAudienceWindow", closeAudienceWindow: "closeAudienceWindow", navigateToSlide: "navigateToSlide" }, ngImport: i0, template: "@if (currentSlide(); as current) {\n\t<pptx-presenter-controls\n\t\t[snapshot]=\"presenterWindow.snapshot()\"\n\t\t[audienceOpen]=\"isAudienceWindowOpen()\"\n\t\t[slides]=\"slides()\"\n\t\t[current]=\"currentSlideIndex()\"\n\t\t[canvasSize]=\"canvasSize()\"\n\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t(patch)=\"presenterWindow.updateSnapshot($event)\"\n\t\t(navigate)=\"navigateToSlide.emit($event)\"\n\t\t(audience)=\"onToggleAudienceWindow()\"\n\t\t(end)=\"exit.emit()\"\n\t/>\n\t<div class=\"pptx-ng-presenter-body\">\n\t\t<!-- Current slide (\u224870%) -->\n\t\t<div\n\t\t\tclass=\"pptx-ng-presenter-current\"\n\t\t\t[class.pptx-ng-presenter-current--advances]=\"paneAdvancesOnClick()\"\n\t\t\trole=\"presentation\"\n\t\t\tdata-pptx-presenter-slide\n\t\t\t(click)=\"onSlidePaneClick()\"\n\t\t>\n\t\t\t<div class=\"pptx-ng-presenter-preview-stage\">\n\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t[slide]=\"currentPreviewSlide()\"\n\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div class=\"pptx-ng-presenter-slide-badge\">{{ slideBadge() }}</div>\n\t\t</div>\n\n\t\t<!-- Controls (\u224830%) -->\n\t\t<div class=\"pptx-ng-presenter-side\">\n\t\t\t<!-- Header: clock + elapsed + window/exit -->\n\t\t\t<div class=\"pptx-ng-presenter-header\">\n\t\t\t\t<div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">\n\t\t\t\t\t\t{{ 'pptx.presenter.currentTime' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-clock\">{{ clockLabel() }}</div>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">{{ 'pptx.presenter.elapsed' | translate }}</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-clock pptx-ng-presenter-elapsed\">\n\t\t\t\t\t\t{{ elapsedLabel() }}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"display: flex; align-items: center; gap: 0.25rem\">\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t(click)=\"onToggleAudienceWindow()\"\n\t\t\t\t\t\t[attr.aria-label]=\"\n\t\t\t\t\t\t\t(isAudienceWindowOpen()\n\t\t\t\t\t\t\t\t? 'pptx.presenter.closeAudienceWindow'\n\t\t\t\t\t\t\t\t: 'pptx.presenter.openAudienceWindow'\n\t\t\t\t\t\t\t) | translate\n\t\t\t\t\t\t\"\n\t\t\t\t\t\t[title]=\"\n\t\t\t\t\t\t\t(isAudienceWindowOpen()\n\t\t\t\t\t\t\t\t? 'pptx.presenter.closeAudienceWindow'\n\t\t\t\t\t\t\t\t: 'pptx.presenter.openAudienceWindow'\n\t\t\t\t\t\t\t) | translate\n\t\t\t\t\t\t\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{{ isAudienceWindowOpen() ? '\u25A3' : '\u25A1' }}\n\t\t\t\t\t</button>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t(click)=\"exit.emit()\"\n\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t\t\t\t[title]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t\t\t>\n\t\t\t\t\t\t✕\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- Navigation -->\n\t\t\t<div class=\"pptx-ng-presenter-nav\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-presenter-navbtn\"\n\t\t\t\t\t(click)=\"movePresentationSlide.emit(-1)\"\n\t\t\t\t\t[disabled]=\"currentSlideIndex() === 0\"\n\t\t\t\t\t[title]=\"'pptx.presenter.previousSlide' | translate\"\n\t\t\t\t>\n\t\t\t\t\t‹ {{ 'pptx.presenter.prev' | translate }}\n\t\t\t\t</button>\n\t\t\t\t<span class=\"pptx-ng-presenter-counter\">{{ counterLabel() }}</span>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-presenter-navbtn\"\n\t\t\t\t\t(click)=\"movePresentationSlide.emit(1)\"\n\t\t\t\t\t[disabled]=\"currentSlideIndex() >= slides().length - 1\"\n\t\t\t\t\t[title]=\"'pptx.presenter.nextSlide' | translate\"\n\t\t\t\t>\n\t\t\t\t\t{{ 'pptx.presenter.next' | translate }} ›\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t<!-- Next slide preview -->\n\t\t\t<div class=\"pptx-ng-presenter-next\">\n\t\t\t\t<div class=\"pptx-ng-presenter-label\" style=\"margin-bottom: 0.5rem\">\n\t\t\t\t\t{{ 'pptx.presenter.nextSlidePreview' | translate }}\n\t\t\t\t</div>\n\t\t\t\t@if (nextPreviewSlide(); as next) {\n\t\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t\t[slide]=\"next\"\n\t\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t\t/>\n\t\t\t\t} @else {\n\t\t\t\t\t<div class=\"pptx-ng-presenter-next-empty\">\n\t\t\t\t\t\t{{ 'pptx.presenter.endOfPresentation' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t<!-- Speaker notes -->\n\t\t\t<div class=\"pptx-ng-presenter-notes\">\n\t\t\t\t<div class=\"pptx-ng-presenter-notes-head\">\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">\n\t\t\t\t\t\t{{ 'pptx.presenter.speakerNotes' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-notes-size\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t\t(click)=\"decreaseNotesFontSize()\"\n\t\t\t\t\t\t\t[disabled]=\"notesFontSize() <= NOTES_FONT_SIZE_MIN\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.decreaseFontSize' | translate\"\n\t\t\t\t\t\t\t[title]=\"'pptx.presenter.decreaseFontSize' | translate\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t−\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<span class=\"pptx-ng-presenter-notes-size-value\">{{ notesFontSize() }}px</span>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t\t(click)=\"increaseNotesFontSize()\"\n\t\t\t\t\t\t\t[disabled]=\"notesFontSize() >= NOTES_FONT_SIZE_MAX\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.increaseFontSize' | translate\"\n\t\t\t\t\t\t\t[title]=\"'pptx.presenter.increaseFontSize' | translate\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t+\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"pptx-ng-presenter-notes-body\" [ngStyle]=\"notesBodyStyle()\">\n\t\t\t\t\t@if (notes().hasRichNotes) {\n\t\t\t\t\t\t@for (seg of notes().segments; track seg.key) {\n\t\t\t\t\t\t\t@if (seg.isBreak) {\n\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<span [ngStyle]=\"seg.style\">{{ seg.text }}</span>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} @else if (notes().hasAnyNotes) {\n\t\t\t\t\t\t{{ notes().plainText }}\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span class=\"pptx-ng-presenter-notes-empty\">\n\t\t\t\t\t\t\t{{ 'pptx.presenter.noNotes' | translate }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n\t<!-- Timer progress bar -->\n\t<div\n\t\tclass=\"pptx-ng-presenter-progress\"\n\t\trole=\"progressbar\"\n\t\t[attr.aria-valuenow]=\"progressValue()\"\n\t\taria-valuemin=\"0\"\n\t\taria-valuemax=\"100\"\n\t\t[attr.aria-label]=\"'pptx.presenter.timerProgress' | translate\"\n\t>\n\t\t<div class=\"pptx-ng-presenter-progress-fill\" [style.width.%]=\"timerPercent()\"></div>\n\t</div>\n} @else {\n\t<div class=\"pptx-ng-presenter-empty\">{{ 'pptx.presenter.noSlides' | translate }}</div>\n}\n", styles: [":host{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;background:var(--pptx-card, #0b0b0c);color:var(--pptx-foreground, #f5f5f5);font-family:system-ui,sans-serif}.pptx-ng-presenter-body{display:flex;flex:1 1 auto;min-height:0}.pptx-ng-presenter-current--advances{cursor:pointer}.pptx-ng-presenter-current{flex:7 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#000;padding:1rem;min-width:0}.pptx-ng-presenter-preview-stage{width:100%;max-width:100%;min-height:0}.pptx-ng-presenter-slide-badge{margin-top:.5rem;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.75rem;color:#ffffff80;-webkit-user-select:none;user-select:none}.pptx-ng-presenter-side{flex:3 1 0;display:flex;flex-direction:column;background:var(--pptx-background, #18181b);border-left:1px solid var(--pptx-border, rgba(255, 255, 255, .12));min-width:260px;max-width:440px}.pptx-ng-presenter-header,.pptx-ng-presenter-nav,.pptx-ng-presenter-next{padding:.5rem 1rem;border-bottom:1px solid var(--pptx-border, rgba(255, 255, 255, .12))}.pptx-ng-presenter-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem}.pptx-ng-presenter-label{font-size:.625rem;text-transform:uppercase;letter-spacing:.06em;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .55))}.pptx-ng-presenter-clock{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.125rem}.pptx-ng-presenter-elapsed{color:var(--pptx-primary, #6ea8fe)}.pptx-ng-presenter-iconbtn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;border-radius:6px;background:transparent;color:var(--pptx-foreground, rgba(255, 255, 255, .7));cursor:pointer;font-size:1rem;line-height:1}.pptx-ng-presenter-iconbtn:hover{background:var(--pptx-secondary, rgba(255, 255, 255, .1));color:#fff}.pptx-ng-presenter-iconbtn:disabled{opacity:.3;cursor:not-allowed}.pptx-ng-presenter-nav{display:flex;align-items:center;justify-content:space-between}.pptx-ng-presenter-navbtn{display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border:none;border-radius:6px;background:var(--pptx-secondary, rgba(255, 255, 255, .08));color:var(--pptx-foreground, #f5f5f5);cursor:pointer;font-size:.75rem}.pptx-ng-presenter-navbtn:hover:not(:disabled){background:#ffffff29}.pptx-ng-presenter-navbtn:disabled{opacity:.4;cursor:not-allowed}.pptx-ng-presenter-counter{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.875rem}.pptx-ng-presenter-next-empty{display:flex;align-items:center;justify-content:center;height:4rem;border:1px solid var(--pptx-border, rgba(255, 255, 255, .12));border-radius:6px;background:var(--pptx-muted, rgba(255, 255, 255, .04));font-size:.75rem;font-style:italic;color:#ffffff80}.pptx-ng-presenter-notes{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;padding:.75rem 1rem}.pptx-ng-presenter-notes-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}.pptx-ng-presenter-notes-size{display:flex;align-items:center;gap:.25rem}.pptx-ng-presenter-notes-size-value{min-width:28px;text-align:center;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.625rem;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .55));-webkit-user-select:none;user-select:none}.pptx-ng-presenter-notes-body{flex:1 1 auto;overflow-y:auto;border:1px solid var(--pptx-border, rgba(255, 255, 255, .12));border-radius:6px;background:var(--pptx-muted, rgba(255, 255, 255, .04));padding:.5rem .75rem;white-space:pre-wrap;line-height:1.5}.pptx-ng-presenter-notes-empty{font-style:italic;color:#ffffff80}.pptx-ng-presenter-progress{height:6px;width:100%;background:#ffffff1f;flex:0 0 auto}.pptx-ng-presenter-progress-fill{height:100%;background:#6ea8fe;transition:width 1s linear}.pptx-ng-presenter-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff9}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "rulerUnit", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "transparentBackground", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: PresenterControlsComponent, selector: "pptx-presenter-controls", inputs: ["snapshot", "audienceOpen", "slides", "current", "canvasSize", "mediaDataUrls"], outputs: ["patch", "navigate", "audience", "end"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
86036
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: PresenterViewComponent, isStandalone: true, selector: "pptx-presenter-view", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, currentSlideIndex: { classPropertyName: "currentSlideIndex", publicName: "currentSlideIndex", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, templateElements: { classPropertyName: "templateElements", publicName: "templateElements", isSignal: true, isRequired: false, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, presentationStartTime: { classPropertyName: "presentationStartTime", publicName: "presentationStartTime", isSignal: true, isRequired: false, transformFunction: null }, isAudienceWindowOpen: { classPropertyName: "isAudienceWindowOpen", publicName: "isAudienceWindowOpen", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { movePresentationSlide: "movePresentationSlide", exit: "exit", openAudienceWindow: "openAudienceWindow", closeAudienceWindow: "closeAudienceWindow", navigateToSlide: "navigateToSlide" }, ngImport: i0, template: "@if (currentSlide(); as current) {\n\t<pptx-presenter-controls\n\t\t[snapshot]=\"presenterWindow.snapshot()\"\n\t\t[audienceOpen]=\"isAudienceWindowOpen()\"\n\t\t[slides]=\"slides()\"\n\t\t[current]=\"currentSlideIndex()\"\n\t\t[canvasSize]=\"canvasSize()\"\n\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t[templateElements]=\"templateElements()\"\n\t\t(patch)=\"presenterWindow.updateSnapshot($event)\"\n\t\t(navigate)=\"navigateToSlide.emit($event)\"\n\t\t(audience)=\"onToggleAudienceWindow()\"\n\t\t(swapDisplays)=\"onSwapDisplays()\"\n\t\t(end)=\"exit.emit()\"\n\t/>\n\t<div class=\"pptx-ng-presenter-body\">\n\t\t<!-- Current slide (\u224870%) -->\n\t\t<div\n\t\t\tclass=\"pptx-ng-presenter-current\"\n\t\t\t[class.pptx-ng-presenter-current--advances]=\"paneAdvancesOnClick()\"\n\t\t\trole=\"presentation\"\n\t\t\tdata-pptx-presenter-slide\n\t\t\t(click)=\"onSlidePaneClick()\"\n\t\t>\n\t\t\t<div class=\"pptx-ng-presenter-preview-stage\" [ngStyle]=\"previewStageStyle()\">\n\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t[slide]=\"currentPreviewSlide()\"\n\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div class=\"pptx-ng-presenter-slide-badge\">{{ slideBadge() }}</div>\n\t\t</div>\n\n\t\t<!-- Controls (\u224830%) -->\n\t\t<div class=\"pptx-ng-presenter-side\">\n\t\t\t<!-- Header: clock + elapsed + window/exit -->\n\t\t\t<div class=\"pptx-ng-presenter-header\">\n\t\t\t\t<div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">\n\t\t\t\t\t\t{{ 'pptx.presenter.currentTime' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-clock\">{{ clockLabel() }}</div>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">{{ 'pptx.presenter.elapsed' | translate }}</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-clock pptx-ng-presenter-elapsed\">\n\t\t\t\t\t\t{{ elapsedLabel() }}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"display: flex; align-items: center; gap: 0.25rem\">\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t(click)=\"onToggleAudienceWindow()\"\n\t\t\t\t\t\t[attr.aria-label]=\"\n\t\t\t\t\t\t\t(isAudienceWindowOpen()\n\t\t\t\t\t\t\t\t? 'pptx.presenter.closeAudienceWindow'\n\t\t\t\t\t\t\t\t: 'pptx.presenter.openAudienceWindow'\n\t\t\t\t\t\t\t) | translate\n\t\t\t\t\t\t\"\n\t\t\t\t\t\t[title]=\"\n\t\t\t\t\t\t\t(isAudienceWindowOpen()\n\t\t\t\t\t\t\t\t? 'pptx.presenter.closeAudienceWindow'\n\t\t\t\t\t\t\t\t: 'pptx.presenter.openAudienceWindow'\n\t\t\t\t\t\t\t) | translate\n\t\t\t\t\t\t\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{{ isAudienceWindowOpen() ? '\u25A3' : '\u25A1' }}\n\t\t\t\t\t</button>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t(click)=\"exit.emit()\"\n\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t\t\t\t[title]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t\t\t>\n\t\t\t\t\t\t✕\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- Navigation -->\n\t\t\t<div class=\"pptx-ng-presenter-nav\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-presenter-navbtn\"\n\t\t\t\t\t(click)=\"movePresentationSlide.emit(-1)\"\n\t\t\t\t\t[disabled]=\"prevDisabled()\"\n\t\t\t\t\tdata-pptx-presenter-control=\"prev\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.prev' | translate\"\n\t\t\t\t\t[title]=\"'pptx.presenter.prev' | translate\"\n\t\t\t\t>\n\t\t\t\t\t‹ {{ 'pptx.presenter.prev' | translate }}\n\t\t\t\t</button>\n\t\t\t\t<span class=\"pptx-ng-presenter-counter\">{{ counterLabel() }}</span>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-presenter-navbtn\"\n\t\t\t\t\t(click)=\"movePresentationSlide.emit(1)\"\n\t\t\t\t\t[disabled]=\"nextDisabled()\"\n\t\t\t\t\tdata-pptx-presenter-control=\"next\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.next' | translate\"\n\t\t\t\t\t[title]=\"'pptx.presenter.next' | translate\"\n\t\t\t\t>\n\t\t\t\t\t{{ 'pptx.presenter.next' | translate }} ›\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t<!-- Next slide preview -->\n\t\t\t<div class=\"pptx-ng-presenter-next\" data-pptx-presenter-next-preview>\n\t\t\t\t<div class=\"pptx-ng-presenter-label\" style=\"margin-bottom: 0.5rem\">\n\t\t\t\t\t{{ 'pptx.presenter.nextSlidePreview' | translate }}\n\t\t\t\t</div>\n\t\t\t\t@if (nextPreviewSlide(); as next) {\n\t\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t\t[slide]=\"next\"\n\t\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t\t/>\n\t\t\t\t} @else {\n\t\t\t\t\t<div class=\"pptx-ng-presenter-next-empty\">\n\t\t\t\t\t\t{{ 'pptx.presenter.endOfPresentation' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t<!-- Speaker notes -->\n\t\t\t<div class=\"pptx-ng-presenter-notes\" data-pptx-presenter-notes>\n\t\t\t\t<div class=\"pptx-ng-presenter-notes-head\">\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">\n\t\t\t\t\t\t{{ 'pptx.presenter.speakerNotes' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-notes-size\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t\t(click)=\"decreaseNotesFontSize()\"\n\t\t\t\t\t\t\t[disabled]=\"notesFontSize() <= NOTES_FONT_SIZE_MIN\"\n\t\t\t\t\t\t\tdata-pptx-presenter-control=\"notes-font-decrease\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.decreaseFontSize' | translate\"\n\t\t\t\t\t\t\t[title]=\"'pptx.presenter.decreaseFontSize' | translate\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t−\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<span class=\"pptx-ng-presenter-notes-size-value\">{{ notesFontSize() }}px</span>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t\t(click)=\"increaseNotesFontSize()\"\n\t\t\t\t\t\t\t[disabled]=\"notesFontSize() >= NOTES_FONT_SIZE_MAX\"\n\t\t\t\t\t\t\tdata-pptx-presenter-control=\"notes-font-increase\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.increaseFontSize' | translate\"\n\t\t\t\t\t\t\t[title]=\"'pptx.presenter.increaseFontSize' | translate\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t+\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"pptx-ng-presenter-notes-body\" [ngStyle]=\"notesBodyStyle()\">\n\t\t\t\t\t@if (notes().hasRichNotes) {\n\t\t\t\t\t\t@for (seg of notes().segments; track seg.key) {\n\t\t\t\t\t\t\t@if (seg.isBreak) {\n\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<span [ngStyle]=\"seg.style\">{{ seg.text }}</span>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} @else if (notes().hasAnyNotes) {\n\t\t\t\t\t\t{{ notes().plainText }}\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span class=\"pptx-ng-presenter-notes-empty\">\n\t\t\t\t\t\t\t{{ 'pptx.presenter.noNotes' | translate }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n\t<!-- Timer progress bar -->\n\t<div\n\t\tclass=\"pptx-ng-presenter-progress\"\n\t\trole=\"progressbar\"\n\t\t[attr.aria-valuenow]=\"progressValue()\"\n\t\taria-valuemin=\"0\"\n\t\taria-valuemax=\"100\"\n\t\t[attr.aria-label]=\"'pptx.presenter.timerProgress' | translate\"\n\t>\n\t\t<div class=\"pptx-ng-presenter-progress-fill\" [style.width.%]=\"timerPercent()\"></div>\n\t</div>\n} @else {\n\t<div class=\"pptx-ng-presenter-empty\">{{ 'pptx.presenter.noSlides' | translate }}</div>\n}\n", styles: [":host{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;background:var(--pptx-card, #0b0b0c);color:var(--pptx-foreground, #f5f5f5);font-family:system-ui,sans-serif}.pptx-ng-presenter-body{display:flex;flex:1 1 auto;min-height:0}.pptx-ng-presenter-current--advances{cursor:pointer}.pptx-ng-presenter-current{flex:7 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#000;padding:1rem;min-width:0;overflow:hidden}.pptx-ng-presenter-preview-stage{width:100%;max-width:100%;min-height:0;transition:transform .2s ease}.pptx-ng-presenter-slide-badge{margin-top:.5rem;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.75rem;color:#ffffff80;-webkit-user-select:none;user-select:none}.pptx-ng-presenter-side{flex:3 1 0;display:flex;flex-direction:column;background:var(--pptx-background, #18181b);border-left:1px solid var(--pptx-border, rgba(255, 255, 255, .12));min-width:260px;max-width:440px}.pptx-ng-presenter-header,.pptx-ng-presenter-nav,.pptx-ng-presenter-next{padding:.5rem 1rem;border-bottom:1px solid var(--pptx-border, rgba(255, 255, 255, .12))}.pptx-ng-presenter-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem}.pptx-ng-presenter-label{font-size:.625rem;text-transform:uppercase;letter-spacing:.06em;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .55))}.pptx-ng-presenter-clock{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.125rem}.pptx-ng-presenter-elapsed{color:var(--pptx-primary, #6ea8fe)}.pptx-ng-presenter-iconbtn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;border-radius:6px;background:transparent;color:var(--pptx-foreground, rgba(255, 255, 255, .7));cursor:pointer;font-size:1rem;line-height:1}.pptx-ng-presenter-iconbtn:hover{background:var(--pptx-secondary, rgba(255, 255, 255, .1));color:#fff}.pptx-ng-presenter-iconbtn:disabled{opacity:.3;cursor:not-allowed}.pptx-ng-presenter-nav{display:flex;align-items:center;justify-content:space-between}.pptx-ng-presenter-navbtn{display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border:none;border-radius:6px;background:var(--pptx-secondary, rgba(255, 255, 255, .08));color:var(--pptx-foreground, #f5f5f5);cursor:pointer;font-size:.75rem}.pptx-ng-presenter-navbtn:hover:not(:disabled){background:#ffffff29}.pptx-ng-presenter-navbtn:disabled{opacity:.4;cursor:not-allowed}.pptx-ng-presenter-counter{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.875rem}.pptx-ng-presenter-next-empty{display:flex;align-items:center;justify-content:center;height:4rem;border:1px solid var(--pptx-border, rgba(255, 255, 255, .12));border-radius:6px;background:var(--pptx-muted, rgba(255, 255, 255, .04));font-size:.75rem;font-style:italic;color:#ffffff80}.pptx-ng-presenter-notes{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;padding:.75rem 1rem}.pptx-ng-presenter-notes-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}.pptx-ng-presenter-notes-size{display:flex;align-items:center;gap:.25rem}.pptx-ng-presenter-notes-size-value{min-width:28px;text-align:center;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.625rem;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .55));-webkit-user-select:none;user-select:none}.pptx-ng-presenter-notes-body{flex:1 1 auto;overflow-y:auto;border:1px solid var(--pptx-border, rgba(255, 255, 255, .12));border-radius:6px;background:var(--pptx-muted, rgba(255, 255, 255, .04));padding:.5rem .75rem;white-space:pre-wrap;line-height:1.5}.pptx-ng-presenter-notes-empty{font-style:italic;color:#ffffff80}.pptx-ng-presenter-progress{height:6px;width:100%;background:#ffffff1f;flex:0 0 auto}.pptx-ng-presenter-progress-fill{height:100%;background:#6ea8fe;transition:width 1s linear}.pptx-ng-presenter-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff9}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "rulerUnit", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "transparentBackground", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }, { kind: "component", type: PresenterControlsComponent, selector: "pptx-presenter-controls", inputs: ["snapshot", "audienceOpen", "slides", "current", "canvasSize", "mediaDataUrls", "templateElements"], outputs: ["patch", "navigate", "audience", "swapDisplays", "end"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
84463
86037
|
}
|
|
84464
86038
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: PresenterViewComponent, decorators: [{
|
|
84465
86039
|
type: Component,
|
|
84466
|
-
args: [{ selector: 'pptx-presenter-view', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgStyle, SlideCanvasComponent, PresenterControlsComponent, TranslatePipe], template: "@if (currentSlide(); as current) {\n\t<pptx-presenter-controls\n\t\t[snapshot]=\"presenterWindow.snapshot()\"\n\t\t[audienceOpen]=\"isAudienceWindowOpen()\"\n\t\t[slides]=\"slides()\"\n\t\t[current]=\"currentSlideIndex()\"\n\t\t[canvasSize]=\"canvasSize()\"\n\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t(patch)=\"presenterWindow.updateSnapshot($event)\"\n\t\t(navigate)=\"navigateToSlide.emit($event)\"\n\t\t(audience)=\"onToggleAudienceWindow()\"\n\t\t(end)=\"exit.emit()\"\n\t/>\n\t<div class=\"pptx-ng-presenter-body\">\n\t\t<!-- Current slide (\u224870%) -->\n\t\t<div\n\t\t\tclass=\"pptx-ng-presenter-current\"\n\t\t\t[class.pptx-ng-presenter-current--advances]=\"paneAdvancesOnClick()\"\n\t\t\trole=\"presentation\"\n\t\t\tdata-pptx-presenter-slide\n\t\t\t(click)=\"onSlidePaneClick()\"\n\t\t>\n\t\t\t<div class=\"pptx-ng-presenter-preview-stage\">\n\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t[slide]=\"currentPreviewSlide()\"\n\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div class=\"pptx-ng-presenter-slide-badge\">{{ slideBadge() }}</div>\n\t\t</div>\n\n\t\t<!-- Controls (\u224830%) -->\n\t\t<div class=\"pptx-ng-presenter-side\">\n\t\t\t<!-- Header: clock + elapsed + window/exit -->\n\t\t\t<div class=\"pptx-ng-presenter-header\">\n\t\t\t\t<div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">\n\t\t\t\t\t\t{{ 'pptx.presenter.currentTime' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-clock\">{{ clockLabel() }}</div>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">{{ 'pptx.presenter.elapsed' | translate }}</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-clock pptx-ng-presenter-elapsed\">\n\t\t\t\t\t\t{{ elapsedLabel() }}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"display: flex; align-items: center; gap: 0.25rem\">\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t(click)=\"onToggleAudienceWindow()\"\n\t\t\t\t\t\t[attr.aria-label]=\"\n\t\t\t\t\t\t\t(isAudienceWindowOpen()\n\t\t\t\t\t\t\t\t? 'pptx.presenter.closeAudienceWindow'\n\t\t\t\t\t\t\t\t: 'pptx.presenter.openAudienceWindow'\n\t\t\t\t\t\t\t) | translate\n\t\t\t\t\t\t\"\n\t\t\t\t\t\t[title]=\"\n\t\t\t\t\t\t\t(isAudienceWindowOpen()\n\t\t\t\t\t\t\t\t? 'pptx.presenter.closeAudienceWindow'\n\t\t\t\t\t\t\t\t: 'pptx.presenter.openAudienceWindow'\n\t\t\t\t\t\t\t) | translate\n\t\t\t\t\t\t\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{{ isAudienceWindowOpen() ? '\u25A3' : '\u25A1' }}\n\t\t\t\t\t</button>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t(click)=\"exit.emit()\"\n\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t\t\t\t[title]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t\t\t>\n\t\t\t\t\t\t✕\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- Navigation -->\n\t\t\t<div class=\"pptx-ng-presenter-nav\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-presenter-navbtn\"\n\t\t\t\t\t(click)=\"movePresentationSlide.emit(-1)\"\n\t\t\t\t\t[disabled]=\"currentSlideIndex() === 0\"\n\t\t\t\t\t[title]=\"'pptx.presenter.previousSlide' | translate\"\n\t\t\t\t>\n\t\t\t\t\t‹ {{ 'pptx.presenter.prev' | translate }}\n\t\t\t\t</button>\n\t\t\t\t<span class=\"pptx-ng-presenter-counter\">{{ counterLabel() }}</span>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-presenter-navbtn\"\n\t\t\t\t\t(click)=\"movePresentationSlide.emit(1)\"\n\t\t\t\t\t[disabled]=\"currentSlideIndex() >= slides().length - 1\"\n\t\t\t\t\t[title]=\"'pptx.presenter.nextSlide' | translate\"\n\t\t\t\t>\n\t\t\t\t\t{{ 'pptx.presenter.next' | translate }} ›\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t<!-- Next slide preview -->\n\t\t\t<div class=\"pptx-ng-presenter-next\">\n\t\t\t\t<div class=\"pptx-ng-presenter-label\" style=\"margin-bottom: 0.5rem\">\n\t\t\t\t\t{{ 'pptx.presenter.nextSlidePreview' | translate }}\n\t\t\t\t</div>\n\t\t\t\t@if (nextPreviewSlide(); as next) {\n\t\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t\t[slide]=\"next\"\n\t\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t\t/>\n\t\t\t\t} @else {\n\t\t\t\t\t<div class=\"pptx-ng-presenter-next-empty\">\n\t\t\t\t\t\t{{ 'pptx.presenter.endOfPresentation' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t<!-- Speaker notes -->\n\t\t\t<div class=\"pptx-ng-presenter-notes\">\n\t\t\t\t<div class=\"pptx-ng-presenter-notes-head\">\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">\n\t\t\t\t\t\t{{ 'pptx.presenter.speakerNotes' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-notes-size\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t\t(click)=\"decreaseNotesFontSize()\"\n\t\t\t\t\t\t\t[disabled]=\"notesFontSize() <= NOTES_FONT_SIZE_MIN\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.decreaseFontSize' | translate\"\n\t\t\t\t\t\t\t[title]=\"'pptx.presenter.decreaseFontSize' | translate\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t−\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<span class=\"pptx-ng-presenter-notes-size-value\">{{ notesFontSize() }}px</span>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t\t(click)=\"increaseNotesFontSize()\"\n\t\t\t\t\t\t\t[disabled]=\"notesFontSize() >= NOTES_FONT_SIZE_MAX\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.increaseFontSize' | translate\"\n\t\t\t\t\t\t\t[title]=\"'pptx.presenter.increaseFontSize' | translate\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t+\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"pptx-ng-presenter-notes-body\" [ngStyle]=\"notesBodyStyle()\">\n\t\t\t\t\t@if (notes().hasRichNotes) {\n\t\t\t\t\t\t@for (seg of notes().segments; track seg.key) {\n\t\t\t\t\t\t\t@if (seg.isBreak) {\n\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<span [ngStyle]=\"seg.style\">{{ seg.text }}</span>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} @else if (notes().hasAnyNotes) {\n\t\t\t\t\t\t{{ notes().plainText }}\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span class=\"pptx-ng-presenter-notes-empty\">\n\t\t\t\t\t\t\t{{ 'pptx.presenter.noNotes' | translate }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n\t<!-- Timer progress bar -->\n\t<div\n\t\tclass=\"pptx-ng-presenter-progress\"\n\t\trole=\"progressbar\"\n\t\t[attr.aria-valuenow]=\"progressValue()\"\n\t\taria-valuemin=\"0\"\n\t\taria-valuemax=\"100\"\n\t\t[attr.aria-label]=\"'pptx.presenter.timerProgress' | translate\"\n\t>\n\t\t<div class=\"pptx-ng-presenter-progress-fill\" [style.width.%]=\"timerPercent()\"></div>\n\t</div>\n} @else {\n\t<div class=\"pptx-ng-presenter-empty\">{{ 'pptx.presenter.noSlides' | translate }}</div>\n}\n", styles: [":host{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;background:var(--pptx-card, #0b0b0c);color:var(--pptx-foreground, #f5f5f5);font-family:system-ui,sans-serif}.pptx-ng-presenter-body{display:flex;flex:1 1 auto;min-height:0}.pptx-ng-presenter-current--advances{cursor:pointer}.pptx-ng-presenter-current{flex:7 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#000;padding:1rem;min-width:0}.pptx-ng-presenter-preview-stage{width:100%;max-width:100%;min-height:0}.pptx-ng-presenter-slide-badge{margin-top:.5rem;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.75rem;color:#ffffff80;-webkit-user-select:none;user-select:none}.pptx-ng-presenter-side{flex:3 1 0;display:flex;flex-direction:column;background:var(--pptx-background, #18181b);border-left:1px solid var(--pptx-border, rgba(255, 255, 255, .12));min-width:260px;max-width:440px}.pptx-ng-presenter-header,.pptx-ng-presenter-nav,.pptx-ng-presenter-next{padding:.5rem 1rem;border-bottom:1px solid var(--pptx-border, rgba(255, 255, 255, .12))}.pptx-ng-presenter-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem}.pptx-ng-presenter-label{font-size:.625rem;text-transform:uppercase;letter-spacing:.06em;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .55))}.pptx-ng-presenter-clock{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.125rem}.pptx-ng-presenter-elapsed{color:var(--pptx-primary, #6ea8fe)}.pptx-ng-presenter-iconbtn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;border-radius:6px;background:transparent;color:var(--pptx-foreground, rgba(255, 255, 255, .7));cursor:pointer;font-size:1rem;line-height:1}.pptx-ng-presenter-iconbtn:hover{background:var(--pptx-secondary, rgba(255, 255, 255, .1));color:#fff}.pptx-ng-presenter-iconbtn:disabled{opacity:.3;cursor:not-allowed}.pptx-ng-presenter-nav{display:flex;align-items:center;justify-content:space-between}.pptx-ng-presenter-navbtn{display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border:none;border-radius:6px;background:var(--pptx-secondary, rgba(255, 255, 255, .08));color:var(--pptx-foreground, #f5f5f5);cursor:pointer;font-size:.75rem}.pptx-ng-presenter-navbtn:hover:not(:disabled){background:#ffffff29}.pptx-ng-presenter-navbtn:disabled{opacity:.4;cursor:not-allowed}.pptx-ng-presenter-counter{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.875rem}.pptx-ng-presenter-next-empty{display:flex;align-items:center;justify-content:center;height:4rem;border:1px solid var(--pptx-border, rgba(255, 255, 255, .12));border-radius:6px;background:var(--pptx-muted, rgba(255, 255, 255, .04));font-size:.75rem;font-style:italic;color:#ffffff80}.pptx-ng-presenter-notes{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;padding:.75rem 1rem}.pptx-ng-presenter-notes-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}.pptx-ng-presenter-notes-size{display:flex;align-items:center;gap:.25rem}.pptx-ng-presenter-notes-size-value{min-width:28px;text-align:center;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.625rem;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .55));-webkit-user-select:none;user-select:none}.pptx-ng-presenter-notes-body{flex:1 1 auto;overflow-y:auto;border:1px solid var(--pptx-border, rgba(255, 255, 255, .12));border-radius:6px;background:var(--pptx-muted, rgba(255, 255, 255, .04));padding:.5rem .75rem;white-space:pre-wrap;line-height:1.5}.pptx-ng-presenter-notes-empty{font-style:italic;color:#ffffff80}.pptx-ng-presenter-progress{height:6px;width:100%;background:#ffffff1f;flex:0 0 auto}.pptx-ng-presenter-progress-fill{height:100%;background:#6ea8fe;transition:width 1s linear}.pptx-ng-presenter-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff9}\n"] }]
|
|
86040
|
+
args: [{ selector: 'pptx-presenter-view', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgStyle, SlideCanvasComponent, PresenterControlsComponent, TranslatePipe], template: "@if (currentSlide(); as current) {\n\t<pptx-presenter-controls\n\t\t[snapshot]=\"presenterWindow.snapshot()\"\n\t\t[audienceOpen]=\"isAudienceWindowOpen()\"\n\t\t[slides]=\"slides()\"\n\t\t[current]=\"currentSlideIndex()\"\n\t\t[canvasSize]=\"canvasSize()\"\n\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t[templateElements]=\"templateElements()\"\n\t\t(patch)=\"presenterWindow.updateSnapshot($event)\"\n\t\t(navigate)=\"navigateToSlide.emit($event)\"\n\t\t(audience)=\"onToggleAudienceWindow()\"\n\t\t(swapDisplays)=\"onSwapDisplays()\"\n\t\t(end)=\"exit.emit()\"\n\t/>\n\t<div class=\"pptx-ng-presenter-body\">\n\t\t<!-- Current slide (\u224870%) -->\n\t\t<div\n\t\t\tclass=\"pptx-ng-presenter-current\"\n\t\t\t[class.pptx-ng-presenter-current--advances]=\"paneAdvancesOnClick()\"\n\t\t\trole=\"presentation\"\n\t\t\tdata-pptx-presenter-slide\n\t\t\t(click)=\"onSlidePaneClick()\"\n\t\t>\n\t\t\t<div class=\"pptx-ng-presenter-preview-stage\" [ngStyle]=\"previewStageStyle()\">\n\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t[slide]=\"currentPreviewSlide()\"\n\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div class=\"pptx-ng-presenter-slide-badge\">{{ slideBadge() }}</div>\n\t\t</div>\n\n\t\t<!-- Controls (\u224830%) -->\n\t\t<div class=\"pptx-ng-presenter-side\">\n\t\t\t<!-- Header: clock + elapsed + window/exit -->\n\t\t\t<div class=\"pptx-ng-presenter-header\">\n\t\t\t\t<div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">\n\t\t\t\t\t\t{{ 'pptx.presenter.currentTime' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-clock\">{{ clockLabel() }}</div>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">{{ 'pptx.presenter.elapsed' | translate }}</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-clock pptx-ng-presenter-elapsed\">\n\t\t\t\t\t\t{{ elapsedLabel() }}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"display: flex; align-items: center; gap: 0.25rem\">\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t(click)=\"onToggleAudienceWindow()\"\n\t\t\t\t\t\t[attr.aria-label]=\"\n\t\t\t\t\t\t\t(isAudienceWindowOpen()\n\t\t\t\t\t\t\t\t? 'pptx.presenter.closeAudienceWindow'\n\t\t\t\t\t\t\t\t: 'pptx.presenter.openAudienceWindow'\n\t\t\t\t\t\t\t) | translate\n\t\t\t\t\t\t\"\n\t\t\t\t\t\t[title]=\"\n\t\t\t\t\t\t\t(isAudienceWindowOpen()\n\t\t\t\t\t\t\t\t? 'pptx.presenter.closeAudienceWindow'\n\t\t\t\t\t\t\t\t: 'pptx.presenter.openAudienceWindow'\n\t\t\t\t\t\t\t) | translate\n\t\t\t\t\t\t\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{{ isAudienceWindowOpen() ? '\u25A3' : '\u25A1' }}\n\t\t\t\t\t</button>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t(click)=\"exit.emit()\"\n\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t\t\t\t[title]=\"'pptx.presenter.endPresentation' | translate\"\n\t\t\t\t\t>\n\t\t\t\t\t\t✕\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- Navigation -->\n\t\t\t<div class=\"pptx-ng-presenter-nav\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-presenter-navbtn\"\n\t\t\t\t\t(click)=\"movePresentationSlide.emit(-1)\"\n\t\t\t\t\t[disabled]=\"prevDisabled()\"\n\t\t\t\t\tdata-pptx-presenter-control=\"prev\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.prev' | translate\"\n\t\t\t\t\t[title]=\"'pptx.presenter.prev' | translate\"\n\t\t\t\t>\n\t\t\t\t\t‹ {{ 'pptx.presenter.prev' | translate }}\n\t\t\t\t</button>\n\t\t\t\t<span class=\"pptx-ng-presenter-counter\">{{ counterLabel() }}</span>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-presenter-navbtn\"\n\t\t\t\t\t(click)=\"movePresentationSlide.emit(1)\"\n\t\t\t\t\t[disabled]=\"nextDisabled()\"\n\t\t\t\t\tdata-pptx-presenter-control=\"next\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.next' | translate\"\n\t\t\t\t\t[title]=\"'pptx.presenter.next' | translate\"\n\t\t\t\t>\n\t\t\t\t\t{{ 'pptx.presenter.next' | translate }} ›\n\t\t\t\t</button>\n\t\t\t</div>\n\n\t\t\t<!-- Next slide preview -->\n\t\t\t<div class=\"pptx-ng-presenter-next\" data-pptx-presenter-next-preview>\n\t\t\t\t<div class=\"pptx-ng-presenter-label\" style=\"margin-bottom: 0.5rem\">\n\t\t\t\t\t{{ 'pptx.presenter.nextSlidePreview' | translate }}\n\t\t\t\t</div>\n\t\t\t\t@if (nextPreviewSlide(); as next) {\n\t\t\t\t\t<pptx-slide-canvas\n\t\t\t\t\t\t[slide]=\"next\"\n\t\t\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t\t[zoom]=\"1\"\n\t\t\t\t\t\t[interactive]=\"false\"\n\t\t\t\t\t/>\n\t\t\t\t} @else {\n\t\t\t\t\t<div class=\"pptx-ng-presenter-next-empty\">\n\t\t\t\t\t\t{{ 'pptx.presenter.endOfPresentation' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t<!-- Speaker notes -->\n\t\t\t<div class=\"pptx-ng-presenter-notes\" data-pptx-presenter-notes>\n\t\t\t\t<div class=\"pptx-ng-presenter-notes-head\">\n\t\t\t\t\t<div class=\"pptx-ng-presenter-label\">\n\t\t\t\t\t\t{{ 'pptx.presenter.speakerNotes' | translate }}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"pptx-ng-presenter-notes-size\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t\t(click)=\"decreaseNotesFontSize()\"\n\t\t\t\t\t\t\t[disabled]=\"notesFontSize() <= NOTES_FONT_SIZE_MIN\"\n\t\t\t\t\t\t\tdata-pptx-presenter-control=\"notes-font-decrease\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.decreaseFontSize' | translate\"\n\t\t\t\t\t\t\t[title]=\"'pptx.presenter.decreaseFontSize' | translate\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t−\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<span class=\"pptx-ng-presenter-notes-size-value\">{{ notesFontSize() }}px</span>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"pptx-ng-presenter-iconbtn\"\n\t\t\t\t\t\t\t(click)=\"increaseNotesFontSize()\"\n\t\t\t\t\t\t\t[disabled]=\"notesFontSize() >= NOTES_FONT_SIZE_MAX\"\n\t\t\t\t\t\t\tdata-pptx-presenter-control=\"notes-font-increase\"\n\t\t\t\t\t\t\t[attr.aria-label]=\"'pptx.presenter.increaseFontSize' | translate\"\n\t\t\t\t\t\t\t[title]=\"'pptx.presenter.increaseFontSize' | translate\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t+\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"pptx-ng-presenter-notes-body\" [ngStyle]=\"notesBodyStyle()\">\n\t\t\t\t\t@if (notes().hasRichNotes) {\n\t\t\t\t\t\t@for (seg of notes().segments; track seg.key) {\n\t\t\t\t\t\t\t@if (seg.isBreak) {\n\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<span [ngStyle]=\"seg.style\">{{ seg.text }}</span>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} @else if (notes().hasAnyNotes) {\n\t\t\t\t\t\t{{ notes().plainText }}\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span class=\"pptx-ng-presenter-notes-empty\">\n\t\t\t\t\t\t\t{{ 'pptx.presenter.noNotes' | translate }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n\t<!-- Timer progress bar -->\n\t<div\n\t\tclass=\"pptx-ng-presenter-progress\"\n\t\trole=\"progressbar\"\n\t\t[attr.aria-valuenow]=\"progressValue()\"\n\t\taria-valuemin=\"0\"\n\t\taria-valuemax=\"100\"\n\t\t[attr.aria-label]=\"'pptx.presenter.timerProgress' | translate\"\n\t>\n\t\t<div class=\"pptx-ng-presenter-progress-fill\" [style.width.%]=\"timerPercent()\"></div>\n\t</div>\n} @else {\n\t<div class=\"pptx-ng-presenter-empty\">{{ 'pptx.presenter.noSlides' | translate }}</div>\n}\n", styles: [":host{position:absolute;inset:0;z-index:50;display:flex;flex-direction:column;background:var(--pptx-card, #0b0b0c);color:var(--pptx-foreground, #f5f5f5);font-family:system-ui,sans-serif}.pptx-ng-presenter-body{display:flex;flex:1 1 auto;min-height:0}.pptx-ng-presenter-current--advances{cursor:pointer}.pptx-ng-presenter-current{flex:7 1 0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#000;padding:1rem;min-width:0;overflow:hidden}.pptx-ng-presenter-preview-stage{width:100%;max-width:100%;min-height:0;transition:transform .2s ease}.pptx-ng-presenter-slide-badge{margin-top:.5rem;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.75rem;color:#ffffff80;-webkit-user-select:none;user-select:none}.pptx-ng-presenter-side{flex:3 1 0;display:flex;flex-direction:column;background:var(--pptx-background, #18181b);border-left:1px solid var(--pptx-border, rgba(255, 255, 255, .12));min-width:260px;max-width:440px}.pptx-ng-presenter-header,.pptx-ng-presenter-nav,.pptx-ng-presenter-next{padding:.5rem 1rem;border-bottom:1px solid var(--pptx-border, rgba(255, 255, 255, .12))}.pptx-ng-presenter-header{display:flex;align-items:center;justify-content:space-between;gap:.5rem}.pptx-ng-presenter-label{font-size:.625rem;text-transform:uppercase;letter-spacing:.06em;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .55))}.pptx-ng-presenter-clock{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:1.125rem}.pptx-ng-presenter-elapsed{color:var(--pptx-primary, #6ea8fe)}.pptx-ng-presenter-iconbtn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;border-radius:6px;background:transparent;color:var(--pptx-foreground, rgba(255, 255, 255, .7));cursor:pointer;font-size:1rem;line-height:1}.pptx-ng-presenter-iconbtn:hover{background:var(--pptx-secondary, rgba(255, 255, 255, .1));color:#fff}.pptx-ng-presenter-iconbtn:disabled{opacity:.3;cursor:not-allowed}.pptx-ng-presenter-nav{display:flex;align-items:center;justify-content:space-between}.pptx-ng-presenter-navbtn{display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border:none;border-radius:6px;background:var(--pptx-secondary, rgba(255, 255, 255, .08));color:var(--pptx-foreground, #f5f5f5);cursor:pointer;font-size:.75rem}.pptx-ng-presenter-navbtn:hover:not(:disabled){background:#ffffff29}.pptx-ng-presenter-navbtn:disabled{opacity:.4;cursor:not-allowed}.pptx-ng-presenter-counter{font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.875rem}.pptx-ng-presenter-next-empty{display:flex;align-items:center;justify-content:center;height:4rem;border:1px solid var(--pptx-border, rgba(255, 255, 255, .12));border-radius:6px;background:var(--pptx-muted, rgba(255, 255, 255, .04));font-size:.75rem;font-style:italic;color:#ffffff80}.pptx-ng-presenter-notes{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;padding:.75rem 1rem}.pptx-ng-presenter-notes-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:.5rem}.pptx-ng-presenter-notes-size{display:flex;align-items:center;gap:.25rem}.pptx-ng-presenter-notes-size-value{min-width:28px;text-align:center;font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;font-size:.625rem;color:var(--pptx-muted-foreground, rgba(255, 255, 255, .55));-webkit-user-select:none;user-select:none}.pptx-ng-presenter-notes-body{flex:1 1 auto;overflow-y:auto;border:1px solid var(--pptx-border, rgba(255, 255, 255, .12));border-radius:6px;background:var(--pptx-muted, rgba(255, 255, 255, .04));padding:.5rem .75rem;white-space:pre-wrap;line-height:1.5}.pptx-ng-presenter-notes-empty{font-style:italic;color:#ffffff80}.pptx-ng-presenter-progress{height:6px;width:100%;background:#ffffff1f;flex:0 0 auto}.pptx-ng-presenter-progress-fill{height:100%;background:#6ea8fe;transition:width 1s linear}.pptx-ng-presenter-empty{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff9}\n"] }]
|
|
84467
86041
|
}], ctorParameters: () => [], propDecorators: { slides: [{ type: i0.Input, args: [{ isSignal: true, alias: "slides", required: true }] }], currentSlideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentSlideIndex", required: true }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], templateElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateElements", required: false }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], presentationStartTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "presentationStartTime", required: false }] }], isAudienceWindowOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isAudienceWindowOpen", required: false }] }], movePresentationSlide: [{ type: i0.Output, args: ["movePresentationSlide"] }], exit: [{ type: i0.Output, args: ["exit"] }], openAudienceWindow: [{ type: i0.Output, args: ["openAudienceWindow"] }], closeAudienceWindow: [{ type: i0.Output, args: ["closeAudienceWindow"] }], navigateToSlide: [{ type: i0.Output, args: ["navigateToSlide"] }] } });
|
|
84468
86042
|
|
|
84469
86043
|
/**
|
|
@@ -87537,13 +89111,19 @@ class RibbonSlideshowSectionComponent {
|
|
|
87537
89111
|
{{ 'pptx.slideShow.fromCurrent' | translate }}
|
|
87538
89112
|
</button>
|
|
87539
89113
|
<span class="pptx-rb-sep"></span>
|
|
89114
|
+
<!-- Presenter View. Deliberately NOT gated on slideCount(): no other
|
|
89115
|
+
binding disables it, and e2e/ribbon-control-inventory.spec.ts diffs
|
|
89116
|
+
exactly which controls each binding leaves usable. The label key is
|
|
89117
|
+
pptx.slideShow.* for the same reason: the old pptx.ribbon.* key
|
|
89118
|
+
happens to carry the same English, so the inventory's accessible-name
|
|
89119
|
+
diff passed by luck and would have broken on any locale edit. -->
|
|
87540
89120
|
<button
|
|
87541
89121
|
type="button"
|
|
87542
89122
|
class="pptx-rb-pill"
|
|
87543
|
-
[
|
|
89123
|
+
[title]="'pptx.slideShow.presenterViewTooltip' | translate"
|
|
87544
89124
|
(click)="presenter.emit()"
|
|
87545
89125
|
>
|
|
87546
|
-
{{ 'pptx.
|
|
89126
|
+
{{ 'pptx.slideShow.presenterView' | translate }}
|
|
87547
89127
|
</button>
|
|
87548
89128
|
<button
|
|
87549
89129
|
type="button"
|
|
@@ -87668,13 +89248,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
87668
89248
|
{{ 'pptx.slideShow.fromCurrent' | translate }}
|
|
87669
89249
|
</button>
|
|
87670
89250
|
<span class="pptx-rb-sep"></span>
|
|
89251
|
+
<!-- Presenter View. Deliberately NOT gated on slideCount(): no other
|
|
89252
|
+
binding disables it, and e2e/ribbon-control-inventory.spec.ts diffs
|
|
89253
|
+
exactly which controls each binding leaves usable. The label key is
|
|
89254
|
+
pptx.slideShow.* for the same reason: the old pptx.ribbon.* key
|
|
89255
|
+
happens to carry the same English, so the inventory's accessible-name
|
|
89256
|
+
diff passed by luck and would have broken on any locale edit. -->
|
|
87671
89257
|
<button
|
|
87672
89258
|
type="button"
|
|
87673
89259
|
class="pptx-rb-pill"
|
|
87674
|
-
[
|
|
89260
|
+
[title]="'pptx.slideShow.presenterViewTooltip' | translate"
|
|
87675
89261
|
(click)="presenter.emit()"
|
|
87676
89262
|
>
|
|
87677
|
-
{{ 'pptx.
|
|
89263
|
+
{{ 'pptx.slideShow.presenterView' | translate }}
|
|
87678
89264
|
</button>
|
|
87679
89265
|
<button
|
|
87680
89266
|
type="button"
|
|
@@ -89740,7 +91326,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
89740
91326
|
}], propDecorators: { canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }] } });
|
|
89741
91327
|
|
|
89742
91328
|
// Generated by scripts/inline-shared.mjs from package.json. Do not edit.
|
|
89743
|
-
const PPTX_ANGULAR_VIEWER_VERSION = "2.
|
|
91329
|
+
const PPTX_ANGULAR_VIEWER_VERSION = "2.12.0";
|
|
89744
91330
|
|
|
89745
91331
|
/**
|
|
89746
91332
|
* account-page.component.ts: File > Account content.
|
|
@@ -93136,7 +94722,8 @@ class RibbonPrimaryRowComponent {
|
|
|
93136
94722
|
[disabled]="slideCount() === 0"
|
|
93137
94723
|
(click)="presenter.emit(); presentMenuOpen.set(false)"
|
|
93138
94724
|
>
|
|
93139
|
-
|
|
94725
|
+
<!-- Same key as the Slide Show tab and the other four bindings. -->
|
|
94726
|
+
{{ 'pptx.slideShow.presenterView' | translate }}
|
|
93140
94727
|
</button>
|
|
93141
94728
|
@if (!toolbar.isHidden('broadcast')) {
|
|
93142
94729
|
<button
|
|
@@ -93328,7 +94915,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
93328
94915
|
[disabled]="slideCount() === 0"
|
|
93329
94916
|
(click)="presenter.emit(); presentMenuOpen.set(false)"
|
|
93330
94917
|
>
|
|
93331
|
-
|
|
94918
|
+
<!-- Same key as the Slide Show tab and the other four bindings. -->
|
|
94919
|
+
{{ 'pptx.slideShow.presenterView' | translate }}
|
|
93332
94920
|
</button>
|
|
93333
94921
|
@if (!toolbar.isHidden('broadcast')) {
|
|
93334
94922
|
<button
|
|
@@ -100025,21 +101613,14 @@ function fillPatternLabelKey(preset) {
|
|
|
100025
101613
|
return schemaLabelKey(FILL_PATTERN_LABEL_KEYS, preset);
|
|
100026
101614
|
}
|
|
100027
101615
|
|
|
100028
|
-
const ARROWS = [
|
|
100029
|
-
'none',
|
|
100030
|
-
'triangle',
|
|
100031
|
-
'arrow',
|
|
100032
|
-
'stealth',
|
|
100033
|
-
'diamond',
|
|
100034
|
-
'oval',
|
|
100035
|
-
];
|
|
100036
101616
|
/**
|
|
100037
101617
|
* Arrowhead width / length steps, i.e. the `a:headEnd/@w` and `@len` values.
|
|
100038
101618
|
*
|
|
100039
|
-
*
|
|
100040
|
-
* package's suite is TestBed-free, so
|
|
101619
|
+
* Re-exported from the shared descriptor table so a unit test can pin the
|
|
101620
|
+
* offered set while the labels change (the package's suite is TestBed-free, so
|
|
101621
|
+
* the template is out of reach).
|
|
100041
101622
|
*/
|
|
100042
|
-
const ARROW_SIZE_VALUES =
|
|
101623
|
+
const ARROW_SIZE_VALUES = CONNECTOR_ARROW_SIZE_VALUES;
|
|
100043
101624
|
const GEOMETRIES = [
|
|
100044
101625
|
['straightConnector1', 'Straight'],
|
|
100045
101626
|
['bentConnector2', 'Bent'],
|
|
@@ -100059,10 +101640,13 @@ class ElementMiscPropertiesComponent {
|
|
|
100059
101640
|
element = input.required(/* @ts-ignore */
|
|
100060
101641
|
...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
|
|
100061
101642
|
patch = output();
|
|
100062
|
-
|
|
100063
|
-
|
|
101643
|
+
/**
|
|
101644
|
+
* The six arrowhead dropdowns, described once in shared. Angular used to
|
|
101645
|
+
* declare its own value order and interpolate sentence-case captions
|
|
101646
|
+
* ("Start arrow"), which read differently from the other four bindings.
|
|
101647
|
+
*/
|
|
101648
|
+
arrowControls = CONNECTOR_ARROW_CONTROLS;
|
|
100064
101649
|
geometries = GEOMETRIES;
|
|
100065
|
-
ends = ['Start', 'End'];
|
|
100066
101650
|
connector = computed(() => this.element().type === 'connector', /* @ts-ignore */
|
|
100067
101651
|
...(ngDevMode ? [{ debugName: "connector" }] : /* istanbul ignore next */ []));
|
|
100068
101652
|
connectorType = computed(() => this.element().shapeType ?? 'straightConnector1', /* @ts-ignore */
|
|
@@ -100073,36 +101657,25 @@ class ElementMiscPropertiesComponent {
|
|
|
100073
101657
|
...(ngDevMode ? [{ debugName: "ole" }] : /* istanbul ignore next */ []));
|
|
100074
101658
|
oleType = computed(() => getOleObjectTypeLabel(this.ole()?.oleObjectType), /* @ts-ignore */
|
|
100075
101659
|
...(ngDevMode ? [{ debugName: "oleType" }] : /* istanbul ignore next */ []));
|
|
100076
|
-
arrowLabel(value) {
|
|
100077
|
-
return arrowheadLabelKey(value);
|
|
100078
|
-
}
|
|
100079
101660
|
/**
|
|
100080
|
-
* Spell
|
|
100081
|
-
*
|
|
100082
|
-
*
|
|
101661
|
+
* Spell one option. Resolving a KEY (not finished text) keeps the wording
|
|
101662
|
+
* live under `OnPush`, since `TranslatePipe` marks the view for check when
|
|
101663
|
+
* the language changes. See `schema-token-labels`.
|
|
100083
101664
|
*/
|
|
100084
|
-
|
|
100085
|
-
return
|
|
101665
|
+
optionLabelKey(control, value) {
|
|
101666
|
+
return schemaLabelKey(control.optionLabelKeys, value);
|
|
100086
101667
|
}
|
|
100087
|
-
arrowValue(
|
|
100088
|
-
return (this.element().shapeStyle
|
|
101668
|
+
arrowValue(control) {
|
|
101669
|
+
return connectorArrowValue(control, this.element().shapeStyle);
|
|
100089
101670
|
}
|
|
100090
|
-
|
|
100091
|
-
|
|
100092
|
-
}
|
|
100093
|
-
onArrow(end, event) {
|
|
100094
|
-
this.updateStyle({ [`connector${end}Arrow`]: event.target.value });
|
|
101671
|
+
onArrow(control, event) {
|
|
101672
|
+
this.updateStyle(connectorArrowPatch(control, event.target.value));
|
|
100095
101673
|
}
|
|
100096
101674
|
onConnectorType(event) {
|
|
100097
101675
|
this.patch.emit({
|
|
100098
101676
|
shapeType: event.target.value,
|
|
100099
101677
|
});
|
|
100100
101678
|
}
|
|
100101
|
-
onSize(end, dimension, event) {
|
|
100102
|
-
this.updateStyle({
|
|
100103
|
-
[`connector${end}Arrow${dimension}`]: event.target.value,
|
|
100104
|
-
});
|
|
100105
|
-
}
|
|
100106
101679
|
updateStyle(update) {
|
|
100107
101680
|
this.patch.emit(connectorStylePatch(this.element(), update));
|
|
100108
101681
|
}
|
|
@@ -100111,37 +101684,34 @@ class ElementMiscPropertiesComponent {
|
|
|
100111
101684
|
@if (connector()) {
|
|
100112
101685
|
<section class="card" aria-label="Connector">
|
|
100113
101686
|
<h3>Connector</h3>
|
|
101687
|
+
<!--
|
|
101688
|
+
Selection is expressed with [selected] on each option rather than
|
|
101689
|
+
[value] on the select: Angular applies an element's own property
|
|
101690
|
+
bindings before the @for below it has produced any options, so a
|
|
101691
|
+
[value] naming a token was assigned to an EMPTY select and dropped
|
|
101692
|
+
back to the first entry. Every one of these dropdowns therefore read
|
|
101693
|
+
"none" / "Small" no matter what the deck authored, and the card
|
|
101694
|
+
silently misreported the connector it was editing.
|
|
101695
|
+
-->
|
|
100114
101696
|
<label class="geometry">
|
|
100115
101697
|
<span>Geometry</span>
|
|
100116
|
-
<select
|
|
101698
|
+
<select (change)="onConnectorType($event)">
|
|
100117
101699
|
@for (geometry of geometries; track geometry[0]) {
|
|
100118
|
-
<option [value]="geometry[0]"
|
|
101700
|
+
<option [value]="geometry[0]" [selected]="geometry[0] === connectorType()">
|
|
101701
|
+
{{ geometry[1] }}
|
|
101702
|
+
</option>
|
|
100119
101703
|
}
|
|
100120
101704
|
</select>
|
|
100121
101705
|
</label>
|
|
100122
101706
|
<div class="grid">
|
|
100123
|
-
@for (
|
|
100124
|
-
<label>
|
|
100125
|
-
<span>{{ end }} arrow</span>
|
|
100126
|
-
<select [value]="arrowValue(end)" (change)="onArrow(end, $event)">
|
|
100127
|
-
@for (arrow of arrows; track arrow) {
|
|
100128
|
-
<option [value]="arrow">{{ arrowLabel(arrow) | translate }}</option>
|
|
100129
|
-
}
|
|
100130
|
-
</select>
|
|
100131
|
-
</label>
|
|
101707
|
+
@for (control of arrowControls; track control.styleKey) {
|
|
100132
101708
|
<label>
|
|
100133
|
-
<span>{{
|
|
100134
|
-
<select
|
|
100135
|
-
@for (
|
|
100136
|
-
<option [value]="
|
|
100137
|
-
|
|
100138
|
-
|
|
100139
|
-
</label>
|
|
100140
|
-
<label>
|
|
100141
|
-
<span>{{ end }} length</span>
|
|
100142
|
-
<select [value]="sizeValue(end, 'Length')" (change)="onSize(end, 'Length', $event)">
|
|
100143
|
-
@for (size of sizes; track size) {
|
|
100144
|
-
<option [value]="size">{{ sizeLabel(size) | translate }}</option>
|
|
101709
|
+
<span>{{ control.labelKey | translate }}</span>
|
|
101710
|
+
<select (change)="onArrow(control, $event)">
|
|
101711
|
+
@for (value of control.values; track value) {
|
|
101712
|
+
<option [value]="value" [selected]="value === arrowValue(control)">
|
|
101713
|
+
{{ optionLabelKey(control, value) | translate }}
|
|
101714
|
+
</option>
|
|
100145
101715
|
}
|
|
100146
101716
|
</select>
|
|
100147
101717
|
</label>
|
|
@@ -100184,37 +101754,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
|
|
|
100184
101754
|
@if (connector()) {
|
|
100185
101755
|
<section class="card" aria-label="Connector">
|
|
100186
101756
|
<h3>Connector</h3>
|
|
101757
|
+
<!--
|
|
101758
|
+
Selection is expressed with [selected] on each option rather than
|
|
101759
|
+
[value] on the select: Angular applies an element's own property
|
|
101760
|
+
bindings before the @for below it has produced any options, so a
|
|
101761
|
+
[value] naming a token was assigned to an EMPTY select and dropped
|
|
101762
|
+
back to the first entry. Every one of these dropdowns therefore read
|
|
101763
|
+
"none" / "Small" no matter what the deck authored, and the card
|
|
101764
|
+
silently misreported the connector it was editing.
|
|
101765
|
+
-->
|
|
100187
101766
|
<label class="geometry">
|
|
100188
101767
|
<span>Geometry</span>
|
|
100189
|
-
<select
|
|
101768
|
+
<select (change)="onConnectorType($event)">
|
|
100190
101769
|
@for (geometry of geometries; track geometry[0]) {
|
|
100191
|
-
<option [value]="geometry[0]"
|
|
101770
|
+
<option [value]="geometry[0]" [selected]="geometry[0] === connectorType()">
|
|
101771
|
+
{{ geometry[1] }}
|
|
101772
|
+
</option>
|
|
100192
101773
|
}
|
|
100193
101774
|
</select>
|
|
100194
101775
|
</label>
|
|
100195
101776
|
<div class="grid">
|
|
100196
|
-
@for (
|
|
100197
|
-
<label>
|
|
100198
|
-
<span>{{ end }} arrow</span>
|
|
100199
|
-
<select [value]="arrowValue(end)" (change)="onArrow(end, $event)">
|
|
100200
|
-
@for (arrow of arrows; track arrow) {
|
|
100201
|
-
<option [value]="arrow">{{ arrowLabel(arrow) | translate }}</option>
|
|
100202
|
-
}
|
|
100203
|
-
</select>
|
|
100204
|
-
</label>
|
|
100205
|
-
<label>
|
|
100206
|
-
<span>{{ end }} width</span>
|
|
100207
|
-
<select [value]="sizeValue(end, 'Width')" (change)="onSize(end, 'Width', $event)">
|
|
100208
|
-
@for (size of sizes; track size) {
|
|
100209
|
-
<option [value]="size">{{ sizeLabel(size) | translate }}</option>
|
|
100210
|
-
}
|
|
100211
|
-
</select>
|
|
100212
|
-
</label>
|
|
101777
|
+
@for (control of arrowControls; track control.styleKey) {
|
|
100213
101778
|
<label>
|
|
100214
|
-
<span>{{
|
|
100215
|
-
<select
|
|
100216
|
-
@for (
|
|
100217
|
-
<option [value]="
|
|
101779
|
+
<span>{{ control.labelKey | translate }}</span>
|
|
101780
|
+
<select (change)="onArrow(control, $event)">
|
|
101781
|
+
@for (value of control.values; track value) {
|
|
101782
|
+
<option [value]="value" [selected]="value === arrowValue(control)">
|
|
101783
|
+
{{ optionLabelKey(control, value) | translate }}
|
|
101784
|
+
</option>
|
|
100218
101785
|
}
|
|
100219
101786
|
</select>
|
|
100220
101787
|
</label>
|
|
@@ -120842,5 +122409,5 @@ function cn(...values) {
|
|
|
120842
122409
|
* Generated bundle index. Do not edit.
|
|
120843
122410
|
*/
|
|
120844
122411
|
|
|
120845
|
-
export { CustomShowsComponent as $, ALIGN_OPTIONS as A, BroadcastDialogComponent as B, CHART_EDITOR_STYLES as C, CanvasFitService as D, ChartAxisOptionsComponent as E, ChartAxisStyleOptionsComponent as F, ChartComboTypeOptionsComponent as G, ChartDataEditorComponent as H, ChartDataLabelOptionsComponent as I, ChartDatapointMarkerOptionsComponent as J, ChartDatapointOptionsComponent as K, ChartDisplayOptionsComponent as L, ChartElementViewComponent as M, ChartErrorBarOptionsComponent as N, ChartMarkerOptionsComponent as O, ChartPartSelectionService as P, ChartPrimitivesComponent as Q, ChartRendererComponent as R, ChartTrendlineOptionsComponent as S, CollaborationCursorsComponent as T, CollaborationService as U, ColorChangedImageComponent as V, CommentsPanelComponent as W, CommentsService as X, ComparePanelComponent as Y, ConnectorRendererComponent as Z, ConnectorTextOverlayComponent as _, ANIMATION_PRESET_CATEGORIES as a, LoadContentService as a$, DATA_TABLE_HEADER_H as a0, DATA_TABLE_KEY_W as a1, DATA_TABLE_PADDING as a2, DATA_TABLE_ROW_H as a3, DEFAULT_BOUNDS as a4, DEFAULT_BROADCAST_SERVER_URL as a5, DEFAULT_CANVAS_HEIGHT as a6, DEFAULT_CANVAS_WIDTH as a7, DEFAULT_COLOR_SCHEME as a8, DEFAULT_FILL_COLOR as a9, EquationEditorDialogComponent as aA, EquationRendererComponent as aB, EquationTemplateGalleryComponent as aC, ExportProgressModalComponent as aD, ExportService as aE, FieldContextService as aF, FindBarComponent as aG, FindReplaceBarComponent as aH, FollowModeBarComponent as aI, FontEmbeddingListComponent as aJ, FontEmbeddingPanelComponent as aK, GALLERY_THEME_PRESETS as aL, GradientPickerComponent as aM, HANDOUT_OPTIONS as aN, HeaderFooterDialogComponent as aO, HyperlinkDialogComponent as aP, ImagePropertiesPanelComponent as aQ, InkDrawingService as aR, InkRendererComponent as aS, InsertSmartArtDialogComponent as aT, InspectorPaneHeaderComponent as aU, InspectorPanelComponent as aV, IsMobileService as aW, KeepAnnotationsDialogComponent as aX, LOCALE_CATALOG as aY, LONG_PRESS_DURATION_MS as aZ, LONG_PRESS_MOVE_TOLERANCE_PX as a_, DEFAULT_LAYOUT as aa, DEFAULT_PALETTE$1 as ab, DEFAULT_PATTERN_FILL_PRESET as ac, DEFAULT_PRINT_SETTINGS as ad, DEFAULT_SLIDE_BACKGROUND as ae, DEFAULT_STROKE_COLOR as af, DEFAULT_STYLE as ag, DEFAULT_TABLE_ROW_HEIGHT as ah, DEFAULT_TEXT_COLOR$1 as ai, DEFAULT_VIEWER_PROFILE as aj, DIRECTIONAL_PRESETS as ak, DIRECTION_OPTIONS as al, DocumentPropertiesCardComponent as am, EMBEDDED_FONTS_STYLE_ID as an, EMPHASIS_PRESETS as ao, ENTRANCE_PRESETS as ap, TEMPLATES as aq, EXIT_PRESETS as ar, EditorContextMenuComponent as as, EditorHistory as at, EditorStateService as au, EditorToolbarComponent as av, EffectsPanelComponent as aw, ElementRendererComponent as ax, EmbeddedFontsService as ay, EncryptedFileDialogComponent as az, AUDIENCE_HASH as b, RibbonInsertFieldsComponent as b$, LocalPresencePublisher as b0, MAX_ZOOM_SCALE as b1, MIN_ZOOM_SCALE as b2, MOTION_PATH_COLUMNS as b3, MediaPreviewComponent as b4, MediaPropertiesPanelComponent as b5, MediaRendererComponent as b6, MediaTrimTimelineComponent as b7, MobileBottomBarComponent as b8, MobileMenuSheetComponent as b9, PresentationToolbarComponent as bA, PresentationTransitionOverlayComponent as bB, PresenterViewComponent as bC, PresenterWindowService as bD, PrintDialogComponent as bE, PrintService as bF, PrintSettingsPanelComponent as bG, PropertiesDialogComponent as bH, REPEAT_MODE_OPTIONS as bI, RESIZE_HANDLES as bJ, RULER_FONT_SIZE as bK, RULER_THICKNESS as bL, ReadingViewOverlayComponent as bM, RemoteSelectionOverlayComponent as bN, RibbonAnimationGalleryComponent as bO, RibbonAnimationsSectionComponent as bP, RibbonArrangeSectionComponent as bQ, RibbonColorPopoverComponent as bR, RibbonComponent as bS, RibbonDesignSectionComponent as bT, RibbonDrawSectionComponent as bU, RibbonDrawingGroupComponent as bV, RibbonEditingSectionComponent as bW, RibbonFileSectionComponent as bX, RibbonFontControlsComponent as bY, RibbonHomeSectionComponent as bZ, RibbonHyperlinkButtonComponent as b_, MobilePresenterViewComponent as ba, MobileSheetComponent as bb, MobileSlidesSheetComponent as bc, MobileToolbarComponent as bd, ModalDialogComponent as be, Model3DRendererComponent as bf, NotesHandoutCardComponent as bg, NotesPanelComponent as bh, NotesToolbarComponent as bi, OleRendererComponent as bj, OutlineViewOverlayComponent as bk, POWER_POINT_VIEWER_PROVIDERS as bl, PRESENTER_CHANNEL_NAME as bm, PRESENTER_MSG_ORIGIN as bn, PX_PER_CM as bo, PX_PER_INCH as bp, PasswordProtectionDialogComponent as bq, PasswordStrengthMeterComponent as br, PowerPointViewerComponent as bs, PresentToolbarAutoHide as bt, PresentationAnnotationOverlayComponent as bu, PresentationAnnotationsService as bv, PresentationOverlayComponent as bw, PresentationPropertiesPanelComponent as bx, PresentationSettingsCardComponent as by, PresentationSubtitleBarComponent as bz, AUDIENCE_NONCE_KEY as c, TablePropertiesComponent as c$, RibbonInsertSectionComponent as c0, RibbonMotionPathGalleryComponent as c1, RibbonParagraphControlsComponent as c2, RibbonPrimaryRowComponent as c3, RibbonReviewSectionComponent as c4, RibbonShapeExtrasComponent as c5, RibbonSlideshowSectionComponent as c6, RibbonTransitionsSectionComponent as c7, RibbonViewSectionComponent as c8, RulerGuidesService as c9, SlideCanvasComponent as cA, SlideDefaultInspectorComponent as cB, SlideDiffChangesComponent as cC, SlideDiffRowComponent as cD, SlideDiffThumbnailsComponent as cE, SlideSizeCardComponent as cF, SlideSorterOverlayComponent as cG, SlideThemeOverridePanelComponent as cH, SlideTransitionCardComponent as cI, SlidesPanelComponent as cJ, SmartArt3DRendererComponent as cK, SmartArt3DService as cL, SmartArtPreviewComponent as cM, SmartArtPropertiesComponent as cN, SmartArtRendererComponent as cO, StatusBarComponent as cP, TABLE_STRUCTURE_TOGGLES as cQ, TEXT_3D_BOTTOM_BEVEL_KEYS as cR, TEXT_3D_TOP_BEVEL_KEYS as cS, TEXT_DIRECTION_OPTIONS$1 as cT, THEME_CATALOG as cU, TIMING_CURVE_OPTIONS as cV, TRIGGER_OPTIONS as cW, TYPE_LABELS as cX, TableCellAdvancedFillComponent as cY, TableCellFormattingComponent as cZ, TableDataEditorComponent as c_, SEQUENCE_OPTIONS as ca, SEVERITY_GROUPS as cb, SEVERITY_LABELS as cc, SHORTCUT_REFERENCE_ITEMS as cd, SLIDE_TRANSITION_KEYFRAMES as ce, DEFAULT_PALETTE as cf, PALETTES$1 as cg, SMART_ART_COLOR_SCHEMES as ch, SMART_ART_STYLE_OPTIONS as ci, SUB_ITEM_LABEL as cj, SVG_WARP_PRESETS as ck, SWIPE_MAX_VERTICAL_PX as cl, SWIPE_THRESHOLD_PX as cm, SelectionPaneComponent as cn, SetUpSlideShowDialogComponent as co, SettingsAppearanceTabComponent as cp, SettingsDialogComponent as cq, SettingsLanguageTabComponent as cr, ShareDialogComponent as cs, ShortcutPanelComponent as ct, ShowOptionsFieldsetComponent as cu, ShowSlidesFieldsetComponent as cv, SignatureStrippedDialogComponent as cw, SignaturesPanelComponent as cx, SignaturesService as cy, SlideBackgroundCardComponent as cz, AVATAR_COLOR_SWATCHES as d, attachTouchGestures as d$, TableRendererComponent as d0, TableResizeOverlayComponent as d1, TableSelectionService as d2, TagsCardComponent as d3, Text3DBevelSectionComponent as d4, Text3DPanelComponent as d5, TextAdvancedPanelComponent as d6, ThemeEditorFieldsComponent as d7, ThemeGalleryComponent as d8, ThemeSelectorCardComponent as d9, ViewerZoomService as dA, WEBM_MIME_CANDIDATES as dB, WriteBackScheduler as dC, ZoomNavigationService as dD, ZoomRendererComponent as dE, ZoomTargetService as dF, addCategory as dG, addCommentToList as dH, addGradientStopPatch as dI, addItem as dJ, addSeries as dK, addSubItem as dL, advanceStep as dM, aiToggleVisible as dN, alignPatch as dO, animationFor as dP, animationPresetLabelKey as dQ, annotationMapToInkInserts as dR, applyAcceptedDiff as dS, applyAnimationPreset as dT, applyFindReplacements as dU, applyFormatToElement as dV, applyMove as dW, applyResize as dX, applyTableStylePreset as dY, asMediaElement as dZ, assignUserColor as d_, TitleBarComponent as da, TitleBarSearchComponent as db, TransitionDirectionPickerComponent as dc, TransitionPreviewComponent as dd, VALIGN_OPTIONS as de, VIEWER_THEME as df, VersionHistoryPanelComponent as dg, ViewerCanvasEditingService as dh, ViewerCollabCursorService as di, ViewerCollaborationSessionService as dj, ViewerCompareService as dk, ViewerCustomShowsService as dl, ViewerDialogsService as dm, ViewerDocumentPropertiesService as dn, ViewerExportService as dp, ViewerExtraDialogsComponent as dq, ViewerFileIOService as dr, ViewerFindReplaceService as ds, ViewerFormatPainterService as dt, ViewerInspectorPanelService as du, ViewerKeyboardService as dv, ViewerMobileSheetService as dw, ViewerPresentationModeService as dx, ViewerThemeGalleryService as dy, ViewerTouchGesturesService as dz, AccessibilityPanelComponent as e, captionDisplayText as e$, beginNodeEdit as e0, bevelSizePatch as e1, boolFromEvent as e2, bringForward as e3, bringToFront as e4, buildBarActions as e5, buildBroadcastConfig as e6, buildBroadcastViewerUrl as e7, buildCategoryLabels as e8, buildCellParagraphs as e9, buildOleInfoRows as eA, buildPatternFillCss as eB, buildPrintHtmlDocument as eC, buildPropertiesPatch as eD, buildRegionMapViewModel as eE, buildSaveSlides as eF, buildShareUrl as eG, buildSmartArtInsertElement as eH, buildSmartArtNodes as eI, buildStockViewModel as eJ, buildSurfaceViewModel as eK, buildTableViewModel as eL, buildTreemapViewModel as eM, buildTrimFragment as eN, buildWaterfallViewModel as eO, buildZeroLine as eP, buildZoomContainerStyle as eQ, buildZoomViewModel as eR, bulletIndentPx as eS, canAddTopLevelNode as eT, canGroupSelection as eU, canRemoveTopLevelNode as eV, canSetStrokeWidth as eW, canStartBroadcast as eX, canStartShare as eY, canUngroupSelection as eZ, canUseClipboard as e_, buildChartViewModel as ea, buildChatLogExport as eb, buildChatLogMarkdown as ec, buildChromeStyle as ed, buildClearHyperlinkPatch as ee, buildClickGroups as ef, buildColStyles as eg, buildCollaborationConfig as eh, buildComboViewModel as ei, buildCssGradientFromShapeStyle as ej, buildDuotoneFilter as ek, buildDuotoneFilterId as el, buildEmbeddedFontStyles as em, buildEquationElement as en, buildEquationSegment as eo, buildFallbackViewModel as ep, buildFontFaceRule as eq, buildGradientFillCss as er, buildGridlinesAndLabels as es, buildHyperlinkPatch as et, buildInkContainerStyle as eu, buildInkStrokes as ev, buildLegend as ew, buildModel3DContainerStyle as ex, buildModel3DViewModel as ey, buildOleActionModel as ez, AccessibilityService as f, createSwipeDismissDrag as f$, cellRunStyle as f0, cellStyleToStyleMap as f1, cellTdStyle as f2, changeCountLabel as f3, changeIcon as f4, characterSpacingPatch as f5, checkFontAvailable as f6, clampCursorPosition as f7, clampGifDimensions as f8, clampIndex as f9, computeIsTablet as fA, computeLinePoints as fB, computeLinearRegression as fC, computePageCount as fD, computePieLayout as fE, computePieSlicePath as fF, computePieSlices as fG, computePlotLayout as fH, computeRSquared as fI, computeRadarPoints as fJ, computeScatterDots as fK, computeSelectionBoxes as fL, computeSingleSelected as fM, computeSlideIndices as fN, computeSnap as fO, computeStackedBarRects as fP, computeStackedValueRange as fQ, computeTextLines as fR, computeTimerProgress as fS, computeTrendlinePrimitives as fT, computeValueRange as fU, convertOmmlToMathMl as fV, copyFormatFromElement as fW, countAccessibilityIssues as fX, countAnnotationStrokes as fY, createAngularAiBridge as fZ, createCustomShow as f_, clampNotesFontSize as fa, clampScale as fb, clampStep as fc, clearAllLocalViewerData as fd, clearAudienceContent as fe, cn as ff, collectAccessibilityIssues as fg, collectElementText as fh, collectSlideText as fi, collectStoredChats as fj, collectUsedFontFamilies as fk, columnWidthStyle as fl, commitNodeText as fm, computeAlign as fn, computeAxisTitlePrimitives as fo, computeBarRects as fp, computeBubbleRadius as fq, computeCornerHandle as fr, computeDataTablePrimitives as fs, computeDistribute as ft, computeDrawingViewBox as fu, computeErrorBarPrimitives as fv, computeFocusTargets as fw, computeHandleBoxes as fx, computeHandoutLayout as fy, computeIsMobile as fz, AccountPageComponent as g, getImageSrc as g$, createWebrtcBundle as g0, createWebsocketBundle as g1, cssObjectToStyleMap as g2, currentColorScheme as g3, currentLayout as g4, currentStyle as g5, defaultCssVars as g6, defaultRadius as g7, defaultThemeColors as g8, deleteElementsByIds as g9, fillColorOf as gA, findInSlides as gB, findOwningSlideIndex as gC, findSlideIndexByElementId as gD, firstVisibleIndex as gE, fitPolynomial as gF, fitZoom as gG, focusTargetChips as gH, fontMimeForFormat as gI, fontSizeOf as gJ, formatAutoNumber as gK, formatAxisValue as gL, formatBytes as gM, formatCursorLabel as gN, formatElapsed as gO, formatFileSize as gP, formatPropertyDate as gQ, formatTime as gR, fpsToFrameIntervalMs as gS, generateBroadcastRoomId as gT, generateCommentId as gU, generateCustomShowId as gV, generatePressureCircles as gW, generateTicks as gX, getClrChangeParams as gY, getContainerStyle as gZ, getDuotoneFilterDef as g_, deleteVersion as ga, demoteNode as gb, deriveModel3DBlobUrl as gc, derivePresenceList as gd, describeSmartArtBounds as ge, disableGlowPatch as gf, disableInnerShadowPatch as gg, disableOuterShadowPatch as gh, disableReflectionPatch as gi, disableSoftEdgePatch as gj, duplicateElementById as gk, durationOf as gl, effectsStateOf as gm, enableGlowPatch as gn, enableInnerShadowPatch as go, enableOuterShadowPatch as gp, enableReflectionPatch as gq, enableSoftEdgePatch as gr, encodeGif as gs, estimatePageCount as gt, evenColumnWidths as gu, evenRowHeights as gv, exitPresentationFullscreen as gw, exportAiChatLogs as gx, extractPathPoints as gy, eyedropperAvailable as gz, ActionSettingsPanelComponent as h, latexToMathml as h$, getLocalStorageUsageSummary as h0, getOleAriaLabel as h1, getOleBadgeLabel as h2, getOleDisplayName as h3, getOleDownloadFileName as h4, getOleTypeColor as h5, getOleTypeLabel as h6, getPasswordStrength as h7, getPatternSvg as h8, getPlaceholderStyle as h9, headerLabel as hA, imageDimensions as hB, inkViewBox as hC, insertTableElementColumn as hD, insertTableElementRow as hE, interpolateWidth as hF, isAudienceTab as hG, isBold as hH, isBrowserOpenableMime as hI, isChildNode as hJ, isElementInteractive as hK, isInjectableUrl as hL, isItalic as hM, isPpactionUrl as hN, isPresenterMessage as hO, isSigned as hP, isTextElement as hQ, isTwoTableFocus as hR, isUnderline as hS, isUrlSafe as hT, isValidRoomId as hU, isViewportBackgroundPressTarget as hV, isZoomActivationKey as hW, issueTrackKey as hX, issueTypeLabel as hY, keyToLabel as hZ, lastVisibleIndex as h_, getVersions as ha, getResolvedShapeClipPath as hb, getResolvedShapeClipPathFor as hc, getShapeFillStrokeStyle as hd, getSlideBackgroundStyle as he, getSlideTransitionAnimations as hf, getSmartArtNodeBounds as hg, getSpeechRecognitionCtor as hh, getTextBlockStyle as hi, getTextWarp as hj, getTouchDistance as hk, getWarpCategory as hl, getWarpPath as hm, gradientStateFromStyle as hn, gradientStateOf as ho, gradientStatePatch as hp, gridColumns as hq, groupElements as hr, groupIssuesBySeverity as hs, hasAnimation as ht, hasCopyableFormat as hu, hasExistingLink as hv, hasExitedFullscreen as hw, hasGradientFill as hx, hasPressureVariation as hy, hasVisibleSlideAfter as hz, AdvancedChartEditorComponent as i, radarAngle as i$, linePointsToSvgString as i0, lineSpacingPatch as i1, loadAudienceContent as i2, mergeCaptionResults as i3, mergeDown as i4, mergeRight as i5, mergeSelection as i6, moveElementBy as i7, moveNodeDown as i8, moveNodeUp as i9, ooxmlDashToCssBorderStyle as iA, openNativeEyeDropper as iB, overallStatus as iC, paletteColor as iD, parseAudienceNonce as iE, parseNodeTextarea as iF, partitionSlides as iG, patchChartData as iH, patchChartStyle as iI, patchTableData as iJ, patchTextStyle as iK, patternPresetOptions as iL, pendingElementStyles as iM, pickColorByClickFallback as iN, pickFile as iO, pickSupportedMimeType as iP, planGifFrames as iQ, planVideoSegments as iR, pointsToSvgPathD as iS, presenceToCursors as iT, presetByLayout as iU, presetsForCategory as iV, pressuresToWidths as iW, prevVisibleIndex as iX, projectDrawingShapes as iY, promoteNode as iZ, provideViewerTheme as i_, msToFrameDelayCs as ia, narrowToCircle as ib, narrowToPolygon as ic, narrowToRect as id, newChartElement as ie, newEquationElement as ig, newPresetShapeElement as ih, newShapeElement as ii, newSmartArtElement as ij, newTableElement as ik, newTextElement as il, nextVisibleIndex as im, nodeBold as io, nodeEditBox as ip, nodeFillColor as iq, nodeFontColor as ir, nodeIdFromKey as is, nodeItalic as it, nodeStyle as iu, normalizeFontFormat as iv, normalizeSlidesPerPage as iw, normalizeValue as ix, numFromEvent as iy, ommlToMathml as iz, AiChangeOverlayComponent as j, setAxisLogScale as j$, radarRingPoints as j0, readAsDataUrl as j1, recordWebm as j2, redistributeColumnWidth as j3, removeAnimation as j4, removeCategory as j5, removeTableElementColumn as j6, removeCommentFromList as j7, removeElementAnimation as j8, removeGradientStopPatch as j9, routeOrthogonalConnector as jA, rowStyle as jB, rulerDragToGuidePosition as jC, rulerHighlight as jD, rulerStripTicks as jE, sampleColorFromSlide as jF, sanitizeColor as jG, sanitizeSlideIndex as jH, sanitizeUserName as jI, saveViewerProfile as jJ, scanAvailableFonts as jK, searchSlides as jL, seedBroadcastFields as jM, seedHyperlinkDraft as jN, seedPropertiesDraft as jO, seedShareFields as jP, segmentFrameCount as jQ, selectValue$2 as jR, sendBackward as jS, sendToBack as jT, sequentialColorScale as jU, serializeWriteBack as jV, seriesColor as jW, setAnimationEmphasis as jX, setAnimationEntrance as jY, setAnimationExit as jZ, setAxis as j_, removeNode as ja, removeTableElementRow as jb, removeSeries as jc, renderToCanvas as jd, reorderAnimationDown as je, reorderAnimationUp as jf, replaceInSlides as jg, replaceMatch as jh, requestPresentationFullscreen as ji, resizeElement as jj, resolveCaptionTracks as jk, resolveChartKind as jl, resolveFontVariant as jm, resolveHyperlinkHref as jn, resolveInteractiveElementId as jo, resolveMediaSrc as jp, resolveOleType as jq, resolveParagraphBullet as jr, resolvePresenterNotes as js, resolveProfileInitial as jt, resolveRegionCode as ju, resolveSlideAutoAdvanceMs as jv, resolvePalette as jw, resolveThemeCatalogEntry as jx, resolveTransitionDuration as jy, revealedElementStyles as jz, AiChatPanelComponent as k, textStyleOf as k$, setAxisTitleStyle as k0, setCategoryLabel as k1, setCellText as k2, setColorScheme as k3, setDataLabels as k4, setDataPointExplosion as k5, setDataPointFill as k6, setDataPointLabel as k7, setDataPointMarker as k8, setDelay as k9, shouldUseSvgWarp as kA, showDirectionPicker as kB, showsTemplateAffordance as kC, signatureCountLabel as kD, signatureKey as kE, signatureTimestamp as kF, signerName as kG, statusLabel as kH, slideNumberOf as kI, smartArtNodes as kJ, paletteColour as kK, snapToGridStep as kL, splitCursorCell as kM, splitMergedCell as kN, statusKind as kO, statusLabel$1 as kP, storeAudienceContent as kQ, stringFromEvent$5 as kR, strokeColorOf as kS, strokeToInkElement as kT, strokeWidthOf as kU, styleShadowFilter as kV, textAdvancedPatch as kW, textAdvancedStateFromStyle as kX, textAdvancedStateOf as kY, textColorOf as kZ, textDirectionPatch as k_, setDirection as ka, setDuration as kb, setElementPosition as kc, setGridlineStyle as kd, setLayout as ke, setLegend as kf, setNodeStyle as kg, setNodeText as kh, setRepeatCount as ki, setRepeatMode as kj, setSequence as kk, setSeriesChartType as kl, setSeriesColor as km, setSeriesErrorBars as kn, setSeriesMarker as ko, setSeriesName as kp, setSeriesTrendline as kq, setSeriesValue as kr, setStyle as ks, setTimingCurve as kt, setTitle as ku, setTrigger as kv, setTriggerShapeId as kw, shapeStylePatch as kx, sheetAfterNavigate as ky, shouldBlockClickAdvance as kz, AiChatService as l, textStylePatch as l0, themeStyle as l1, themeToCssVars as l2, thumbnailHeight as l3, thumbnailZoom as l4, toggleCommentResolvedInList as l5, toggleNodeBold as l6, toggleNodeItalic as l7, toggleSheet as l8, topLevelNodeCount as l9, transformSelectedTextCase as la, translationsEn as lb, ungroupElements as lc, updateElementById as ld, updateGlowPatch as le, updateGradientStopPatch as lf, updateInnerShadowPatch as lg, updateOuterShadowPatch as lh, updateReflectionPatch as li, vAlignPatch as lj, validatePassword as lk, validatePrintSettings as ll, validateRoomId as lm, valueToY as ln, vermilionDarkColors as lo, vermilionDarkTheme as lp, vermilionLightColors as lq, vermilionLightTheme as lr, vermilionRadius as ls, waypointsToPathD as lt, worstStatus as lu, zoomTargetSlideIndex as lv, AiComposerComponent as m, AiFocusBarComponent as n, AiFocusHighlightOverlayComponent as o, AiMessageListComponent as p, AiPanelStore as q, AiProposalCardComponent as r, AiSettingsSectionComponent as s, toChatSummary as t, AiToolCallCardComponent as u, AnimationAuthorPanelComponent as v, AnimationPanelComponent as w, AnimationPlaybackService as x, AutosaveService as y, CURSOR_PALETTE as z };
|
|
120846
|
-
//# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-
|
|
122412
|
+
export { CustomShowsComponent as $, ALIGN_OPTIONS as A, BroadcastDialogComponent as B, CHART_EDITOR_STYLES as C, CanvasFitService as D, ChartAxisOptionsComponent as E, ChartAxisStyleOptionsComponent as F, ChartComboTypeOptionsComponent as G, ChartDataEditorComponent as H, ChartDataLabelOptionsComponent as I, ChartDatapointMarkerOptionsComponent as J, ChartDatapointOptionsComponent as K, ChartDisplayOptionsComponent as L, ChartElementViewComponent as M, ChartErrorBarOptionsComponent as N, ChartMarkerOptionsComponent as O, ChartPartSelectionService as P, ChartPrimitivesComponent as Q, ChartRendererComponent as R, ChartTrendlineOptionsComponent as S, CollaborationCursorsComponent as T, CollaborationService as U, ColorChangedImageComponent as V, CommentsPanelComponent as W, CommentsService as X, ComparePanelComponent as Y, ConnectorRendererComponent as Z, ConnectorTextOverlayComponent as _, ANIMATION_PRESET_CATEGORIES as a, LoadContentService as a$, DATA_TABLE_HEADER_H as a0, DATA_TABLE_KEY_W as a1, DATA_TABLE_PADDING as a2, DATA_TABLE_ROW_H as a3, DEFAULT_BOUNDS as a4, DEFAULT_BROADCAST_SERVER_URL as a5, DEFAULT_CANVAS_HEIGHT as a6, DEFAULT_CANVAS_WIDTH as a7, DEFAULT_COLOR_SCHEME as a8, DEFAULT_FILL_COLOR as a9, EquationEditorDialogComponent as aA, EquationRendererComponent as aB, EquationTemplateGalleryComponent as aC, ExportProgressModalComponent as aD, ExportService as aE, FieldContextService as aF, FindBarComponent as aG, FindReplaceBarComponent as aH, FollowModeBarComponent as aI, FontEmbeddingListComponent as aJ, FontEmbeddingPanelComponent as aK, GALLERY_THEME_PRESETS as aL, GradientPickerComponent as aM, HANDOUT_OPTIONS as aN, HeaderFooterDialogComponent as aO, HyperlinkDialogComponent as aP, ImagePropertiesPanelComponent as aQ, InkDrawingService as aR, InkRendererComponent as aS, InsertSmartArtDialogComponent as aT, InspectorPaneHeaderComponent as aU, InspectorPanelComponent as aV, IsMobileService as aW, KeepAnnotationsDialogComponent as aX, LOCALE_CATALOG as aY, LONG_PRESS_DURATION_MS as aZ, LONG_PRESS_MOVE_TOLERANCE_PX as a_, DEFAULT_LAYOUT as aa, DEFAULT_PALETTE$1 as ab, DEFAULT_PATTERN_FILL_PRESET as ac, DEFAULT_PRINT_SETTINGS as ad, DEFAULT_SLIDE_BACKGROUND as ae, DEFAULT_STROKE_COLOR as af, DEFAULT_STYLE as ag, DEFAULT_TABLE_ROW_HEIGHT as ah, DEFAULT_TEXT_COLOR$1 as ai, DEFAULT_VIEWER_PROFILE as aj, DIRECTIONAL_PRESETS as ak, DIRECTION_OPTIONS as al, DocumentPropertiesCardComponent as am, EMBEDDED_FONTS_STYLE_ID as an, EMPHASIS_PRESETS as ao, ENTRANCE_PRESETS as ap, TEMPLATES as aq, EXIT_PRESETS as ar, EditorContextMenuComponent as as, EditorHistory as at, EditorStateService as au, EditorToolbarComponent as av, EffectsPanelComponent as aw, ElementRendererComponent as ax, EmbeddedFontsService as ay, EncryptedFileDialogComponent as az, AUDIENCE_HASH as b, RibbonHyperlinkButtonComponent as b$, LocalPresencePublisher as b0, MAX_ZOOM_SCALE as b1, MIN_ZOOM_SCALE as b2, MOTION_PATH_COLUMNS as b3, MediaPreviewComponent as b4, MediaPropertiesPanelComponent as b5, MediaRendererComponent as b6, MediaTrimTimelineComponent as b7, MobileBottomBarComponent as b8, MobileMenuSheetComponent as b9, PresentationSubtitleBarComponent as bA, PresentationToolbarComponent as bB, PresentationTransitionOverlayComponent as bC, PresenterViewComponent as bD, PresenterWindowService as bE, PrintDialogComponent as bF, PrintService as bG, PrintSettingsPanelComponent as bH, PropertiesDialogComponent as bI, REPEAT_MODE_OPTIONS as bJ, RESIZE_HANDLES as bK, RULER_FONT_SIZE as bL, RULER_THICKNESS as bM, ReadingViewOverlayComponent as bN, RemoteSelectionOverlayComponent as bO, RibbonAnimationGalleryComponent as bP, RibbonAnimationsSectionComponent as bQ, RibbonArrangeSectionComponent as bR, RibbonColorPopoverComponent as bS, RibbonComponent as bT, RibbonDesignSectionComponent as bU, RibbonDrawSectionComponent as bV, RibbonDrawingGroupComponent as bW, RibbonEditingSectionComponent as bX, RibbonFileSectionComponent as bY, RibbonFontControlsComponent as bZ, RibbonHomeSectionComponent as b_, MobilePresenterViewComponent as ba, MobileSheetComponent as bb, MobileSlidesSheetComponent as bc, MobileToolbarComponent as bd, ModalDialogComponent as be, Model3DRendererComponent as bf, NotesHandoutCardComponent as bg, NotesPanelComponent as bh, NotesToolbarComponent as bi, OleRendererComponent as bj, OutlineViewOverlayComponent as bk, POWER_POINT_VIEWER_PROVIDERS as bl, PRESENTER_CHANNEL_NAME as bm, PRESENTER_MSG_ORIGIN as bn, PRESENTER_TIMER_SEGMENT_MS as bo, PX_PER_CM as bp, PX_PER_INCH as bq, PasswordProtectionDialogComponent as br, PasswordStrengthMeterComponent as bs, PowerPointViewerComponent as bt, PresentToolbarAutoHide as bu, PresentationAnnotationOverlayComponent as bv, PresentationAnnotationsService as bw, PresentationOverlayComponent as bx, PresentationPropertiesPanelComponent as by, PresentationSettingsCardComponent as bz, AUDIENCE_NONCE_KEY as c, TableDataEditorComponent as c$, RibbonInsertFieldsComponent as c0, RibbonInsertSectionComponent as c1, RibbonMotionPathGalleryComponent as c2, RibbonParagraphControlsComponent as c3, RibbonPrimaryRowComponent as c4, RibbonReviewSectionComponent as c5, RibbonShapeExtrasComponent as c6, RibbonSlideshowSectionComponent as c7, RibbonTransitionsSectionComponent as c8, RibbonViewSectionComponent as c9, SlideBackgroundCardComponent as cA, SlideCanvasComponent as cB, SlideDefaultInspectorComponent as cC, SlideDiffChangesComponent as cD, SlideDiffRowComponent as cE, SlideDiffThumbnailsComponent as cF, SlideSizeCardComponent as cG, SlideSorterOverlayComponent as cH, SlideThemeOverridePanelComponent as cI, SlideTransitionCardComponent as cJ, SlidesPanelComponent as cK, SmartArt3DRendererComponent as cL, SmartArt3DService as cM, SmartArtPreviewComponent as cN, SmartArtPropertiesComponent as cO, SmartArtRendererComponent as cP, StatusBarComponent as cQ, TABLE_STRUCTURE_TOGGLES as cR, TEXT_3D_BOTTOM_BEVEL_KEYS as cS, TEXT_3D_TOP_BEVEL_KEYS as cT, TEXT_DIRECTION_OPTIONS$1 as cU, THEME_CATALOG as cV, TIMING_CURVE_OPTIONS as cW, TRIGGER_OPTIONS as cX, TYPE_LABELS as cY, TableCellAdvancedFillComponent as cZ, TableCellFormattingComponent as c_, RulerGuidesService as ca, SEQUENCE_OPTIONS as cb, SEVERITY_GROUPS as cc, SEVERITY_LABELS as cd, SHORTCUT_REFERENCE_ITEMS as ce, SLIDE_TRANSITION_KEYFRAMES as cf, DEFAULT_PALETTE as cg, PALETTES$1 as ch, SMART_ART_COLOR_SCHEMES as ci, SMART_ART_STYLE_OPTIONS as cj, SUB_ITEM_LABEL as ck, SVG_WARP_PRESETS as cl, SWIPE_MAX_VERTICAL_PX as cm, SWIPE_THRESHOLD_PX as cn, SelectionPaneComponent as co, SetUpSlideShowDialogComponent as cp, SettingsAppearanceTabComponent as cq, SettingsDialogComponent as cr, SettingsLanguageTabComponent as cs, ShareDialogComponent as ct, ShortcutPanelComponent as cu, ShowOptionsFieldsetComponent as cv, ShowSlidesFieldsetComponent as cw, SignatureStrippedDialogComponent as cx, SignaturesPanelComponent as cy, SignaturesService as cz, AVATAR_COLOR_SWATCHES as d, asMediaElement as d$, TablePropertiesComponent as d0, TableRendererComponent as d1, TableResizeOverlayComponent as d2, TableSelectionService as d3, TagsCardComponent as d4, Text3DBevelSectionComponent as d5, Text3DPanelComponent as d6, TextAdvancedPanelComponent as d7, ThemeEditorFieldsComponent as d8, ThemeGalleryComponent as d9, ViewerTouchGesturesService as dA, ViewerZoomService as dB, WEBM_MIME_CANDIDATES as dC, WriteBackScheduler as dD, ZoomNavigationService as dE, ZoomRendererComponent as dF, ZoomTargetService as dG, addCategory as dH, addCommentToList as dI, addGradientStopPatch as dJ, addItem as dK, addSeries as dL, addSubItem as dM, advanceStep as dN, affordanceElements as dO, aiToggleVisible as dP, alignPatch as dQ, animationFor as dR, animationPresetLabelKey as dS, annotationMapToInkInserts as dT, applyAcceptedDiff as dU, applyAnimationPreset as dV, applyFindReplacements as dW, applyFormatToElement as dX, applyMove as dY, applyResize as dZ, applyTableStylePreset as d_, ThemeSelectorCardComponent as da, TitleBarComponent as db, TitleBarSearchComponent as dc, TransitionDirectionPickerComponent as dd, TransitionPreviewComponent as de, VALIGN_OPTIONS as df, VIEWER_THEME as dg, VersionHistoryPanelComponent as dh, ViewerCanvasEditingService as di, ViewerCollabCursorService as dj, ViewerCollaborationSessionService as dk, ViewerCompareService as dl, ViewerCustomShowsService as dm, ViewerDialogsService as dn, ViewerDocumentPropertiesService as dp, ViewerExportService as dq, ViewerExtraDialogsComponent as dr, ViewerFileIOService as ds, ViewerFindReplaceService as dt, ViewerFormatPainterService as du, ViewerInspectorPanelService as dv, ViewerKeyboardService as dw, ViewerMobileSheetService as dx, ViewerPresentationModeService as dy, ViewerThemeGalleryService as dz, AccessibilityPanelComponent as e, canUngroupSelection as e$, assignUserColor as e0, attachTouchGestures as e1, beginNodeEdit as e2, bevelSizePatch as e3, boolFromEvent as e4, bringForward as e5, bringToFront as e6, buildBarActions as e7, buildBroadcastConfig as e8, buildBroadcastViewerUrl as e9, buildModel3DViewModel as eA, buildOleActionModel as eB, buildOleInfoRows as eC, buildPatternFillCss as eD, buildPrintHtmlDocument as eE, buildPropertiesPatch as eF, buildRegionMapViewModel as eG, buildSaveSlides as eH, buildShareUrl as eI, buildSmartArtInsertElement as eJ, buildSmartArtNodes as eK, buildStockViewModel as eL, buildSurfaceViewModel as eM, buildTableViewModel as eN, buildTreemapViewModel as eO, buildTrimFragment as eP, buildWaterfallViewModel as eQ, buildZeroLine as eR, buildZoomContainerStyle as eS, buildZoomViewModel as eT, bulletIndentPx as eU, canAddTopLevelNode as eV, canGroupSelection as eW, canRemoveTopLevelNode as eX, canSetStrokeWidth as eY, canStartBroadcast as eZ, canStartShare as e_, buildCategoryLabels as ea, buildCellParagraphs as eb, buildChartViewModel as ec, buildChatLogExport as ed, buildChatLogMarkdown as ee, buildChromeStyle as ef, buildClearHyperlinkPatch as eg, buildClickGroups as eh, buildColStyles as ei, buildCollaborationConfig as ej, buildComboViewModel as ek, buildCssGradientFromShapeStyle as el, buildDuotoneFilter as em, buildDuotoneFilterId as en, buildEmbeddedFontStyles as eo, buildEquationElement as ep, buildEquationSegment as eq, buildFallbackViewModel as er, buildFontFaceRule as es, buildGradientFillCss as et, buildGridlinesAndLabels as eu, buildHyperlinkPatch as ev, buildInkContainerStyle as ew, buildInkStrokes as ex, buildLegend as ey, buildModel3DContainerStyle as ez, AccessibilityService as f, createCustomShow as f$, canUseClipboard as f0, captionDisplayText as f1, cellRunStyle as f2, cellStyleToStyleMap as f3, cellTdStyle as f4, changeCountLabel as f5, changeIcon as f6, characterSpacingPatch as f7, checkFontAvailable as f8, clampCursorPosition as f9, computeHandoutLayout as fA, computeIsMobile as fB, computeIsTablet as fC, computeLinePoints as fD, computeLinearRegression as fE, computePageCount as fF, computePieLayout as fG, computePieSlicePath as fH, computePieSlices as fI, computePlotLayout as fJ, computeRSquared as fK, computeRadarPoints as fL, computeScatterDots as fM, computeSelectionBoxes as fN, computeSingleSelected as fO, computeSlideIndices as fP, computeSnap as fQ, computeStackedBarRects as fR, computeStackedValueRange as fS, computeTextLines as fT, computeTrendlinePrimitives as fU, computeValueRange as fV, convertOmmlToMathMl as fW, copyFormatFromElement as fX, countAccessibilityIssues as fY, countAnnotationStrokes as fZ, createAngularAiBridge as f_, clampGifDimensions as fa, clampIndex as fb, clampNotesFontSize as fc, clampScale as fd, clampStep as fe, clearAllLocalViewerData as ff, clearAudienceContent as fg, cn as fh, collectAccessibilityIssues as fi, collectElementText as fj, collectSlideText as fk, collectStoredChats as fl, collectUsedFontFamilies as fm, columnWidthStyle as fn, commitNodeText as fo, computeAlign as fp, computeAxisTitlePrimitives as fq, computeBarRects as fr, computeBubbleRadius as fs, computeCornerHandle as ft, computeDataTablePrimitives as fu, computeDistribute as fv, computeDrawingViewBox as fw, computeErrorBarPrimitives as fx, computeFocusTargets as fy, computeHandleBoxes as fz, AccountPageComponent as g, getDuotoneFilterDef as g$, createSwipeDismissDrag as g0, createWebrtcBundle as g1, createWebsocketBundle as g2, cssObjectToStyleMap as g3, currentColorScheme as g4, currentLayout as g5, currentStyle as g6, defaultCssVars as g7, defaultRadius as g8, defaultThemeColors as g9, eyedropperAvailable as gA, fillColorOf as gB, findInSlides as gC, findOwningSlideIndex as gD, findSlideIndexByElementId as gE, firstVisibleIndex as gF, fitPolynomial as gG, fitZoom as gH, focusTargetChips as gI, fontMimeForFormat as gJ, fontSizeOf as gK, formatAutoNumber as gL, formatAxisValue as gM, formatBytes as gN, formatCursorLabel as gO, formatElapsed as gP, formatFileSize as gQ, formatPropertyDate as gR, formatTime as gS, fpsToFrameIntervalMs as gT, generateBroadcastRoomId as gU, generateCommentId as gV, generateCustomShowId as gW, generatePressureCircles as gX, generateTicks as gY, getClrChangeParams as gZ, getContainerStyle as g_, deleteElementsByIds as ga, deleteVersion as gb, demoteNode as gc, deriveModel3DBlobUrl as gd, derivePresenceList as ge, describeSmartArtBounds as gf, disableGlowPatch as gg, disableInnerShadowPatch as gh, disableOuterShadowPatch as gi, disableReflectionPatch as gj, disableSoftEdgePatch as gk, duplicateElementById as gl, durationOf as gm, effectsStateOf as gn, enableGlowPatch as go, enableInnerShadowPatch as gp, enableOuterShadowPatch as gq, enableReflectionPatch as gr, enableSoftEdgePatch as gs, encodeGif as gt, estimatePageCount as gu, evenColumnWidths as gv, evenRowHeights as gw, exitPresentationFullscreen as gx, exportAiChatLogs as gy, extractPathPoints as gz, ActionSettingsPanelComponent as h, lastVisibleIndex as h$, getImageSrc as h0, getLocalStorageUsageSummary as h1, getOleAriaLabel as h2, getOleBadgeLabel as h3, getOleDisplayName as h4, getOleDownloadFileName as h5, getOleTypeColor as h6, getOleTypeLabel as h7, getPasswordStrength as h8, getPatternSvg as h9, hasVisibleSlideAfter as hA, headerLabel as hB, imageDimensions as hC, inkViewBox as hD, insertTableElementColumn as hE, insertTableElementRow as hF, interpolateWidth as hG, isAudienceTab as hH, isBold as hI, isBrowserOpenableMime as hJ, isChildNode as hK, isElementInteractive as hL, isInjectableUrl as hM, isItalic as hN, isPpactionUrl as hO, isPresenterMessage as hP, isSigned as hQ, isTextElement as hR, isTwoTableFocus as hS, isUnderline as hT, isUrlSafe as hU, isValidRoomId as hV, isViewportBackgroundPressTarget as hW, isZoomActivationKey as hX, issueTrackKey as hY, issueTypeLabel as hZ, keyToLabel as h_, getPlaceholderStyle as ha, getVersions as hb, getResolvedShapeClipPath as hc, getResolvedShapeClipPathFor as hd, getShapeFillStrokeStyle as he, getSlideBackgroundStyle as hf, getSlideTransitionAnimations as hg, getSmartArtNodeBounds as hh, getSpeechRecognitionCtor as hi, getTextBlockStyle as hj, getTextWarp as hk, getTouchDistance as hl, getWarpCategory as hm, getWarpPath as hn, gradientStateFromStyle as ho, gradientStateOf as hp, gradientStatePatch as hq, gridColumns as hr, groupElements as hs, groupIssuesBySeverity as ht, hasAnimation as hu, hasCopyableFormat as hv, hasExistingLink as hw, hasExitedFullscreen as hx, hasGradientFill as hy, hasPressureVariation as hz, AdvancedChartEditorComponent as i, promoteNode as i$, latexToMathml as i0, linePointsToSvgString as i1, lineSpacingPatch as i2, loadAudienceContent as i3, mergeCaptionResults as i4, mergeDown as i5, mergeRight as i6, mergeSelection as i7, moveElementBy as i8, moveNodeDown as i9, ommlToMathml as iA, ooxmlDashToCssBorderStyle as iB, openNativeEyeDropper as iC, overallStatus as iD, paletteColor as iE, parseAudienceNonce as iF, parseNodeTextarea as iG, partitionSlides as iH, patchChartData as iI, patchChartStyle as iJ, patchTableData as iK, patchTextStyle as iL, patternPresetOptions as iM, pendingElementStyles as iN, pickColorByClickFallback as iO, pickFile as iP, pickSupportedMimeType as iQ, planGifFrames as iR, planVideoSegments as iS, pointsToSvgPathD as iT, presenceToCursors as iU, presenterTimerProgress as iV, presetByLayout as iW, presetsForCategory as iX, pressuresToWidths as iY, prevVisibleIndex as iZ, projectDrawingShapes as i_, moveNodeUp as ia, msToFrameDelayCs as ib, narrowToCircle as ic, narrowToPolygon as id, narrowToRect as ie, newChartElement as ig, newEquationElement as ih, newPresetShapeElement as ii, newShapeElement as ij, newSmartArtElement as ik, newTableElement as il, newTextElement as im, nextVisibleIndex as io, nodeBold as ip, nodeEditBox as iq, nodeFillColor as ir, nodeFontColor as is, nodeIdFromKey as it, nodeItalic as iu, nodeStyle as iv, normalizeFontFormat as iw, normalizeSlidesPerPage as ix, normalizeValue as iy, numFromEvent as iz, AiChangeOverlayComponent as j, setAnimationExit as j$, provideViewerTheme as j0, radarAngle as j1, radarRingPoints as j2, readAsDataUrl as j3, recordWebm as j4, redistributeColumnWidth as j5, removeAnimation as j6, removeCategory as j7, removeTableElementColumn as j8, removeCommentFromList as j9, resolveTransitionDuration as jA, revealedElementStyles as jB, routeOrthogonalConnector as jC, rowStyle as jD, rulerDragToGuidePosition as jE, rulerHighlight as jF, rulerStripTicks as jG, sampleColorFromSlide as jH, sanitizeColor as jI, sanitizeSlideIndex as jJ, sanitizeUserName as jK, saveViewerProfile as jL, scanAvailableFonts as jM, searchSlides as jN, seedBroadcastFields as jO, seedHyperlinkDraft as jP, seedPropertiesDraft as jQ, seedShareFields as jR, segmentFrameCount as jS, selectValue$2 as jT, sendBackward as jU, sendToBack as jV, sequentialColorScale as jW, serializeWriteBack as jX, seriesColor as jY, setAnimationEmphasis as jZ, setAnimationEntrance as j_, removeElementAnimation as ja, removeGradientStopPatch as jb, removeNode as jc, removeTableElementRow as jd, removeSeries as je, renderToCanvas as jf, reorderAnimationDown as jg, reorderAnimationUp as jh, replaceInSlides as ji, replaceMatch as jj, requestPresentationFullscreen as jk, resizeElement as jl, resolveCaptionTracks as jm, resolveChartKind as jn, resolveFontVariant as jo, resolveHyperlinkHref as jp, resolveInteractiveElementId as jq, resolveMediaSrc as jr, resolveOleType as js, resolveParagraphBullet as jt, resolvePresenterNotes as ju, resolveProfileInitial as jv, resolveRegionCode as jw, resolveSlideAutoAdvanceMs as jx, resolvePalette as jy, resolveThemeCatalogEntry as jz, AiChatPanelComponent as k, textColorOf as k$, setAxis as k0, setAxisLogScale as k1, setAxisTitleStyle as k2, setCategoryLabel as k3, setCellText as k4, setColorScheme as k5, setDataLabels as k6, setDataPointExplosion as k7, setDataPointFill as k8, setDataPointLabel as k9, sheetAfterNavigate as kA, shouldBlockClickAdvance as kB, shouldUseSvgWarp as kC, showDirectionPicker as kD, showsTemplateAffordance as kE, signatureCountLabel as kF, signatureKey as kG, signatureTimestamp as kH, signerName as kI, statusLabel as kJ, slideNumberOf as kK, smartArtNodes as kL, paletteColour as kM, snapToGridStep as kN, splitCursorCell as kO, splitMergedCell as kP, statusKind as kQ, statusLabel$1 as kR, storeAudienceContent as kS, stringFromEvent$5 as kT, strokeColorOf as kU, strokeToInkElement as kV, strokeWidthOf as kW, styleShadowFilter as kX, textAdvancedPatch as kY, textAdvancedStateFromStyle as kZ, textAdvancedStateOf as k_, setDataPointMarker as ka, setDelay as kb, setDirection as kc, setDuration as kd, setElementPosition as ke, setGridlineStyle as kf, setLayout as kg, setLegend as kh, setNodeStyle as ki, setNodeText as kj, setRepeatCount as kk, setRepeatMode as kl, setSequence as km, setSeriesChartType as kn, setSeriesColor as ko, setSeriesErrorBars as kp, setSeriesMarker as kq, setSeriesName as kr, setSeriesTrendline as ks, setSeriesValue as kt, setStyle as ku, setTimingCurve as kv, setTitle as kw, setTrigger as kx, setTriggerShapeId as ky, shapeStylePatch as kz, AiChatService as l, textDirectionPatch as l0, textStyleOf as l1, textStylePatch as l2, themeStyle as l3, themeToCssVars as l4, thumbnailHeight as l5, thumbnailZoom as l6, toggleCommentResolvedInList as l7, toggleNodeBold as l8, toggleNodeItalic as l9, toggleSheet as la, topLevelNodeCount as lb, transformSelectedTextCase as lc, translationsEn as ld, ungroupElements as le, updateElementById as lf, updateGlowPatch as lg, updateGradientStopPatch as lh, updateInnerShadowPatch as li, updateOuterShadowPatch as lj, updateReflectionPatch as lk, vAlignPatch as ll, validatePassword as lm, validatePrintSettings as ln, validateRoomId as lo, valueToY as lp, vermilionDarkColors as lq, vermilionDarkTheme as lr, vermilionLightColors as ls, vermilionLightTheme as lt, vermilionRadius as lu, waypointsToPathD as lv, worstStatus as lw, zoomTargetSlideIndex as lx, AiComposerComponent as m, AiFocusBarComponent as n, AiFocusHighlightOverlayComponent as o, AiMessageListComponent as p, AiPanelStore as q, AiProposalCardComponent as r, AiSettingsSectionComponent as s, toChatSummary as t, AiToolCallCardComponent as u, AnimationAuthorPanelComponent as v, AnimationPanelComponent as w, AnimationPlaybackService as x, AutosaveService as y, CURSOR_PALETTE as z };
|
|
122413
|
+
//# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-DYqQlNxt.mjs.map
|