@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.cjs +252 -127
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +251 -126
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +253 -128
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +252 -127
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +252 -127
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +251 -126
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +252 -127
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +251 -126
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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
|
-
|
|
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
|
-
() =>
|
|
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
|
-
() =>
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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.
|
|
1478
|
-
video.style.
|
|
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
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
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 =
|
|
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 || " "}</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 =
|
|
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
|
|
2811
|
+
label: "Slide Navigation",
|
|
2674
2812
|
type: "page-nav",
|
|
2675
2813
|
group: "navigation",
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
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 =
|
|
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
|
|
3457
|
+
label: "Slide Navigation",
|
|
3328
3458
|
type: "page-nav",
|
|
3329
3459
|
group: "navigation",
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
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 =
|
|
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;">${
|
|
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;">${
|
|
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;">${
|
|
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 ${
|
|
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
|
|
4169
|
+
label: "Slide Navigation",
|
|
4048
4170
|
type: "page-nav",
|
|
4049
4171
|
group: "navigation",
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
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
|
-
${
|
|
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;">${
|
|
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
|
`;
|