@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/angular.cjs
CHANGED
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var core = require('@angular/core');
|
|
6
6
|
var common = require('@angular/common');
|
|
7
7
|
var DOMPurify2 = require('dompurify');
|
|
8
|
+
var pdfjsLib = require('pdfjs-dist');
|
|
8
9
|
var docx = require('docx-preview');
|
|
9
10
|
var fflate = require('fflate');
|
|
10
11
|
var XLSX = require('xlsx');
|
|
@@ -38,6 +39,7 @@ function _interopNamespace(e) {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
var DOMPurify2__default = /*#__PURE__*/_interopDefault(DOMPurify2);
|
|
42
|
+
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
41
43
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
42
44
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
43
45
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
@@ -558,11 +560,21 @@ var ToolbarController = class {
|
|
|
558
560
|
el;
|
|
559
561
|
toolbarEl;
|
|
560
562
|
actions = [];
|
|
563
|
+
pageInputEl = null;
|
|
564
|
+
pageLabelEl = null;
|
|
561
565
|
constructor(container) {
|
|
562
566
|
this.el = container;
|
|
563
567
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
564
568
|
this.el.appendChild(this.toolbarEl);
|
|
565
569
|
}
|
|
570
|
+
setPage(page, max) {
|
|
571
|
+
if (this.pageInputEl) {
|
|
572
|
+
this.pageInputEl.value = page.toString();
|
|
573
|
+
}
|
|
574
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
575
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
566
578
|
update(actions) {
|
|
567
579
|
this.actions = actions;
|
|
568
580
|
this.render();
|
|
@@ -605,6 +617,7 @@ var ToolbarController = class {
|
|
|
605
617
|
if (action.type === "separator") {
|
|
606
618
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
607
619
|
} else if (action.type === "page-nav") {
|
|
620
|
+
const max = action.max ?? 1;
|
|
608
621
|
const prevBtn = this.createButton(
|
|
609
622
|
"prev",
|
|
610
623
|
ICON_PAGE_PREV,
|
|
@@ -623,7 +636,6 @@ var ToolbarController = class {
|
|
|
623
636
|
"Next Page",
|
|
624
637
|
() => {
|
|
625
638
|
const cur = parseInt(input.value, 10) || 1;
|
|
626
|
-
const max = action.max ?? 1;
|
|
627
639
|
if (cur < max) {
|
|
628
640
|
input.value = (cur + 1).toString();
|
|
629
641
|
action.execute("next", cur + 1);
|
|
@@ -635,15 +647,18 @@ var ToolbarController = class {
|
|
|
635
647
|
type: "number",
|
|
636
648
|
value: (action.value ?? 1).toString(),
|
|
637
649
|
min: "1",
|
|
638
|
-
max:
|
|
650
|
+
max: max.toString()
|
|
639
651
|
});
|
|
640
652
|
input.addEventListener("change", () => {
|
|
641
|
-
|
|
642
|
-
if (
|
|
643
|
-
|
|
644
|
-
|
|
653
|
+
let val = parseInt(input.value, 10);
|
|
654
|
+
if (isNaN(val)) val = 1;
|
|
655
|
+
val = Math.max(1, Math.min(max, val));
|
|
656
|
+
input.value = val.toString();
|
|
657
|
+
action.execute("go", val);
|
|
645
658
|
});
|
|
646
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
659
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
660
|
+
this.pageInputEl = input;
|
|
661
|
+
this.pageLabelEl = label;
|
|
647
662
|
groupEl.appendChild(prevBtn);
|
|
648
663
|
groupEl.appendChild(input);
|
|
649
664
|
groupEl.appendChild(label);
|
|
@@ -770,6 +785,8 @@ var FilePreviewViewer = class {
|
|
|
770
785
|
keyHandler = null;
|
|
771
786
|
currentContainer = null;
|
|
772
787
|
currentOptions = {};
|
|
788
|
+
resizeObserver = null;
|
|
789
|
+
fullscreenHandler = null;
|
|
773
790
|
/**
|
|
774
791
|
* Register a preview plugin.
|
|
775
792
|
*/
|
|
@@ -821,7 +838,13 @@ var FilePreviewViewer = class {
|
|
|
821
838
|
buffer,
|
|
822
839
|
options,
|
|
823
840
|
signal,
|
|
824
|
-
emit: (event, payload) =>
|
|
841
|
+
emit: (event, payload) => {
|
|
842
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
843
|
+
const total = payload.total ?? payload.totalPages;
|
|
844
|
+
this.toolbar?.setPage(payload.page, total);
|
|
845
|
+
}
|
|
846
|
+
this.eventEmitter.emit(event, payload);
|
|
847
|
+
}
|
|
825
848
|
});
|
|
826
849
|
this.activeInstance = instance;
|
|
827
850
|
this.hideLoading();
|
|
@@ -836,12 +859,31 @@ var FilePreviewViewer = class {
|
|
|
836
859
|
label: "Toggle Fullscreen",
|
|
837
860
|
type: "button",
|
|
838
861
|
group: "view",
|
|
839
|
-
execute: () => {
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
862
|
+
execute: async () => {
|
|
863
|
+
try {
|
|
864
|
+
const isNativeFs = !!document.fullscreenElement;
|
|
865
|
+
const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
|
|
866
|
+
if (!isNativeFs && !isCssFs) {
|
|
867
|
+
if (this.wrapperEl?.requestFullscreen) {
|
|
868
|
+
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
869
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
870
|
+
});
|
|
871
|
+
} else {
|
|
872
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
873
|
+
}
|
|
874
|
+
} else {
|
|
875
|
+
if (document.fullscreenElement) {
|
|
876
|
+
await document.exitFullscreen().catch(() => {
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
880
|
+
}
|
|
881
|
+
} catch {
|
|
882
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
844
883
|
}
|
|
884
|
+
setTimeout(() => {
|
|
885
|
+
this.activeInstance?.fitToPage?.();
|
|
886
|
+
}, 120);
|
|
845
887
|
}
|
|
846
888
|
});
|
|
847
889
|
}
|
|
@@ -855,6 +897,7 @@ var FilePreviewViewer = class {
|
|
|
855
897
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
856
898
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
857
899
|
instance.goToPage?.(index + 1);
|
|
900
|
+
this.toolbar?.setPage(index + 1);
|
|
858
901
|
});
|
|
859
902
|
if (options.showThumbnails) {
|
|
860
903
|
this.thumbnailPanel.show();
|
|
@@ -890,6 +933,15 @@ var FilePreviewViewer = class {
|
|
|
890
933
|
window.removeEventListener("keydown", this.keyHandler);
|
|
891
934
|
this.keyHandler = null;
|
|
892
935
|
}
|
|
936
|
+
if (this.resizeObserver) {
|
|
937
|
+
this.resizeObserver.disconnect();
|
|
938
|
+
this.resizeObserver = null;
|
|
939
|
+
}
|
|
940
|
+
if (this.fullscreenHandler) {
|
|
941
|
+
document.removeEventListener("fullscreenchange", this.fullscreenHandler);
|
|
942
|
+
document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
943
|
+
this.fullscreenHandler = null;
|
|
944
|
+
}
|
|
893
945
|
this.abort();
|
|
894
946
|
this.destroyInstance();
|
|
895
947
|
this.toolbar?.destroy();
|
|
@@ -969,6 +1021,25 @@ var FilePreviewViewer = class {
|
|
|
969
1021
|
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
|
|
970
1022
|
this.setupKeyboardShortcuts();
|
|
971
1023
|
this.setupDragAndDrop(container, options);
|
|
1024
|
+
this.setupResizeAndFullscreenListeners();
|
|
1025
|
+
}
|
|
1026
|
+
setupResizeAndFullscreenListeners() {
|
|
1027
|
+
if (this.fullscreenHandler) return;
|
|
1028
|
+
this.fullscreenHandler = () => {
|
|
1029
|
+
setTimeout(() => {
|
|
1030
|
+
this.activeInstance?.fitToPage?.();
|
|
1031
|
+
}, 100);
|
|
1032
|
+
};
|
|
1033
|
+
document.addEventListener("fullscreenchange", this.fullscreenHandler);
|
|
1034
|
+
document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
1035
|
+
if (typeof ResizeObserver !== "undefined" && this.contentEl) {
|
|
1036
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
1037
|
+
if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
|
|
1038
|
+
this.activeInstance.fitToPage?.();
|
|
1039
|
+
}
|
|
1040
|
+
});
|
|
1041
|
+
this.resizeObserver.observe(this.contentEl);
|
|
1042
|
+
}
|
|
972
1043
|
}
|
|
973
1044
|
setupKeyboardShortcuts() {
|
|
974
1045
|
if (this.keyHandler) return;
|
|
@@ -980,9 +1051,13 @@ var FilePreviewViewer = class {
|
|
|
980
1051
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
981
1052
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
982
1053
|
this.activeInstance.goToPage?.(cur + 1);
|
|
1054
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
1055
|
+
this.toolbar?.setPage(nextCur);
|
|
983
1056
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
984
1057
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
985
1058
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
1059
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
1060
|
+
this.toolbar?.setPage(prevCur);
|
|
986
1061
|
} else if (e.key === "+" || e.key === "=") {
|
|
987
1062
|
this.activeInstance.zoomIn?.();
|
|
988
1063
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1248,30 +1323,62 @@ var CfbfReader = class {
|
|
|
1248
1323
|
return result.subarray(0, targetSize);
|
|
1249
1324
|
}
|
|
1250
1325
|
};
|
|
1251
|
-
|
|
1252
|
-
|
|
1326
|
+
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1327
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1328
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1253
1331
|
var PdfPlugin = class {
|
|
1254
1332
|
id = "pdf";
|
|
1255
|
-
name = "PDF Preview";
|
|
1333
|
+
name = "PDF Document Preview";
|
|
1256
1334
|
extensions = [".pdf"];
|
|
1257
1335
|
mimeTypes = ["application/pdf"];
|
|
1258
1336
|
weight = 100;
|
|
1259
1337
|
supports(file) {
|
|
1260
1338
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1261
1339
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1262
|
-
|
|
1340
|
+
if (ext) return this.extensions.includes(ext);
|
|
1341
|
+
return this.mimeTypes.includes(mime || "");
|
|
1263
1342
|
}
|
|
1264
1343
|
getToolbarActions(instance) {
|
|
1344
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1345
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1265
1346
|
return [
|
|
1347
|
+
{
|
|
1348
|
+
id: "thumbnails",
|
|
1349
|
+
icon: "thumbnails",
|
|
1350
|
+
label: "Page Thumbnails",
|
|
1351
|
+
type: "button",
|
|
1352
|
+
group: "navigation",
|
|
1353
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1354
|
+
},
|
|
1355
|
+
{
|
|
1356
|
+
id: "page-nav",
|
|
1357
|
+
icon: "",
|
|
1358
|
+
label: "Page Navigation",
|
|
1359
|
+
type: "page-nav",
|
|
1360
|
+
group: "navigation",
|
|
1361
|
+
value: curPage,
|
|
1362
|
+
max: totalPages,
|
|
1363
|
+
execute: (action, page) => {
|
|
1364
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1365
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1366
|
+
if (action === "prev") {
|
|
1367
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1368
|
+
} else if (action === "next") {
|
|
1369
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1370
|
+
} else if (typeof page === "number") {
|
|
1371
|
+
instance.goToPage?.(page);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
},
|
|
1266
1375
|
{
|
|
1267
1376
|
id: "zoom-out",
|
|
1268
1377
|
icon: "zoom-out",
|
|
1269
1378
|
label: "Zoom Out",
|
|
1270
1379
|
type: "button",
|
|
1271
1380
|
group: "zoom",
|
|
1272
|
-
execute: () =>
|
|
1273
|
-
instance.zoomOut?.();
|
|
1274
|
-
}
|
|
1381
|
+
execute: () => instance.zoomOut?.()
|
|
1275
1382
|
},
|
|
1276
1383
|
{
|
|
1277
1384
|
id: "zoom-in",
|
|
@@ -1279,9 +1386,7 @@ var PdfPlugin = class {
|
|
|
1279
1386
|
label: "Zoom In",
|
|
1280
1387
|
type: "button",
|
|
1281
1388
|
group: "zoom",
|
|
1282
|
-
execute: () =>
|
|
1283
|
-
instance.zoomIn?.();
|
|
1284
|
-
}
|
|
1389
|
+
execute: () => instance.zoomIn?.()
|
|
1285
1390
|
},
|
|
1286
1391
|
{
|
|
1287
1392
|
id: "fit-page",
|
|
@@ -1289,39 +1394,23 @@ var PdfPlugin = class {
|
|
|
1289
1394
|
label: "Fit to Page",
|
|
1290
1395
|
type: "button",
|
|
1291
1396
|
group: "zoom",
|
|
1292
|
-
execute: () =>
|
|
1293
|
-
instance.fitToPage?.();
|
|
1294
|
-
}
|
|
1397
|
+
execute: () => instance.fitToPage?.()
|
|
1295
1398
|
},
|
|
1296
1399
|
{
|
|
1297
1400
|
id: "rotate-cw",
|
|
1298
1401
|
icon: "rotate-cw",
|
|
1299
|
-
label: "Rotate",
|
|
1402
|
+
label: "Rotate Clockwise",
|
|
1300
1403
|
type: "button",
|
|
1301
1404
|
group: "view",
|
|
1302
|
-
execute: () =>
|
|
1303
|
-
instance.rotateCW?.();
|
|
1304
|
-
}
|
|
1305
|
-
},
|
|
1306
|
-
{
|
|
1307
|
-
id: "page-nav",
|
|
1308
|
-
icon: "page-nav",
|
|
1309
|
-
label: "Page Navigation",
|
|
1310
|
-
type: "page-nav",
|
|
1311
|
-
group: "navigation",
|
|
1312
|
-
execute: (page) => {
|
|
1313
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1314
|
-
}
|
|
1405
|
+
execute: () => instance.rotateCW?.()
|
|
1315
1406
|
},
|
|
1316
1407
|
{
|
|
1317
1408
|
id: "download",
|
|
1318
1409
|
icon: "download",
|
|
1319
|
-
label: "Download",
|
|
1410
|
+
label: "Download PDF",
|
|
1320
1411
|
type: "button",
|
|
1321
1412
|
group: "actions",
|
|
1322
|
-
execute: () =>
|
|
1323
|
-
instance.download?.();
|
|
1324
|
-
}
|
|
1413
|
+
execute: () => instance.download?.()
|
|
1325
1414
|
},
|
|
1326
1415
|
{
|
|
1327
1416
|
id: "print",
|
|
@@ -1329,99 +1418,224 @@ var PdfPlugin = class {
|
|
|
1329
1418
|
label: "Print",
|
|
1330
1419
|
type: "button",
|
|
1331
1420
|
group: "actions",
|
|
1332
|
-
execute: () =>
|
|
1333
|
-
instance.print?.();
|
|
1334
|
-
}
|
|
1421
|
+
execute: () => instance.print?.()
|
|
1335
1422
|
}
|
|
1336
1423
|
];
|
|
1337
1424
|
}
|
|
1338
1425
|
async render(ctx) {
|
|
1339
|
-
const
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1426
|
+
const container = document.createElement("div");
|
|
1427
|
+
container.className = "fp-pdf-container";
|
|
1428
|
+
container.style.width = "100%";
|
|
1429
|
+
container.style.height = "100%";
|
|
1430
|
+
container.style.overflow = "auto";
|
|
1431
|
+
container.style.display = "flex";
|
|
1432
|
+
container.style.flexDirection = "column";
|
|
1433
|
+
container.style.alignItems = "center";
|
|
1434
|
+
container.style.justifyContent = "flex-start";
|
|
1435
|
+
container.style.padding = "20px 16px";
|
|
1436
|
+
container.style.backgroundColor = "#0f172a";
|
|
1437
|
+
container.style.boxSizing = "border-box";
|
|
1438
|
+
container.style.position = "relative";
|
|
1439
|
+
const pageCard = document.createElement("div");
|
|
1440
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1441
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1442
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1443
|
+
pageCard.style.borderRadius = "4px";
|
|
1444
|
+
pageCard.style.overflow = "hidden";
|
|
1445
|
+
pageCard.style.lineHeight = "0";
|
|
1446
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1447
|
+
pageCard.style.position = "relative";
|
|
1448
|
+
pageCard.style.flexShrink = "0";
|
|
1449
|
+
let canvas = document.createElement("canvas");
|
|
1450
|
+
pageCard.appendChild(canvas);
|
|
1451
|
+
container.appendChild(pageCard);
|
|
1452
|
+
const indicator = document.createElement("div");
|
|
1453
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1454
|
+
indicator.style.position = "sticky";
|
|
1455
|
+
indicator.style.bottom = "16px";
|
|
1456
|
+
indicator.style.marginTop = "16px";
|
|
1457
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1458
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1459
|
+
indicator.style.color = "#f8fafc";
|
|
1460
|
+
indicator.style.fontSize = "12px";
|
|
1461
|
+
indicator.style.fontWeight = "600";
|
|
1462
|
+
indicator.style.padding = "5px 14px";
|
|
1463
|
+
indicator.style.borderRadius = "20px";
|
|
1464
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1465
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1466
|
+
indicator.style.zIndex = "10";
|
|
1467
|
+
indicator.style.userSelect = "none";
|
|
1468
|
+
indicator.style.pointerEvents = "none";
|
|
1469
|
+
container.appendChild(indicator);
|
|
1470
|
+
ctx.container.appendChild(container);
|
|
1471
|
+
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1472
|
+
data: new Uint8Array(ctx.buffer),
|
|
1473
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/cmaps/`,
|
|
1474
|
+
cMapPacked: true,
|
|
1475
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/standard_fonts/`
|
|
1476
|
+
});
|
|
1477
|
+
const pdfDoc = await loadingTask.promise;
|
|
1478
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1355
1479
|
let currentPage = 1;
|
|
1356
|
-
let
|
|
1480
|
+
let zoomScale = 1;
|
|
1357
1481
|
let rotation = 0;
|
|
1482
|
+
let currentRenderTask = null;
|
|
1483
|
+
const renderPage = async (pageNum) => {
|
|
1484
|
+
if (currentRenderTask) {
|
|
1485
|
+
try {
|
|
1486
|
+
currentRenderTask.cancel();
|
|
1487
|
+
} catch {
|
|
1488
|
+
}
|
|
1489
|
+
currentRenderTask = null;
|
|
1490
|
+
}
|
|
1491
|
+
const newCanvas = document.createElement("canvas");
|
|
1492
|
+
pageCard.replaceChild(newCanvas, canvas);
|
|
1493
|
+
canvas = newCanvas;
|
|
1494
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1495
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1496
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1497
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1498
|
+
const containerWidth = container.clientWidth || 900;
|
|
1499
|
+
const containerHeight = container.clientHeight || 700;
|
|
1500
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1501
|
+
const availWidth = Math.max(100, containerWidth - 48);
|
|
1502
|
+
const availHeight = Math.max(100, containerHeight - 88);
|
|
1503
|
+
const scaleW = availWidth / unscaledVp.width;
|
|
1504
|
+
const scaleH = availHeight / unscaledVp.height;
|
|
1505
|
+
const fitScale = Math.min(scaleW, scaleH);
|
|
1506
|
+
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1507
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1508
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1509
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1510
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1511
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1512
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1513
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1514
|
+
if (!canvasCtx) return;
|
|
1515
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1516
|
+
currentRenderTask = page.render({
|
|
1517
|
+
canvasContext: canvasCtx,
|
|
1518
|
+
viewport
|
|
1519
|
+
});
|
|
1520
|
+
try {
|
|
1521
|
+
await currentRenderTask.promise;
|
|
1522
|
+
} catch (err) {
|
|
1523
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1524
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1525
|
+
}
|
|
1526
|
+
} finally {
|
|
1527
|
+
currentRenderTask = null;
|
|
1528
|
+
}
|
|
1529
|
+
};
|
|
1530
|
+
await renderPage(1);
|
|
1358
1531
|
const cleanup = () => {
|
|
1359
|
-
|
|
1360
|
-
|
|
1532
|
+
if (currentRenderTask) {
|
|
1533
|
+
try {
|
|
1534
|
+
currentRenderTask.cancel();
|
|
1535
|
+
} catch {
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
try {
|
|
1539
|
+
pdfDoc.destroy();
|
|
1540
|
+
} catch {
|
|
1541
|
+
}
|
|
1542
|
+
container.remove();
|
|
1361
1543
|
ctx.container.innerHTML = "";
|
|
1362
1544
|
};
|
|
1363
1545
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1364
|
-
|
|
1546
|
+
const instance = {
|
|
1365
1547
|
destroy: cleanup,
|
|
1366
1548
|
zoomIn: () => {
|
|
1367
|
-
|
|
1368
|
-
|
|
1549
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1550
|
+
renderPage(currentPage);
|
|
1369
1551
|
},
|
|
1370
1552
|
zoomOut: () => {
|
|
1371
|
-
|
|
1372
|
-
|
|
1553
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1554
|
+
renderPage(currentPage);
|
|
1373
1555
|
},
|
|
1374
|
-
getZoom: () =>
|
|
1556
|
+
getZoom: () => zoomScale,
|
|
1375
1557
|
setZoom: (level) => {
|
|
1376
|
-
|
|
1377
|
-
|
|
1558
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1559
|
+
renderPage(currentPage);
|
|
1378
1560
|
},
|
|
1379
1561
|
fitToPage: () => {
|
|
1380
|
-
|
|
1381
|
-
|
|
1562
|
+
zoomScale = 1;
|
|
1563
|
+
rotation = 0;
|
|
1564
|
+
renderPage(currentPage);
|
|
1382
1565
|
},
|
|
1383
1566
|
rotateCW: () => {
|
|
1384
1567
|
rotation = (rotation + 90) % 360;
|
|
1385
|
-
|
|
1568
|
+
renderPage(currentPage);
|
|
1386
1569
|
},
|
|
1387
1570
|
rotateCCW: () => {
|
|
1388
1571
|
rotation = (rotation - 90 + 360) % 360;
|
|
1389
|
-
|
|
1572
|
+
renderPage(currentPage);
|
|
1390
1573
|
},
|
|
1391
1574
|
getRotation: () => rotation,
|
|
1575
|
+
getPageCount: () => totalPages,
|
|
1576
|
+
getCurrentPage: () => currentPage,
|
|
1392
1577
|
goToPage: (page) => {
|
|
1393
|
-
|
|
1394
|
-
iframe.src = `${url}#page=${page}`;
|
|
1578
|
+
renderPage(page);
|
|
1395
1579
|
},
|
|
1396
|
-
getCurrentPage: () => currentPage,
|
|
1397
1580
|
download: () => {
|
|
1581
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1582
|
+
const url = URL.createObjectURL(blob);
|
|
1398
1583
|
const a = document.createElement("a");
|
|
1399
1584
|
a.href = url;
|
|
1400
1585
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1401
1586
|
a.click();
|
|
1587
|
+
URL.revokeObjectURL(url);
|
|
1402
1588
|
},
|
|
1403
1589
|
print: () => {
|
|
1404
|
-
|
|
1590
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1591
|
+
const url = URL.createObjectURL(blob);
|
|
1592
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1593
|
+
hiddenIframe.style.position = "fixed";
|
|
1594
|
+
hiddenIframe.style.right = "0";
|
|
1595
|
+
hiddenIframe.style.bottom = "0";
|
|
1596
|
+
hiddenIframe.style.width = "0";
|
|
1597
|
+
hiddenIframe.style.height = "0";
|
|
1598
|
+
hiddenIframe.style.border = "0";
|
|
1599
|
+
document.body.appendChild(hiddenIframe);
|
|
1600
|
+
hiddenIframe.src = url;
|
|
1601
|
+
hiddenIframe.onload = () => {
|
|
1602
|
+
setTimeout(() => {
|
|
1603
|
+
hiddenIframe.contentWindow?.print();
|
|
1604
|
+
setTimeout(() => {
|
|
1605
|
+
hiddenIframe.remove();
|
|
1606
|
+
URL.revokeObjectURL(url);
|
|
1607
|
+
}, 1e3);
|
|
1608
|
+
}, 300);
|
|
1609
|
+
};
|
|
1405
1610
|
},
|
|
1406
1611
|
getThumbnails: async () => {
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1612
|
+
const thumbnails = [];
|
|
1613
|
+
const count = Math.min(totalPages, 50);
|
|
1614
|
+
for (let i = 1; i <= count; i++) {
|
|
1615
|
+
thumbnails.push({
|
|
1616
|
+
index: i,
|
|
1617
|
+
label: `Page ${i}`,
|
|
1618
|
+
render: async (thumbCanvas) => {
|
|
1619
|
+
try {
|
|
1620
|
+
const p = await pdfDoc.getPage(i);
|
|
1621
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1622
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1623
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1624
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1625
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1626
|
+
if (tCtx) {
|
|
1627
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1628
|
+
}
|
|
1629
|
+
} catch (e) {
|
|
1630
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1419
1631
|
}
|
|
1420
1632
|
}
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1633
|
+
});
|
|
1634
|
+
}
|
|
1635
|
+
return thumbnails;
|
|
1423
1636
|
}
|
|
1424
1637
|
};
|
|
1638
|
+
return instance;
|
|
1425
1639
|
}
|
|
1426
1640
|
};
|
|
1427
1641
|
function pdfPlugin() {
|
|
@@ -1748,7 +1962,31 @@ var DocxPlugin = class {
|
|
|
1748
1962
|
return this.mimeTypes.includes(mime || "");
|
|
1749
1963
|
}
|
|
1750
1964
|
getToolbarActions(instance) {
|
|
1751
|
-
|
|
1965
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1966
|
+
const actions = [];
|
|
1967
|
+
if (totalPages > 1) {
|
|
1968
|
+
actions.push({
|
|
1969
|
+
id: "page-nav",
|
|
1970
|
+
icon: "",
|
|
1971
|
+
label: "Page Navigation",
|
|
1972
|
+
type: "page-nav",
|
|
1973
|
+
group: "navigation",
|
|
1974
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1975
|
+
max: totalPages,
|
|
1976
|
+
execute: (action, page) => {
|
|
1977
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1978
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1979
|
+
if (action === "prev") {
|
|
1980
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1981
|
+
} else if (action === "next") {
|
|
1982
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1983
|
+
} else if (typeof page === "number") {
|
|
1984
|
+
instance.goToPage?.(page);
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
actions.push(
|
|
1752
1990
|
{
|
|
1753
1991
|
id: "zoom-out",
|
|
1754
1992
|
icon: "zoom-out",
|
|
@@ -1773,6 +2011,14 @@ var DocxPlugin = class {
|
|
|
1773
2011
|
group: "zoom",
|
|
1774
2012
|
execute: () => instance.fitToPage?.()
|
|
1775
2013
|
},
|
|
2014
|
+
{
|
|
2015
|
+
id: "rotate-cw",
|
|
2016
|
+
icon: "rotate-cw",
|
|
2017
|
+
label: "Rotate",
|
|
2018
|
+
type: "button",
|
|
2019
|
+
group: "view",
|
|
2020
|
+
execute: () => instance.rotateCW?.()
|
|
2021
|
+
},
|
|
1776
2022
|
{
|
|
1777
2023
|
id: "download",
|
|
1778
2024
|
icon: "download",
|
|
@@ -1789,7 +2035,8 @@ var DocxPlugin = class {
|
|
|
1789
2035
|
group: "actions",
|
|
1790
2036
|
execute: () => instance.print?.()
|
|
1791
2037
|
}
|
|
1792
|
-
|
|
2038
|
+
);
|
|
2039
|
+
return actions;
|
|
1793
2040
|
}
|
|
1794
2041
|
async render(ctx) {
|
|
1795
2042
|
const wrapper = document.createElement("div");
|
|
@@ -1865,7 +2112,71 @@ var DocxPlugin = class {
|
|
|
1865
2112
|
}
|
|
1866
2113
|
}
|
|
1867
2114
|
}
|
|
2115
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2116
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2117
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2118
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2119
|
+
let currentPage = 1;
|
|
2120
|
+
let indicator = null;
|
|
2121
|
+
if (totalPages > 1) {
|
|
2122
|
+
indicator = document.createElement("div");
|
|
2123
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2124
|
+
indicator.style.position = "sticky";
|
|
2125
|
+
indicator.style.bottom = "16px";
|
|
2126
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2127
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2128
|
+
indicator.style.color = "#f8fafc";
|
|
2129
|
+
indicator.style.fontSize = "12px";
|
|
2130
|
+
indicator.style.fontWeight = "600";
|
|
2131
|
+
indicator.style.padding = "5px 14px";
|
|
2132
|
+
indicator.style.borderRadius = "20px";
|
|
2133
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2134
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2135
|
+
indicator.style.zIndex = "10";
|
|
2136
|
+
indicator.style.userSelect = "none";
|
|
2137
|
+
indicator.style.pointerEvents = "none";
|
|
2138
|
+
indicator.style.textAlign = "center";
|
|
2139
|
+
indicator.style.width = "fit-content";
|
|
2140
|
+
indicator.style.margin = "16px auto 0";
|
|
2141
|
+
ctx.container.appendChild(indicator);
|
|
2142
|
+
}
|
|
2143
|
+
const showPage = (pageNum) => {
|
|
2144
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2145
|
+
if (pageElements.length > 1) {
|
|
2146
|
+
pageElements.forEach((sec, idx) => {
|
|
2147
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
if (indicator) {
|
|
2151
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2152
|
+
}
|
|
2153
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2154
|
+
};
|
|
2155
|
+
if (totalPages > 1) {
|
|
2156
|
+
showPage(1);
|
|
2157
|
+
}
|
|
2158
|
+
scale = 1;
|
|
2159
|
+
let rotation = 0;
|
|
2160
|
+
const calculateFitScale = () => {
|
|
2161
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2162
|
+
const elW = activeEl.offsetWidth || 816;
|
|
2163
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2164
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
2165
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
2166
|
+
const sW = availW / elW;
|
|
2167
|
+
const sH = availH / elH;
|
|
2168
|
+
return Math.min(1.1, Math.min(sW, sH));
|
|
2169
|
+
};
|
|
2170
|
+
const applyTransform = () => {
|
|
2171
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2172
|
+
wrapper.style.transformOrigin = "top center";
|
|
2173
|
+
};
|
|
2174
|
+
setTimeout(() => {
|
|
2175
|
+
scale = calculateFitScale();
|
|
2176
|
+
applyTransform();
|
|
2177
|
+
}, 60);
|
|
1868
2178
|
const cleanup = () => {
|
|
2179
|
+
indicator?.remove();
|
|
1869
2180
|
for (const url of createdBlobUrls) {
|
|
1870
2181
|
URL.revokeObjectURL(url);
|
|
1871
2182
|
}
|
|
@@ -1876,22 +2187,36 @@ var DocxPlugin = class {
|
|
|
1876
2187
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1877
2188
|
return {
|
|
1878
2189
|
destroy: cleanup,
|
|
2190
|
+
getPageCount: () => totalPages,
|
|
2191
|
+
getCurrentPage: () => currentPage,
|
|
2192
|
+
goToPage: (page) => {
|
|
2193
|
+
showPage(page);
|
|
2194
|
+
},
|
|
1879
2195
|
zoomIn: () => {
|
|
1880
|
-
scale += 0.
|
|
1881
|
-
|
|
2196
|
+
scale += 0.15;
|
|
2197
|
+
applyTransform();
|
|
1882
2198
|
},
|
|
1883
2199
|
zoomOut: () => {
|
|
1884
|
-
scale = Math.max(0.2, scale - 0.
|
|
1885
|
-
|
|
2200
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2201
|
+
applyTransform();
|
|
1886
2202
|
},
|
|
1887
2203
|
getZoom: () => scale,
|
|
1888
2204
|
setZoom: (level) => {
|
|
1889
2205
|
scale = level;
|
|
1890
|
-
|
|
2206
|
+
applyTransform();
|
|
1891
2207
|
},
|
|
1892
2208
|
fitToPage: () => {
|
|
1893
|
-
scale =
|
|
1894
|
-
|
|
2209
|
+
scale = calculateFitScale();
|
|
2210
|
+
rotation = 0;
|
|
2211
|
+
applyTransform();
|
|
2212
|
+
},
|
|
2213
|
+
rotateCW: () => {
|
|
2214
|
+
rotation = (rotation + 90) % 360;
|
|
2215
|
+
applyTransform();
|
|
2216
|
+
},
|
|
2217
|
+
rotateCCW: () => {
|
|
2218
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2219
|
+
applyTransform();
|
|
1895
2220
|
},
|
|
1896
2221
|
download: () => {
|
|
1897
2222
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
@@ -2140,7 +2465,31 @@ var ExcelPlugin = class {
|
|
|
2140
2465
|
return this.mimeTypes.includes(mime || "");
|
|
2141
2466
|
}
|
|
2142
2467
|
getToolbarActions(instance) {
|
|
2143
|
-
|
|
2468
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2469
|
+
const actions = [];
|
|
2470
|
+
if (totalSheets > 1) {
|
|
2471
|
+
actions.push({
|
|
2472
|
+
id: "page-nav",
|
|
2473
|
+
icon: "",
|
|
2474
|
+
label: "Sheet Navigation",
|
|
2475
|
+
type: "page-nav",
|
|
2476
|
+
group: "navigation",
|
|
2477
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2478
|
+
max: totalSheets,
|
|
2479
|
+
execute: (action, sheet) => {
|
|
2480
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2481
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2482
|
+
if (action === "prev") {
|
|
2483
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2484
|
+
} else if (action === "next") {
|
|
2485
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2486
|
+
} else if (typeof sheet === "number") {
|
|
2487
|
+
instance.goToPage?.(sheet);
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
});
|
|
2491
|
+
}
|
|
2492
|
+
actions.push(
|
|
2144
2493
|
{
|
|
2145
2494
|
id: "zoom-out",
|
|
2146
2495
|
icon: "zoom-out",
|
|
@@ -2162,13 +2511,23 @@ var ExcelPlugin = class {
|
|
|
2162
2511
|
}
|
|
2163
2512
|
},
|
|
2164
2513
|
{
|
|
2165
|
-
id: "page
|
|
2166
|
-
icon: "page
|
|
2167
|
-
label: "
|
|
2168
|
-
type: "
|
|
2169
|
-
group: "
|
|
2170
|
-
execute: (
|
|
2171
|
-
|
|
2514
|
+
id: "fit-page",
|
|
2515
|
+
icon: "fit-page",
|
|
2516
|
+
label: "Fit to View",
|
|
2517
|
+
type: "button",
|
|
2518
|
+
group: "zoom",
|
|
2519
|
+
execute: () => {
|
|
2520
|
+
instance.fitToPage?.();
|
|
2521
|
+
}
|
|
2522
|
+
},
|
|
2523
|
+
{
|
|
2524
|
+
id: "rotate-cw",
|
|
2525
|
+
icon: "rotate-cw",
|
|
2526
|
+
label: "Rotate",
|
|
2527
|
+
type: "button",
|
|
2528
|
+
group: "view",
|
|
2529
|
+
execute: () => {
|
|
2530
|
+
instance.rotateCW?.();
|
|
2172
2531
|
}
|
|
2173
2532
|
},
|
|
2174
2533
|
{
|
|
@@ -2191,7 +2550,8 @@ var ExcelPlugin = class {
|
|
|
2191
2550
|
instance.print?.();
|
|
2192
2551
|
}
|
|
2193
2552
|
}
|
|
2194
|
-
|
|
2553
|
+
);
|
|
2554
|
+
return actions;
|
|
2195
2555
|
}
|
|
2196
2556
|
async render(ctx) {
|
|
2197
2557
|
const container = document.createElement("div");
|
|
@@ -2220,9 +2580,23 @@ var ExcelPlugin = class {
|
|
|
2220
2580
|
container.appendChild(tabsArea);
|
|
2221
2581
|
ctx.container.appendChild(container);
|
|
2222
2582
|
let scale = 1;
|
|
2583
|
+
let rotation = 0;
|
|
2223
2584
|
let currentSheetIndex = 1;
|
|
2224
2585
|
let sheetNames = [];
|
|
2225
2586
|
let wb = null;
|
|
2587
|
+
const applyTransform = () => {
|
|
2588
|
+
contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2589
|
+
contentArea.style.transformOrigin = "top left";
|
|
2590
|
+
};
|
|
2591
|
+
const calculateFitScale = () => {
|
|
2592
|
+
const table = contentArea.querySelector("table");
|
|
2593
|
+
if (!table) return 1;
|
|
2594
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
2595
|
+
const availH = Math.max(200, container.clientHeight - 80);
|
|
2596
|
+
const tW = table.offsetWidth || 800;
|
|
2597
|
+
const tH = table.offsetHeight || 600;
|
|
2598
|
+
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2599
|
+
};
|
|
2226
2600
|
try {
|
|
2227
2601
|
wb = XLSX__namespace.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
2228
2602
|
sheetNames = wb.SheetNames || [];
|
|
@@ -2275,6 +2649,7 @@ var ExcelPlugin = class {
|
|
|
2275
2649
|
b.style.fontWeight = "normal";
|
|
2276
2650
|
}
|
|
2277
2651
|
});
|
|
2652
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2278
2653
|
};
|
|
2279
2654
|
if (sheetNames.length > 0) {
|
|
2280
2655
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2309,17 +2684,30 @@ var ExcelPlugin = class {
|
|
|
2309
2684
|
return {
|
|
2310
2685
|
destroy: cleanup,
|
|
2311
2686
|
zoomIn: () => {
|
|
2312
|
-
scale += 0.
|
|
2313
|
-
|
|
2687
|
+
scale += 0.15;
|
|
2688
|
+
applyTransform();
|
|
2314
2689
|
},
|
|
2315
2690
|
zoomOut: () => {
|
|
2316
|
-
scale = Math.max(0.2, scale - 0.
|
|
2317
|
-
|
|
2691
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2692
|
+
applyTransform();
|
|
2318
2693
|
},
|
|
2319
2694
|
getZoom: () => scale,
|
|
2320
2695
|
setZoom: (level) => {
|
|
2321
2696
|
scale = level;
|
|
2322
|
-
|
|
2697
|
+
applyTransform();
|
|
2698
|
+
},
|
|
2699
|
+
fitToPage: () => {
|
|
2700
|
+
scale = calculateFitScale();
|
|
2701
|
+
rotation = 0;
|
|
2702
|
+
applyTransform();
|
|
2703
|
+
},
|
|
2704
|
+
rotateCW: () => {
|
|
2705
|
+
rotation = (rotation + 90) % 360;
|
|
2706
|
+
applyTransform();
|
|
2707
|
+
},
|
|
2708
|
+
rotateCCW: () => {
|
|
2709
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2710
|
+
applyTransform();
|
|
2323
2711
|
},
|
|
2324
2712
|
goToPage: (page) => {
|
|
2325
2713
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -2524,7 +2912,31 @@ var CodePlugin = class {
|
|
|
2524
2912
|
return false;
|
|
2525
2913
|
}
|
|
2526
2914
|
getToolbarActions(instance) {
|
|
2527
|
-
|
|
2915
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2916
|
+
const actions = [];
|
|
2917
|
+
if (totalPages > 1) {
|
|
2918
|
+
actions.push({
|
|
2919
|
+
id: "page-nav",
|
|
2920
|
+
icon: "",
|
|
2921
|
+
label: "Page Navigation",
|
|
2922
|
+
type: "page-nav",
|
|
2923
|
+
group: "navigation",
|
|
2924
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2925
|
+
max: totalPages,
|
|
2926
|
+
execute: (action, page) => {
|
|
2927
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2928
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2929
|
+
if (action === "prev") {
|
|
2930
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2931
|
+
} else if (action === "next") {
|
|
2932
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2933
|
+
} else if (typeof page === "number") {
|
|
2934
|
+
instance.goToPage?.(page);
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
});
|
|
2938
|
+
}
|
|
2939
|
+
actions.push(
|
|
2528
2940
|
{
|
|
2529
2941
|
id: "zoom-out",
|
|
2530
2942
|
icon: "zoom-out",
|
|
@@ -2545,6 +2957,26 @@ var CodePlugin = class {
|
|
|
2545
2957
|
instance.zoomIn?.();
|
|
2546
2958
|
}
|
|
2547
2959
|
},
|
|
2960
|
+
{
|
|
2961
|
+
id: "fit-page",
|
|
2962
|
+
icon: "fit-page",
|
|
2963
|
+
label: "Fit to View",
|
|
2964
|
+
type: "button",
|
|
2965
|
+
group: "zoom",
|
|
2966
|
+
execute: () => {
|
|
2967
|
+
instance.fitToPage?.();
|
|
2968
|
+
}
|
|
2969
|
+
},
|
|
2970
|
+
{
|
|
2971
|
+
id: "rotate-cw",
|
|
2972
|
+
icon: "rotate-cw",
|
|
2973
|
+
label: "Rotate",
|
|
2974
|
+
type: "button",
|
|
2975
|
+
group: "view",
|
|
2976
|
+
execute: () => {
|
|
2977
|
+
instance.rotateCW?.();
|
|
2978
|
+
}
|
|
2979
|
+
},
|
|
2548
2980
|
{
|
|
2549
2981
|
id: "copy",
|
|
2550
2982
|
icon: "copy",
|
|
@@ -2575,11 +3007,16 @@ var CodePlugin = class {
|
|
|
2575
3007
|
instance.print?.();
|
|
2576
3008
|
}
|
|
2577
3009
|
}
|
|
2578
|
-
|
|
3010
|
+
);
|
|
3011
|
+
return actions;
|
|
2579
3012
|
}
|
|
2580
3013
|
async render(ctx) {
|
|
2581
3014
|
const decoder = new TextDecoder("utf-8");
|
|
2582
|
-
const
|
|
3015
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
3016
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
3017
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
3018
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
3019
|
+
let currentPage = 1;
|
|
2583
3020
|
const container = document.createElement("div");
|
|
2584
3021
|
container.style.width = "100%";
|
|
2585
3022
|
container.style.height = "100%";
|
|
@@ -2589,6 +3026,7 @@ var CodePlugin = class {
|
|
|
2589
3026
|
container.style.padding = "16px";
|
|
2590
3027
|
container.style.boxSizing = "border-box";
|
|
2591
3028
|
let fontSize = 13;
|
|
3029
|
+
let rotation = 0;
|
|
2592
3030
|
const pre = document.createElement("pre");
|
|
2593
3031
|
pre.style.margin = "0";
|
|
2594
3032
|
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
@@ -2598,25 +3036,66 @@ var CodePlugin = class {
|
|
|
2598
3036
|
pre.style.wordBreak = "break-all";
|
|
2599
3037
|
const code = document.createElement("code");
|
|
2600
3038
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
3039
|
+
const renderCodePage = (text) => {
|
|
3040
|
+
try {
|
|
3041
|
+
if (ext && hljs__default.default.getLanguage(ext)) {
|
|
3042
|
+
code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
|
|
3043
|
+
} else {
|
|
3044
|
+
code.innerHTML = hljs__default.default.highlightAuto(text).value;
|
|
3045
|
+
}
|
|
3046
|
+
} catch {
|
|
3047
|
+
code.textContent = text;
|
|
2606
3048
|
}
|
|
2607
|
-
}
|
|
2608
|
-
|
|
2609
|
-
}
|
|
3049
|
+
};
|
|
3050
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2610
3051
|
pre.appendChild(code);
|
|
2611
3052
|
container.appendChild(pre);
|
|
3053
|
+
let indicator = null;
|
|
3054
|
+
if (totalPages > 1) {
|
|
3055
|
+
indicator = document.createElement("div");
|
|
3056
|
+
indicator.className = "fp-code-page-indicator";
|
|
3057
|
+
indicator.style.position = "sticky";
|
|
3058
|
+
indicator.style.bottom = "16px";
|
|
3059
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3060
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3061
|
+
indicator.style.color = "#f8fafc";
|
|
3062
|
+
indicator.style.fontSize = "12px";
|
|
3063
|
+
indicator.style.fontWeight = "600";
|
|
3064
|
+
indicator.style.padding = "5px 14px";
|
|
3065
|
+
indicator.style.borderRadius = "20px";
|
|
3066
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3067
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3068
|
+
indicator.style.zIndex = "10";
|
|
3069
|
+
indicator.style.userSelect = "none";
|
|
3070
|
+
indicator.style.pointerEvents = "none";
|
|
3071
|
+
indicator.style.textAlign = "center";
|
|
3072
|
+
indicator.style.width = "fit-content";
|
|
3073
|
+
indicator.style.margin = "16px auto 0";
|
|
3074
|
+
container.appendChild(indicator);
|
|
3075
|
+
}
|
|
3076
|
+
const showPage = (pageNum) => {
|
|
3077
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3078
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3079
|
+
if (indicator) {
|
|
3080
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3081
|
+
}
|
|
3082
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3083
|
+
};
|
|
3084
|
+
if (totalPages > 1) {
|
|
3085
|
+
showPage(1);
|
|
3086
|
+
}
|
|
2612
3087
|
ctx.container.appendChild(container);
|
|
2613
3088
|
const cleanup = () => {
|
|
3089
|
+
indicator?.remove();
|
|
2614
3090
|
container.remove();
|
|
2615
3091
|
ctx.container.innerHTML = "";
|
|
2616
3092
|
};
|
|
2617
3093
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2618
3094
|
return {
|
|
2619
3095
|
destroy: cleanup,
|
|
3096
|
+
getPageCount: () => totalPages,
|
|
3097
|
+
getCurrentPage: () => currentPage,
|
|
3098
|
+
goToPage: (page) => showPage(page),
|
|
2620
3099
|
zoomIn: () => {
|
|
2621
3100
|
fontSize = Math.min(32, fontSize + 2);
|
|
2622
3101
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2630,6 +3109,22 @@ var CodePlugin = class {
|
|
|
2630
3109
|
fontSize = Math.round(13 * level);
|
|
2631
3110
|
pre.style.fontSize = `${fontSize}px`;
|
|
2632
3111
|
},
|
|
3112
|
+
fitToPage: () => {
|
|
3113
|
+
fontSize = 13;
|
|
3114
|
+
rotation = 0;
|
|
3115
|
+
pre.style.fontSize = "13px";
|
|
3116
|
+
pre.style.transform = "none";
|
|
3117
|
+
},
|
|
3118
|
+
rotateCW: () => {
|
|
3119
|
+
rotation = (rotation + 90) % 360;
|
|
3120
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3121
|
+
pre.style.transformOrigin = "top left";
|
|
3122
|
+
},
|
|
3123
|
+
rotateCCW: () => {
|
|
3124
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3125
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3126
|
+
pre.style.transformOrigin = "top left";
|
|
3127
|
+
},
|
|
2633
3128
|
download: () => {
|
|
2634
3129
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
2635
3130
|
const blob = new Blob([ctx.buffer], { type: mimeType });
|
|
@@ -2644,7 +3139,7 @@ var CodePlugin = class {
|
|
|
2644
3139
|
window.print();
|
|
2645
3140
|
},
|
|
2646
3141
|
copy: () => {
|
|
2647
|
-
navigator.clipboard?.writeText(
|
|
3142
|
+
navigator.clipboard?.writeText(fullText);
|
|
2648
3143
|
}
|
|
2649
3144
|
};
|
|
2650
3145
|
}
|
|
@@ -3141,6 +3636,14 @@ var PptxPlugin = class {
|
|
|
3141
3636
|
group: "zoom",
|
|
3142
3637
|
execute: () => instance.fitToPage?.()
|
|
3143
3638
|
},
|
|
3639
|
+
{
|
|
3640
|
+
id: "rotate-cw",
|
|
3641
|
+
icon: "rotate-cw",
|
|
3642
|
+
label: "Rotate",
|
|
3643
|
+
type: "button",
|
|
3644
|
+
group: "view",
|
|
3645
|
+
execute: () => instance.rotateCW?.()
|
|
3646
|
+
},
|
|
3144
3647
|
{
|
|
3145
3648
|
id: "download",
|
|
3146
3649
|
icon: "download",
|
|
@@ -3165,6 +3668,7 @@ var PptxPlugin = class {
|
|
|
3165
3668
|
const slideCount = renderer.slidePaths?.length || 1;
|
|
3166
3669
|
let currentSlide = 1;
|
|
3167
3670
|
let scale = 1;
|
|
3671
|
+
let rotation = 0;
|
|
3168
3672
|
const wrapper = document.createElement("div");
|
|
3169
3673
|
wrapper.className = "fp-pptx-wrapper";
|
|
3170
3674
|
wrapper.style.cssText = `
|
|
@@ -3187,6 +3691,8 @@ var PptxPlugin = class {
|
|
|
3187
3691
|
background: #ffffff;
|
|
3188
3692
|
transform-origin: top center;
|
|
3189
3693
|
transition: transform 0.2s ease;
|
|
3694
|
+
max-width: calc(100% - 32px);
|
|
3695
|
+
max-height: calc(100% - 48px);
|
|
3190
3696
|
`;
|
|
3191
3697
|
const canvas = document.createElement("canvas");
|
|
3192
3698
|
slideContainer.appendChild(canvas);
|
|
@@ -3194,10 +3700,22 @@ var PptxPlugin = class {
|
|
|
3194
3700
|
ctx.container.innerHTML = "";
|
|
3195
3701
|
ctx.container.style.overflow = "auto";
|
|
3196
3702
|
ctx.container.appendChild(wrapper);
|
|
3703
|
+
const calculateFitScale = () => {
|
|
3704
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
3705
|
+
const availH = Math.max(200, ctx.container.clientHeight - 72);
|
|
3706
|
+
const cW = canvas.offsetWidth || 1280;
|
|
3707
|
+
const cH = canvas.offsetHeight || 720;
|
|
3708
|
+
return Math.min(1, Math.min(availW / cW, availH / cH));
|
|
3709
|
+
};
|
|
3710
|
+
const applyTransform = () => {
|
|
3711
|
+
slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
3712
|
+
};
|
|
3197
3713
|
const renderCurrentSlide = async () => {
|
|
3198
3714
|
try {
|
|
3199
3715
|
await renderer.renderSlide(currentSlide - 1, canvas, 1280);
|
|
3200
3716
|
ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
|
|
3717
|
+
scale = calculateFitScale();
|
|
3718
|
+
applyTransform();
|
|
3201
3719
|
} catch (err) {
|
|
3202
3720
|
console.error("[PptxPlugin] Failed to render slide:", err);
|
|
3203
3721
|
}
|
|
@@ -3220,21 +3738,30 @@ var PptxPlugin = class {
|
|
|
3220
3738
|
getPageCount: () => slideCount,
|
|
3221
3739
|
getCurrentPage: () => currentSlide,
|
|
3222
3740
|
zoomIn: () => {
|
|
3223
|
-
scale += 0.
|
|
3224
|
-
|
|
3741
|
+
scale += 0.15;
|
|
3742
|
+
applyTransform();
|
|
3225
3743
|
},
|
|
3226
3744
|
zoomOut: () => {
|
|
3227
|
-
scale = Math.max(0.2, scale - 0.
|
|
3228
|
-
|
|
3745
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
3746
|
+
applyTransform();
|
|
3229
3747
|
},
|
|
3230
3748
|
getZoom: () => scale,
|
|
3231
3749
|
setZoom: (level) => {
|
|
3232
3750
|
scale = level;
|
|
3233
|
-
|
|
3751
|
+
applyTransform();
|
|
3234
3752
|
},
|
|
3235
3753
|
fitToPage: () => {
|
|
3236
|
-
scale =
|
|
3237
|
-
|
|
3754
|
+
scale = calculateFitScale();
|
|
3755
|
+
rotation = 0;
|
|
3756
|
+
applyTransform();
|
|
3757
|
+
},
|
|
3758
|
+
rotateCW: () => {
|
|
3759
|
+
rotation = (rotation + 90) % 360;
|
|
3760
|
+
applyTransform();
|
|
3761
|
+
},
|
|
3762
|
+
rotateCCW: () => {
|
|
3763
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3764
|
+
applyTransform();
|
|
3238
3765
|
},
|
|
3239
3766
|
getThumbnails: () => {
|
|
3240
3767
|
const list = [];
|
|
@@ -3466,7 +3993,31 @@ var RtfPlugin = class {
|
|
|
3466
3993
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3467
3994
|
}
|
|
3468
3995
|
getToolbarActions(instance) {
|
|
3469
|
-
|
|
3996
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3997
|
+
const actions = [];
|
|
3998
|
+
if (totalPages > 1) {
|
|
3999
|
+
actions.push({
|
|
4000
|
+
id: "page-nav",
|
|
4001
|
+
icon: "",
|
|
4002
|
+
label: "Page Navigation",
|
|
4003
|
+
type: "page-nav",
|
|
4004
|
+
group: "navigation",
|
|
4005
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4006
|
+
max: totalPages,
|
|
4007
|
+
execute: (action, page) => {
|
|
4008
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4009
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4010
|
+
if (action === "prev") {
|
|
4011
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4012
|
+
} else if (action === "next") {
|
|
4013
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4014
|
+
} else if (typeof page === "number") {
|
|
4015
|
+
instance.goToPage?.(page);
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
});
|
|
4019
|
+
}
|
|
4020
|
+
actions.push(
|
|
3470
4021
|
{
|
|
3471
4022
|
id: "zoom-out",
|
|
3472
4023
|
icon: "zoom-out",
|
|
@@ -3491,6 +4042,14 @@ var RtfPlugin = class {
|
|
|
3491
4042
|
group: "zoom",
|
|
3492
4043
|
execute: () => instance.fitToPage?.()
|
|
3493
4044
|
},
|
|
4045
|
+
{
|
|
4046
|
+
id: "rotate-cw",
|
|
4047
|
+
icon: "rotate-cw",
|
|
4048
|
+
label: "Rotate",
|
|
4049
|
+
type: "button",
|
|
4050
|
+
group: "view",
|
|
4051
|
+
execute: () => instance.rotateCW?.()
|
|
4052
|
+
},
|
|
3494
4053
|
{
|
|
3495
4054
|
id: "download",
|
|
3496
4055
|
icon: "download",
|
|
@@ -3507,7 +4066,8 @@ var RtfPlugin = class {
|
|
|
3507
4066
|
group: "actions",
|
|
3508
4067
|
execute: () => instance.print?.()
|
|
3509
4068
|
}
|
|
3510
|
-
|
|
4069
|
+
);
|
|
4070
|
+
return actions;
|
|
3511
4071
|
}
|
|
3512
4072
|
async render(ctx) {
|
|
3513
4073
|
const wrapper = document.createElement("div");
|
|
@@ -3526,44 +4086,124 @@ var RtfPlugin = class {
|
|
|
3526
4086
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3527
4087
|
ctx.container.appendChild(wrapper);
|
|
3528
4088
|
let scale = 1;
|
|
4089
|
+
let rotation = 0;
|
|
4090
|
+
let pageElements = [];
|
|
4091
|
+
const calculateFitScale = () => {
|
|
4092
|
+
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4093
|
+
const elW = activeEl.offsetWidth || 850;
|
|
4094
|
+
const elH = activeEl.offsetHeight || 1e3;
|
|
4095
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4096
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4097
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4098
|
+
};
|
|
4099
|
+
const applyTransform = () => {
|
|
4100
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4101
|
+
wrapper.style.transformOrigin = "top center";
|
|
4102
|
+
};
|
|
4103
|
+
setTimeout(() => {
|
|
4104
|
+
scale = calculateFitScale();
|
|
4105
|
+
applyTransform();
|
|
4106
|
+
}, 60);
|
|
3529
4107
|
try {
|
|
3530
4108
|
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3531
4109
|
RTFJS__namespace.loggingEnabled(false);
|
|
3532
4110
|
}
|
|
3533
4111
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3534
4112
|
const htmlElements = await doc.render();
|
|
3535
|
-
|
|
4113
|
+
pageElements = htmlElements;
|
|
4114
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
4115
|
+
const el = htmlElements[i];
|
|
4116
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3536
4117
|
wrapper.appendChild(el);
|
|
3537
4118
|
}
|
|
3538
4119
|
} catch (err) {
|
|
3539
4120
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3540
4121
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3541
4122
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3542
|
-
|
|
4123
|
+
const pre = document.createElement("pre");
|
|
4124
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
4125
|
+
pre.style.fontFamily = "serif";
|
|
4126
|
+
pre.style.color = "#333";
|
|
4127
|
+
pre.textContent = clean;
|
|
4128
|
+
wrapper.appendChild(pre);
|
|
4129
|
+
pageElements = [pre];
|
|
4130
|
+
}
|
|
4131
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
4132
|
+
let currentPage = 1;
|
|
4133
|
+
let indicator = null;
|
|
4134
|
+
if (totalPages > 1) {
|
|
4135
|
+
indicator = document.createElement("div");
|
|
4136
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
4137
|
+
indicator.style.position = "sticky";
|
|
4138
|
+
indicator.style.bottom = "16px";
|
|
4139
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4140
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4141
|
+
indicator.style.color = "#f8fafc";
|
|
4142
|
+
indicator.style.fontSize = "12px";
|
|
4143
|
+
indicator.style.fontWeight = "600";
|
|
4144
|
+
indicator.style.padding = "5px 14px";
|
|
4145
|
+
indicator.style.borderRadius = "20px";
|
|
4146
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4147
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4148
|
+
indicator.style.zIndex = "10";
|
|
4149
|
+
indicator.style.userSelect = "none";
|
|
4150
|
+
indicator.style.pointerEvents = "none";
|
|
4151
|
+
indicator.style.textAlign = "center";
|
|
4152
|
+
indicator.style.width = "fit-content";
|
|
4153
|
+
indicator.style.margin = "16px auto 0";
|
|
4154
|
+
ctx.container.appendChild(indicator);
|
|
4155
|
+
}
|
|
4156
|
+
const showPage = (pageNum) => {
|
|
4157
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4158
|
+
if (totalPages > 1) {
|
|
4159
|
+
pageElements.forEach((el, idx) => {
|
|
4160
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4161
|
+
});
|
|
4162
|
+
}
|
|
4163
|
+
if (indicator) {
|
|
4164
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4165
|
+
}
|
|
4166
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4167
|
+
};
|
|
4168
|
+
if (totalPages > 1) {
|
|
4169
|
+
showPage(1);
|
|
3543
4170
|
}
|
|
3544
4171
|
const cleanup = () => {
|
|
4172
|
+
indicator?.remove();
|
|
3545
4173
|
wrapper.remove();
|
|
3546
4174
|
ctx.container.innerHTML = "";
|
|
3547
4175
|
};
|
|
3548
4176
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3549
4177
|
return {
|
|
3550
4178
|
destroy: cleanup,
|
|
4179
|
+
getPageCount: () => totalPages,
|
|
4180
|
+
getCurrentPage: () => currentPage,
|
|
4181
|
+
goToPage: (page) => showPage(page),
|
|
3551
4182
|
zoomIn: () => {
|
|
3552
|
-
scale += 0.
|
|
3553
|
-
|
|
4183
|
+
scale += 0.15;
|
|
4184
|
+
applyTransform();
|
|
3554
4185
|
},
|
|
3555
4186
|
zoomOut: () => {
|
|
3556
|
-
scale = Math.max(0.2, scale - 0.
|
|
3557
|
-
|
|
4187
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4188
|
+
applyTransform();
|
|
3558
4189
|
},
|
|
3559
4190
|
getZoom: () => scale,
|
|
3560
4191
|
setZoom: (level) => {
|
|
3561
4192
|
scale = level;
|
|
3562
|
-
|
|
4193
|
+
applyTransform();
|
|
3563
4194
|
},
|
|
3564
4195
|
fitToPage: () => {
|
|
3565
|
-
scale =
|
|
3566
|
-
|
|
4196
|
+
scale = calculateFitScale();
|
|
4197
|
+
rotation = 0;
|
|
4198
|
+
applyTransform();
|
|
4199
|
+
},
|
|
4200
|
+
rotateCW: () => {
|
|
4201
|
+
rotation = (rotation + 90) % 360;
|
|
4202
|
+
applyTransform();
|
|
4203
|
+
},
|
|
4204
|
+
rotateCCW: () => {
|
|
4205
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4206
|
+
applyTransform();
|
|
3567
4207
|
},
|
|
3568
4208
|
download: () => {
|
|
3569
4209
|
const blob = new Blob([ctx.buffer], { type: "application/rtf" });
|
|
@@ -3735,41 +4375,41 @@ var OpenDocumentPlugin = class {
|
|
|
3735
4375
|
}
|
|
3736
4376
|
getToolbarActions(instance) {
|
|
3737
4377
|
const isPresentation = instance.isPresentation;
|
|
4378
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3738
4379
|
const actions = [];
|
|
3739
|
-
if (isPresentation) {
|
|
3740
|
-
|
|
3741
|
-
{
|
|
4380
|
+
if (isPresentation || totalPages > 1) {
|
|
4381
|
+
if (isPresentation) {
|
|
4382
|
+
actions.push({
|
|
3742
4383
|
id: "thumbnails",
|
|
3743
4384
|
icon: "thumbnails",
|
|
3744
4385
|
label: "Slide Thumbnails",
|
|
3745
4386
|
type: "button",
|
|
3746
4387
|
group: "navigation",
|
|
3747
4388
|
execute: () => instance.toggleThumbnails?.()
|
|
3748
|
-
}
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
}
|
|
4389
|
+
});
|
|
4390
|
+
}
|
|
4391
|
+
actions.push({
|
|
4392
|
+
id: "page-nav",
|
|
4393
|
+
icon: "",
|
|
4394
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4395
|
+
type: "page-nav",
|
|
4396
|
+
group: "navigation",
|
|
4397
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4398
|
+
max: totalPages,
|
|
4399
|
+
execute: (action, page) => {
|
|
4400
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4401
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4402
|
+
if (action === "prev") {
|
|
4403
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4404
|
+
} else if (action === "next") {
|
|
4405
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4406
|
+
} else if (typeof page === "number") {
|
|
4407
|
+
instance.goToPage?.(page);
|
|
4408
|
+
} else if (typeof action === "number") {
|
|
4409
|
+
instance.goToPage?.(action);
|
|
3770
4410
|
}
|
|
3771
4411
|
}
|
|
3772
|
-
);
|
|
4412
|
+
});
|
|
3773
4413
|
}
|
|
3774
4414
|
actions.push(
|
|
3775
4415
|
{
|
|
@@ -3791,11 +4431,19 @@ var OpenDocumentPlugin = class {
|
|
|
3791
4431
|
{
|
|
3792
4432
|
id: "fit-page",
|
|
3793
4433
|
icon: "fit-page",
|
|
3794
|
-
label: "Fit to Page",
|
|
4434
|
+
label: isPresentation ? "Fit to Slide" : "Fit to Page",
|
|
3795
4435
|
type: "button",
|
|
3796
4436
|
group: "zoom",
|
|
3797
4437
|
execute: () => instance.fitToPage?.()
|
|
3798
4438
|
},
|
|
4439
|
+
{
|
|
4440
|
+
id: "rotate-cw",
|
|
4441
|
+
icon: "rotate-cw",
|
|
4442
|
+
label: "Rotate",
|
|
4443
|
+
type: "button",
|
|
4444
|
+
group: "view",
|
|
4445
|
+
execute: () => instance.rotateCW?.()
|
|
4446
|
+
},
|
|
3799
4447
|
{
|
|
3800
4448
|
id: "download",
|
|
3801
4449
|
icon: "download",
|
|
@@ -3859,6 +4507,22 @@ var OpenDocumentPlugin = class {
|
|
|
3859
4507
|
container.appendChild(wrapper);
|
|
3860
4508
|
ctx.container.appendChild(container);
|
|
3861
4509
|
let scale = 1;
|
|
4510
|
+
let rotation = 0;
|
|
4511
|
+
const calculateFitScale = () => {
|
|
4512
|
+
const elW = wrapper.offsetWidth || 850;
|
|
4513
|
+
const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
|
|
4514
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4515
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4516
|
+
return Math.min(1, Math.min(availW / elW, availH / elH));
|
|
4517
|
+
};
|
|
4518
|
+
const applyTransform = () => {
|
|
4519
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4520
|
+
wrapper.style.transformOrigin = "top center";
|
|
4521
|
+
};
|
|
4522
|
+
setTimeout(() => {
|
|
4523
|
+
scale = calculateFitScale();
|
|
4524
|
+
applyTransform();
|
|
4525
|
+
}, 60);
|
|
3862
4526
|
let currentPage = 1;
|
|
3863
4527
|
let totalPages = 1;
|
|
3864
4528
|
let slides = [];
|
|
@@ -3917,21 +4581,30 @@ var OpenDocumentPlugin = class {
|
|
|
3917
4581
|
destroy: cleanup,
|
|
3918
4582
|
isPresentation,
|
|
3919
4583
|
zoomIn: () => {
|
|
3920
|
-
scale += 0.
|
|
3921
|
-
|
|
4584
|
+
scale += 0.15;
|
|
4585
|
+
applyTransform();
|
|
3922
4586
|
},
|
|
3923
4587
|
zoomOut: () => {
|
|
3924
|
-
scale = Math.max(0.2, scale - 0.
|
|
3925
|
-
|
|
4588
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4589
|
+
applyTransform();
|
|
3926
4590
|
},
|
|
3927
4591
|
getZoom: () => scale,
|
|
3928
4592
|
setZoom: (level) => {
|
|
3929
4593
|
scale = level;
|
|
3930
|
-
|
|
4594
|
+
applyTransform();
|
|
3931
4595
|
},
|
|
3932
4596
|
fitToPage: () => {
|
|
3933
|
-
scale =
|
|
3934
|
-
|
|
4597
|
+
scale = calculateFitScale();
|
|
4598
|
+
rotation = 0;
|
|
4599
|
+
applyTransform();
|
|
4600
|
+
},
|
|
4601
|
+
rotateCW: () => {
|
|
4602
|
+
rotation = (rotation + 90) % 360;
|
|
4603
|
+
applyTransform();
|
|
4604
|
+
},
|
|
4605
|
+
rotateCCW: () => {
|
|
4606
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4607
|
+
applyTransform();
|
|
3935
4608
|
},
|
|
3936
4609
|
goToPage,
|
|
3937
4610
|
getPageCount: () => totalPages,
|
|
@@ -4152,7 +4825,31 @@ var DocPlugin = class {
|
|
|
4152
4825
|
return this.mimeTypes.includes(mime || "");
|
|
4153
4826
|
}
|
|
4154
4827
|
getToolbarActions(instance) {
|
|
4155
|
-
|
|
4828
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4829
|
+
const actions = [];
|
|
4830
|
+
if (totalPages > 1) {
|
|
4831
|
+
actions.push({
|
|
4832
|
+
id: "page-nav",
|
|
4833
|
+
icon: "",
|
|
4834
|
+
label: "Page Navigation",
|
|
4835
|
+
type: "page-nav",
|
|
4836
|
+
group: "navigation",
|
|
4837
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4838
|
+
max: totalPages,
|
|
4839
|
+
execute: (action, page) => {
|
|
4840
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4841
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4842
|
+
if (action === "prev") {
|
|
4843
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4844
|
+
} else if (action === "next") {
|
|
4845
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4846
|
+
} else if (typeof page === "number") {
|
|
4847
|
+
instance.goToPage?.(page);
|
|
4848
|
+
}
|
|
4849
|
+
}
|
|
4850
|
+
});
|
|
4851
|
+
}
|
|
4852
|
+
actions.push(
|
|
4156
4853
|
{
|
|
4157
4854
|
id: "zoom-out",
|
|
4158
4855
|
icon: "zoom-out",
|
|
@@ -4177,6 +4874,14 @@ var DocPlugin = class {
|
|
|
4177
4874
|
group: "zoom",
|
|
4178
4875
|
execute: () => instance.fitToPage?.()
|
|
4179
4876
|
},
|
|
4877
|
+
{
|
|
4878
|
+
id: "rotate-cw",
|
|
4879
|
+
icon: "rotate-cw",
|
|
4880
|
+
label: "Rotate",
|
|
4881
|
+
type: "button",
|
|
4882
|
+
group: "view",
|
|
4883
|
+
execute: () => instance.rotateCW?.()
|
|
4884
|
+
},
|
|
4180
4885
|
{
|
|
4181
4886
|
id: "copy",
|
|
4182
4887
|
icon: "copy",
|
|
@@ -4201,7 +4906,8 @@ var DocPlugin = class {
|
|
|
4201
4906
|
group: "actions",
|
|
4202
4907
|
execute: () => instance.print?.()
|
|
4203
4908
|
}
|
|
4204
|
-
|
|
4909
|
+
);
|
|
4910
|
+
return actions;
|
|
4205
4911
|
}
|
|
4206
4912
|
async render(ctx) {
|
|
4207
4913
|
const container = document.createElement("div");
|
|
@@ -4228,6 +4934,7 @@ var DocPlugin = class {
|
|
|
4228
4934
|
ctx.container.appendChild(container);
|
|
4229
4935
|
let scale = 1;
|
|
4230
4936
|
let extractedRawText = "";
|
|
4937
|
+
let isFallback = false;
|
|
4231
4938
|
try {
|
|
4232
4939
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4233
4940
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4241,42 +4948,131 @@ var DocPlugin = class {
|
|
|
4241
4948
|
const tableStream = cfbf.readStream(tableName);
|
|
4242
4949
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4243
4950
|
extractedRawText = text;
|
|
4244
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4245
4951
|
} catch (err) {
|
|
4246
4952
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4247
4953
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4248
4954
|
extractedRawText = fallback;
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4955
|
+
isFallback = true;
|
|
4956
|
+
}
|
|
4957
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4958
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4959
|
+
let currentPage = 1;
|
|
4960
|
+
wrapper.innerHTML = "";
|
|
4961
|
+
const pageCards = [];
|
|
4962
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4963
|
+
const pageCard = document.createElement("div");
|
|
4964
|
+
pageCard.className = "fp-doc-page-card";
|
|
4965
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4966
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4967
|
+
pageCard.style.borderRadius = "4px";
|
|
4968
|
+
pageCard.style.padding = "56px 48px";
|
|
4969
|
+
pageCard.style.minHeight = "100%";
|
|
4970
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4971
|
+
if (isFallback && i === 0) {
|
|
4972
|
+
pageCard.innerHTML = `
|
|
4973
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4974
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4975
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4976
|
+
</div>
|
|
4977
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4978
|
+
`;
|
|
4979
|
+
} else {
|
|
4980
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4981
|
+
}
|
|
4982
|
+
wrapper.appendChild(pageCard);
|
|
4983
|
+
pageCards.push(pageCard);
|
|
4984
|
+
}
|
|
4985
|
+
let indicator = null;
|
|
4986
|
+
if (totalPages > 1) {
|
|
4987
|
+
indicator = document.createElement("div");
|
|
4988
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4989
|
+
indicator.style.position = "sticky";
|
|
4990
|
+
indicator.style.bottom = "16px";
|
|
4991
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4992
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4993
|
+
indicator.style.color = "#f8fafc";
|
|
4994
|
+
indicator.style.fontSize = "12px";
|
|
4995
|
+
indicator.style.fontWeight = "600";
|
|
4996
|
+
indicator.style.padding = "5px 14px";
|
|
4997
|
+
indicator.style.borderRadius = "20px";
|
|
4998
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4999
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
5000
|
+
indicator.style.zIndex = "10";
|
|
5001
|
+
indicator.style.userSelect = "none";
|
|
5002
|
+
indicator.style.pointerEvents = "none";
|
|
5003
|
+
indicator.style.textAlign = "center";
|
|
5004
|
+
indicator.style.width = "fit-content";
|
|
5005
|
+
indicator.style.margin = "16px auto 0";
|
|
5006
|
+
container.appendChild(indicator);
|
|
5007
|
+
}
|
|
5008
|
+
const showPage = (pageNum) => {
|
|
5009
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
5010
|
+
if (totalPages > 1) {
|
|
5011
|
+
pageCards.forEach((card, idx) => {
|
|
5012
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
5013
|
+
});
|
|
5014
|
+
}
|
|
5015
|
+
if (indicator) {
|
|
5016
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
5017
|
+
}
|
|
5018
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
5019
|
+
};
|
|
5020
|
+
if (totalPages > 1) {
|
|
5021
|
+
showPage(1);
|
|
4256
5022
|
}
|
|
5023
|
+
let rotation = 0;
|
|
5024
|
+
const calculateFitScale = () => {
|
|
5025
|
+
const activeCard = pageCards[currentPage - 1] || wrapper;
|
|
5026
|
+
const elW = activeCard.offsetWidth || 850;
|
|
5027
|
+
const elH = activeCard.offsetHeight || 1e3;
|
|
5028
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
5029
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
5030
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
5031
|
+
};
|
|
5032
|
+
const applyTransform = () => {
|
|
5033
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5034
|
+
wrapper.style.transformOrigin = "top center";
|
|
5035
|
+
};
|
|
5036
|
+
setTimeout(() => {
|
|
5037
|
+
scale = calculateFitScale();
|
|
5038
|
+
applyTransform();
|
|
5039
|
+
}, 60);
|
|
4257
5040
|
const cleanup = () => {
|
|
5041
|
+
indicator?.remove();
|
|
4258
5042
|
container.remove();
|
|
4259
5043
|
ctx.container.innerHTML = "";
|
|
4260
5044
|
};
|
|
4261
5045
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4262
5046
|
return {
|
|
4263
5047
|
destroy: cleanup,
|
|
5048
|
+
getPageCount: () => totalPages,
|
|
5049
|
+
getCurrentPage: () => currentPage,
|
|
5050
|
+
goToPage: (page) => showPage(page),
|
|
4264
5051
|
zoomIn: () => {
|
|
4265
|
-
scale += 0.
|
|
4266
|
-
|
|
5052
|
+
scale += 0.15;
|
|
5053
|
+
applyTransform();
|
|
4267
5054
|
},
|
|
4268
5055
|
zoomOut: () => {
|
|
4269
|
-
scale = Math.max(0.2, scale - 0.
|
|
4270
|
-
|
|
5056
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5057
|
+
applyTransform();
|
|
4271
5058
|
},
|
|
4272
5059
|
getZoom: () => scale,
|
|
4273
5060
|
setZoom: (level) => {
|
|
4274
5061
|
scale = level;
|
|
4275
|
-
|
|
5062
|
+
applyTransform();
|
|
4276
5063
|
},
|
|
4277
5064
|
fitToPage: () => {
|
|
4278
|
-
scale =
|
|
4279
|
-
|
|
5065
|
+
scale = calculateFitScale();
|
|
5066
|
+
rotation = 0;
|
|
5067
|
+
applyTransform();
|
|
5068
|
+
},
|
|
5069
|
+
rotateCW: () => {
|
|
5070
|
+
rotation = (rotation + 90) % 360;
|
|
5071
|
+
applyTransform();
|
|
5072
|
+
},
|
|
5073
|
+
rotateCCW: () => {
|
|
5074
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5075
|
+
applyTransform();
|
|
4280
5076
|
},
|
|
4281
5077
|
copy: () => {
|
|
4282
5078
|
navigator.clipboard.writeText(extractedRawText);
|
|
@@ -4392,11 +5188,16 @@ var DocPlugin = class {
|
|
|
4392
5188
|
heuristicTextExtraction(buffer) {
|
|
4393
5189
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4394
5190
|
}
|
|
5191
|
+
splitIntoPages(text) {
|
|
5192
|
+
if (!text) return [""];
|
|
5193
|
+
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);
|
|
5194
|
+
return parts.length > 0 ? parts : [text];
|
|
5195
|
+
}
|
|
4395
5196
|
/**
|
|
4396
5197
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4397
5198
|
*/
|
|
4398
5199
|
formatDocToHtml(text, filename) {
|
|
4399
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
5200
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4400
5201
|
let html = "";
|
|
4401
5202
|
let inList = false;
|
|
4402
5203
|
for (const rawLine of lines) {
|
|
@@ -4511,6 +5312,14 @@ var PptPlugin = class {
|
|
|
4511
5312
|
group: "zoom",
|
|
4512
5313
|
execute: () => instance.fitToPage?.()
|
|
4513
5314
|
},
|
|
5315
|
+
{
|
|
5316
|
+
id: "rotate-cw",
|
|
5317
|
+
icon: "rotate-cw",
|
|
5318
|
+
label: "Rotate",
|
|
5319
|
+
type: "button",
|
|
5320
|
+
group: "view",
|
|
5321
|
+
execute: () => instance.rotateCW?.()
|
|
5322
|
+
},
|
|
4514
5323
|
{
|
|
4515
5324
|
id: "download",
|
|
4516
5325
|
icon: "download",
|
|
@@ -4544,22 +5353,36 @@ var PptPlugin = class {
|
|
|
4544
5353
|
const slideCard = document.createElement("div");
|
|
4545
5354
|
slideCard.className = "fp-ppt-slide-card";
|
|
4546
5355
|
slideCard.style.width = "960px";
|
|
4547
|
-
slideCard.style.maxWidth = "
|
|
5356
|
+
slideCard.style.maxWidth = "calc(100% - 32px)";
|
|
5357
|
+
slideCard.style.maxHeight = "calc(100% - 48px)";
|
|
4548
5358
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4549
5359
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4550
5360
|
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4551
5361
|
slideCard.style.borderRadius = "8px";
|
|
4552
5362
|
slideCard.style.boxSizing = "border-box";
|
|
4553
5363
|
slideCard.style.position = "relative";
|
|
4554
|
-
slideCard.style.overflow = "hidden";
|
|
4555
|
-
slideCard.style.transformOrigin = "center center";
|
|
4556
5364
|
slideCard.style.transition = "transform 0.2s ease";
|
|
5365
|
+
slideCard.style.transformOrigin = "center center";
|
|
5366
|
+
slideCard.style.flexShrink = "0";
|
|
4557
5367
|
container.appendChild(slideCard);
|
|
4558
5368
|
ctx.container.appendChild(container);
|
|
4559
5369
|
let scale = 1;
|
|
5370
|
+
let rotation = 0;
|
|
4560
5371
|
let currentSlide = 1;
|
|
4561
5372
|
let slides = [];
|
|
4562
5373
|
const createdBlobUrls = [];
|
|
5374
|
+
const calculateFitScale = () => {
|
|
5375
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
5376
|
+
const availH = Math.max(200, container.clientHeight - 72);
|
|
5377
|
+
return Math.min(1, Math.min(availW / 960, availH / 540));
|
|
5378
|
+
};
|
|
5379
|
+
const applyTransform = () => {
|
|
5380
|
+
slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5381
|
+
};
|
|
5382
|
+
setTimeout(() => {
|
|
5383
|
+
scale = calculateFitScale();
|
|
5384
|
+
applyTransform();
|
|
5385
|
+
}, 60);
|
|
4563
5386
|
try {
|
|
4564
5387
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4565
5388
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
@@ -4660,21 +5483,30 @@ var PptPlugin = class {
|
|
|
4660
5483
|
return {
|
|
4661
5484
|
destroy: cleanup,
|
|
4662
5485
|
zoomIn: () => {
|
|
4663
|
-
scale += 0.
|
|
4664
|
-
|
|
5486
|
+
scale += 0.15;
|
|
5487
|
+
applyTransform();
|
|
4665
5488
|
},
|
|
4666
5489
|
zoomOut: () => {
|
|
4667
|
-
scale = Math.max(0.
|
|
4668
|
-
|
|
5490
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5491
|
+
applyTransform();
|
|
4669
5492
|
},
|
|
4670
5493
|
getZoom: () => scale,
|
|
4671
5494
|
setZoom: (level) => {
|
|
4672
5495
|
scale = level;
|
|
4673
|
-
|
|
5496
|
+
applyTransform();
|
|
4674
5497
|
},
|
|
4675
5498
|
fitToPage: () => {
|
|
4676
|
-
scale =
|
|
4677
|
-
|
|
5499
|
+
scale = calculateFitScale();
|
|
5500
|
+
rotation = 0;
|
|
5501
|
+
applyTransform();
|
|
5502
|
+
},
|
|
5503
|
+
rotateCW: () => {
|
|
5504
|
+
rotation = (rotation + 90) % 360;
|
|
5505
|
+
applyTransform();
|
|
5506
|
+
},
|
|
5507
|
+
rotateCCW: () => {
|
|
5508
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5509
|
+
applyTransform();
|
|
4678
5510
|
},
|
|
4679
5511
|
goToPage: (page) => {
|
|
4680
5512
|
if (page >= 1 && page <= totalSlides) {
|