pptx-react-viewer 1.1.4 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +512 -96
- package/dist/index.mjs +512 -97
- package/dist/viewer/index.js +530 -102
- package/dist/viewer/index.mjs +530 -103
- package/node_modules/emf-converter/dist/index.d.mts +2 -2
- package/node_modules/emf-converter/dist/index.d.ts +2 -2
- package/node_modules/emf-converter/dist/index.js +91 -33
- package/node_modules/emf-converter/dist/index.mjs +91 -33
- package/node_modules/emf-converter/package.json +1 -1
- package/node_modules/mtx-decompressor/dist/index.js +39 -9
- package/node_modules/mtx-decompressor/dist/index.mjs +39 -9
- package/node_modules/mtx-decompressor/package.json +1 -1
- package/node_modules/pptx-viewer-core/dist/cli/index.js +0 -0
- package/node_modules/pptx-viewer-core/dist/cli/index.mjs +0 -0
- package/node_modules/pptx-viewer-core/dist/converter/index.js +0 -0
- package/node_modules/pptx-viewer-core/dist/converter/index.mjs +0 -0
- package/node_modules/pptx-viewer-core/dist/index.d.mts +95 -11
- package/node_modules/pptx-viewer-core/dist/index.d.ts +95 -11
- package/node_modules/pptx-viewer-core/dist/index.js +795 -257
- package/node_modules/pptx-viewer-core/dist/index.mjs +791 -258
- package/node_modules/pptx-viewer-core/dist/{signature-inspection-status-BcJSdOvb.d.mts → signature-inspection-status-BCUpfCQh.d.mts} +13 -2
- package/node_modules/pptx-viewer-core/dist/{signature-inspection-status-BcJSdOvb.d.ts → signature-inspection-status-BCUpfCQh.d.ts} +13 -2
- package/node_modules/pptx-viewer-core/dist/signature-node/index.d.mts +2 -2
- package/node_modules/pptx-viewer-core/dist/signature-node/index.d.ts +2 -2
- package/node_modules/pptx-viewer-core/dist/signature-node/index.js +17 -3
- package/node_modules/pptx-viewer-core/dist/signature-node/index.mjs +16 -4
- package/node_modules/pptx-viewer-core/package.json +1 -1
- package/package.json +6 -4
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ var clsx = require('clsx');
|
|
|
7
7
|
var tailwindMerge = require('tailwind-merge');
|
|
8
8
|
var lu = require('react-icons/lu');
|
|
9
9
|
var pptxViewerCore = require('pptx-viewer-core');
|
|
10
|
+
var DOMPurify = require('dompurify');
|
|
10
11
|
var reactI18next = require('react-i18next');
|
|
11
12
|
var html2canvasPro = require('html2canvas-pro');
|
|
12
13
|
var JSZip = require('jszip');
|
|
@@ -33,6 +34,7 @@ function _interopNamespace(e) {
|
|
|
33
34
|
|
|
34
35
|
var React10__namespace = /*#__PURE__*/_interopNamespace(React10);
|
|
35
36
|
var ReactDOM__namespace = /*#__PURE__*/_interopNamespace(ReactDOM);
|
|
37
|
+
var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
|
|
36
38
|
var html2canvasPro__default = /*#__PURE__*/_interopDefault(html2canvasPro);
|
|
37
39
|
var JSZip__default = /*#__PURE__*/_interopDefault(JSZip);
|
|
38
40
|
|
|
@@ -43596,7 +43598,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
|
|
|
43596
43598
|
return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
|
|
43597
43599
|
}
|
|
43598
43600
|
function useSyncExternalStore$2(subscribe3, getSnapshot2) {
|
|
43599
|
-
didWarnOld18Alpha || void 0 ===
|
|
43601
|
+
didWarnOld18Alpha || void 0 === React100.startTransition || (didWarnOld18Alpha = true, console.error(
|
|
43600
43602
|
"You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
|
|
43601
43603
|
));
|
|
43602
43604
|
var value = getSnapshot2();
|
|
@@ -43606,7 +43608,7 @@ var require_use_sync_external_store_shim_development = __commonJS({
|
|
|
43606
43608
|
"The result of getSnapshot should be cached to avoid an infinite loop"
|
|
43607
43609
|
), didWarnUncachedGetSnapshot = true);
|
|
43608
43610
|
}
|
|
43609
|
-
cachedValue =
|
|
43611
|
+
cachedValue = useState86({
|
|
43610
43612
|
inst: { value, getSnapshot: getSnapshot2 }
|
|
43611
43613
|
});
|
|
43612
43614
|
var inst = cachedValue[0].inst, forceUpdate = cachedValue[1];
|
|
@@ -43644,8 +43646,8 @@ var require_use_sync_external_store_shim_development = __commonJS({
|
|
|
43644
43646
|
return getSnapshot2();
|
|
43645
43647
|
}
|
|
43646
43648
|
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
|
|
43647
|
-
var
|
|
43648
|
-
exports$1.useSyncExternalStore = void 0 !==
|
|
43649
|
+
var React100 = __require("react"), objectIs = "function" === typeof Object.is ? Object.is : is2, useState86 = React100.useState, useEffect72 = React100.useEffect, useLayoutEffect7 = React100.useLayoutEffect, useDebugValue = React100.useDebugValue, didWarnOld18Alpha = false, didWarnUncachedGetSnapshot = false, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
|
|
43650
|
+
exports$1.useSyncExternalStore = void 0 !== React100.useSyncExternalStore ? React100.useSyncExternalStore : shim;
|
|
43649
43651
|
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
|
|
43650
43652
|
})();
|
|
43651
43653
|
}
|
|
@@ -43668,7 +43670,7 @@ var require_with_selector_development = __commonJS({
|
|
|
43668
43670
|
return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
|
|
43669
43671
|
}
|
|
43670
43672
|
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
|
|
43671
|
-
var
|
|
43673
|
+
var React100 = __require("react"), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is2, useSyncExternalStore3 = shim.useSyncExternalStore, useRef73 = React100.useRef, useEffect72 = React100.useEffect, useMemo41 = React100.useMemo, useDebugValue = React100.useDebugValue;
|
|
43672
43674
|
exports$1.useSyncExternalStoreWithSelector = function(subscribe3, getSnapshot2, getServerSnapshot2, selector, isEqual) {
|
|
43673
43675
|
var instRef = useRef73(null);
|
|
43674
43676
|
if (null === instRef.current) {
|
|
@@ -74100,6 +74102,13 @@ function hasDistinctScriptFonts(fonts) {
|
|
|
74100
74102
|
}
|
|
74101
74103
|
return Boolean(fonts.eastAsia) && fonts.eastAsia !== base || Boolean(fonts.complexScript) && fonts.complexScript !== base || Boolean(fonts.symbol) && fonts.symbol !== base;
|
|
74102
74104
|
}
|
|
74105
|
+
function sanitizeMathMl(markup) {
|
|
74106
|
+
const purify = DOMPurify__default.default;
|
|
74107
|
+
if (typeof purify.sanitize !== "function") {
|
|
74108
|
+
return markup;
|
|
74109
|
+
}
|
|
74110
|
+
return purify.sanitize(markup, { USE_PROFILES: { mathMl: true, svg: true } });
|
|
74111
|
+
}
|
|
74103
74112
|
function renderScriptAwareText(text2, needsScriptFonts, scriptFonts, baseFontFamily, keyPrefix) {
|
|
74104
74113
|
if (!needsScriptFonts || !text2) {
|
|
74105
74114
|
return text2;
|
|
@@ -74190,14 +74199,15 @@ function renderSegmentContent(elementId, segmentIndex, textValue, lines, needsSc
|
|
|
74190
74199
|
}
|
|
74191
74200
|
function renderEquationSegment(elementId, segmentIndex, equationXml, equationNumber) {
|
|
74192
74201
|
const mathml = convertOmmlToMathMl(equationXml);
|
|
74193
|
-
const
|
|
74202
|
+
const safeMathml = mathml ? sanitizeMathMl(mathml) : "";
|
|
74203
|
+
const equationContent = safeMathml ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
74194
74204
|
"span",
|
|
74195
74205
|
{
|
|
74196
74206
|
className: "inline-block align-middle",
|
|
74197
74207
|
style: {
|
|
74198
74208
|
fontFamily: '"Cambria Math", "STIX Two Math", serif'
|
|
74199
74209
|
},
|
|
74200
|
-
dangerouslySetInnerHTML: { __html:
|
|
74210
|
+
dangerouslySetInnerHTML: { __html: safeMathml }
|
|
74201
74211
|
}
|
|
74202
74212
|
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block px-1 py-0.5 rounded text-xs bg-gray-200/20 text-gray-400 italic", children: "Equation" });
|
|
74203
74213
|
if (equationNumber) {
|
|
@@ -86554,7 +86564,7 @@ function ResizeHandle({
|
|
|
86554
86564
|
}
|
|
86555
86565
|
);
|
|
86556
86566
|
}
|
|
86557
|
-
function
|
|
86567
|
+
function SlideThumbnailImpl({
|
|
86558
86568
|
slide,
|
|
86559
86569
|
templateElements,
|
|
86560
86570
|
canvasSize
|
|
@@ -86792,6 +86802,37 @@ function ThumbnailTable({
|
|
|
86792
86802
|
}
|
|
86793
86803
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center text-[10px] text-muted-foreground pointer-events-none", children: "Table" });
|
|
86794
86804
|
}
|
|
86805
|
+
function arePropsEqual(prev, next) {
|
|
86806
|
+
if (prev.slide.id !== next.slide.id) {
|
|
86807
|
+
return false;
|
|
86808
|
+
}
|
|
86809
|
+
if (prev.slide.isDirty !== next.slide.isDirty) {
|
|
86810
|
+
return false;
|
|
86811
|
+
}
|
|
86812
|
+
if (prev.slide.hidden !== next.slide.hidden) {
|
|
86813
|
+
return false;
|
|
86814
|
+
}
|
|
86815
|
+
if (prev.slide.elements !== next.slide.elements) {
|
|
86816
|
+
return false;
|
|
86817
|
+
}
|
|
86818
|
+
if (prev.slide.backgroundColor !== next.slide.backgroundColor) {
|
|
86819
|
+
return false;
|
|
86820
|
+
}
|
|
86821
|
+
if (prev.slide.backgroundImage !== next.slide.backgroundImage) {
|
|
86822
|
+
return false;
|
|
86823
|
+
}
|
|
86824
|
+
if (prev.slide.backgroundGradient !== next.slide.backgroundGradient) {
|
|
86825
|
+
return false;
|
|
86826
|
+
}
|
|
86827
|
+
if (prev.templateElements !== next.templateElements) {
|
|
86828
|
+
return false;
|
|
86829
|
+
}
|
|
86830
|
+
if (prev.canvasSize.width !== next.canvasSize.width || prev.canvasSize.height !== next.canvasSize.height) {
|
|
86831
|
+
return false;
|
|
86832
|
+
}
|
|
86833
|
+
return true;
|
|
86834
|
+
}
|
|
86835
|
+
var SlideThumbnail = React10__namespace.default.memo(SlideThumbnailImpl, arePropsEqual);
|
|
86795
86836
|
function ContextMenu({
|
|
86796
86837
|
contextMenuState,
|
|
86797
86838
|
mode,
|
|
@@ -90525,7 +90566,7 @@ function BendingProcessRenderer({
|
|
|
90525
90566
|
}
|
|
90526
90567
|
);
|
|
90527
90568
|
}
|
|
90528
|
-
function
|
|
90569
|
+
function SmartArtRendererImpl({
|
|
90529
90570
|
element: element2,
|
|
90530
90571
|
className = ""
|
|
90531
90572
|
}) {
|
|
@@ -90636,6 +90677,30 @@ function renderLayout(layoutType, element2, nodes, palette, style) {
|
|
|
90636
90677
|
}
|
|
90637
90678
|
return /* @__PURE__ */ jsxRuntime.jsx(ListRenderer, { element: element2, nodes, palette, style });
|
|
90638
90679
|
}
|
|
90680
|
+
function arePropsEqual2(prev, next) {
|
|
90681
|
+
if (prev.className !== next.className) {
|
|
90682
|
+
return false;
|
|
90683
|
+
}
|
|
90684
|
+
if (prev.element.id !== next.element.id) {
|
|
90685
|
+
return false;
|
|
90686
|
+
}
|
|
90687
|
+
if (prev.element.type !== next.element.type) {
|
|
90688
|
+
return false;
|
|
90689
|
+
}
|
|
90690
|
+
if (prev.element.width !== next.element.width || prev.element.height !== next.element.height) {
|
|
90691
|
+
return false;
|
|
90692
|
+
}
|
|
90693
|
+
if (prev.element.x !== next.element.x || prev.element.y !== next.element.y) {
|
|
90694
|
+
return false;
|
|
90695
|
+
}
|
|
90696
|
+
const prevData = prev.element.type === "smartArt" ? prev.element.smartArtData : void 0;
|
|
90697
|
+
const nextData = next.element.type === "smartArt" ? next.element.smartArtData : void 0;
|
|
90698
|
+
if (prevData !== nextData) {
|
|
90699
|
+
return false;
|
|
90700
|
+
}
|
|
90701
|
+
return true;
|
|
90702
|
+
}
|
|
90703
|
+
var SmartArtRenderer = React10__namespace.default.memo(SmartArtRendererImpl, arePropsEqual2);
|
|
90639
90704
|
function ZoomElementRenderer({
|
|
90640
90705
|
element: element2,
|
|
90641
90706
|
slides,
|
|
@@ -93579,7 +93644,7 @@ function SectionBlock({
|
|
|
93579
93644
|
)
|
|
93580
93645
|
] });
|
|
93581
93646
|
}
|
|
93582
|
-
function
|
|
93647
|
+
function SlideCardImpl({
|
|
93583
93648
|
slide,
|
|
93584
93649
|
index,
|
|
93585
93650
|
isActive,
|
|
@@ -93633,6 +93698,49 @@ function SlideCard({
|
|
|
93633
93698
|
}
|
|
93634
93699
|
);
|
|
93635
93700
|
}
|
|
93701
|
+
function arePropsEqual3(prev, next) {
|
|
93702
|
+
if (prev.slide.id !== next.slide.id) {
|
|
93703
|
+
return false;
|
|
93704
|
+
}
|
|
93705
|
+
if (prev.slide.isDirty !== next.slide.isDirty) {
|
|
93706
|
+
return false;
|
|
93707
|
+
}
|
|
93708
|
+
if (prev.slide.hidden !== next.slide.hidden) {
|
|
93709
|
+
return false;
|
|
93710
|
+
}
|
|
93711
|
+
if (prev.slide.elements !== next.slide.elements) {
|
|
93712
|
+
return false;
|
|
93713
|
+
}
|
|
93714
|
+
if (prev.index !== next.index) {
|
|
93715
|
+
return false;
|
|
93716
|
+
}
|
|
93717
|
+
if (prev.isActive !== next.isActive) {
|
|
93718
|
+
return false;
|
|
93719
|
+
}
|
|
93720
|
+
if (prev.isDragTarget !== next.isDragTarget) {
|
|
93721
|
+
return false;
|
|
93722
|
+
}
|
|
93723
|
+
if (prev.isSelected !== next.isSelected) {
|
|
93724
|
+
return false;
|
|
93725
|
+
}
|
|
93726
|
+
if (prev.selectedCount !== next.selectedCount) {
|
|
93727
|
+
return false;
|
|
93728
|
+
}
|
|
93729
|
+
if (prev.selectionOrder !== next.selectionOrder) {
|
|
93730
|
+
return false;
|
|
93731
|
+
}
|
|
93732
|
+
if (prev.canEdit !== next.canEdit) {
|
|
93733
|
+
return false;
|
|
93734
|
+
}
|
|
93735
|
+
if (prev.canvasSize.width !== next.canvasSize.width || prev.canvasSize.height !== next.canvasSize.height) {
|
|
93736
|
+
return false;
|
|
93737
|
+
}
|
|
93738
|
+
if (prev.onSlideClick !== next.onSlideClick || prev.onDoubleClick !== next.onDoubleClick || prev.onContextMenu !== next.onContextMenu || prev.onDragStart !== next.onDragStart || prev.onDragOver !== next.onDragOver || prev.onDragLeave !== next.onDragLeave || prev.onDrop !== next.onDrop) {
|
|
93739
|
+
return false;
|
|
93740
|
+
}
|
|
93741
|
+
return true;
|
|
93742
|
+
}
|
|
93743
|
+
var SlideCard = React10__namespace.default.memo(SlideCardImpl, arePropsEqual3);
|
|
93636
93744
|
function SorterContextMenu({
|
|
93637
93745
|
x: x2,
|
|
93638
93746
|
y,
|
|
@@ -94426,6 +94534,14 @@ function getCurrentParagraphIndex(editorEl, segments) {
|
|
|
94426
94534
|
}
|
|
94427
94535
|
return paraIdx;
|
|
94428
94536
|
}
|
|
94537
|
+
var CSS_VALUE_SAFE = /^[a-zA-Z0-9 _,.\-+#'%/]{1,100}$/;
|
|
94538
|
+
function isCssValueSafe(value) {
|
|
94539
|
+
if (value === void 0 || value === null) {
|
|
94540
|
+
return false;
|
|
94541
|
+
}
|
|
94542
|
+
const str = String(value);
|
|
94543
|
+
return str.length > 0 && CSS_VALUE_SAFE.test(str);
|
|
94544
|
+
}
|
|
94429
94545
|
function deriveStyleFromElement(element2, inheritedStyle) {
|
|
94430
94546
|
const style = { ...inheritedStyle };
|
|
94431
94547
|
const tagName = element2.tagName.toLowerCase();
|
|
@@ -94558,17 +94674,17 @@ function segmentsToEditorHtml(segments) {
|
|
|
94558
94674
|
if (segment.style.strikethrough) {
|
|
94559
94675
|
inlineStyles.push("text-decoration:line-through");
|
|
94560
94676
|
}
|
|
94561
|
-
if (segment.style.color) {
|
|
94677
|
+
if (segment.style.color && isCssValueSafe(segment.style.color)) {
|
|
94562
94678
|
inlineStyles.push(`color:${segment.style.color}`);
|
|
94563
94679
|
}
|
|
94564
|
-
if (segment.style.fontSize) {
|
|
94565
|
-
inlineStyles.push(`font-size:${segment.style.fontSize}pt`);
|
|
94680
|
+
if (segment.style.fontSize && Number.isFinite(Number(segment.style.fontSize))) {
|
|
94681
|
+
inlineStyles.push(`font-size:${Number(segment.style.fontSize)}pt`);
|
|
94566
94682
|
}
|
|
94567
|
-
if (segment.style.fontFamily) {
|
|
94683
|
+
if (segment.style.fontFamily && isCssValueSafe(segment.style.fontFamily)) {
|
|
94568
94684
|
inlineStyles.push(`font-family:${segment.style.fontFamily}`);
|
|
94569
94685
|
}
|
|
94570
94686
|
const text2 = escapeHtml(segment.text);
|
|
94571
|
-
if (segment.style.hyperlink) {
|
|
94687
|
+
if (segment.style.hyperlink && isUrlSafe(segment.style.hyperlink)) {
|
|
94572
94688
|
const href = escapeHtml(segment.style.hyperlink);
|
|
94573
94689
|
return `<a href="${href}" style="color:#4a9eff;text-decoration:underline;cursor:pointer" data-hyperlink="${href}">${text2}</a>`;
|
|
94574
94690
|
}
|
|
@@ -94651,7 +94767,8 @@ function renderRichNotesSegments(segments) {
|
|
|
94651
94767
|
if (segment.style.fontFamily) {
|
|
94652
94768
|
style.fontFamily = segment.style.fontFamily;
|
|
94653
94769
|
}
|
|
94654
|
-
if (segment.style.hyperlink) {
|
|
94770
|
+
if (segment.style.hyperlink && isUrlSafe(segment.style.hyperlink)) {
|
|
94771
|
+
const safeHref = segment.style.hyperlink;
|
|
94655
94772
|
style.color = "#4a9eff";
|
|
94656
94773
|
style.textDecoration = "underline";
|
|
94657
94774
|
style.cursor = "pointer";
|
|
@@ -94659,11 +94776,11 @@ function renderRichNotesSegments(segments) {
|
|
|
94659
94776
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
94660
94777
|
"a",
|
|
94661
94778
|
{
|
|
94662
|
-
href:
|
|
94779
|
+
href: safeHref,
|
|
94663
94780
|
style,
|
|
94664
94781
|
onClick: (e2) => {
|
|
94665
94782
|
e2.preventDefault();
|
|
94666
|
-
|
|
94783
|
+
safeOpenUrl(safeHref);
|
|
94667
94784
|
},
|
|
94668
94785
|
children: segment.text
|
|
94669
94786
|
},
|
|
@@ -95215,7 +95332,7 @@ function useSlideNotes({
|
|
|
95215
95332
|
const href = target.getAttribute("data-hyperlink") || target.getAttribute("href");
|
|
95216
95333
|
if (href && (e2.ctrlKey || e2.metaKey)) {
|
|
95217
95334
|
e2.preventDefault();
|
|
95218
|
-
|
|
95335
|
+
safeOpenUrl(href);
|
|
95219
95336
|
}
|
|
95220
95337
|
}, []);
|
|
95221
95338
|
return {
|
|
@@ -96888,7 +97005,7 @@ function renderNotesSegments(segments) {
|
|
|
96888
97005
|
return React10__namespace.default.createElement("span", { key: `seg-${index}`, style }, segment.text);
|
|
96889
97006
|
});
|
|
96890
97007
|
}
|
|
96891
|
-
function
|
|
97008
|
+
function ScaledSlidePreviewImpl({
|
|
96892
97009
|
slide,
|
|
96893
97010
|
templateElements,
|
|
96894
97011
|
canvasSize,
|
|
@@ -97035,6 +97152,40 @@ function ScaledSlidePreview({
|
|
|
97035
97152
|
}
|
|
97036
97153
|
);
|
|
97037
97154
|
}
|
|
97155
|
+
function arePropsEqual4(prev, next) {
|
|
97156
|
+
if (prev.slide.id !== next.slide.id) {
|
|
97157
|
+
return false;
|
|
97158
|
+
}
|
|
97159
|
+
if (prev.slide.isDirty !== next.slide.isDirty) {
|
|
97160
|
+
return false;
|
|
97161
|
+
}
|
|
97162
|
+
if (prev.slide.hidden !== next.slide.hidden) {
|
|
97163
|
+
return false;
|
|
97164
|
+
}
|
|
97165
|
+
if (prev.slide.elements !== next.slide.elements) {
|
|
97166
|
+
return false;
|
|
97167
|
+
}
|
|
97168
|
+
if (prev.slide.backgroundColor !== next.slide.backgroundColor) {
|
|
97169
|
+
return false;
|
|
97170
|
+
}
|
|
97171
|
+
if (prev.slide.backgroundImage !== next.slide.backgroundImage) {
|
|
97172
|
+
return false;
|
|
97173
|
+
}
|
|
97174
|
+
if (prev.slide.backgroundGradient !== next.slide.backgroundGradient) {
|
|
97175
|
+
return false;
|
|
97176
|
+
}
|
|
97177
|
+
if (prev.templateElements !== next.templateElements) {
|
|
97178
|
+
return false;
|
|
97179
|
+
}
|
|
97180
|
+
if (prev.canvasSize.width !== next.canvasSize.width || prev.canvasSize.height !== next.canvasSize.height) {
|
|
97181
|
+
return false;
|
|
97182
|
+
}
|
|
97183
|
+
if (prev.className !== next.className) {
|
|
97184
|
+
return false;
|
|
97185
|
+
}
|
|
97186
|
+
return true;
|
|
97187
|
+
}
|
|
97188
|
+
var ScaledSlidePreview = React10__namespace.default.memo(ScaledSlidePreviewImpl, arePropsEqual4);
|
|
97038
97189
|
function PresenterView({
|
|
97039
97190
|
slides,
|
|
97040
97191
|
currentSlideIndex,
|
|
@@ -111338,6 +111489,13 @@ function convertOmmlToLatex(omml) {
|
|
|
111338
111489
|
}
|
|
111339
111490
|
return ommlChildrenToLatex(oMath);
|
|
111340
111491
|
}
|
|
111492
|
+
function sanitizeMathMl2(markup) {
|
|
111493
|
+
const purify = DOMPurify__default.default;
|
|
111494
|
+
if (typeof purify.sanitize !== "function") {
|
|
111495
|
+
return markup;
|
|
111496
|
+
}
|
|
111497
|
+
return purify.sanitize(markup, { USE_PROFILES: { mathMl: true, svg: true } });
|
|
111498
|
+
}
|
|
111341
111499
|
var TEMPLATES = [
|
|
111342
111500
|
{
|
|
111343
111501
|
label: "Fraction",
|
|
@@ -111403,7 +111561,8 @@ var TEMPLATES = [
|
|
|
111403
111561
|
var TEMPLATE_MATHML = TEMPLATES.map((tmpl) => {
|
|
111404
111562
|
try {
|
|
111405
111563
|
const tmplOmml = convertLatexToOmml(tmpl.latex);
|
|
111406
|
-
|
|
111564
|
+
const raw = convertOmmlToMathMl(tmplOmml);
|
|
111565
|
+
return raw ? sanitizeMathMl2(raw) : "";
|
|
111407
111566
|
} catch {
|
|
111408
111567
|
return "";
|
|
111409
111568
|
}
|
|
@@ -111415,7 +111574,7 @@ function MathMlPreview({ mathml }) {
|
|
|
111415
111574
|
return;
|
|
111416
111575
|
}
|
|
111417
111576
|
if (mathml) {
|
|
111418
|
-
containerRef.current.innerHTML = mathml;
|
|
111577
|
+
containerRef.current.innerHTML = sanitizeMathMl2(mathml);
|
|
111419
111578
|
} else {
|
|
111420
111579
|
containerRef.current.innerHTML = "";
|
|
111421
111580
|
}
|
|
@@ -111443,6 +111602,7 @@ function EquationEditorDialog({
|
|
|
111443
111602
|
return convertOmmlToLatex(existingOmml);
|
|
111444
111603
|
}, [existingOmml]);
|
|
111445
111604
|
const [latex, setLatex] = React10.useState(initialLatex);
|
|
111605
|
+
const deferredLatex = React10.useDeferredValue(latex);
|
|
111446
111606
|
const textareaRef = React10.useRef(null);
|
|
111447
111607
|
React10.useEffect(() => {
|
|
111448
111608
|
if (isOpen) {
|
|
@@ -111451,17 +111611,17 @@ function EquationEditorDialog({
|
|
|
111451
111611
|
}
|
|
111452
111612
|
}, [isOpen, initialLatex]);
|
|
111453
111613
|
const { mathml, omml } = React10.useMemo(() => {
|
|
111454
|
-
if (!
|
|
111614
|
+
if (!deferredLatex.trim()) {
|
|
111455
111615
|
return { mathml: "", omml: {} };
|
|
111456
111616
|
}
|
|
111457
111617
|
try {
|
|
111458
|
-
const ommlObj = convertLatexToOmml(
|
|
111618
|
+
const ommlObj = convertLatexToOmml(deferredLatex);
|
|
111459
111619
|
const mathmlStr = convertOmmlToMathMl(ommlObj);
|
|
111460
111620
|
return { mathml: mathmlStr, omml: ommlObj };
|
|
111461
111621
|
} catch {
|
|
111462
111622
|
return { mathml: "", omml: {} };
|
|
111463
111623
|
}
|
|
111464
|
-
}, [
|
|
111624
|
+
}, [deferredLatex]);
|
|
111465
111625
|
const handleInsert = React10.useCallback(() => {
|
|
111466
111626
|
if (!latex.trim()) {
|
|
111467
111627
|
return;
|
|
@@ -114196,6 +114356,7 @@ function useEditorHistory(input) {
|
|
|
114196
114356
|
const historyFutureRef = React10.useRef([]);
|
|
114197
114357
|
const lastHistorySnapshotRef = React10.useRef(null);
|
|
114198
114358
|
const lastHistorySerializedRef = React10.useRef("");
|
|
114359
|
+
const lastCheapHashRef = React10.useRef("");
|
|
114199
114360
|
const isApplyingHistoryRef = React10.useRef(false);
|
|
114200
114361
|
const unlockHistoryTimerRef = React10.useRef(null);
|
|
114201
114362
|
const [canUndo, setCanUndo] = React10.useState(false);
|
|
@@ -114337,15 +114498,21 @@ function useEditorHistory(input) {
|
|
|
114337
114498
|
if (hasActivePointerInteraction()) {
|
|
114338
114499
|
return;
|
|
114339
114500
|
}
|
|
114501
|
+
const cheapHash = `${slides.length}|${activeSlideIndex}|${canvasSize.width}x${canvasSize.height}|${slides.map((s) => `${s.id}:${s.elements.length}`).join("/")}`;
|
|
114502
|
+
if (cheapHash === lastCheapHashRef.current) {
|
|
114503
|
+
return;
|
|
114504
|
+
}
|
|
114340
114505
|
const snapshot2 = buildHistorySnapshot();
|
|
114341
114506
|
const serialized = JSON.stringify(snapshot2);
|
|
114342
114507
|
if (serialized === lastHistorySerializedRef.current) {
|
|
114508
|
+
lastCheapHashRef.current = cheapHash;
|
|
114343
114509
|
return;
|
|
114344
114510
|
}
|
|
114345
114511
|
const previousSnapshot = lastHistorySnapshotRef.current;
|
|
114346
114512
|
if (!previousSnapshot) {
|
|
114347
114513
|
lastHistorySnapshotRef.current = cloneHistorySnapshot(snapshot2);
|
|
114348
114514
|
lastHistorySerializedRef.current = serialized;
|
|
114515
|
+
lastCheapHashRef.current = cheapHash;
|
|
114349
114516
|
updateHistoryAvailability();
|
|
114350
114517
|
return;
|
|
114351
114518
|
}
|
|
@@ -114356,13 +114523,18 @@ function useEditorHistory(input) {
|
|
|
114356
114523
|
historyFutureRef.current = [];
|
|
114357
114524
|
lastHistorySnapshotRef.current = cloneHistorySnapshot(snapshot2);
|
|
114358
114525
|
lastHistorySerializedRef.current = serialized;
|
|
114526
|
+
lastCheapHashRef.current = cheapHash;
|
|
114359
114527
|
updateHistoryAvailability();
|
|
114360
114528
|
}, [
|
|
114529
|
+
activeSlideIndex,
|
|
114361
114530
|
buildHistorySnapshot,
|
|
114531
|
+
canvasSize.height,
|
|
114532
|
+
canvasSize.width,
|
|
114362
114533
|
error2,
|
|
114363
114534
|
hasActivePointerInteraction,
|
|
114364
114535
|
loading2,
|
|
114365
114536
|
pointerCommitNonce,
|
|
114537
|
+
slides,
|
|
114366
114538
|
updateHistoryAvailability
|
|
114367
114539
|
]);
|
|
114368
114540
|
return {
|
|
@@ -118074,7 +118246,8 @@ async function storeAudienceContent(content) {
|
|
|
118074
118246
|
const tx = db.transaction(STORE_NAME2, "readwrite");
|
|
118075
118247
|
const store = tx.objectStore(STORE_NAME2);
|
|
118076
118248
|
const bytes = content instanceof Uint8Array ? content : new Uint8Array(content);
|
|
118077
|
-
|
|
118249
|
+
const record = { bytes, createdAt: Date.now() };
|
|
118250
|
+
store.put(record, CONTENT_KEY);
|
|
118078
118251
|
tx.oncomplete = () => {
|
|
118079
118252
|
db.close();
|
|
118080
118253
|
resolve2();
|
|
@@ -118107,14 +118280,34 @@ async function clearAudienceContent() {
|
|
|
118107
118280
|
var PRESENTER_CHANNEL_NAME = "pptx-viewer-presenter";
|
|
118108
118281
|
var AUDIENCE_HASH = "#pptx-audience";
|
|
118109
118282
|
var PRESENTER_MSG_ORIGIN = "pptx-viewer-presenter";
|
|
118283
|
+
var AUDIENCE_NONCE_KEY = "nonce";
|
|
118284
|
+
function generateSessionId() {
|
|
118285
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
118286
|
+
return crypto.randomUUID();
|
|
118287
|
+
}
|
|
118288
|
+
return `s${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
|
|
118289
|
+
}
|
|
118290
|
+
function parseAudienceNonce() {
|
|
118291
|
+
const hash = window.location.hash;
|
|
118292
|
+
if (!hash.startsWith(AUDIENCE_HASH)) {
|
|
118293
|
+
return null;
|
|
118294
|
+
}
|
|
118295
|
+
const trailing = hash.slice(AUDIENCE_HASH.length);
|
|
118296
|
+
if (!trailing) {
|
|
118297
|
+
return null;
|
|
118298
|
+
}
|
|
118299
|
+
const params2 = new URLSearchParams(trailing.replace(/^[&;?]/, ""));
|
|
118300
|
+
return params2.get(AUDIENCE_NONCE_KEY);
|
|
118301
|
+
}
|
|
118110
118302
|
function isAudienceTab() {
|
|
118111
|
-
return window.location.hash
|
|
118303
|
+
return window.location.hash.startsWith(AUDIENCE_HASH);
|
|
118112
118304
|
}
|
|
118113
118305
|
function usePresenterWindow(input) {
|
|
118114
118306
|
const { currentSlideIndex, isPresenterMode, content } = input;
|
|
118115
118307
|
const audienceWindowRef = React10.useRef(null);
|
|
118116
118308
|
const channelRef = React10.useRef(null);
|
|
118117
118309
|
const pollTimerRef = React10.useRef(null);
|
|
118310
|
+
const sessionIdRef = React10.useRef("");
|
|
118118
118311
|
const getChannel2 = React10.useCallback(() => {
|
|
118119
118312
|
if (!channelRef.current) {
|
|
118120
118313
|
channelRef.current = new BroadcastChannel(PRESENTER_CHANNEL_NAME);
|
|
@@ -118126,10 +118319,14 @@ function usePresenterWindow(input) {
|
|
|
118126
118319
|
}, []);
|
|
118127
118320
|
const syncSlideToAudience = React10.useCallback(
|
|
118128
118321
|
(slideIndex) => {
|
|
118322
|
+
if (!sessionIdRef.current) {
|
|
118323
|
+
return;
|
|
118324
|
+
}
|
|
118129
118325
|
const msg = {
|
|
118130
118326
|
origin: PRESENTER_MSG_ORIGIN,
|
|
118131
118327
|
type: "presenter-slide-change",
|
|
118132
|
-
slideIndex
|
|
118328
|
+
slideIndex,
|
|
118329
|
+
sessionId: sessionIdRef.current
|
|
118133
118330
|
};
|
|
118134
118331
|
try {
|
|
118135
118332
|
getChannel2().postMessage(msg);
|
|
@@ -118139,13 +118336,16 @@ function usePresenterWindow(input) {
|
|
|
118139
118336
|
[getChannel2]
|
|
118140
118337
|
);
|
|
118141
118338
|
const closeAudienceWindow = React10.useCallback(() => {
|
|
118142
|
-
|
|
118143
|
-
|
|
118144
|
-
|
|
118145
|
-
|
|
118146
|
-
|
|
118147
|
-
|
|
118148
|
-
|
|
118339
|
+
if (sessionIdRef.current) {
|
|
118340
|
+
try {
|
|
118341
|
+
const exitMsg = {
|
|
118342
|
+
origin: PRESENTER_MSG_ORIGIN,
|
|
118343
|
+
type: "presenter-exit",
|
|
118344
|
+
sessionId: sessionIdRef.current
|
|
118345
|
+
};
|
|
118346
|
+
getChannel2().postMessage(exitMsg);
|
|
118347
|
+
} catch {
|
|
118348
|
+
}
|
|
118149
118349
|
}
|
|
118150
118350
|
const win = audienceWindowRef.current;
|
|
118151
118351
|
if (win && !win.closed) {
|
|
@@ -118155,6 +118355,7 @@ function usePresenterWindow(input) {
|
|
|
118155
118355
|
}
|
|
118156
118356
|
}
|
|
118157
118357
|
audienceWindowRef.current = null;
|
|
118358
|
+
sessionIdRef.current = "";
|
|
118158
118359
|
if (pollTimerRef.current !== null) {
|
|
118159
118360
|
clearInterval(pollTimerRef.current);
|
|
118160
118361
|
pollTimerRef.current = null;
|
|
@@ -118165,20 +118366,53 @@ function usePresenterWindow(input) {
|
|
|
118165
118366
|
if (isAudienceWindowOpen()) {
|
|
118166
118367
|
closeAudienceWindow();
|
|
118167
118368
|
}
|
|
118168
|
-
|
|
118169
|
-
|
|
118170
|
-
}
|
|
118171
|
-
const url = new URL(window.location.href);
|
|
118172
|
-
url.hash = AUDIENCE_HASH;
|
|
118173
|
-
const win = window.open(url.toString(), "_blank");
|
|
118174
|
-
if (!win) {
|
|
118369
|
+
const blankWin = window.open("about:blank", "_blank");
|
|
118370
|
+
if (!blankWin) {
|
|
118175
118371
|
return false;
|
|
118176
118372
|
}
|
|
118177
|
-
audienceWindowRef.current =
|
|
118373
|
+
audienceWindowRef.current = blankWin;
|
|
118374
|
+
const sessionId = generateSessionId();
|
|
118375
|
+
sessionIdRef.current = sessionId;
|
|
118376
|
+
const audienceUrl = new URL(window.location.href);
|
|
118377
|
+
const params2 = new URLSearchParams();
|
|
118378
|
+
params2.set(AUDIENCE_NONCE_KEY, sessionId);
|
|
118379
|
+
audienceUrl.hash = `${AUDIENCE_HASH}&${params2.toString()}`;
|
|
118380
|
+
const navigateOrClose = (ok) => {
|
|
118381
|
+
const win = audienceWindowRef.current;
|
|
118382
|
+
if (!win || win.closed) {
|
|
118383
|
+
return;
|
|
118384
|
+
}
|
|
118385
|
+
if (!ok) {
|
|
118386
|
+
try {
|
|
118387
|
+
win.close();
|
|
118388
|
+
} catch {
|
|
118389
|
+
}
|
|
118390
|
+
audienceWindowRef.current = null;
|
|
118391
|
+
sessionIdRef.current = "";
|
|
118392
|
+
return;
|
|
118393
|
+
}
|
|
118394
|
+
try {
|
|
118395
|
+
win.location.replace(audienceUrl.toString());
|
|
118396
|
+
} catch {
|
|
118397
|
+
try {
|
|
118398
|
+
win.close();
|
|
118399
|
+
} catch {
|
|
118400
|
+
}
|
|
118401
|
+
audienceWindowRef.current = null;
|
|
118402
|
+
sessionIdRef.current = "";
|
|
118403
|
+
}
|
|
118404
|
+
};
|
|
118405
|
+
if (content) {
|
|
118406
|
+
void storeAudienceContent(content).then(() => navigateOrClose(true)).catch(() => navigateOrClose(false));
|
|
118407
|
+
} else {
|
|
118408
|
+
navigateOrClose(true);
|
|
118409
|
+
}
|
|
118178
118410
|
window.setTimeout(() => syncSlideToAudience(currentSlideIndex), 1500);
|
|
118179
118411
|
pollTimerRef.current = setInterval(() => {
|
|
118180
|
-
|
|
118412
|
+
const win = audienceWindowRef.current;
|
|
118413
|
+
if (!win || win.closed) {
|
|
118181
118414
|
audienceWindowRef.current = null;
|
|
118415
|
+
sessionIdRef.current = "";
|
|
118182
118416
|
if (pollTimerRef.current !== null) {
|
|
118183
118417
|
clearInterval(pollTimerRef.current);
|
|
118184
118418
|
pollTimerRef.current = null;
|
|
@@ -118206,6 +118440,13 @@ function usePresenterWindow(input) {
|
|
|
118206
118440
|
closeAudienceWindow();
|
|
118207
118441
|
}
|
|
118208
118442
|
}, [isPresenterMode, closeAudienceWindow]);
|
|
118443
|
+
React10.useEffect(() => {
|
|
118444
|
+
const handleBeforeUnload = () => {
|
|
118445
|
+
void clearAudienceContent();
|
|
118446
|
+
};
|
|
118447
|
+
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
118448
|
+
return () => window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
118449
|
+
}, []);
|
|
118209
118450
|
return {
|
|
118210
118451
|
openAudienceWindow,
|
|
118211
118452
|
closeAudienceWindow,
|
|
@@ -118243,6 +118484,7 @@ function useAudienceMode(input) {
|
|
|
118243
118484
|
if (!isAudienceTab()) {
|
|
118244
118485
|
return;
|
|
118245
118486
|
}
|
|
118487
|
+
const expectedSessionId = parseAudienceNonce();
|
|
118246
118488
|
let channel;
|
|
118247
118489
|
try {
|
|
118248
118490
|
channel = new BroadcastChannel(PRESENTER_CHANNEL_NAME);
|
|
@@ -118254,6 +118496,9 @@ function useAudienceMode(input) {
|
|
|
118254
118496
|
if (!data || data.origin !== PRESENTER_MSG_ORIGIN) {
|
|
118255
118497
|
return;
|
|
118256
118498
|
}
|
|
118499
|
+
if (expectedSessionId && data.sessionId !== expectedSessionId) {
|
|
118500
|
+
return;
|
|
118501
|
+
}
|
|
118257
118502
|
if (data.type === "presenter-slide-change") {
|
|
118258
118503
|
onSetActiveSlideIndex(data.slideIndex);
|
|
118259
118504
|
}
|
|
@@ -119187,6 +119432,12 @@ function useTouchGestures(input) {
|
|
|
119187
119432
|
callbacksRef.current = callbacks;
|
|
119188
119433
|
const scaleRef = React10.useRef(currentScale);
|
|
119189
119434
|
scaleRef.current = currentScale;
|
|
119435
|
+
const [targetVersion, setTargetVersion] = React10.useState(0);
|
|
119436
|
+
const lastTargetRef = React10.useRef(null);
|
|
119437
|
+
if (targetRef.current !== lastTargetRef.current) {
|
|
119438
|
+
lastTargetRef.current = targetRef.current;
|
|
119439
|
+
queueMicrotask(() => setTargetVersion((v) => v + 1));
|
|
119440
|
+
}
|
|
119190
119441
|
React10.useEffect(() => {
|
|
119191
119442
|
const el = targetRef.current;
|
|
119192
119443
|
if (!el || !enabled) {
|
|
@@ -119275,7 +119526,7 @@ function useTouchGestures(input) {
|
|
|
119275
119526
|
el.removeEventListener("touchcancel", handleTouchCancel);
|
|
119276
119527
|
cancelLongPress();
|
|
119277
119528
|
};
|
|
119278
|
-
}, [targetRef, enabled]);
|
|
119529
|
+
}, [targetRef, enabled, targetVersion]);
|
|
119279
119530
|
}
|
|
119280
119531
|
|
|
119281
119532
|
// src/viewer/utils/dom-helpers.ts
|
|
@@ -119296,11 +119547,31 @@ function safeConfirm(message) {
|
|
|
119296
119547
|
return false;
|
|
119297
119548
|
}
|
|
119298
119549
|
}
|
|
119550
|
+
function sanitizeDownloadFilename(input) {
|
|
119551
|
+
if (typeof input !== "string" || input.trim().length === 0) {
|
|
119552
|
+
return "presentation.pptx";
|
|
119553
|
+
}
|
|
119554
|
+
let cleaned = input.replace(/[\x00-\x1f\x7f"\\/:*?<>|]/g, "_").replace(/\.\./g, "__").replace(/^\.+/, "").trim();
|
|
119555
|
+
if (cleaned.length === 0) {
|
|
119556
|
+
return "presentation.pptx";
|
|
119557
|
+
}
|
|
119558
|
+
if (cleaned.length > 200) {
|
|
119559
|
+
const dot = cleaned.lastIndexOf(".");
|
|
119560
|
+
if (dot > 0 && cleaned.length - dot <= 16) {
|
|
119561
|
+
const ext = cleaned.slice(dot);
|
|
119562
|
+
cleaned = cleaned.slice(0, 200 - ext.length) + ext;
|
|
119563
|
+
} else {
|
|
119564
|
+
cleaned = cleaned.slice(0, 200);
|
|
119565
|
+
}
|
|
119566
|
+
}
|
|
119567
|
+
return cleaned;
|
|
119568
|
+
}
|
|
119299
119569
|
function downloadBlob(blob, filename) {
|
|
119570
|
+
const safeName = sanitizeDownloadFilename(filename);
|
|
119300
119571
|
const url = URL.createObjectURL(blob);
|
|
119301
119572
|
const a2 = document.createElement("a");
|
|
119302
119573
|
a2.href = url;
|
|
119303
|
-
a2.download =
|
|
119574
|
+
a2.download = safeName;
|
|
119304
119575
|
document.body.appendChild(a2);
|
|
119305
119576
|
a2.click();
|
|
119306
119577
|
setTimeout(() => {
|
|
@@ -119731,27 +120002,82 @@ function openAutosaveDb2() {
|
|
|
119731
120002
|
req.onerror = () => reject(req.error);
|
|
119732
120003
|
});
|
|
119733
120004
|
}
|
|
119734
|
-
async function
|
|
120005
|
+
async function deleteOldestAutosaveEntry() {
|
|
119735
120006
|
const db = await openAutosaveDb2();
|
|
119736
|
-
return new Promise((resolve2
|
|
119737
|
-
|
|
119738
|
-
|
|
119739
|
-
|
|
119740
|
-
|
|
119741
|
-
|
|
119742
|
-
|
|
119743
|
-
|
|
119744
|
-
|
|
119745
|
-
|
|
119746
|
-
|
|
119747
|
-
|
|
119748
|
-
|
|
119749
|
-
|
|
119750
|
-
|
|
119751
|
-
|
|
119752
|
-
|
|
120007
|
+
return new Promise((resolve2) => {
|
|
120008
|
+
try {
|
|
120009
|
+
const tx = db.transaction(STORE_NAME3, "readwrite");
|
|
120010
|
+
const store = tx.objectStore(STORE_NAME3);
|
|
120011
|
+
let oldestKey = null;
|
|
120012
|
+
let oldestTimestamp = Infinity;
|
|
120013
|
+
const cursorReq = store.openCursor();
|
|
120014
|
+
cursorReq.onsuccess = () => {
|
|
120015
|
+
const cursor = cursorReq.result;
|
|
120016
|
+
if (cursor) {
|
|
120017
|
+
const value = cursor.value;
|
|
120018
|
+
if (typeof value.timestamp === "number" && value.timestamp < oldestTimestamp) {
|
|
120019
|
+
oldestTimestamp = value.timestamp;
|
|
120020
|
+
oldestKey = cursor.primaryKey;
|
|
120021
|
+
}
|
|
120022
|
+
cursor.continue();
|
|
120023
|
+
} else if (oldestKey !== null) {
|
|
120024
|
+
store.delete(oldestKey);
|
|
120025
|
+
}
|
|
120026
|
+
};
|
|
120027
|
+
tx.oncomplete = () => {
|
|
120028
|
+
db.close();
|
|
120029
|
+
resolve2(oldestKey !== null);
|
|
120030
|
+
};
|
|
120031
|
+
tx.onerror = () => {
|
|
120032
|
+
db.close();
|
|
120033
|
+
resolve2(false);
|
|
120034
|
+
};
|
|
120035
|
+
} catch {
|
|
120036
|
+
try {
|
|
120037
|
+
db.close();
|
|
120038
|
+
} catch {
|
|
120039
|
+
}
|
|
120040
|
+
resolve2(false);
|
|
120041
|
+
}
|
|
119753
120042
|
});
|
|
119754
120043
|
}
|
|
120044
|
+
function putAutosaveRecord(filePath, data) {
|
|
120045
|
+
return openAutosaveDb2().then(
|
|
120046
|
+
(db) => new Promise((resolve2, reject) => {
|
|
120047
|
+
const tx = db.transaction(STORE_NAME3, "readwrite");
|
|
120048
|
+
const store = tx.objectStore(STORE_NAME3);
|
|
120049
|
+
store.put({
|
|
120050
|
+
key: filePath,
|
|
120051
|
+
data,
|
|
120052
|
+
timestamp: Date.now(),
|
|
120053
|
+
size: data.byteLength
|
|
120054
|
+
});
|
|
120055
|
+
tx.oncomplete = () => {
|
|
120056
|
+
db.close();
|
|
120057
|
+
resolve2(true);
|
|
120058
|
+
};
|
|
120059
|
+
tx.onerror = () => {
|
|
120060
|
+
db.close();
|
|
120061
|
+
reject(tx.error);
|
|
120062
|
+
};
|
|
120063
|
+
})
|
|
120064
|
+
);
|
|
120065
|
+
}
|
|
120066
|
+
async function saveToIndexedDb(filePath, data) {
|
|
120067
|
+
try {
|
|
120068
|
+
return await putAutosaveRecord(filePath, data);
|
|
120069
|
+
} catch (err) {
|
|
120070
|
+
const errName = err instanceof Error || err instanceof DOMException ? err.name : "";
|
|
120071
|
+
if (errName !== "QuotaExceededError") {
|
|
120072
|
+
throw err;
|
|
120073
|
+
}
|
|
120074
|
+
const deleted = await deleteOldestAutosaveEntry();
|
|
120075
|
+
if (!deleted) {
|
|
120076
|
+
throw err;
|
|
120077
|
+
}
|
|
120078
|
+
return putAutosaveRecord(filePath, data);
|
|
120079
|
+
}
|
|
120080
|
+
}
|
|
119755
120081
|
function useAutosave(input) {
|
|
119756
120082
|
const {
|
|
119757
120083
|
isDirty,
|
|
@@ -119868,6 +120194,25 @@ function collectReferencedFontFamilies(slides) {
|
|
|
119868
120194
|
}
|
|
119869
120195
|
return families;
|
|
119870
120196
|
}
|
|
120197
|
+
var FONT_NAME_UNSAFE_CHARS = /["\\\n\r;}<>]/;
|
|
120198
|
+
var FONT_FORMAT_ALLOWED = /* @__PURE__ */ new Set([
|
|
120199
|
+
"truetype",
|
|
120200
|
+
"opentype",
|
|
120201
|
+
"woff",
|
|
120202
|
+
"woff2",
|
|
120203
|
+
"svg",
|
|
120204
|
+
"embedded-opentype"
|
|
120205
|
+
]);
|
|
120206
|
+
var FONT_DATA_URL_PATTERN = /^data:font\/[a-z0-9+.-]+(?:;charset=[a-z0-9-]+)?;base64,[A-Za-z0-9+/=]+$/i;
|
|
120207
|
+
function isFontDataUrlSafe(url) {
|
|
120208
|
+
if (typeof url !== "string" || url.length === 0) {
|
|
120209
|
+
return false;
|
|
120210
|
+
}
|
|
120211
|
+
if (url.startsWith("blob:")) {
|
|
120212
|
+
return true;
|
|
120213
|
+
}
|
|
120214
|
+
return FONT_DATA_URL_PATTERN.test(url);
|
|
120215
|
+
}
|
|
119871
120216
|
function useFontInjection({ embeddedFonts, slides }) {
|
|
119872
120217
|
React10.useEffect(() => {
|
|
119873
120218
|
if (!embeddedFonts.length) {
|
|
@@ -119875,17 +120220,28 @@ function useFontInjection({ embeddedFonts, slides }) {
|
|
|
119875
120220
|
}
|
|
119876
120221
|
const styleEl = document.createElement("style");
|
|
119877
120222
|
styleEl.id = EMBEDDED_FONTS_STYLE_ID;
|
|
119878
|
-
const cssRules = embeddedFonts.
|
|
120223
|
+
const cssRules = embeddedFonts.flatMap((font) => {
|
|
120224
|
+
if (typeof font.name !== "string" || font.name.length === 0 || FONT_NAME_UNSAFE_CHARS.test(font.name)) {
|
|
120225
|
+
return [];
|
|
120226
|
+
}
|
|
120227
|
+
if (!isFontDataUrlSafe(font.dataUrl)) {
|
|
120228
|
+
return [];
|
|
120229
|
+
}
|
|
120230
|
+
const fontFormat = font.format ?? "truetype";
|
|
120231
|
+
if (!FONT_FORMAT_ALLOWED.has(fontFormat)) {
|
|
120232
|
+
return [];
|
|
120233
|
+
}
|
|
119879
120234
|
const fontWeight = font.bold ? "700" : "400";
|
|
119880
120235
|
const fontStyleCss = font.italic ? "italic" : "normal";
|
|
119881
|
-
|
|
119882
|
-
|
|
120236
|
+
return [
|
|
120237
|
+
`@font-face {
|
|
119883
120238
|
font-family: "${font.name}";
|
|
119884
120239
|
src: url("${font.dataUrl}") format("${fontFormat}");
|
|
119885
120240
|
font-weight: ${fontWeight};
|
|
119886
120241
|
font-style: ${fontStyleCss};
|
|
119887
120242
|
font-display: swap;
|
|
119888
|
-
}
|
|
120243
|
+
}`
|
|
120244
|
+
];
|
|
119889
120245
|
}).join("\n");
|
|
119890
120246
|
styleEl.textContent = cssRules;
|
|
119891
120247
|
document.head.appendChild(styleEl);
|
|
@@ -119914,7 +120270,7 @@ function useFontInjection({ embeddedFonts, slides }) {
|
|
|
119914
120270
|
const linkEl = document.createElement("link");
|
|
119915
120271
|
linkEl.id = GOOGLE_FONTS_LINK_ID;
|
|
119916
120272
|
linkEl.rel = "stylesheet";
|
|
119917
|
-
linkEl.href = `https://fonts.googleapis.com/css2?${googleFamilies.map((f) => `family=${GOOGLE_FONTS_AVAILABLE[f]}`).join("&")}&display=swap`;
|
|
120273
|
+
linkEl.href = `https://fonts.googleapis.com/css2?${googleFamilies.map((f) => `family=${encodeURIComponent(GOOGLE_FONTS_AVAILABLE[f])}`).join("&")}&display=swap`;
|
|
119918
120274
|
document.head.appendChild(linkEl);
|
|
119919
120275
|
return () => {
|
|
119920
120276
|
const existing = document.getElementById(GOOGLE_FONTS_LINK_ID);
|
|
@@ -119930,13 +120286,18 @@ function useFontInjection({ embeddedFonts, slides }) {
|
|
|
119930
120286
|
}
|
|
119931
120287
|
const styleEl = document.createElement("style");
|
|
119932
120288
|
styleEl.id = SYMBOL_FONTS_STYLE_ID;
|
|
119933
|
-
const rules = neededSymbolFonts.
|
|
119934
|
-
(font
|
|
120289
|
+
const rules = neededSymbolFonts.flatMap((font) => {
|
|
120290
|
+
if (typeof font !== "string" || FONT_NAME_UNSAFE_CHARS.test(font)) {
|
|
120291
|
+
return [];
|
|
120292
|
+
}
|
|
120293
|
+
return [
|
|
120294
|
+
`@font-face {
|
|
119935
120295
|
font-family: "${font}";
|
|
119936
120296
|
src: local("${font}"), local("${font} Regular");
|
|
119937
120297
|
font-display: swap;
|
|
119938
120298
|
}`
|
|
119939
|
-
|
|
120299
|
+
];
|
|
120300
|
+
}).join("\n");
|
|
119940
120301
|
styleEl.textContent = rules;
|
|
119941
120302
|
document.head.appendChild(styleEl);
|
|
119942
120303
|
return () => {
|
|
@@ -120079,16 +120440,17 @@ function useLoadContent({
|
|
|
120079
120440
|
`[pptx] Large file detected (${fileSizeMB.toFixed(1)} MB). Loading may use significant memory.`
|
|
120080
120441
|
);
|
|
120081
120442
|
}
|
|
120082
|
-
|
|
120083
|
-
handlerRef.current.dispose();
|
|
120084
|
-
handlerRef.current = null;
|
|
120085
|
-
}
|
|
120443
|
+
const previousHandler = handlerRef.current;
|
|
120086
120444
|
const handler = new pptxViewerCore.PptxHandler();
|
|
120087
120445
|
const parsed = await handler.load(buffer);
|
|
120088
120446
|
if (cancelled || token !== renderTokenRef.current) {
|
|
120089
120447
|
handler.dispose();
|
|
120090
120448
|
return;
|
|
120091
120449
|
}
|
|
120450
|
+
if (previousHandler) {
|
|
120451
|
+
previousHandler.dispose();
|
|
120452
|
+
}
|
|
120453
|
+
handlerRef.current = null;
|
|
120092
120454
|
const mediaElements = [];
|
|
120093
120455
|
for (const slide of parsed.slides) {
|
|
120094
120456
|
collectMediaElements(slide.elements, mediaElements);
|
|
@@ -120133,6 +120495,7 @@ function useLoadContent({
|
|
|
120133
120495
|
})
|
|
120134
120496
|
);
|
|
120135
120497
|
const { paths: imagePaths, refs: imageRefs } = collectImagePaths(parsed.slides);
|
|
120498
|
+
let nextSlides = parsed.slides;
|
|
120136
120499
|
if (imagePaths.size > 0) {
|
|
120137
120500
|
const resolvedMap = /* @__PURE__ */ new Map();
|
|
120138
120501
|
await Promise.all(
|
|
@@ -120146,15 +120509,47 @@ function useLoadContent({
|
|
|
120146
120509
|
}
|
|
120147
120510
|
})
|
|
120148
120511
|
);
|
|
120512
|
+
const elementPatches = /* @__PURE__ */ new Map();
|
|
120149
120513
|
for (const ref of imageRefs) {
|
|
120150
120514
|
const url = resolvedMap.get(ref.path);
|
|
120151
|
-
if (url) {
|
|
120152
|
-
|
|
120515
|
+
if (!url) {
|
|
120516
|
+
continue;
|
|
120153
120517
|
}
|
|
120518
|
+
const id2 = ref.element.id;
|
|
120519
|
+
const existing = elementPatches.get(id2) ?? {};
|
|
120520
|
+
existing[ref.field] = url;
|
|
120521
|
+
elementPatches.set(id2, existing);
|
|
120522
|
+
}
|
|
120523
|
+
if (elementPatches.size > 0) {
|
|
120524
|
+
const patchElements = (elements) => {
|
|
120525
|
+
let mutated = false;
|
|
120526
|
+
const next = elements.map((el) => {
|
|
120527
|
+
let updated = el;
|
|
120528
|
+
const patch = elementPatches.get(el.id);
|
|
120529
|
+
if (patch) {
|
|
120530
|
+
updated = { ...el, ...patch };
|
|
120531
|
+
}
|
|
120532
|
+
if (updated.type === "group" && updated.children?.length) {
|
|
120533
|
+
const newChildren = patchElements(updated.children);
|
|
120534
|
+
if (newChildren !== updated.children) {
|
|
120535
|
+
updated = { ...updated, children: newChildren };
|
|
120536
|
+
}
|
|
120537
|
+
}
|
|
120538
|
+
if (updated !== el) {
|
|
120539
|
+
mutated = true;
|
|
120540
|
+
}
|
|
120541
|
+
return updated;
|
|
120542
|
+
});
|
|
120543
|
+
return mutated ? next : elements;
|
|
120544
|
+
};
|
|
120545
|
+
nextSlides = parsed.slides.map((s) => {
|
|
120546
|
+
const newElements = patchElements(s.elements);
|
|
120547
|
+
return newElements === s.elements ? s : { ...s, elements: newElements };
|
|
120548
|
+
});
|
|
120154
120549
|
}
|
|
120155
120550
|
}
|
|
120156
120551
|
handlerRef.current = handler;
|
|
120157
|
-
setSlides(
|
|
120552
|
+
setSlides(nextSlides);
|
|
120158
120553
|
setTemplateElementsBySlideId({});
|
|
120159
120554
|
setCanvasSize({
|
|
120160
120555
|
width: parsed.width ?? DEFAULT_CANVAS_WIDTH,
|
|
@@ -121328,7 +121723,19 @@ function injectFontFaces(svg, fontFaces) {
|
|
|
121328
121723
|
if (!fontFaces.length) {
|
|
121329
121724
|
return svg;
|
|
121330
121725
|
}
|
|
121331
|
-
const
|
|
121726
|
+
const safeFontFaces = fontFaces.filter((f) => {
|
|
121727
|
+
if (f.css.toLowerCase().includes("</style")) {
|
|
121728
|
+
console.warn(
|
|
121729
|
+
`[export-svg] Dropping @font-face entry for "${f.family}" containing "</style" \u2014 would break out of the <style> block.`
|
|
121730
|
+
);
|
|
121731
|
+
return false;
|
|
121732
|
+
}
|
|
121733
|
+
return true;
|
|
121734
|
+
});
|
|
121735
|
+
if (!safeFontFaces.length) {
|
|
121736
|
+
return svg;
|
|
121737
|
+
}
|
|
121738
|
+
const styleBlock = `<style type="text/css">${safeFontFaces.map((f) => f.css).join("\n")}</style>`;
|
|
121332
121739
|
if (svg.includes("<defs>")) {
|
|
121333
121740
|
return svg.replace("<defs>", `<defs>${styleBlock}`);
|
|
121334
121741
|
}
|
|
@@ -121654,7 +122061,7 @@ function useExportHandlers(input) {
|
|
|
121654
122061
|
activeSlideIndexForGuides,
|
|
121655
122062
|
modalControls
|
|
121656
122063
|
});
|
|
121657
|
-
const handleExportPng = async () => {
|
|
122064
|
+
const handleExportPng = React10.useCallback(async () => {
|
|
121658
122065
|
const stageEl = canvasStageRef.current;
|
|
121659
122066
|
if (!stageEl) {
|
|
121660
122067
|
return;
|
|
@@ -121666,8 +122073,8 @@ function useExportHandlers(input) {
|
|
|
121666
122073
|
} catch (err) {
|
|
121667
122074
|
console.error("[PowerPointViewer] PNG export failed:", err);
|
|
121668
122075
|
}
|
|
121669
|
-
};
|
|
121670
|
-
const handleExportPdf = async () => {
|
|
122076
|
+
}, [canvasStageRef, activeSlideIndex, activeSlide?.backgroundColor]);
|
|
122077
|
+
const handleExportPdf = React10.useCallback(async () => {
|
|
121671
122078
|
if (!canvasStageRef.current) {
|
|
121672
122079
|
return;
|
|
121673
122080
|
}
|
|
@@ -121708,8 +122115,8 @@ function useExportHandlers(input) {
|
|
|
121708
122115
|
exportAbortRef.current = null;
|
|
121709
122116
|
setExportModalOpen(false);
|
|
121710
122117
|
}
|
|
121711
|
-
};
|
|
121712
|
-
const handleExportNotesPdf = async () => {
|
|
122118
|
+
}, [canvasStageRef, slides.length, setActiveSlideIndex, activeSlideIndex]);
|
|
122119
|
+
const handleExportNotesPdf = React10.useCallback(async () => {
|
|
121713
122120
|
if (!canvasStageRef.current) {
|
|
121714
122121
|
return;
|
|
121715
122122
|
}
|
|
@@ -121752,8 +122159,8 @@ function useExportHandlers(input) {
|
|
|
121752
122159
|
exportAbortRef.current = null;
|
|
121753
122160
|
setExportModalOpen(false);
|
|
121754
122161
|
}
|
|
121755
|
-
};
|
|
121756
|
-
const handleCopySlideAsImage = async () => {
|
|
122162
|
+
}, [canvasStageRef, slides, setActiveSlideIndex, activeSlideIndex]);
|
|
122163
|
+
const handleCopySlideAsImage = React10.useCallback(async () => {
|
|
121757
122164
|
const stageEl = canvasStageRef.current;
|
|
121758
122165
|
if (!stageEl) {
|
|
121759
122166
|
return;
|
|
@@ -121765,8 +122172,8 @@ function useExportHandlers(input) {
|
|
|
121765
122172
|
} catch (err) {
|
|
121766
122173
|
console.error("[PowerPointViewer] Copy slide as image failed:", err);
|
|
121767
122174
|
}
|
|
121768
|
-
};
|
|
121769
|
-
const handleExportVideo = async () => {
|
|
122175
|
+
}, [canvasStageRef, activeSlide?.backgroundColor]);
|
|
122176
|
+
const handleExportVideo = React10.useCallback(async () => {
|
|
121770
122177
|
if (!canvasStageRef.current) {
|
|
121771
122178
|
return;
|
|
121772
122179
|
}
|
|
@@ -121808,8 +122215,8 @@ function useExportHandlers(input) {
|
|
|
121808
122215
|
exportAbortRef.current = null;
|
|
121809
122216
|
setExportModalOpen(false);
|
|
121810
122217
|
}
|
|
121811
|
-
};
|
|
121812
|
-
const handleExportGif = async () => {
|
|
122218
|
+
}, [canvasStageRef, slides.length, setActiveSlideIndex, activeSlideIndex]);
|
|
122219
|
+
const handleExportGif = React10.useCallback(async () => {
|
|
121813
122220
|
if (!canvasStageRef.current) {
|
|
121814
122221
|
return;
|
|
121815
122222
|
}
|
|
@@ -121847,7 +122254,7 @@ function useExportHandlers(input) {
|
|
|
121847
122254
|
exportAbortRef.current = null;
|
|
121848
122255
|
setExportModalOpen(false);
|
|
121849
122256
|
}
|
|
121850
|
-
};
|
|
122257
|
+
}, [canvasStageRef, slides.length, setActiveSlideIndex, activeSlideIndex]);
|
|
121851
122258
|
const handleCancelExport = React10.useCallback(() => {
|
|
121852
122259
|
exportAbortRef.current?.abort();
|
|
121853
122260
|
exportAbortRef.current = null;
|
|
@@ -121873,6 +122280,15 @@ function useExportHandlers(input) {
|
|
|
121873
122280
|
exportStatusMessage
|
|
121874
122281
|
};
|
|
121875
122282
|
}
|
|
122283
|
+
function escapeHtmlAttr(value) {
|
|
122284
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
122285
|
+
}
|
|
122286
|
+
function safeDataImageSrc(src) {
|
|
122287
|
+
if (typeof src !== "string" || !src.startsWith("data:image/")) {
|
|
122288
|
+
return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNgAAIAAAUAAen63NgAAAAASUVORK5CYII=";
|
|
122289
|
+
}
|
|
122290
|
+
return escapeHtmlAttr(src);
|
|
122291
|
+
}
|
|
121876
122292
|
function openPrintWindow(title, bodyHtml, orientation, colorFilter, frameSlides) {
|
|
121877
122293
|
const printWindow = window.open("", "_blank", "noopener,noreferrer");
|
|
121878
122294
|
if (!printWindow) {
|
|
@@ -122055,7 +122471,7 @@ function usePrintHandlers(input) {
|
|
|
122055
122471
|
const slideImages = slideIndices.map((idx) => allImages[idx]).filter(Boolean);
|
|
122056
122472
|
if (settings.printWhat === "slides") {
|
|
122057
122473
|
const bodyHtml = slideImages.map(
|
|
122058
|
-
(img, i3) => `<section class="page slide-page"><img class="slide-img" src="${img}" alt="Slide ${slideIndices[i3] + 1}" /></section>`
|
|
122474
|
+
(img, i3) => `<section class="page slide-page"><img class="slide-img" src="${safeDataImageSrc(img)}" alt="Slide ${slideIndices[i3] + 1}" /></section>`
|
|
122059
122475
|
).join("");
|
|
122060
122476
|
openPrintWindow(
|
|
122061
122477
|
"Slides",
|
|
@@ -122071,7 +122487,7 @@ function usePrintHandlers(input) {
|
|
|
122071
122487
|
const idx = slideIndices[i3];
|
|
122072
122488
|
const notes = slides[idx]?.notes?.trim() || "";
|
|
122073
122489
|
return `<section class="page notes-page">
|
|
122074
|
-
<img class="notes-slide" src="${img}" alt="Slide ${idx + 1}" />
|
|
122490
|
+
<img class="notes-slide" src="${safeDataImageSrc(img)}" alt="Slide ${idx + 1}" />
|
|
122075
122491
|
<div class="notes-text">${escapeHtml2(notes)}</div>
|
|
122076
122492
|
</section>`;
|
|
122077
122493
|
}).join("");
|
|
@@ -122103,14 +122519,14 @@ function usePrintHandlers(input) {
|
|
|
122103
122519
|
if (isThreePerPage) {
|
|
122104
122520
|
const rows = Array.from({ length: spp }, (_, cellIndex) => {
|
|
122105
122521
|
const img = pageImgs[cellIndex];
|
|
122106
|
-
const slideCell = img ? `<div class="handout-cell"><img src="${img}" alt="Slide ${slideIndices[i3 + cellIndex] + 1}" /></div>` : `<div class="handout-cell"></div>`;
|
|
122522
|
+
const slideCell = img ? `<div class="handout-cell"><img src="${safeDataImageSrc(img)}" alt="Slide ${slideIndices[i3 + cellIndex] + 1}" /></div>` : `<div class="handout-cell"></div>`;
|
|
122107
122523
|
return `<div class="handout-row-3">${slideCell}${buildNoteLines()}</div>`;
|
|
122108
122524
|
}).join("");
|
|
122109
122525
|
pages.push(`<section class="page"><div class="handout-grid-3">${rows}</div></section>`);
|
|
122110
122526
|
} else {
|
|
122111
122527
|
const cells = Array.from({ length: spp }, (_, cellIndex) => {
|
|
122112
122528
|
const img = pageImgs[cellIndex];
|
|
122113
|
-
return img ? `<div class="handout-cell"><img src="${img}" alt="Slide ${slideIndices[i3 + cellIndex] + 1}" /></div>` : `<div class="handout-cell"></div>`;
|
|
122529
|
+
return img ? `<div class="handout-cell"><img src="${safeDataImageSrc(img)}" alt="Slide ${slideIndices[i3 + cellIndex] + 1}" /></div>` : `<div class="handout-cell"></div>`;
|
|
122114
122530
|
}).join("");
|
|
122115
122531
|
pages.push(
|
|
122116
122532
|
`<section class="page"><div class="handout-grid" style="grid-template-columns: repeat(${grid.columns}, minmax(0, 1fr)); grid-template-rows: repeat(${grid.rows}, minmax(0, 1fr));">${cells}</div></section>`
|