@files-preview-app/preview-file 1.2.2 → 1.2.3
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 +232 -28
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +231 -27
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +233 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +232 -28
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +232 -28
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +231 -27
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +232 -28
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +231 -27
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import DOMPurify2 from 'dompurify';
|
|
2
2
|
import * as docx from 'docx-preview';
|
|
3
3
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
4
4
|
import * as XLSX from 'xlsx';
|
|
@@ -339,12 +339,12 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
339
339
|
return { buffer, metadata };
|
|
340
340
|
}
|
|
341
341
|
function sanitizeHTML(html) {
|
|
342
|
-
return
|
|
342
|
+
return DOMPurify2.sanitize(html, {
|
|
343
343
|
USE_PROFILES: { html: true }
|
|
344
344
|
});
|
|
345
345
|
}
|
|
346
346
|
function sanitizeSVG(svg) {
|
|
347
|
-
return
|
|
347
|
+
return DOMPurify2.sanitize(svg, {
|
|
348
348
|
USE_PROFILES: { svg: true, svgFilters: true }
|
|
349
349
|
});
|
|
350
350
|
}
|
|
@@ -443,6 +443,9 @@ var ICON_THUMBNAILS = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
443
443
|
var ICON_CLOSE = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>`;
|
|
444
444
|
var ICON_FULLSCREEN = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"></path></svg>`;
|
|
445
445
|
var ICON_COPY = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
|
|
446
|
+
var ICON_FAST_FORWARD = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 19 22 12 13 5 13 19"></polygon><polygon points="2 19 11 12 2 5 2 19"></polygon></svg>`;
|
|
447
|
+
var ICON_REWIND = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 19 2 12 11 5 11 19"></polygon><polygon points="22 19 13 12 22 5 22 19"></polygon></svg>`;
|
|
448
|
+
var ICON_SPEED = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>`;
|
|
446
449
|
var ICON_MAP = {
|
|
447
450
|
"zoom-in": ICON_ZOOM_IN,
|
|
448
451
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -463,7 +466,12 @@ var ICON_MAP = {
|
|
|
463
466
|
"page-prev": ICON_PAGE_PREV,
|
|
464
467
|
"page-next": ICON_PAGE_NEXT,
|
|
465
468
|
"chevron-left": ICON_PAGE_PREV,
|
|
466
|
-
"chevron-right": ICON_PAGE_NEXT
|
|
469
|
+
"chevron-right": ICON_PAGE_NEXT,
|
|
470
|
+
"fast-forward": ICON_FAST_FORWARD,
|
|
471
|
+
"forward-10": ICON_FAST_FORWARD,
|
|
472
|
+
"rewind": ICON_REWIND,
|
|
473
|
+
"replay-10": ICON_REWIND,
|
|
474
|
+
"speed": ICON_SPEED
|
|
467
475
|
};
|
|
468
476
|
var ToolbarController = class {
|
|
469
477
|
el;
|
|
@@ -1431,6 +1439,16 @@ var MediaPlugin = class {
|
|
|
1431
1439
|
}
|
|
1432
1440
|
if (instance.play) {
|
|
1433
1441
|
actions.push(
|
|
1442
|
+
{
|
|
1443
|
+
id: "replay-10",
|
|
1444
|
+
icon: "replay-10",
|
|
1445
|
+
label: "Rewind 10s",
|
|
1446
|
+
type: "button",
|
|
1447
|
+
group: "actions",
|
|
1448
|
+
execute: () => {
|
|
1449
|
+
instance.rewind?.(10);
|
|
1450
|
+
}
|
|
1451
|
+
},
|
|
1434
1452
|
{
|
|
1435
1453
|
id: "play",
|
|
1436
1454
|
icon: "play",
|
|
@@ -1450,6 +1468,26 @@ var MediaPlugin = class {
|
|
|
1450
1468
|
execute: () => {
|
|
1451
1469
|
instance.pause?.();
|
|
1452
1470
|
}
|
|
1471
|
+
},
|
|
1472
|
+
{
|
|
1473
|
+
id: "forward-10",
|
|
1474
|
+
icon: "forward-10",
|
|
1475
|
+
label: "Fast Forward 10s",
|
|
1476
|
+
type: "button",
|
|
1477
|
+
group: "actions",
|
|
1478
|
+
execute: () => {
|
|
1479
|
+
instance.fastForward?.(10);
|
|
1480
|
+
}
|
|
1481
|
+
},
|
|
1482
|
+
{
|
|
1483
|
+
id: "speed",
|
|
1484
|
+
icon: "speed",
|
|
1485
|
+
label: "Playback Speed",
|
|
1486
|
+
type: "button",
|
|
1487
|
+
group: "actions",
|
|
1488
|
+
execute: () => {
|
|
1489
|
+
instance.cycleSpeed?.();
|
|
1490
|
+
}
|
|
1453
1491
|
}
|
|
1454
1492
|
);
|
|
1455
1493
|
}
|
|
@@ -1572,6 +1610,28 @@ var MediaPlugin = class {
|
|
|
1572
1610
|
play: mediaElement ? () => mediaElement?.play() : void 0,
|
|
1573
1611
|
pause: mediaElement ? () => mediaElement?.pause() : void 0,
|
|
1574
1612
|
isPlaying: mediaElement ? () => !mediaElement?.paused : void 0,
|
|
1613
|
+
fastForward: mediaElement ? (seconds = 10) => {
|
|
1614
|
+
if (mediaElement) {
|
|
1615
|
+
mediaElement.currentTime = Math.min(mediaElement.duration || Infinity, mediaElement.currentTime + seconds);
|
|
1616
|
+
}
|
|
1617
|
+
} : void 0,
|
|
1618
|
+
rewind: mediaElement ? (seconds = 10) => {
|
|
1619
|
+
if (mediaElement) {
|
|
1620
|
+
mediaElement.currentTime = Math.max(0, mediaElement.currentTime - seconds);
|
|
1621
|
+
}
|
|
1622
|
+
} : void 0,
|
|
1623
|
+
cycleSpeed: mediaElement ? () => {
|
|
1624
|
+
if (mediaElement) {
|
|
1625
|
+
const speeds = [1, 1.25, 1.5, 2, 0.5];
|
|
1626
|
+
const curIndex = speeds.indexOf(mediaElement.playbackRate);
|
|
1627
|
+
const nextIndex = curIndex === -1 ? 0 : (curIndex + 1) % speeds.length;
|
|
1628
|
+
mediaElement.playbackRate = speeds[nextIndex];
|
|
1629
|
+
}
|
|
1630
|
+
} : void 0,
|
|
1631
|
+
setPlaybackRate: mediaElement ? (rate) => {
|
|
1632
|
+
if (mediaElement) mediaElement.playbackRate = rate;
|
|
1633
|
+
} : void 0,
|
|
1634
|
+
getPlaybackRate: mediaElement ? () => mediaElement?.playbackRate ?? 1 : void 0,
|
|
1575
1635
|
download: () => {
|
|
1576
1636
|
const a = document.createElement("a");
|
|
1577
1637
|
a.href = url;
|
|
@@ -1653,16 +1713,35 @@ var DocxPlugin = class {
|
|
|
1653
1713
|
wrapper.style.transformOrigin = "top center";
|
|
1654
1714
|
wrapper.style.transition = "transform 0.2s ease";
|
|
1655
1715
|
wrapper.style.padding = "24px 16px";
|
|
1656
|
-
wrapper.style.maxWidth = "
|
|
1716
|
+
wrapper.style.maxWidth = "950px";
|
|
1657
1717
|
wrapper.style.margin = "0 auto";
|
|
1658
1718
|
wrapper.style.boxSizing = "border-box";
|
|
1659
1719
|
ctx.container.style.overflow = "auto";
|
|
1660
1720
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
1661
1721
|
ctx.container.appendChild(wrapper);
|
|
1722
|
+
const styleOverride = document.createElement("style");
|
|
1723
|
+
styleOverride.textContent = `
|
|
1724
|
+
.fp-docx-wrapper .docx-wrapper {
|
|
1725
|
+
background: transparent !important;
|
|
1726
|
+
padding: 0 !important;
|
|
1727
|
+
display: flex !important;
|
|
1728
|
+
flex-direction: column !important;
|
|
1729
|
+
align-items: center !important;
|
|
1730
|
+
box-sizing: border-box !important;
|
|
1731
|
+
}
|
|
1732
|
+
.fp-docx-wrapper section.docx {
|
|
1733
|
+
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08) !important;
|
|
1734
|
+
border-radius: 4px !important;
|
|
1735
|
+
margin-bottom: 24px !important;
|
|
1736
|
+
background-color: #ffffff !important;
|
|
1737
|
+
}
|
|
1738
|
+
`;
|
|
1739
|
+
ctx.container.appendChild(styleOverride);
|
|
1662
1740
|
let scale = 1;
|
|
1663
1741
|
let renderedSuccessfully = false;
|
|
1742
|
+
const createdBlobUrls = [];
|
|
1664
1743
|
try {
|
|
1665
|
-
await docx.renderAsync(ctx.buffer, wrapper,
|
|
1744
|
+
await docx.renderAsync(ctx.buffer, wrapper, wrapper, {
|
|
1666
1745
|
inWrapper: true,
|
|
1667
1746
|
ignoreWidth: false,
|
|
1668
1747
|
ignoreHeight: false,
|
|
@@ -1671,19 +1750,25 @@ var DocxPlugin = class {
|
|
|
1671
1750
|
breakPages: true,
|
|
1672
1751
|
experimental: true
|
|
1673
1752
|
});
|
|
1753
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1754
|
+
ctx.container.appendChild(wrapper);
|
|
1755
|
+
}
|
|
1674
1756
|
if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
|
|
1675
1757
|
renderedSuccessfully = true;
|
|
1676
1758
|
}
|
|
1677
1759
|
} catch (err) {
|
|
1678
|
-
console.warn("[DocxPlugin] docx-preview failed, triggering native
|
|
1760
|
+
console.warn("[DocxPlugin] docx-preview failed, triggering native fallback:", err);
|
|
1679
1761
|
}
|
|
1680
1762
|
if (!renderedSuccessfully) {
|
|
1681
1763
|
try {
|
|
1682
1764
|
wrapper.innerHTML = "";
|
|
1683
|
-
this.renderXmlFallback(ctx, wrapper);
|
|
1765
|
+
this.renderXmlFallback(ctx, wrapper, createdBlobUrls);
|
|
1766
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1767
|
+
ctx.container.appendChild(wrapper);
|
|
1768
|
+
}
|
|
1684
1769
|
renderedSuccessfully = true;
|
|
1685
1770
|
} catch (fallbackErr) {
|
|
1686
|
-
console.error("[DocxPlugin]
|
|
1771
|
+
console.error("[DocxPlugin] Native fallback failed:", fallbackErr);
|
|
1687
1772
|
wrapper.innerHTML = `
|
|
1688
1773
|
<div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
|
|
1689
1774
|
<div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
|
|
@@ -1691,10 +1776,17 @@ var DocxPlugin = class {
|
|
|
1691
1776
|
<p style="color: #64748b; margin: 0;">Could not parse document content</p>
|
|
1692
1777
|
</div>
|
|
1693
1778
|
`;
|
|
1779
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1780
|
+
ctx.container.appendChild(wrapper);
|
|
1781
|
+
}
|
|
1694
1782
|
}
|
|
1695
1783
|
}
|
|
1696
1784
|
const cleanup = () => {
|
|
1785
|
+
for (const url of createdBlobUrls) {
|
|
1786
|
+
URL.revokeObjectURL(url);
|
|
1787
|
+
}
|
|
1697
1788
|
wrapper.remove();
|
|
1789
|
+
styleOverride.remove();
|
|
1698
1790
|
ctx.container.innerHTML = "";
|
|
1699
1791
|
};
|
|
1700
1792
|
ctx.signal.addEventListener("abort", cleanup);
|
|
@@ -1731,13 +1823,50 @@ var DocxPlugin = class {
|
|
|
1731
1823
|
}
|
|
1732
1824
|
};
|
|
1733
1825
|
}
|
|
1734
|
-
renderXmlFallback(ctx, wrapper) {
|
|
1826
|
+
renderXmlFallback(ctx, wrapper, createdBlobUrls) {
|
|
1827
|
+
const magic = new Uint8Array(ctx.buffer.slice(0, 8));
|
|
1828
|
+
if (magic[0] === 208 && magic[1] === 207 && magic[2] === 17 && magic[3] === 224) {
|
|
1829
|
+
this.renderBinaryDocFallback(ctx, wrapper);
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1735
1832
|
const unzipped = unzipSync(new Uint8Array(ctx.buffer));
|
|
1736
|
-
const
|
|
1833
|
+
const docKey = Object.keys(unzipped).find((k) => k.replace(/^[./\\]+/, "").toLowerCase() === "word/document.xml");
|
|
1834
|
+
const docXmlEntry = docKey ? unzipped[docKey] : void 0;
|
|
1737
1835
|
if (!docXmlEntry) throw new Error("Missing word/document.xml in DOCX package");
|
|
1738
1836
|
const xmlStr = strFromU8(docXmlEntry);
|
|
1739
1837
|
const parser = new DOMParser();
|
|
1740
1838
|
const doc = parser.parseFromString(xmlStr, "application/xml");
|
|
1839
|
+
const imageMap = {};
|
|
1840
|
+
const relsKey = Object.keys(unzipped).find((k) => k.replace(/^[./\\]+/, "").toLowerCase() === "word/_rels/document.xml.rels");
|
|
1841
|
+
if (relsKey && unzipped[relsKey]) {
|
|
1842
|
+
try {
|
|
1843
|
+
const relsXml = strFromU8(unzipped[relsKey]);
|
|
1844
|
+
const relsDoc = parser.parseFromString(relsXml, "application/xml");
|
|
1845
|
+
const relEls = Array.from(relsDoc.getElementsByTagName("Relationship"));
|
|
1846
|
+
for (const rel of relEls) {
|
|
1847
|
+
const rId = rel.getAttribute("Id");
|
|
1848
|
+
const target = rel.getAttribute("Target");
|
|
1849
|
+
if (rId && target) {
|
|
1850
|
+
const cleanTarget = target.replace(/^\.\.\//, "").replace(/^\//, "");
|
|
1851
|
+
const fullTargetKey = Object.keys(unzipped).find((k) => {
|
|
1852
|
+
const norm = k.replace(/^[./\\]+/, "").toLowerCase();
|
|
1853
|
+
return norm === ("word/" + cleanTarget).toLowerCase() || norm === cleanTarget.toLowerCase();
|
|
1854
|
+
});
|
|
1855
|
+
if (fullTargetKey && unzipped[fullTargetKey]) {
|
|
1856
|
+
const bytes = unzipped[fullTargetKey];
|
|
1857
|
+
const ext = cleanTarget.split(".").pop()?.toLowerCase() || "png";
|
|
1858
|
+
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "gif" ? "image/gif" : ext === "svg" ? "image/svg+xml" : "image/png";
|
|
1859
|
+
const blob = new Blob([bytes], { type: mime });
|
|
1860
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
1861
|
+
imageMap[rId] = blobUrl;
|
|
1862
|
+
createdBlobUrls.push(blobUrl);
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
} catch (relsErr) {
|
|
1867
|
+
console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1741
1870
|
const card = document.createElement("div");
|
|
1742
1871
|
card.className = "fp-docx-page-card";
|
|
1743
1872
|
card.style.backgroundColor = "#ffffff";
|
|
@@ -1755,7 +1884,7 @@ var DocxPlugin = class {
|
|
|
1755
1884
|
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
1756
1885
|
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
1757
1886
|
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
1758
|
-
const textContent = this.extractParagraphHtml(child);
|
|
1887
|
+
const textContent = this.extractParagraphHtml(child, imageMap);
|
|
1759
1888
|
if (!textContent.trim()) {
|
|
1760
1889
|
html += '<div style="height: 10px;"></div>';
|
|
1761
1890
|
continue;
|
|
@@ -1781,7 +1910,7 @@ var DocxPlugin = class {
|
|
|
1781
1910
|
html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
1782
1911
|
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
1783
1912
|
cells.forEach((tc) => {
|
|
1784
|
-
const cellText = this.extractParagraphHtml(tc);
|
|
1913
|
+
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
1785
1914
|
html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
1786
1915
|
});
|
|
1787
1916
|
html += "</tr>";
|
|
@@ -1789,34 +1918,63 @@ var DocxPlugin = class {
|
|
|
1789
1918
|
html += "</table>";
|
|
1790
1919
|
}
|
|
1791
1920
|
}
|
|
1792
|
-
card.innerHTML =
|
|
1793
|
-
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "img", "div"],
|
|
1921
|
+
card.innerHTML = DOMPurify2.sanitize(html, {
|
|
1922
|
+
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
|
|
1794
1923
|
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
1795
1924
|
});
|
|
1796
1925
|
wrapper.appendChild(card);
|
|
1797
1926
|
}
|
|
1798
|
-
extractParagraphHtml(pElement) {
|
|
1927
|
+
extractParagraphHtml(pElement, imageMap = {}) {
|
|
1799
1928
|
let result = "";
|
|
1929
|
+
const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
|
|
1930
|
+
for (const drawing of drawings) {
|
|
1931
|
+
const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
|
|
1932
|
+
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
1933
|
+
if (rId && imageMap[rId]) {
|
|
1934
|
+
result += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1800
1937
|
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
1801
|
-
if (runs.length === 0) {
|
|
1802
|
-
return
|
|
1938
|
+
if (runs.length === 0 && !result) {
|
|
1939
|
+
return DOMPurify2.sanitize(pElement.textContent || "");
|
|
1803
1940
|
}
|
|
1804
1941
|
for (const r of runs) {
|
|
1942
|
+
const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
|
|
1943
|
+
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
1944
|
+
if (rId && imageMap[rId]) {
|
|
1945
|
+
result += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
|
|
1946
|
+
}
|
|
1947
|
+
const brs = r.getElementsByTagNameNS("*", "br");
|
|
1948
|
+
for (let i = 0; i < brs.length; i++) {
|
|
1949
|
+
result += "<br/>";
|
|
1950
|
+
}
|
|
1951
|
+
const tabs = r.getElementsByTagNameNS("*", "tab");
|
|
1952
|
+
if (tabs.length > 0) {
|
|
1953
|
+
result += " ";
|
|
1954
|
+
}
|
|
1805
1955
|
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
1806
1956
|
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
1807
1957
|
const isItalic = !!rPr?.getElementsByTagNameNS("*", "i")[0];
|
|
1808
1958
|
const isUnderline = !!rPr?.getElementsByTagNameNS("*", "u")[0];
|
|
1959
|
+
const isStrike = !!rPr?.getElementsByTagNameNS("*", "strike")[0];
|
|
1809
1960
|
const colorNode = rPr?.getElementsByTagNameNS("*", "color")[0];
|
|
1810
1961
|
const colorVal = colorNode?.getAttribute("w:val") || colorNode?.getAttribute("val");
|
|
1962
|
+
const szNode = rPr?.getElementsByTagNameNS("*", "sz")[0];
|
|
1963
|
+
const szVal = szNode?.getAttribute("w:val") || szNode?.getAttribute("val");
|
|
1811
1964
|
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
1812
1965
|
let text = texts.map((t) => t.textContent || "").join("");
|
|
1813
1966
|
if (!text) continue;
|
|
1814
|
-
text =
|
|
1967
|
+
text = DOMPurify2.sanitize(text);
|
|
1815
1968
|
let styles = "";
|
|
1816
1969
|
if (isBold) styles += "font-weight: bold; ";
|
|
1817
1970
|
if (isItalic) styles += "font-style: italic; ";
|
|
1818
1971
|
if (isUnderline) styles += "text-decoration: underline; ";
|
|
1972
|
+
if (isStrike) styles += "text-decoration: line-through; ";
|
|
1819
1973
|
if (colorVal && colorVal !== "auto") styles += `color: #${colorVal}; `;
|
|
1974
|
+
if (szVal) {
|
|
1975
|
+
const pt = parseInt(szVal, 10) / 2;
|
|
1976
|
+
if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
|
|
1977
|
+
}
|
|
1820
1978
|
if (styles) {
|
|
1821
1979
|
result += `<span style="${styles}">${text}</span>`;
|
|
1822
1980
|
} else {
|
|
@@ -1825,6 +1983,52 @@ var DocxPlugin = class {
|
|
|
1825
1983
|
}
|
|
1826
1984
|
return result;
|
|
1827
1985
|
}
|
|
1986
|
+
renderBinaryDocFallback(ctx, wrapper) {
|
|
1987
|
+
const card = document.createElement("div");
|
|
1988
|
+
card.className = "fp-docx-page-card";
|
|
1989
|
+
card.style.backgroundColor = "#ffffff";
|
|
1990
|
+
card.style.borderRadius = "6px";
|
|
1991
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
1992
|
+
card.style.padding = "48px 56px";
|
|
1993
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
1994
|
+
card.style.color = "#1e293b";
|
|
1995
|
+
card.style.lineHeight = "1.6";
|
|
1996
|
+
try {
|
|
1997
|
+
const cfbf = new CfbfReader(ctx.buffer);
|
|
1998
|
+
const wordDocStream = cfbf.readStream("WordDocument");
|
|
1999
|
+
if (wordDocStream && wordDocStream.length >= 512) {
|
|
2000
|
+
const text2 = this.extractReadableStrings(wordDocStream);
|
|
2001
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2.sanitize(text2)}</div>`;
|
|
2002
|
+
wrapper.appendChild(card);
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
2005
|
+
} catch {
|
|
2006
|
+
}
|
|
2007
|
+
const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
|
|
2008
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2.sanitize(text)}</div>`;
|
|
2009
|
+
wrapper.appendChild(card);
|
|
2010
|
+
}
|
|
2011
|
+
extractReadableStrings(bytes) {
|
|
2012
|
+
let result = "";
|
|
2013
|
+
let current = "";
|
|
2014
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
2015
|
+
const b = bytes[i];
|
|
2016
|
+
if (b >= 32 && b <= 126 || b === 10 || b === 13 || b === 9) {
|
|
2017
|
+
current += String.fromCharCode(b);
|
|
2018
|
+
} else if (b === 0 && i + 1 < bytes.length && bytes[i + 1] >= 32 && bytes[i + 1] <= 126) {
|
|
2019
|
+
continue;
|
|
2020
|
+
} else {
|
|
2021
|
+
if (current.trim().length > 3) {
|
|
2022
|
+
result += current.trim() + "\n\n";
|
|
2023
|
+
}
|
|
2024
|
+
current = "";
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
if (current.trim().length > 3) {
|
|
2028
|
+
result += current.trim();
|
|
2029
|
+
}
|
|
2030
|
+
return result;
|
|
2031
|
+
}
|
|
1828
2032
|
};
|
|
1829
2033
|
function docxPlugin() {
|
|
1830
2034
|
return new DocxPlugin();
|
|
@@ -2636,7 +2840,7 @@ var MarkdownPlugin = class {
|
|
|
2636
2840
|
gfm: true,
|
|
2637
2841
|
breaks: true
|
|
2638
2842
|
});
|
|
2639
|
-
const cleanHtml =
|
|
2843
|
+
const cleanHtml = DOMPurify2.sanitize(rawHtml, {
|
|
2640
2844
|
USE_PROFILES: { html: true }
|
|
2641
2845
|
});
|
|
2642
2846
|
const wrapper = document.createElement("div");
|
|
@@ -3351,7 +3555,7 @@ var HtmlPreviewPlugin = class {
|
|
|
3351
3555
|
}
|
|
3352
3556
|
async render(ctx) {
|
|
3353
3557
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
3354
|
-
const sanitized =
|
|
3558
|
+
const sanitized = DOMPurify2.sanitize(rawHtml, {
|
|
3355
3559
|
WHOLE_DOCUMENT: true,
|
|
3356
3560
|
ADD_TAGS: ["style", "link"],
|
|
3357
3561
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -3594,7 +3798,7 @@ var OpenDocumentPlugin = class {
|
|
|
3594
3798
|
wrapper.style.padding = "48px";
|
|
3595
3799
|
wrapper.style.minHeight = "100%";
|
|
3596
3800
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
3597
|
-
wrapper.innerHTML =
|
|
3801
|
+
wrapper.innerHTML = DOMPurify2.sanitize(bodyHtml, {
|
|
3598
3802
|
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
|
|
3599
3803
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
3600
3804
|
});
|
|
@@ -4114,24 +4318,24 @@ var DocPlugin = class {
|
|
|
4114
4318
|
html += "</ul>";
|
|
4115
4319
|
inList = false;
|
|
4116
4320
|
}
|
|
4117
|
-
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${
|
|
4321
|
+
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify2.sanitize(line)}</h2>`;
|
|
4118
4322
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
4119
4323
|
if (!inList) {
|
|
4120
4324
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
4121
4325
|
inList = true;
|
|
4122
4326
|
}
|
|
4123
4327
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
4124
|
-
html += `<li style="margin: 4px 0; line-height: 1.6;">${
|
|
4328
|
+
html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify2.sanitize(bulletText)}</li>`;
|
|
4125
4329
|
} else {
|
|
4126
4330
|
if (inList) {
|
|
4127
4331
|
html += "</ul>";
|
|
4128
4332
|
inList = false;
|
|
4129
4333
|
}
|
|
4130
|
-
html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${
|
|
4334
|
+
html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify2.sanitize(line)}</p>`;
|
|
4131
4335
|
}
|
|
4132
4336
|
}
|
|
4133
4337
|
if (inList) html += "</ul>";
|
|
4134
|
-
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${
|
|
4338
|
+
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify2.sanitize(filename)})</p>`;
|
|
4135
4339
|
}
|
|
4136
4340
|
};
|
|
4137
4341
|
function docPlugin() {
|
|
@@ -4286,10 +4490,10 @@ var PptPlugin = class {
|
|
|
4286
4490
|
</div>
|
|
4287
4491
|
<div style="text-align: center; width: 100%;">
|
|
4288
4492
|
<h1 style="font-size: ${idx === 1 ? "36px" : "28px"}; color: #1e3a8a; margin: 0 0 24px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; font-weight: 700;">
|
|
4289
|
-
${
|
|
4493
|
+
${DOMPurify2.sanitize(s.title || `Slide ${idx}`)}
|
|
4290
4494
|
</h1>
|
|
4291
4495
|
<div style="display: flex; flex-direction: column; gap: 12px; max-width: 80%; margin: 0 auto; text-align: ${idx === 1 ? "center" : "left"};">
|
|
4292
|
-
${s.texts.map((t) => `<div style="font-size: 18px; color: #334155; line-height: 1.5; font-family: -apple-system, BlinkMacSystemFont, sans-serif;">${
|
|
4496
|
+
${s.texts.map((t) => `<div style="font-size: 18px; color: #334155; line-height: 1.5; font-family: -apple-system, BlinkMacSystemFont, sans-serif;">${DOMPurify2.sanitize(t)}</div>`).join("")}
|
|
4293
4497
|
</div>
|
|
4294
4498
|
</div>
|
|
4295
4499
|
`;
|