@files-preview-app/preview-file 1.2.4 → 1.2.6
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 +1043 -211
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +1042 -211
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +1043 -211
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1042 -211
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1043 -211
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +1042 -211
- package/dist/react.js.map +1 -1
- package/dist/styles.css +28 -1
- package/dist/vue.cjs +1043 -211
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +1042 -211
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var DOMPurify2 = require('dompurify');
|
|
4
|
+
var pdfjsLib = require('pdfjs-dist');
|
|
4
5
|
var docx = require('docx-preview');
|
|
5
6
|
var fflate = require('fflate');
|
|
6
7
|
var XLSX = require('xlsx');
|
|
@@ -34,6 +35,7 @@ function _interopNamespace(e) {
|
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
var DOMPurify2__default = /*#__PURE__*/_interopDefault(DOMPurify2);
|
|
38
|
+
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
37
39
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
38
40
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
39
41
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
@@ -551,11 +553,21 @@ var ToolbarController = class {
|
|
|
551
553
|
el;
|
|
552
554
|
toolbarEl;
|
|
553
555
|
actions = [];
|
|
556
|
+
pageInputEl = null;
|
|
557
|
+
pageLabelEl = null;
|
|
554
558
|
constructor(container) {
|
|
555
559
|
this.el = container;
|
|
556
560
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
557
561
|
this.el.appendChild(this.toolbarEl);
|
|
558
562
|
}
|
|
563
|
+
setPage(page, max) {
|
|
564
|
+
if (this.pageInputEl) {
|
|
565
|
+
this.pageInputEl.value = page.toString();
|
|
566
|
+
}
|
|
567
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
568
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
559
571
|
update(actions) {
|
|
560
572
|
this.actions = actions;
|
|
561
573
|
this.render();
|
|
@@ -598,6 +610,7 @@ var ToolbarController = class {
|
|
|
598
610
|
if (action.type === "separator") {
|
|
599
611
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
600
612
|
} else if (action.type === "page-nav") {
|
|
613
|
+
const max = action.max ?? 1;
|
|
601
614
|
const prevBtn = this.createButton(
|
|
602
615
|
"prev",
|
|
603
616
|
ICON_PAGE_PREV,
|
|
@@ -616,7 +629,6 @@ var ToolbarController = class {
|
|
|
616
629
|
"Next Page",
|
|
617
630
|
() => {
|
|
618
631
|
const cur = parseInt(input.value, 10) || 1;
|
|
619
|
-
const max = action.max ?? 1;
|
|
620
632
|
if (cur < max) {
|
|
621
633
|
input.value = (cur + 1).toString();
|
|
622
634
|
action.execute("next", cur + 1);
|
|
@@ -628,15 +640,18 @@ var ToolbarController = class {
|
|
|
628
640
|
type: "number",
|
|
629
641
|
value: (action.value ?? 1).toString(),
|
|
630
642
|
min: "1",
|
|
631
|
-
max:
|
|
643
|
+
max: max.toString()
|
|
632
644
|
});
|
|
633
645
|
input.addEventListener("change", () => {
|
|
634
|
-
|
|
635
|
-
if (
|
|
636
|
-
|
|
637
|
-
|
|
646
|
+
let val = parseInt(input.value, 10);
|
|
647
|
+
if (isNaN(val)) val = 1;
|
|
648
|
+
val = Math.max(1, Math.min(max, val));
|
|
649
|
+
input.value = val.toString();
|
|
650
|
+
action.execute("go", val);
|
|
638
651
|
});
|
|
639
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
652
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
653
|
+
this.pageInputEl = input;
|
|
654
|
+
this.pageLabelEl = label;
|
|
640
655
|
groupEl.appendChild(prevBtn);
|
|
641
656
|
groupEl.appendChild(input);
|
|
642
657
|
groupEl.appendChild(label);
|
|
@@ -763,6 +778,8 @@ var FilePreviewViewer = class {
|
|
|
763
778
|
keyHandler = null;
|
|
764
779
|
currentContainer = null;
|
|
765
780
|
currentOptions = {};
|
|
781
|
+
resizeObserver = null;
|
|
782
|
+
fullscreenHandler = null;
|
|
766
783
|
/**
|
|
767
784
|
* Register a preview plugin.
|
|
768
785
|
*/
|
|
@@ -814,7 +831,13 @@ var FilePreviewViewer = class {
|
|
|
814
831
|
buffer,
|
|
815
832
|
options,
|
|
816
833
|
signal,
|
|
817
|
-
emit: (event, payload) =>
|
|
834
|
+
emit: (event, payload) => {
|
|
835
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
836
|
+
const total = payload.total ?? payload.totalPages;
|
|
837
|
+
this.toolbar?.setPage(payload.page, total);
|
|
838
|
+
}
|
|
839
|
+
this.eventEmitter.emit(event, payload);
|
|
840
|
+
}
|
|
818
841
|
});
|
|
819
842
|
this.activeInstance = instance;
|
|
820
843
|
this.hideLoading();
|
|
@@ -829,12 +852,31 @@ var FilePreviewViewer = class {
|
|
|
829
852
|
label: "Toggle Fullscreen",
|
|
830
853
|
type: "button",
|
|
831
854
|
group: "view",
|
|
832
|
-
execute: () => {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
855
|
+
execute: async () => {
|
|
856
|
+
try {
|
|
857
|
+
const isNativeFs = !!document.fullscreenElement;
|
|
858
|
+
const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
|
|
859
|
+
if (!isNativeFs && !isCssFs) {
|
|
860
|
+
if (this.wrapperEl?.requestFullscreen) {
|
|
861
|
+
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
862
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
863
|
+
});
|
|
864
|
+
} else {
|
|
865
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
866
|
+
}
|
|
867
|
+
} else {
|
|
868
|
+
if (document.fullscreenElement) {
|
|
869
|
+
await document.exitFullscreen().catch(() => {
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
873
|
+
}
|
|
874
|
+
} catch {
|
|
875
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
837
876
|
}
|
|
877
|
+
setTimeout(() => {
|
|
878
|
+
this.activeInstance?.fitToPage?.();
|
|
879
|
+
}, 120);
|
|
838
880
|
}
|
|
839
881
|
});
|
|
840
882
|
}
|
|
@@ -848,6 +890,7 @@ var FilePreviewViewer = class {
|
|
|
848
890
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
849
891
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
850
892
|
instance.goToPage?.(index + 1);
|
|
893
|
+
this.toolbar?.setPage(index + 1);
|
|
851
894
|
});
|
|
852
895
|
if (options.showThumbnails) {
|
|
853
896
|
this.thumbnailPanel.show();
|
|
@@ -883,6 +926,15 @@ var FilePreviewViewer = class {
|
|
|
883
926
|
window.removeEventListener("keydown", this.keyHandler);
|
|
884
927
|
this.keyHandler = null;
|
|
885
928
|
}
|
|
929
|
+
if (this.resizeObserver) {
|
|
930
|
+
this.resizeObserver.disconnect();
|
|
931
|
+
this.resizeObserver = null;
|
|
932
|
+
}
|
|
933
|
+
if (this.fullscreenHandler) {
|
|
934
|
+
document.removeEventListener("fullscreenchange", this.fullscreenHandler);
|
|
935
|
+
document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
936
|
+
this.fullscreenHandler = null;
|
|
937
|
+
}
|
|
886
938
|
this.abort();
|
|
887
939
|
this.destroyInstance();
|
|
888
940
|
this.toolbar?.destroy();
|
|
@@ -962,6 +1014,25 @@ var FilePreviewViewer = class {
|
|
|
962
1014
|
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
|
|
963
1015
|
this.setupKeyboardShortcuts();
|
|
964
1016
|
this.setupDragAndDrop(container, options);
|
|
1017
|
+
this.setupResizeAndFullscreenListeners();
|
|
1018
|
+
}
|
|
1019
|
+
setupResizeAndFullscreenListeners() {
|
|
1020
|
+
if (this.fullscreenHandler) return;
|
|
1021
|
+
this.fullscreenHandler = () => {
|
|
1022
|
+
setTimeout(() => {
|
|
1023
|
+
this.activeInstance?.fitToPage?.();
|
|
1024
|
+
}, 100);
|
|
1025
|
+
};
|
|
1026
|
+
document.addEventListener("fullscreenchange", this.fullscreenHandler);
|
|
1027
|
+
document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
1028
|
+
if (typeof ResizeObserver !== "undefined" && this.contentEl) {
|
|
1029
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
1030
|
+
if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
|
|
1031
|
+
this.activeInstance.fitToPage?.();
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
this.resizeObserver.observe(this.contentEl);
|
|
1035
|
+
}
|
|
965
1036
|
}
|
|
966
1037
|
setupKeyboardShortcuts() {
|
|
967
1038
|
if (this.keyHandler) return;
|
|
@@ -973,9 +1044,13 @@ var FilePreviewViewer = class {
|
|
|
973
1044
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
974
1045
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
975
1046
|
this.activeInstance.goToPage?.(cur + 1);
|
|
1047
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
1048
|
+
this.toolbar?.setPage(nextCur);
|
|
976
1049
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
977
1050
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
978
1051
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
1052
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
1053
|
+
this.toolbar?.setPage(prevCur);
|
|
979
1054
|
} else if (e.key === "+" || e.key === "=") {
|
|
980
1055
|
this.activeInstance.zoomIn?.();
|
|
981
1056
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1241,30 +1316,62 @@ var CfbfReader = class {
|
|
|
1241
1316
|
return result.subarray(0, targetSize);
|
|
1242
1317
|
}
|
|
1243
1318
|
};
|
|
1244
|
-
|
|
1245
|
-
|
|
1319
|
+
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1320
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1321
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1246
1324
|
var PdfPlugin = class {
|
|
1247
1325
|
id = "pdf";
|
|
1248
|
-
name = "PDF Preview";
|
|
1326
|
+
name = "PDF Document Preview";
|
|
1249
1327
|
extensions = [".pdf"];
|
|
1250
1328
|
mimeTypes = ["application/pdf"];
|
|
1251
1329
|
weight = 100;
|
|
1252
1330
|
supports(file) {
|
|
1253
1331
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1254
1332
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1255
|
-
|
|
1333
|
+
if (ext) return this.extensions.includes(ext);
|
|
1334
|
+
return this.mimeTypes.includes(mime || "");
|
|
1256
1335
|
}
|
|
1257
1336
|
getToolbarActions(instance) {
|
|
1337
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1338
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1258
1339
|
return [
|
|
1340
|
+
{
|
|
1341
|
+
id: "thumbnails",
|
|
1342
|
+
icon: "thumbnails",
|
|
1343
|
+
label: "Page Thumbnails",
|
|
1344
|
+
type: "button",
|
|
1345
|
+
group: "navigation",
|
|
1346
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
id: "page-nav",
|
|
1350
|
+
icon: "",
|
|
1351
|
+
label: "Page Navigation",
|
|
1352
|
+
type: "page-nav",
|
|
1353
|
+
group: "navigation",
|
|
1354
|
+
value: curPage,
|
|
1355
|
+
max: totalPages,
|
|
1356
|
+
execute: (action, page) => {
|
|
1357
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1358
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1359
|
+
if (action === "prev") {
|
|
1360
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1361
|
+
} else if (action === "next") {
|
|
1362
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1363
|
+
} else if (typeof page === "number") {
|
|
1364
|
+
instance.goToPage?.(page);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
},
|
|
1259
1368
|
{
|
|
1260
1369
|
id: "zoom-out",
|
|
1261
1370
|
icon: "zoom-out",
|
|
1262
1371
|
label: "Zoom Out",
|
|
1263
1372
|
type: "button",
|
|
1264
1373
|
group: "zoom",
|
|
1265
|
-
execute: () =>
|
|
1266
|
-
instance.zoomOut?.();
|
|
1267
|
-
}
|
|
1374
|
+
execute: () => instance.zoomOut?.()
|
|
1268
1375
|
},
|
|
1269
1376
|
{
|
|
1270
1377
|
id: "zoom-in",
|
|
@@ -1272,9 +1379,7 @@ var PdfPlugin = class {
|
|
|
1272
1379
|
label: "Zoom In",
|
|
1273
1380
|
type: "button",
|
|
1274
1381
|
group: "zoom",
|
|
1275
|
-
execute: () =>
|
|
1276
|
-
instance.zoomIn?.();
|
|
1277
|
-
}
|
|
1382
|
+
execute: () => instance.zoomIn?.()
|
|
1278
1383
|
},
|
|
1279
1384
|
{
|
|
1280
1385
|
id: "fit-page",
|
|
@@ -1282,39 +1387,23 @@ var PdfPlugin = class {
|
|
|
1282
1387
|
label: "Fit to Page",
|
|
1283
1388
|
type: "button",
|
|
1284
1389
|
group: "zoom",
|
|
1285
|
-
execute: () =>
|
|
1286
|
-
instance.fitToPage?.();
|
|
1287
|
-
}
|
|
1390
|
+
execute: () => instance.fitToPage?.()
|
|
1288
1391
|
},
|
|
1289
1392
|
{
|
|
1290
1393
|
id: "rotate-cw",
|
|
1291
1394
|
icon: "rotate-cw",
|
|
1292
|
-
label: "Rotate",
|
|
1395
|
+
label: "Rotate Clockwise",
|
|
1293
1396
|
type: "button",
|
|
1294
1397
|
group: "view",
|
|
1295
|
-
execute: () =>
|
|
1296
|
-
instance.rotateCW?.();
|
|
1297
|
-
}
|
|
1298
|
-
},
|
|
1299
|
-
{
|
|
1300
|
-
id: "page-nav",
|
|
1301
|
-
icon: "page-nav",
|
|
1302
|
-
label: "Page Navigation",
|
|
1303
|
-
type: "page-nav",
|
|
1304
|
-
group: "navigation",
|
|
1305
|
-
execute: (page) => {
|
|
1306
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1307
|
-
}
|
|
1398
|
+
execute: () => instance.rotateCW?.()
|
|
1308
1399
|
},
|
|
1309
1400
|
{
|
|
1310
1401
|
id: "download",
|
|
1311
1402
|
icon: "download",
|
|
1312
|
-
label: "Download",
|
|
1403
|
+
label: "Download PDF",
|
|
1313
1404
|
type: "button",
|
|
1314
1405
|
group: "actions",
|
|
1315
|
-
execute: () =>
|
|
1316
|
-
instance.download?.();
|
|
1317
|
-
}
|
|
1406
|
+
execute: () => instance.download?.()
|
|
1318
1407
|
},
|
|
1319
1408
|
{
|
|
1320
1409
|
id: "print",
|
|
@@ -1322,99 +1411,224 @@ var PdfPlugin = class {
|
|
|
1322
1411
|
label: "Print",
|
|
1323
1412
|
type: "button",
|
|
1324
1413
|
group: "actions",
|
|
1325
|
-
execute: () =>
|
|
1326
|
-
instance.print?.();
|
|
1327
|
-
}
|
|
1414
|
+
execute: () => instance.print?.()
|
|
1328
1415
|
}
|
|
1329
1416
|
];
|
|
1330
1417
|
}
|
|
1331
1418
|
async render(ctx) {
|
|
1332
|
-
const
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1419
|
+
const container = document.createElement("div");
|
|
1420
|
+
container.className = "fp-pdf-container";
|
|
1421
|
+
container.style.width = "100%";
|
|
1422
|
+
container.style.height = "100%";
|
|
1423
|
+
container.style.overflow = "auto";
|
|
1424
|
+
container.style.display = "flex";
|
|
1425
|
+
container.style.flexDirection = "column";
|
|
1426
|
+
container.style.alignItems = "center";
|
|
1427
|
+
container.style.justifyContent = "flex-start";
|
|
1428
|
+
container.style.padding = "20px 16px";
|
|
1429
|
+
container.style.backgroundColor = "#0f172a";
|
|
1430
|
+
container.style.boxSizing = "border-box";
|
|
1431
|
+
container.style.position = "relative";
|
|
1432
|
+
const pageCard = document.createElement("div");
|
|
1433
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1434
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1435
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1436
|
+
pageCard.style.borderRadius = "4px";
|
|
1437
|
+
pageCard.style.overflow = "hidden";
|
|
1438
|
+
pageCard.style.lineHeight = "0";
|
|
1439
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1440
|
+
pageCard.style.position = "relative";
|
|
1441
|
+
pageCard.style.flexShrink = "0";
|
|
1442
|
+
let canvas = document.createElement("canvas");
|
|
1443
|
+
pageCard.appendChild(canvas);
|
|
1444
|
+
container.appendChild(pageCard);
|
|
1445
|
+
const indicator = document.createElement("div");
|
|
1446
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1447
|
+
indicator.style.position = "sticky";
|
|
1448
|
+
indicator.style.bottom = "16px";
|
|
1449
|
+
indicator.style.marginTop = "16px";
|
|
1450
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1451
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1452
|
+
indicator.style.color = "#f8fafc";
|
|
1453
|
+
indicator.style.fontSize = "12px";
|
|
1454
|
+
indicator.style.fontWeight = "600";
|
|
1455
|
+
indicator.style.padding = "5px 14px";
|
|
1456
|
+
indicator.style.borderRadius = "20px";
|
|
1457
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1458
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1459
|
+
indicator.style.zIndex = "10";
|
|
1460
|
+
indicator.style.userSelect = "none";
|
|
1461
|
+
indicator.style.pointerEvents = "none";
|
|
1462
|
+
container.appendChild(indicator);
|
|
1463
|
+
ctx.container.appendChild(container);
|
|
1464
|
+
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1465
|
+
data: new Uint8Array(ctx.buffer),
|
|
1466
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/cmaps/`,
|
|
1467
|
+
cMapPacked: true,
|
|
1468
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/standard_fonts/`
|
|
1469
|
+
});
|
|
1470
|
+
const pdfDoc = await loadingTask.promise;
|
|
1471
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1348
1472
|
let currentPage = 1;
|
|
1349
|
-
let
|
|
1473
|
+
let zoomScale = 1;
|
|
1350
1474
|
let rotation = 0;
|
|
1475
|
+
let currentRenderTask = null;
|
|
1476
|
+
const renderPage = async (pageNum) => {
|
|
1477
|
+
if (currentRenderTask) {
|
|
1478
|
+
try {
|
|
1479
|
+
currentRenderTask.cancel();
|
|
1480
|
+
} catch {
|
|
1481
|
+
}
|
|
1482
|
+
currentRenderTask = null;
|
|
1483
|
+
}
|
|
1484
|
+
const newCanvas = document.createElement("canvas");
|
|
1485
|
+
pageCard.replaceChild(newCanvas, canvas);
|
|
1486
|
+
canvas = newCanvas;
|
|
1487
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1488
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1489
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1490
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1491
|
+
const containerWidth = container.clientWidth || 900;
|
|
1492
|
+
const containerHeight = container.clientHeight || 700;
|
|
1493
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1494
|
+
const availWidth = Math.max(100, containerWidth - 48);
|
|
1495
|
+
const availHeight = Math.max(100, containerHeight - 88);
|
|
1496
|
+
const scaleW = availWidth / unscaledVp.width;
|
|
1497
|
+
const scaleH = availHeight / unscaledVp.height;
|
|
1498
|
+
const fitScale = Math.min(scaleW, scaleH);
|
|
1499
|
+
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1500
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1501
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1502
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1503
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1504
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1505
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1506
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1507
|
+
if (!canvasCtx) return;
|
|
1508
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1509
|
+
currentRenderTask = page.render({
|
|
1510
|
+
canvasContext: canvasCtx,
|
|
1511
|
+
viewport
|
|
1512
|
+
});
|
|
1513
|
+
try {
|
|
1514
|
+
await currentRenderTask.promise;
|
|
1515
|
+
} catch (err) {
|
|
1516
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1517
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1518
|
+
}
|
|
1519
|
+
} finally {
|
|
1520
|
+
currentRenderTask = null;
|
|
1521
|
+
}
|
|
1522
|
+
};
|
|
1523
|
+
await renderPage(1);
|
|
1351
1524
|
const cleanup = () => {
|
|
1352
|
-
|
|
1353
|
-
|
|
1525
|
+
if (currentRenderTask) {
|
|
1526
|
+
try {
|
|
1527
|
+
currentRenderTask.cancel();
|
|
1528
|
+
} catch {
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
try {
|
|
1532
|
+
pdfDoc.destroy();
|
|
1533
|
+
} catch {
|
|
1534
|
+
}
|
|
1535
|
+
container.remove();
|
|
1354
1536
|
ctx.container.innerHTML = "";
|
|
1355
1537
|
};
|
|
1356
1538
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1357
|
-
|
|
1539
|
+
const instance = {
|
|
1358
1540
|
destroy: cleanup,
|
|
1359
1541
|
zoomIn: () => {
|
|
1360
|
-
|
|
1361
|
-
|
|
1542
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1543
|
+
renderPage(currentPage);
|
|
1362
1544
|
},
|
|
1363
1545
|
zoomOut: () => {
|
|
1364
|
-
|
|
1365
|
-
|
|
1546
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1547
|
+
renderPage(currentPage);
|
|
1366
1548
|
},
|
|
1367
|
-
getZoom: () =>
|
|
1549
|
+
getZoom: () => zoomScale,
|
|
1368
1550
|
setZoom: (level) => {
|
|
1369
|
-
|
|
1370
|
-
|
|
1551
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1552
|
+
renderPage(currentPage);
|
|
1371
1553
|
},
|
|
1372
1554
|
fitToPage: () => {
|
|
1373
|
-
|
|
1374
|
-
|
|
1555
|
+
zoomScale = 1;
|
|
1556
|
+
rotation = 0;
|
|
1557
|
+
renderPage(currentPage);
|
|
1375
1558
|
},
|
|
1376
1559
|
rotateCW: () => {
|
|
1377
1560
|
rotation = (rotation + 90) % 360;
|
|
1378
|
-
|
|
1561
|
+
renderPage(currentPage);
|
|
1379
1562
|
},
|
|
1380
1563
|
rotateCCW: () => {
|
|
1381
1564
|
rotation = (rotation - 90 + 360) % 360;
|
|
1382
|
-
|
|
1565
|
+
renderPage(currentPage);
|
|
1383
1566
|
},
|
|
1384
1567
|
getRotation: () => rotation,
|
|
1568
|
+
getPageCount: () => totalPages,
|
|
1569
|
+
getCurrentPage: () => currentPage,
|
|
1385
1570
|
goToPage: (page) => {
|
|
1386
|
-
|
|
1387
|
-
iframe.src = `${url}#page=${page}`;
|
|
1571
|
+
renderPage(page);
|
|
1388
1572
|
},
|
|
1389
|
-
getCurrentPage: () => currentPage,
|
|
1390
1573
|
download: () => {
|
|
1574
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1575
|
+
const url = URL.createObjectURL(blob);
|
|
1391
1576
|
const a = document.createElement("a");
|
|
1392
1577
|
a.href = url;
|
|
1393
1578
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1394
1579
|
a.click();
|
|
1580
|
+
URL.revokeObjectURL(url);
|
|
1395
1581
|
},
|
|
1396
1582
|
print: () => {
|
|
1397
|
-
|
|
1583
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1584
|
+
const url = URL.createObjectURL(blob);
|
|
1585
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1586
|
+
hiddenIframe.style.position = "fixed";
|
|
1587
|
+
hiddenIframe.style.right = "0";
|
|
1588
|
+
hiddenIframe.style.bottom = "0";
|
|
1589
|
+
hiddenIframe.style.width = "0";
|
|
1590
|
+
hiddenIframe.style.height = "0";
|
|
1591
|
+
hiddenIframe.style.border = "0";
|
|
1592
|
+
document.body.appendChild(hiddenIframe);
|
|
1593
|
+
hiddenIframe.src = url;
|
|
1594
|
+
hiddenIframe.onload = () => {
|
|
1595
|
+
setTimeout(() => {
|
|
1596
|
+
hiddenIframe.contentWindow?.print();
|
|
1597
|
+
setTimeout(() => {
|
|
1598
|
+
hiddenIframe.remove();
|
|
1599
|
+
URL.revokeObjectURL(url);
|
|
1600
|
+
}, 1e3);
|
|
1601
|
+
}, 300);
|
|
1602
|
+
};
|
|
1398
1603
|
},
|
|
1399
1604
|
getThumbnails: async () => {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1605
|
+
const thumbnails = [];
|
|
1606
|
+
const count = Math.min(totalPages, 50);
|
|
1607
|
+
for (let i = 1; i <= count; i++) {
|
|
1608
|
+
thumbnails.push({
|
|
1609
|
+
index: i,
|
|
1610
|
+
label: `Page ${i}`,
|
|
1611
|
+
render: async (thumbCanvas) => {
|
|
1612
|
+
try {
|
|
1613
|
+
const p = await pdfDoc.getPage(i);
|
|
1614
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1615
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1616
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1617
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1618
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1619
|
+
if (tCtx) {
|
|
1620
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1621
|
+
}
|
|
1622
|
+
} catch (e) {
|
|
1623
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1412
1624
|
}
|
|
1413
1625
|
}
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1628
|
+
return thumbnails;
|
|
1416
1629
|
}
|
|
1417
1630
|
};
|
|
1631
|
+
return instance;
|
|
1418
1632
|
}
|
|
1419
1633
|
};
|
|
1420
1634
|
function pdfPlugin() {
|
|
@@ -1741,7 +1955,31 @@ var DocxPlugin = class {
|
|
|
1741
1955
|
return this.mimeTypes.includes(mime || "");
|
|
1742
1956
|
}
|
|
1743
1957
|
getToolbarActions(instance) {
|
|
1744
|
-
|
|
1958
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1959
|
+
const actions = [];
|
|
1960
|
+
if (totalPages > 1) {
|
|
1961
|
+
actions.push({
|
|
1962
|
+
id: "page-nav",
|
|
1963
|
+
icon: "",
|
|
1964
|
+
label: "Page Navigation",
|
|
1965
|
+
type: "page-nav",
|
|
1966
|
+
group: "navigation",
|
|
1967
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1968
|
+
max: totalPages,
|
|
1969
|
+
execute: (action, page) => {
|
|
1970
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1971
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1972
|
+
if (action === "prev") {
|
|
1973
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1974
|
+
} else if (action === "next") {
|
|
1975
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1976
|
+
} else if (typeof page === "number") {
|
|
1977
|
+
instance.goToPage?.(page);
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
});
|
|
1981
|
+
}
|
|
1982
|
+
actions.push(
|
|
1745
1983
|
{
|
|
1746
1984
|
id: "zoom-out",
|
|
1747
1985
|
icon: "zoom-out",
|
|
@@ -1766,6 +2004,14 @@ var DocxPlugin = class {
|
|
|
1766
2004
|
group: "zoom",
|
|
1767
2005
|
execute: () => instance.fitToPage?.()
|
|
1768
2006
|
},
|
|
2007
|
+
{
|
|
2008
|
+
id: "rotate-cw",
|
|
2009
|
+
icon: "rotate-cw",
|
|
2010
|
+
label: "Rotate",
|
|
2011
|
+
type: "button",
|
|
2012
|
+
group: "view",
|
|
2013
|
+
execute: () => instance.rotateCW?.()
|
|
2014
|
+
},
|
|
1769
2015
|
{
|
|
1770
2016
|
id: "download",
|
|
1771
2017
|
icon: "download",
|
|
@@ -1782,7 +2028,8 @@ var DocxPlugin = class {
|
|
|
1782
2028
|
group: "actions",
|
|
1783
2029
|
execute: () => instance.print?.()
|
|
1784
2030
|
}
|
|
1785
|
-
|
|
2031
|
+
);
|
|
2032
|
+
return actions;
|
|
1786
2033
|
}
|
|
1787
2034
|
async render(ctx) {
|
|
1788
2035
|
const wrapper = document.createElement("div");
|
|
@@ -1858,7 +2105,71 @@ var DocxPlugin = class {
|
|
|
1858
2105
|
}
|
|
1859
2106
|
}
|
|
1860
2107
|
}
|
|
2108
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2109
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2110
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2111
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2112
|
+
let currentPage = 1;
|
|
2113
|
+
let indicator = null;
|
|
2114
|
+
if (totalPages > 1) {
|
|
2115
|
+
indicator = document.createElement("div");
|
|
2116
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2117
|
+
indicator.style.position = "sticky";
|
|
2118
|
+
indicator.style.bottom = "16px";
|
|
2119
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2120
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2121
|
+
indicator.style.color = "#f8fafc";
|
|
2122
|
+
indicator.style.fontSize = "12px";
|
|
2123
|
+
indicator.style.fontWeight = "600";
|
|
2124
|
+
indicator.style.padding = "5px 14px";
|
|
2125
|
+
indicator.style.borderRadius = "20px";
|
|
2126
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2127
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2128
|
+
indicator.style.zIndex = "10";
|
|
2129
|
+
indicator.style.userSelect = "none";
|
|
2130
|
+
indicator.style.pointerEvents = "none";
|
|
2131
|
+
indicator.style.textAlign = "center";
|
|
2132
|
+
indicator.style.width = "fit-content";
|
|
2133
|
+
indicator.style.margin = "16px auto 0";
|
|
2134
|
+
ctx.container.appendChild(indicator);
|
|
2135
|
+
}
|
|
2136
|
+
const showPage = (pageNum) => {
|
|
2137
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2138
|
+
if (pageElements.length > 1) {
|
|
2139
|
+
pageElements.forEach((sec, idx) => {
|
|
2140
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
if (indicator) {
|
|
2144
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2145
|
+
}
|
|
2146
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2147
|
+
};
|
|
2148
|
+
if (totalPages > 1) {
|
|
2149
|
+
showPage(1);
|
|
2150
|
+
}
|
|
2151
|
+
scale = 1;
|
|
2152
|
+
let rotation = 0;
|
|
2153
|
+
const calculateFitScale = () => {
|
|
2154
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2155
|
+
const elW = activeEl.offsetWidth || 816;
|
|
2156
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2157
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
2158
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
2159
|
+
const sW = availW / elW;
|
|
2160
|
+
const sH = availH / elH;
|
|
2161
|
+
return Math.min(1.1, Math.min(sW, sH));
|
|
2162
|
+
};
|
|
2163
|
+
const applyTransform = () => {
|
|
2164
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2165
|
+
wrapper.style.transformOrigin = "top center";
|
|
2166
|
+
};
|
|
2167
|
+
setTimeout(() => {
|
|
2168
|
+
scale = calculateFitScale();
|
|
2169
|
+
applyTransform();
|
|
2170
|
+
}, 60);
|
|
1861
2171
|
const cleanup = () => {
|
|
2172
|
+
indicator?.remove();
|
|
1862
2173
|
for (const url of createdBlobUrls) {
|
|
1863
2174
|
URL.revokeObjectURL(url);
|
|
1864
2175
|
}
|
|
@@ -1869,22 +2180,36 @@ var DocxPlugin = class {
|
|
|
1869
2180
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1870
2181
|
return {
|
|
1871
2182
|
destroy: cleanup,
|
|
2183
|
+
getPageCount: () => totalPages,
|
|
2184
|
+
getCurrentPage: () => currentPage,
|
|
2185
|
+
goToPage: (page) => {
|
|
2186
|
+
showPage(page);
|
|
2187
|
+
},
|
|
1872
2188
|
zoomIn: () => {
|
|
1873
|
-
scale += 0.
|
|
1874
|
-
|
|
2189
|
+
scale += 0.15;
|
|
2190
|
+
applyTransform();
|
|
1875
2191
|
},
|
|
1876
2192
|
zoomOut: () => {
|
|
1877
|
-
scale = Math.max(0.2, scale - 0.
|
|
1878
|
-
|
|
2193
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2194
|
+
applyTransform();
|
|
1879
2195
|
},
|
|
1880
2196
|
getZoom: () => scale,
|
|
1881
2197
|
setZoom: (level) => {
|
|
1882
2198
|
scale = level;
|
|
1883
|
-
|
|
2199
|
+
applyTransform();
|
|
1884
2200
|
},
|
|
1885
2201
|
fitToPage: () => {
|
|
1886
|
-
scale =
|
|
1887
|
-
|
|
2202
|
+
scale = calculateFitScale();
|
|
2203
|
+
rotation = 0;
|
|
2204
|
+
applyTransform();
|
|
2205
|
+
},
|
|
2206
|
+
rotateCW: () => {
|
|
2207
|
+
rotation = (rotation + 90) % 360;
|
|
2208
|
+
applyTransform();
|
|
2209
|
+
},
|
|
2210
|
+
rotateCCW: () => {
|
|
2211
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2212
|
+
applyTransform();
|
|
1888
2213
|
},
|
|
1889
2214
|
download: () => {
|
|
1890
2215
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
@@ -2133,7 +2458,31 @@ var ExcelPlugin = class {
|
|
|
2133
2458
|
return this.mimeTypes.includes(mime || "");
|
|
2134
2459
|
}
|
|
2135
2460
|
getToolbarActions(instance) {
|
|
2136
|
-
|
|
2461
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2462
|
+
const actions = [];
|
|
2463
|
+
if (totalSheets > 1) {
|
|
2464
|
+
actions.push({
|
|
2465
|
+
id: "page-nav",
|
|
2466
|
+
icon: "",
|
|
2467
|
+
label: "Sheet Navigation",
|
|
2468
|
+
type: "page-nav",
|
|
2469
|
+
group: "navigation",
|
|
2470
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2471
|
+
max: totalSheets,
|
|
2472
|
+
execute: (action, sheet) => {
|
|
2473
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2474
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2475
|
+
if (action === "prev") {
|
|
2476
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2477
|
+
} else if (action === "next") {
|
|
2478
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2479
|
+
} else if (typeof sheet === "number") {
|
|
2480
|
+
instance.goToPage?.(sheet);
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
});
|
|
2484
|
+
}
|
|
2485
|
+
actions.push(
|
|
2137
2486
|
{
|
|
2138
2487
|
id: "zoom-out",
|
|
2139
2488
|
icon: "zoom-out",
|
|
@@ -2155,13 +2504,23 @@ var ExcelPlugin = class {
|
|
|
2155
2504
|
}
|
|
2156
2505
|
},
|
|
2157
2506
|
{
|
|
2158
|
-
id: "page
|
|
2159
|
-
icon: "page
|
|
2160
|
-
label: "
|
|
2161
|
-
type: "
|
|
2162
|
-
group: "
|
|
2163
|
-
execute: (
|
|
2164
|
-
|
|
2507
|
+
id: "fit-page",
|
|
2508
|
+
icon: "fit-page",
|
|
2509
|
+
label: "Fit to View",
|
|
2510
|
+
type: "button",
|
|
2511
|
+
group: "zoom",
|
|
2512
|
+
execute: () => {
|
|
2513
|
+
instance.fitToPage?.();
|
|
2514
|
+
}
|
|
2515
|
+
},
|
|
2516
|
+
{
|
|
2517
|
+
id: "rotate-cw",
|
|
2518
|
+
icon: "rotate-cw",
|
|
2519
|
+
label: "Rotate",
|
|
2520
|
+
type: "button",
|
|
2521
|
+
group: "view",
|
|
2522
|
+
execute: () => {
|
|
2523
|
+
instance.rotateCW?.();
|
|
2165
2524
|
}
|
|
2166
2525
|
},
|
|
2167
2526
|
{
|
|
@@ -2184,7 +2543,8 @@ var ExcelPlugin = class {
|
|
|
2184
2543
|
instance.print?.();
|
|
2185
2544
|
}
|
|
2186
2545
|
}
|
|
2187
|
-
|
|
2546
|
+
);
|
|
2547
|
+
return actions;
|
|
2188
2548
|
}
|
|
2189
2549
|
async render(ctx) {
|
|
2190
2550
|
const container = document.createElement("div");
|
|
@@ -2213,9 +2573,23 @@ var ExcelPlugin = class {
|
|
|
2213
2573
|
container.appendChild(tabsArea);
|
|
2214
2574
|
ctx.container.appendChild(container);
|
|
2215
2575
|
let scale = 1;
|
|
2576
|
+
let rotation = 0;
|
|
2216
2577
|
let currentSheetIndex = 1;
|
|
2217
2578
|
let sheetNames = [];
|
|
2218
2579
|
let wb = null;
|
|
2580
|
+
const applyTransform = () => {
|
|
2581
|
+
contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2582
|
+
contentArea.style.transformOrigin = "top left";
|
|
2583
|
+
};
|
|
2584
|
+
const calculateFitScale = () => {
|
|
2585
|
+
const table = contentArea.querySelector("table");
|
|
2586
|
+
if (!table) return 1;
|
|
2587
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
2588
|
+
const availH = Math.max(200, container.clientHeight - 80);
|
|
2589
|
+
const tW = table.offsetWidth || 800;
|
|
2590
|
+
const tH = table.offsetHeight || 600;
|
|
2591
|
+
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2592
|
+
};
|
|
2219
2593
|
try {
|
|
2220
2594
|
wb = XLSX__namespace.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
2221
2595
|
sheetNames = wb.SheetNames || [];
|
|
@@ -2268,6 +2642,7 @@ var ExcelPlugin = class {
|
|
|
2268
2642
|
b.style.fontWeight = "normal";
|
|
2269
2643
|
}
|
|
2270
2644
|
});
|
|
2645
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2271
2646
|
};
|
|
2272
2647
|
if (sheetNames.length > 0) {
|
|
2273
2648
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2302,17 +2677,30 @@ var ExcelPlugin = class {
|
|
|
2302
2677
|
return {
|
|
2303
2678
|
destroy: cleanup,
|
|
2304
2679
|
zoomIn: () => {
|
|
2305
|
-
scale += 0.
|
|
2306
|
-
|
|
2680
|
+
scale += 0.15;
|
|
2681
|
+
applyTransform();
|
|
2307
2682
|
},
|
|
2308
2683
|
zoomOut: () => {
|
|
2309
|
-
scale = Math.max(0.2, scale - 0.
|
|
2310
|
-
|
|
2684
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2685
|
+
applyTransform();
|
|
2311
2686
|
},
|
|
2312
2687
|
getZoom: () => scale,
|
|
2313
2688
|
setZoom: (level) => {
|
|
2314
2689
|
scale = level;
|
|
2315
|
-
|
|
2690
|
+
applyTransform();
|
|
2691
|
+
},
|
|
2692
|
+
fitToPage: () => {
|
|
2693
|
+
scale = calculateFitScale();
|
|
2694
|
+
rotation = 0;
|
|
2695
|
+
applyTransform();
|
|
2696
|
+
},
|
|
2697
|
+
rotateCW: () => {
|
|
2698
|
+
rotation = (rotation + 90) % 360;
|
|
2699
|
+
applyTransform();
|
|
2700
|
+
},
|
|
2701
|
+
rotateCCW: () => {
|
|
2702
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2703
|
+
applyTransform();
|
|
2316
2704
|
},
|
|
2317
2705
|
goToPage: (page) => {
|
|
2318
2706
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -2517,7 +2905,31 @@ var CodePlugin = class {
|
|
|
2517
2905
|
return false;
|
|
2518
2906
|
}
|
|
2519
2907
|
getToolbarActions(instance) {
|
|
2520
|
-
|
|
2908
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2909
|
+
const actions = [];
|
|
2910
|
+
if (totalPages > 1) {
|
|
2911
|
+
actions.push({
|
|
2912
|
+
id: "page-nav",
|
|
2913
|
+
icon: "",
|
|
2914
|
+
label: "Page Navigation",
|
|
2915
|
+
type: "page-nav",
|
|
2916
|
+
group: "navigation",
|
|
2917
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2918
|
+
max: totalPages,
|
|
2919
|
+
execute: (action, page) => {
|
|
2920
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2921
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2922
|
+
if (action === "prev") {
|
|
2923
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2924
|
+
} else if (action === "next") {
|
|
2925
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2926
|
+
} else if (typeof page === "number") {
|
|
2927
|
+
instance.goToPage?.(page);
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
});
|
|
2931
|
+
}
|
|
2932
|
+
actions.push(
|
|
2521
2933
|
{
|
|
2522
2934
|
id: "zoom-out",
|
|
2523
2935
|
icon: "zoom-out",
|
|
@@ -2538,6 +2950,26 @@ var CodePlugin = class {
|
|
|
2538
2950
|
instance.zoomIn?.();
|
|
2539
2951
|
}
|
|
2540
2952
|
},
|
|
2953
|
+
{
|
|
2954
|
+
id: "fit-page",
|
|
2955
|
+
icon: "fit-page",
|
|
2956
|
+
label: "Fit to View",
|
|
2957
|
+
type: "button",
|
|
2958
|
+
group: "zoom",
|
|
2959
|
+
execute: () => {
|
|
2960
|
+
instance.fitToPage?.();
|
|
2961
|
+
}
|
|
2962
|
+
},
|
|
2963
|
+
{
|
|
2964
|
+
id: "rotate-cw",
|
|
2965
|
+
icon: "rotate-cw",
|
|
2966
|
+
label: "Rotate",
|
|
2967
|
+
type: "button",
|
|
2968
|
+
group: "view",
|
|
2969
|
+
execute: () => {
|
|
2970
|
+
instance.rotateCW?.();
|
|
2971
|
+
}
|
|
2972
|
+
},
|
|
2541
2973
|
{
|
|
2542
2974
|
id: "copy",
|
|
2543
2975
|
icon: "copy",
|
|
@@ -2568,11 +3000,16 @@ var CodePlugin = class {
|
|
|
2568
3000
|
instance.print?.();
|
|
2569
3001
|
}
|
|
2570
3002
|
}
|
|
2571
|
-
|
|
3003
|
+
);
|
|
3004
|
+
return actions;
|
|
2572
3005
|
}
|
|
2573
3006
|
async render(ctx) {
|
|
2574
3007
|
const decoder = new TextDecoder("utf-8");
|
|
2575
|
-
const
|
|
3008
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
3009
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
3010
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
3011
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
3012
|
+
let currentPage = 1;
|
|
2576
3013
|
const container = document.createElement("div");
|
|
2577
3014
|
container.style.width = "100%";
|
|
2578
3015
|
container.style.height = "100%";
|
|
@@ -2582,6 +3019,7 @@ var CodePlugin = class {
|
|
|
2582
3019
|
container.style.padding = "16px";
|
|
2583
3020
|
container.style.boxSizing = "border-box";
|
|
2584
3021
|
let fontSize = 13;
|
|
3022
|
+
let rotation = 0;
|
|
2585
3023
|
const pre = document.createElement("pre");
|
|
2586
3024
|
pre.style.margin = "0";
|
|
2587
3025
|
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
@@ -2591,25 +3029,66 @@ var CodePlugin = class {
|
|
|
2591
3029
|
pre.style.wordBreak = "break-all";
|
|
2592
3030
|
const code = document.createElement("code");
|
|
2593
3031
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
3032
|
+
const renderCodePage = (text) => {
|
|
3033
|
+
try {
|
|
3034
|
+
if (ext && hljs__default.default.getLanguage(ext)) {
|
|
3035
|
+
code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
|
|
3036
|
+
} else {
|
|
3037
|
+
code.innerHTML = hljs__default.default.highlightAuto(text).value;
|
|
3038
|
+
}
|
|
3039
|
+
} catch {
|
|
3040
|
+
code.textContent = text;
|
|
2599
3041
|
}
|
|
2600
|
-
}
|
|
2601
|
-
|
|
2602
|
-
}
|
|
3042
|
+
};
|
|
3043
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2603
3044
|
pre.appendChild(code);
|
|
2604
3045
|
container.appendChild(pre);
|
|
3046
|
+
let indicator = null;
|
|
3047
|
+
if (totalPages > 1) {
|
|
3048
|
+
indicator = document.createElement("div");
|
|
3049
|
+
indicator.className = "fp-code-page-indicator";
|
|
3050
|
+
indicator.style.position = "sticky";
|
|
3051
|
+
indicator.style.bottom = "16px";
|
|
3052
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3053
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3054
|
+
indicator.style.color = "#f8fafc";
|
|
3055
|
+
indicator.style.fontSize = "12px";
|
|
3056
|
+
indicator.style.fontWeight = "600";
|
|
3057
|
+
indicator.style.padding = "5px 14px";
|
|
3058
|
+
indicator.style.borderRadius = "20px";
|
|
3059
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3060
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3061
|
+
indicator.style.zIndex = "10";
|
|
3062
|
+
indicator.style.userSelect = "none";
|
|
3063
|
+
indicator.style.pointerEvents = "none";
|
|
3064
|
+
indicator.style.textAlign = "center";
|
|
3065
|
+
indicator.style.width = "fit-content";
|
|
3066
|
+
indicator.style.margin = "16px auto 0";
|
|
3067
|
+
container.appendChild(indicator);
|
|
3068
|
+
}
|
|
3069
|
+
const showPage = (pageNum) => {
|
|
3070
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3071
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3072
|
+
if (indicator) {
|
|
3073
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3074
|
+
}
|
|
3075
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3076
|
+
};
|
|
3077
|
+
if (totalPages > 1) {
|
|
3078
|
+
showPage(1);
|
|
3079
|
+
}
|
|
2605
3080
|
ctx.container.appendChild(container);
|
|
2606
3081
|
const cleanup = () => {
|
|
3082
|
+
indicator?.remove();
|
|
2607
3083
|
container.remove();
|
|
2608
3084
|
ctx.container.innerHTML = "";
|
|
2609
3085
|
};
|
|
2610
3086
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2611
3087
|
return {
|
|
2612
3088
|
destroy: cleanup,
|
|
3089
|
+
getPageCount: () => totalPages,
|
|
3090
|
+
getCurrentPage: () => currentPage,
|
|
3091
|
+
goToPage: (page) => showPage(page),
|
|
2613
3092
|
zoomIn: () => {
|
|
2614
3093
|
fontSize = Math.min(32, fontSize + 2);
|
|
2615
3094
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2623,6 +3102,22 @@ var CodePlugin = class {
|
|
|
2623
3102
|
fontSize = Math.round(13 * level);
|
|
2624
3103
|
pre.style.fontSize = `${fontSize}px`;
|
|
2625
3104
|
},
|
|
3105
|
+
fitToPage: () => {
|
|
3106
|
+
fontSize = 13;
|
|
3107
|
+
rotation = 0;
|
|
3108
|
+
pre.style.fontSize = "13px";
|
|
3109
|
+
pre.style.transform = "none";
|
|
3110
|
+
},
|
|
3111
|
+
rotateCW: () => {
|
|
3112
|
+
rotation = (rotation + 90) % 360;
|
|
3113
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3114
|
+
pre.style.transformOrigin = "top left";
|
|
3115
|
+
},
|
|
3116
|
+
rotateCCW: () => {
|
|
3117
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3118
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3119
|
+
pre.style.transformOrigin = "top left";
|
|
3120
|
+
},
|
|
2626
3121
|
download: () => {
|
|
2627
3122
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
2628
3123
|
const blob = new Blob([ctx.buffer], { type: mimeType });
|
|
@@ -2637,7 +3132,7 @@ var CodePlugin = class {
|
|
|
2637
3132
|
window.print();
|
|
2638
3133
|
},
|
|
2639
3134
|
copy: () => {
|
|
2640
|
-
navigator.clipboard?.writeText(
|
|
3135
|
+
navigator.clipboard?.writeText(fullText);
|
|
2641
3136
|
}
|
|
2642
3137
|
};
|
|
2643
3138
|
}
|
|
@@ -3134,6 +3629,14 @@ var PptxPlugin = class {
|
|
|
3134
3629
|
group: "zoom",
|
|
3135
3630
|
execute: () => instance.fitToPage?.()
|
|
3136
3631
|
},
|
|
3632
|
+
{
|
|
3633
|
+
id: "rotate-cw",
|
|
3634
|
+
icon: "rotate-cw",
|
|
3635
|
+
label: "Rotate",
|
|
3636
|
+
type: "button",
|
|
3637
|
+
group: "view",
|
|
3638
|
+
execute: () => instance.rotateCW?.()
|
|
3639
|
+
},
|
|
3137
3640
|
{
|
|
3138
3641
|
id: "download",
|
|
3139
3642
|
icon: "download",
|
|
@@ -3158,6 +3661,7 @@ var PptxPlugin = class {
|
|
|
3158
3661
|
const slideCount = renderer.slidePaths?.length || 1;
|
|
3159
3662
|
let currentSlide = 1;
|
|
3160
3663
|
let scale = 1;
|
|
3664
|
+
let rotation = 0;
|
|
3161
3665
|
const wrapper = document.createElement("div");
|
|
3162
3666
|
wrapper.className = "fp-pptx-wrapper";
|
|
3163
3667
|
wrapper.style.cssText = `
|
|
@@ -3180,6 +3684,8 @@ var PptxPlugin = class {
|
|
|
3180
3684
|
background: #ffffff;
|
|
3181
3685
|
transform-origin: top center;
|
|
3182
3686
|
transition: transform 0.2s ease;
|
|
3687
|
+
max-width: calc(100% - 32px);
|
|
3688
|
+
max-height: calc(100% - 48px);
|
|
3183
3689
|
`;
|
|
3184
3690
|
const canvas = document.createElement("canvas");
|
|
3185
3691
|
slideContainer.appendChild(canvas);
|
|
@@ -3187,10 +3693,22 @@ var PptxPlugin = class {
|
|
|
3187
3693
|
ctx.container.innerHTML = "";
|
|
3188
3694
|
ctx.container.style.overflow = "auto";
|
|
3189
3695
|
ctx.container.appendChild(wrapper);
|
|
3696
|
+
const calculateFitScale = () => {
|
|
3697
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
3698
|
+
const availH = Math.max(200, ctx.container.clientHeight - 72);
|
|
3699
|
+
const cW = canvas.offsetWidth || 1280;
|
|
3700
|
+
const cH = canvas.offsetHeight || 720;
|
|
3701
|
+
return Math.min(1, Math.min(availW / cW, availH / cH));
|
|
3702
|
+
};
|
|
3703
|
+
const applyTransform = () => {
|
|
3704
|
+
slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
3705
|
+
};
|
|
3190
3706
|
const renderCurrentSlide = async () => {
|
|
3191
3707
|
try {
|
|
3192
3708
|
await renderer.renderSlide(currentSlide - 1, canvas, 1280);
|
|
3193
3709
|
ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
|
|
3710
|
+
scale = calculateFitScale();
|
|
3711
|
+
applyTransform();
|
|
3194
3712
|
} catch (err) {
|
|
3195
3713
|
console.error("[PptxPlugin] Failed to render slide:", err);
|
|
3196
3714
|
}
|
|
@@ -3213,21 +3731,30 @@ var PptxPlugin = class {
|
|
|
3213
3731
|
getPageCount: () => slideCount,
|
|
3214
3732
|
getCurrentPage: () => currentSlide,
|
|
3215
3733
|
zoomIn: () => {
|
|
3216
|
-
scale += 0.
|
|
3217
|
-
|
|
3734
|
+
scale += 0.15;
|
|
3735
|
+
applyTransform();
|
|
3218
3736
|
},
|
|
3219
3737
|
zoomOut: () => {
|
|
3220
|
-
scale = Math.max(0.2, scale - 0.
|
|
3221
|
-
|
|
3738
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
3739
|
+
applyTransform();
|
|
3222
3740
|
},
|
|
3223
3741
|
getZoom: () => scale,
|
|
3224
3742
|
setZoom: (level) => {
|
|
3225
3743
|
scale = level;
|
|
3226
|
-
|
|
3744
|
+
applyTransform();
|
|
3227
3745
|
},
|
|
3228
3746
|
fitToPage: () => {
|
|
3229
|
-
scale =
|
|
3230
|
-
|
|
3747
|
+
scale = calculateFitScale();
|
|
3748
|
+
rotation = 0;
|
|
3749
|
+
applyTransform();
|
|
3750
|
+
},
|
|
3751
|
+
rotateCW: () => {
|
|
3752
|
+
rotation = (rotation + 90) % 360;
|
|
3753
|
+
applyTransform();
|
|
3754
|
+
},
|
|
3755
|
+
rotateCCW: () => {
|
|
3756
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3757
|
+
applyTransform();
|
|
3231
3758
|
},
|
|
3232
3759
|
getThumbnails: () => {
|
|
3233
3760
|
const list = [];
|
|
@@ -3459,7 +3986,31 @@ var RtfPlugin = class {
|
|
|
3459
3986
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3460
3987
|
}
|
|
3461
3988
|
getToolbarActions(instance) {
|
|
3462
|
-
|
|
3989
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3990
|
+
const actions = [];
|
|
3991
|
+
if (totalPages > 1) {
|
|
3992
|
+
actions.push({
|
|
3993
|
+
id: "page-nav",
|
|
3994
|
+
icon: "",
|
|
3995
|
+
label: "Page Navigation",
|
|
3996
|
+
type: "page-nav",
|
|
3997
|
+
group: "navigation",
|
|
3998
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3999
|
+
max: totalPages,
|
|
4000
|
+
execute: (action, page) => {
|
|
4001
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4002
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4003
|
+
if (action === "prev") {
|
|
4004
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4005
|
+
} else if (action === "next") {
|
|
4006
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4007
|
+
} else if (typeof page === "number") {
|
|
4008
|
+
instance.goToPage?.(page);
|
|
4009
|
+
}
|
|
4010
|
+
}
|
|
4011
|
+
});
|
|
4012
|
+
}
|
|
4013
|
+
actions.push(
|
|
3463
4014
|
{
|
|
3464
4015
|
id: "zoom-out",
|
|
3465
4016
|
icon: "zoom-out",
|
|
@@ -3484,6 +4035,14 @@ var RtfPlugin = class {
|
|
|
3484
4035
|
group: "zoom",
|
|
3485
4036
|
execute: () => instance.fitToPage?.()
|
|
3486
4037
|
},
|
|
4038
|
+
{
|
|
4039
|
+
id: "rotate-cw",
|
|
4040
|
+
icon: "rotate-cw",
|
|
4041
|
+
label: "Rotate",
|
|
4042
|
+
type: "button",
|
|
4043
|
+
group: "view",
|
|
4044
|
+
execute: () => instance.rotateCW?.()
|
|
4045
|
+
},
|
|
3487
4046
|
{
|
|
3488
4047
|
id: "download",
|
|
3489
4048
|
icon: "download",
|
|
@@ -3500,7 +4059,8 @@ var RtfPlugin = class {
|
|
|
3500
4059
|
group: "actions",
|
|
3501
4060
|
execute: () => instance.print?.()
|
|
3502
4061
|
}
|
|
3503
|
-
|
|
4062
|
+
);
|
|
4063
|
+
return actions;
|
|
3504
4064
|
}
|
|
3505
4065
|
async render(ctx) {
|
|
3506
4066
|
const wrapper = document.createElement("div");
|
|
@@ -3519,44 +4079,124 @@ var RtfPlugin = class {
|
|
|
3519
4079
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3520
4080
|
ctx.container.appendChild(wrapper);
|
|
3521
4081
|
let scale = 1;
|
|
4082
|
+
let rotation = 0;
|
|
4083
|
+
let pageElements = [];
|
|
4084
|
+
const calculateFitScale = () => {
|
|
4085
|
+
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4086
|
+
const elW = activeEl.offsetWidth || 850;
|
|
4087
|
+
const elH = activeEl.offsetHeight || 1e3;
|
|
4088
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4089
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4090
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4091
|
+
};
|
|
4092
|
+
const applyTransform = () => {
|
|
4093
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4094
|
+
wrapper.style.transformOrigin = "top center";
|
|
4095
|
+
};
|
|
4096
|
+
setTimeout(() => {
|
|
4097
|
+
scale = calculateFitScale();
|
|
4098
|
+
applyTransform();
|
|
4099
|
+
}, 60);
|
|
3522
4100
|
try {
|
|
3523
4101
|
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3524
4102
|
RTFJS__namespace.loggingEnabled(false);
|
|
3525
4103
|
}
|
|
3526
4104
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3527
4105
|
const htmlElements = await doc.render();
|
|
3528
|
-
|
|
4106
|
+
pageElements = htmlElements;
|
|
4107
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
4108
|
+
const el = htmlElements[i];
|
|
4109
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3529
4110
|
wrapper.appendChild(el);
|
|
3530
4111
|
}
|
|
3531
4112
|
} catch (err) {
|
|
3532
4113
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3533
4114
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3534
4115
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3535
|
-
|
|
4116
|
+
const pre = document.createElement("pre");
|
|
4117
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
4118
|
+
pre.style.fontFamily = "serif";
|
|
4119
|
+
pre.style.color = "#333";
|
|
4120
|
+
pre.textContent = clean;
|
|
4121
|
+
wrapper.appendChild(pre);
|
|
4122
|
+
pageElements = [pre];
|
|
4123
|
+
}
|
|
4124
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
4125
|
+
let currentPage = 1;
|
|
4126
|
+
let indicator = null;
|
|
4127
|
+
if (totalPages > 1) {
|
|
4128
|
+
indicator = document.createElement("div");
|
|
4129
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
4130
|
+
indicator.style.position = "sticky";
|
|
4131
|
+
indicator.style.bottom = "16px";
|
|
4132
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4133
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4134
|
+
indicator.style.color = "#f8fafc";
|
|
4135
|
+
indicator.style.fontSize = "12px";
|
|
4136
|
+
indicator.style.fontWeight = "600";
|
|
4137
|
+
indicator.style.padding = "5px 14px";
|
|
4138
|
+
indicator.style.borderRadius = "20px";
|
|
4139
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4140
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4141
|
+
indicator.style.zIndex = "10";
|
|
4142
|
+
indicator.style.userSelect = "none";
|
|
4143
|
+
indicator.style.pointerEvents = "none";
|
|
4144
|
+
indicator.style.textAlign = "center";
|
|
4145
|
+
indicator.style.width = "fit-content";
|
|
4146
|
+
indicator.style.margin = "16px auto 0";
|
|
4147
|
+
ctx.container.appendChild(indicator);
|
|
4148
|
+
}
|
|
4149
|
+
const showPage = (pageNum) => {
|
|
4150
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4151
|
+
if (totalPages > 1) {
|
|
4152
|
+
pageElements.forEach((el, idx) => {
|
|
4153
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4154
|
+
});
|
|
4155
|
+
}
|
|
4156
|
+
if (indicator) {
|
|
4157
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4158
|
+
}
|
|
4159
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4160
|
+
};
|
|
4161
|
+
if (totalPages > 1) {
|
|
4162
|
+
showPage(1);
|
|
3536
4163
|
}
|
|
3537
4164
|
const cleanup = () => {
|
|
4165
|
+
indicator?.remove();
|
|
3538
4166
|
wrapper.remove();
|
|
3539
4167
|
ctx.container.innerHTML = "";
|
|
3540
4168
|
};
|
|
3541
4169
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3542
4170
|
return {
|
|
3543
4171
|
destroy: cleanup,
|
|
4172
|
+
getPageCount: () => totalPages,
|
|
4173
|
+
getCurrentPage: () => currentPage,
|
|
4174
|
+
goToPage: (page) => showPage(page),
|
|
3544
4175
|
zoomIn: () => {
|
|
3545
|
-
scale += 0.
|
|
3546
|
-
|
|
4176
|
+
scale += 0.15;
|
|
4177
|
+
applyTransform();
|
|
3547
4178
|
},
|
|
3548
4179
|
zoomOut: () => {
|
|
3549
|
-
scale = Math.max(0.2, scale - 0.
|
|
3550
|
-
|
|
4180
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4181
|
+
applyTransform();
|
|
3551
4182
|
},
|
|
3552
4183
|
getZoom: () => scale,
|
|
3553
4184
|
setZoom: (level) => {
|
|
3554
4185
|
scale = level;
|
|
3555
|
-
|
|
4186
|
+
applyTransform();
|
|
3556
4187
|
},
|
|
3557
4188
|
fitToPage: () => {
|
|
3558
|
-
scale =
|
|
3559
|
-
|
|
4189
|
+
scale = calculateFitScale();
|
|
4190
|
+
rotation = 0;
|
|
4191
|
+
applyTransform();
|
|
4192
|
+
},
|
|
4193
|
+
rotateCW: () => {
|
|
4194
|
+
rotation = (rotation + 90) % 360;
|
|
4195
|
+
applyTransform();
|
|
4196
|
+
},
|
|
4197
|
+
rotateCCW: () => {
|
|
4198
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4199
|
+
applyTransform();
|
|
3560
4200
|
},
|
|
3561
4201
|
download: () => {
|
|
3562
4202
|
const blob = new Blob([ctx.buffer], { type: "application/rtf" });
|
|
@@ -3728,41 +4368,41 @@ var OpenDocumentPlugin = class {
|
|
|
3728
4368
|
}
|
|
3729
4369
|
getToolbarActions(instance) {
|
|
3730
4370
|
const isPresentation = instance.isPresentation;
|
|
4371
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3731
4372
|
const actions = [];
|
|
3732
|
-
if (isPresentation) {
|
|
3733
|
-
|
|
3734
|
-
{
|
|
4373
|
+
if (isPresentation || totalPages > 1) {
|
|
4374
|
+
if (isPresentation) {
|
|
4375
|
+
actions.push({
|
|
3735
4376
|
id: "thumbnails",
|
|
3736
4377
|
icon: "thumbnails",
|
|
3737
4378
|
label: "Slide Thumbnails",
|
|
3738
4379
|
type: "button",
|
|
3739
4380
|
group: "navigation",
|
|
3740
4381
|
execute: () => instance.toggleThumbnails?.()
|
|
3741
|
-
}
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
}
|
|
4382
|
+
});
|
|
4383
|
+
}
|
|
4384
|
+
actions.push({
|
|
4385
|
+
id: "page-nav",
|
|
4386
|
+
icon: "",
|
|
4387
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4388
|
+
type: "page-nav",
|
|
4389
|
+
group: "navigation",
|
|
4390
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4391
|
+
max: totalPages,
|
|
4392
|
+
execute: (action, page) => {
|
|
4393
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4394
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4395
|
+
if (action === "prev") {
|
|
4396
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4397
|
+
} else if (action === "next") {
|
|
4398
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4399
|
+
} else if (typeof page === "number") {
|
|
4400
|
+
instance.goToPage?.(page);
|
|
4401
|
+
} else if (typeof action === "number") {
|
|
4402
|
+
instance.goToPage?.(action);
|
|
3763
4403
|
}
|
|
3764
4404
|
}
|
|
3765
|
-
);
|
|
4405
|
+
});
|
|
3766
4406
|
}
|
|
3767
4407
|
actions.push(
|
|
3768
4408
|
{
|
|
@@ -3784,11 +4424,19 @@ var OpenDocumentPlugin = class {
|
|
|
3784
4424
|
{
|
|
3785
4425
|
id: "fit-page",
|
|
3786
4426
|
icon: "fit-page",
|
|
3787
|
-
label: "Fit to Page",
|
|
4427
|
+
label: isPresentation ? "Fit to Slide" : "Fit to Page",
|
|
3788
4428
|
type: "button",
|
|
3789
4429
|
group: "zoom",
|
|
3790
4430
|
execute: () => instance.fitToPage?.()
|
|
3791
4431
|
},
|
|
4432
|
+
{
|
|
4433
|
+
id: "rotate-cw",
|
|
4434
|
+
icon: "rotate-cw",
|
|
4435
|
+
label: "Rotate",
|
|
4436
|
+
type: "button",
|
|
4437
|
+
group: "view",
|
|
4438
|
+
execute: () => instance.rotateCW?.()
|
|
4439
|
+
},
|
|
3792
4440
|
{
|
|
3793
4441
|
id: "download",
|
|
3794
4442
|
icon: "download",
|
|
@@ -3852,6 +4500,22 @@ var OpenDocumentPlugin = class {
|
|
|
3852
4500
|
container.appendChild(wrapper);
|
|
3853
4501
|
ctx.container.appendChild(container);
|
|
3854
4502
|
let scale = 1;
|
|
4503
|
+
let rotation = 0;
|
|
4504
|
+
const calculateFitScale = () => {
|
|
4505
|
+
const elW = wrapper.offsetWidth || 850;
|
|
4506
|
+
const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
|
|
4507
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4508
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4509
|
+
return Math.min(1, Math.min(availW / elW, availH / elH));
|
|
4510
|
+
};
|
|
4511
|
+
const applyTransform = () => {
|
|
4512
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4513
|
+
wrapper.style.transformOrigin = "top center";
|
|
4514
|
+
};
|
|
4515
|
+
setTimeout(() => {
|
|
4516
|
+
scale = calculateFitScale();
|
|
4517
|
+
applyTransform();
|
|
4518
|
+
}, 60);
|
|
3855
4519
|
let currentPage = 1;
|
|
3856
4520
|
let totalPages = 1;
|
|
3857
4521
|
let slides = [];
|
|
@@ -3910,21 +4574,30 @@ var OpenDocumentPlugin = class {
|
|
|
3910
4574
|
destroy: cleanup,
|
|
3911
4575
|
isPresentation,
|
|
3912
4576
|
zoomIn: () => {
|
|
3913
|
-
scale += 0.
|
|
3914
|
-
|
|
4577
|
+
scale += 0.15;
|
|
4578
|
+
applyTransform();
|
|
3915
4579
|
},
|
|
3916
4580
|
zoomOut: () => {
|
|
3917
|
-
scale = Math.max(0.2, scale - 0.
|
|
3918
|
-
|
|
4581
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4582
|
+
applyTransform();
|
|
3919
4583
|
},
|
|
3920
4584
|
getZoom: () => scale,
|
|
3921
4585
|
setZoom: (level) => {
|
|
3922
4586
|
scale = level;
|
|
3923
|
-
|
|
4587
|
+
applyTransform();
|
|
3924
4588
|
},
|
|
3925
4589
|
fitToPage: () => {
|
|
3926
|
-
scale =
|
|
3927
|
-
|
|
4590
|
+
scale = calculateFitScale();
|
|
4591
|
+
rotation = 0;
|
|
4592
|
+
applyTransform();
|
|
4593
|
+
},
|
|
4594
|
+
rotateCW: () => {
|
|
4595
|
+
rotation = (rotation + 90) % 360;
|
|
4596
|
+
applyTransform();
|
|
4597
|
+
},
|
|
4598
|
+
rotateCCW: () => {
|
|
4599
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4600
|
+
applyTransform();
|
|
3928
4601
|
},
|
|
3929
4602
|
goToPage,
|
|
3930
4603
|
getPageCount: () => totalPages,
|
|
@@ -4145,7 +4818,31 @@ var DocPlugin = class {
|
|
|
4145
4818
|
return this.mimeTypes.includes(mime || "");
|
|
4146
4819
|
}
|
|
4147
4820
|
getToolbarActions(instance) {
|
|
4148
|
-
|
|
4821
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4822
|
+
const actions = [];
|
|
4823
|
+
if (totalPages > 1) {
|
|
4824
|
+
actions.push({
|
|
4825
|
+
id: "page-nav",
|
|
4826
|
+
icon: "",
|
|
4827
|
+
label: "Page Navigation",
|
|
4828
|
+
type: "page-nav",
|
|
4829
|
+
group: "navigation",
|
|
4830
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4831
|
+
max: totalPages,
|
|
4832
|
+
execute: (action, page) => {
|
|
4833
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4834
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4835
|
+
if (action === "prev") {
|
|
4836
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4837
|
+
} else if (action === "next") {
|
|
4838
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4839
|
+
} else if (typeof page === "number") {
|
|
4840
|
+
instance.goToPage?.(page);
|
|
4841
|
+
}
|
|
4842
|
+
}
|
|
4843
|
+
});
|
|
4844
|
+
}
|
|
4845
|
+
actions.push(
|
|
4149
4846
|
{
|
|
4150
4847
|
id: "zoom-out",
|
|
4151
4848
|
icon: "zoom-out",
|
|
@@ -4170,6 +4867,14 @@ var DocPlugin = class {
|
|
|
4170
4867
|
group: "zoom",
|
|
4171
4868
|
execute: () => instance.fitToPage?.()
|
|
4172
4869
|
},
|
|
4870
|
+
{
|
|
4871
|
+
id: "rotate-cw",
|
|
4872
|
+
icon: "rotate-cw",
|
|
4873
|
+
label: "Rotate",
|
|
4874
|
+
type: "button",
|
|
4875
|
+
group: "view",
|
|
4876
|
+
execute: () => instance.rotateCW?.()
|
|
4877
|
+
},
|
|
4173
4878
|
{
|
|
4174
4879
|
id: "copy",
|
|
4175
4880
|
icon: "copy",
|
|
@@ -4194,7 +4899,8 @@ var DocPlugin = class {
|
|
|
4194
4899
|
group: "actions",
|
|
4195
4900
|
execute: () => instance.print?.()
|
|
4196
4901
|
}
|
|
4197
|
-
|
|
4902
|
+
);
|
|
4903
|
+
return actions;
|
|
4198
4904
|
}
|
|
4199
4905
|
async render(ctx) {
|
|
4200
4906
|
const container = document.createElement("div");
|
|
@@ -4221,6 +4927,7 @@ var DocPlugin = class {
|
|
|
4221
4927
|
ctx.container.appendChild(container);
|
|
4222
4928
|
let scale = 1;
|
|
4223
4929
|
let extractedRawText = "";
|
|
4930
|
+
let isFallback = false;
|
|
4224
4931
|
try {
|
|
4225
4932
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4226
4933
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4234,42 +4941,131 @@ var DocPlugin = class {
|
|
|
4234
4941
|
const tableStream = cfbf.readStream(tableName);
|
|
4235
4942
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4236
4943
|
extractedRawText = text;
|
|
4237
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4238
4944
|
} catch (err) {
|
|
4239
4945
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4240
4946
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4241
4947
|
extractedRawText = fallback;
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4948
|
+
isFallback = true;
|
|
4949
|
+
}
|
|
4950
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4951
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4952
|
+
let currentPage = 1;
|
|
4953
|
+
wrapper.innerHTML = "";
|
|
4954
|
+
const pageCards = [];
|
|
4955
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4956
|
+
const pageCard = document.createElement("div");
|
|
4957
|
+
pageCard.className = "fp-doc-page-card";
|
|
4958
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4959
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4960
|
+
pageCard.style.borderRadius = "4px";
|
|
4961
|
+
pageCard.style.padding = "56px 48px";
|
|
4962
|
+
pageCard.style.minHeight = "100%";
|
|
4963
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4964
|
+
if (isFallback && i === 0) {
|
|
4965
|
+
pageCard.innerHTML = `
|
|
4966
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4967
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4968
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4969
|
+
</div>
|
|
4970
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4971
|
+
`;
|
|
4972
|
+
} else {
|
|
4973
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4974
|
+
}
|
|
4975
|
+
wrapper.appendChild(pageCard);
|
|
4976
|
+
pageCards.push(pageCard);
|
|
4977
|
+
}
|
|
4978
|
+
let indicator = null;
|
|
4979
|
+
if (totalPages > 1) {
|
|
4980
|
+
indicator = document.createElement("div");
|
|
4981
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4982
|
+
indicator.style.position = "sticky";
|
|
4983
|
+
indicator.style.bottom = "16px";
|
|
4984
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4985
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4986
|
+
indicator.style.color = "#f8fafc";
|
|
4987
|
+
indicator.style.fontSize = "12px";
|
|
4988
|
+
indicator.style.fontWeight = "600";
|
|
4989
|
+
indicator.style.padding = "5px 14px";
|
|
4990
|
+
indicator.style.borderRadius = "20px";
|
|
4991
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4992
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4993
|
+
indicator.style.zIndex = "10";
|
|
4994
|
+
indicator.style.userSelect = "none";
|
|
4995
|
+
indicator.style.pointerEvents = "none";
|
|
4996
|
+
indicator.style.textAlign = "center";
|
|
4997
|
+
indicator.style.width = "fit-content";
|
|
4998
|
+
indicator.style.margin = "16px auto 0";
|
|
4999
|
+
container.appendChild(indicator);
|
|
5000
|
+
}
|
|
5001
|
+
const showPage = (pageNum) => {
|
|
5002
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
5003
|
+
if (totalPages > 1) {
|
|
5004
|
+
pageCards.forEach((card, idx) => {
|
|
5005
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
5006
|
+
});
|
|
5007
|
+
}
|
|
5008
|
+
if (indicator) {
|
|
5009
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5010
|
+
}
|
|
5011
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5012
|
+
};
|
|
5013
|
+
if (totalPages > 1) {
|
|
5014
|
+
showPage(1);
|
|
4249
5015
|
}
|
|
5016
|
+
let rotation = 0;
|
|
5017
|
+
const calculateFitScale = () => {
|
|
5018
|
+
const activeCard = pageCards[currentPage - 1] || wrapper;
|
|
5019
|
+
const elW = activeCard.offsetWidth || 850;
|
|
5020
|
+
const elH = activeCard.offsetHeight || 1e3;
|
|
5021
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
5022
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
5023
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
5024
|
+
};
|
|
5025
|
+
const applyTransform = () => {
|
|
5026
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5027
|
+
wrapper.style.transformOrigin = "top center";
|
|
5028
|
+
};
|
|
5029
|
+
setTimeout(() => {
|
|
5030
|
+
scale = calculateFitScale();
|
|
5031
|
+
applyTransform();
|
|
5032
|
+
}, 60);
|
|
4250
5033
|
const cleanup = () => {
|
|
5034
|
+
indicator?.remove();
|
|
4251
5035
|
container.remove();
|
|
4252
5036
|
ctx.container.innerHTML = "";
|
|
4253
5037
|
};
|
|
4254
5038
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4255
5039
|
return {
|
|
4256
5040
|
destroy: cleanup,
|
|
5041
|
+
getPageCount: () => totalPages,
|
|
5042
|
+
getCurrentPage: () => currentPage,
|
|
5043
|
+
goToPage: (page) => showPage(page),
|
|
4257
5044
|
zoomIn: () => {
|
|
4258
|
-
scale += 0.
|
|
4259
|
-
|
|
5045
|
+
scale += 0.15;
|
|
5046
|
+
applyTransform();
|
|
4260
5047
|
},
|
|
4261
5048
|
zoomOut: () => {
|
|
4262
|
-
scale = Math.max(0.2, scale - 0.
|
|
4263
|
-
|
|
5049
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5050
|
+
applyTransform();
|
|
4264
5051
|
},
|
|
4265
5052
|
getZoom: () => scale,
|
|
4266
5053
|
setZoom: (level) => {
|
|
4267
5054
|
scale = level;
|
|
4268
|
-
|
|
5055
|
+
applyTransform();
|
|
4269
5056
|
},
|
|
4270
5057
|
fitToPage: () => {
|
|
4271
|
-
scale =
|
|
4272
|
-
|
|
5058
|
+
scale = calculateFitScale();
|
|
5059
|
+
rotation = 0;
|
|
5060
|
+
applyTransform();
|
|
5061
|
+
},
|
|
5062
|
+
rotateCW: () => {
|
|
5063
|
+
rotation = (rotation + 90) % 360;
|
|
5064
|
+
applyTransform();
|
|
5065
|
+
},
|
|
5066
|
+
rotateCCW: () => {
|
|
5067
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5068
|
+
applyTransform();
|
|
4273
5069
|
},
|
|
4274
5070
|
copy: () => {
|
|
4275
5071
|
navigator.clipboard.writeText(extractedRawText);
|
|
@@ -4385,11 +5181,16 @@ var DocPlugin = class {
|
|
|
4385
5181
|
heuristicTextExtraction(buffer) {
|
|
4386
5182
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4387
5183
|
}
|
|
5184
|
+
splitIntoPages(text) {
|
|
5185
|
+
if (!text) return [""];
|
|
5186
|
+
const parts = text.split(/[\x0C\f]|\r?\n\s*[-=_]{3,}\s*(?:PAGE|Page|page break)[\s\d\w-]*[-=_]{3,}\s*\r?\n/i).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
5187
|
+
return parts.length > 0 ? parts : [text];
|
|
5188
|
+
}
|
|
4388
5189
|
/**
|
|
4389
5190
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4390
5191
|
*/
|
|
4391
5192
|
formatDocToHtml(text, filename) {
|
|
4392
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
5193
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4393
5194
|
let html = "";
|
|
4394
5195
|
let inList = false;
|
|
4395
5196
|
for (const rawLine of lines) {
|
|
@@ -4504,6 +5305,14 @@ var PptPlugin = class {
|
|
|
4504
5305
|
group: "zoom",
|
|
4505
5306
|
execute: () => instance.fitToPage?.()
|
|
4506
5307
|
},
|
|
5308
|
+
{
|
|
5309
|
+
id: "rotate-cw",
|
|
5310
|
+
icon: "rotate-cw",
|
|
5311
|
+
label: "Rotate",
|
|
5312
|
+
type: "button",
|
|
5313
|
+
group: "view",
|
|
5314
|
+
execute: () => instance.rotateCW?.()
|
|
5315
|
+
},
|
|
4507
5316
|
{
|
|
4508
5317
|
id: "download",
|
|
4509
5318
|
icon: "download",
|
|
@@ -4537,22 +5346,36 @@ var PptPlugin = class {
|
|
|
4537
5346
|
const slideCard = document.createElement("div");
|
|
4538
5347
|
slideCard.className = "fp-ppt-slide-card";
|
|
4539
5348
|
slideCard.style.width = "960px";
|
|
4540
|
-
slideCard.style.maxWidth = "
|
|
5349
|
+
slideCard.style.maxWidth = "calc(100% - 32px)";
|
|
5350
|
+
slideCard.style.maxHeight = "calc(100% - 48px)";
|
|
4541
5351
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4542
5352
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4543
5353
|
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4544
5354
|
slideCard.style.borderRadius = "8px";
|
|
4545
5355
|
slideCard.style.boxSizing = "border-box";
|
|
4546
5356
|
slideCard.style.position = "relative";
|
|
4547
|
-
slideCard.style.overflow = "hidden";
|
|
4548
|
-
slideCard.style.transformOrigin = "center center";
|
|
4549
5357
|
slideCard.style.transition = "transform 0.2s ease";
|
|
5358
|
+
slideCard.style.transformOrigin = "center center";
|
|
5359
|
+
slideCard.style.flexShrink = "0";
|
|
4550
5360
|
container.appendChild(slideCard);
|
|
4551
5361
|
ctx.container.appendChild(container);
|
|
4552
5362
|
let scale = 1;
|
|
5363
|
+
let rotation = 0;
|
|
4553
5364
|
let currentSlide = 1;
|
|
4554
5365
|
let slides = [];
|
|
4555
5366
|
const createdBlobUrls = [];
|
|
5367
|
+
const calculateFitScale = () => {
|
|
5368
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
5369
|
+
const availH = Math.max(200, container.clientHeight - 72);
|
|
5370
|
+
return Math.min(1, Math.min(availW / 960, availH / 540));
|
|
5371
|
+
};
|
|
5372
|
+
const applyTransform = () => {
|
|
5373
|
+
slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5374
|
+
};
|
|
5375
|
+
setTimeout(() => {
|
|
5376
|
+
scale = calculateFitScale();
|
|
5377
|
+
applyTransform();
|
|
5378
|
+
}, 60);
|
|
4556
5379
|
try {
|
|
4557
5380
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4558
5381
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
@@ -4653,21 +5476,30 @@ var PptPlugin = class {
|
|
|
4653
5476
|
return {
|
|
4654
5477
|
destroy: cleanup,
|
|
4655
5478
|
zoomIn: () => {
|
|
4656
|
-
scale += 0.
|
|
4657
|
-
|
|
5479
|
+
scale += 0.15;
|
|
5480
|
+
applyTransform();
|
|
4658
5481
|
},
|
|
4659
5482
|
zoomOut: () => {
|
|
4660
|
-
scale = Math.max(0.
|
|
4661
|
-
|
|
5483
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5484
|
+
applyTransform();
|
|
4662
5485
|
},
|
|
4663
5486
|
getZoom: () => scale,
|
|
4664
5487
|
setZoom: (level) => {
|
|
4665
5488
|
scale = level;
|
|
4666
|
-
|
|
5489
|
+
applyTransform();
|
|
4667
5490
|
},
|
|
4668
5491
|
fitToPage: () => {
|
|
4669
|
-
scale =
|
|
4670
|
-
|
|
5492
|
+
scale = calculateFitScale();
|
|
5493
|
+
rotation = 0;
|
|
5494
|
+
applyTransform();
|
|
5495
|
+
},
|
|
5496
|
+
rotateCW: () => {
|
|
5497
|
+
rotation = (rotation + 90) % 360;
|
|
5498
|
+
applyTransform();
|
|
5499
|
+
},
|
|
5500
|
+
rotateCCW: () => {
|
|
5501
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5502
|
+
applyTransform();
|
|
4671
5503
|
},
|
|
4672
5504
|
goToPage: (page) => {
|
|
4673
5505
|
if (page >= 1 && page <= totalSlides) {
|