@files-preview-app/preview-file 1.2.0 → 1.2.2

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.cjs CHANGED
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var DOMPurify5 = require('dompurify');
3
+ var DOMPurify6 = require('dompurify');
4
4
  var docx = require('docx-preview');
5
+ var fflate = require('fflate');
5
6
  var XLSX = require('xlsx');
6
7
  var hljs = require('highlight.js');
7
- var fflate = require('fflate');
8
8
  var marked = require('marked');
9
9
  var pptxBrowser = require('pptx-browser');
10
10
  var THREE = require('three');
@@ -33,7 +33,7 @@ function _interopNamespace(e) {
33
33
  return Object.freeze(n);
34
34
  }
35
35
 
36
- var DOMPurify5__default = /*#__PURE__*/_interopDefault(DOMPurify5);
36
+ var DOMPurify6__default = /*#__PURE__*/_interopDefault(DOMPurify6);
37
37
  var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
38
38
  var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
39
39
  var hljs__default = /*#__PURE__*/_interopDefault(hljs);
@@ -367,12 +367,12 @@ async function sourceToArrayBuffer(source, signal) {
367
367
  return { buffer, metadata };
368
368
  }
369
369
  function sanitizeHTML(html) {
370
- return DOMPurify5__default.default.sanitize(html, {
370
+ return DOMPurify6__default.default.sanitize(html, {
371
371
  USE_PROFILES: { html: true }
372
372
  });
373
373
  }
374
374
  function sanitizeSVG(svg) {
375
- return DOMPurify5__default.default.sanitize(svg, {
375
+ return DOMPurify6__default.default.sanitize(svg, {
376
376
  USE_PROFILES: { svg: true, svgFilters: true }
377
377
  });
378
378
  }
@@ -487,7 +487,11 @@ var ICON_MAP = {
487
487
  "close": ICON_CLOSE,
488
488
  "copy": ICON_COPY,
489
489
  "prev": ICON_PAGE_PREV,
490
- "next": ICON_PAGE_NEXT
490
+ "next": ICON_PAGE_NEXT,
491
+ "page-prev": ICON_PAGE_PREV,
492
+ "page-next": ICON_PAGE_NEXT,
493
+ "chevron-left": ICON_PAGE_PREV,
494
+ "chevron-right": ICON_PAGE_NEXT
491
495
  };
492
496
  var ToolbarController = class {
493
497
  el;
@@ -519,7 +523,9 @@ var ToolbarController = class {
519
523
  view: [],
520
524
  actions: []
521
525
  };
522
- for (const action of this.actions) {
526
+ const hasPageNav = this.actions.some((a) => a.type === "page-nav");
527
+ const effectiveActions = hasPageNav ? this.actions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : this.actions;
528
+ for (const action of effectiveActions) {
523
529
  if (groups[action.group]) {
524
530
  groups[action.group].push(action);
525
531
  }
@@ -542,13 +548,26 @@ var ToolbarController = class {
542
548
  "prev",
543
549
  ICON_PAGE_PREV,
544
550
  "Previous Page",
545
- () => action.execute("prev")
551
+ () => {
552
+ const cur = parseInt(input.value, 10) || 1;
553
+ if (cur > 1) {
554
+ input.value = (cur - 1).toString();
555
+ action.execute("prev", cur - 1);
556
+ }
557
+ }
546
558
  );
547
559
  const nextBtn = this.createButton(
548
560
  "next",
549
561
  ICON_PAGE_NEXT,
550
562
  "Next Page",
551
- () => action.execute("next")
563
+ () => {
564
+ const cur = parseInt(input.value, 10) || 1;
565
+ const max = action.max ?? 1;
566
+ if (cur < max) {
567
+ input.value = (cur + 1).toString();
568
+ action.execute("next", cur + 1);
569
+ }
570
+ }
552
571
  );
553
572
  const input = createElement("input", {
554
573
  className: "fp-toolbar-input",
@@ -558,7 +577,10 @@ var ToolbarController = class {
558
577
  max: (action.max ?? 1).toString()
559
578
  });
560
579
  input.addEventListener("change", () => {
561
- action.execute("go", parseInt(input.value, 10));
580
+ const val = parseInt(input.value, 10);
581
+ if (!isNaN(val)) {
582
+ action.execute("go", val);
583
+ }
562
584
  });
563
585
  const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${action.max ?? 1}`);
564
586
  groupEl.appendChild(prevBtn);
@@ -599,11 +621,11 @@ var ToolbarController = class {
599
621
  type: "button",
600
622
  "data-action-id": id
601
623
  });
602
- const svg = ICON_MAP[iconHtml] || iconHtml;
603
- if (svg && svg.startsWith("<svg")) {
624
+ const svg = ICON_MAP[iconHtml] || ICON_MAP[id] || (iconHtml && iconHtml.startsWith("<svg") ? iconHtml : null);
625
+ if (svg) {
604
626
  btn.innerHTML = sanitizeSVG(svg);
605
627
  } else {
606
- btn.textContent = svg || title;
628
+ btn.textContent = title || id;
607
629
  }
608
630
  btn.addEventListener("click", onClick);
609
631
  return btn;
@@ -1346,12 +1368,12 @@ function pdfPlugin() {
1346
1368
  }
1347
1369
 
1348
1370
  // ../plugins/media/dist/index.js
1349
- var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"];
1350
- var VIDEO_EXTS = [".mp4", ".webm", ".ogg"];
1351
- var AUDIO_EXTS = [".mp3", ".wav", ".ogg"];
1371
+ var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".bmp", ".ico", ".tiff", ".tif", ".avif"];
1372
+ var VIDEO_EXTS = [".mp4", ".m4v", ".webm", ".ogv", ".ogg", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".3gp", ".mpg", ".mpeg"];
1373
+ var AUDIO_EXTS = [".mp3", ".wav", ".ogg", ".flac", ".aac", ".m4a", ".wma", ".opus", ".weba"];
1352
1374
  var MediaPlugin = class {
1353
1375
  id = "media";
1354
- name = "Media Preview";
1376
+ name = "Media Preview (Image, Video, Audio)";
1355
1377
  extensions = [...IMAGE_EXTS, ...VIDEO_EXTS, ...AUDIO_EXTS];
1356
1378
  mimeTypes = [
1357
1379
  "image/jpeg",
@@ -1359,12 +1381,29 @@ var MediaPlugin = class {
1359
1381
  "image/gif",
1360
1382
  "image/webp",
1361
1383
  "image/svg+xml",
1384
+ "image/bmp",
1385
+ "image/x-icon",
1386
+ "image/tiff",
1387
+ "image/avif",
1362
1388
  "video/mp4",
1363
1389
  "video/webm",
1364
1390
  "video/ogg",
1391
+ "video/quicktime",
1392
+ "video/x-msvideo",
1393
+ "video/x-matroska",
1394
+ "video/x-flv",
1395
+ "video/x-ms-wmv",
1396
+ "video/3gpp",
1397
+ "video/mpeg",
1365
1398
  "audio/mpeg",
1366
1399
  "audio/wav",
1367
- "audio/ogg"
1400
+ "audio/ogg",
1401
+ "audio/flac",
1402
+ "audio/aac",
1403
+ "audio/mp4",
1404
+ "audio/x-ms-wma",
1405
+ "audio/opus",
1406
+ "audio/webm"
1368
1407
  ];
1369
1408
  weight = 90;
1370
1409
  supports(file) {
@@ -1497,8 +1536,12 @@ var MediaPlugin = class {
1497
1536
  const video = document.createElement("video");
1498
1537
  video.src = url;
1499
1538
  video.controls = true;
1500
- video.style.maxWidth = "100%";
1501
- video.style.maxHeight = "100%";
1539
+ video.playsInline = true;
1540
+ video.style.maxWidth = "90%";
1541
+ video.style.maxHeight = "90%";
1542
+ video.style.borderRadius = "8px";
1543
+ video.style.boxShadow = "0 8px 30px rgba(0,0,0,0.3)";
1544
+ video.style.backgroundColor = "#000000";
1502
1545
  element = video;
1503
1546
  mediaElement = video;
1504
1547
  } else if (isAudio) {
@@ -1574,7 +1617,7 @@ function mediaPlugin() {
1574
1617
  }
1575
1618
  var DocxPlugin = class {
1576
1619
  id = "docx";
1577
- name = "Word Document Preview";
1620
+ name = "Word Document Preview (.docx, .docm, .dotx, .dotm)";
1578
1621
  extensions = [".docx", ".docm", ".dotx", ".dotm"];
1579
1622
  mimeTypes = [
1580
1623
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
@@ -1596,9 +1639,7 @@ var DocxPlugin = class {
1596
1639
  label: "Zoom Out",
1597
1640
  type: "button",
1598
1641
  group: "zoom",
1599
- execute: () => {
1600
- instance.zoomOut?.();
1601
- }
1642
+ execute: () => instance.zoomOut?.()
1602
1643
  },
1603
1644
  {
1604
1645
  id: "zoom-in",
@@ -1606,9 +1647,7 @@ var DocxPlugin = class {
1606
1647
  label: "Zoom In",
1607
1648
  type: "button",
1608
1649
  group: "zoom",
1609
- execute: () => {
1610
- instance.zoomIn?.();
1611
- }
1650
+ execute: () => instance.zoomIn?.()
1612
1651
  },
1613
1652
  {
1614
1653
  id: "fit-page",
@@ -1616,9 +1655,7 @@ var DocxPlugin = class {
1616
1655
  label: "Fit to Page",
1617
1656
  type: "button",
1618
1657
  group: "zoom",
1619
- execute: () => {
1620
- instance.fitToPage?.();
1621
- }
1658
+ execute: () => instance.fitToPage?.()
1622
1659
  },
1623
1660
  {
1624
1661
  id: "download",
@@ -1626,9 +1663,7 @@ var DocxPlugin = class {
1626
1663
  label: "Download",
1627
1664
  type: "button",
1628
1665
  group: "actions",
1629
- execute: () => {
1630
- instance.download?.();
1631
- }
1666
+ execute: () => instance.download?.()
1632
1667
  },
1633
1668
  {
1634
1669
  id: "print",
@@ -1636,9 +1671,7 @@ var DocxPlugin = class {
1636
1671
  label: "Print",
1637
1672
  type: "button",
1638
1673
  group: "actions",
1639
- execute: () => {
1640
- instance.print?.();
1641
- }
1674
+ execute: () => instance.print?.()
1642
1675
  }
1643
1676
  ];
1644
1677
  }
@@ -1647,24 +1680,46 @@ var DocxPlugin = class {
1647
1680
  wrapper.className = "fp-docx-wrapper";
1648
1681
  wrapper.style.transformOrigin = "top center";
1649
1682
  wrapper.style.transition = "transform 0.2s ease";
1650
- wrapper.style.padding = "16px";
1683
+ wrapper.style.padding = "24px 16px";
1684
+ wrapper.style.maxWidth = "900px";
1685
+ wrapper.style.margin = "0 auto";
1686
+ wrapper.style.boxSizing = "border-box";
1651
1687
  ctx.container.style.overflow = "auto";
1688
+ ctx.container.style.backgroundColor = "#f1f5f9";
1652
1689
  ctx.container.appendChild(wrapper);
1653
1690
  let scale = 1;
1691
+ let renderedSuccessfully = false;
1654
1692
  try {
1655
1693
  await docx__namespace.renderAsync(ctx.buffer, wrapper, ctx.container, {
1656
1694
  inWrapper: true,
1657
1695
  ignoreWidth: false,
1658
- ignoreHeight: false
1696
+ ignoreHeight: false,
1697
+ ignoreFonts: true,
1698
+ // Avoid crashes on embedded obfuscated fonts
1699
+ breakPages: true,
1700
+ experimental: true
1659
1701
  });
1660
- } catch {
1661
- wrapper.innerHTML = `
1662
- <div style="text-align:center; padding: 40px; color: #666;">
1663
- <div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
1664
- <h3>${ctx.metadata.name || "Word Document"}</h3>
1665
- <p>DOCX render preview</p>
1666
- </div>
1667
- `;
1702
+ if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
1703
+ renderedSuccessfully = true;
1704
+ }
1705
+ } catch (err) {
1706
+ console.warn("[DocxPlugin] docx-preview failed, triggering native XML fallback:", err);
1707
+ }
1708
+ if (!renderedSuccessfully) {
1709
+ try {
1710
+ wrapper.innerHTML = "";
1711
+ this.renderXmlFallback(ctx, wrapper);
1712
+ renderedSuccessfully = true;
1713
+ } catch (fallbackErr) {
1714
+ console.error("[DocxPlugin] XML fallback failed:", fallbackErr);
1715
+ wrapper.innerHTML = `
1716
+ <div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
1717
+ <div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
1718
+ <h3 style="margin: 0 0 8px; color: #1e293b;">${ctx.metadata.name || "Word Document"}</h3>
1719
+ <p style="color: #64748b; margin: 0;">Could not parse document content</p>
1720
+ </div>
1721
+ `;
1722
+ }
1668
1723
  }
1669
1724
  const cleanup = () => {
1670
1725
  wrapper.remove();
@@ -1688,7 +1743,7 @@ var DocxPlugin = class {
1688
1743
  },
1689
1744
  fitToPage: () => {
1690
1745
  scale = 1;
1691
- wrapper.style.transform = `scale(1)`;
1746
+ wrapper.style.transform = "scale(1)";
1692
1747
  },
1693
1748
  download: () => {
1694
1749
  const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
@@ -1704,6 +1759,100 @@ var DocxPlugin = class {
1704
1759
  }
1705
1760
  };
1706
1761
  }
1762
+ renderXmlFallback(ctx, wrapper) {
1763
+ const unzipped = fflate.unzipSync(new Uint8Array(ctx.buffer));
1764
+ const docXmlEntry = unzipped["word/document.xml"];
1765
+ if (!docXmlEntry) throw new Error("Missing word/document.xml in DOCX package");
1766
+ const xmlStr = fflate.strFromU8(docXmlEntry);
1767
+ const parser = new DOMParser();
1768
+ const doc = parser.parseFromString(xmlStr, "application/xml");
1769
+ const card = document.createElement("div");
1770
+ card.className = "fp-docx-page-card";
1771
+ card.style.backgroundColor = "#ffffff";
1772
+ card.style.borderRadius = "6px";
1773
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
1774
+ card.style.padding = "48px 56px";
1775
+ card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
1776
+ card.style.color = "#1e293b";
1777
+ card.style.lineHeight = "1.6";
1778
+ const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
1779
+ let html = "";
1780
+ for (const child of Array.from(body.children)) {
1781
+ const tag = child.localName || child.nodeName.split(":").pop();
1782
+ if (tag === "p") {
1783
+ const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
1784
+ const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
1785
+ const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
1786
+ const textContent = this.extractParagraphHtml(child);
1787
+ if (!textContent.trim()) {
1788
+ html += '<div style="height: 10px;"></div>';
1789
+ continue;
1790
+ }
1791
+ const lowerStyle = styleVal.toLowerCase();
1792
+ if (lowerStyle.includes("title")) {
1793
+ html += `<h1 style="font-size: 28px; font-weight: 700; color: #1e3a8a; margin: 24px 0 12px; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px;">${textContent}</h1>`;
1794
+ } else if (lowerStyle.includes("heading1") || styleVal === "1") {
1795
+ html += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
1796
+ } else if (lowerStyle.includes("heading2") || styleVal === "2") {
1797
+ html += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
1798
+ } else if (lowerStyle.includes("heading3") || styleVal === "3") {
1799
+ html += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
1800
+ } else if (numPr) {
1801
+ html += `<div style="display: flex; gap: 8px; margin: 4px 0 4px 20px;"><span style="color: #2563eb; font-weight: bold;">\u2022</span><span>${textContent}</span></div>`;
1802
+ } else {
1803
+ html += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
1804
+ }
1805
+ } else if (tag === "tbl") {
1806
+ html += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
1807
+ const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
1808
+ rows.forEach((tr, rIdx) => {
1809
+ html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
1810
+ const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
1811
+ cells.forEach((tc) => {
1812
+ const cellText = this.extractParagraphHtml(tc);
1813
+ html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
1814
+ });
1815
+ html += "</tr>";
1816
+ });
1817
+ html += "</table>";
1818
+ }
1819
+ }
1820
+ card.innerHTML = DOMPurify6__default.default.sanitize(html, {
1821
+ ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "img", "div"],
1822
+ ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
1823
+ });
1824
+ wrapper.appendChild(card);
1825
+ }
1826
+ extractParagraphHtml(pElement) {
1827
+ let result = "";
1828
+ const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
1829
+ if (runs.length === 0) {
1830
+ return DOMPurify6__default.default.sanitize(pElement.textContent || "");
1831
+ }
1832
+ for (const r of runs) {
1833
+ const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
1834
+ const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
1835
+ const isItalic = !!rPr?.getElementsByTagNameNS("*", "i")[0];
1836
+ const isUnderline = !!rPr?.getElementsByTagNameNS("*", "u")[0];
1837
+ const colorNode = rPr?.getElementsByTagNameNS("*", "color")[0];
1838
+ const colorVal = colorNode?.getAttribute("w:val") || colorNode?.getAttribute("val");
1839
+ const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
1840
+ let text = texts.map((t) => t.textContent || "").join("");
1841
+ if (!text) continue;
1842
+ text = DOMPurify6__default.default.sanitize(text);
1843
+ let styles = "";
1844
+ if (isBold) styles += "font-weight: bold; ";
1845
+ if (isItalic) styles += "font-style: italic; ";
1846
+ if (isUnderline) styles += "text-decoration: underline; ";
1847
+ if (colorVal && colorVal !== "auto") styles += `color: #${colorVal}; `;
1848
+ if (styles) {
1849
+ result += `<span style="${styles}">${text}</span>`;
1850
+ } else {
1851
+ result += text;
1852
+ }
1853
+ }
1854
+ return result;
1855
+ }
1707
1856
  };
1708
1857
  function docxPlugin() {
1709
1858
  return new DocxPlugin();
@@ -2515,7 +2664,7 @@ var MarkdownPlugin = class {
2515
2664
  gfm: true,
2516
2665
  breaks: true
2517
2666
  });
2518
- const cleanHtml = DOMPurify5__default.default.sanitize(rawHtml, {
2667
+ const cleanHtml = DOMPurify6__default.default.sanitize(rawHtml, {
2519
2668
  USE_PROFILES: { html: true }
2520
2669
  });
2521
2670
  const wrapper = document.createElement("div");
@@ -2679,35 +2828,27 @@ var PptxPlugin = class {
2679
2828
  group: "navigation",
2680
2829
  execute: () => instance.toggleThumbnails?.()
2681
2830
  },
2682
- {
2683
- id: "page-prev",
2684
- icon: "page-prev",
2685
- label: "Previous Slide",
2686
- type: "button",
2687
- group: "navigation",
2688
- execute: () => {
2689
- const cur = instance.getCurrentPage?.() ?? 1;
2690
- if (cur > 1) instance.goToPage?.(cur - 1);
2691
- }
2692
- },
2693
2831
  {
2694
2832
  id: "page-nav",
2695
2833
  icon: "",
2696
- label: "Slide Number",
2834
+ label: "Slide Navigation",
2697
2835
  type: "page-nav",
2698
2836
  group: "navigation",
2699
- execute: (page) => instance.goToPage?.(Number(page))
2700
- },
2701
- {
2702
- id: "page-next",
2703
- icon: "page-next",
2704
- label: "Next Slide",
2705
- type: "button",
2706
- group: "navigation",
2707
- execute: () => {
2708
- const cur = instance.getCurrentPage?.() ?? 1;
2709
- const total = instance.getPageCount?.() ?? 1;
2710
- if (cur < total) instance.goToPage?.(cur + 1);
2837
+ value: instance.getCurrentPage?.() ?? 1,
2838
+ max: instance.getPageCount?.() ?? 1,
2839
+ execute: (action, page) => {
2840
+ if (action === "prev") {
2841
+ const cur = instance.getCurrentPage?.() ?? 1;
2842
+ if (cur > 1) instance.goToPage?.(cur - 1);
2843
+ } else if (action === "next") {
2844
+ const cur = instance.getCurrentPage?.() ?? 1;
2845
+ const total = instance.getPageCount?.() ?? 1;
2846
+ if (cur < total) instance.goToPage?.(cur + 1);
2847
+ } else if (typeof page === "number") {
2848
+ instance.goToPage?.(page);
2849
+ } else if (typeof action === "number") {
2850
+ instance.goToPage?.(action);
2851
+ }
2711
2852
  }
2712
2853
  },
2713
2854
  {
@@ -3238,7 +3379,7 @@ var HtmlPreviewPlugin = class {
3238
3379
  }
3239
3380
  async render(ctx) {
3240
3381
  const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
3241
- const sanitized = DOMPurify5__default.default.sanitize(rawHtml, {
3382
+ const sanitized = DOMPurify6__default.default.sanitize(rawHtml, {
3242
3383
  WHOLE_DOCUMENT: true,
3243
3384
  ADD_TAGS: ["style", "link"],
3244
3385
  ADD_ATTR: ["target", "rel"]
@@ -3333,35 +3474,27 @@ var OpenDocumentPlugin = class {
3333
3474
  group: "navigation",
3334
3475
  execute: () => instance.toggleThumbnails?.()
3335
3476
  },
3336
- {
3337
- id: "page-prev",
3338
- icon: "page-prev",
3339
- label: "Previous Slide",
3340
- type: "button",
3341
- group: "navigation",
3342
- execute: () => {
3343
- const cur = instance.getCurrentPage?.() ?? 1;
3344
- if (cur > 1) instance.goToPage?.(cur - 1);
3345
- }
3346
- },
3347
3477
  {
3348
3478
  id: "page-nav",
3349
3479
  icon: "",
3350
- label: "Slide Number",
3480
+ label: "Slide Navigation",
3351
3481
  type: "page-nav",
3352
3482
  group: "navigation",
3353
- execute: (p) => instance.goToPage?.(Number(p))
3354
- },
3355
- {
3356
- id: "page-next",
3357
- icon: "page-next",
3358
- label: "Next Slide",
3359
- type: "button",
3360
- group: "navigation",
3361
- execute: () => {
3362
- const cur = instance.getCurrentPage?.() ?? 1;
3363
- const total = instance.getPageCount?.() ?? 1;
3364
- if (cur < total) instance.goToPage?.(cur + 1);
3483
+ value: instance.getCurrentPage?.() ?? 1,
3484
+ max: instance.getPageCount?.() ?? 1,
3485
+ execute: (action, page) => {
3486
+ if (action === "prev") {
3487
+ const cur = instance.getCurrentPage?.() ?? 1;
3488
+ if (cur > 1) instance.goToPage?.(cur - 1);
3489
+ } else if (action === "next") {
3490
+ const cur = instance.getCurrentPage?.() ?? 1;
3491
+ const total = instance.getPageCount?.() ?? 1;
3492
+ if (cur < total) instance.goToPage?.(cur + 1);
3493
+ } else if (typeof page === "number") {
3494
+ instance.goToPage?.(page);
3495
+ } else if (typeof action === "number") {
3496
+ instance.goToPage?.(action);
3497
+ }
3365
3498
  }
3366
3499
  }
3367
3500
  );
@@ -3489,7 +3622,7 @@ var OpenDocumentPlugin = class {
3489
3622
  wrapper.style.padding = "48px";
3490
3623
  wrapper.style.minHeight = "100%";
3491
3624
  const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
3492
- wrapper.innerHTML = DOMPurify5__default.default.sanitize(bodyHtml, {
3625
+ wrapper.innerHTML = DOMPurify6__default.default.sanitize(bodyHtml, {
3493
3626
  ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
3494
3627
  ADD_ATTR: ["style", "colspan", "rowspan"]
3495
3628
  });
@@ -4009,24 +4142,24 @@ var DocPlugin = class {
4009
4142
  html += "</ul>";
4010
4143
  inList = false;
4011
4144
  }
4012
- html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify5__default.default.sanitize(line)}</h2>`;
4145
+ html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6__default.default.sanitize(line)}</h2>`;
4013
4146
  } else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
4014
4147
  if (!inList) {
4015
4148
  html += '<ul style="margin: 8px 0; padding-left: 24px;">';
4016
4149
  inList = true;
4017
4150
  }
4018
4151
  const bulletText = line.replace(/^[•\-\*]\s*/, "");
4019
- html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify5__default.default.sanitize(bulletText)}</li>`;
4152
+ html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify6__default.default.sanitize(bulletText)}</li>`;
4020
4153
  } else {
4021
4154
  if (inList) {
4022
4155
  html += "</ul>";
4023
4156
  inList = false;
4024
4157
  }
4025
- html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify5__default.default.sanitize(line)}</p>`;
4158
+ html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify6__default.default.sanitize(line)}</p>`;
4026
4159
  }
4027
4160
  }
4028
4161
  if (inList) html += "</ul>";
4029
- return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify5__default.default.sanitize(filename)})</p>`;
4162
+ return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6__default.default.sanitize(filename)})</p>`;
4030
4163
  }
4031
4164
  };
4032
4165
  function docPlugin() {
@@ -4053,35 +4186,27 @@ var PptPlugin = class {
4053
4186
  group: "navigation",
4054
4187
  execute: () => instance.toggleThumbnails?.()
4055
4188
  },
4056
- {
4057
- id: "page-prev",
4058
- icon: "page-prev",
4059
- label: "Previous Slide",
4060
- type: "button",
4061
- group: "navigation",
4062
- execute: () => {
4063
- const cur = instance.getCurrentPage?.() ?? 1;
4064
- if (cur > 1) instance.goToPage?.(cur - 1);
4065
- }
4066
- },
4067
4189
  {
4068
4190
  id: "page-nav",
4069
4191
  icon: "",
4070
- label: "Slide Number",
4192
+ label: "Slide Navigation",
4071
4193
  type: "page-nav",
4072
4194
  group: "navigation",
4073
- execute: (p) => instance.goToPage?.(Number(p))
4074
- },
4075
- {
4076
- id: "page-next",
4077
- icon: "page-next",
4078
- label: "Next Slide",
4079
- type: "button",
4080
- group: "navigation",
4081
- execute: () => {
4082
- const cur = instance.getCurrentPage?.() ?? 1;
4083
- const total = instance.getPageCount?.() ?? 1;
4084
- if (cur < total) instance.goToPage?.(cur + 1);
4195
+ value: instance.getCurrentPage?.() ?? 1,
4196
+ max: instance.getPageCount?.() ?? 1,
4197
+ execute: (action, page) => {
4198
+ if (action === "prev") {
4199
+ const cur = instance.getCurrentPage?.() ?? 1;
4200
+ if (cur > 1) instance.goToPage?.(cur - 1);
4201
+ } else if (action === "next") {
4202
+ const cur = instance.getCurrentPage?.() ?? 1;
4203
+ const total = instance.getPageCount?.() ?? 1;
4204
+ if (cur < total) instance.goToPage?.(cur + 1);
4205
+ } else if (typeof page === "number") {
4206
+ instance.goToPage?.(page);
4207
+ } else if (typeof action === "number") {
4208
+ instance.goToPage?.(action);
4209
+ }
4085
4210
  }
4086
4211
  },
4087
4212
  {
@@ -4189,10 +4314,10 @@ var PptPlugin = class {
4189
4314
  </div>
4190
4315
  <div style="text-align: center; width: 100%;">
4191
4316
  <h1 style="font-size: ${idx === 1 ? "36px" : "28px"}; color: #1e3a8a; margin: 0 0 24px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; font-weight: 700;">
4192
- ${DOMPurify5__default.default.sanitize(s.title || `Slide ${idx}`)}
4317
+ ${DOMPurify6__default.default.sanitize(s.title || `Slide ${idx}`)}
4193
4318
  </h1>
4194
4319
  <div style="display: flex; flex-direction: column; gap: 12px; max-width: 80%; margin: 0 auto; text-align: ${idx === 1 ? "center" : "left"};">
4195
- ${s.texts.map((t) => `<div style="font-size: 18px; color: #334155; line-height: 1.5; font-family: -apple-system, BlinkMacSystemFont, sans-serif;">${DOMPurify5__default.default.sanitize(t)}</div>`).join("")}
4320
+ ${s.texts.map((t) => `<div style="font-size: 18px; color: #334155; line-height: 1.5; font-family: -apple-system, BlinkMacSystemFont, sans-serif;">${DOMPurify6__default.default.sanitize(t)}</div>`).join("")}
4196
4321
  </div>
4197
4322
  </div>
4198
4323
  `;