@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/vue.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { defineComponent, ref, onMounted, watch, onBeforeUnmount, h } from 'vue';
2
- import DOMPurify5 from 'dompurify';
2
+ import DOMPurify6 from 'dompurify';
3
3
  import * as docx from 'docx-preview';
4
+ import { unzipSync, strFromU8, unzip } from 'fflate';
4
5
  import * as XLSX from 'xlsx';
5
6
  import hljs from 'highlight.js';
6
- import { unzipSync, strFromU8, unzip } from 'fflate';
7
7
  import { marked } from 'marked';
8
8
  import { PptxRenderer } from 'pptx-browser';
9
9
  import * as THREE from 'three';
@@ -340,7 +340,7 @@ async function sourceToArrayBuffer(source, signal) {
340
340
  return { buffer, metadata };
341
341
  }
342
342
  function sanitizeSVG(svg) {
343
- return DOMPurify5.sanitize(svg, {
343
+ return DOMPurify6.sanitize(svg, {
344
344
  USE_PROFILES: { svg: true, svgFilters: true }
345
345
  });
346
346
  }
@@ -416,7 +416,11 @@ var ICON_MAP = {
416
416
  "close": ICON_CLOSE,
417
417
  "copy": ICON_COPY,
418
418
  "prev": ICON_PAGE_PREV,
419
- "next": ICON_PAGE_NEXT
419
+ "next": ICON_PAGE_NEXT,
420
+ "page-prev": ICON_PAGE_PREV,
421
+ "page-next": ICON_PAGE_NEXT,
422
+ "chevron-left": ICON_PAGE_PREV,
423
+ "chevron-right": ICON_PAGE_NEXT
420
424
  };
421
425
  var ToolbarController = class {
422
426
  el;
@@ -448,7 +452,9 @@ var ToolbarController = class {
448
452
  view: [],
449
453
  actions: []
450
454
  };
451
- for (const action of this.actions) {
455
+ const hasPageNav = this.actions.some((a) => a.type === "page-nav");
456
+ const effectiveActions = hasPageNav ? this.actions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : this.actions;
457
+ for (const action of effectiveActions) {
452
458
  if (groups[action.group]) {
453
459
  groups[action.group].push(action);
454
460
  }
@@ -471,13 +477,26 @@ var ToolbarController = class {
471
477
  "prev",
472
478
  ICON_PAGE_PREV,
473
479
  "Previous Page",
474
- () => action.execute("prev")
480
+ () => {
481
+ const cur = parseInt(input.value, 10) || 1;
482
+ if (cur > 1) {
483
+ input.value = (cur - 1).toString();
484
+ action.execute("prev", cur - 1);
485
+ }
486
+ }
475
487
  );
476
488
  const nextBtn = this.createButton(
477
489
  "next",
478
490
  ICON_PAGE_NEXT,
479
491
  "Next Page",
480
- () => action.execute("next")
492
+ () => {
493
+ const cur = parseInt(input.value, 10) || 1;
494
+ const max = action.max ?? 1;
495
+ if (cur < max) {
496
+ input.value = (cur + 1).toString();
497
+ action.execute("next", cur + 1);
498
+ }
499
+ }
481
500
  );
482
501
  const input = createElement("input", {
483
502
  className: "fp-toolbar-input",
@@ -487,7 +506,10 @@ var ToolbarController = class {
487
506
  max: (action.max ?? 1).toString()
488
507
  });
489
508
  input.addEventListener("change", () => {
490
- action.execute("go", parseInt(input.value, 10));
509
+ const val = parseInt(input.value, 10);
510
+ if (!isNaN(val)) {
511
+ action.execute("go", val);
512
+ }
491
513
  });
492
514
  const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${action.max ?? 1}`);
493
515
  groupEl.appendChild(prevBtn);
@@ -528,11 +550,11 @@ var ToolbarController = class {
528
550
  type: "button",
529
551
  "data-action-id": id
530
552
  });
531
- const svg = ICON_MAP[iconHtml] || iconHtml;
532
- if (svg && svg.startsWith("<svg")) {
553
+ const svg = ICON_MAP[iconHtml] || ICON_MAP[id] || (iconHtml && iconHtml.startsWith("<svg") ? iconHtml : null);
554
+ if (svg) {
533
555
  btn.innerHTML = sanitizeSVG(svg);
534
556
  } else {
535
- btn.textContent = svg || title;
557
+ btn.textContent = title || id;
536
558
  }
537
559
  btn.addEventListener("click", onClick);
538
560
  return btn;
@@ -1275,12 +1297,12 @@ function pdfPlugin() {
1275
1297
  }
1276
1298
 
1277
1299
  // ../plugins/media/dist/index.js
1278
- var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"];
1279
- var VIDEO_EXTS = [".mp4", ".webm", ".ogg"];
1280
- var AUDIO_EXTS = [".mp3", ".wav", ".ogg"];
1300
+ var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".bmp", ".ico", ".tiff", ".tif", ".avif"];
1301
+ var VIDEO_EXTS = [".mp4", ".m4v", ".webm", ".ogv", ".ogg", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".3gp", ".mpg", ".mpeg"];
1302
+ var AUDIO_EXTS = [".mp3", ".wav", ".ogg", ".flac", ".aac", ".m4a", ".wma", ".opus", ".weba"];
1281
1303
  var MediaPlugin = class {
1282
1304
  id = "media";
1283
- name = "Media Preview";
1305
+ name = "Media Preview (Image, Video, Audio)";
1284
1306
  extensions = [...IMAGE_EXTS, ...VIDEO_EXTS, ...AUDIO_EXTS];
1285
1307
  mimeTypes = [
1286
1308
  "image/jpeg",
@@ -1288,12 +1310,29 @@ var MediaPlugin = class {
1288
1310
  "image/gif",
1289
1311
  "image/webp",
1290
1312
  "image/svg+xml",
1313
+ "image/bmp",
1314
+ "image/x-icon",
1315
+ "image/tiff",
1316
+ "image/avif",
1291
1317
  "video/mp4",
1292
1318
  "video/webm",
1293
1319
  "video/ogg",
1320
+ "video/quicktime",
1321
+ "video/x-msvideo",
1322
+ "video/x-matroska",
1323
+ "video/x-flv",
1324
+ "video/x-ms-wmv",
1325
+ "video/3gpp",
1326
+ "video/mpeg",
1294
1327
  "audio/mpeg",
1295
1328
  "audio/wav",
1296
- "audio/ogg"
1329
+ "audio/ogg",
1330
+ "audio/flac",
1331
+ "audio/aac",
1332
+ "audio/mp4",
1333
+ "audio/x-ms-wma",
1334
+ "audio/opus",
1335
+ "audio/webm"
1297
1336
  ];
1298
1337
  weight = 90;
1299
1338
  supports(file) {
@@ -1426,8 +1465,12 @@ var MediaPlugin = class {
1426
1465
  const video = document.createElement("video");
1427
1466
  video.src = url;
1428
1467
  video.controls = true;
1429
- video.style.maxWidth = "100%";
1430
- video.style.maxHeight = "100%";
1468
+ video.playsInline = true;
1469
+ video.style.maxWidth = "90%";
1470
+ video.style.maxHeight = "90%";
1471
+ video.style.borderRadius = "8px";
1472
+ video.style.boxShadow = "0 8px 30px rgba(0,0,0,0.3)";
1473
+ video.style.backgroundColor = "#000000";
1431
1474
  element = video;
1432
1475
  mediaElement = video;
1433
1476
  } else if (isAudio) {
@@ -1503,7 +1546,7 @@ function mediaPlugin() {
1503
1546
  }
1504
1547
  var DocxPlugin = class {
1505
1548
  id = "docx";
1506
- name = "Word Document Preview";
1549
+ name = "Word Document Preview (.docx, .docm, .dotx, .dotm)";
1507
1550
  extensions = [".docx", ".docm", ".dotx", ".dotm"];
1508
1551
  mimeTypes = [
1509
1552
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
@@ -1525,9 +1568,7 @@ var DocxPlugin = class {
1525
1568
  label: "Zoom Out",
1526
1569
  type: "button",
1527
1570
  group: "zoom",
1528
- execute: () => {
1529
- instance.zoomOut?.();
1530
- }
1571
+ execute: () => instance.zoomOut?.()
1531
1572
  },
1532
1573
  {
1533
1574
  id: "zoom-in",
@@ -1535,9 +1576,7 @@ var DocxPlugin = class {
1535
1576
  label: "Zoom In",
1536
1577
  type: "button",
1537
1578
  group: "zoom",
1538
- execute: () => {
1539
- instance.zoomIn?.();
1540
- }
1579
+ execute: () => instance.zoomIn?.()
1541
1580
  },
1542
1581
  {
1543
1582
  id: "fit-page",
@@ -1545,9 +1584,7 @@ var DocxPlugin = class {
1545
1584
  label: "Fit to Page",
1546
1585
  type: "button",
1547
1586
  group: "zoom",
1548
- execute: () => {
1549
- instance.fitToPage?.();
1550
- }
1587
+ execute: () => instance.fitToPage?.()
1551
1588
  },
1552
1589
  {
1553
1590
  id: "download",
@@ -1555,9 +1592,7 @@ var DocxPlugin = class {
1555
1592
  label: "Download",
1556
1593
  type: "button",
1557
1594
  group: "actions",
1558
- execute: () => {
1559
- instance.download?.();
1560
- }
1595
+ execute: () => instance.download?.()
1561
1596
  },
1562
1597
  {
1563
1598
  id: "print",
@@ -1565,9 +1600,7 @@ var DocxPlugin = class {
1565
1600
  label: "Print",
1566
1601
  type: "button",
1567
1602
  group: "actions",
1568
- execute: () => {
1569
- instance.print?.();
1570
- }
1603
+ execute: () => instance.print?.()
1571
1604
  }
1572
1605
  ];
1573
1606
  }
@@ -1576,24 +1609,46 @@ var DocxPlugin = class {
1576
1609
  wrapper.className = "fp-docx-wrapper";
1577
1610
  wrapper.style.transformOrigin = "top center";
1578
1611
  wrapper.style.transition = "transform 0.2s ease";
1579
- wrapper.style.padding = "16px";
1612
+ wrapper.style.padding = "24px 16px";
1613
+ wrapper.style.maxWidth = "900px";
1614
+ wrapper.style.margin = "0 auto";
1615
+ wrapper.style.boxSizing = "border-box";
1580
1616
  ctx.container.style.overflow = "auto";
1617
+ ctx.container.style.backgroundColor = "#f1f5f9";
1581
1618
  ctx.container.appendChild(wrapper);
1582
1619
  let scale = 1;
1620
+ let renderedSuccessfully = false;
1583
1621
  try {
1584
1622
  await docx.renderAsync(ctx.buffer, wrapper, ctx.container, {
1585
1623
  inWrapper: true,
1586
1624
  ignoreWidth: false,
1587
- ignoreHeight: false
1625
+ ignoreHeight: false,
1626
+ ignoreFonts: true,
1627
+ // Avoid crashes on embedded obfuscated fonts
1628
+ breakPages: true,
1629
+ experimental: true
1588
1630
  });
1589
- } catch {
1590
- wrapper.innerHTML = `
1591
- <div style="text-align:center; padding: 40px; color: #666;">
1592
- <div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
1593
- <h3>${ctx.metadata.name || "Word Document"}</h3>
1594
- <p>DOCX render preview</p>
1595
- </div>
1596
- `;
1631
+ if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
1632
+ renderedSuccessfully = true;
1633
+ }
1634
+ } catch (err) {
1635
+ console.warn("[DocxPlugin] docx-preview failed, triggering native XML fallback:", err);
1636
+ }
1637
+ if (!renderedSuccessfully) {
1638
+ try {
1639
+ wrapper.innerHTML = "";
1640
+ this.renderXmlFallback(ctx, wrapper);
1641
+ renderedSuccessfully = true;
1642
+ } catch (fallbackErr) {
1643
+ console.error("[DocxPlugin] XML fallback failed:", fallbackErr);
1644
+ wrapper.innerHTML = `
1645
+ <div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
1646
+ <div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
1647
+ <h3 style="margin: 0 0 8px; color: #1e293b;">${ctx.metadata.name || "Word Document"}</h3>
1648
+ <p style="color: #64748b; margin: 0;">Could not parse document content</p>
1649
+ </div>
1650
+ `;
1651
+ }
1597
1652
  }
1598
1653
  const cleanup = () => {
1599
1654
  wrapper.remove();
@@ -1617,7 +1672,7 @@ var DocxPlugin = class {
1617
1672
  },
1618
1673
  fitToPage: () => {
1619
1674
  scale = 1;
1620
- wrapper.style.transform = `scale(1)`;
1675
+ wrapper.style.transform = "scale(1)";
1621
1676
  },
1622
1677
  download: () => {
1623
1678
  const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
@@ -1633,6 +1688,100 @@ var DocxPlugin = class {
1633
1688
  }
1634
1689
  };
1635
1690
  }
1691
+ renderXmlFallback(ctx, wrapper) {
1692
+ const unzipped = unzipSync(new Uint8Array(ctx.buffer));
1693
+ const docXmlEntry = unzipped["word/document.xml"];
1694
+ if (!docXmlEntry) throw new Error("Missing word/document.xml in DOCX package");
1695
+ const xmlStr = strFromU8(docXmlEntry);
1696
+ const parser = new DOMParser();
1697
+ const doc = parser.parseFromString(xmlStr, "application/xml");
1698
+ const card = document.createElement("div");
1699
+ card.className = "fp-docx-page-card";
1700
+ card.style.backgroundColor = "#ffffff";
1701
+ card.style.borderRadius = "6px";
1702
+ card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
1703
+ card.style.padding = "48px 56px";
1704
+ card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
1705
+ card.style.color = "#1e293b";
1706
+ card.style.lineHeight = "1.6";
1707
+ const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
1708
+ let html = "";
1709
+ for (const child of Array.from(body.children)) {
1710
+ const tag = child.localName || child.nodeName.split(":").pop();
1711
+ if (tag === "p") {
1712
+ const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
1713
+ const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
1714
+ const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
1715
+ const textContent = this.extractParagraphHtml(child);
1716
+ if (!textContent.trim()) {
1717
+ html += '<div style="height: 10px;"></div>';
1718
+ continue;
1719
+ }
1720
+ const lowerStyle = styleVal.toLowerCase();
1721
+ if (lowerStyle.includes("title")) {
1722
+ 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>`;
1723
+ } else if (lowerStyle.includes("heading1") || styleVal === "1") {
1724
+ html += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
1725
+ } else if (lowerStyle.includes("heading2") || styleVal === "2") {
1726
+ html += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
1727
+ } else if (lowerStyle.includes("heading3") || styleVal === "3") {
1728
+ html += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
1729
+ } else if (numPr) {
1730
+ 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>`;
1731
+ } else {
1732
+ html += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
1733
+ }
1734
+ } else if (tag === "tbl") {
1735
+ html += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
1736
+ const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
1737
+ rows.forEach((tr, rIdx) => {
1738
+ html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
1739
+ const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
1740
+ cells.forEach((tc) => {
1741
+ const cellText = this.extractParagraphHtml(tc);
1742
+ html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || "&nbsp;"}</td>`;
1743
+ });
1744
+ html += "</tr>";
1745
+ });
1746
+ html += "</table>";
1747
+ }
1748
+ }
1749
+ card.innerHTML = DOMPurify6.sanitize(html, {
1750
+ ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "img", "div"],
1751
+ ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
1752
+ });
1753
+ wrapper.appendChild(card);
1754
+ }
1755
+ extractParagraphHtml(pElement) {
1756
+ let result = "";
1757
+ const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
1758
+ if (runs.length === 0) {
1759
+ return DOMPurify6.sanitize(pElement.textContent || "");
1760
+ }
1761
+ for (const r of runs) {
1762
+ const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
1763
+ const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
1764
+ const isItalic = !!rPr?.getElementsByTagNameNS("*", "i")[0];
1765
+ const isUnderline = !!rPr?.getElementsByTagNameNS("*", "u")[0];
1766
+ const colorNode = rPr?.getElementsByTagNameNS("*", "color")[0];
1767
+ const colorVal = colorNode?.getAttribute("w:val") || colorNode?.getAttribute("val");
1768
+ const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
1769
+ let text = texts.map((t) => t.textContent || "").join("");
1770
+ if (!text) continue;
1771
+ text = DOMPurify6.sanitize(text);
1772
+ let styles = "";
1773
+ if (isBold) styles += "font-weight: bold; ";
1774
+ if (isItalic) styles += "font-style: italic; ";
1775
+ if (isUnderline) styles += "text-decoration: underline; ";
1776
+ if (colorVal && colorVal !== "auto") styles += `color: #${colorVal}; `;
1777
+ if (styles) {
1778
+ result += `<span style="${styles}">${text}</span>`;
1779
+ } else {
1780
+ result += text;
1781
+ }
1782
+ }
1783
+ return result;
1784
+ }
1636
1785
  };
1637
1786
  function docxPlugin() {
1638
1787
  return new DocxPlugin();
@@ -2444,7 +2593,7 @@ var MarkdownPlugin = class {
2444
2593
  gfm: true,
2445
2594
  breaks: true
2446
2595
  });
2447
- const cleanHtml = DOMPurify5.sanitize(rawHtml, {
2596
+ const cleanHtml = DOMPurify6.sanitize(rawHtml, {
2448
2597
  USE_PROFILES: { html: true }
2449
2598
  });
2450
2599
  const wrapper = document.createElement("div");
@@ -2608,35 +2757,27 @@ var PptxPlugin = class {
2608
2757
  group: "navigation",
2609
2758
  execute: () => instance.toggleThumbnails?.()
2610
2759
  },
2611
- {
2612
- id: "page-prev",
2613
- icon: "page-prev",
2614
- label: "Previous Slide",
2615
- type: "button",
2616
- group: "navigation",
2617
- execute: () => {
2618
- const cur = instance.getCurrentPage?.() ?? 1;
2619
- if (cur > 1) instance.goToPage?.(cur - 1);
2620
- }
2621
- },
2622
2760
  {
2623
2761
  id: "page-nav",
2624
2762
  icon: "",
2625
- label: "Slide Number",
2763
+ label: "Slide Navigation",
2626
2764
  type: "page-nav",
2627
2765
  group: "navigation",
2628
- execute: (page) => instance.goToPage?.(Number(page))
2629
- },
2630
- {
2631
- id: "page-next",
2632
- icon: "page-next",
2633
- label: "Next Slide",
2634
- type: "button",
2635
- group: "navigation",
2636
- execute: () => {
2637
- const cur = instance.getCurrentPage?.() ?? 1;
2638
- const total = instance.getPageCount?.() ?? 1;
2639
- if (cur < total) instance.goToPage?.(cur + 1);
2766
+ value: instance.getCurrentPage?.() ?? 1,
2767
+ max: instance.getPageCount?.() ?? 1,
2768
+ execute: (action, page) => {
2769
+ if (action === "prev") {
2770
+ const cur = instance.getCurrentPage?.() ?? 1;
2771
+ if (cur > 1) instance.goToPage?.(cur - 1);
2772
+ } else if (action === "next") {
2773
+ const cur = instance.getCurrentPage?.() ?? 1;
2774
+ const total = instance.getPageCount?.() ?? 1;
2775
+ if (cur < total) instance.goToPage?.(cur + 1);
2776
+ } else if (typeof page === "number") {
2777
+ instance.goToPage?.(page);
2778
+ } else if (typeof action === "number") {
2779
+ instance.goToPage?.(action);
2780
+ }
2640
2781
  }
2641
2782
  },
2642
2783
  {
@@ -3167,7 +3308,7 @@ var HtmlPreviewPlugin = class {
3167
3308
  }
3168
3309
  async render(ctx) {
3169
3310
  const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
3170
- const sanitized = DOMPurify5.sanitize(rawHtml, {
3311
+ const sanitized = DOMPurify6.sanitize(rawHtml, {
3171
3312
  WHOLE_DOCUMENT: true,
3172
3313
  ADD_TAGS: ["style", "link"],
3173
3314
  ADD_ATTR: ["target", "rel"]
@@ -3262,35 +3403,27 @@ var OpenDocumentPlugin = class {
3262
3403
  group: "navigation",
3263
3404
  execute: () => instance.toggleThumbnails?.()
3264
3405
  },
3265
- {
3266
- id: "page-prev",
3267
- icon: "page-prev",
3268
- label: "Previous Slide",
3269
- type: "button",
3270
- group: "navigation",
3271
- execute: () => {
3272
- const cur = instance.getCurrentPage?.() ?? 1;
3273
- if (cur > 1) instance.goToPage?.(cur - 1);
3274
- }
3275
- },
3276
3406
  {
3277
3407
  id: "page-nav",
3278
3408
  icon: "",
3279
- label: "Slide Number",
3409
+ label: "Slide Navigation",
3280
3410
  type: "page-nav",
3281
3411
  group: "navigation",
3282
- execute: (p) => instance.goToPage?.(Number(p))
3283
- },
3284
- {
3285
- id: "page-next",
3286
- icon: "page-next",
3287
- label: "Next Slide",
3288
- type: "button",
3289
- group: "navigation",
3290
- execute: () => {
3291
- const cur = instance.getCurrentPage?.() ?? 1;
3292
- const total = instance.getPageCount?.() ?? 1;
3293
- if (cur < total) instance.goToPage?.(cur + 1);
3412
+ value: instance.getCurrentPage?.() ?? 1,
3413
+ max: instance.getPageCount?.() ?? 1,
3414
+ execute: (action, page) => {
3415
+ if (action === "prev") {
3416
+ const cur = instance.getCurrentPage?.() ?? 1;
3417
+ if (cur > 1) instance.goToPage?.(cur - 1);
3418
+ } else if (action === "next") {
3419
+ const cur = instance.getCurrentPage?.() ?? 1;
3420
+ const total = instance.getPageCount?.() ?? 1;
3421
+ if (cur < total) instance.goToPage?.(cur + 1);
3422
+ } else if (typeof page === "number") {
3423
+ instance.goToPage?.(page);
3424
+ } else if (typeof action === "number") {
3425
+ instance.goToPage?.(action);
3426
+ }
3294
3427
  }
3295
3428
  }
3296
3429
  );
@@ -3418,7 +3551,7 @@ var OpenDocumentPlugin = class {
3418
3551
  wrapper.style.padding = "48px";
3419
3552
  wrapper.style.minHeight = "100%";
3420
3553
  const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
3421
- wrapper.innerHTML = DOMPurify5.sanitize(bodyHtml, {
3554
+ wrapper.innerHTML = DOMPurify6.sanitize(bodyHtml, {
3422
3555
  ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
3423
3556
  ADD_ATTR: ["style", "colspan", "rowspan"]
3424
3557
  });
@@ -3938,24 +4071,24 @@ var DocPlugin = class {
3938
4071
  html += "</ul>";
3939
4072
  inList = false;
3940
4073
  }
3941
- 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>`;
4074
+ 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>`;
3942
4075
  } else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
3943
4076
  if (!inList) {
3944
4077
  html += '<ul style="margin: 8px 0; padding-left: 24px;">';
3945
4078
  inList = true;
3946
4079
  }
3947
4080
  const bulletText = line.replace(/^[•\-\*]\s*/, "");
3948
- html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify5.sanitize(bulletText)}</li>`;
4081
+ html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify6.sanitize(bulletText)}</li>`;
3949
4082
  } else {
3950
4083
  if (inList) {
3951
4084
  html += "</ul>";
3952
4085
  inList = false;
3953
4086
  }
3954
- html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify5.sanitize(line)}</p>`;
4087
+ html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify6.sanitize(line)}</p>`;
3955
4088
  }
3956
4089
  }
3957
4090
  if (inList) html += "</ul>";
3958
- return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify5.sanitize(filename)})</p>`;
4091
+ return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify6.sanitize(filename)})</p>`;
3959
4092
  }
3960
4093
  };
3961
4094
  function docPlugin() {
@@ -3982,35 +4115,27 @@ var PptPlugin = class {
3982
4115
  group: "navigation",
3983
4116
  execute: () => instance.toggleThumbnails?.()
3984
4117
  },
3985
- {
3986
- id: "page-prev",
3987
- icon: "page-prev",
3988
- label: "Previous Slide",
3989
- type: "button",
3990
- group: "navigation",
3991
- execute: () => {
3992
- const cur = instance.getCurrentPage?.() ?? 1;
3993
- if (cur > 1) instance.goToPage?.(cur - 1);
3994
- }
3995
- },
3996
4118
  {
3997
4119
  id: "page-nav",
3998
4120
  icon: "",
3999
- label: "Slide Number",
4121
+ label: "Slide Navigation",
4000
4122
  type: "page-nav",
4001
4123
  group: "navigation",
4002
- execute: (p) => instance.goToPage?.(Number(p))
4003
- },
4004
- {
4005
- id: "page-next",
4006
- icon: "page-next",
4007
- label: "Next Slide",
4008
- type: "button",
4009
- group: "navigation",
4010
- execute: () => {
4011
- const cur = instance.getCurrentPage?.() ?? 1;
4012
- const total = instance.getPageCount?.() ?? 1;
4013
- if (cur < total) instance.goToPage?.(cur + 1);
4124
+ value: instance.getCurrentPage?.() ?? 1,
4125
+ max: instance.getPageCount?.() ?? 1,
4126
+ execute: (action, page) => {
4127
+ if (action === "prev") {
4128
+ const cur = instance.getCurrentPage?.() ?? 1;
4129
+ if (cur > 1) instance.goToPage?.(cur - 1);
4130
+ } else if (action === "next") {
4131
+ const cur = instance.getCurrentPage?.() ?? 1;
4132
+ const total = instance.getPageCount?.() ?? 1;
4133
+ if (cur < total) instance.goToPage?.(cur + 1);
4134
+ } else if (typeof page === "number") {
4135
+ instance.goToPage?.(page);
4136
+ } else if (typeof action === "number") {
4137
+ instance.goToPage?.(action);
4138
+ }
4014
4139
  }
4015
4140
  },
4016
4141
  {
@@ -4118,10 +4243,10 @@ var PptPlugin = class {
4118
4243
  </div>
4119
4244
  <div style="text-align: center; width: 100%;">
4120
4245
  <h1 style="font-size: ${idx === 1 ? "36px" : "28px"}; color: #1e3a8a; margin: 0 0 24px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; font-weight: 700;">
4121
- ${DOMPurify5.sanitize(s.title || `Slide ${idx}`)}
4246
+ ${DOMPurify6.sanitize(s.title || `Slide ${idx}`)}
4122
4247
  </h1>
4123
4248
  <div style="display: flex; flex-direction: column; gap: 12px; max-width: 80%; margin: 0 auto; text-align: ${idx === 1 ? "center" : "left"};">
4124
- ${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("")}
4249
+ ${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("")}
4125
4250
  </div>
4126
4251
  </div>
4127
4252
  `;