@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/vue.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { defineComponent, ref, onMounted, watch, onBeforeUnmount, h } from 'vue';
|
|
2
|
-
import
|
|
2
|
+
import DOMPurify2 from 'dompurify';
|
|
3
3
|
import * as docx from 'docx-preview';
|
|
4
|
+
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
4
5
|
import * as XLSX from 'xlsx';
|
|
5
6
|
import hljs from 'highlight.js';
|
|
6
|
-
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
7
7
|
import { marked } from 'marked';
|
|
8
8
|
import { PptxRenderer } from 'pptx-browser';
|
|
9
9
|
import * as THREE from 'three';
|
|
@@ -340,7 +340,7 @@ async function sourceToArrayBuffer(source, signal) {
|
|
|
340
340
|
return { buffer, metadata };
|
|
341
341
|
}
|
|
342
342
|
function sanitizeSVG(svg) {
|
|
343
|
-
return
|
|
343
|
+
return DOMPurify2.sanitize(svg, {
|
|
344
344
|
USE_PROFILES: { svg: true, svgFilters: true }
|
|
345
345
|
});
|
|
346
346
|
}
|
|
@@ -400,6 +400,9 @@ var ICON_THUMBNAILS = `<svg width="24" height="24" viewBox="0 0 24 24" fill="non
|
|
|
400
400
|
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>`;
|
|
401
401
|
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>`;
|
|
402
402
|
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>`;
|
|
403
|
+
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>`;
|
|
404
|
+
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>`;
|
|
405
|
+
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>`;
|
|
403
406
|
var ICON_MAP = {
|
|
404
407
|
"zoom-in": ICON_ZOOM_IN,
|
|
405
408
|
"zoom-out": ICON_ZOOM_OUT,
|
|
@@ -416,7 +419,16 @@ var ICON_MAP = {
|
|
|
416
419
|
"close": ICON_CLOSE,
|
|
417
420
|
"copy": ICON_COPY,
|
|
418
421
|
"prev": ICON_PAGE_PREV,
|
|
419
|
-
"next": ICON_PAGE_NEXT
|
|
422
|
+
"next": ICON_PAGE_NEXT,
|
|
423
|
+
"page-prev": ICON_PAGE_PREV,
|
|
424
|
+
"page-next": ICON_PAGE_NEXT,
|
|
425
|
+
"chevron-left": ICON_PAGE_PREV,
|
|
426
|
+
"chevron-right": ICON_PAGE_NEXT,
|
|
427
|
+
"fast-forward": ICON_FAST_FORWARD,
|
|
428
|
+
"forward-10": ICON_FAST_FORWARD,
|
|
429
|
+
"rewind": ICON_REWIND,
|
|
430
|
+
"replay-10": ICON_REWIND,
|
|
431
|
+
"speed": ICON_SPEED
|
|
420
432
|
};
|
|
421
433
|
var ToolbarController = class {
|
|
422
434
|
el;
|
|
@@ -448,7 +460,9 @@ var ToolbarController = class {
|
|
|
448
460
|
view: [],
|
|
449
461
|
actions: []
|
|
450
462
|
};
|
|
451
|
-
|
|
463
|
+
const hasPageNav = this.actions.some((a) => a.type === "page-nav");
|
|
464
|
+
const effectiveActions = hasPageNav ? this.actions.filter((a) => a.id !== "page-prev" && a.id !== "page-next" && a.id !== "prev" && a.id !== "next") : this.actions;
|
|
465
|
+
for (const action of effectiveActions) {
|
|
452
466
|
if (groups[action.group]) {
|
|
453
467
|
groups[action.group].push(action);
|
|
454
468
|
}
|
|
@@ -471,13 +485,26 @@ var ToolbarController = class {
|
|
|
471
485
|
"prev",
|
|
472
486
|
ICON_PAGE_PREV,
|
|
473
487
|
"Previous Page",
|
|
474
|
-
() =>
|
|
488
|
+
() => {
|
|
489
|
+
const cur = parseInt(input.value, 10) || 1;
|
|
490
|
+
if (cur > 1) {
|
|
491
|
+
input.value = (cur - 1).toString();
|
|
492
|
+
action.execute("prev", cur - 1);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
475
495
|
);
|
|
476
496
|
const nextBtn = this.createButton(
|
|
477
497
|
"next",
|
|
478
498
|
ICON_PAGE_NEXT,
|
|
479
499
|
"Next Page",
|
|
480
|
-
() =>
|
|
500
|
+
() => {
|
|
501
|
+
const cur = parseInt(input.value, 10) || 1;
|
|
502
|
+
const max = action.max ?? 1;
|
|
503
|
+
if (cur < max) {
|
|
504
|
+
input.value = (cur + 1).toString();
|
|
505
|
+
action.execute("next", cur + 1);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
481
508
|
);
|
|
482
509
|
const input = createElement("input", {
|
|
483
510
|
className: "fp-toolbar-input",
|
|
@@ -487,7 +514,10 @@ var ToolbarController = class {
|
|
|
487
514
|
max: (action.max ?? 1).toString()
|
|
488
515
|
});
|
|
489
516
|
input.addEventListener("change", () => {
|
|
490
|
-
|
|
517
|
+
const val = parseInt(input.value, 10);
|
|
518
|
+
if (!isNaN(val)) {
|
|
519
|
+
action.execute("go", val);
|
|
520
|
+
}
|
|
491
521
|
});
|
|
492
522
|
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${action.max ?? 1}`);
|
|
493
523
|
groupEl.appendChild(prevBtn);
|
|
@@ -528,11 +558,11 @@ var ToolbarController = class {
|
|
|
528
558
|
type: "button",
|
|
529
559
|
"data-action-id": id
|
|
530
560
|
});
|
|
531
|
-
const svg = ICON_MAP[iconHtml] || iconHtml;
|
|
532
|
-
if (svg
|
|
561
|
+
const svg = ICON_MAP[iconHtml] || ICON_MAP[id] || (iconHtml && iconHtml.startsWith("<svg") ? iconHtml : null);
|
|
562
|
+
if (svg) {
|
|
533
563
|
btn.innerHTML = sanitizeSVG(svg);
|
|
534
564
|
} else {
|
|
535
|
-
btn.textContent =
|
|
565
|
+
btn.textContent = title || id;
|
|
536
566
|
}
|
|
537
567
|
btn.addEventListener("click", onClick);
|
|
538
568
|
return btn;
|
|
@@ -1275,12 +1305,12 @@ function pdfPlugin() {
|
|
|
1275
1305
|
}
|
|
1276
1306
|
|
|
1277
1307
|
// ../plugins/media/dist/index.js
|
|
1278
|
-
var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg"];
|
|
1279
|
-
var VIDEO_EXTS = [".mp4", ".webm", ".ogg"];
|
|
1280
|
-
var AUDIO_EXTS = [".mp3", ".wav", ".ogg"];
|
|
1308
|
+
var IMAGE_EXTS = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".bmp", ".ico", ".tiff", ".tif", ".avif"];
|
|
1309
|
+
var VIDEO_EXTS = [".mp4", ".m4v", ".webm", ".ogv", ".ogg", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".3gp", ".mpg", ".mpeg"];
|
|
1310
|
+
var AUDIO_EXTS = [".mp3", ".wav", ".ogg", ".flac", ".aac", ".m4a", ".wma", ".opus", ".weba"];
|
|
1281
1311
|
var MediaPlugin = class {
|
|
1282
1312
|
id = "media";
|
|
1283
|
-
name = "Media Preview";
|
|
1313
|
+
name = "Media Preview (Image, Video, Audio)";
|
|
1284
1314
|
extensions = [...IMAGE_EXTS, ...VIDEO_EXTS, ...AUDIO_EXTS];
|
|
1285
1315
|
mimeTypes = [
|
|
1286
1316
|
"image/jpeg",
|
|
@@ -1288,12 +1318,29 @@ var MediaPlugin = class {
|
|
|
1288
1318
|
"image/gif",
|
|
1289
1319
|
"image/webp",
|
|
1290
1320
|
"image/svg+xml",
|
|
1321
|
+
"image/bmp",
|
|
1322
|
+
"image/x-icon",
|
|
1323
|
+
"image/tiff",
|
|
1324
|
+
"image/avif",
|
|
1291
1325
|
"video/mp4",
|
|
1292
1326
|
"video/webm",
|
|
1293
1327
|
"video/ogg",
|
|
1328
|
+
"video/quicktime",
|
|
1329
|
+
"video/x-msvideo",
|
|
1330
|
+
"video/x-matroska",
|
|
1331
|
+
"video/x-flv",
|
|
1332
|
+
"video/x-ms-wmv",
|
|
1333
|
+
"video/3gpp",
|
|
1334
|
+
"video/mpeg",
|
|
1294
1335
|
"audio/mpeg",
|
|
1295
1336
|
"audio/wav",
|
|
1296
|
-
"audio/ogg"
|
|
1337
|
+
"audio/ogg",
|
|
1338
|
+
"audio/flac",
|
|
1339
|
+
"audio/aac",
|
|
1340
|
+
"audio/mp4",
|
|
1341
|
+
"audio/x-ms-wma",
|
|
1342
|
+
"audio/opus",
|
|
1343
|
+
"audio/webm"
|
|
1297
1344
|
];
|
|
1298
1345
|
weight = 90;
|
|
1299
1346
|
supports(file) {
|
|
@@ -1349,6 +1396,16 @@ var MediaPlugin = class {
|
|
|
1349
1396
|
}
|
|
1350
1397
|
if (instance.play) {
|
|
1351
1398
|
actions.push(
|
|
1399
|
+
{
|
|
1400
|
+
id: "replay-10",
|
|
1401
|
+
icon: "replay-10",
|
|
1402
|
+
label: "Rewind 10s",
|
|
1403
|
+
type: "button",
|
|
1404
|
+
group: "actions",
|
|
1405
|
+
execute: () => {
|
|
1406
|
+
instance.rewind?.(10);
|
|
1407
|
+
}
|
|
1408
|
+
},
|
|
1352
1409
|
{
|
|
1353
1410
|
id: "play",
|
|
1354
1411
|
icon: "play",
|
|
@@ -1368,6 +1425,26 @@ var MediaPlugin = class {
|
|
|
1368
1425
|
execute: () => {
|
|
1369
1426
|
instance.pause?.();
|
|
1370
1427
|
}
|
|
1428
|
+
},
|
|
1429
|
+
{
|
|
1430
|
+
id: "forward-10",
|
|
1431
|
+
icon: "forward-10",
|
|
1432
|
+
label: "Fast Forward 10s",
|
|
1433
|
+
type: "button",
|
|
1434
|
+
group: "actions",
|
|
1435
|
+
execute: () => {
|
|
1436
|
+
instance.fastForward?.(10);
|
|
1437
|
+
}
|
|
1438
|
+
},
|
|
1439
|
+
{
|
|
1440
|
+
id: "speed",
|
|
1441
|
+
icon: "speed",
|
|
1442
|
+
label: "Playback Speed",
|
|
1443
|
+
type: "button",
|
|
1444
|
+
group: "actions",
|
|
1445
|
+
execute: () => {
|
|
1446
|
+
instance.cycleSpeed?.();
|
|
1447
|
+
}
|
|
1371
1448
|
}
|
|
1372
1449
|
);
|
|
1373
1450
|
}
|
|
@@ -1426,8 +1503,12 @@ var MediaPlugin = class {
|
|
|
1426
1503
|
const video = document.createElement("video");
|
|
1427
1504
|
video.src = url;
|
|
1428
1505
|
video.controls = true;
|
|
1429
|
-
video.
|
|
1430
|
-
video.style.
|
|
1506
|
+
video.playsInline = true;
|
|
1507
|
+
video.style.maxWidth = "90%";
|
|
1508
|
+
video.style.maxHeight = "90%";
|
|
1509
|
+
video.style.borderRadius = "8px";
|
|
1510
|
+
video.style.boxShadow = "0 8px 30px rgba(0,0,0,0.3)";
|
|
1511
|
+
video.style.backgroundColor = "#000000";
|
|
1431
1512
|
element = video;
|
|
1432
1513
|
mediaElement = video;
|
|
1433
1514
|
} else if (isAudio) {
|
|
@@ -1486,6 +1567,28 @@ var MediaPlugin = class {
|
|
|
1486
1567
|
play: mediaElement ? () => mediaElement?.play() : void 0,
|
|
1487
1568
|
pause: mediaElement ? () => mediaElement?.pause() : void 0,
|
|
1488
1569
|
isPlaying: mediaElement ? () => !mediaElement?.paused : void 0,
|
|
1570
|
+
fastForward: mediaElement ? (seconds = 10) => {
|
|
1571
|
+
if (mediaElement) {
|
|
1572
|
+
mediaElement.currentTime = Math.min(mediaElement.duration || Infinity, mediaElement.currentTime + seconds);
|
|
1573
|
+
}
|
|
1574
|
+
} : void 0,
|
|
1575
|
+
rewind: mediaElement ? (seconds = 10) => {
|
|
1576
|
+
if (mediaElement) {
|
|
1577
|
+
mediaElement.currentTime = Math.max(0, mediaElement.currentTime - seconds);
|
|
1578
|
+
}
|
|
1579
|
+
} : void 0,
|
|
1580
|
+
cycleSpeed: mediaElement ? () => {
|
|
1581
|
+
if (mediaElement) {
|
|
1582
|
+
const speeds = [1, 1.25, 1.5, 2, 0.5];
|
|
1583
|
+
const curIndex = speeds.indexOf(mediaElement.playbackRate);
|
|
1584
|
+
const nextIndex = curIndex === -1 ? 0 : (curIndex + 1) % speeds.length;
|
|
1585
|
+
mediaElement.playbackRate = speeds[nextIndex];
|
|
1586
|
+
}
|
|
1587
|
+
} : void 0,
|
|
1588
|
+
setPlaybackRate: mediaElement ? (rate) => {
|
|
1589
|
+
if (mediaElement) mediaElement.playbackRate = rate;
|
|
1590
|
+
} : void 0,
|
|
1591
|
+
getPlaybackRate: mediaElement ? () => mediaElement?.playbackRate ?? 1 : void 0,
|
|
1489
1592
|
download: () => {
|
|
1490
1593
|
const a = document.createElement("a");
|
|
1491
1594
|
a.href = url;
|
|
@@ -1503,7 +1606,7 @@ function mediaPlugin() {
|
|
|
1503
1606
|
}
|
|
1504
1607
|
var DocxPlugin = class {
|
|
1505
1608
|
id = "docx";
|
|
1506
|
-
name = "Word Document Preview";
|
|
1609
|
+
name = "Word Document Preview (.docx, .docm, .dotx, .dotm)";
|
|
1507
1610
|
extensions = [".docx", ".docm", ".dotx", ".dotm"];
|
|
1508
1611
|
mimeTypes = [
|
|
1509
1612
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
@@ -1525,9 +1628,7 @@ var DocxPlugin = class {
|
|
|
1525
1628
|
label: "Zoom Out",
|
|
1526
1629
|
type: "button",
|
|
1527
1630
|
group: "zoom",
|
|
1528
|
-
execute: () =>
|
|
1529
|
-
instance.zoomOut?.();
|
|
1530
|
-
}
|
|
1631
|
+
execute: () => instance.zoomOut?.()
|
|
1531
1632
|
},
|
|
1532
1633
|
{
|
|
1533
1634
|
id: "zoom-in",
|
|
@@ -1535,9 +1636,7 @@ var DocxPlugin = class {
|
|
|
1535
1636
|
label: "Zoom In",
|
|
1536
1637
|
type: "button",
|
|
1537
1638
|
group: "zoom",
|
|
1538
|
-
execute: () =>
|
|
1539
|
-
instance.zoomIn?.();
|
|
1540
|
-
}
|
|
1639
|
+
execute: () => instance.zoomIn?.()
|
|
1541
1640
|
},
|
|
1542
1641
|
{
|
|
1543
1642
|
id: "fit-page",
|
|
@@ -1545,9 +1644,7 @@ var DocxPlugin = class {
|
|
|
1545
1644
|
label: "Fit to Page",
|
|
1546
1645
|
type: "button",
|
|
1547
1646
|
group: "zoom",
|
|
1548
|
-
execute: () =>
|
|
1549
|
-
instance.fitToPage?.();
|
|
1550
|
-
}
|
|
1647
|
+
execute: () => instance.fitToPage?.()
|
|
1551
1648
|
},
|
|
1552
1649
|
{
|
|
1553
1650
|
id: "download",
|
|
@@ -1555,9 +1652,7 @@ var DocxPlugin = class {
|
|
|
1555
1652
|
label: "Download",
|
|
1556
1653
|
type: "button",
|
|
1557
1654
|
group: "actions",
|
|
1558
|
-
execute: () =>
|
|
1559
|
-
instance.download?.();
|
|
1560
|
-
}
|
|
1655
|
+
execute: () => instance.download?.()
|
|
1561
1656
|
},
|
|
1562
1657
|
{
|
|
1563
1658
|
id: "print",
|
|
@@ -1565,9 +1660,7 @@ var DocxPlugin = class {
|
|
|
1565
1660
|
label: "Print",
|
|
1566
1661
|
type: "button",
|
|
1567
1662
|
group: "actions",
|
|
1568
|
-
execute: () =>
|
|
1569
|
-
instance.print?.();
|
|
1570
|
-
}
|
|
1663
|
+
execute: () => instance.print?.()
|
|
1571
1664
|
}
|
|
1572
1665
|
];
|
|
1573
1666
|
}
|
|
@@ -1576,27 +1669,81 @@ var DocxPlugin = class {
|
|
|
1576
1669
|
wrapper.className = "fp-docx-wrapper";
|
|
1577
1670
|
wrapper.style.transformOrigin = "top center";
|
|
1578
1671
|
wrapper.style.transition = "transform 0.2s ease";
|
|
1579
|
-
wrapper.style.padding = "16px";
|
|
1672
|
+
wrapper.style.padding = "24px 16px";
|
|
1673
|
+
wrapper.style.maxWidth = "950px";
|
|
1674
|
+
wrapper.style.margin = "0 auto";
|
|
1675
|
+
wrapper.style.boxSizing = "border-box";
|
|
1580
1676
|
ctx.container.style.overflow = "auto";
|
|
1677
|
+
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
1581
1678
|
ctx.container.appendChild(wrapper);
|
|
1679
|
+
const styleOverride = document.createElement("style");
|
|
1680
|
+
styleOverride.textContent = `
|
|
1681
|
+
.fp-docx-wrapper .docx-wrapper {
|
|
1682
|
+
background: transparent !important;
|
|
1683
|
+
padding: 0 !important;
|
|
1684
|
+
display: flex !important;
|
|
1685
|
+
flex-direction: column !important;
|
|
1686
|
+
align-items: center !important;
|
|
1687
|
+
box-sizing: border-box !important;
|
|
1688
|
+
}
|
|
1689
|
+
.fp-docx-wrapper section.docx {
|
|
1690
|
+
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08) !important;
|
|
1691
|
+
border-radius: 4px !important;
|
|
1692
|
+
margin-bottom: 24px !important;
|
|
1693
|
+
background-color: #ffffff !important;
|
|
1694
|
+
}
|
|
1695
|
+
`;
|
|
1696
|
+
ctx.container.appendChild(styleOverride);
|
|
1582
1697
|
let scale = 1;
|
|
1698
|
+
let renderedSuccessfully = false;
|
|
1699
|
+
const createdBlobUrls = [];
|
|
1583
1700
|
try {
|
|
1584
|
-
await docx.renderAsync(ctx.buffer, wrapper,
|
|
1701
|
+
await docx.renderAsync(ctx.buffer, wrapper, wrapper, {
|
|
1585
1702
|
inWrapper: true,
|
|
1586
1703
|
ignoreWidth: false,
|
|
1587
|
-
ignoreHeight: false
|
|
1704
|
+
ignoreHeight: false,
|
|
1705
|
+
ignoreFonts: true,
|
|
1706
|
+
// Avoid crashes on embedded obfuscated fonts
|
|
1707
|
+
breakPages: true,
|
|
1708
|
+
experimental: true
|
|
1588
1709
|
});
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1710
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1711
|
+
ctx.container.appendChild(wrapper);
|
|
1712
|
+
}
|
|
1713
|
+
if (wrapper.children.length > 0 && (wrapper.textContent?.trim().length ?? 0) > 0) {
|
|
1714
|
+
renderedSuccessfully = true;
|
|
1715
|
+
}
|
|
1716
|
+
} catch (err) {
|
|
1717
|
+
console.warn("[DocxPlugin] docx-preview failed, triggering native fallback:", err);
|
|
1718
|
+
}
|
|
1719
|
+
if (!renderedSuccessfully) {
|
|
1720
|
+
try {
|
|
1721
|
+
wrapper.innerHTML = "";
|
|
1722
|
+
this.renderXmlFallback(ctx, wrapper, createdBlobUrls);
|
|
1723
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1724
|
+
ctx.container.appendChild(wrapper);
|
|
1725
|
+
}
|
|
1726
|
+
renderedSuccessfully = true;
|
|
1727
|
+
} catch (fallbackErr) {
|
|
1728
|
+
console.error("[DocxPlugin] Native fallback failed:", fallbackErr);
|
|
1729
|
+
wrapper.innerHTML = `
|
|
1730
|
+
<div style="text-align:center; padding: 48px; background: #fff; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.06);">
|
|
1731
|
+
<div style="font-size:48px; margin-bottom: 16px;">\u{1F4C4}</div>
|
|
1732
|
+
<h3 style="margin: 0 0 8px; color: #1e293b;">${ctx.metadata.name || "Word Document"}</h3>
|
|
1733
|
+
<p style="color: #64748b; margin: 0;">Could not parse document content</p>
|
|
1734
|
+
</div>
|
|
1735
|
+
`;
|
|
1736
|
+
if (!ctx.container.contains(wrapper)) {
|
|
1737
|
+
ctx.container.appendChild(wrapper);
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1597
1740
|
}
|
|
1598
1741
|
const cleanup = () => {
|
|
1742
|
+
for (const url of createdBlobUrls) {
|
|
1743
|
+
URL.revokeObjectURL(url);
|
|
1744
|
+
}
|
|
1599
1745
|
wrapper.remove();
|
|
1746
|
+
styleOverride.remove();
|
|
1600
1747
|
ctx.container.innerHTML = "";
|
|
1601
1748
|
};
|
|
1602
1749
|
ctx.signal.addEventListener("abort", cleanup);
|
|
@@ -1617,7 +1764,7 @@ var DocxPlugin = class {
|
|
|
1617
1764
|
},
|
|
1618
1765
|
fitToPage: () => {
|
|
1619
1766
|
scale = 1;
|
|
1620
|
-
wrapper.style.transform =
|
|
1767
|
+
wrapper.style.transform = "scale(1)";
|
|
1621
1768
|
},
|
|
1622
1769
|
download: () => {
|
|
1623
1770
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
@@ -1633,6 +1780,212 @@ var DocxPlugin = class {
|
|
|
1633
1780
|
}
|
|
1634
1781
|
};
|
|
1635
1782
|
}
|
|
1783
|
+
renderXmlFallback(ctx, wrapper, createdBlobUrls) {
|
|
1784
|
+
const magic = new Uint8Array(ctx.buffer.slice(0, 8));
|
|
1785
|
+
if (magic[0] === 208 && magic[1] === 207 && magic[2] === 17 && magic[3] === 224) {
|
|
1786
|
+
this.renderBinaryDocFallback(ctx, wrapper);
|
|
1787
|
+
return;
|
|
1788
|
+
}
|
|
1789
|
+
const unzipped = unzipSync(new Uint8Array(ctx.buffer));
|
|
1790
|
+
const docKey = Object.keys(unzipped).find((k) => k.replace(/^[./\\]+/, "").toLowerCase() === "word/document.xml");
|
|
1791
|
+
const docXmlEntry = docKey ? unzipped[docKey] : void 0;
|
|
1792
|
+
if (!docXmlEntry) throw new Error("Missing word/document.xml in DOCX package");
|
|
1793
|
+
const xmlStr = strFromU8(docXmlEntry);
|
|
1794
|
+
const parser = new DOMParser();
|
|
1795
|
+
const doc = parser.parseFromString(xmlStr, "application/xml");
|
|
1796
|
+
const imageMap = {};
|
|
1797
|
+
const relsKey = Object.keys(unzipped).find((k) => k.replace(/^[./\\]+/, "").toLowerCase() === "word/_rels/document.xml.rels");
|
|
1798
|
+
if (relsKey && unzipped[relsKey]) {
|
|
1799
|
+
try {
|
|
1800
|
+
const relsXml = strFromU8(unzipped[relsKey]);
|
|
1801
|
+
const relsDoc = parser.parseFromString(relsXml, "application/xml");
|
|
1802
|
+
const relEls = Array.from(relsDoc.getElementsByTagName("Relationship"));
|
|
1803
|
+
for (const rel of relEls) {
|
|
1804
|
+
const rId = rel.getAttribute("Id");
|
|
1805
|
+
const target = rel.getAttribute("Target");
|
|
1806
|
+
if (rId && target) {
|
|
1807
|
+
const cleanTarget = target.replace(/^\.\.\//, "").replace(/^\//, "");
|
|
1808
|
+
const fullTargetKey = Object.keys(unzipped).find((k) => {
|
|
1809
|
+
const norm = k.replace(/^[./\\]+/, "").toLowerCase();
|
|
1810
|
+
return norm === ("word/" + cleanTarget).toLowerCase() || norm === cleanTarget.toLowerCase();
|
|
1811
|
+
});
|
|
1812
|
+
if (fullTargetKey && unzipped[fullTargetKey]) {
|
|
1813
|
+
const bytes = unzipped[fullTargetKey];
|
|
1814
|
+
const ext = cleanTarget.split(".").pop()?.toLowerCase() || "png";
|
|
1815
|
+
const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "gif" ? "image/gif" : ext === "svg" ? "image/svg+xml" : "image/png";
|
|
1816
|
+
const blob = new Blob([bytes], { type: mime });
|
|
1817
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
1818
|
+
imageMap[rId] = blobUrl;
|
|
1819
|
+
createdBlobUrls.push(blobUrl);
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
} catch (relsErr) {
|
|
1824
|
+
console.warn("[DocxPlugin] Error parsing relationships:", relsErr);
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
const card = document.createElement("div");
|
|
1828
|
+
card.className = "fp-docx-page-card";
|
|
1829
|
+
card.style.backgroundColor = "#ffffff";
|
|
1830
|
+
card.style.borderRadius = "6px";
|
|
1831
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
1832
|
+
card.style.padding = "48px 56px";
|
|
1833
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
1834
|
+
card.style.color = "#1e293b";
|
|
1835
|
+
card.style.lineHeight = "1.6";
|
|
1836
|
+
const body = doc.getElementsByTagNameNS("*", "body")[0] || doc.documentElement;
|
|
1837
|
+
let html = "";
|
|
1838
|
+
for (const child of Array.from(body.children)) {
|
|
1839
|
+
const tag = child.localName || child.nodeName.split(":").pop();
|
|
1840
|
+
if (tag === "p") {
|
|
1841
|
+
const pStyle = child.getElementsByTagNameNS("*", "pStyle")[0];
|
|
1842
|
+
const styleVal = pStyle?.getAttribute("w:val") || pStyle?.getAttribute("val") || "";
|
|
1843
|
+
const numPr = child.getElementsByTagNameNS("*", "numPr")[0];
|
|
1844
|
+
const textContent = this.extractParagraphHtml(child, imageMap);
|
|
1845
|
+
if (!textContent.trim()) {
|
|
1846
|
+
html += '<div style="height: 10px;"></div>';
|
|
1847
|
+
continue;
|
|
1848
|
+
}
|
|
1849
|
+
const lowerStyle = styleVal.toLowerCase();
|
|
1850
|
+
if (lowerStyle.includes("title")) {
|
|
1851
|
+
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>`;
|
|
1852
|
+
} else if (lowerStyle.includes("heading1") || styleVal === "1") {
|
|
1853
|
+
html += `<h2 style="font-size: 22px; font-weight: 700; color: #1e40af; margin: 20px 0 10px;">${textContent}</h2>`;
|
|
1854
|
+
} else if (lowerStyle.includes("heading2") || styleVal === "2") {
|
|
1855
|
+
html += `<h3 style="font-size: 18px; font-weight: 600; color: #2563eb; margin: 16px 0 8px;">${textContent}</h3>`;
|
|
1856
|
+
} else if (lowerStyle.includes("heading3") || styleVal === "3") {
|
|
1857
|
+
html += `<h4 style="font-size: 15px; font-weight: 600; color: #334155; margin: 12px 0 6px;">${textContent}</h4>`;
|
|
1858
|
+
} else if (numPr) {
|
|
1859
|
+
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>`;
|
|
1860
|
+
} else {
|
|
1861
|
+
html += `<p style="margin: 8px 0; font-size: 14px;">${textContent}</p>`;
|
|
1862
|
+
}
|
|
1863
|
+
} else if (tag === "tbl") {
|
|
1864
|
+
html += '<table style="width: 100%; border-collapse: collapse; margin: 20px 0; border: 1px solid #cbd5e1;">';
|
|
1865
|
+
const rows = Array.from(child.getElementsByTagNameNS("*", "tr"));
|
|
1866
|
+
rows.forEach((tr, rIdx) => {
|
|
1867
|
+
html += `<tr style="${rIdx === 0 ? "background-color: #f8fafc; font-weight: 600;" : ""}">`;
|
|
1868
|
+
const cells = Array.from(tr.getElementsByTagNameNS("*", "tc"));
|
|
1869
|
+
cells.forEach((tc) => {
|
|
1870
|
+
const cellText = this.extractParagraphHtml(tc, imageMap);
|
|
1871
|
+
html += `<td style="border: 1px solid #cbd5e1; padding: 8px 12px; font-size: 13px;">${cellText || " "}</td>`;
|
|
1872
|
+
});
|
|
1873
|
+
html += "</tr>";
|
|
1874
|
+
});
|
|
1875
|
+
html += "</table>";
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
card.innerHTML = DOMPurify2.sanitize(html, {
|
|
1879
|
+
ADD_TAGS: ["h1", "h2", "h3", "h4", "p", "table", "tr", "td", "span", "b", "i", "u", "s", "strike", "img", "div", "br"],
|
|
1880
|
+
ADD_ATTR: ["style", "src", "alt", "colspan", "rowspan"]
|
|
1881
|
+
});
|
|
1882
|
+
wrapper.appendChild(card);
|
|
1883
|
+
}
|
|
1884
|
+
extractParagraphHtml(pElement, imageMap = {}) {
|
|
1885
|
+
let result = "";
|
|
1886
|
+
const drawings = Array.from(pElement.getElementsByTagNameNS("*", "drawing"));
|
|
1887
|
+
for (const drawing of drawings) {
|
|
1888
|
+
const blip = drawing.getElementsByTagNameNS("*", "blip")[0];
|
|
1889
|
+
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
1890
|
+
if (rId && imageMap[rId]) {
|
|
1891
|
+
result += `<div style="text-align:center; margin: 12px 0;"><img src="${imageMap[rId]}" style="max-width: 100%; height: auto; border-radius: 4px;" /></div>`;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
const runs = Array.from(pElement.getElementsByTagNameNS("*", "r"));
|
|
1895
|
+
if (runs.length === 0 && !result) {
|
|
1896
|
+
return DOMPurify2.sanitize(pElement.textContent || "");
|
|
1897
|
+
}
|
|
1898
|
+
for (const r of runs) {
|
|
1899
|
+
const blip = r.getElementsByTagNameNS("*", "blip")[0] || r.getElementsByTagNameNS("*", "imagedata")[0];
|
|
1900
|
+
const rId = blip?.getAttribute("r:embed") || blip?.getAttribute("r:id");
|
|
1901
|
+
if (rId && imageMap[rId]) {
|
|
1902
|
+
result += `<img src="${imageMap[rId]}" style="max-width: 100%; height: auto; display: inline-block; margin: 4px;" />`;
|
|
1903
|
+
}
|
|
1904
|
+
const brs = r.getElementsByTagNameNS("*", "br");
|
|
1905
|
+
for (let i = 0; i < brs.length; i++) {
|
|
1906
|
+
result += "<br/>";
|
|
1907
|
+
}
|
|
1908
|
+
const tabs = r.getElementsByTagNameNS("*", "tab");
|
|
1909
|
+
if (tabs.length > 0) {
|
|
1910
|
+
result += " ";
|
|
1911
|
+
}
|
|
1912
|
+
const rPr = r.getElementsByTagNameNS("*", "rPr")[0];
|
|
1913
|
+
const isBold = !!rPr?.getElementsByTagNameNS("*", "b")[0];
|
|
1914
|
+
const isItalic = !!rPr?.getElementsByTagNameNS("*", "i")[0];
|
|
1915
|
+
const isUnderline = !!rPr?.getElementsByTagNameNS("*", "u")[0];
|
|
1916
|
+
const isStrike = !!rPr?.getElementsByTagNameNS("*", "strike")[0];
|
|
1917
|
+
const colorNode = rPr?.getElementsByTagNameNS("*", "color")[0];
|
|
1918
|
+
const colorVal = colorNode?.getAttribute("w:val") || colorNode?.getAttribute("val");
|
|
1919
|
+
const szNode = rPr?.getElementsByTagNameNS("*", "sz")[0];
|
|
1920
|
+
const szVal = szNode?.getAttribute("w:val") || szNode?.getAttribute("val");
|
|
1921
|
+
const texts = Array.from(r.getElementsByTagNameNS("*", "t"));
|
|
1922
|
+
let text = texts.map((t) => t.textContent || "").join("");
|
|
1923
|
+
if (!text) continue;
|
|
1924
|
+
text = DOMPurify2.sanitize(text);
|
|
1925
|
+
let styles = "";
|
|
1926
|
+
if (isBold) styles += "font-weight: bold; ";
|
|
1927
|
+
if (isItalic) styles += "font-style: italic; ";
|
|
1928
|
+
if (isUnderline) styles += "text-decoration: underline; ";
|
|
1929
|
+
if (isStrike) styles += "text-decoration: line-through; ";
|
|
1930
|
+
if (colorVal && colorVal !== "auto") styles += `color: #${colorVal}; `;
|
|
1931
|
+
if (szVal) {
|
|
1932
|
+
const pt = parseInt(szVal, 10) / 2;
|
|
1933
|
+
if (!isNaN(pt) && pt > 0) styles += `font-size: ${pt}pt; `;
|
|
1934
|
+
}
|
|
1935
|
+
if (styles) {
|
|
1936
|
+
result += `<span style="${styles}">${text}</span>`;
|
|
1937
|
+
} else {
|
|
1938
|
+
result += text;
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
return result;
|
|
1942
|
+
}
|
|
1943
|
+
renderBinaryDocFallback(ctx, wrapper) {
|
|
1944
|
+
const card = document.createElement("div");
|
|
1945
|
+
card.className = "fp-docx-page-card";
|
|
1946
|
+
card.style.backgroundColor = "#ffffff";
|
|
1947
|
+
card.style.borderRadius = "6px";
|
|
1948
|
+
card.style.boxShadow = "0 4px 24px rgba(0,0,0,0.08)";
|
|
1949
|
+
card.style.padding = "48px 56px";
|
|
1950
|
+
card.style.fontFamily = 'Calibri, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
|
1951
|
+
card.style.color = "#1e293b";
|
|
1952
|
+
card.style.lineHeight = "1.6";
|
|
1953
|
+
try {
|
|
1954
|
+
const cfbf = new CfbfReader(ctx.buffer);
|
|
1955
|
+
const wordDocStream = cfbf.readStream("WordDocument");
|
|
1956
|
+
if (wordDocStream && wordDocStream.length >= 512) {
|
|
1957
|
+
const text2 = this.extractReadableStrings(wordDocStream);
|
|
1958
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2.sanitize(text2)}</div>`;
|
|
1959
|
+
wrapper.appendChild(card);
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1962
|
+
} catch {
|
|
1963
|
+
}
|
|
1964
|
+
const text = this.extractReadableStrings(new Uint8Array(ctx.buffer));
|
|
1965
|
+
card.innerHTML = `<div style="white-space: pre-wrap;">${DOMPurify2.sanitize(text)}</div>`;
|
|
1966
|
+
wrapper.appendChild(card);
|
|
1967
|
+
}
|
|
1968
|
+
extractReadableStrings(bytes) {
|
|
1969
|
+
let result = "";
|
|
1970
|
+
let current = "";
|
|
1971
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1972
|
+
const b = bytes[i];
|
|
1973
|
+
if (b >= 32 && b <= 126 || b === 10 || b === 13 || b === 9) {
|
|
1974
|
+
current += String.fromCharCode(b);
|
|
1975
|
+
} else if (b === 0 && i + 1 < bytes.length && bytes[i + 1] >= 32 && bytes[i + 1] <= 126) {
|
|
1976
|
+
continue;
|
|
1977
|
+
} else {
|
|
1978
|
+
if (current.trim().length > 3) {
|
|
1979
|
+
result += current.trim() + "\n\n";
|
|
1980
|
+
}
|
|
1981
|
+
current = "";
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
if (current.trim().length > 3) {
|
|
1985
|
+
result += current.trim();
|
|
1986
|
+
}
|
|
1987
|
+
return result;
|
|
1988
|
+
}
|
|
1636
1989
|
};
|
|
1637
1990
|
function docxPlugin() {
|
|
1638
1991
|
return new DocxPlugin();
|
|
@@ -2444,7 +2797,7 @@ var MarkdownPlugin = class {
|
|
|
2444
2797
|
gfm: true,
|
|
2445
2798
|
breaks: true
|
|
2446
2799
|
});
|
|
2447
|
-
const cleanHtml =
|
|
2800
|
+
const cleanHtml = DOMPurify2.sanitize(rawHtml, {
|
|
2448
2801
|
USE_PROFILES: { html: true }
|
|
2449
2802
|
});
|
|
2450
2803
|
const wrapper = document.createElement("div");
|
|
@@ -2608,35 +2961,27 @@ var PptxPlugin = class {
|
|
|
2608
2961
|
group: "navigation",
|
|
2609
2962
|
execute: () => instance.toggleThumbnails?.()
|
|
2610
2963
|
},
|
|
2611
|
-
{
|
|
2612
|
-
id: "page-prev",
|
|
2613
|
-
icon: "page-prev",
|
|
2614
|
-
label: "Previous Slide",
|
|
2615
|
-
type: "button",
|
|
2616
|
-
group: "navigation",
|
|
2617
|
-
execute: () => {
|
|
2618
|
-
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2619
|
-
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2620
|
-
}
|
|
2621
|
-
},
|
|
2622
2964
|
{
|
|
2623
2965
|
id: "page-nav",
|
|
2624
2966
|
icon: "",
|
|
2625
|
-
label: "Slide
|
|
2967
|
+
label: "Slide Navigation",
|
|
2626
2968
|
type: "page-nav",
|
|
2627
2969
|
group: "navigation",
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2970
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2971
|
+
max: instance.getPageCount?.() ?? 1,
|
|
2972
|
+
execute: (action, page) => {
|
|
2973
|
+
if (action === "prev") {
|
|
2974
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2975
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2976
|
+
} else if (action === "next") {
|
|
2977
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2978
|
+
const total = instance.getPageCount?.() ?? 1;
|
|
2979
|
+
if (cur < total) instance.goToPage?.(cur + 1);
|
|
2980
|
+
} else if (typeof page === "number") {
|
|
2981
|
+
instance.goToPage?.(page);
|
|
2982
|
+
} else if (typeof action === "number") {
|
|
2983
|
+
instance.goToPage?.(action);
|
|
2984
|
+
}
|
|
2640
2985
|
}
|
|
2641
2986
|
},
|
|
2642
2987
|
{
|
|
@@ -3167,7 +3512,7 @@ var HtmlPreviewPlugin = class {
|
|
|
3167
3512
|
}
|
|
3168
3513
|
async render(ctx) {
|
|
3169
3514
|
const rawHtml = new TextDecoder("utf-8").decode(ctx.buffer);
|
|
3170
|
-
const sanitized =
|
|
3515
|
+
const sanitized = DOMPurify2.sanitize(rawHtml, {
|
|
3171
3516
|
WHOLE_DOCUMENT: true,
|
|
3172
3517
|
ADD_TAGS: ["style", "link"],
|
|
3173
3518
|
ADD_ATTR: ["target", "rel"]
|
|
@@ -3262,35 +3607,27 @@ var OpenDocumentPlugin = class {
|
|
|
3262
3607
|
group: "navigation",
|
|
3263
3608
|
execute: () => instance.toggleThumbnails?.()
|
|
3264
3609
|
},
|
|
3265
|
-
{
|
|
3266
|
-
id: "page-prev",
|
|
3267
|
-
icon: "page-prev",
|
|
3268
|
-
label: "Previous Slide",
|
|
3269
|
-
type: "button",
|
|
3270
|
-
group: "navigation",
|
|
3271
|
-
execute: () => {
|
|
3272
|
-
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3273
|
-
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3274
|
-
}
|
|
3275
|
-
},
|
|
3276
3610
|
{
|
|
3277
3611
|
id: "page-nav",
|
|
3278
3612
|
icon: "",
|
|
3279
|
-
label: "Slide
|
|
3613
|
+
label: "Slide Navigation",
|
|
3280
3614
|
type: "page-nav",
|
|
3281
3615
|
group: "navigation",
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3616
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3617
|
+
max: instance.getPageCount?.() ?? 1,
|
|
3618
|
+
execute: (action, page) => {
|
|
3619
|
+
if (action === "prev") {
|
|
3620
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3621
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3622
|
+
} else if (action === "next") {
|
|
3623
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3624
|
+
const total = instance.getPageCount?.() ?? 1;
|
|
3625
|
+
if (cur < total) instance.goToPage?.(cur + 1);
|
|
3626
|
+
} else if (typeof page === "number") {
|
|
3627
|
+
instance.goToPage?.(page);
|
|
3628
|
+
} else if (typeof action === "number") {
|
|
3629
|
+
instance.goToPage?.(action);
|
|
3630
|
+
}
|
|
3294
3631
|
}
|
|
3295
3632
|
}
|
|
3296
3633
|
);
|
|
@@ -3418,7 +3755,7 @@ var OpenDocumentPlugin = class {
|
|
|
3418
3755
|
wrapper.style.padding = "48px";
|
|
3419
3756
|
wrapper.style.minHeight = "100%";
|
|
3420
3757
|
const bodyHtml = this.renderOdfBody(contentDoc, styleMap, imageUrls);
|
|
3421
|
-
wrapper.innerHTML =
|
|
3758
|
+
wrapper.innerHTML = DOMPurify2.sanitize(bodyHtml, {
|
|
3422
3759
|
ADD_TAGS: ["math", "semantics", "mrow", "mi", "mo", "mn", "msup", "msub"],
|
|
3423
3760
|
ADD_ATTR: ["style", "colspan", "rowspan"]
|
|
3424
3761
|
});
|
|
@@ -3938,24 +4275,24 @@ var DocPlugin = class {
|
|
|
3938
4275
|
html += "</ul>";
|
|
3939
4276
|
inList = false;
|
|
3940
4277
|
}
|
|
3941
|
-
html += `<h2 style="font-size: 18px; font-weight: 700; color: #1e3a8a; margin: 20px 0 8px; border-bottom: 1px solid #e2e8f0; padding-bottom: 4px;">${
|
|
4278
|
+
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>`;
|
|
3942
4279
|
} else if (line.startsWith("\u2022") || line.startsWith("-") || line.startsWith("*")) {
|
|
3943
4280
|
if (!inList) {
|
|
3944
4281
|
html += '<ul style="margin: 8px 0; padding-left: 24px;">';
|
|
3945
4282
|
inList = true;
|
|
3946
4283
|
}
|
|
3947
4284
|
const bulletText = line.replace(/^[•\-\*]\s*/, "");
|
|
3948
|
-
html += `<li style="margin: 4px 0; line-height: 1.6;">${
|
|
4285
|
+
html += `<li style="margin: 4px 0; line-height: 1.6;">${DOMPurify2.sanitize(bulletText)}</li>`;
|
|
3949
4286
|
} else {
|
|
3950
4287
|
if (inList) {
|
|
3951
4288
|
html += "</ul>";
|
|
3952
4289
|
inList = false;
|
|
3953
4290
|
}
|
|
3954
|
-
html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${
|
|
4291
|
+
html += `<p style="line-height: 1.7; margin: 10px 0; font-size: 14px; text-align: justify;">${DOMPurify2.sanitize(line)}</p>`;
|
|
3955
4292
|
}
|
|
3956
4293
|
}
|
|
3957
4294
|
if (inList) html += "</ul>";
|
|
3958
|
-
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${
|
|
4295
|
+
return html || `<p style="color: #64748b; font-style: italic;">(No readable text found in ${DOMPurify2.sanitize(filename)})</p>`;
|
|
3959
4296
|
}
|
|
3960
4297
|
};
|
|
3961
4298
|
function docPlugin() {
|
|
@@ -3982,35 +4319,27 @@ var PptPlugin = class {
|
|
|
3982
4319
|
group: "navigation",
|
|
3983
4320
|
execute: () => instance.toggleThumbnails?.()
|
|
3984
4321
|
},
|
|
3985
|
-
{
|
|
3986
|
-
id: "page-prev",
|
|
3987
|
-
icon: "page-prev",
|
|
3988
|
-
label: "Previous Slide",
|
|
3989
|
-
type: "button",
|
|
3990
|
-
group: "navigation",
|
|
3991
|
-
execute: () => {
|
|
3992
|
-
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3993
|
-
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3994
|
-
}
|
|
3995
|
-
},
|
|
3996
4322
|
{
|
|
3997
4323
|
id: "page-nav",
|
|
3998
4324
|
icon: "",
|
|
3999
|
-
label: "Slide
|
|
4325
|
+
label: "Slide Navigation",
|
|
4000
4326
|
type: "page-nav",
|
|
4001
4327
|
group: "navigation",
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4328
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4329
|
+
max: instance.getPageCount?.() ?? 1,
|
|
4330
|
+
execute: (action, page) => {
|
|
4331
|
+
if (action === "prev") {
|
|
4332
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4333
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4334
|
+
} else if (action === "next") {
|
|
4335
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4336
|
+
const total = instance.getPageCount?.() ?? 1;
|
|
4337
|
+
if (cur < total) instance.goToPage?.(cur + 1);
|
|
4338
|
+
} else if (typeof page === "number") {
|
|
4339
|
+
instance.goToPage?.(page);
|
|
4340
|
+
} else if (typeof action === "number") {
|
|
4341
|
+
instance.goToPage?.(action);
|
|
4342
|
+
}
|
|
4014
4343
|
}
|
|
4015
4344
|
},
|
|
4016
4345
|
{
|
|
@@ -4118,10 +4447,10 @@ var PptPlugin = class {
|
|
|
4118
4447
|
</div>
|
|
4119
4448
|
<div style="text-align: center; width: 100%;">
|
|
4120
4449
|
<h1 style="font-size: ${idx === 1 ? "36px" : "28px"}; color: #1e3a8a; margin: 0 0 24px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; font-weight: 700;">
|
|
4121
|
-
${
|
|
4450
|
+
${DOMPurify2.sanitize(s.title || `Slide ${idx}`)}
|
|
4122
4451
|
</h1>
|
|
4123
4452
|
<div style="display: flex; flex-direction: column; gap: 12px; max-width: 80%; margin: 0 auto; text-align: ${idx === 1 ? "center" : "left"};">
|
|
4124
|
-
${s.texts.map((t) => `<div style="font-size: 18px; color: #334155; line-height: 1.5; font-family: -apple-system, BlinkMacSystemFont, sans-serif;">${
|
|
4453
|
+
${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("")}
|
|
4125
4454
|
</div>
|
|
4126
4455
|
</div>
|
|
4127
4456
|
`;
|