@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.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Component, ChangeDetectionStrategy, Input, Output, ViewChild, EventEmitter as EventEmitter$1 } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import DOMPurify2 from 'dompurify';
|
|
4
|
+
import * as pdfjsLib from 'pdfjs-dist';
|
|
4
5
|
import * as docx from 'docx-preview';
|
|
5
6
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
6
7
|
import * as XLSX from 'xlsx';
|
|
@@ -527,11 +528,21 @@ var ToolbarController = class {
|
|
|
527
528
|
el;
|
|
528
529
|
toolbarEl;
|
|
529
530
|
actions = [];
|
|
531
|
+
pageInputEl = null;
|
|
532
|
+
pageLabelEl = null;
|
|
530
533
|
constructor(container) {
|
|
531
534
|
this.el = container;
|
|
532
535
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
533
536
|
this.el.appendChild(this.toolbarEl);
|
|
534
537
|
}
|
|
538
|
+
setPage(page, max) {
|
|
539
|
+
if (this.pageInputEl) {
|
|
540
|
+
this.pageInputEl.value = page.toString();
|
|
541
|
+
}
|
|
542
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
543
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
535
546
|
update(actions) {
|
|
536
547
|
this.actions = actions;
|
|
537
548
|
this.render();
|
|
@@ -574,6 +585,7 @@ var ToolbarController = class {
|
|
|
574
585
|
if (action.type === "separator") {
|
|
575
586
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
576
587
|
} else if (action.type === "page-nav") {
|
|
588
|
+
const max = action.max ?? 1;
|
|
577
589
|
const prevBtn = this.createButton(
|
|
578
590
|
"prev",
|
|
579
591
|
ICON_PAGE_PREV,
|
|
@@ -592,7 +604,6 @@ var ToolbarController = class {
|
|
|
592
604
|
"Next Page",
|
|
593
605
|
() => {
|
|
594
606
|
const cur = parseInt(input.value, 10) || 1;
|
|
595
|
-
const max = action.max ?? 1;
|
|
596
607
|
if (cur < max) {
|
|
597
608
|
input.value = (cur + 1).toString();
|
|
598
609
|
action.execute("next", cur + 1);
|
|
@@ -604,15 +615,18 @@ var ToolbarController = class {
|
|
|
604
615
|
type: "number",
|
|
605
616
|
value: (action.value ?? 1).toString(),
|
|
606
617
|
min: "1",
|
|
607
|
-
max:
|
|
618
|
+
max: max.toString()
|
|
608
619
|
});
|
|
609
620
|
input.addEventListener("change", () => {
|
|
610
|
-
|
|
611
|
-
if (
|
|
612
|
-
|
|
613
|
-
|
|
621
|
+
let val = parseInt(input.value, 10);
|
|
622
|
+
if (isNaN(val)) val = 1;
|
|
623
|
+
val = Math.max(1, Math.min(max, val));
|
|
624
|
+
input.value = val.toString();
|
|
625
|
+
action.execute("go", val);
|
|
614
626
|
});
|
|
615
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
627
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
628
|
+
this.pageInputEl = input;
|
|
629
|
+
this.pageLabelEl = label;
|
|
616
630
|
groupEl.appendChild(prevBtn);
|
|
617
631
|
groupEl.appendChild(input);
|
|
618
632
|
groupEl.appendChild(label);
|
|
@@ -739,6 +753,8 @@ var FilePreviewViewer = class {
|
|
|
739
753
|
keyHandler = null;
|
|
740
754
|
currentContainer = null;
|
|
741
755
|
currentOptions = {};
|
|
756
|
+
resizeObserver = null;
|
|
757
|
+
fullscreenHandler = null;
|
|
742
758
|
/**
|
|
743
759
|
* Register a preview plugin.
|
|
744
760
|
*/
|
|
@@ -790,7 +806,13 @@ var FilePreviewViewer = class {
|
|
|
790
806
|
buffer,
|
|
791
807
|
options,
|
|
792
808
|
signal,
|
|
793
|
-
emit: (event, payload) =>
|
|
809
|
+
emit: (event, payload) => {
|
|
810
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
811
|
+
const total = payload.total ?? payload.totalPages;
|
|
812
|
+
this.toolbar?.setPage(payload.page, total);
|
|
813
|
+
}
|
|
814
|
+
this.eventEmitter.emit(event, payload);
|
|
815
|
+
}
|
|
794
816
|
});
|
|
795
817
|
this.activeInstance = instance;
|
|
796
818
|
this.hideLoading();
|
|
@@ -805,12 +827,31 @@ var FilePreviewViewer = class {
|
|
|
805
827
|
label: "Toggle Fullscreen",
|
|
806
828
|
type: "button",
|
|
807
829
|
group: "view",
|
|
808
|
-
execute: () => {
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
830
|
+
execute: async () => {
|
|
831
|
+
try {
|
|
832
|
+
const isNativeFs = !!document.fullscreenElement;
|
|
833
|
+
const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
|
|
834
|
+
if (!isNativeFs && !isCssFs) {
|
|
835
|
+
if (this.wrapperEl?.requestFullscreen) {
|
|
836
|
+
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
837
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
838
|
+
});
|
|
839
|
+
} else {
|
|
840
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
841
|
+
}
|
|
842
|
+
} else {
|
|
843
|
+
if (document.fullscreenElement) {
|
|
844
|
+
await document.exitFullscreen().catch(() => {
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
848
|
+
}
|
|
849
|
+
} catch {
|
|
850
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
813
851
|
}
|
|
852
|
+
setTimeout(() => {
|
|
853
|
+
this.activeInstance?.fitToPage?.();
|
|
854
|
+
}, 120);
|
|
814
855
|
}
|
|
815
856
|
});
|
|
816
857
|
}
|
|
@@ -824,6 +865,7 @@ var FilePreviewViewer = class {
|
|
|
824
865
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
825
866
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
826
867
|
instance.goToPage?.(index + 1);
|
|
868
|
+
this.toolbar?.setPage(index + 1);
|
|
827
869
|
});
|
|
828
870
|
if (options.showThumbnails) {
|
|
829
871
|
this.thumbnailPanel.show();
|
|
@@ -859,6 +901,15 @@ var FilePreviewViewer = class {
|
|
|
859
901
|
window.removeEventListener("keydown", this.keyHandler);
|
|
860
902
|
this.keyHandler = null;
|
|
861
903
|
}
|
|
904
|
+
if (this.resizeObserver) {
|
|
905
|
+
this.resizeObserver.disconnect();
|
|
906
|
+
this.resizeObserver = null;
|
|
907
|
+
}
|
|
908
|
+
if (this.fullscreenHandler) {
|
|
909
|
+
document.removeEventListener("fullscreenchange", this.fullscreenHandler);
|
|
910
|
+
document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
911
|
+
this.fullscreenHandler = null;
|
|
912
|
+
}
|
|
862
913
|
this.abort();
|
|
863
914
|
this.destroyInstance();
|
|
864
915
|
this.toolbar?.destroy();
|
|
@@ -938,6 +989,25 @@ var FilePreviewViewer = class {
|
|
|
938
989
|
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
|
|
939
990
|
this.setupKeyboardShortcuts();
|
|
940
991
|
this.setupDragAndDrop(container, options);
|
|
992
|
+
this.setupResizeAndFullscreenListeners();
|
|
993
|
+
}
|
|
994
|
+
setupResizeAndFullscreenListeners() {
|
|
995
|
+
if (this.fullscreenHandler) return;
|
|
996
|
+
this.fullscreenHandler = () => {
|
|
997
|
+
setTimeout(() => {
|
|
998
|
+
this.activeInstance?.fitToPage?.();
|
|
999
|
+
}, 100);
|
|
1000
|
+
};
|
|
1001
|
+
document.addEventListener("fullscreenchange", this.fullscreenHandler);
|
|
1002
|
+
document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
1003
|
+
if (typeof ResizeObserver !== "undefined" && this.contentEl) {
|
|
1004
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
1005
|
+
if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
|
|
1006
|
+
this.activeInstance.fitToPage?.();
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
this.resizeObserver.observe(this.contentEl);
|
|
1010
|
+
}
|
|
941
1011
|
}
|
|
942
1012
|
setupKeyboardShortcuts() {
|
|
943
1013
|
if (this.keyHandler) return;
|
|
@@ -949,9 +1019,13 @@ var FilePreviewViewer = class {
|
|
|
949
1019
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
950
1020
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
951
1021
|
this.activeInstance.goToPage?.(cur + 1);
|
|
1022
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
1023
|
+
this.toolbar?.setPage(nextCur);
|
|
952
1024
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
953
1025
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
954
1026
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
1027
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
1028
|
+
this.toolbar?.setPage(prevCur);
|
|
955
1029
|
} else if (e.key === "+" || e.key === "=") {
|
|
956
1030
|
this.activeInstance.zoomIn?.();
|
|
957
1031
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1217,30 +1291,62 @@ var CfbfReader = class {
|
|
|
1217
1291
|
return result.subarray(0, targetSize);
|
|
1218
1292
|
}
|
|
1219
1293
|
};
|
|
1220
|
-
|
|
1221
|
-
|
|
1294
|
+
if (typeof window !== "undefined" && pdfjsLib.GlobalWorkerOptions) {
|
|
1295
|
+
if (!pdfjsLib.GlobalWorkerOptions.workerSrc) {
|
|
1296
|
+
pdfjsLib.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1222
1299
|
var PdfPlugin = class {
|
|
1223
1300
|
id = "pdf";
|
|
1224
|
-
name = "PDF Preview";
|
|
1301
|
+
name = "PDF Document Preview";
|
|
1225
1302
|
extensions = [".pdf"];
|
|
1226
1303
|
mimeTypes = ["application/pdf"];
|
|
1227
1304
|
weight = 100;
|
|
1228
1305
|
supports(file) {
|
|
1229
1306
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1230
1307
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1231
|
-
|
|
1308
|
+
if (ext) return this.extensions.includes(ext);
|
|
1309
|
+
return this.mimeTypes.includes(mime || "");
|
|
1232
1310
|
}
|
|
1233
1311
|
getToolbarActions(instance) {
|
|
1312
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1313
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1234
1314
|
return [
|
|
1315
|
+
{
|
|
1316
|
+
id: "thumbnails",
|
|
1317
|
+
icon: "thumbnails",
|
|
1318
|
+
label: "Page Thumbnails",
|
|
1319
|
+
type: "button",
|
|
1320
|
+
group: "navigation",
|
|
1321
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1322
|
+
},
|
|
1323
|
+
{
|
|
1324
|
+
id: "page-nav",
|
|
1325
|
+
icon: "",
|
|
1326
|
+
label: "Page Navigation",
|
|
1327
|
+
type: "page-nav",
|
|
1328
|
+
group: "navigation",
|
|
1329
|
+
value: curPage,
|
|
1330
|
+
max: totalPages,
|
|
1331
|
+
execute: (action, page) => {
|
|
1332
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1333
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1334
|
+
if (action === "prev") {
|
|
1335
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1336
|
+
} else if (action === "next") {
|
|
1337
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1338
|
+
} else if (typeof page === "number") {
|
|
1339
|
+
instance.goToPage?.(page);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
},
|
|
1235
1343
|
{
|
|
1236
1344
|
id: "zoom-out",
|
|
1237
1345
|
icon: "zoom-out",
|
|
1238
1346
|
label: "Zoom Out",
|
|
1239
1347
|
type: "button",
|
|
1240
1348
|
group: "zoom",
|
|
1241
|
-
execute: () =>
|
|
1242
|
-
instance.zoomOut?.();
|
|
1243
|
-
}
|
|
1349
|
+
execute: () => instance.zoomOut?.()
|
|
1244
1350
|
},
|
|
1245
1351
|
{
|
|
1246
1352
|
id: "zoom-in",
|
|
@@ -1248,9 +1354,7 @@ var PdfPlugin = class {
|
|
|
1248
1354
|
label: "Zoom In",
|
|
1249
1355
|
type: "button",
|
|
1250
1356
|
group: "zoom",
|
|
1251
|
-
execute: () =>
|
|
1252
|
-
instance.zoomIn?.();
|
|
1253
|
-
}
|
|
1357
|
+
execute: () => instance.zoomIn?.()
|
|
1254
1358
|
},
|
|
1255
1359
|
{
|
|
1256
1360
|
id: "fit-page",
|
|
@@ -1258,39 +1362,23 @@ var PdfPlugin = class {
|
|
|
1258
1362
|
label: "Fit to Page",
|
|
1259
1363
|
type: "button",
|
|
1260
1364
|
group: "zoom",
|
|
1261
|
-
execute: () =>
|
|
1262
|
-
instance.fitToPage?.();
|
|
1263
|
-
}
|
|
1365
|
+
execute: () => instance.fitToPage?.()
|
|
1264
1366
|
},
|
|
1265
1367
|
{
|
|
1266
1368
|
id: "rotate-cw",
|
|
1267
1369
|
icon: "rotate-cw",
|
|
1268
|
-
label: "Rotate",
|
|
1370
|
+
label: "Rotate Clockwise",
|
|
1269
1371
|
type: "button",
|
|
1270
1372
|
group: "view",
|
|
1271
|
-
execute: () =>
|
|
1272
|
-
instance.rotateCW?.();
|
|
1273
|
-
}
|
|
1274
|
-
},
|
|
1275
|
-
{
|
|
1276
|
-
id: "page-nav",
|
|
1277
|
-
icon: "page-nav",
|
|
1278
|
-
label: "Page Navigation",
|
|
1279
|
-
type: "page-nav",
|
|
1280
|
-
group: "navigation",
|
|
1281
|
-
execute: (page) => {
|
|
1282
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1283
|
-
}
|
|
1373
|
+
execute: () => instance.rotateCW?.()
|
|
1284
1374
|
},
|
|
1285
1375
|
{
|
|
1286
1376
|
id: "download",
|
|
1287
1377
|
icon: "download",
|
|
1288
|
-
label: "Download",
|
|
1378
|
+
label: "Download PDF",
|
|
1289
1379
|
type: "button",
|
|
1290
1380
|
group: "actions",
|
|
1291
|
-
execute: () =>
|
|
1292
|
-
instance.download?.();
|
|
1293
|
-
}
|
|
1381
|
+
execute: () => instance.download?.()
|
|
1294
1382
|
},
|
|
1295
1383
|
{
|
|
1296
1384
|
id: "print",
|
|
@@ -1298,99 +1386,224 @@ var PdfPlugin = class {
|
|
|
1298
1386
|
label: "Print",
|
|
1299
1387
|
type: "button",
|
|
1300
1388
|
group: "actions",
|
|
1301
|
-
execute: () =>
|
|
1302
|
-
instance.print?.();
|
|
1303
|
-
}
|
|
1389
|
+
execute: () => instance.print?.()
|
|
1304
1390
|
}
|
|
1305
1391
|
];
|
|
1306
1392
|
}
|
|
1307
1393
|
async render(ctx) {
|
|
1308
|
-
const
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1394
|
+
const container = document.createElement("div");
|
|
1395
|
+
container.className = "fp-pdf-container";
|
|
1396
|
+
container.style.width = "100%";
|
|
1397
|
+
container.style.height = "100%";
|
|
1398
|
+
container.style.overflow = "auto";
|
|
1399
|
+
container.style.display = "flex";
|
|
1400
|
+
container.style.flexDirection = "column";
|
|
1401
|
+
container.style.alignItems = "center";
|
|
1402
|
+
container.style.justifyContent = "flex-start";
|
|
1403
|
+
container.style.padding = "20px 16px";
|
|
1404
|
+
container.style.backgroundColor = "#0f172a";
|
|
1405
|
+
container.style.boxSizing = "border-box";
|
|
1406
|
+
container.style.position = "relative";
|
|
1407
|
+
const pageCard = document.createElement("div");
|
|
1408
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1409
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1410
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1411
|
+
pageCard.style.borderRadius = "4px";
|
|
1412
|
+
pageCard.style.overflow = "hidden";
|
|
1413
|
+
pageCard.style.lineHeight = "0";
|
|
1414
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1415
|
+
pageCard.style.position = "relative";
|
|
1416
|
+
pageCard.style.flexShrink = "0";
|
|
1417
|
+
let canvas = document.createElement("canvas");
|
|
1418
|
+
pageCard.appendChild(canvas);
|
|
1419
|
+
container.appendChild(pageCard);
|
|
1420
|
+
const indicator = document.createElement("div");
|
|
1421
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1422
|
+
indicator.style.position = "sticky";
|
|
1423
|
+
indicator.style.bottom = "16px";
|
|
1424
|
+
indicator.style.marginTop = "16px";
|
|
1425
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1426
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1427
|
+
indicator.style.color = "#f8fafc";
|
|
1428
|
+
indicator.style.fontSize = "12px";
|
|
1429
|
+
indicator.style.fontWeight = "600";
|
|
1430
|
+
indicator.style.padding = "5px 14px";
|
|
1431
|
+
indicator.style.borderRadius = "20px";
|
|
1432
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1433
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1434
|
+
indicator.style.zIndex = "10";
|
|
1435
|
+
indicator.style.userSelect = "none";
|
|
1436
|
+
indicator.style.pointerEvents = "none";
|
|
1437
|
+
container.appendChild(indicator);
|
|
1438
|
+
ctx.container.appendChild(container);
|
|
1439
|
+
const loadingTask = pdfjsLib.getDocument({
|
|
1440
|
+
data: new Uint8Array(ctx.buffer),
|
|
1441
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/cmaps/`,
|
|
1442
|
+
cMapPacked: true,
|
|
1443
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/standard_fonts/`
|
|
1444
|
+
});
|
|
1445
|
+
const pdfDoc = await loadingTask.promise;
|
|
1446
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1324
1447
|
let currentPage = 1;
|
|
1325
|
-
let
|
|
1448
|
+
let zoomScale = 1;
|
|
1326
1449
|
let rotation = 0;
|
|
1450
|
+
let currentRenderTask = null;
|
|
1451
|
+
const renderPage = async (pageNum) => {
|
|
1452
|
+
if (currentRenderTask) {
|
|
1453
|
+
try {
|
|
1454
|
+
currentRenderTask.cancel();
|
|
1455
|
+
} catch {
|
|
1456
|
+
}
|
|
1457
|
+
currentRenderTask = null;
|
|
1458
|
+
}
|
|
1459
|
+
const newCanvas = document.createElement("canvas");
|
|
1460
|
+
pageCard.replaceChild(newCanvas, canvas);
|
|
1461
|
+
canvas = newCanvas;
|
|
1462
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1463
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1464
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1465
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1466
|
+
const containerWidth = container.clientWidth || 900;
|
|
1467
|
+
const containerHeight = container.clientHeight || 700;
|
|
1468
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1469
|
+
const availWidth = Math.max(100, containerWidth - 48);
|
|
1470
|
+
const availHeight = Math.max(100, containerHeight - 88);
|
|
1471
|
+
const scaleW = availWidth / unscaledVp.width;
|
|
1472
|
+
const scaleH = availHeight / unscaledVp.height;
|
|
1473
|
+
const fitScale = Math.min(scaleW, scaleH);
|
|
1474
|
+
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1475
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1476
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1477
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1478
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1479
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1480
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1481
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1482
|
+
if (!canvasCtx) return;
|
|
1483
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1484
|
+
currentRenderTask = page.render({
|
|
1485
|
+
canvasContext: canvasCtx,
|
|
1486
|
+
viewport
|
|
1487
|
+
});
|
|
1488
|
+
try {
|
|
1489
|
+
await currentRenderTask.promise;
|
|
1490
|
+
} catch (err) {
|
|
1491
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1492
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1493
|
+
}
|
|
1494
|
+
} finally {
|
|
1495
|
+
currentRenderTask = null;
|
|
1496
|
+
}
|
|
1497
|
+
};
|
|
1498
|
+
await renderPage(1);
|
|
1327
1499
|
const cleanup = () => {
|
|
1328
|
-
|
|
1329
|
-
|
|
1500
|
+
if (currentRenderTask) {
|
|
1501
|
+
try {
|
|
1502
|
+
currentRenderTask.cancel();
|
|
1503
|
+
} catch {
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
try {
|
|
1507
|
+
pdfDoc.destroy();
|
|
1508
|
+
} catch {
|
|
1509
|
+
}
|
|
1510
|
+
container.remove();
|
|
1330
1511
|
ctx.container.innerHTML = "";
|
|
1331
1512
|
};
|
|
1332
1513
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1333
|
-
|
|
1514
|
+
const instance = {
|
|
1334
1515
|
destroy: cleanup,
|
|
1335
1516
|
zoomIn: () => {
|
|
1336
|
-
|
|
1337
|
-
|
|
1517
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1518
|
+
renderPage(currentPage);
|
|
1338
1519
|
},
|
|
1339
1520
|
zoomOut: () => {
|
|
1340
|
-
|
|
1341
|
-
|
|
1521
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1522
|
+
renderPage(currentPage);
|
|
1342
1523
|
},
|
|
1343
|
-
getZoom: () =>
|
|
1524
|
+
getZoom: () => zoomScale,
|
|
1344
1525
|
setZoom: (level) => {
|
|
1345
|
-
|
|
1346
|
-
|
|
1526
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1527
|
+
renderPage(currentPage);
|
|
1347
1528
|
},
|
|
1348
1529
|
fitToPage: () => {
|
|
1349
|
-
|
|
1350
|
-
|
|
1530
|
+
zoomScale = 1;
|
|
1531
|
+
rotation = 0;
|
|
1532
|
+
renderPage(currentPage);
|
|
1351
1533
|
},
|
|
1352
1534
|
rotateCW: () => {
|
|
1353
1535
|
rotation = (rotation + 90) % 360;
|
|
1354
|
-
|
|
1536
|
+
renderPage(currentPage);
|
|
1355
1537
|
},
|
|
1356
1538
|
rotateCCW: () => {
|
|
1357
1539
|
rotation = (rotation - 90 + 360) % 360;
|
|
1358
|
-
|
|
1540
|
+
renderPage(currentPage);
|
|
1359
1541
|
},
|
|
1360
1542
|
getRotation: () => rotation,
|
|
1543
|
+
getPageCount: () => totalPages,
|
|
1544
|
+
getCurrentPage: () => currentPage,
|
|
1361
1545
|
goToPage: (page) => {
|
|
1362
|
-
|
|
1363
|
-
iframe.src = `${url}#page=${page}`;
|
|
1546
|
+
renderPage(page);
|
|
1364
1547
|
},
|
|
1365
|
-
getCurrentPage: () => currentPage,
|
|
1366
1548
|
download: () => {
|
|
1549
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1550
|
+
const url = URL.createObjectURL(blob);
|
|
1367
1551
|
const a = document.createElement("a");
|
|
1368
1552
|
a.href = url;
|
|
1369
1553
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1370
1554
|
a.click();
|
|
1555
|
+
URL.revokeObjectURL(url);
|
|
1371
1556
|
},
|
|
1372
1557
|
print: () => {
|
|
1373
|
-
|
|
1558
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1559
|
+
const url = URL.createObjectURL(blob);
|
|
1560
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1561
|
+
hiddenIframe.style.position = "fixed";
|
|
1562
|
+
hiddenIframe.style.right = "0";
|
|
1563
|
+
hiddenIframe.style.bottom = "0";
|
|
1564
|
+
hiddenIframe.style.width = "0";
|
|
1565
|
+
hiddenIframe.style.height = "0";
|
|
1566
|
+
hiddenIframe.style.border = "0";
|
|
1567
|
+
document.body.appendChild(hiddenIframe);
|
|
1568
|
+
hiddenIframe.src = url;
|
|
1569
|
+
hiddenIframe.onload = () => {
|
|
1570
|
+
setTimeout(() => {
|
|
1571
|
+
hiddenIframe.contentWindow?.print();
|
|
1572
|
+
setTimeout(() => {
|
|
1573
|
+
hiddenIframe.remove();
|
|
1574
|
+
URL.revokeObjectURL(url);
|
|
1575
|
+
}, 1e3);
|
|
1576
|
+
}, 300);
|
|
1577
|
+
};
|
|
1374
1578
|
},
|
|
1375
1579
|
getThumbnails: async () => {
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1580
|
+
const thumbnails = [];
|
|
1581
|
+
const count = Math.min(totalPages, 50);
|
|
1582
|
+
for (let i = 1; i <= count; i++) {
|
|
1583
|
+
thumbnails.push({
|
|
1584
|
+
index: i,
|
|
1585
|
+
label: `Page ${i}`,
|
|
1586
|
+
render: async (thumbCanvas) => {
|
|
1587
|
+
try {
|
|
1588
|
+
const p = await pdfDoc.getPage(i);
|
|
1589
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1590
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1591
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1592
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1593
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1594
|
+
if (tCtx) {
|
|
1595
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1596
|
+
}
|
|
1597
|
+
} catch (e) {
|
|
1598
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1388
1599
|
}
|
|
1389
1600
|
}
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1603
|
+
return thumbnails;
|
|
1392
1604
|
}
|
|
1393
1605
|
};
|
|
1606
|
+
return instance;
|
|
1394
1607
|
}
|
|
1395
1608
|
};
|
|
1396
1609
|
function pdfPlugin() {
|
|
@@ -1717,7 +1930,31 @@ var DocxPlugin = class {
|
|
|
1717
1930
|
return this.mimeTypes.includes(mime || "");
|
|
1718
1931
|
}
|
|
1719
1932
|
getToolbarActions(instance) {
|
|
1720
|
-
|
|
1933
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1934
|
+
const actions = [];
|
|
1935
|
+
if (totalPages > 1) {
|
|
1936
|
+
actions.push({
|
|
1937
|
+
id: "page-nav",
|
|
1938
|
+
icon: "",
|
|
1939
|
+
label: "Page Navigation",
|
|
1940
|
+
type: "page-nav",
|
|
1941
|
+
group: "navigation",
|
|
1942
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1943
|
+
max: totalPages,
|
|
1944
|
+
execute: (action, page) => {
|
|
1945
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1946
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1947
|
+
if (action === "prev") {
|
|
1948
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1949
|
+
} else if (action === "next") {
|
|
1950
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1951
|
+
} else if (typeof page === "number") {
|
|
1952
|
+
instance.goToPage?.(page);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
actions.push(
|
|
1721
1958
|
{
|
|
1722
1959
|
id: "zoom-out",
|
|
1723
1960
|
icon: "zoom-out",
|
|
@@ -1742,6 +1979,14 @@ var DocxPlugin = class {
|
|
|
1742
1979
|
group: "zoom",
|
|
1743
1980
|
execute: () => instance.fitToPage?.()
|
|
1744
1981
|
},
|
|
1982
|
+
{
|
|
1983
|
+
id: "rotate-cw",
|
|
1984
|
+
icon: "rotate-cw",
|
|
1985
|
+
label: "Rotate",
|
|
1986
|
+
type: "button",
|
|
1987
|
+
group: "view",
|
|
1988
|
+
execute: () => instance.rotateCW?.()
|
|
1989
|
+
},
|
|
1745
1990
|
{
|
|
1746
1991
|
id: "download",
|
|
1747
1992
|
icon: "download",
|
|
@@ -1758,7 +2003,8 @@ var DocxPlugin = class {
|
|
|
1758
2003
|
group: "actions",
|
|
1759
2004
|
execute: () => instance.print?.()
|
|
1760
2005
|
}
|
|
1761
|
-
|
|
2006
|
+
);
|
|
2007
|
+
return actions;
|
|
1762
2008
|
}
|
|
1763
2009
|
async render(ctx) {
|
|
1764
2010
|
const wrapper = document.createElement("div");
|
|
@@ -1834,7 +2080,71 @@ var DocxPlugin = class {
|
|
|
1834
2080
|
}
|
|
1835
2081
|
}
|
|
1836
2082
|
}
|
|
2083
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2084
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2085
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2086
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2087
|
+
let currentPage = 1;
|
|
2088
|
+
let indicator = null;
|
|
2089
|
+
if (totalPages > 1) {
|
|
2090
|
+
indicator = document.createElement("div");
|
|
2091
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2092
|
+
indicator.style.position = "sticky";
|
|
2093
|
+
indicator.style.bottom = "16px";
|
|
2094
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2095
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2096
|
+
indicator.style.color = "#f8fafc";
|
|
2097
|
+
indicator.style.fontSize = "12px";
|
|
2098
|
+
indicator.style.fontWeight = "600";
|
|
2099
|
+
indicator.style.padding = "5px 14px";
|
|
2100
|
+
indicator.style.borderRadius = "20px";
|
|
2101
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2102
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2103
|
+
indicator.style.zIndex = "10";
|
|
2104
|
+
indicator.style.userSelect = "none";
|
|
2105
|
+
indicator.style.pointerEvents = "none";
|
|
2106
|
+
indicator.style.textAlign = "center";
|
|
2107
|
+
indicator.style.width = "fit-content";
|
|
2108
|
+
indicator.style.margin = "16px auto 0";
|
|
2109
|
+
ctx.container.appendChild(indicator);
|
|
2110
|
+
}
|
|
2111
|
+
const showPage = (pageNum) => {
|
|
2112
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2113
|
+
if (pageElements.length > 1) {
|
|
2114
|
+
pageElements.forEach((sec, idx) => {
|
|
2115
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2116
|
+
});
|
|
2117
|
+
}
|
|
2118
|
+
if (indicator) {
|
|
2119
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2120
|
+
}
|
|
2121
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2122
|
+
};
|
|
2123
|
+
if (totalPages > 1) {
|
|
2124
|
+
showPage(1);
|
|
2125
|
+
}
|
|
2126
|
+
scale = 1;
|
|
2127
|
+
let rotation = 0;
|
|
2128
|
+
const calculateFitScale = () => {
|
|
2129
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2130
|
+
const elW = activeEl.offsetWidth || 816;
|
|
2131
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2132
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
2133
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
2134
|
+
const sW = availW / elW;
|
|
2135
|
+
const sH = availH / elH;
|
|
2136
|
+
return Math.min(1.1, Math.min(sW, sH));
|
|
2137
|
+
};
|
|
2138
|
+
const applyTransform = () => {
|
|
2139
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2140
|
+
wrapper.style.transformOrigin = "top center";
|
|
2141
|
+
};
|
|
2142
|
+
setTimeout(() => {
|
|
2143
|
+
scale = calculateFitScale();
|
|
2144
|
+
applyTransform();
|
|
2145
|
+
}, 60);
|
|
1837
2146
|
const cleanup = () => {
|
|
2147
|
+
indicator?.remove();
|
|
1838
2148
|
for (const url of createdBlobUrls) {
|
|
1839
2149
|
URL.revokeObjectURL(url);
|
|
1840
2150
|
}
|
|
@@ -1845,22 +2155,36 @@ var DocxPlugin = class {
|
|
|
1845
2155
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1846
2156
|
return {
|
|
1847
2157
|
destroy: cleanup,
|
|
2158
|
+
getPageCount: () => totalPages,
|
|
2159
|
+
getCurrentPage: () => currentPage,
|
|
2160
|
+
goToPage: (page) => {
|
|
2161
|
+
showPage(page);
|
|
2162
|
+
},
|
|
1848
2163
|
zoomIn: () => {
|
|
1849
|
-
scale += 0.
|
|
1850
|
-
|
|
2164
|
+
scale += 0.15;
|
|
2165
|
+
applyTransform();
|
|
1851
2166
|
},
|
|
1852
2167
|
zoomOut: () => {
|
|
1853
|
-
scale = Math.max(0.2, scale - 0.
|
|
1854
|
-
|
|
2168
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2169
|
+
applyTransform();
|
|
1855
2170
|
},
|
|
1856
2171
|
getZoom: () => scale,
|
|
1857
2172
|
setZoom: (level) => {
|
|
1858
2173
|
scale = level;
|
|
1859
|
-
|
|
2174
|
+
applyTransform();
|
|
1860
2175
|
},
|
|
1861
2176
|
fitToPage: () => {
|
|
1862
|
-
scale =
|
|
1863
|
-
|
|
2177
|
+
scale = calculateFitScale();
|
|
2178
|
+
rotation = 0;
|
|
2179
|
+
applyTransform();
|
|
2180
|
+
},
|
|
2181
|
+
rotateCW: () => {
|
|
2182
|
+
rotation = (rotation + 90) % 360;
|
|
2183
|
+
applyTransform();
|
|
2184
|
+
},
|
|
2185
|
+
rotateCCW: () => {
|
|
2186
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2187
|
+
applyTransform();
|
|
1864
2188
|
},
|
|
1865
2189
|
download: () => {
|
|
1866
2190
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
@@ -2109,7 +2433,31 @@ var ExcelPlugin = class {
|
|
|
2109
2433
|
return this.mimeTypes.includes(mime || "");
|
|
2110
2434
|
}
|
|
2111
2435
|
getToolbarActions(instance) {
|
|
2112
|
-
|
|
2436
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2437
|
+
const actions = [];
|
|
2438
|
+
if (totalSheets > 1) {
|
|
2439
|
+
actions.push({
|
|
2440
|
+
id: "page-nav",
|
|
2441
|
+
icon: "",
|
|
2442
|
+
label: "Sheet Navigation",
|
|
2443
|
+
type: "page-nav",
|
|
2444
|
+
group: "navigation",
|
|
2445
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2446
|
+
max: totalSheets,
|
|
2447
|
+
execute: (action, sheet) => {
|
|
2448
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2449
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2450
|
+
if (action === "prev") {
|
|
2451
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2452
|
+
} else if (action === "next") {
|
|
2453
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2454
|
+
} else if (typeof sheet === "number") {
|
|
2455
|
+
instance.goToPage?.(sheet);
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
});
|
|
2459
|
+
}
|
|
2460
|
+
actions.push(
|
|
2113
2461
|
{
|
|
2114
2462
|
id: "zoom-out",
|
|
2115
2463
|
icon: "zoom-out",
|
|
@@ -2131,13 +2479,23 @@ var ExcelPlugin = class {
|
|
|
2131
2479
|
}
|
|
2132
2480
|
},
|
|
2133
2481
|
{
|
|
2134
|
-
id: "page
|
|
2135
|
-
icon: "page
|
|
2136
|
-
label: "
|
|
2137
|
-
type: "
|
|
2138
|
-
group: "
|
|
2139
|
-
execute: (
|
|
2140
|
-
|
|
2482
|
+
id: "fit-page",
|
|
2483
|
+
icon: "fit-page",
|
|
2484
|
+
label: "Fit to View",
|
|
2485
|
+
type: "button",
|
|
2486
|
+
group: "zoom",
|
|
2487
|
+
execute: () => {
|
|
2488
|
+
instance.fitToPage?.();
|
|
2489
|
+
}
|
|
2490
|
+
},
|
|
2491
|
+
{
|
|
2492
|
+
id: "rotate-cw",
|
|
2493
|
+
icon: "rotate-cw",
|
|
2494
|
+
label: "Rotate",
|
|
2495
|
+
type: "button",
|
|
2496
|
+
group: "view",
|
|
2497
|
+
execute: () => {
|
|
2498
|
+
instance.rotateCW?.();
|
|
2141
2499
|
}
|
|
2142
2500
|
},
|
|
2143
2501
|
{
|
|
@@ -2160,7 +2518,8 @@ var ExcelPlugin = class {
|
|
|
2160
2518
|
instance.print?.();
|
|
2161
2519
|
}
|
|
2162
2520
|
}
|
|
2163
|
-
|
|
2521
|
+
);
|
|
2522
|
+
return actions;
|
|
2164
2523
|
}
|
|
2165
2524
|
async render(ctx) {
|
|
2166
2525
|
const container = document.createElement("div");
|
|
@@ -2189,9 +2548,23 @@ var ExcelPlugin = class {
|
|
|
2189
2548
|
container.appendChild(tabsArea);
|
|
2190
2549
|
ctx.container.appendChild(container);
|
|
2191
2550
|
let scale = 1;
|
|
2551
|
+
let rotation = 0;
|
|
2192
2552
|
let currentSheetIndex = 1;
|
|
2193
2553
|
let sheetNames = [];
|
|
2194
2554
|
let wb = null;
|
|
2555
|
+
const applyTransform = () => {
|
|
2556
|
+
contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2557
|
+
contentArea.style.transformOrigin = "top left";
|
|
2558
|
+
};
|
|
2559
|
+
const calculateFitScale = () => {
|
|
2560
|
+
const table = contentArea.querySelector("table");
|
|
2561
|
+
if (!table) return 1;
|
|
2562
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
2563
|
+
const availH = Math.max(200, container.clientHeight - 80);
|
|
2564
|
+
const tW = table.offsetWidth || 800;
|
|
2565
|
+
const tH = table.offsetHeight || 600;
|
|
2566
|
+
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2567
|
+
};
|
|
2195
2568
|
try {
|
|
2196
2569
|
wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
2197
2570
|
sheetNames = wb.SheetNames || [];
|
|
@@ -2244,6 +2617,7 @@ var ExcelPlugin = class {
|
|
|
2244
2617
|
b.style.fontWeight = "normal";
|
|
2245
2618
|
}
|
|
2246
2619
|
});
|
|
2620
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2247
2621
|
};
|
|
2248
2622
|
if (sheetNames.length > 0) {
|
|
2249
2623
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2278,17 +2652,30 @@ var ExcelPlugin = class {
|
|
|
2278
2652
|
return {
|
|
2279
2653
|
destroy: cleanup,
|
|
2280
2654
|
zoomIn: () => {
|
|
2281
|
-
scale += 0.
|
|
2282
|
-
|
|
2655
|
+
scale += 0.15;
|
|
2656
|
+
applyTransform();
|
|
2283
2657
|
},
|
|
2284
2658
|
zoomOut: () => {
|
|
2285
|
-
scale = Math.max(0.2, scale - 0.
|
|
2286
|
-
|
|
2659
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2660
|
+
applyTransform();
|
|
2287
2661
|
},
|
|
2288
2662
|
getZoom: () => scale,
|
|
2289
2663
|
setZoom: (level) => {
|
|
2290
2664
|
scale = level;
|
|
2291
|
-
|
|
2665
|
+
applyTransform();
|
|
2666
|
+
},
|
|
2667
|
+
fitToPage: () => {
|
|
2668
|
+
scale = calculateFitScale();
|
|
2669
|
+
rotation = 0;
|
|
2670
|
+
applyTransform();
|
|
2671
|
+
},
|
|
2672
|
+
rotateCW: () => {
|
|
2673
|
+
rotation = (rotation + 90) % 360;
|
|
2674
|
+
applyTransform();
|
|
2675
|
+
},
|
|
2676
|
+
rotateCCW: () => {
|
|
2677
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2678
|
+
applyTransform();
|
|
2292
2679
|
},
|
|
2293
2680
|
goToPage: (page) => {
|
|
2294
2681
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -2493,7 +2880,31 @@ var CodePlugin = class {
|
|
|
2493
2880
|
return false;
|
|
2494
2881
|
}
|
|
2495
2882
|
getToolbarActions(instance) {
|
|
2496
|
-
|
|
2883
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2884
|
+
const actions = [];
|
|
2885
|
+
if (totalPages > 1) {
|
|
2886
|
+
actions.push({
|
|
2887
|
+
id: "page-nav",
|
|
2888
|
+
icon: "",
|
|
2889
|
+
label: "Page Navigation",
|
|
2890
|
+
type: "page-nav",
|
|
2891
|
+
group: "navigation",
|
|
2892
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2893
|
+
max: totalPages,
|
|
2894
|
+
execute: (action, page) => {
|
|
2895
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2896
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2897
|
+
if (action === "prev") {
|
|
2898
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2899
|
+
} else if (action === "next") {
|
|
2900
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2901
|
+
} else if (typeof page === "number") {
|
|
2902
|
+
instance.goToPage?.(page);
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
});
|
|
2906
|
+
}
|
|
2907
|
+
actions.push(
|
|
2497
2908
|
{
|
|
2498
2909
|
id: "zoom-out",
|
|
2499
2910
|
icon: "zoom-out",
|
|
@@ -2514,6 +2925,26 @@ var CodePlugin = class {
|
|
|
2514
2925
|
instance.zoomIn?.();
|
|
2515
2926
|
}
|
|
2516
2927
|
},
|
|
2928
|
+
{
|
|
2929
|
+
id: "fit-page",
|
|
2930
|
+
icon: "fit-page",
|
|
2931
|
+
label: "Fit to View",
|
|
2932
|
+
type: "button",
|
|
2933
|
+
group: "zoom",
|
|
2934
|
+
execute: () => {
|
|
2935
|
+
instance.fitToPage?.();
|
|
2936
|
+
}
|
|
2937
|
+
},
|
|
2938
|
+
{
|
|
2939
|
+
id: "rotate-cw",
|
|
2940
|
+
icon: "rotate-cw",
|
|
2941
|
+
label: "Rotate",
|
|
2942
|
+
type: "button",
|
|
2943
|
+
group: "view",
|
|
2944
|
+
execute: () => {
|
|
2945
|
+
instance.rotateCW?.();
|
|
2946
|
+
}
|
|
2947
|
+
},
|
|
2517
2948
|
{
|
|
2518
2949
|
id: "copy",
|
|
2519
2950
|
icon: "copy",
|
|
@@ -2544,11 +2975,16 @@ var CodePlugin = class {
|
|
|
2544
2975
|
instance.print?.();
|
|
2545
2976
|
}
|
|
2546
2977
|
}
|
|
2547
|
-
|
|
2978
|
+
);
|
|
2979
|
+
return actions;
|
|
2548
2980
|
}
|
|
2549
2981
|
async render(ctx) {
|
|
2550
2982
|
const decoder = new TextDecoder("utf-8");
|
|
2551
|
-
const
|
|
2983
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
2984
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
2985
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2986
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
2987
|
+
let currentPage = 1;
|
|
2552
2988
|
const container = document.createElement("div");
|
|
2553
2989
|
container.style.width = "100%";
|
|
2554
2990
|
container.style.height = "100%";
|
|
@@ -2558,6 +2994,7 @@ var CodePlugin = class {
|
|
|
2558
2994
|
container.style.padding = "16px";
|
|
2559
2995
|
container.style.boxSizing = "border-box";
|
|
2560
2996
|
let fontSize = 13;
|
|
2997
|
+
let rotation = 0;
|
|
2561
2998
|
const pre = document.createElement("pre");
|
|
2562
2999
|
pre.style.margin = "0";
|
|
2563
3000
|
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
@@ -2567,25 +3004,66 @@ var CodePlugin = class {
|
|
|
2567
3004
|
pre.style.wordBreak = "break-all";
|
|
2568
3005
|
const code = document.createElement("code");
|
|
2569
3006
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
3007
|
+
const renderCodePage = (text) => {
|
|
3008
|
+
try {
|
|
3009
|
+
if (ext && hljs.getLanguage(ext)) {
|
|
3010
|
+
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
3011
|
+
} else {
|
|
3012
|
+
code.innerHTML = hljs.highlightAuto(text).value;
|
|
3013
|
+
}
|
|
3014
|
+
} catch {
|
|
3015
|
+
code.textContent = text;
|
|
2575
3016
|
}
|
|
2576
|
-
}
|
|
2577
|
-
|
|
2578
|
-
}
|
|
3017
|
+
};
|
|
3018
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2579
3019
|
pre.appendChild(code);
|
|
2580
3020
|
container.appendChild(pre);
|
|
3021
|
+
let indicator = null;
|
|
3022
|
+
if (totalPages > 1) {
|
|
3023
|
+
indicator = document.createElement("div");
|
|
3024
|
+
indicator.className = "fp-code-page-indicator";
|
|
3025
|
+
indicator.style.position = "sticky";
|
|
3026
|
+
indicator.style.bottom = "16px";
|
|
3027
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3028
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3029
|
+
indicator.style.color = "#f8fafc";
|
|
3030
|
+
indicator.style.fontSize = "12px";
|
|
3031
|
+
indicator.style.fontWeight = "600";
|
|
3032
|
+
indicator.style.padding = "5px 14px";
|
|
3033
|
+
indicator.style.borderRadius = "20px";
|
|
3034
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3035
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3036
|
+
indicator.style.zIndex = "10";
|
|
3037
|
+
indicator.style.userSelect = "none";
|
|
3038
|
+
indicator.style.pointerEvents = "none";
|
|
3039
|
+
indicator.style.textAlign = "center";
|
|
3040
|
+
indicator.style.width = "fit-content";
|
|
3041
|
+
indicator.style.margin = "16px auto 0";
|
|
3042
|
+
container.appendChild(indicator);
|
|
3043
|
+
}
|
|
3044
|
+
const showPage = (pageNum) => {
|
|
3045
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3046
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3047
|
+
if (indicator) {
|
|
3048
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3049
|
+
}
|
|
3050
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3051
|
+
};
|
|
3052
|
+
if (totalPages > 1) {
|
|
3053
|
+
showPage(1);
|
|
3054
|
+
}
|
|
2581
3055
|
ctx.container.appendChild(container);
|
|
2582
3056
|
const cleanup = () => {
|
|
3057
|
+
indicator?.remove();
|
|
2583
3058
|
container.remove();
|
|
2584
3059
|
ctx.container.innerHTML = "";
|
|
2585
3060
|
};
|
|
2586
3061
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2587
3062
|
return {
|
|
2588
3063
|
destroy: cleanup,
|
|
3064
|
+
getPageCount: () => totalPages,
|
|
3065
|
+
getCurrentPage: () => currentPage,
|
|
3066
|
+
goToPage: (page) => showPage(page),
|
|
2589
3067
|
zoomIn: () => {
|
|
2590
3068
|
fontSize = Math.min(32, fontSize + 2);
|
|
2591
3069
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2599,6 +3077,22 @@ var CodePlugin = class {
|
|
|
2599
3077
|
fontSize = Math.round(13 * level);
|
|
2600
3078
|
pre.style.fontSize = `${fontSize}px`;
|
|
2601
3079
|
},
|
|
3080
|
+
fitToPage: () => {
|
|
3081
|
+
fontSize = 13;
|
|
3082
|
+
rotation = 0;
|
|
3083
|
+
pre.style.fontSize = "13px";
|
|
3084
|
+
pre.style.transform = "none";
|
|
3085
|
+
},
|
|
3086
|
+
rotateCW: () => {
|
|
3087
|
+
rotation = (rotation + 90) % 360;
|
|
3088
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3089
|
+
pre.style.transformOrigin = "top left";
|
|
3090
|
+
},
|
|
3091
|
+
rotateCCW: () => {
|
|
3092
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3093
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3094
|
+
pre.style.transformOrigin = "top left";
|
|
3095
|
+
},
|
|
2602
3096
|
download: () => {
|
|
2603
3097
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
2604
3098
|
const blob = new Blob([ctx.buffer], { type: mimeType });
|
|
@@ -2613,7 +3107,7 @@ var CodePlugin = class {
|
|
|
2613
3107
|
window.print();
|
|
2614
3108
|
},
|
|
2615
3109
|
copy: () => {
|
|
2616
|
-
navigator.clipboard?.writeText(
|
|
3110
|
+
navigator.clipboard?.writeText(fullText);
|
|
2617
3111
|
}
|
|
2618
3112
|
};
|
|
2619
3113
|
}
|
|
@@ -3110,6 +3604,14 @@ var PptxPlugin = class {
|
|
|
3110
3604
|
group: "zoom",
|
|
3111
3605
|
execute: () => instance.fitToPage?.()
|
|
3112
3606
|
},
|
|
3607
|
+
{
|
|
3608
|
+
id: "rotate-cw",
|
|
3609
|
+
icon: "rotate-cw",
|
|
3610
|
+
label: "Rotate",
|
|
3611
|
+
type: "button",
|
|
3612
|
+
group: "view",
|
|
3613
|
+
execute: () => instance.rotateCW?.()
|
|
3614
|
+
},
|
|
3113
3615
|
{
|
|
3114
3616
|
id: "download",
|
|
3115
3617
|
icon: "download",
|
|
@@ -3134,6 +3636,7 @@ var PptxPlugin = class {
|
|
|
3134
3636
|
const slideCount = renderer.slidePaths?.length || 1;
|
|
3135
3637
|
let currentSlide = 1;
|
|
3136
3638
|
let scale = 1;
|
|
3639
|
+
let rotation = 0;
|
|
3137
3640
|
const wrapper = document.createElement("div");
|
|
3138
3641
|
wrapper.className = "fp-pptx-wrapper";
|
|
3139
3642
|
wrapper.style.cssText = `
|
|
@@ -3156,6 +3659,8 @@ var PptxPlugin = class {
|
|
|
3156
3659
|
background: #ffffff;
|
|
3157
3660
|
transform-origin: top center;
|
|
3158
3661
|
transition: transform 0.2s ease;
|
|
3662
|
+
max-width: calc(100% - 32px);
|
|
3663
|
+
max-height: calc(100% - 48px);
|
|
3159
3664
|
`;
|
|
3160
3665
|
const canvas = document.createElement("canvas");
|
|
3161
3666
|
slideContainer.appendChild(canvas);
|
|
@@ -3163,10 +3668,22 @@ var PptxPlugin = class {
|
|
|
3163
3668
|
ctx.container.innerHTML = "";
|
|
3164
3669
|
ctx.container.style.overflow = "auto";
|
|
3165
3670
|
ctx.container.appendChild(wrapper);
|
|
3671
|
+
const calculateFitScale = () => {
|
|
3672
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
3673
|
+
const availH = Math.max(200, ctx.container.clientHeight - 72);
|
|
3674
|
+
const cW = canvas.offsetWidth || 1280;
|
|
3675
|
+
const cH = canvas.offsetHeight || 720;
|
|
3676
|
+
return Math.min(1, Math.min(availW / cW, availH / cH));
|
|
3677
|
+
};
|
|
3678
|
+
const applyTransform = () => {
|
|
3679
|
+
slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
3680
|
+
};
|
|
3166
3681
|
const renderCurrentSlide = async () => {
|
|
3167
3682
|
try {
|
|
3168
3683
|
await renderer.renderSlide(currentSlide - 1, canvas, 1280);
|
|
3169
3684
|
ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
|
|
3685
|
+
scale = calculateFitScale();
|
|
3686
|
+
applyTransform();
|
|
3170
3687
|
} catch (err) {
|
|
3171
3688
|
console.error("[PptxPlugin] Failed to render slide:", err);
|
|
3172
3689
|
}
|
|
@@ -3189,21 +3706,30 @@ var PptxPlugin = class {
|
|
|
3189
3706
|
getPageCount: () => slideCount,
|
|
3190
3707
|
getCurrentPage: () => currentSlide,
|
|
3191
3708
|
zoomIn: () => {
|
|
3192
|
-
scale += 0.
|
|
3193
|
-
|
|
3709
|
+
scale += 0.15;
|
|
3710
|
+
applyTransform();
|
|
3194
3711
|
},
|
|
3195
3712
|
zoomOut: () => {
|
|
3196
|
-
scale = Math.max(0.2, scale - 0.
|
|
3197
|
-
|
|
3713
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
3714
|
+
applyTransform();
|
|
3198
3715
|
},
|
|
3199
3716
|
getZoom: () => scale,
|
|
3200
3717
|
setZoom: (level) => {
|
|
3201
3718
|
scale = level;
|
|
3202
|
-
|
|
3719
|
+
applyTransform();
|
|
3203
3720
|
},
|
|
3204
3721
|
fitToPage: () => {
|
|
3205
|
-
scale =
|
|
3206
|
-
|
|
3722
|
+
scale = calculateFitScale();
|
|
3723
|
+
rotation = 0;
|
|
3724
|
+
applyTransform();
|
|
3725
|
+
},
|
|
3726
|
+
rotateCW: () => {
|
|
3727
|
+
rotation = (rotation + 90) % 360;
|
|
3728
|
+
applyTransform();
|
|
3729
|
+
},
|
|
3730
|
+
rotateCCW: () => {
|
|
3731
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3732
|
+
applyTransform();
|
|
3207
3733
|
},
|
|
3208
3734
|
getThumbnails: () => {
|
|
3209
3735
|
const list = [];
|
|
@@ -3435,7 +3961,31 @@ var RtfPlugin = class {
|
|
|
3435
3961
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3436
3962
|
}
|
|
3437
3963
|
getToolbarActions(instance) {
|
|
3438
|
-
|
|
3964
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3965
|
+
const actions = [];
|
|
3966
|
+
if (totalPages > 1) {
|
|
3967
|
+
actions.push({
|
|
3968
|
+
id: "page-nav",
|
|
3969
|
+
icon: "",
|
|
3970
|
+
label: "Page Navigation",
|
|
3971
|
+
type: "page-nav",
|
|
3972
|
+
group: "navigation",
|
|
3973
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3974
|
+
max: totalPages,
|
|
3975
|
+
execute: (action, page) => {
|
|
3976
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3977
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3978
|
+
if (action === "prev") {
|
|
3979
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3980
|
+
} else if (action === "next") {
|
|
3981
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3982
|
+
} else if (typeof page === "number") {
|
|
3983
|
+
instance.goToPage?.(page);
|
|
3984
|
+
}
|
|
3985
|
+
}
|
|
3986
|
+
});
|
|
3987
|
+
}
|
|
3988
|
+
actions.push(
|
|
3439
3989
|
{
|
|
3440
3990
|
id: "zoom-out",
|
|
3441
3991
|
icon: "zoom-out",
|
|
@@ -3460,6 +4010,14 @@ var RtfPlugin = class {
|
|
|
3460
4010
|
group: "zoom",
|
|
3461
4011
|
execute: () => instance.fitToPage?.()
|
|
3462
4012
|
},
|
|
4013
|
+
{
|
|
4014
|
+
id: "rotate-cw",
|
|
4015
|
+
icon: "rotate-cw",
|
|
4016
|
+
label: "Rotate",
|
|
4017
|
+
type: "button",
|
|
4018
|
+
group: "view",
|
|
4019
|
+
execute: () => instance.rotateCW?.()
|
|
4020
|
+
},
|
|
3463
4021
|
{
|
|
3464
4022
|
id: "download",
|
|
3465
4023
|
icon: "download",
|
|
@@ -3476,7 +4034,8 @@ var RtfPlugin = class {
|
|
|
3476
4034
|
group: "actions",
|
|
3477
4035
|
execute: () => instance.print?.()
|
|
3478
4036
|
}
|
|
3479
|
-
|
|
4037
|
+
);
|
|
4038
|
+
return actions;
|
|
3480
4039
|
}
|
|
3481
4040
|
async render(ctx) {
|
|
3482
4041
|
const wrapper = document.createElement("div");
|
|
@@ -3495,44 +4054,124 @@ var RtfPlugin = class {
|
|
|
3495
4054
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3496
4055
|
ctx.container.appendChild(wrapper);
|
|
3497
4056
|
let scale = 1;
|
|
4057
|
+
let rotation = 0;
|
|
4058
|
+
let pageElements = [];
|
|
4059
|
+
const calculateFitScale = () => {
|
|
4060
|
+
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4061
|
+
const elW = activeEl.offsetWidth || 850;
|
|
4062
|
+
const elH = activeEl.offsetHeight || 1e3;
|
|
4063
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4064
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4065
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4066
|
+
};
|
|
4067
|
+
const applyTransform = () => {
|
|
4068
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4069
|
+
wrapper.style.transformOrigin = "top center";
|
|
4070
|
+
};
|
|
4071
|
+
setTimeout(() => {
|
|
4072
|
+
scale = calculateFitScale();
|
|
4073
|
+
applyTransform();
|
|
4074
|
+
}, 60);
|
|
3498
4075
|
try {
|
|
3499
4076
|
if (typeof RTFJS.loggingEnabled === "function") {
|
|
3500
4077
|
RTFJS.loggingEnabled(false);
|
|
3501
4078
|
}
|
|
3502
4079
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
3503
4080
|
const htmlElements = await doc.render();
|
|
3504
|
-
|
|
4081
|
+
pageElements = htmlElements;
|
|
4082
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
4083
|
+
const el = htmlElements[i];
|
|
4084
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3505
4085
|
wrapper.appendChild(el);
|
|
3506
4086
|
}
|
|
3507
4087
|
} catch (err) {
|
|
3508
4088
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3509
4089
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3510
4090
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3511
|
-
|
|
4091
|
+
const pre = document.createElement("pre");
|
|
4092
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
4093
|
+
pre.style.fontFamily = "serif";
|
|
4094
|
+
pre.style.color = "#333";
|
|
4095
|
+
pre.textContent = clean;
|
|
4096
|
+
wrapper.appendChild(pre);
|
|
4097
|
+
pageElements = [pre];
|
|
4098
|
+
}
|
|
4099
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
4100
|
+
let currentPage = 1;
|
|
4101
|
+
let indicator = null;
|
|
4102
|
+
if (totalPages > 1) {
|
|
4103
|
+
indicator = document.createElement("div");
|
|
4104
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
4105
|
+
indicator.style.position = "sticky";
|
|
4106
|
+
indicator.style.bottom = "16px";
|
|
4107
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4108
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4109
|
+
indicator.style.color = "#f8fafc";
|
|
4110
|
+
indicator.style.fontSize = "12px";
|
|
4111
|
+
indicator.style.fontWeight = "600";
|
|
4112
|
+
indicator.style.padding = "5px 14px";
|
|
4113
|
+
indicator.style.borderRadius = "20px";
|
|
4114
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4115
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4116
|
+
indicator.style.zIndex = "10";
|
|
4117
|
+
indicator.style.userSelect = "none";
|
|
4118
|
+
indicator.style.pointerEvents = "none";
|
|
4119
|
+
indicator.style.textAlign = "center";
|
|
4120
|
+
indicator.style.width = "fit-content";
|
|
4121
|
+
indicator.style.margin = "16px auto 0";
|
|
4122
|
+
ctx.container.appendChild(indicator);
|
|
4123
|
+
}
|
|
4124
|
+
const showPage = (pageNum) => {
|
|
4125
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4126
|
+
if (totalPages > 1) {
|
|
4127
|
+
pageElements.forEach((el, idx) => {
|
|
4128
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4129
|
+
});
|
|
4130
|
+
}
|
|
4131
|
+
if (indicator) {
|
|
4132
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4133
|
+
}
|
|
4134
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4135
|
+
};
|
|
4136
|
+
if (totalPages > 1) {
|
|
4137
|
+
showPage(1);
|
|
3512
4138
|
}
|
|
3513
4139
|
const cleanup = () => {
|
|
4140
|
+
indicator?.remove();
|
|
3514
4141
|
wrapper.remove();
|
|
3515
4142
|
ctx.container.innerHTML = "";
|
|
3516
4143
|
};
|
|
3517
4144
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3518
4145
|
return {
|
|
3519
4146
|
destroy: cleanup,
|
|
4147
|
+
getPageCount: () => totalPages,
|
|
4148
|
+
getCurrentPage: () => currentPage,
|
|
4149
|
+
goToPage: (page) => showPage(page),
|
|
3520
4150
|
zoomIn: () => {
|
|
3521
|
-
scale += 0.
|
|
3522
|
-
|
|
4151
|
+
scale += 0.15;
|
|
4152
|
+
applyTransform();
|
|
3523
4153
|
},
|
|
3524
4154
|
zoomOut: () => {
|
|
3525
|
-
scale = Math.max(0.2, scale - 0.
|
|
3526
|
-
|
|
4155
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4156
|
+
applyTransform();
|
|
3527
4157
|
},
|
|
3528
4158
|
getZoom: () => scale,
|
|
3529
4159
|
setZoom: (level) => {
|
|
3530
4160
|
scale = level;
|
|
3531
|
-
|
|
4161
|
+
applyTransform();
|
|
3532
4162
|
},
|
|
3533
4163
|
fitToPage: () => {
|
|
3534
|
-
scale =
|
|
3535
|
-
|
|
4164
|
+
scale = calculateFitScale();
|
|
4165
|
+
rotation = 0;
|
|
4166
|
+
applyTransform();
|
|
4167
|
+
},
|
|
4168
|
+
rotateCW: () => {
|
|
4169
|
+
rotation = (rotation + 90) % 360;
|
|
4170
|
+
applyTransform();
|
|
4171
|
+
},
|
|
4172
|
+
rotateCCW: () => {
|
|
4173
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4174
|
+
applyTransform();
|
|
3536
4175
|
},
|
|
3537
4176
|
download: () => {
|
|
3538
4177
|
const blob = new Blob([ctx.buffer], { type: "application/rtf" });
|
|
@@ -3704,41 +4343,41 @@ var OpenDocumentPlugin = class {
|
|
|
3704
4343
|
}
|
|
3705
4344
|
getToolbarActions(instance) {
|
|
3706
4345
|
const isPresentation = instance.isPresentation;
|
|
4346
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3707
4347
|
const actions = [];
|
|
3708
|
-
if (isPresentation) {
|
|
3709
|
-
|
|
3710
|
-
{
|
|
4348
|
+
if (isPresentation || totalPages > 1) {
|
|
4349
|
+
if (isPresentation) {
|
|
4350
|
+
actions.push({
|
|
3711
4351
|
id: "thumbnails",
|
|
3712
4352
|
icon: "thumbnails",
|
|
3713
4353
|
label: "Slide Thumbnails",
|
|
3714
4354
|
type: "button",
|
|
3715
4355
|
group: "navigation",
|
|
3716
4356
|
execute: () => instance.toggleThumbnails?.()
|
|
3717
|
-
}
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
}
|
|
4357
|
+
});
|
|
4358
|
+
}
|
|
4359
|
+
actions.push({
|
|
4360
|
+
id: "page-nav",
|
|
4361
|
+
icon: "",
|
|
4362
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4363
|
+
type: "page-nav",
|
|
4364
|
+
group: "navigation",
|
|
4365
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4366
|
+
max: totalPages,
|
|
4367
|
+
execute: (action, page) => {
|
|
4368
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4369
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4370
|
+
if (action === "prev") {
|
|
4371
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4372
|
+
} else if (action === "next") {
|
|
4373
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4374
|
+
} else if (typeof page === "number") {
|
|
4375
|
+
instance.goToPage?.(page);
|
|
4376
|
+
} else if (typeof action === "number") {
|
|
4377
|
+
instance.goToPage?.(action);
|
|
3739
4378
|
}
|
|
3740
4379
|
}
|
|
3741
|
-
);
|
|
4380
|
+
});
|
|
3742
4381
|
}
|
|
3743
4382
|
actions.push(
|
|
3744
4383
|
{
|
|
@@ -3760,11 +4399,19 @@ var OpenDocumentPlugin = class {
|
|
|
3760
4399
|
{
|
|
3761
4400
|
id: "fit-page",
|
|
3762
4401
|
icon: "fit-page",
|
|
3763
|
-
label: "Fit to Page",
|
|
4402
|
+
label: isPresentation ? "Fit to Slide" : "Fit to Page",
|
|
3764
4403
|
type: "button",
|
|
3765
4404
|
group: "zoom",
|
|
3766
4405
|
execute: () => instance.fitToPage?.()
|
|
3767
4406
|
},
|
|
4407
|
+
{
|
|
4408
|
+
id: "rotate-cw",
|
|
4409
|
+
icon: "rotate-cw",
|
|
4410
|
+
label: "Rotate",
|
|
4411
|
+
type: "button",
|
|
4412
|
+
group: "view",
|
|
4413
|
+
execute: () => instance.rotateCW?.()
|
|
4414
|
+
},
|
|
3768
4415
|
{
|
|
3769
4416
|
id: "download",
|
|
3770
4417
|
icon: "download",
|
|
@@ -3828,6 +4475,22 @@ var OpenDocumentPlugin = class {
|
|
|
3828
4475
|
container.appendChild(wrapper);
|
|
3829
4476
|
ctx.container.appendChild(container);
|
|
3830
4477
|
let scale = 1;
|
|
4478
|
+
let rotation = 0;
|
|
4479
|
+
const calculateFitScale = () => {
|
|
4480
|
+
const elW = wrapper.offsetWidth || 850;
|
|
4481
|
+
const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
|
|
4482
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4483
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4484
|
+
return Math.min(1, Math.min(availW / elW, availH / elH));
|
|
4485
|
+
};
|
|
4486
|
+
const applyTransform = () => {
|
|
4487
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4488
|
+
wrapper.style.transformOrigin = "top center";
|
|
4489
|
+
};
|
|
4490
|
+
setTimeout(() => {
|
|
4491
|
+
scale = calculateFitScale();
|
|
4492
|
+
applyTransform();
|
|
4493
|
+
}, 60);
|
|
3831
4494
|
let currentPage = 1;
|
|
3832
4495
|
let totalPages = 1;
|
|
3833
4496
|
let slides = [];
|
|
@@ -3886,21 +4549,30 @@ var OpenDocumentPlugin = class {
|
|
|
3886
4549
|
destroy: cleanup,
|
|
3887
4550
|
isPresentation,
|
|
3888
4551
|
zoomIn: () => {
|
|
3889
|
-
scale += 0.
|
|
3890
|
-
|
|
4552
|
+
scale += 0.15;
|
|
4553
|
+
applyTransform();
|
|
3891
4554
|
},
|
|
3892
4555
|
zoomOut: () => {
|
|
3893
|
-
scale = Math.max(0.2, scale - 0.
|
|
3894
|
-
|
|
4556
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4557
|
+
applyTransform();
|
|
3895
4558
|
},
|
|
3896
4559
|
getZoom: () => scale,
|
|
3897
4560
|
setZoom: (level) => {
|
|
3898
4561
|
scale = level;
|
|
3899
|
-
|
|
4562
|
+
applyTransform();
|
|
3900
4563
|
},
|
|
3901
4564
|
fitToPage: () => {
|
|
3902
|
-
scale =
|
|
3903
|
-
|
|
4565
|
+
scale = calculateFitScale();
|
|
4566
|
+
rotation = 0;
|
|
4567
|
+
applyTransform();
|
|
4568
|
+
},
|
|
4569
|
+
rotateCW: () => {
|
|
4570
|
+
rotation = (rotation + 90) % 360;
|
|
4571
|
+
applyTransform();
|
|
4572
|
+
},
|
|
4573
|
+
rotateCCW: () => {
|
|
4574
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4575
|
+
applyTransform();
|
|
3904
4576
|
},
|
|
3905
4577
|
goToPage,
|
|
3906
4578
|
getPageCount: () => totalPages,
|
|
@@ -4121,7 +4793,31 @@ var DocPlugin = class {
|
|
|
4121
4793
|
return this.mimeTypes.includes(mime || "");
|
|
4122
4794
|
}
|
|
4123
4795
|
getToolbarActions(instance) {
|
|
4124
|
-
|
|
4796
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4797
|
+
const actions = [];
|
|
4798
|
+
if (totalPages > 1) {
|
|
4799
|
+
actions.push({
|
|
4800
|
+
id: "page-nav",
|
|
4801
|
+
icon: "",
|
|
4802
|
+
label: "Page Navigation",
|
|
4803
|
+
type: "page-nav",
|
|
4804
|
+
group: "navigation",
|
|
4805
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4806
|
+
max: totalPages,
|
|
4807
|
+
execute: (action, page) => {
|
|
4808
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4809
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4810
|
+
if (action === "prev") {
|
|
4811
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4812
|
+
} else if (action === "next") {
|
|
4813
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4814
|
+
} else if (typeof page === "number") {
|
|
4815
|
+
instance.goToPage?.(page);
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4818
|
+
});
|
|
4819
|
+
}
|
|
4820
|
+
actions.push(
|
|
4125
4821
|
{
|
|
4126
4822
|
id: "zoom-out",
|
|
4127
4823
|
icon: "zoom-out",
|
|
@@ -4146,6 +4842,14 @@ var DocPlugin = class {
|
|
|
4146
4842
|
group: "zoom",
|
|
4147
4843
|
execute: () => instance.fitToPage?.()
|
|
4148
4844
|
},
|
|
4845
|
+
{
|
|
4846
|
+
id: "rotate-cw",
|
|
4847
|
+
icon: "rotate-cw",
|
|
4848
|
+
label: "Rotate",
|
|
4849
|
+
type: "button",
|
|
4850
|
+
group: "view",
|
|
4851
|
+
execute: () => instance.rotateCW?.()
|
|
4852
|
+
},
|
|
4149
4853
|
{
|
|
4150
4854
|
id: "copy",
|
|
4151
4855
|
icon: "copy",
|
|
@@ -4170,7 +4874,8 @@ var DocPlugin = class {
|
|
|
4170
4874
|
group: "actions",
|
|
4171
4875
|
execute: () => instance.print?.()
|
|
4172
4876
|
}
|
|
4173
|
-
|
|
4877
|
+
);
|
|
4878
|
+
return actions;
|
|
4174
4879
|
}
|
|
4175
4880
|
async render(ctx) {
|
|
4176
4881
|
const container = document.createElement("div");
|
|
@@ -4197,6 +4902,7 @@ var DocPlugin = class {
|
|
|
4197
4902
|
ctx.container.appendChild(container);
|
|
4198
4903
|
let scale = 1;
|
|
4199
4904
|
let extractedRawText = "";
|
|
4905
|
+
let isFallback = false;
|
|
4200
4906
|
try {
|
|
4201
4907
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4202
4908
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4210,42 +4916,131 @@ var DocPlugin = class {
|
|
|
4210
4916
|
const tableStream = cfbf.readStream(tableName);
|
|
4211
4917
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4212
4918
|
extractedRawText = text;
|
|
4213
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4214
4919
|
} catch (err) {
|
|
4215
4920
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4216
4921
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4217
4922
|
extractedRawText = fallback;
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4923
|
+
isFallback = true;
|
|
4924
|
+
}
|
|
4925
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4926
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4927
|
+
let currentPage = 1;
|
|
4928
|
+
wrapper.innerHTML = "";
|
|
4929
|
+
const pageCards = [];
|
|
4930
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4931
|
+
const pageCard = document.createElement("div");
|
|
4932
|
+
pageCard.className = "fp-doc-page-card";
|
|
4933
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4934
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4935
|
+
pageCard.style.borderRadius = "4px";
|
|
4936
|
+
pageCard.style.padding = "56px 48px";
|
|
4937
|
+
pageCard.style.minHeight = "100%";
|
|
4938
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4939
|
+
if (isFallback && i === 0) {
|
|
4940
|
+
pageCard.innerHTML = `
|
|
4941
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4942
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4943
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4944
|
+
</div>
|
|
4945
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4946
|
+
`;
|
|
4947
|
+
} else {
|
|
4948
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4949
|
+
}
|
|
4950
|
+
wrapper.appendChild(pageCard);
|
|
4951
|
+
pageCards.push(pageCard);
|
|
4952
|
+
}
|
|
4953
|
+
let indicator = null;
|
|
4954
|
+
if (totalPages > 1) {
|
|
4955
|
+
indicator = document.createElement("div");
|
|
4956
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4957
|
+
indicator.style.position = "sticky";
|
|
4958
|
+
indicator.style.bottom = "16px";
|
|
4959
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4960
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4961
|
+
indicator.style.color = "#f8fafc";
|
|
4962
|
+
indicator.style.fontSize = "12px";
|
|
4963
|
+
indicator.style.fontWeight = "600";
|
|
4964
|
+
indicator.style.padding = "5px 14px";
|
|
4965
|
+
indicator.style.borderRadius = "20px";
|
|
4966
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4967
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4968
|
+
indicator.style.zIndex = "10";
|
|
4969
|
+
indicator.style.userSelect = "none";
|
|
4970
|
+
indicator.style.pointerEvents = "none";
|
|
4971
|
+
indicator.style.textAlign = "center";
|
|
4972
|
+
indicator.style.width = "fit-content";
|
|
4973
|
+
indicator.style.margin = "16px auto 0";
|
|
4974
|
+
container.appendChild(indicator);
|
|
4975
|
+
}
|
|
4976
|
+
const showPage = (pageNum) => {
|
|
4977
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4978
|
+
if (totalPages > 1) {
|
|
4979
|
+
pageCards.forEach((card, idx) => {
|
|
4980
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4981
|
+
});
|
|
4982
|
+
}
|
|
4983
|
+
if (indicator) {
|
|
4984
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4985
|
+
}
|
|
4986
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4987
|
+
};
|
|
4988
|
+
if (totalPages > 1) {
|
|
4989
|
+
showPage(1);
|
|
4225
4990
|
}
|
|
4991
|
+
let rotation = 0;
|
|
4992
|
+
const calculateFitScale = () => {
|
|
4993
|
+
const activeCard = pageCards[currentPage - 1] || wrapper;
|
|
4994
|
+
const elW = activeCard.offsetWidth || 850;
|
|
4995
|
+
const elH = activeCard.offsetHeight || 1e3;
|
|
4996
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4997
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4998
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4999
|
+
};
|
|
5000
|
+
const applyTransform = () => {
|
|
5001
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5002
|
+
wrapper.style.transformOrigin = "top center";
|
|
5003
|
+
};
|
|
5004
|
+
setTimeout(() => {
|
|
5005
|
+
scale = calculateFitScale();
|
|
5006
|
+
applyTransform();
|
|
5007
|
+
}, 60);
|
|
4226
5008
|
const cleanup = () => {
|
|
5009
|
+
indicator?.remove();
|
|
4227
5010
|
container.remove();
|
|
4228
5011
|
ctx.container.innerHTML = "";
|
|
4229
5012
|
};
|
|
4230
5013
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4231
5014
|
return {
|
|
4232
5015
|
destroy: cleanup,
|
|
5016
|
+
getPageCount: () => totalPages,
|
|
5017
|
+
getCurrentPage: () => currentPage,
|
|
5018
|
+
goToPage: (page) => showPage(page),
|
|
4233
5019
|
zoomIn: () => {
|
|
4234
|
-
scale += 0.
|
|
4235
|
-
|
|
5020
|
+
scale += 0.15;
|
|
5021
|
+
applyTransform();
|
|
4236
5022
|
},
|
|
4237
5023
|
zoomOut: () => {
|
|
4238
|
-
scale = Math.max(0.2, scale - 0.
|
|
4239
|
-
|
|
5024
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5025
|
+
applyTransform();
|
|
4240
5026
|
},
|
|
4241
5027
|
getZoom: () => scale,
|
|
4242
5028
|
setZoom: (level) => {
|
|
4243
5029
|
scale = level;
|
|
4244
|
-
|
|
5030
|
+
applyTransform();
|
|
4245
5031
|
},
|
|
4246
5032
|
fitToPage: () => {
|
|
4247
|
-
scale =
|
|
4248
|
-
|
|
5033
|
+
scale = calculateFitScale();
|
|
5034
|
+
rotation = 0;
|
|
5035
|
+
applyTransform();
|
|
5036
|
+
},
|
|
5037
|
+
rotateCW: () => {
|
|
5038
|
+
rotation = (rotation + 90) % 360;
|
|
5039
|
+
applyTransform();
|
|
5040
|
+
},
|
|
5041
|
+
rotateCCW: () => {
|
|
5042
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5043
|
+
applyTransform();
|
|
4249
5044
|
},
|
|
4250
5045
|
copy: () => {
|
|
4251
5046
|
navigator.clipboard.writeText(extractedRawText);
|
|
@@ -4361,11 +5156,16 @@ var DocPlugin = class {
|
|
|
4361
5156
|
heuristicTextExtraction(buffer) {
|
|
4362
5157
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4363
5158
|
}
|
|
5159
|
+
splitIntoPages(text) {
|
|
5160
|
+
if (!text) return [""];
|
|
5161
|
+
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);
|
|
5162
|
+
return parts.length > 0 ? parts : [text];
|
|
5163
|
+
}
|
|
4364
5164
|
/**
|
|
4365
5165
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4366
5166
|
*/
|
|
4367
5167
|
formatDocToHtml(text, filename) {
|
|
4368
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
5168
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4369
5169
|
let html = "";
|
|
4370
5170
|
let inList = false;
|
|
4371
5171
|
for (const rawLine of lines) {
|
|
@@ -4480,6 +5280,14 @@ var PptPlugin = class {
|
|
|
4480
5280
|
group: "zoom",
|
|
4481
5281
|
execute: () => instance.fitToPage?.()
|
|
4482
5282
|
},
|
|
5283
|
+
{
|
|
5284
|
+
id: "rotate-cw",
|
|
5285
|
+
icon: "rotate-cw",
|
|
5286
|
+
label: "Rotate",
|
|
5287
|
+
type: "button",
|
|
5288
|
+
group: "view",
|
|
5289
|
+
execute: () => instance.rotateCW?.()
|
|
5290
|
+
},
|
|
4483
5291
|
{
|
|
4484
5292
|
id: "download",
|
|
4485
5293
|
icon: "download",
|
|
@@ -4513,22 +5321,36 @@ var PptPlugin = class {
|
|
|
4513
5321
|
const slideCard = document.createElement("div");
|
|
4514
5322
|
slideCard.className = "fp-ppt-slide-card";
|
|
4515
5323
|
slideCard.style.width = "960px";
|
|
4516
|
-
slideCard.style.maxWidth = "
|
|
5324
|
+
slideCard.style.maxWidth = "calc(100% - 32px)";
|
|
5325
|
+
slideCard.style.maxHeight = "calc(100% - 48px)";
|
|
4517
5326
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4518
5327
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4519
5328
|
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4520
5329
|
slideCard.style.borderRadius = "8px";
|
|
4521
5330
|
slideCard.style.boxSizing = "border-box";
|
|
4522
5331
|
slideCard.style.position = "relative";
|
|
4523
|
-
slideCard.style.overflow = "hidden";
|
|
4524
|
-
slideCard.style.transformOrigin = "center center";
|
|
4525
5332
|
slideCard.style.transition = "transform 0.2s ease";
|
|
5333
|
+
slideCard.style.transformOrigin = "center center";
|
|
5334
|
+
slideCard.style.flexShrink = "0";
|
|
4526
5335
|
container.appendChild(slideCard);
|
|
4527
5336
|
ctx.container.appendChild(container);
|
|
4528
5337
|
let scale = 1;
|
|
5338
|
+
let rotation = 0;
|
|
4529
5339
|
let currentSlide = 1;
|
|
4530
5340
|
let slides = [];
|
|
4531
5341
|
const createdBlobUrls = [];
|
|
5342
|
+
const calculateFitScale = () => {
|
|
5343
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
5344
|
+
const availH = Math.max(200, container.clientHeight - 72);
|
|
5345
|
+
return Math.min(1, Math.min(availW / 960, availH / 540));
|
|
5346
|
+
};
|
|
5347
|
+
const applyTransform = () => {
|
|
5348
|
+
slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5349
|
+
};
|
|
5350
|
+
setTimeout(() => {
|
|
5351
|
+
scale = calculateFitScale();
|
|
5352
|
+
applyTransform();
|
|
5353
|
+
}, 60);
|
|
4532
5354
|
try {
|
|
4533
5355
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4534
5356
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
@@ -4629,21 +5451,30 @@ var PptPlugin = class {
|
|
|
4629
5451
|
return {
|
|
4630
5452
|
destroy: cleanup,
|
|
4631
5453
|
zoomIn: () => {
|
|
4632
|
-
scale += 0.
|
|
4633
|
-
|
|
5454
|
+
scale += 0.15;
|
|
5455
|
+
applyTransform();
|
|
4634
5456
|
},
|
|
4635
5457
|
zoomOut: () => {
|
|
4636
|
-
scale = Math.max(0.
|
|
4637
|
-
|
|
5458
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5459
|
+
applyTransform();
|
|
4638
5460
|
},
|
|
4639
5461
|
getZoom: () => scale,
|
|
4640
5462
|
setZoom: (level) => {
|
|
4641
5463
|
scale = level;
|
|
4642
|
-
|
|
5464
|
+
applyTransform();
|
|
4643
5465
|
},
|
|
4644
5466
|
fitToPage: () => {
|
|
4645
|
-
scale =
|
|
4646
|
-
|
|
5467
|
+
scale = calculateFitScale();
|
|
5468
|
+
rotation = 0;
|
|
5469
|
+
applyTransform();
|
|
5470
|
+
},
|
|
5471
|
+
rotateCW: () => {
|
|
5472
|
+
rotation = (rotation + 90) % 360;
|
|
5473
|
+
applyTransform();
|
|
5474
|
+
},
|
|
5475
|
+
rotateCCW: () => {
|
|
5476
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5477
|
+
applyTransform();
|
|
4647
5478
|
},
|
|
4648
5479
|
goToPage: (page) => {
|
|
4649
5480
|
if (page >= 1 && page <= totalSlides) {
|