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