@files-preview-app/preview-file 1.2.1 → 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/angular.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { Component, ChangeDetectionStrategy, Input, Output, ViewChild, EventEmitter as EventEmitter$1 } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
- import DOMPurify5 from 'dompurify';
3
+ import DOMPurify6 from 'dompurify';
4
4
  import * as docx from 'docx-preview';
5
+ import { unzipSync, strFromU8, unzip } from 'fflate';
5
6
  import * as XLSX from 'xlsx';
6
7
  import hljs from 'highlight.js';
7
- import { unzipSync, strFromU8, unzip } from 'fflate';
8
8
  import { marked } from 'marked';
9
9
  import { PptxRenderer } from 'pptx-browser';
10
10
  import * as THREE from 'three';
@@ -388,7 +388,7 @@ async function sourceToArrayBuffer(source, signal) {
388
388
  return { buffer, metadata };
389
389
  }
390
390
  function sanitizeSVG(svg) {
391
- return DOMPurify5.sanitize(svg, {
391
+ return DOMPurify6.sanitize(svg, {
392
392
  USE_PROFILES: { svg: true, svgFilters: true }
393
393
  });
394
394
  }
@@ -464,7 +464,11 @@ var ICON_MAP = {
464
464
  "close": ICON_CLOSE,
465
465
  "copy": ICON_COPY,
466
466
  "prev": ICON_PAGE_PREV,
467
- "next": ICON_PAGE_NEXT
467
+ "next": ICON_PAGE_NEXT,
468
+ "page-prev": ICON_PAGE_PREV,
469
+ "page-next": ICON_PAGE_NEXT,
470
+ "chevron-left": ICON_PAGE_PREV,
471
+ "chevron-right": ICON_PAGE_NEXT
468
472
  };
469
473
  var ToolbarController = class {
470
474
  el;
@@ -496,7 +500,9 @@ var ToolbarController = class {
496
500
  view: [],
497
501
  actions: []
498
502
  };
499
- for (const action of this.actions) {
503
+ const hasPageNav = this.actions.some((a) => a.type === "page-nav");
504
+ const effectiveActions = hasPageNav ? this.actions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : this.actions;
505
+ for (const action of effectiveActions) {
500
506
  if (groups[action.group]) {
501
507
  groups[action.group].push(action);
502
508
  }
@@ -519,13 +525,26 @@ var ToolbarController = class {
519
525
  "prev",
520
526
  ICON_PAGE_PREV,
521
527
  "Previous Page",
522
- () => action.execute("prev")
528
+ () => {
529
+ const cur = parseInt(input.value, 10) || 1;
530
+ if (cur > 1) {
531
+ input.value = (cur - 1).toString();
532
+ action.execute("prev", cur - 1);
533
+ }
534
+ }
523
535
  );
524
536
  const nextBtn = this.createButton(
525
537
  "next",
526
538
  ICON_PAGE_NEXT,
527
539
  "Next Page",
528
- () => action.execute("next")
540
+ () => {
541
+ const cur = parseInt(input.value, 10) || 1;
542
+ const max = action.max ?? 1;
543
+ if (cur < max) {
544
+ input.value = (cur + 1).toString();
545
+ action.execute("next", cur + 1);
546
+ }
547
+ }
529
548
  );
530
549
  const input = createElement("input", {
531
550
  className: "fp-toolbar-input",
@@ -535,7 +554,10 @@ var ToolbarController = class {
535
554
  max: (action.max ?? 1).toString()
536
555
  });
537
556
  input.addEventListener("change", () => {
538
- action.execute("go", parseInt(input.value, 10));
557
+ const val = parseInt(input.value, 10);
558
+ if (!isNaN(val)) {
559
+ action.execute("go", val);
560
+ }
539
561
  });
540
562
  const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${action.max ?? 1}`);
541
563
  groupEl.appendChild(prevBtn);
@@ -576,11 +598,11 @@ var ToolbarController = class {
576
598
  type: "button",
577
599
  "data-action-id": id
578
600
  });
579
- const svg = ICON_MAP[iconHtml] || iconHtml;
580
- if (svg && svg.startsWith("<svg")) {
601
+ const svg = ICON_MAP[iconHtml] || ICON_MAP[id] || (iconHtml && iconHtml.startsWith("<svg") ? iconHtml : null);
602
+ if (svg) {
581
603
  btn.innerHTML = sanitizeSVG(svg);
582
604
  } else {
583
- btn.textContent = svg || title;
605
+ btn.textContent = title || id;
584
606
  }
585
607
  btn.addEventListener("click", onClick);
586
608
  return btn;
@@ -1323,12 +1345,12 @@ function pdfPlugin() {
1323
1345
  }
1324
1346
 
1325
1347
  // ../plugins/media/dist/index.js
1326
- var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"];
1327
- var VIDEO_EXTS = [".mp4", ".webm", ".ogg"];
1328
- var AUDIO_EXTS = [".mp3", ".wav", ".ogg"];
1348
+ var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".bmp", ".ico", ".tiff", ".tif", ".avif"];
1349
+ var VIDEO_EXTS = [".mp4", ".m4v", ".webm", ".ogv", ".ogg", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".3gp", ".mpg", ".mpeg"];
1350
+ var AUDIO_EXTS = [".mp3", ".wav", ".ogg", ".flac", ".aac", ".m4a", ".wma", ".opus", ".weba"];
1329
1351
  var MediaPlugin = class {
1330
1352
  id = "media";
1331
- name = "Media Preview";
1353
+ name = "Media Preview (Image, Video, Audio)";
1332
1354
  extensions = [...IMAGE_EXTS, ...VIDEO_EXTS, ...AUDIO_EXTS];
1333
1355
  mimeTypes = [
1334
1356
  "image/jpeg",
@@ -1336,12 +1358,29 @@ var MediaPlugin = class {
1336
1358
  "image/gif",
1337
1359
  "image/webp",
1338
1360
  "image/svg+xml",
1361
+ "image/bmp",
1362
+ "image/x-icon",
1363
+ "image/tiff",
1364
+ "image/avif",
1339
1365
  "video/mp4",
1340
1366
  "video/webm",
1341
1367
  "video/ogg",
1368
+ "video/quicktime",
1369
+ "video/x-msvideo",
1370
+ "video/x-matroska",
1371
+ "video/x-flv",
1372
+ "video/x-ms-wmv",
1373
+ "video/3gpp",
1374
+ "video/mpeg",
1342
1375
  "audio/mpeg",
1343
1376
  "audio/wav",
1344
- "audio/ogg"
1377
+ "audio/ogg",
1378
+ "audio/flac",
1379
+ "audio/aac",
1380
+ "audio/mp4",
1381
+ "audio/x-ms-wma",
1382
+ "audio/opus",
1383
+ "audio/webm"
1345
1384
  ];
1346
1385
  weight = 90;
1347
1386
  supports(file) {
@@ -1474,8 +1513,12 @@ var MediaPlugin = class {
1474
1513
  const video = document.createElement("video");
1475
1514
  video.src = url;
1476
1515
  video.controls = true;
1477
- video.style.maxWidth = "100%";
1478
- video.style.maxHeight = "100%";
1516
+ video.playsInline = true;
1517
+ video.style.maxWidth = "90%";
1518
+ video.style.maxHeight = "90%";
1519
+ video.style.borderRadius = "8px";
1520
+ video.style.boxShadow = "0 8px 30px rgba(0,0,0,0.3)";
1521
+ video.style.backgroundColor = "#000000";
1479
1522
  element = video;
1480
1523
  mediaElement = video;
1481
1524
  } else if (isAudio) {
@@ -1551,7 +1594,7 @@ function mediaPlugin() {
1551
1594
  }
1552
1595
  var DocxPlugin = class {
1553
1596
  id = "docx";
1554
- name = "Word Document Preview";
1597
+ name = "Word Document Preview (.docx, .docm, .dotx, .dotm)";
1555
1598
  extensions = [".docx", ".docm", ".dotx", ".dotm"];
1556
1599
  mimeTypes = [
1557
1600
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
@@ -1573,9 +1616,7 @@ var DocxPlugin = class {
1573
1616
  label: "Zoom Out",
1574
1617
  type: "button",
1575
1618
  group: "zoom",
1576
- execute: () => {
1577
- instance.zoomOut?.();
1578
- }
1619
+ execute: () => instance.zoomOut?.()
1579
1620
  },
1580
1621
  {
1581
1622
  id: "zoom-in",
@@ -1583,9 +1624,7 @@ var DocxPlugin = class {
1583
1624
  label: "Zoom In",
1584
1625
  type: "button",
1585
1626
  group: "zoom",
1586
- execute: () => {
1587
- instance.zoomIn?.();
1588
- }
1627
+ execute: () => instance.zoomIn?.()
1589
1628
  },
1590
1629
  {
1591
1630
  id: "fit-page",
@@ -1593,9 +1632,7 @@ var DocxPlugin = class {
1593
1632
  label: "Fit to Page",
1594
1633
  type: "button",
1595
1634
  group: "zoom",
1596
- execute: () => {
1597
- instance.fitToPage?.();
1598
- }
1635
+ execute: () => instance.fitToPage?.()
1599
1636
  },
1600
1637
  {
1601
1638
  id: "download",
@@ -1603,9 +1640,7 @@ var DocxPlugin = class {
1603
1640
  label: "Download",
1604
1641
  type: "button",
1605
1642
  group: "actions",
1606
- execute: () => {
1607
- instance.download?.();
1608
- }
1643
+ execute: () => instance.download?.()
1609
1644
  },
1610
1645
  {
1611
1646
  id: "print",
@@ -1613,9 +1648,7 @@ var DocxPlugin = class {
1613
1648
  label: "Print",
1614
1649
  type: "button",
1615
1650
  group: "actions",
1616
- execute: () => {
1617
- instance.print?.();
1618
- }
1651
+ execute: () => instance.print?.()
1619
1652
  }
1620
1653
  ];
1621
1654
  }
@@ -1624,24 +1657,46 @@ var DocxPlugin = class {
1624
1657
  wrapper.className = "fp-docx-wrapper";
1625
1658
  wrapper.style.transformOrigin = "top center";
1626
1659
  wrapper.style.transition = "transform 0.2s ease";
1627
- wrapper.style.padding = "16px";
1660
+ wrapper.style.padding = "24px 16px";
1661
+ wrapper.style.maxWidth = "900px";
1662
+ wrapper.style.margin = "0 auto";
1663
+ wrapper.style.boxSizing = "border-box";
1628
1664
  ctx.container.style.overflow = "auto";
1665
+ ctx.container.style.backgroundColor = "#f1f5f9";
1629
1666
  ctx.container.appendChild(wrapper);
1630
1667
  let scale = 1;
1668
+ let renderedSuccessfully = false;
1631
1669
  try {
1632
1670
  await docx.renderAsync(ctx.buffer, wrapper, ctx.container, {
1633
1671
  inWrapper: true,
1634
1672
  ignoreWidth: false,
1635
- ignoreHeight: false
1673
+ ignoreHeight: false,
1674
+ ignoreFonts: true,
1675
+ // Avoid crashes on embedded obfuscated fonts
1676
+ breakPages: true,
1677
+ experimental: true
1636
1678
  });
1637
- } catch {
1638
- wrapper.innerHTML = `
1639
- <div style="text-align:center; padding: 40px; color: #666;">
1640
- <div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
1641
- <h3>${ctx.metadata.name || "Word Document"}</h3>
1642
- <p>DOCX render preview</p>
1643
- </div>
1644
- `;
1679
+ if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
1680
+ renderedSuccessfully = true;
1681
+ }
1682
+ } catch (err) {
1683
+ console.warn("[DocxPlugin] docx-preview failed, triggering native XML fallback:", err);
1684
+ }
1685
+ if (!renderedSuccessfully) {
1686
+ try {
1687
+ wrapper.innerHTML = "";
1688
+ this.renderXmlFallback(ctx, wrapper);
1689
+ renderedSuccessfully = true;
1690
+ } catch (fallbackErr) {
1691
+ console.error("[DocxPlugin] XML fallback failed:", fallbackErr);
1692
+ wrapper.innerHTML = `
1693
+ <div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
1694
+ <div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
1695
+ <h3 style="margin: 0 0 8px; color: #1e293b;">${ctx.metadata.name || "Word Document"}</h3>
1696
+ <p style="color: #64748b; margin: 0;">Could not parse document content</p>
1697
+ </div>
1698
+ `;
1699
+ }
1645
1700
  }
1646
1701
  const cleanup = () => {
1647
1702
  wrapper.remove();
@@ -1665,7 +1720,7 @@ var DocxPlugin = class {
1665
1720
  },
1666
1721
  fitToPage: () => {
1667
1722
  scale = 1;
1668
- wrapper.style.transform = `scale(1)`;
1723
+ wrapper.style.transform = "scale(1)";
1669
1724
  },
1670
1725
  download: () => {
1671
1726
  const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
@@ -1681,6 +1736,100 @@ var DocxPlugin = class {
1681
1736
  }
1682
1737
  };
1683
1738
  }
1739
+ renderXmlFallback(ctx, wrapper) {
1740
+ const unzipped = unzipSync(new Uint8Array(ctx.buffer));
1741
+ const docXmlEntry = unzipped["word/document.xml"];
1742
+ if (!docXmlEntry) throw new Error("Missing word/document.xml in DOCX package");
1743
+ const xmlStr = strFromU8(docXmlEntry);
1744
+ const parser = new DOMParser();
1745
+ const doc = parser.parseFromString(xmlStr, "application/xml");
1746
+ const card = document.createElement("div");
1747
+ card.className = "fp-docx-page-card";
1748
+ card.style.backgroundColor = "#ffffff";
1749
+ card.style.borderRadius = "6px";
1750
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
1751
+ card.style.padding = "48px 56px";
1752
+ card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
1753
+ card.style.color = "#1e293b";
1754
+ card.style.lineHeight = "1.6";
1755
+ const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
1756
+ let html = "";
1757
+ for (const child of Array.from(body.children)) {
1758
+ const tag = child.localName || child.nodeName.split(":").pop();
1759
+ if (tag === "p") {
1760
+ const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
1761
+ const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
1762
+ const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
1763
+ const textContent = this.extractParagraphHtml(child);
1764
+ if (!textContent.trim()) {
1765
+ html += '<div style="height: 10px;"></div>';
1766
+ continue;
1767
+ }
1768
+ const lowerStyle = styleVal.toLowerCase();
1769
+ if (lowerStyle.includes("title")) {
1770
+ 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>`;
1771
+ } else if (lowerStyle.includes("heading1") || styleVal === "1") {
1772
+ html += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
1773
+ } else if (lowerStyle.includes("heading2") || styleVal === "2") {
1774
+ html += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
1775
+ } else if (lowerStyle.includes("heading3") || styleVal === "3") {
1776
+ html += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
1777
+ } else if (numPr) {
1778
+ 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>`;
1779
+ } else {
1780
+ html += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
1781
+ }
1782
+ } else if (tag === "tbl") {
1783
+ html += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
1784
+ const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
1785
+ rows.forEach((tr, rIdx) => {
1786
+ html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
1787
+ const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
1788
+ cells.forEach((tc) => {
1789
+ const cellText = this.extractParagraphHtml(tc);
1790
+ html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
1791
+ });
1792
+ html += "</tr>";
1793
+ });
1794
+ html += "</table>";
1795
+ }
1796
+ }
1797
+ card.innerHTML = DOMPurify6.sanitize(html, {
1798
+ ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "img", "div"],
1799
+ ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
1800
+ });
1801
+ wrapper.appendChild(card);
1802
+ }
1803
+ extractParagraphHtml(pElement) {
1804
+ let result = "";
1805
+ const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
1806
+ if (runs.length === 0) {
1807
+ return DOMPurify6.sanitize(pElement.textContent || "");
1808
+ }
1809
+ for (const r of runs) {
1810
+ const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
1811
+ const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
1812
+ const isItalic = !!rPr?.getElementsByTagNameNS("*", "i")[0];
1813
+ const isUnderline = !!rPr?.getElementsByTagNameNS("*", "u")[0];
1814
+ const colorNode = rPr?.getElementsByTagNameNS("*", "color")[0];
1815
+ const colorVal = colorNode?.getAttribute("w:val") || colorNode?.getAttribute("val");
1816
+ const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
1817
+ let text = texts.map((t) => t.textContent || "").join("");
1818
+ if (!text) continue;
1819
+ text = DOMPurify6.sanitize(text);
1820
+ let styles = "";
1821
+ if (isBold) styles += "font-weight: bold; ";
1822
+ if (isItalic) styles += "font-style: italic; ";
1823
+ if (isUnderline) styles += "text-decoration: underline; ";
1824
+ if (colorVal && colorVal !== "auto") styles += `color: #${colorVal}; `;
1825
+ if (styles) {
1826
+ result += `<span style="${styles}">${text}</span>`;
1827
+ } else {
1828
+ result += text;
1829
+ }
1830
+ }
1831
+ return result;
1832
+ }
1684
1833
  };
1685
1834
  function docxPlugin() {
1686
1835
  return new DocxPlugin();
@@ -2492,7 +2641,7 @@ var MarkdownPlugin = class {
2492
2641
  gfm: true,
2493
2642
  breaks: true
2494
2643
  });
2495
- const cleanHtml = DOMPurify5.sanitize(rawHtml, {
2644
+ const cleanHtml = DOMPurify6.sanitize(rawHtml, {
2496
2645
  USE_PROFILES: { html: true }
2497
2646
  });
2498
2647
  const wrapper = document.createElement("div");
@@ -2656,35 +2805,27 @@ var PptxPlugin = class {
2656
2805
  group: "navigation",
2657
2806
  execute: () => instance.toggleThumbnails?.()
2658
2807
  },
2659
- {
2660
- id: "page-prev",
2661
- icon: "page-prev",
2662
- label: "Previous Slide",
2663
- type: "button",
2664
- group: "navigation",
2665
- execute: () => {
2666
- const cur = instance.getCurrentPage?.() ?? 1;
2667
- if (cur > 1) instance.goToPage?.(cur - 1);
2668
- }
2669
- },
2670
2808
  {
2671
2809
  id: "page-nav",
2672
2810
  icon: "",
2673
- label: "Slide Number",
2811
+ label: "Slide Navigation",
2674
2812
  type: "page-nav",
2675
2813
  group: "navigation",
2676
- execute: (page) => instance.goToPage?.(Number(page))
2677
- },
2678
- {
2679
- id: "page-next",
2680
- icon: "page-next",
2681
- label: "Next Slide",
2682
- type: "button",
2683
- group: "navigation",
2684
- execute: () => {
2685
- const cur = instance.getCurrentPage?.() ?? 1;
2686
- const total = instance.getPageCount?.() ?? 1;
2687
- if (cur < total) instance.goToPage?.(cur + 1);
2814
+ value: instance.getCurrentPage?.() ?? 1,
2815
+ max: instance.getPageCount?.() ?? 1,
2816
+ execute: (action, page) => {
2817
+ if (action === "prev") {
2818
+ const cur = instance.getCurrentPage?.() ?? 1;
2819
+ if (cur > 1) instance.goToPage?.(cur - 1);
2820
+ } else if (action === "next") {
2821
+ const cur = instance.getCurrentPage?.() ?? 1;
2822
+ const total = instance.getPageCount?.() ?? 1;
2823
+ if (cur < total) instance.goToPage?.(cur + 1);
2824
+ } else if (typeof page === "number") {
2825
+ instance.goToPage?.(page);
2826
+ } else if (typeof action === "number") {
2827
+ instance.goToPage?.(action);
2828
+ }
2688
2829
  }
2689
2830
  },
2690
2831
  {
@@ -3215,7 +3356,7 @@ var HtmlPreviewPlugin = class {
3215
3356
  }
3216
3357
  async render(ctx) {
3217
3358
  const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
3218
- const sanitized = DOMPurify5.sanitize(rawHtml, {
3359
+ const sanitized = DOMPurify6.sanitize(rawHtml, {
3219
3360
  WHOLE_DOCUMENT: true,
3220
3361
  ADD_TAGS: ["style", "link"],
3221
3362
  ADD_ATTR: ["target", "rel"]
@@ -3310,35 +3451,27 @@ var OpenDocumentPlugin = class {
3310
3451
  group: "navigation",
3311
3452
  execute: () => instance.toggleThumbnails?.()
3312
3453
  },
3313
- {
3314
- id: "page-prev",
3315
- icon: "page-prev",
3316
- label: "Previous Slide",
3317
- type: "button",
3318
- group: "navigation",
3319
- execute: () => {
3320
- const cur = instance.getCurrentPage?.() ?? 1;
3321
- if (cur > 1) instance.goToPage?.(cur - 1);
3322
- }
3323
- },
3324
3454
  {
3325
3455
  id: "page-nav",
3326
3456
  icon: "",
3327
- label: "Slide Number",
3457
+ label: "Slide Navigation",
3328
3458
  type: "page-nav",
3329
3459
  group: "navigation",
3330
- execute: (p) => instance.goToPage?.(Number(p))
3331
- },
3332
- {
3333
- id: "page-next",
3334
- icon: "page-next",
3335
- label: "Next Slide",
3336
- type: "button",
3337
- group: "navigation",
3338
- execute: () => {
3339
- const cur = instance.getCurrentPage?.() ?? 1;
3340
- const total = instance.getPageCount?.() ?? 1;
3341
- if (cur < total) instance.goToPage?.(cur + 1);
3460
+ value: instance.getCurrentPage?.() ?? 1,
3461
+ max: instance.getPageCount?.() ?? 1,
3462
+ execute: (action, page) => {
3463
+ if (action === "prev") {
3464
+ const cur = instance.getCurrentPage?.() ?? 1;
3465
+ if (cur > 1) instance.goToPage?.(cur - 1);
3466
+ } else if (action === "next") {
3467
+ const cur = instance.getCurrentPage?.() ?? 1;
3468
+ const total = instance.getPageCount?.() ?? 1;
3469
+ if (cur < total) instance.goToPage?.(cur + 1);
3470
+ } else if (typeof page === "number") {
3471
+ instance.goToPage?.(page);
3472
+ } else if (typeof action === "number") {
3473
+ instance.goToPage?.(action);
3474
+ }
3342
3475
  }
3343
3476
  }
3344
3477
  );
@@ -3466,7 +3599,7 @@ var OpenDocumentPlugin = class {
3466
3599
  wrapper.style.padding = "48px";
3467
3600
  wrapper.style.minHeight = "100%";
3468
3601
  const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
3469
- wrapper.innerHTML = DOMPurify5.sanitize(bodyHtml, {
3602
+ wrapper.innerHTML = DOMPurify6.sanitize(bodyHtml, {
3470
3603
  ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
3471
3604
  ADD_ATTR: ["style", "colspan", "rowspan"]
3472
3605
  });
@@ -3986,24 +4119,24 @@ var DocPlugin = class {
3986
4119
  html += "</ul>";
3987
4120
  inList = false;
3988
4121
  }
3989
- html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify5.sanitize(line)}</h2>`;
4122
+ html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify6.sanitize(line)}</h2>`;
3990
4123
  } else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
3991
4124
  if (!inList) {
3992
4125
  html += '<ul style="margin: 8px 0; padding-left: 24px;">';
3993
4126
  inList = true;
3994
4127
  }
3995
4128
  const bulletText = line.replace(/^[•\-\*]\s*/, "");
3996
- html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify5.sanitize(bulletText)}</li>`;
4129
+ html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify6.sanitize(bulletText)}</li>`;
3997
4130
  } else {
3998
4131
  if (inList) {
3999
4132
  html += "</ul>";
4000
4133
  inList = false;
4001
4134
  }
4002
- html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify5.sanitize(line)}</p>`;
4135
+ html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
4003
4136
  }
4004
4137
  }
4005
4138
  if (inList) html += "</ul>";
4006
- return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify5.sanitize(filename)})</p>`;
4139
+ return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6.sanitize(filename)})</p>`;
4007
4140
  }
4008
4141
  };
4009
4142
  function docPlugin() {
@@ -4030,35 +4163,27 @@ var PptPlugin = class {
4030
4163
  group: "navigation",
4031
4164
  execute: () => instance.toggleThumbnails?.()
4032
4165
  },
4033
- {
4034
- id: "page-prev",
4035
- icon: "page-prev",
4036
- label: "Previous Slide",
4037
- type: "button",
4038
- group: "navigation",
4039
- execute: () => {
4040
- const cur = instance.getCurrentPage?.() ?? 1;
4041
- if (cur > 1) instance.goToPage?.(cur - 1);
4042
- }
4043
- },
4044
4166
  {
4045
4167
  id: "page-nav",
4046
4168
  icon: "",
4047
- label: "Slide Number",
4169
+ label: "Slide Navigation",
4048
4170
  type: "page-nav",
4049
4171
  group: "navigation",
4050
- execute: (p) => instance.goToPage?.(Number(p))
4051
- },
4052
- {
4053
- id: "page-next",
4054
- icon: "page-next",
4055
- label: "Next Slide",
4056
- type: "button",
4057
- group: "navigation",
4058
- execute: () => {
4059
- const cur = instance.getCurrentPage?.() ?? 1;
4060
- const total = instance.getPageCount?.() ?? 1;
4061
- if (cur < total) instance.goToPage?.(cur + 1);
4172
+ value: instance.getCurrentPage?.() ?? 1,
4173
+ max: instance.getPageCount?.() ?? 1,
4174
+ execute: (action, page) => {
4175
+ if (action === "prev") {
4176
+ const cur = instance.getCurrentPage?.() ?? 1;
4177
+ if (cur > 1) instance.goToPage?.(cur - 1);
4178
+ } else if (action === "next") {
4179
+ const cur = instance.getCurrentPage?.() ?? 1;
4180
+ const total = instance.getPageCount?.() ?? 1;
4181
+ if (cur < total) instance.goToPage?.(cur + 1);
4182
+ } else if (typeof page === "number") {
4183
+ instance.goToPage?.(page);
4184
+ } else if (typeof action === "number") {
4185
+ instance.goToPage?.(action);
4186
+ }
4062
4187
  }
4063
4188
  },
4064
4189
  {
@@ -4166,10 +4291,10 @@ var PptPlugin = class {
4166
4291
  </div>
4167
4292
  <div style="text-align: center; width: 100%;">
4168
4293
  <h1 style="font-size: ${idx === 1 ? "36px" : "28px"}; color: #1e3a8a; margin: 0 0 24px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; font-weight: 700;">
4169
- ${DOMPurify5.sanitize(s.title || `Slide ${idx}`)}
4294
+ ${DOMPurify6.sanitize(s.title || `Slide ${idx}`)}
4170
4295
  </h1>
4171
4296
  <div style="display: flex; flex-direction: column; gap: 12px; max-width: 80%; margin: 0 auto; text-align: ${idx === 1 ? "center" : "left"};">
4172
- ${s.texts.map((t) => `<div style="font-size: 18px; color: #334155; line-height: 1.5; font-family: -apple-system, BlinkMacSystemFont, sans-serif;">${DOMPurify5.sanitize(t)}</div>`).join("")}
4297
+ ${s.texts.map((t) => `<div style="font-size: 18px; color: #334155; line-height: 1.5; font-family: -apple-system, BlinkMacSystemFont, sans-serif;">${DOMPurify6.sanitize(t)}</div>`).join("")}
4173
4298
  </div>
4174
4299
  </div>
4175
4300
  `;