@files-preview-app/preview-file 1.2.1 → 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 +457 -128
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +456 -127
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +458 -129
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +457 -128
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +457 -128
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +456 -127
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +457 -128
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +456 -127
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import DOMPurify2 from 'dompurify';
|
|
2
2
|
import * as docx from 'docx-preview';
|
|
3
|
+
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
3
4
|
import * as XLSX from 'xlsx';
|
|
4
5
|
import hljs from 'highlight.js';
|
|
5
|
-
import { unzip, unzipSync, strFromU8 } from 'fflate';
|
|
6
6
|
import { marked } from 'marked';
|
|
7
7
|
import { PptxRenderer } from 'pptx-browser';
|
|
8
8
|
import * as THREE from 'three';
|
|
@@ -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,
|
|
@@ -459,7 +462,16 @@ var ICON_MAP = {
|
|
|
459
462
|
"close": ICON_CLOSE,
|
|
460
463
|
"copy": ICON_COPY,
|
|
461
464
|
"prev": ICON_PAGE_PREV,
|
|
462
|
-
"next": ICON_PAGE_NEXT
|
|
465
|
+
"next": ICON_PAGE_NEXT,
|
|
466
|
+
"page-prev": ICON_PAGE_PREV,
|
|
467
|
+
"page-next": ICON_PAGE_NEXT,
|
|
468
|
+
"chevron-left": ICON_PAGE_PREV,
|
|
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
|
|
463
475
|
};
|
|
464
476
|
var ToolbarController = class {
|
|
465
477
|
el;
|
|
@@ -491,7 +503,9 @@ var ToolbarController = class {
|
|
|
491
503
|
view: [],
|
|
492
504
|
actions: []
|
|
493
505
|
};
|
|
494
|
-
|
|
506
|
+
const hasPageNav = this.actions.some((a) => a.type === "page-nav");
|
|
507
|
+
const effectiveActions = hasPageNav ? this.actions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : this.actions;
|
|
508
|
+
for (const action of effectiveActions) {
|
|
495
509
|
if (groups[action.group]) {
|
|
496
510
|
groups[action.group].push(action);
|
|
497
511
|
}
|
|
@@ -514,13 +528,26 @@ var ToolbarController = class {
|
|
|
514
528
|
"prev",
|
|
515
529
|
ICON_PAGE_PREV,
|
|
516
530
|
"Previous Page",
|
|
517
|
-
() =>
|
|
531
|
+
() => {
|
|
532
|
+
const cur = parseInt(input.value, 10) || 1;
|
|
533
|
+
if (cur > 1) {
|
|
534
|
+
input.value = (cur - 1).toString();
|
|
535
|
+
action.execute("prev", cur - 1);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
518
538
|
);
|
|
519
539
|
const nextBtn = this.createButton(
|
|
520
540
|
"next",
|
|
521
541
|
ICON_PAGE_NEXT,
|
|
522
542
|
"Next Page",
|
|
523
|
-
() =>
|
|
543
|
+
() => {
|
|
544
|
+
const cur = parseInt(input.value, 10) || 1;
|
|
545
|
+
const max = action.max ?? 1;
|
|
546
|
+
if (cur < max) {
|
|
547
|
+
input.value = (cur + 1).toString();
|
|
548
|
+
action.execute("next", cur + 1);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
524
551
|
);
|
|
525
552
|
const input = createElement("input", {
|
|
526
553
|
className: "fp-toolbar-input",
|
|
@@ -530,7 +557,10 @@ var ToolbarController = class {
|
|
|
530
557
|
max: (action.max ?? 1).toString()
|
|
531
558
|
});
|
|
532
559
|
input.addEventListener("change", () => {
|
|
533
|
-
|
|
560
|
+
const val = parseInt(input.value, 10);
|
|
561
|
+
if (!isNaN(val)) {
|
|
562
|
+
action.execute("go", val);
|
|
563
|
+
}
|
|
534
564
|
});
|
|
535
565
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${action.max ?? 1}`);
|
|
536
566
|
groupEl.appendChild(prevBtn);
|
|
@@ -571,11 +601,11 @@ var ToolbarController = class {
|
|
|
571
601
|
type: "button",
|
|
572
602
|
"data-action-id": id
|
|
573
603
|
});
|
|
574
|
-
const svg = ICON_MAP[iconHtml] || iconHtml;
|
|
575
|
-
if (svg
|
|
604
|
+
const svg = ICON_MAP[iconHtml] || ICON_MAP[id] || (iconHtml && iconHtml.startsWith("<svg") ? iconHtml : null);
|
|
605
|
+
if (svg) {
|
|
576
606
|
btn.innerHTML = sanitizeSVG(svg);
|
|
577
607
|
} else {
|
|
578
|
-
btn.textContent =
|
|
608
|
+
btn.textContent = title || id;
|
|
579
609
|
}
|
|
580
610
|
btn.addEventListener("click", onClick);
|
|
581
611
|
return btn;
|
|
@@ -1318,12 +1348,12 @@ function pdfPlugin() {
|
|
|
1318
1348
|
}
|
|
1319
1349
|
|
|
1320
1350
|
// ../plugins/media/dist/index.js
|
|
1321
|
-
var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"];
|
|
1322
|
-
var VIDEO_EXTS = [".mp4", ".webm", ".ogg"];
|
|
1323
|
-
var AUDIO_EXTS = [".mp3", ".wav", ".ogg"];
|
|
1351
|
+
var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".bmp", ".ico", ".tiff", ".tif", ".avif"];
|
|
1352
|
+
var VIDEO_EXTS = [".mp4", ".m4v", ".webm", ".ogv", ".ogg", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".3gp", ".mpg", ".mpeg"];
|
|
1353
|
+
var AUDIO_EXTS = [".mp3", ".wav", ".ogg", ".flac", ".aac", ".m4a", ".wma", ".opus", ".weba"];
|
|
1324
1354
|
var MediaPlugin = class {
|
|
1325
1355
|
id = "media";
|
|
1326
|
-
name = "Media Preview";
|
|
1356
|
+
name = "Media Preview (Image, Video, Audio)";
|
|
1327
1357
|
extensions = [...IMAGE_EXTS, ...VIDEO_EXTS, ...AUDIO_EXTS];
|
|
1328
1358
|
mimeTypes = [
|
|
1329
1359
|
"image/jpeg",
|
|
@@ -1331,12 +1361,29 @@ var MediaPlugin = class {
|
|
|
1331
1361
|
"image/gif",
|
|
1332
1362
|
"image/webp",
|
|
1333
1363
|
"image/svg+xml",
|
|
1364
|
+
"image/bmp",
|
|
1365
|
+
"image/x-icon",
|
|
1366
|
+
"image/tiff",
|
|
1367
|
+
"image/avif",
|
|
1334
1368
|
"video/mp4",
|
|
1335
1369
|
"video/webm",
|
|
1336
1370
|
"video/ogg",
|
|
1371
|
+
"video/quicktime",
|
|
1372
|
+
"video/x-msvideo",
|
|
1373
|
+
"video/x-matroska",
|
|
1374
|
+
"video/x-flv",
|
|
1375
|
+
"video/x-ms-wmv",
|
|
1376
|
+
"video/3gpp",
|
|
1377
|
+
"video/mpeg",
|
|
1337
1378
|
"audio/mpeg",
|
|
1338
1379
|
"audio/wav",
|
|
1339
|
-
"audio/ogg"
|
|
1380
|
+
"audio/ogg",
|
|
1381
|
+
"audio/flac",
|
|
1382
|
+
"audio/aac",
|
|
1383
|
+
"audio/mp4",
|
|
1384
|
+
"audio/x-ms-wma",
|
|
1385
|
+
"audio/opus",
|
|
1386
|
+
"audio/webm"
|
|
1340
1387
|
];
|
|
1341
1388
|
weight = 90;
|
|
1342
1389
|
supports(file) {
|
|
@@ -1392,6 +1439,16 @@ var MediaPlugin = class {
|
|
|
1392
1439
|
}
|
|
1393
1440
|
if (instance.play) {
|
|
1394
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
|
+
},
|
|
1395
1452
|
{
|
|
1396
1453
|
id: "play",
|
|
1397
1454
|
icon: "play",
|
|
@@ -1411,6 +1468,26 @@ var MediaPlugin = class {
|
|
|
1411
1468
|
execute: () => {
|
|
1412
1469
|
instance.pause?.();
|
|
1413
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
|
+
}
|
|
1414
1491
|
}
|
|
1415
1492
|
);
|
|
1416
1493
|
}
|
|
@@ -1469,8 +1546,12 @@ var MediaPlugin = class {
|
|
|
1469
1546
|
const video = document.createElement("video");
|
|
1470
1547
|
video.src = url;
|
|
1471
1548
|
video.controls = true;
|
|
1472
|
-
video.
|
|
1473
|
-
video.style.
|
|
1549
|
+
video.playsInline = true;
|
|
1550
|
+
video.style.maxWidth = "90%";
|
|
1551
|
+
video.style.maxHeight = "90%";
|
|
1552
|
+
video.style.borderRadius = "8px";
|
|
1553
|
+
video.style.boxShadow = "0 8px 30px rgba(0,0,0,0.3)";
|
|
1554
|
+
video.style.backgroundColor = "#000000";
|
|
1474
1555
|
element = video;
|
|
1475
1556
|
mediaElement = video;
|
|
1476
1557
|
} else if (isAudio) {
|
|
@@ -1529,6 +1610,28 @@ var MediaPlugin = class {
|
|
|
1529
1610
|
play: mediaElement ? () => mediaElement?.play() : void 0,
|
|
1530
1611
|
pause: mediaElement ? () => mediaElement?.pause() : void 0,
|
|
1531
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,
|
|
1532
1635
|
download: () => {
|
|
1533
1636
|
const a = document.createElement("a");
|
|
1534
1637
|
a.href = url;
|
|
@@ -1546,7 +1649,7 @@ function mediaPlugin() {
|
|
|
1546
1649
|
}
|
|
1547
1650
|
var DocxPlugin = class {
|
|
1548
1651
|
id = "docx";
|
|
1549
|
-
name = "Word Document Preview";
|
|
1652
|
+
name = "Word Document Preview (.docx, .docm, .dotx, .dotm)";
|
|
1550
1653
|
extensions = [".docx", ".docm", ".dotx", ".dotm"];
|
|
1551
1654
|
mimeTypes = [
|
|
1552
1655
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
@@ -1568,9 +1671,7 @@ var DocxPlugin = class {
|
|
|
1568
1671
|
label: "Zoom Out",
|
|
1569
1672
|
type: "button",
|
|
1570
1673
|
group: "zoom",
|
|
1571
|
-
execute: () =>
|
|
1572
|
-
instance.zoomOut?.();
|
|
1573
|
-
}
|
|
1674
|
+
execute: () => instance.zoomOut?.()
|
|
1574
1675
|
},
|
|
1575
1676
|
{
|
|
1576
1677
|
id: "zoom-in",
|
|
@@ -1578,9 +1679,7 @@ var DocxPlugin = class {
|
|
|
1578
1679
|
label: "Zoom In",
|
|
1579
1680
|
type: "button",
|
|
1580
1681
|
group: "zoom",
|
|
1581
|
-
execute: () =>
|
|
1582
|
-
instance.zoomIn?.();
|
|
1583
|
-
}
|
|
1682
|
+
execute: () => instance.zoomIn?.()
|
|
1584
1683
|
},
|
|
1585
1684
|
{
|
|
1586
1685
|
id: "fit-page",
|
|
@@ -1588,9 +1687,7 @@ var DocxPlugin = class {
|
|
|
1588
1687
|
label: "Fit to Page",
|
|
1589
1688
|
type: "button",
|
|
1590
1689
|
group: "zoom",
|
|
1591
|
-
execute: () =>
|
|
1592
|
-
instance.fitToPage?.();
|
|
1593
|
-
}
|
|
1690
|
+
execute: () => instance.fitToPage?.()
|
|
1594
1691
|
},
|
|
1595
1692
|
{
|
|
1596
1693
|
id: "download",
|
|
@@ -1598,9 +1695,7 @@ var DocxPlugin = class {
|
|
|
1598
1695
|
label: "Download",
|
|
1599
1696
|
type: "button",
|
|
1600
1697
|
group: "actions",
|
|
1601
|
-
execute: () =>
|
|
1602
|
-
instance.download?.();
|
|
1603
|
-
}
|
|
1698
|
+
execute: () => instance.download?.()
|
|
1604
1699
|
},
|
|
1605
1700
|
{
|
|
1606
1701
|
id: "print",
|
|
@@ -1608,9 +1703,7 @@ var DocxPlugin = class {
|
|
|
1608
1703
|
label: "Print",
|
|
1609
1704
|
type: "button",
|
|
1610
1705
|
group: "actions",
|
|
1611
|
-
execute: () =>
|
|
1612
|
-
instance.print?.();
|
|
1613
|
-
}
|
|
1706
|
+
execute: () => instance.print?.()
|
|
1614
1707
|
}
|
|
1615
1708
|
];
|
|
1616
1709
|
}
|
|
@@ -1619,27 +1712,81 @@ var DocxPlugin = class {
|
|
|
1619
1712
|
wrapper.className = "fp-docx-wrapper";
|
|
1620
1713
|
wrapper.style.transformOrigin = "top center";
|
|
1621
1714
|
wrapper.style.transition = "transform 0.2s ease";
|
|
1622
|
-
wrapper.style.padding = "16px";
|
|
1715
|
+
wrapper.style.padding = "24px 16px";
|
|
1716
|
+
wrapper.style.maxWidth = "950px";
|
|
1717
|
+
wrapper.style.margin = "0 auto";
|
|
1718
|
+
wrapper.style.boxSizing = "border-box";
|
|
1623
1719
|
ctx.container.style.overflow = "auto";
|
|
1720
|
+
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
1624
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);
|
|
1625
1740
|
let scale = 1;
|
|
1741
|
+
let renderedSuccessfully = false;
|
|
1742
|
+
const createdBlobUrls = [];
|
|
1626
1743
|
try {
|
|
1627
|
-
await docx.renderAsync(ctx.buffer, wrapper,
|
|
1744
|
+
await docx.renderAsync(ctx.buffer, wrapper, wrapper, {
|
|
1628
1745
|
inWrapper: true,
|
|
1629
1746
|
ignoreWidth: false,
|
|
1630
|
-
ignoreHeight: false
|
|
1747
|
+
ignoreHeight: false,
|
|
1748
|
+
ignoreFonts: true,
|
|
1749
|
+
// Avoid crashes on embedded obfuscated fonts
|
|
1750
|
+
breakPages: true,
|
|
1751
|
+
experimental: true
|
|
1631
1752
|
});
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1753
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1754
|
+
ctx.container.appendChild(wrapper);
|
|
1755
|
+
}
|
|
1756
|
+
if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
|
|
1757
|
+
renderedSuccessfully = true;
|
|
1758
|
+
}
|
|
1759
|
+
} catch (err) {
|
|
1760
|
+
console.warn("[DocxPlugin] docx-preview failed, triggering native fallback:", err);
|
|
1761
|
+
}
|
|
1762
|
+
if (!renderedSuccessfully) {
|
|
1763
|
+
try {
|
|
1764
|
+
wrapper.innerHTML = "";
|
|
1765
|
+
this.renderXmlFallback(ctx, wrapper, createdBlobUrls);
|
|
1766
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1767
|
+
ctx.container.appendChild(wrapper);
|
|
1768
|
+
}
|
|
1769
|
+
renderedSuccessfully = true;
|
|
1770
|
+
} catch (fallbackErr) {
|
|
1771
|
+
console.error("[DocxPlugin] Native fallback failed:", fallbackErr);
|
|
1772
|
+
wrapper.innerHTML = `
|
|
1773
|
+
<div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
|
|
1774
|
+
<div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
|
|
1775
|
+
<h3 style="margin: 0 0 8px; color: #1e293b;">${ctx.metadata.name || "Word Document"}</h3>
|
|
1776
|
+
<p style="color: #64748b; margin: 0;">Could not parse document content</p>
|
|
1777
|
+
</div>
|
|
1778
|
+
`;
|
|
1779
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1780
|
+
ctx.container.appendChild(wrapper);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1640
1783
|
}
|
|
1641
1784
|
const cleanup = () => {
|
|
1785
|
+
for (const url of createdBlobUrls) {
|
|
1786
|
+
URL.revokeObjectURL(url);
|
|
1787
|
+
}
|
|
1642
1788
|
wrapper.remove();
|
|
1789
|
+
styleOverride.remove();
|
|
1643
1790
|
ctx.container.innerHTML = "";
|
|
1644
1791
|
};
|
|
1645
1792
|
ctx.signal.addEventListener("abort", cleanup);
|
|
@@ -1660,7 +1807,7 @@ var DocxPlugin = class {
|
|
|
1660
1807
|
},
|
|
1661
1808
|
fitToPage: () => {
|
|
1662
1809
|
scale = 1;
|
|
1663
|
-
wrapper.style.transform =
|
|
1810
|
+
wrapper.style.transform = "scale(1)";
|
|
1664
1811
|
},
|
|
1665
1812
|
download: () => {
|
|
1666
1813
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
@@ -1676,6 +1823,212 @@ var DocxPlugin = class {
|
|
|
1676
1823
|
}
|
|
1677
1824
|
};
|
|
1678
1825
|
}
|
|
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
|
+
}
|
|
1832
|
+
const unzipped = unzipSync(new Uint8Array(ctx.buffer));
|
|
1833
|
+
const docKey = Object.keys(unzipped).find((k) => k.replace(/^[./\\]+/, "").toLowerCase() === "word/document.xml");
|
|
1834
|
+
const docXmlEntry = docKey ? unzipped[docKey] : void 0;
|
|
1835
|
+
if (!docXmlEntry) throw new Error("Missing word/document.xml in DOCX package");
|
|
1836
|
+
const xmlStr = strFromU8(docXmlEntry);
|
|
1837
|
+
const parser = new DOMParser();
|
|
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
|
+
}
|
|
1870
|
+
const card = document.createElement("div");
|
|
1871
|
+
card.className = "fp-docx-page-card";
|
|
1872
|
+
card.style.backgroundColor = "#ffffff";
|
|
1873
|
+
card.style.borderRadius = "6px";
|
|
1874
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
1875
|
+
card.style.padding = "48px 56px";
|
|
1876
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
1877
|
+
card.style.color = "#1e293b";
|
|
1878
|
+
card.style.lineHeight = "1.6";
|
|
1879
|
+
const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
|
|
1880
|
+
let html = "";
|
|
1881
|
+
for (const child of Array.from(body.children)) {
|
|
1882
|
+
const tag = child.localName || child.nodeName.split(":").pop();
|
|
1883
|
+
if (tag === "p") {
|
|
1884
|
+
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
1885
|
+
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
1886
|
+
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
1887
|
+
const textContent = this.extractParagraphHtml(child, imageMap);
|
|
1888
|
+
if (!textContent.trim()) {
|
|
1889
|
+
html += '<div style="height: 10px;"></div>';
|
|
1890
|
+
continue;
|
|
1891
|
+
}
|
|
1892
|
+
const lowerStyle = styleVal.toLowerCase();
|
|
1893
|
+
if (lowerStyle.includes("title")) {
|
|
1894
|
+
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>`;
|
|
1895
|
+
} else if (lowerStyle.includes("heading1") || styleVal === "1") {
|
|
1896
|
+
html += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
|
|
1897
|
+
} else if (lowerStyle.includes("heading2") || styleVal === "2") {
|
|
1898
|
+
html += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
|
|
1899
|
+
} else if (lowerStyle.includes("heading3") || styleVal === "3") {
|
|
1900
|
+
html += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
|
|
1901
|
+
} else if (numPr) {
|
|
1902
|
+
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>`;
|
|
1903
|
+
} else {
|
|
1904
|
+
html += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
|
|
1905
|
+
}
|
|
1906
|
+
} else if (tag === "tbl") {
|
|
1907
|
+
html += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
|
|
1908
|
+
const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
|
|
1909
|
+
rows.forEach((tr, rIdx) => {
|
|
1910
|
+
html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
1911
|
+
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
1912
|
+
cells.forEach((tc) => {
|
|
1913
|
+
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
1914
|
+
html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
1915
|
+
});
|
|
1916
|
+
html += "</tr>";
|
|
1917
|
+
});
|
|
1918
|
+
html += "</table>";
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
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"],
|
|
1923
|
+
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
1924
|
+
});
|
|
1925
|
+
wrapper.appendChild(card);
|
|
1926
|
+
}
|
|
1927
|
+
extractParagraphHtml(pElement, imageMap = {}) {
|
|
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
|
+
}
|
|
1937
|
+
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
1938
|
+
if (runs.length === 0 && !result) {
|
|
1939
|
+
return DOMPurify2.sanitize(pElement.textContent || "");
|
|
1940
|
+
}
|
|
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
|
+
}
|
|
1955
|
+
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
1956
|
+
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
1957
|
+
const isItalic = !!rPr?.getElementsByTagNameNS("*", "i")[0];
|
|
1958
|
+
const isUnderline = !!rPr?.getElementsByTagNameNS("*", "u")[0];
|
|
1959
|
+
const isStrike = !!rPr?.getElementsByTagNameNS("*", "strike")[0];
|
|
1960
|
+
const colorNode = rPr?.getElementsByTagNameNS("*", "color")[0];
|
|
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");
|
|
1964
|
+
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
1965
|
+
let text = texts.map((t) => t.textContent || "").join("");
|
|
1966
|
+
if (!text) continue;
|
|
1967
|
+
text = DOMPurify2.sanitize(text);
|
|
1968
|
+
let styles = "";
|
|
1969
|
+
if (isBold) styles += "font-weight: bold; ";
|
|
1970
|
+
if (isItalic) styles += "font-style: italic; ";
|
|
1971
|
+
if (isUnderline) styles += "text-decoration: underline; ";
|
|
1972
|
+
if (isStrike) styles += "text-decoration: line-through; ";
|
|
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
|
+
}
|
|
1978
|
+
if (styles) {
|
|
1979
|
+
result += `<span style="${styles}">${text}</span>`;
|
|
1980
|
+
} else {
|
|
1981
|
+
result += text;
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
return result;
|
|
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
|
+
}
|
|
1679
2032
|
};
|
|
1680
2033
|
function docxPlugin() {
|
|
1681
2034
|
return new DocxPlugin();
|
|
@@ -2487,7 +2840,7 @@ var MarkdownPlugin = class {
|
|
|
2487
2840
|
gfm: true,
|
|
2488
2841
|
breaks: true
|
|
2489
2842
|
});
|
|
2490
|
-
const cleanHtml =
|
|
2843
|
+
const cleanHtml = DOMPurify2.sanitize(rawHtml, {
|
|
2491
2844
|
USE_PROFILES: { html: true }
|
|
2492
2845
|
});
|
|
2493
2846
|
const wrapper = document.createElement("div");
|
|
@@ -2651,35 +3004,27 @@ var PptxPlugin = class {
|
|
|
2651
3004
|
group: "navigation",
|
|
2652
3005
|
execute: () => instance.toggleThumbnails?.()
|
|
2653
3006
|
},
|
|
2654
|
-
{
|
|
2655
|
-
id: "page-prev",
|
|
2656
|
-
icon: "page-prev",
|
|
2657
|
-
label: "Previous Slide",
|
|
2658
|
-
type: "button",
|
|
2659
|
-
group: "navigation",
|
|
2660
|
-
execute: () => {
|
|
2661
|
-
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2662
|
-
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2663
|
-
}
|
|
2664
|
-
},
|
|
2665
3007
|
{
|
|
2666
3008
|
id: "page-nav",
|
|
2667
3009
|
icon: "",
|
|
2668
|
-
label: "Slide
|
|
3010
|
+
label: "Slide Navigation",
|
|
2669
3011
|
type: "page-nav",
|
|
2670
3012
|
group: "navigation",
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
3013
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3014
|
+
max: instance.getPageCount?.() ?? 1,
|
|
3015
|
+
execute: (action, page) => {
|
|
3016
|
+
if (action === "prev") {
|
|
3017
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3018
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3019
|
+
} else if (action === "next") {
|
|
3020
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3021
|
+
const total = instance.getPageCount?.() ?? 1;
|
|
3022
|
+
if (cur < total) instance.goToPage?.(cur + 1);
|
|
3023
|
+
} else if (typeof page === "number") {
|
|
3024
|
+
instance.goToPage?.(page);
|
|
3025
|
+
} else if (typeof action === "number") {
|
|
3026
|
+
instance.goToPage?.(action);
|
|
3027
|
+
}
|
|
2683
3028
|
}
|
|
2684
3029
|
},
|
|
2685
3030
|
{
|
|
@@ -3210,7 +3555,7 @@ var HtmlPreviewPlugin = class {
|
|
|
3210
3555
|
}
|
|
3211
3556
|
async render(ctx) {
|
|
3212
3557
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
3213
|
-
const sanitized =
|
|
3558
|
+
const sanitized = DOMPurify2.sanitize(rawHtml, {
|
|
3214
3559
|
WHOLE_DOCUMENT: true,
|
|
3215
3560
|
ADD_TAGS: ["style", "link"],
|
|
3216
3561
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -3305,35 +3650,27 @@ var OpenDocumentPlugin = class {
|
|
|
3305
3650
|
group: "navigation",
|
|
3306
3651
|
execute: () => instance.toggleThumbnails?.()
|
|
3307
3652
|
},
|
|
3308
|
-
{
|
|
3309
|
-
id: "page-prev",
|
|
3310
|
-
icon: "page-prev",
|
|
3311
|
-
label: "Previous Slide",
|
|
3312
|
-
type: "button",
|
|
3313
|
-
group: "navigation",
|
|
3314
|
-
execute: () => {
|
|
3315
|
-
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3316
|
-
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3317
|
-
}
|
|
3318
|
-
},
|
|
3319
3653
|
{
|
|
3320
3654
|
id: "page-nav",
|
|
3321
3655
|
icon: "",
|
|
3322
|
-
label: "Slide
|
|
3656
|
+
label: "Slide Navigation",
|
|
3323
3657
|
type: "page-nav",
|
|
3324
3658
|
group: "navigation",
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3659
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3660
|
+
max: instance.getPageCount?.() ?? 1,
|
|
3661
|
+
execute: (action, page) => {
|
|
3662
|
+
if (action === "prev") {
|
|
3663
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3664
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3665
|
+
} else if (action === "next") {
|
|
3666
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3667
|
+
const total = instance.getPageCount?.() ?? 1;
|
|
3668
|
+
if (cur < total) instance.goToPage?.(cur + 1);
|
|
3669
|
+
} else if (typeof page === "number") {
|
|
3670
|
+
instance.goToPage?.(page);
|
|
3671
|
+
} else if (typeof action === "number") {
|
|
3672
|
+
instance.goToPage?.(action);
|
|
3673
|
+
}
|
|
3337
3674
|
}
|
|
3338
3675
|
}
|
|
3339
3676
|
);
|
|
@@ -3461,7 +3798,7 @@ var OpenDocumentPlugin = class {
|
|
|
3461
3798
|
wrapper.style.padding = "48px";
|
|
3462
3799
|
wrapper.style.minHeight = "100%";
|
|
3463
3800
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
3464
|
-
wrapper.innerHTML =
|
|
3801
|
+
wrapper.innerHTML = DOMPurify2.sanitize(bodyHtml, {
|
|
3465
3802
|
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
|
|
3466
3803
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
3467
3804
|
});
|
|
@@ -3981,24 +4318,24 @@ var DocPlugin = class {
|
|
|
3981
4318
|
html += "</ul>";
|
|
3982
4319
|
inList = false;
|
|
3983
4320
|
}
|
|
3984
|
-
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>`;
|
|
3985
4322
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
3986
4323
|
if (!inList) {
|
|
3987
4324
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
3988
4325
|
inList = true;
|
|
3989
4326
|
}
|
|
3990
4327
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
3991
|
-
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>`;
|
|
3992
4329
|
} else {
|
|
3993
4330
|
if (inList) {
|
|
3994
4331
|
html += "</ul>";
|
|
3995
4332
|
inList = false;
|
|
3996
4333
|
}
|
|
3997
|
-
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>`;
|
|
3998
4335
|
}
|
|
3999
4336
|
}
|
|
4000
4337
|
if (inList) html += "</ul>";
|
|
4001
|
-
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>`;
|
|
4002
4339
|
}
|
|
4003
4340
|
};
|
|
4004
4341
|
function docPlugin() {
|
|
@@ -4025,35 +4362,27 @@ var PptPlugin = class {
|
|
|
4025
4362
|
group: "navigation",
|
|
4026
4363
|
execute: () => instance.toggleThumbnails?.()
|
|
4027
4364
|
},
|
|
4028
|
-
{
|
|
4029
|
-
id: "page-prev",
|
|
4030
|
-
icon: "page-prev",
|
|
4031
|
-
label: "Previous Slide",
|
|
4032
|
-
type: "button",
|
|
4033
|
-
group: "navigation",
|
|
4034
|
-
execute: () => {
|
|
4035
|
-
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4036
|
-
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4037
|
-
}
|
|
4038
|
-
},
|
|
4039
4365
|
{
|
|
4040
4366
|
id: "page-nav",
|
|
4041
4367
|
icon: "",
|
|
4042
|
-
label: "Slide
|
|
4368
|
+
label: "Slide Navigation",
|
|
4043
4369
|
type: "page-nav",
|
|
4044
4370
|
group: "navigation",
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4371
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4372
|
+
max: instance.getPageCount?.() ?? 1,
|
|
4373
|
+
execute: (action, page) => {
|
|
4374
|
+
if (action === "prev") {
|
|
4375
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4376
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4377
|
+
} else if (action === "next") {
|
|
4378
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4379
|
+
const total = instance.getPageCount?.() ?? 1;
|
|
4380
|
+
if (cur < total) instance.goToPage?.(cur + 1);
|
|
4381
|
+
} else if (typeof page === "number") {
|
|
4382
|
+
instance.goToPage?.(page);
|
|
4383
|
+
} else if (typeof action === "number") {
|
|
4384
|
+
instance.goToPage?.(action);
|
|
4385
|
+
}
|
|
4057
4386
|
}
|
|
4058
4387
|
},
|
|
4059
4388
|
{
|
|
@@ -4161,10 +4490,10 @@ var PptPlugin = class {
|
|
|
4161
4490
|
</div>
|
|
4162
4491
|
<div style="text-align: center; width: 100%;">
|
|
4163
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;">
|
|
4164
|
-
${
|
|
4493
|
+
${DOMPurify2.sanitize(s.title || `Slide ${idx}`)}
|
|
4165
4494
|
</h1>
|
|
4166
4495
|
<div style="display: flex; flex-direction: column; gap: 12px; max-width: 80%; margin: 0 auto; text-align: ${idx === 1 ? "center" : "left"};">
|
|
4167
|
-
${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("")}
|
|
4168
4497
|
</div>
|
|
4169
4498
|
</div>
|
|
4170
4499
|
`;
|