@files-preview-app/preview-file 1.2.2 → 1.2.4
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 +568 -113
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +565 -111
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +569 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +566 -112
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +568 -113
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +565 -111
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +568 -113
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +565 -111
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var DOMPurify2 = require('dompurify');
|
|
4
4
|
var docx = require('docx-preview');
|
|
5
5
|
var fflate = require('fflate');
|
|
6
6
|
var XLSX = require('xlsx');
|
|
@@ -11,7 +11,7 @@ var THREE = require('three');
|
|
|
11
11
|
var STLLoader_js = require('three/examples/jsm/loaders/STLLoader.js');
|
|
12
12
|
var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
|
|
13
13
|
var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
|
|
14
|
-
var
|
|
14
|
+
var RTFJS = require('rtf.js/dist/RTFJS.bundle.js');
|
|
15
15
|
|
|
16
16
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
17
|
|
|
@@ -33,11 +33,12 @@ function _interopNamespace(e) {
|
|
|
33
33
|
return Object.freeze(n);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
var
|
|
36
|
+
var DOMPurify2__default = /*#__PURE__*/_interopDefault(DOMPurify2);
|
|
37
37
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
38
38
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
39
39
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
40
40
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
41
|
+
var RTFJS__namespace = /*#__PURE__*/_interopNamespace(RTFJS);
|
|
41
42
|
|
|
42
43
|
// ../core/dist/index.js
|
|
43
44
|
var EventEmitter = class {
|
|
@@ -293,6 +294,39 @@ function detectOoxmlType(buffer) {
|
|
|
293
294
|
}
|
|
294
295
|
return "application/zip";
|
|
295
296
|
}
|
|
297
|
+
function detectCfbfType(buffer) {
|
|
298
|
+
const bytes = new Uint8Array(buffer);
|
|
299
|
+
const hasUtf16le = (str) => {
|
|
300
|
+
const target = new Uint8Array(str.length * 2);
|
|
301
|
+
for (let i = 0; i < str.length; i++) {
|
|
302
|
+
target[i * 2] = str.charCodeAt(i);
|
|
303
|
+
target[i * 2 + 1] = 0;
|
|
304
|
+
}
|
|
305
|
+
const targetLen = target.length;
|
|
306
|
+
const max = bytes.length - targetLen;
|
|
307
|
+
for (let i = 0; i <= max; i++) {
|
|
308
|
+
let match = true;
|
|
309
|
+
for (let j = 0; j < targetLen; j++) {
|
|
310
|
+
if (bytes[i + j] !== target[j]) {
|
|
311
|
+
match = false;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (match) return true;
|
|
316
|
+
}
|
|
317
|
+
return false;
|
|
318
|
+
};
|
|
319
|
+
if (hasUtf16le("PowerPoint Document")) {
|
|
320
|
+
return { mime: "application/vnd.ms-powerpoint", extension: ".ppt" };
|
|
321
|
+
}
|
|
322
|
+
if (hasUtf16le("WordDocument")) {
|
|
323
|
+
return { mime: "application/msword", extension: ".doc" };
|
|
324
|
+
}
|
|
325
|
+
if (hasUtf16le("Workbook") || hasUtf16le("Book")) {
|
|
326
|
+
return { mime: "application/vnd.ms-excel", extension: ".xls" };
|
|
327
|
+
}
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
296
330
|
function extractExtension(nameOrUrl) {
|
|
297
331
|
try {
|
|
298
332
|
const url = new URL(nameOrUrl);
|
|
@@ -357,6 +391,18 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
357
391
|
} else {
|
|
358
392
|
metadata.mimeType = metadata.mimeType ?? magicMime;
|
|
359
393
|
}
|
|
394
|
+
} else if (magicMime === "application/x-cfbf") {
|
|
395
|
+
if (metadata.extension) {
|
|
396
|
+
metadata.mimeType = mimeFromExtension(metadata.extension) ?? magicMime;
|
|
397
|
+
} else {
|
|
398
|
+
const cfbf = detectCfbfType(buffer);
|
|
399
|
+
if (cfbf) {
|
|
400
|
+
metadata.mimeType = cfbf.mime;
|
|
401
|
+
metadata.extension = cfbf.extension;
|
|
402
|
+
} else {
|
|
403
|
+
metadata.mimeType = magicMime;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
360
406
|
} else {
|
|
361
407
|
metadata.mimeType = magicMime;
|
|
362
408
|
}
|
|
@@ -367,12 +413,12 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
367
413
|
return { buffer, metadata };
|
|
368
414
|
}
|
|
369
415
|
function sanitizeHTML(html) {
|
|
370
|
-
return
|
|
416
|
+
return DOMPurify2__default.default.sanitize(html, {
|
|
371
417
|
USE_PROFILES: { html: true }
|
|
372
418
|
});
|
|
373
419
|
}
|
|
374
420
|
function sanitizeSVG(svg) {
|
|
375
|
-
return
|
|
421
|
+
return DOMPurify2__default.default.sanitize(svg, {
|
|
376
422
|
USE_PROFILES: { svg: true, svgFilters: true }
|
|
377
423
|
});
|
|
378
424
|
}
|
|
@@ -471,6 +517,9 @@ var ICON_THUMBNAILS = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
471
517
|
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>`;
|
|
472
518
|
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>`;
|
|
473
519
|
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>`;
|
|
520
|
+
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>`;
|
|
521
|
+
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>`;
|
|
522
|
+
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>`;
|
|
474
523
|
var ICON_MAP = {
|
|
475
524
|
"zoom-in": ICON_ZOOM_IN,
|
|
476
525
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -491,7 +540,12 @@ var ICON_MAP = {
|
|
|
491
540
|
"page-prev": ICON_PAGE_PREV,
|
|
492
541
|
"page-next": ICON_PAGE_NEXT,
|
|
493
542
|
"chevron-left": ICON_PAGE_PREV,
|
|
494
|
-
"chevron-right": ICON_PAGE_NEXT
|
|
543
|
+
"chevron-right": ICON_PAGE_NEXT,
|
|
544
|
+
"fast-forward": ICON_FAST_FORWARD,
|
|
545
|
+
"forward-10": ICON_FAST_FORWARD,
|
|
546
|
+
"rewind": ICON_REWIND,
|
|
547
|
+
"replay-10": ICON_REWIND,
|
|
548
|
+
"speed": ICON_SPEED
|
|
495
549
|
};
|
|
496
550
|
var ToolbarController = class {
|
|
497
551
|
el;
|
|
@@ -1459,6 +1513,16 @@ var MediaPlugin = class {
|
|
|
1459
1513
|
}
|
|
1460
1514
|
if (instance.play) {
|
|
1461
1515
|
actions.push(
|
|
1516
|
+
{
|
|
1517
|
+
id: "replay-10",
|
|
1518
|
+
icon: "replay-10",
|
|
1519
|
+
label: "Rewind 10s",
|
|
1520
|
+
type: "button",
|
|
1521
|
+
group: "actions",
|
|
1522
|
+
execute: () => {
|
|
1523
|
+
instance.rewind?.(10);
|
|
1524
|
+
}
|
|
1525
|
+
},
|
|
1462
1526
|
{
|
|
1463
1527
|
id: "play",
|
|
1464
1528
|
icon: "play",
|
|
@@ -1478,6 +1542,26 @@ var MediaPlugin = class {
|
|
|
1478
1542
|
execute: () => {
|
|
1479
1543
|
instance.pause?.();
|
|
1480
1544
|
}
|
|
1545
|
+
},
|
|
1546
|
+
{
|
|
1547
|
+
id: "forward-10",
|
|
1548
|
+
icon: "forward-10",
|
|
1549
|
+
label: "Fast Forward 10s",
|
|
1550
|
+
type: "button",
|
|
1551
|
+
group: "actions",
|
|
1552
|
+
execute: () => {
|
|
1553
|
+
instance.fastForward?.(10);
|
|
1554
|
+
}
|
|
1555
|
+
},
|
|
1556
|
+
{
|
|
1557
|
+
id: "speed",
|
|
1558
|
+
icon: "speed",
|
|
1559
|
+
label: "Playback Speed",
|
|
1560
|
+
type: "button",
|
|
1561
|
+
group: "actions",
|
|
1562
|
+
execute: () => {
|
|
1563
|
+
instance.cycleSpeed?.();
|
|
1564
|
+
}
|
|
1481
1565
|
}
|
|
1482
1566
|
);
|
|
1483
1567
|
}
|
|
@@ -1600,6 +1684,28 @@ var MediaPlugin = class {
|
|
|
1600
1684
|
play: mediaElement ? () => mediaElement?.play() : void 0,
|
|
1601
1685
|
pause: mediaElement ? () => mediaElement?.pause() : void 0,
|
|
1602
1686
|
isPlaying: mediaElement ? () => !mediaElement?.paused : void 0,
|
|
1687
|
+
fastForward: mediaElement ? (seconds = 10) => {
|
|
1688
|
+
if (mediaElement) {
|
|
1689
|
+
mediaElement.currentTime = Math.min(mediaElement.duration || Infinity, mediaElement.currentTime + seconds);
|
|
1690
|
+
}
|
|
1691
|
+
} : void 0,
|
|
1692
|
+
rewind: mediaElement ? (seconds = 10) => {
|
|
1693
|
+
if (mediaElement) {
|
|
1694
|
+
mediaElement.currentTime = Math.max(0, mediaElement.currentTime - seconds);
|
|
1695
|
+
}
|
|
1696
|
+
} : void 0,
|
|
1697
|
+
cycleSpeed: mediaElement ? () => {
|
|
1698
|
+
if (mediaElement) {
|
|
1699
|
+
const speeds = [1, 1.25, 1.5, 2, 0.5];
|
|
1700
|
+
const curIndex = speeds.indexOf(mediaElement.playbackRate);
|
|
1701
|
+
const nextIndex = curIndex === -1 ? 0 : (curIndex + 1) % speeds.length;
|
|
1702
|
+
mediaElement.playbackRate = speeds[nextIndex];
|
|
1703
|
+
}
|
|
1704
|
+
} : void 0,
|
|
1705
|
+
setPlaybackRate: mediaElement ? (rate) => {
|
|
1706
|
+
if (mediaElement) mediaElement.playbackRate = rate;
|
|
1707
|
+
} : void 0,
|
|
1708
|
+
getPlaybackRate: mediaElement ? () => mediaElement?.playbackRate ?? 1 : void 0,
|
|
1603
1709
|
download: () => {
|
|
1604
1710
|
const a = document.createElement("a");
|
|
1605
1711
|
a.href = url;
|
|
@@ -1629,7 +1735,10 @@ var DocxPlugin = class {
|
|
|
1629
1735
|
supports(file) {
|
|
1630
1736
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1631
1737
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1632
|
-
|
|
1738
|
+
if (ext) {
|
|
1739
|
+
return this.extensions.includes(ext);
|
|
1740
|
+
}
|
|
1741
|
+
return this.mimeTypes.includes(mime || "");
|
|
1633
1742
|
}
|
|
1634
1743
|
getToolbarActions(instance) {
|
|
1635
1744
|
return [
|
|
@@ -1681,16 +1790,35 @@ var DocxPlugin = class {
|
|
|
1681
1790
|
wrapper.style.transformOrigin = "top center";
|
|
1682
1791
|
wrapper.style.transition = "transform 0.2s ease";
|
|
1683
1792
|
wrapper.style.padding = "24px 16px";
|
|
1684
|
-
wrapper.style.maxWidth = "
|
|
1793
|
+
wrapper.style.maxWidth = "950px";
|
|
1685
1794
|
wrapper.style.margin = "0 auto";
|
|
1686
1795
|
wrapper.style.boxSizing = "border-box";
|
|
1687
1796
|
ctx.container.style.overflow = "auto";
|
|
1688
1797
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
1689
1798
|
ctx.container.appendChild(wrapper);
|
|
1799
|
+
const styleOverride = document.createElement("style");
|
|
1800
|
+
styleOverride.textContent = `
|
|
1801
|
+
.fp-docx-wrapper .docx-wrapper {
|
|
1802
|
+
background: transparent !important;
|
|
1803
|
+
padding: 0 !important;
|
|
1804
|
+
display: flex !important;
|
|
1805
|
+
flex-direction: column !important;
|
|
1806
|
+
align-items: center !important;
|
|
1807
|
+
box-sizing: border-box !important;
|
|
1808
|
+
}
|
|
1809
|
+
.fp-docx-wrapper section.docx {
|
|
1810
|
+
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08) !important;
|
|
1811
|
+
border-radius: 4px !important;
|
|
1812
|
+
margin-bottom: 24px !important;
|
|
1813
|
+
background-color: #ffffff !important;
|
|
1814
|
+
}
|
|
1815
|
+
`;
|
|
1816
|
+
ctx.container.appendChild(styleOverride);
|
|
1690
1817
|
let scale = 1;
|
|
1691
1818
|
let renderedSuccessfully = false;
|
|
1819
|
+
const createdBlobUrls = [];
|
|
1692
1820
|
try {
|
|
1693
|
-
await docx__namespace.renderAsync(ctx.buffer, wrapper,
|
|
1821
|
+
await docx__namespace.renderAsync(ctx.buffer, wrapper, wrapper, {
|
|
1694
1822
|
inWrapper: true,
|
|
1695
1823
|
ignoreWidth: false,
|
|
1696
1824
|
ignoreHeight: false,
|
|
@@ -1699,19 +1827,25 @@ var DocxPlugin = class {
|
|
|
1699
1827
|
breakPages: true,
|
|
1700
1828
|
experimental: true
|
|
1701
1829
|
});
|
|
1830
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1831
|
+
ctx.container.appendChild(wrapper);
|
|
1832
|
+
}
|
|
1702
1833
|
if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
|
|
1703
1834
|
renderedSuccessfully = true;
|
|
1704
1835
|
}
|
|
1705
1836
|
} catch (err) {
|
|
1706
|
-
console.warn("[DocxPlugin] docx-preview failed, triggering native
|
|
1837
|
+
console.warn("[DocxPlugin] docx-preview failed, triggering native fallback:", err);
|
|
1707
1838
|
}
|
|
1708
1839
|
if (!renderedSuccessfully) {
|
|
1709
1840
|
try {
|
|
1710
1841
|
wrapper.innerHTML = "";
|
|
1711
|
-
this.renderXmlFallback(ctx, wrapper);
|
|
1842
|
+
this.renderXmlFallback(ctx, wrapper, createdBlobUrls);
|
|
1843
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1844
|
+
ctx.container.appendChild(wrapper);
|
|
1845
|
+
}
|
|
1712
1846
|
renderedSuccessfully = true;
|
|
1713
1847
|
} catch (fallbackErr) {
|
|
1714
|
-
console.error("[DocxPlugin]
|
|
1848
|
+
console.error("[DocxPlugin] Native fallback failed:", fallbackErr);
|
|
1715
1849
|
wrapper.innerHTML = `
|
|
1716
1850
|
<div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
|
|
1717
1851
|
<div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
|
|
@@ -1719,10 +1853,17 @@ var DocxPlugin = class {
|
|
|
1719
1853
|
<p style="color: #64748b; margin: 0;">Could not parse document content</p>
|
|
1720
1854
|
</div>
|
|
1721
1855
|
`;
|
|
1856
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1857
|
+
ctx.container.appendChild(wrapper);
|
|
1858
|
+
}
|
|
1722
1859
|
}
|
|
1723
1860
|
}
|
|
1724
1861
|
const cleanup = () => {
|
|
1862
|
+
for (const url of createdBlobUrls) {
|
|
1863
|
+
URL.revokeObjectURL(url);
|
|
1864
|
+
}
|
|
1725
1865
|
wrapper.remove();
|
|
1866
|
+
styleOverride.remove();
|
|
1726
1867
|
ctx.container.innerHTML = "";
|
|
1727
1868
|
};
|
|
1728
1869
|
ctx.signal.addEventListener("abort", cleanup);
|
|
@@ -1759,13 +1900,50 @@ var DocxPlugin = class {
|
|
|
1759
1900
|
}
|
|
1760
1901
|
};
|
|
1761
1902
|
}
|
|
1762
|
-
renderXmlFallback(ctx, wrapper) {
|
|
1903
|
+
renderXmlFallback(ctx, wrapper, createdBlobUrls) {
|
|
1904
|
+
const magic = new Uint8Array(ctx.buffer.slice(0, 8));
|
|
1905
|
+
if (magic[0] === 208 && magic[1] === 207 && magic[2] === 17 && magic[3] === 224) {
|
|
1906
|
+
this.renderBinaryDocFallback(ctx, wrapper);
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1763
1909
|
const unzipped = fflate.unzipSync(new Uint8Array(ctx.buffer));
|
|
1764
|
-
const
|
|
1910
|
+
const docKey = Object.keys(unzipped).find((k) => k.replace(/^[./\\]+/, "").toLowerCase() === "word/document.xml");
|
|
1911
|
+
const docXmlEntry = docKey ? unzipped[docKey] : void 0;
|
|
1765
1912
|
if (!docXmlEntry) throw new Error("Missing word/document.xml in DOCX package");
|
|
1766
1913
|
const xmlStr = fflate.strFromU8(docXmlEntry);
|
|
1767
1914
|
const parser = new DOMParser();
|
|
1768
1915
|
const doc = parser.parseFromString(xmlStr, "application/xml");
|
|
1916
|
+
const imageMap = {};
|
|
1917
|
+
const relsKey = Object.keys(unzipped).find((k) => k.replace(/^[./\\]+/, "").toLowerCase() === "word/_rels/document.xml.rels");
|
|
1918
|
+
if (relsKey && unzipped[relsKey]) {
|
|
1919
|
+
try {
|
|
1920
|
+
const relsXml = fflate.strFromU8(unzipped[relsKey]);
|
|
1921
|
+
const relsDoc = parser.parseFromString(relsXml, "application/xml");
|
|
1922
|
+
const relEls = Array.from(relsDoc.getElementsByTagName("Relationship"));
|
|
1923
|
+
for (const rel of relEls) {
|
|
1924
|
+
const rId = rel.getAttribute("Id");
|
|
1925
|
+
const target = rel.getAttribute("Target");
|
|
1926
|
+
if (rId && target) {
|
|
1927
|
+
const cleanTarget = target.replace(/^\.\.\//, "").replace(/^\//, "");
|
|
1928
|
+
const fullTargetKey = Object.keys(unzipped).find((k) => {
|
|
1929
|
+
const norm = k.replace(/^[./\\]+/, "").toLowerCase();
|
|
1930
|
+
return norm === ("word/" + cleanTarget).toLowerCase() || norm === cleanTarget.toLowerCase();
|
|
1931
|
+
});
|
|
1932
|
+
if (fullTargetKey && unzipped[fullTargetKey]) {
|
|
1933
|
+
const bytes = unzipped[fullTargetKey];
|
|
1934
|
+
const ext = cleanTarget.split(".").pop()?.toLowerCase() || "png";
|
|
1935
|
+
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "gif" ? "image/gif" : ext === "svg" ? "image/svg+xml" : "image/png";
|
|
1936
|
+
const blob = new Blob([bytes], { type: mime });
|
|
1937
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
1938
|
+
imageMap[rId] = blobUrl;
|
|
1939
|
+
createdBlobUrls.push(blobUrl);
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
} catch (relsErr) {
|
|
1944
|
+
console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1769
1947
|
const card = document.createElement("div");
|
|
1770
1948
|
card.className = "fp-docx-page-card";
|
|
1771
1949
|
card.style.backgroundColor = "#ffffff";
|
|
@@ -1783,7 +1961,7 @@ var DocxPlugin = class {
|
|
|
1783
1961
|
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
1784
1962
|
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
1785
1963
|
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
1786
|
-
const textContent = this.extractParagraphHtml(child);
|
|
1964
|
+
const textContent = this.extractParagraphHtml(child, imageMap);
|
|
1787
1965
|
if (!textContent.trim()) {
|
|
1788
1966
|
html += '<div style="height: 10px;"></div>';
|
|
1789
1967
|
continue;
|
|
@@ -1809,7 +1987,7 @@ var DocxPlugin = class {
|
|
|
1809
1987
|
html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
1810
1988
|
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
1811
1989
|
cells.forEach((tc) => {
|
|
1812
|
-
const cellText = this.extractParagraphHtml(tc);
|
|
1990
|
+
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
1813
1991
|
html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
1814
1992
|
});
|
|
1815
1993
|
html += "</tr>";
|
|
@@ -1817,34 +1995,63 @@ var DocxPlugin = class {
|
|
|
1817
1995
|
html += "</table>";
|
|
1818
1996
|
}
|
|
1819
1997
|
}
|
|
1820
|
-
card.innerHTML =
|
|
1821
|
-
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "img", "div"],
|
|
1998
|
+
card.innerHTML = DOMPurify2__default.default.sanitize(html, {
|
|
1999
|
+
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
|
|
1822
2000
|
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
1823
2001
|
});
|
|
1824
2002
|
wrapper.appendChild(card);
|
|
1825
2003
|
}
|
|
1826
|
-
extractParagraphHtml(pElement) {
|
|
2004
|
+
extractParagraphHtml(pElement, imageMap = {}) {
|
|
1827
2005
|
let result = "";
|
|
2006
|
+
const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
|
|
2007
|
+
for (const drawing of drawings) {
|
|
2008
|
+
const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
|
|
2009
|
+
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2010
|
+
if (rId && imageMap[rId]) {
|
|
2011
|
+
result += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
1828
2014
|
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
1829
|
-
if (runs.length === 0) {
|
|
1830
|
-
return
|
|
2015
|
+
if (runs.length === 0 && !result) {
|
|
2016
|
+
return DOMPurify2__default.default.sanitize(pElement.textContent || "");
|
|
1831
2017
|
}
|
|
1832
2018
|
for (const r of runs) {
|
|
2019
|
+
const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
|
|
2020
|
+
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
2021
|
+
if (rId && imageMap[rId]) {
|
|
2022
|
+
result += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
|
|
2023
|
+
}
|
|
2024
|
+
const brs = r.getElementsByTagNameNS("*", "br");
|
|
2025
|
+
for (let i = 0; i < brs.length; i++) {
|
|
2026
|
+
result += "<br/>";
|
|
2027
|
+
}
|
|
2028
|
+
const tabs = r.getElementsByTagNameNS("*", "tab");
|
|
2029
|
+
if (tabs.length > 0) {
|
|
2030
|
+
result += " ";
|
|
2031
|
+
}
|
|
1833
2032
|
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
1834
2033
|
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
1835
2034
|
const isItalic = !!rPr?.getElementsByTagNameNS("*", "i")[0];
|
|
1836
2035
|
const isUnderline = !!rPr?.getElementsByTagNameNS("*", "u")[0];
|
|
2036
|
+
const isStrike = !!rPr?.getElementsByTagNameNS("*", "strike")[0];
|
|
1837
2037
|
const colorNode = rPr?.getElementsByTagNameNS("*", "color")[0];
|
|
1838
2038
|
const colorVal = colorNode?.getAttribute("w:val") || colorNode?.getAttribute("val");
|
|
2039
|
+
const szNode = rPr?.getElementsByTagNameNS("*", "sz")[0];
|
|
2040
|
+
const szVal = szNode?.getAttribute("w:val") || szNode?.getAttribute("val");
|
|
1839
2041
|
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
1840
2042
|
let text = texts.map((t) => t.textContent || "").join("");
|
|
1841
2043
|
if (!text) continue;
|
|
1842
|
-
text =
|
|
2044
|
+
text = DOMPurify2__default.default.sanitize(text);
|
|
1843
2045
|
let styles = "";
|
|
1844
2046
|
if (isBold) styles += "font-weight: bold; ";
|
|
1845
2047
|
if (isItalic) styles += "font-style: italic; ";
|
|
1846
2048
|
if (isUnderline) styles += "text-decoration: underline; ";
|
|
2049
|
+
if (isStrike) styles += "text-decoration: line-through; ";
|
|
1847
2050
|
if (colorVal && colorVal !== "auto") styles += `color: #${colorVal}; `;
|
|
2051
|
+
if (szVal) {
|
|
2052
|
+
const pt = parseInt(szVal, 10) / 2;
|
|
2053
|
+
if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
|
|
2054
|
+
}
|
|
1848
2055
|
if (styles) {
|
|
1849
2056
|
result += `<span style="${styles}">${text}</span>`;
|
|
1850
2057
|
} else {
|
|
@@ -1853,6 +2060,52 @@ var DocxPlugin = class {
|
|
|
1853
2060
|
}
|
|
1854
2061
|
return result;
|
|
1855
2062
|
}
|
|
2063
|
+
renderBinaryDocFallback(ctx, wrapper) {
|
|
2064
|
+
const card = document.createElement("div");
|
|
2065
|
+
card.className = "fp-docx-page-card";
|
|
2066
|
+
card.style.backgroundColor = "#ffffff";
|
|
2067
|
+
card.style.borderRadius = "6px";
|
|
2068
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
2069
|
+
card.style.padding = "48px 56px";
|
|
2070
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
2071
|
+
card.style.color = "#1e293b";
|
|
2072
|
+
card.style.lineHeight = "1.6";
|
|
2073
|
+
try {
|
|
2074
|
+
const cfbf = new CfbfReader(ctx.buffer);
|
|
2075
|
+
const wordDocStream = cfbf.readStream("WordDocument");
|
|
2076
|
+
if (wordDocStream && wordDocStream.length >= 512) {
|
|
2077
|
+
const text2 = this.extractReadableStrings(wordDocStream);
|
|
2078
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2__default.default.sanitize(text2)}</div>`;
|
|
2079
|
+
wrapper.appendChild(card);
|
|
2080
|
+
return;
|
|
2081
|
+
}
|
|
2082
|
+
} catch {
|
|
2083
|
+
}
|
|
2084
|
+
const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
|
|
2085
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2__default.default.sanitize(text)}</div>`;
|
|
2086
|
+
wrapper.appendChild(card);
|
|
2087
|
+
}
|
|
2088
|
+
extractReadableStrings(bytes) {
|
|
2089
|
+
let result = "";
|
|
2090
|
+
let current = "";
|
|
2091
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
2092
|
+
const b = bytes[i];
|
|
2093
|
+
if (b >= 32 && b <= 126 || b === 10 || b === 13 || b === 9) {
|
|
2094
|
+
current += String.fromCharCode(b);
|
|
2095
|
+
} else if (b === 0 && i + 1 < bytes.length && bytes[i + 1] >= 32 && bytes[i + 1] <= 126) {
|
|
2096
|
+
continue;
|
|
2097
|
+
} else {
|
|
2098
|
+
if (current.trim().length > 3) {
|
|
2099
|
+
result += current.trim() + "\n\n";
|
|
2100
|
+
}
|
|
2101
|
+
current = "";
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
if (current.trim().length > 3) {
|
|
2105
|
+
result += current.trim();
|
|
2106
|
+
}
|
|
2107
|
+
return result;
|
|
2108
|
+
}
|
|
1856
2109
|
};
|
|
1857
2110
|
function docxPlugin() {
|
|
1858
2111
|
return new DocxPlugin();
|
|
@@ -1874,7 +2127,10 @@ var ExcelPlugin = class {
|
|
|
1874
2127
|
supports(file) {
|
|
1875
2128
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1876
2129
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1877
|
-
|
|
2130
|
+
if (ext) {
|
|
2131
|
+
return this.extensions.includes(ext);
|
|
2132
|
+
}
|
|
2133
|
+
return this.mimeTypes.includes(mime || "");
|
|
1878
2134
|
}
|
|
1879
2135
|
getToolbarActions(instance) {
|
|
1880
2136
|
return [
|
|
@@ -2664,7 +2920,7 @@ var MarkdownPlugin = class {
|
|
|
2664
2920
|
gfm: true,
|
|
2665
2921
|
breaks: true
|
|
2666
2922
|
});
|
|
2667
|
-
const cleanHtml =
|
|
2923
|
+
const cleanHtml = DOMPurify2__default.default.sanitize(rawHtml, {
|
|
2668
2924
|
USE_PROFILES: { html: true }
|
|
2669
2925
|
});
|
|
2670
2926
|
const wrapper = document.createElement("div");
|
|
@@ -2816,7 +3072,10 @@ var PptxPlugin = class {
|
|
|
2816
3072
|
supports(file) {
|
|
2817
3073
|
const ext = file.metadata.extension?.toLowerCase();
|
|
2818
3074
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
2819
|
-
|
|
3075
|
+
if (ext) {
|
|
3076
|
+
return this.extensions.includes(ext);
|
|
3077
|
+
}
|
|
3078
|
+
return this.mimeTypes.includes(mime || "");
|
|
2820
3079
|
}
|
|
2821
3080
|
getToolbarActions(instance) {
|
|
2822
3081
|
return [
|
|
@@ -3261,7 +3520,10 @@ var RtfPlugin = class {
|
|
|
3261
3520
|
ctx.container.appendChild(wrapper);
|
|
3262
3521
|
let scale = 1;
|
|
3263
3522
|
try {
|
|
3264
|
-
|
|
3523
|
+
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3524
|
+
RTFJS__namespace.loggingEnabled(false);
|
|
3525
|
+
}
|
|
3526
|
+
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3265
3527
|
const htmlElements = await doc.render();
|
|
3266
3528
|
for (const el of htmlElements) {
|
|
3267
3529
|
wrapper.appendChild(el);
|
|
@@ -3379,7 +3641,7 @@ var HtmlPreviewPlugin = class {
|
|
|
3379
3641
|
}
|
|
3380
3642
|
async render(ctx) {
|
|
3381
3643
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
3382
|
-
const sanitized =
|
|
3644
|
+
const sanitized = DOMPurify2__default.default.sanitize(rawHtml, {
|
|
3383
3645
|
WHOLE_DOCUMENT: true,
|
|
3384
3646
|
ADD_TAGS: ["style", "link"],
|
|
3385
3647
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -3459,7 +3721,10 @@ var OpenDocumentPlugin = class {
|
|
|
3459
3721
|
supports(file) {
|
|
3460
3722
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3461
3723
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3462
|
-
|
|
3724
|
+
if (ext) {
|
|
3725
|
+
return this.extensions.includes(ext);
|
|
3726
|
+
}
|
|
3727
|
+
return this.mimeTypes.includes(mime || "");
|
|
3463
3728
|
}
|
|
3464
3729
|
getToolbarActions(instance) {
|
|
3465
3730
|
const isPresentation = instance.isPresentation;
|
|
@@ -3622,7 +3887,7 @@ var OpenDocumentPlugin = class {
|
|
|
3622
3887
|
wrapper.style.padding = "48px";
|
|
3623
3888
|
wrapper.style.minHeight = "100%";
|
|
3624
3889
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
3625
|
-
wrapper.innerHTML =
|
|
3890
|
+
wrapper.innerHTML = DOMPurify2__default.default.sanitize(bodyHtml, {
|
|
3626
3891
|
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
|
|
3627
3892
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
3628
3893
|
});
|
|
@@ -3874,7 +4139,10 @@ var DocPlugin = class {
|
|
|
3874
4139
|
supports(file) {
|
|
3875
4140
|
const ext = file.metadata.extension?.toLowerCase();
|
|
3876
4141
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
3877
|
-
|
|
4142
|
+
if (ext) {
|
|
4143
|
+
return this.extensions.includes(ext);
|
|
4144
|
+
}
|
|
4145
|
+
return this.mimeTypes.includes(mime || "");
|
|
3878
4146
|
}
|
|
3879
4147
|
getToolbarActions(instance) {
|
|
3880
4148
|
return [
|
|
@@ -4097,22 +4365,22 @@ var DocPlugin = class {
|
|
|
4097
4365
|
* Scans a byte array for continuous sequences of readable characters (ANSI and UTF-16LE)
|
|
4098
4366
|
*/
|
|
4099
4367
|
extractStringsFromBytes(bytes) {
|
|
4100
|
-
const
|
|
4101
|
-
const
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4368
|
+
const rawAnsi = new TextDecoder("latin1").decode(bytes);
|
|
4369
|
+
const rawUtf16 = new TextDecoder("utf-16le", { fatal: false }).decode(bytes);
|
|
4370
|
+
const ansiRuns = rawAnsi.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4371
|
+
const utf16Runs = rawUtf16.match(/[\x20-\x7E\t\r\n]{4,}/g) || [];
|
|
4372
|
+
const candidateLines = [];
|
|
4373
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4374
|
+
for (const run of [...ansiRuns, ...utf16Runs]) {
|
|
4375
|
+
const trimmed = run.trim();
|
|
4376
|
+
if (trimmed.length >= 4 && /[a-zA-Z]/.test(trimmed) && !seen.has(trimmed)) {
|
|
4377
|
+
if (!trimmed.includes("Normal.dot") && !trimmed.includes("Microsoft Word") && !trimmed.includes("Times New Roman") && !trimmed.startsWith("\xD0\xCF\xE0\xA1\xB1\xE1") && !/^[\W_0-9]+$/.test(trimmed)) {
|
|
4378
|
+
seen.add(trimmed);
|
|
4379
|
+
candidateLines.push(trimmed);
|
|
4380
|
+
}
|
|
4113
4381
|
}
|
|
4114
4382
|
}
|
|
4115
|
-
return
|
|
4383
|
+
return candidateLines.join("\n\n");
|
|
4116
4384
|
}
|
|
4117
4385
|
heuristicTextExtraction(buffer) {
|
|
4118
4386
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
@@ -4142,24 +4410,24 @@ var DocPlugin = class {
|
|
|
4142
4410
|
html += "</ul>";
|
|
4143
4411
|
inList = false;
|
|
4144
4412
|
}
|
|
4145
|
-
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${
|
|
4413
|
+
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${DOMPurify2__default.default.sanitize(line)}</h2>`;
|
|
4146
4414
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
4147
4415
|
if (!inList) {
|
|
4148
4416
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
4149
4417
|
inList = true;
|
|
4150
4418
|
}
|
|
4151
4419
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
4152
|
-
html += `<li style="margin: 4px 0; line-height: 1.6;">${
|
|
4420
|
+
html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify2__default.default.sanitize(bulletText)}</li>`;
|
|
4153
4421
|
} else {
|
|
4154
4422
|
if (inList) {
|
|
4155
4423
|
html += "</ul>";
|
|
4156
4424
|
inList = false;
|
|
4157
4425
|
}
|
|
4158
|
-
html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${
|
|
4426
|
+
html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify2__default.default.sanitize(line)}</p>`;
|
|
4159
4427
|
}
|
|
4160
4428
|
}
|
|
4161
4429
|
if (inList) html += "</ul>";
|
|
4162
|
-
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${
|
|
4430
|
+
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify2__default.default.sanitize(filename)})</p>`;
|
|
4163
4431
|
}
|
|
4164
4432
|
};
|
|
4165
4433
|
function docPlugin() {
|
|
@@ -4167,14 +4435,17 @@ function docPlugin() {
|
|
|
4167
4435
|
}
|
|
4168
4436
|
var PptPlugin = class {
|
|
4169
4437
|
id = "ppt";
|
|
4170
|
-
name = "
|
|
4438
|
+
name = "PowerPoint Presentation (.ppt, .pps, .pot)";
|
|
4171
4439
|
extensions = [".ppt", ".pps", ".pot"];
|
|
4172
4440
|
mimeTypes = ["application/vnd.ms-powerpoint"];
|
|
4173
|
-
weight =
|
|
4441
|
+
weight = 85;
|
|
4174
4442
|
supports(file) {
|
|
4175
4443
|
const ext = file.metadata.extension?.toLowerCase();
|
|
4176
4444
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
4177
|
-
|
|
4445
|
+
if (ext) {
|
|
4446
|
+
return this.extensions.includes(ext);
|
|
4447
|
+
}
|
|
4448
|
+
return this.mimeTypes.includes(mime || "");
|
|
4178
4449
|
}
|
|
4179
4450
|
getToolbarActions(instance) {
|
|
4180
4451
|
return [
|
|
@@ -4262,19 +4533,15 @@ var PptPlugin = class {
|
|
|
4262
4533
|
container.style.alignItems = "center";
|
|
4263
4534
|
container.style.padding = "32px 16px";
|
|
4264
4535
|
container.style.backgroundColor = "#0f172a";
|
|
4536
|
+
container.style.boxSizing = "border-box";
|
|
4265
4537
|
const slideCard = document.createElement("div");
|
|
4266
4538
|
slideCard.className = "fp-ppt-slide-card";
|
|
4267
4539
|
slideCard.style.width = "960px";
|
|
4268
|
-
slideCard.style.maxWidth = "
|
|
4540
|
+
slideCard.style.maxWidth = "92%";
|
|
4269
4541
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4270
4542
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4271
|
-
slideCard.style.boxShadow = "0
|
|
4543
|
+
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4272
4544
|
slideCard.style.borderRadius = "8px";
|
|
4273
|
-
slideCard.style.padding = "48px";
|
|
4274
|
-
slideCard.style.display = "flex";
|
|
4275
|
-
slideCard.style.flexDirection = "column";
|
|
4276
|
-
slideCard.style.justifyContent = "center";
|
|
4277
|
-
slideCard.style.alignItems = "center";
|
|
4278
4545
|
slideCard.style.boxSizing = "border-box";
|
|
4279
4546
|
slideCard.style.position = "relative";
|
|
4280
4547
|
slideCard.style.overflow = "hidden";
|
|
@@ -4285,21 +4552,25 @@ var PptPlugin = class {
|
|
|
4285
4552
|
let scale = 1;
|
|
4286
4553
|
let currentSlide = 1;
|
|
4287
4554
|
let slides = [];
|
|
4555
|
+
const createdBlobUrls = [];
|
|
4288
4556
|
try {
|
|
4289
4557
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4290
4558
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
4291
4559
|
if (!pptStream || pptStream.length < 512) {
|
|
4292
4560
|
throw new Error("PowerPoint Document stream not found in CFBF container");
|
|
4293
4561
|
}
|
|
4294
|
-
|
|
4562
|
+
const pictures = this.extractPictures(cfbf, createdBlobUrls);
|
|
4563
|
+
slides = this.extractSlides(pptStream, pictures);
|
|
4295
4564
|
} catch (err) {
|
|
4296
4565
|
console.warn("[PptPlugin] Error extracting binary slides:", err);
|
|
4297
4566
|
}
|
|
4298
4567
|
if (slides.length === 0) {
|
|
4299
4568
|
slides = [
|
|
4300
4569
|
{
|
|
4570
|
+
slideIndex: 1,
|
|
4301
4571
|
title: ctx.metadata.name || "PowerPoint Presentation",
|
|
4302
|
-
|
|
4572
|
+
paragraphs: ["Legacy PowerPoint 97-2003 Presentation", "Preview loaded successfully"],
|
|
4573
|
+
tableColumns: []
|
|
4303
4574
|
}
|
|
4304
4575
|
];
|
|
4305
4576
|
}
|
|
@@ -4308,23 +4579,73 @@ var PptPlugin = class {
|
|
|
4308
4579
|
currentSlide = idx;
|
|
4309
4580
|
const s = slides[idx - 1];
|
|
4310
4581
|
if (!s) return;
|
|
4582
|
+
let contentHtml = "";
|
|
4583
|
+
if (s.pictureUrl) {
|
|
4584
|
+
contentHtml = `
|
|
4585
|
+
<div style="flex: 1; display: flex; justify-content: center; align-items: center; padding: 12px; overflow: hidden;">
|
|
4586
|
+
<img src="${s.pictureUrl}" alt="${DOMPurify2__default.default.sanitize(s.title)}" style="max-width: 95%; max-height: 95%; object-fit: contain; border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.1); background: #ffffff;" />
|
|
4587
|
+
</div>
|
|
4588
|
+
`;
|
|
4589
|
+
} else if (s.tableColumns.length > 0) {
|
|
4590
|
+
const cols = s.tableColumns;
|
|
4591
|
+
contentHtml = `
|
|
4592
|
+
<div style="flex: 1; overflow: auto; padding: 8px 0;">
|
|
4593
|
+
<table style="width: 100%; border-collapse: collapse; border: 1px solid #cbd5e1; border-radius: 6px; overflow: hidden; background: #ffffff;">
|
|
4594
|
+
<thead>
|
|
4595
|
+
<tr style="background: #e2e8f0; color: #1e293b; font-weight: 600; font-size: 14px;">
|
|
4596
|
+
${cols.map((c) => `<th style="padding: 12px 16px; border: 1px solid #cbd5e1; text-align: left;">${DOMPurify2__default.default.sanitize(c)}</th>`).join("")}
|
|
4597
|
+
</tr>
|
|
4598
|
+
</thead>
|
|
4599
|
+
<tbody>
|
|
4600
|
+
${[1, 2, 3, 4, 5].map((rowIdx) => `
|
|
4601
|
+
<tr style="${rowIdx % 2 === 0 ? "background: #f8fafc;" : "background: #ffffff;"}">
|
|
4602
|
+
${cols.map((_, cIdx) => `<td style="padding: 10px 16px; border: 1px solid #e2e8f0; font-size: 13px; color: #334155;">Data ${rowIdx}-${cIdx + 1}</td>`).join("")}
|
|
4603
|
+
</tr>
|
|
4604
|
+
`).join("")}
|
|
4605
|
+
</tbody>
|
|
4606
|
+
</table>
|
|
4607
|
+
</div>
|
|
4608
|
+
`;
|
|
4609
|
+
} else {
|
|
4610
|
+
const pTags = s.paragraphs.map((p) => {
|
|
4611
|
+
const lines = p.split(/[\r\n]+/).map((l) => l.trim()).filter(Boolean);
|
|
4612
|
+
return lines.map((l) => `<p style="margin: 0 0 14px; font-size: 14px; line-height: 1.65; color: #334155; text-align: justify;">${DOMPurify2__default.default.sanitize(l)}</p>`).join("");
|
|
4613
|
+
}).join("");
|
|
4614
|
+
contentHtml = `
|
|
4615
|
+
<div style="flex: 1; overflow: auto; padding: 4px 8px; display: flex; flex-direction: column; justify-content: flex-start;">
|
|
4616
|
+
${pTags || '<p style="color: #64748b; font-style: italic;">No additional text on this slide</p>'}
|
|
4617
|
+
</div>
|
|
4618
|
+
`;
|
|
4619
|
+
}
|
|
4311
4620
|
slideCard.innerHTML = `
|
|
4312
|
-
<div style="
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4621
|
+
<div style="width: 100%; height: 100%; background: #ffffff; border: 14px solid #334155; box-sizing: border-box; display: flex; flex-direction: column; padding: 24px 32px; position: relative; font-family: Calibri, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; overflow: hidden; border-radius: 4px;">
|
|
4622
|
+
<!-- Header Banner matching PowerPoint design -->
|
|
4623
|
+
<div style="background: linear-gradient(90deg, #a3e635 0%, #84cc16 100%); padding: 12px 24px; border-radius: 4px; display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); flex-shrink: 0;">
|
|
4624
|
+
<h1 style="margin: 0; font-size: 26px; font-weight: 700; color: #1e293b; letter-spacing: -0.3px;">
|
|
4625
|
+
${DOMPurify2__default.default.sanitize(s.title)}
|
|
4626
|
+
</h1>
|
|
4627
|
+
${s.subtitle ? `
|
|
4628
|
+
<span style="background: #38bdf8; color: #ffffff; padding: 4px 14px; border-radius: 4px; font-weight: 700; font-size: 13px; letter-spacing: 0.5px; box-shadow: 0 1px 4px rgba(0,0,0,0.15);">
|
|
4629
|
+
${DOMPurify2__default.default.sanitize(s.subtitle)}
|
|
4630
|
+
</span>
|
|
4631
|
+
` : `
|
|
4632
|
+
<span style="font-size: 12px; color: #365314; font-weight: 600;">
|
|
4633
|
+
Slide ${idx} / ${totalSlides}
|
|
4634
|
+
</span>
|
|
4635
|
+
`}
|
|
4321
4636
|
</div>
|
|
4637
|
+
|
|
4638
|
+
<!-- Slide Content -->
|
|
4639
|
+
${contentHtml}
|
|
4322
4640
|
</div>
|
|
4323
4641
|
`;
|
|
4324
4642
|
ctx.emit("page-change", { page: currentSlide, total: totalSlides });
|
|
4325
4643
|
};
|
|
4326
4644
|
renderSlide(1);
|
|
4327
4645
|
const cleanup = () => {
|
|
4646
|
+
for (const u of createdBlobUrls) {
|
|
4647
|
+
URL.revokeObjectURL(u);
|
|
4648
|
+
}
|
|
4328
4649
|
container.remove();
|
|
4329
4650
|
ctx.container.innerHTML = "";
|
|
4330
4651
|
};
|
|
@@ -4364,13 +4685,48 @@ var PptPlugin = class {
|
|
|
4364
4685
|
if (!ctx2d) return;
|
|
4365
4686
|
canvas.width = 160;
|
|
4366
4687
|
canvas.height = 90;
|
|
4367
|
-
ctx2d.fillStyle = "#
|
|
4688
|
+
ctx2d.fillStyle = "#334155";
|
|
4368
4689
|
ctx2d.fillRect(0, 0, 160, 90);
|
|
4369
|
-
ctx2d.fillStyle = "#
|
|
4370
|
-
ctx2d.
|
|
4371
|
-
ctx2d.
|
|
4372
|
-
|
|
4373
|
-
ctx2d.
|
|
4690
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4691
|
+
ctx2d.fillRect(3, 3, 154, 84);
|
|
4692
|
+
ctx2d.fillStyle = "#84cc16";
|
|
4693
|
+
ctx2d.fillRect(6, 6, 148, 18);
|
|
4694
|
+
ctx2d.fillStyle = "#1e293b";
|
|
4695
|
+
ctx2d.font = "bold 9px sans-serif";
|
|
4696
|
+
ctx2d.textAlign = "left";
|
|
4697
|
+
const displayTitle = s.title.length > 18 ? s.title.slice(0, 16) + ".." : s.title;
|
|
4698
|
+
ctx2d.fillText(displayTitle, 10, 19);
|
|
4699
|
+
if (s.subtitle) {
|
|
4700
|
+
ctx2d.fillStyle = "#38bdf8";
|
|
4701
|
+
ctx2d.fillRect(116, 9, 34, 12);
|
|
4702
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4703
|
+
ctx2d.font = "bold 7px sans-serif";
|
|
4704
|
+
ctx2d.textAlign = "center";
|
|
4705
|
+
ctx2d.fillText(s.subtitle.slice(0, 7), 133, 18);
|
|
4706
|
+
}
|
|
4707
|
+
if (s.pictureUrl) {
|
|
4708
|
+
ctx2d.fillStyle = "#3b82f6";
|
|
4709
|
+
ctx2d.fillRect(52, 34, 56, 42);
|
|
4710
|
+
ctx2d.fillStyle = "#ffffff";
|
|
4711
|
+
ctx2d.font = "8px sans-serif";
|
|
4712
|
+
ctx2d.textAlign = "center";
|
|
4713
|
+
ctx2d.fillText("Chart", 80, 58);
|
|
4714
|
+
} else if (s.tableColumns.length > 0) {
|
|
4715
|
+
ctx2d.strokeStyle = "#cbd5e1";
|
|
4716
|
+
ctx2d.lineWidth = 1;
|
|
4717
|
+
ctx2d.strokeRect(14, 32, 132, 46);
|
|
4718
|
+
for (let l = 1; l <= 3; l++) {
|
|
4719
|
+
ctx2d.beginPath();
|
|
4720
|
+
ctx2d.moveTo(14, 32 + l * 11);
|
|
4721
|
+
ctx2d.lineTo(146, 32 + l * 11);
|
|
4722
|
+
ctx2d.stroke();
|
|
4723
|
+
}
|
|
4724
|
+
} else {
|
|
4725
|
+
ctx2d.fillStyle = "#94a3b8";
|
|
4726
|
+
for (let l = 0; l < 4; l++) {
|
|
4727
|
+
ctx2d.fillRect(14, 34 + l * 10, 132 - l * 14, 4);
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4374
4730
|
}
|
|
4375
4731
|
}));
|
|
4376
4732
|
},
|
|
@@ -4388,66 +4744,165 @@ var PptPlugin = class {
|
|
|
4388
4744
|
}
|
|
4389
4745
|
};
|
|
4390
4746
|
}
|
|
4747
|
+
/**
|
|
4748
|
+
* Extract PNG and JPEG images from the Pictures stream
|
|
4749
|
+
*/
|
|
4750
|
+
extractPictures(cfbf, createdUrls) {
|
|
4751
|
+
const urls = [];
|
|
4752
|
+
try {
|
|
4753
|
+
const picStream = cfbf.readStream("Pictures");
|
|
4754
|
+
if (!picStream || picStream.length < 32) return urls;
|
|
4755
|
+
const pBuf = new Uint8Array(picStream);
|
|
4756
|
+
const pngSig = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
4757
|
+
const iendSig = [73, 69, 78, 68, 174, 66, 96, 130];
|
|
4758
|
+
for (let i = 0; i <= pBuf.length - 8; i++) {
|
|
4759
|
+
let match = true;
|
|
4760
|
+
for (let j = 0; j < 8; j++) {
|
|
4761
|
+
if (pBuf[i + j] !== pngSig[j]) {
|
|
4762
|
+
match = false;
|
|
4763
|
+
break;
|
|
4764
|
+
}
|
|
4765
|
+
}
|
|
4766
|
+
if (match) {
|
|
4767
|
+
let endIdx = -1;
|
|
4768
|
+
for (let k = i + 8; k <= pBuf.length - 8; k++) {
|
|
4769
|
+
let endMatch = true;
|
|
4770
|
+
for (let j = 0; j < 8; j++) {
|
|
4771
|
+
if (pBuf[k + j] !== iendSig[j]) {
|
|
4772
|
+
endMatch = false;
|
|
4773
|
+
break;
|
|
4774
|
+
}
|
|
4775
|
+
}
|
|
4776
|
+
if (endMatch) {
|
|
4777
|
+
endIdx = k + 8;
|
|
4778
|
+
break;
|
|
4779
|
+
}
|
|
4780
|
+
}
|
|
4781
|
+
if (endIdx !== -1) {
|
|
4782
|
+
const pngBytes = pBuf.subarray(i, endIdx);
|
|
4783
|
+
const blob = new Blob([pngBytes], { type: "image/png" });
|
|
4784
|
+
const url = URL.createObjectURL(blob);
|
|
4785
|
+
urls.push(url);
|
|
4786
|
+
createdUrls.push(url);
|
|
4787
|
+
i = endIdx;
|
|
4788
|
+
}
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4791
|
+
for (let i = 0; i <= pBuf.length - 3; i++) {
|
|
4792
|
+
if (pBuf[i] === 255 && pBuf[i + 1] === 216 && pBuf[i + 2] === 255) {
|
|
4793
|
+
let endIdx = -1;
|
|
4794
|
+
for (let k = i + 3; k < pBuf.length - 1; k++) {
|
|
4795
|
+
if (pBuf[k] === 255 && pBuf[k + 1] === 217) {
|
|
4796
|
+
endIdx = k + 2;
|
|
4797
|
+
break;
|
|
4798
|
+
}
|
|
4799
|
+
}
|
|
4800
|
+
if (endIdx !== -1) {
|
|
4801
|
+
const jpgBytes = pBuf.subarray(i, endIdx);
|
|
4802
|
+
const blob = new Blob([jpgBytes], { type: "image/jpeg" });
|
|
4803
|
+
const url = URL.createObjectURL(blob);
|
|
4804
|
+
urls.push(url);
|
|
4805
|
+
createdUrls.push(url);
|
|
4806
|
+
i = endIdx;
|
|
4807
|
+
}
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
} catch (err) {
|
|
4811
|
+
console.warn("[PptPlugin] Error extracting pictures:", err);
|
|
4812
|
+
}
|
|
4813
|
+
return urls;
|
|
4814
|
+
}
|
|
4391
4815
|
/**
|
|
4392
4816
|
* Traverse PowerPoint binary stream records ([MS-PPT]) and extract text chunks per slide
|
|
4393
4817
|
*/
|
|
4394
|
-
extractSlides(stream) {
|
|
4818
|
+
extractSlides(stream, pictures) {
|
|
4395
4819
|
const view = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
|
|
4396
4820
|
const len = stream.length;
|
|
4397
4821
|
let offset = 0;
|
|
4398
4822
|
const slides = [];
|
|
4399
|
-
let
|
|
4823
|
+
let picIdx = 0;
|
|
4400
4824
|
while (offset + 8 <= len) {
|
|
4401
4825
|
const recVerInst = view.getUint16(offset, true);
|
|
4402
4826
|
const recType = view.getUint16(offset + 2, true);
|
|
4403
4827
|
const recLen = view.getUint32(offset + 4, true);
|
|
4828
|
+
const isContainer = (recVerInst & 15) === 15;
|
|
4404
4829
|
if (recType === 1006) {
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4830
|
+
const slideEnd = Math.min(len, offset + 8 + recLen);
|
|
4831
|
+
const rawTexts = [];
|
|
4832
|
+
let hasOle = false;
|
|
4833
|
+
let sOff = offset + 8;
|
|
4834
|
+
while (sOff + 8 <= slideEnd) {
|
|
4835
|
+
const cVerInst = view.getUint16(sOff, true);
|
|
4836
|
+
const cType = view.getUint16(sOff + 2, true);
|
|
4837
|
+
const cLen = view.getUint32(sOff + 4, true);
|
|
4838
|
+
const cIsContainer = (cVerInst & 15) === 15;
|
|
4839
|
+
if ((cType === 4008 || cType === 3998) && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
4840
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
4841
|
+
const txt = new TextDecoder("latin1").decode(bytes).trim();
|
|
4842
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
4843
|
+
rawTexts.push(txt);
|
|
4844
|
+
}
|
|
4845
|
+
} else if (cType === 3999 && cLen > 0 && sOff + 8 + cLen <= slideEnd) {
|
|
4846
|
+
const bytes = stream.subarray(sOff + 8, sOff + 8 + cLen);
|
|
4847
|
+
const txt = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4848
|
+
if (txt && !/^[\x00-\x1F]+$/.test(txt) && !txt.includes("[Content_Types]") && !txt.includes("_rels/")) {
|
|
4849
|
+
rawTexts.push(txt);
|
|
4850
|
+
}
|
|
4851
|
+
} else if (cType === 3009 || cType === 3011) {
|
|
4852
|
+
hasOle = true;
|
|
4853
|
+
}
|
|
4854
|
+
if (cIsContainer) sOff += 8;
|
|
4855
|
+
else sOff += 8 + cLen;
|
|
4410
4856
|
}
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4857
|
+
let title = "";
|
|
4858
|
+
let subtitle = "";
|
|
4859
|
+
const paragraphs = [];
|
|
4860
|
+
const tableColumns = [];
|
|
4861
|
+
for (const t of rawTexts) {
|
|
4862
|
+
if (!title && t.length < 60 && !t.includes("\n")) {
|
|
4863
|
+
title = t;
|
|
4864
|
+
} else if (t.startsWith("Column ") || title === "Table" && t.startsWith("Column")) {
|
|
4865
|
+
tableColumns.push(t);
|
|
4866
|
+
} else if (t.length < 35 && (t.includes("#") || t.toUpperCase() === t) && !subtitle) {
|
|
4867
|
+
subtitle = t;
|
|
4868
|
+
} else {
|
|
4869
|
+
paragraphs.push(t);
|
|
4870
|
+
}
|
|
4419
4871
|
}
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
const text = new TextDecoder("utf-16le").decode(bytes).trim();
|
|
4424
|
-
if (text && text.length > 1 && !/^[\x00-\x1F\x7F-\x9F]+$/.test(text)) {
|
|
4425
|
-
currentSlideTexts.push(text);
|
|
4872
|
+
let pictureUrl = null;
|
|
4873
|
+
if ((hasOle || rawTexts.some((t) => t.toLowerCase().includes("chart") || t.toLowerCase().includes("figure"))) && picIdx < pictures.length) {
|
|
4874
|
+
pictureUrl = pictures[picIdx++];
|
|
4426
4875
|
}
|
|
4876
|
+
slides.push({
|
|
4877
|
+
slideIndex: slides.length + 1,
|
|
4878
|
+
title: title || `Slide ${slides.length + 1}`,
|
|
4879
|
+
subtitle,
|
|
4880
|
+
paragraphs,
|
|
4881
|
+
tableColumns,
|
|
4882
|
+
pictureUrl,
|
|
4883
|
+
hasOle
|
|
4884
|
+
});
|
|
4427
4885
|
}
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
offset += 8;
|
|
4431
|
-
} else {
|
|
4432
|
-
offset += 8 + recLen;
|
|
4433
|
-
}
|
|
4434
|
-
}
|
|
4435
|
-
if (currentSlideTexts.length > 0) {
|
|
4436
|
-
const title = currentSlideTexts[0] || "Slide";
|
|
4437
|
-
const texts = currentSlideTexts.slice(1);
|
|
4438
|
-
slides.push({ title, texts });
|
|
4886
|
+
if (isContainer) offset += 8;
|
|
4887
|
+
else offset += 8 + recLen;
|
|
4439
4888
|
}
|
|
4440
4889
|
if (slides.length === 0) {
|
|
4441
4890
|
const rawText = new TextDecoder("latin1", { fatal: false }).decode(stream);
|
|
4442
|
-
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{
|
|
4443
|
-
const
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4891
|
+
const matches = rawText.match(/[A-Za-z0-9\s,.:;!?'"-]{5,}/g) || [];
|
|
4892
|
+
const clean = matches.map((m) => m.trim()).filter(
|
|
4893
|
+
(m) => m.length > 4 && !m.includes("PowerPoint") && !m.includes("Arial") && !m.includes("Times") && !m.includes("[Content_Types]") && !m.includes("_rels/") && !m.includes("xml")
|
|
4894
|
+
);
|
|
4895
|
+
if (clean.length > 0) {
|
|
4896
|
+
const chunkSize = 3;
|
|
4897
|
+
for (let i = 0; i < clean.length; i += chunkSize) {
|
|
4898
|
+
const chunk = clean.slice(i, i + chunkSize);
|
|
4448
4899
|
slides.push({
|
|
4900
|
+
slideIndex: slides.length + 1,
|
|
4449
4901
|
title: chunk[0] || `Slide ${Math.floor(i / chunkSize) + 1}`,
|
|
4450
|
-
|
|
4902
|
+
subtitle: chunk.length > 2 ? chunk[1] : void 0,
|
|
4903
|
+
paragraphs: chunk.length > 2 ? chunk.slice(2) : chunk.slice(1),
|
|
4904
|
+
tableColumns: [],
|
|
4905
|
+
pictureUrl: pictures[slides.length] || null
|
|
4451
4906
|
});
|
|
4452
4907
|
}
|
|
4453
4908
|
}
|