@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/react.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { memo, forwardRef, useRef, useImperativeHandle, useEffect } from 'react';
|
|
2
2
|
import DOMPurify2 from 'dompurify';
|
|
3
|
+
import * as pdfjsLib from 'pdfjs-dist';
|
|
3
4
|
import * as docx from 'docx-preview';
|
|
4
5
|
import { unzipSync, strFromU8, unzip } from 'fflate';
|
|
5
6
|
import * as XLSX from 'xlsx';
|
|
@@ -480,11 +481,21 @@ var ToolbarController = class {
|
|
|
480
481
|
el;
|
|
481
482
|
toolbarEl;
|
|
482
483
|
actions = [];
|
|
484
|
+
pageInputEl = null;
|
|
485
|
+
pageLabelEl = null;
|
|
483
486
|
constructor(container) {
|
|
484
487
|
this.el = container;
|
|
485
488
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
486
489
|
this.el.appendChild(this.toolbarEl);
|
|
487
490
|
}
|
|
491
|
+
setPage(page, max) {
|
|
492
|
+
if (this.pageInputEl) {
|
|
493
|
+
this.pageInputEl.value = page.toString();
|
|
494
|
+
}
|
|
495
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
496
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
488
499
|
update(actions) {
|
|
489
500
|
this.actions = actions;
|
|
490
501
|
this.render();
|
|
@@ -527,6 +538,7 @@ var ToolbarController = class {
|
|
|
527
538
|
if (action.type === "separator") {
|
|
528
539
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
529
540
|
} else if (action.type === "page-nav") {
|
|
541
|
+
const max = action.max ?? 1;
|
|
530
542
|
const prevBtn = this.createButton(
|
|
531
543
|
"prev",
|
|
532
544
|
ICON_PAGE_PREV,
|
|
@@ -545,7 +557,6 @@ var ToolbarController = class {
|
|
|
545
557
|
"Next Page",
|
|
546
558
|
() => {
|
|
547
559
|
const cur = parseInt(input.value, 10) || 1;
|
|
548
|
-
const max = action.max ?? 1;
|
|
549
560
|
if (cur < max) {
|
|
550
561
|
input.value = (cur + 1).toString();
|
|
551
562
|
action.execute("next", cur + 1);
|
|
@@ -557,15 +568,18 @@ var ToolbarController = class {
|
|
|
557
568
|
type: "number",
|
|
558
569
|
value: (action.value ?? 1).toString(),
|
|
559
570
|
min: "1",
|
|
560
|
-
max:
|
|
571
|
+
max: max.toString()
|
|
561
572
|
});
|
|
562
573
|
input.addEventListener("change", () => {
|
|
563
|
-
|
|
564
|
-
if (
|
|
565
|
-
|
|
566
|
-
|
|
574
|
+
let val = parseInt(input.value, 10);
|
|
575
|
+
if (isNaN(val)) val = 1;
|
|
576
|
+
val = Math.max(1, Math.min(max, val));
|
|
577
|
+
input.value = val.toString();
|
|
578
|
+
action.execute("go", val);
|
|
567
579
|
});
|
|
568
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
580
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
581
|
+
this.pageInputEl = input;
|
|
582
|
+
this.pageLabelEl = label;
|
|
569
583
|
groupEl.appendChild(prevBtn);
|
|
570
584
|
groupEl.appendChild(input);
|
|
571
585
|
groupEl.appendChild(label);
|
|
@@ -692,6 +706,8 @@ var FilePreviewViewer = class {
|
|
|
692
706
|
keyHandler = null;
|
|
693
707
|
currentContainer = null;
|
|
694
708
|
currentOptions = {};
|
|
709
|
+
resizeObserver = null;
|
|
710
|
+
fullscreenHandler = null;
|
|
695
711
|
/**
|
|
696
712
|
* Register a preview plugin.
|
|
697
713
|
*/
|
|
@@ -743,7 +759,13 @@ var FilePreviewViewer = class {
|
|
|
743
759
|
buffer,
|
|
744
760
|
options,
|
|
745
761
|
signal,
|
|
746
|
-
emit: (event, payload) =>
|
|
762
|
+
emit: (event, payload) => {
|
|
763
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
764
|
+
const total = payload.total ?? payload.totalPages;
|
|
765
|
+
this.toolbar?.setPage(payload.page, total);
|
|
766
|
+
}
|
|
767
|
+
this.eventEmitter.emit(event, payload);
|
|
768
|
+
}
|
|
747
769
|
});
|
|
748
770
|
this.activeInstance = instance;
|
|
749
771
|
this.hideLoading();
|
|
@@ -758,12 +780,31 @@ var FilePreviewViewer = class {
|
|
|
758
780
|
label: "Toggle Fullscreen",
|
|
759
781
|
type: "button",
|
|
760
782
|
group: "view",
|
|
761
|
-
execute: () => {
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
783
|
+
execute: async () => {
|
|
784
|
+
try {
|
|
785
|
+
const isNativeFs = !!document.fullscreenElement;
|
|
786
|
+
const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
|
|
787
|
+
if (!isNativeFs && !isCssFs) {
|
|
788
|
+
if (this.wrapperEl?.requestFullscreen) {
|
|
789
|
+
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
790
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
791
|
+
});
|
|
792
|
+
} else {
|
|
793
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
794
|
+
}
|
|
795
|
+
} else {
|
|
796
|
+
if (document.fullscreenElement) {
|
|
797
|
+
await document.exitFullscreen().catch(() => {
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
801
|
+
}
|
|
802
|
+
} catch {
|
|
803
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
766
804
|
}
|
|
805
|
+
setTimeout(() => {
|
|
806
|
+
this.activeInstance?.fitToPage?.();
|
|
807
|
+
}, 120);
|
|
767
808
|
}
|
|
768
809
|
});
|
|
769
810
|
}
|
|
@@ -777,6 +818,7 @@ var FilePreviewViewer = class {
|
|
|
777
818
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
778
819
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
779
820
|
instance.goToPage?.(index + 1);
|
|
821
|
+
this.toolbar?.setPage(index + 1);
|
|
780
822
|
});
|
|
781
823
|
if (options.showThumbnails) {
|
|
782
824
|
this.thumbnailPanel.show();
|
|
@@ -812,6 +854,15 @@ var FilePreviewViewer = class {
|
|
|
812
854
|
window.removeEventListener("keydown", this.keyHandler);
|
|
813
855
|
this.keyHandler = null;
|
|
814
856
|
}
|
|
857
|
+
if (this.resizeObserver) {
|
|
858
|
+
this.resizeObserver.disconnect();
|
|
859
|
+
this.resizeObserver = null;
|
|
860
|
+
}
|
|
861
|
+
if (this.fullscreenHandler) {
|
|
862
|
+
document.removeEventListener("fullscreenchange", this.fullscreenHandler);
|
|
863
|
+
document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
864
|
+
this.fullscreenHandler = null;
|
|
865
|
+
}
|
|
815
866
|
this.abort();
|
|
816
867
|
this.destroyInstance();
|
|
817
868
|
this.toolbar?.destroy();
|
|
@@ -891,6 +942,25 @@ var FilePreviewViewer = class {
|
|
|
891
942
|
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
|
|
892
943
|
this.setupKeyboardShortcuts();
|
|
893
944
|
this.setupDragAndDrop(container, options);
|
|
945
|
+
this.setupResizeAndFullscreenListeners();
|
|
946
|
+
}
|
|
947
|
+
setupResizeAndFullscreenListeners() {
|
|
948
|
+
if (this.fullscreenHandler) return;
|
|
949
|
+
this.fullscreenHandler = () => {
|
|
950
|
+
setTimeout(() => {
|
|
951
|
+
this.activeInstance?.fitToPage?.();
|
|
952
|
+
}, 100);
|
|
953
|
+
};
|
|
954
|
+
document.addEventListener("fullscreenchange", this.fullscreenHandler);
|
|
955
|
+
document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
956
|
+
if (typeof ResizeObserver !== "undefined" && this.contentEl) {
|
|
957
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
958
|
+
if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
|
|
959
|
+
this.activeInstance.fitToPage?.();
|
|
960
|
+
}
|
|
961
|
+
});
|
|
962
|
+
this.resizeObserver.observe(this.contentEl);
|
|
963
|
+
}
|
|
894
964
|
}
|
|
895
965
|
setupKeyboardShortcuts() {
|
|
896
966
|
if (this.keyHandler) return;
|
|
@@ -902,9 +972,13 @@ var FilePreviewViewer = class {
|
|
|
902
972
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
903
973
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
904
974
|
this.activeInstance.goToPage?.(cur + 1);
|
|
975
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
976
|
+
this.toolbar?.setPage(nextCur);
|
|
905
977
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
906
978
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
907
979
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
980
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
981
|
+
this.toolbar?.setPage(prevCur);
|
|
908
982
|
} else if (e.key === "+" || e.key === "=") {
|
|
909
983
|
this.activeInstance.zoomIn?.();
|
|
910
984
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1170,30 +1244,62 @@ var CfbfReader = class {
|
|
|
1170
1244
|
return result.subarray(0, targetSize);
|
|
1171
1245
|
}
|
|
1172
1246
|
};
|
|
1173
|
-
|
|
1174
|
-
|
|
1247
|
+
if (typeof window !== "undefined" && pdfjsLib.GlobalWorkerOptions) {
|
|
1248
|
+
if (!pdfjsLib.GlobalWorkerOptions.workerSrc) {
|
|
1249
|
+
pdfjsLib.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1175
1252
|
var PdfPlugin = class {
|
|
1176
1253
|
id = "pdf";
|
|
1177
|
-
name = "PDF Preview";
|
|
1254
|
+
name = "PDF Document Preview";
|
|
1178
1255
|
extensions = [".pdf"];
|
|
1179
1256
|
mimeTypes = ["application/pdf"];
|
|
1180
1257
|
weight = 100;
|
|
1181
1258
|
supports(file) {
|
|
1182
1259
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1183
1260
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1184
|
-
|
|
1261
|
+
if (ext) return this.extensions.includes(ext);
|
|
1262
|
+
return this.mimeTypes.includes(mime || "");
|
|
1185
1263
|
}
|
|
1186
1264
|
getToolbarActions(instance) {
|
|
1265
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1266
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1187
1267
|
return [
|
|
1268
|
+
{
|
|
1269
|
+
id: "thumbnails",
|
|
1270
|
+
icon: "thumbnails",
|
|
1271
|
+
label: "Page Thumbnails",
|
|
1272
|
+
type: "button",
|
|
1273
|
+
group: "navigation",
|
|
1274
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1275
|
+
},
|
|
1276
|
+
{
|
|
1277
|
+
id: "page-nav",
|
|
1278
|
+
icon: "",
|
|
1279
|
+
label: "Page Navigation",
|
|
1280
|
+
type: "page-nav",
|
|
1281
|
+
group: "navigation",
|
|
1282
|
+
value: curPage,
|
|
1283
|
+
max: totalPages,
|
|
1284
|
+
execute: (action, page) => {
|
|
1285
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1286
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1287
|
+
if (action === "prev") {
|
|
1288
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1289
|
+
} else if (action === "next") {
|
|
1290
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1291
|
+
} else if (typeof page === "number") {
|
|
1292
|
+
instance.goToPage?.(page);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
},
|
|
1188
1296
|
{
|
|
1189
1297
|
id: "zoom-out",
|
|
1190
1298
|
icon: "zoom-out",
|
|
1191
1299
|
label: "Zoom Out",
|
|
1192
1300
|
type: "button",
|
|
1193
1301
|
group: "zoom",
|
|
1194
|
-
execute: () =>
|
|
1195
|
-
instance.zoomOut?.();
|
|
1196
|
-
}
|
|
1302
|
+
execute: () => instance.zoomOut?.()
|
|
1197
1303
|
},
|
|
1198
1304
|
{
|
|
1199
1305
|
id: "zoom-in",
|
|
@@ -1201,9 +1307,7 @@ var PdfPlugin = class {
|
|
|
1201
1307
|
label: "Zoom In",
|
|
1202
1308
|
type: "button",
|
|
1203
1309
|
group: "zoom",
|
|
1204
|
-
execute: () =>
|
|
1205
|
-
instance.zoomIn?.();
|
|
1206
|
-
}
|
|
1310
|
+
execute: () => instance.zoomIn?.()
|
|
1207
1311
|
},
|
|
1208
1312
|
{
|
|
1209
1313
|
id: "fit-page",
|
|
@@ -1211,39 +1315,23 @@ var PdfPlugin = class {
|
|
|
1211
1315
|
label: "Fit to Page",
|
|
1212
1316
|
type: "button",
|
|
1213
1317
|
group: "zoom",
|
|
1214
|
-
execute: () =>
|
|
1215
|
-
instance.fitToPage?.();
|
|
1216
|
-
}
|
|
1318
|
+
execute: () => instance.fitToPage?.()
|
|
1217
1319
|
},
|
|
1218
1320
|
{
|
|
1219
1321
|
id: "rotate-cw",
|
|
1220
1322
|
icon: "rotate-cw",
|
|
1221
|
-
label: "Rotate",
|
|
1323
|
+
label: "Rotate Clockwise",
|
|
1222
1324
|
type: "button",
|
|
1223
1325
|
group: "view",
|
|
1224
|
-
execute: () =>
|
|
1225
|
-
instance.rotateCW?.();
|
|
1226
|
-
}
|
|
1227
|
-
},
|
|
1228
|
-
{
|
|
1229
|
-
id: "page-nav",
|
|
1230
|
-
icon: "page-nav",
|
|
1231
|
-
label: "Page Navigation",
|
|
1232
|
-
type: "page-nav",
|
|
1233
|
-
group: "navigation",
|
|
1234
|
-
execute: (page) => {
|
|
1235
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1236
|
-
}
|
|
1326
|
+
execute: () => instance.rotateCW?.()
|
|
1237
1327
|
},
|
|
1238
1328
|
{
|
|
1239
1329
|
id: "download",
|
|
1240
1330
|
icon: "download",
|
|
1241
|
-
label: "Download",
|
|
1331
|
+
label: "Download PDF",
|
|
1242
1332
|
type: "button",
|
|
1243
1333
|
group: "actions",
|
|
1244
|
-
execute: () =>
|
|
1245
|
-
instance.download?.();
|
|
1246
|
-
}
|
|
1334
|
+
execute: () => instance.download?.()
|
|
1247
1335
|
},
|
|
1248
1336
|
{
|
|
1249
1337
|
id: "print",
|
|
@@ -1251,99 +1339,224 @@ var PdfPlugin = class {
|
|
|
1251
1339
|
label: "Print",
|
|
1252
1340
|
type: "button",
|
|
1253
1341
|
group: "actions",
|
|
1254
|
-
execute: () =>
|
|
1255
|
-
instance.print?.();
|
|
1256
|
-
}
|
|
1342
|
+
execute: () => instance.print?.()
|
|
1257
1343
|
}
|
|
1258
1344
|
];
|
|
1259
1345
|
}
|
|
1260
1346
|
async render(ctx) {
|
|
1261
|
-
const
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1347
|
+
const container = document.createElement("div");
|
|
1348
|
+
container.className = "fp-pdf-container";
|
|
1349
|
+
container.style.width = "100%";
|
|
1350
|
+
container.style.height = "100%";
|
|
1351
|
+
container.style.overflow = "auto";
|
|
1352
|
+
container.style.display = "flex";
|
|
1353
|
+
container.style.flexDirection = "column";
|
|
1354
|
+
container.style.alignItems = "center";
|
|
1355
|
+
container.style.justifyContent = "flex-start";
|
|
1356
|
+
container.style.padding = "20px 16px";
|
|
1357
|
+
container.style.backgroundColor = "#0f172a";
|
|
1358
|
+
container.style.boxSizing = "border-box";
|
|
1359
|
+
container.style.position = "relative";
|
|
1360
|
+
const pageCard = document.createElement("div");
|
|
1361
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1362
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1363
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1364
|
+
pageCard.style.borderRadius = "4px";
|
|
1365
|
+
pageCard.style.overflow = "hidden";
|
|
1366
|
+
pageCard.style.lineHeight = "0";
|
|
1367
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1368
|
+
pageCard.style.position = "relative";
|
|
1369
|
+
pageCard.style.flexShrink = "0";
|
|
1370
|
+
let canvas = document.createElement("canvas");
|
|
1371
|
+
pageCard.appendChild(canvas);
|
|
1372
|
+
container.appendChild(pageCard);
|
|
1373
|
+
const indicator = document.createElement("div");
|
|
1374
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1375
|
+
indicator.style.position = "sticky";
|
|
1376
|
+
indicator.style.bottom = "16px";
|
|
1377
|
+
indicator.style.marginTop = "16px";
|
|
1378
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1379
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1380
|
+
indicator.style.color = "#f8fafc";
|
|
1381
|
+
indicator.style.fontSize = "12px";
|
|
1382
|
+
indicator.style.fontWeight = "600";
|
|
1383
|
+
indicator.style.padding = "5px 14px";
|
|
1384
|
+
indicator.style.borderRadius = "20px";
|
|
1385
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1386
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1387
|
+
indicator.style.zIndex = "10";
|
|
1388
|
+
indicator.style.userSelect = "none";
|
|
1389
|
+
indicator.style.pointerEvents = "none";
|
|
1390
|
+
container.appendChild(indicator);
|
|
1391
|
+
ctx.container.appendChild(container);
|
|
1392
|
+
const loadingTask = pdfjsLib.getDocument({
|
|
1393
|
+
data: new Uint8Array(ctx.buffer),
|
|
1394
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/cmaps/`,
|
|
1395
|
+
cMapPacked: true,
|
|
1396
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib.version || "4.10.38"}/standard_fonts/`
|
|
1397
|
+
});
|
|
1398
|
+
const pdfDoc = await loadingTask.promise;
|
|
1399
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1277
1400
|
let currentPage = 1;
|
|
1278
|
-
let
|
|
1401
|
+
let zoomScale = 1;
|
|
1279
1402
|
let rotation = 0;
|
|
1403
|
+
let currentRenderTask = null;
|
|
1404
|
+
const renderPage = async (pageNum) => {
|
|
1405
|
+
if (currentRenderTask) {
|
|
1406
|
+
try {
|
|
1407
|
+
currentRenderTask.cancel();
|
|
1408
|
+
} catch {
|
|
1409
|
+
}
|
|
1410
|
+
currentRenderTask = null;
|
|
1411
|
+
}
|
|
1412
|
+
const newCanvas = document.createElement("canvas");
|
|
1413
|
+
pageCard.replaceChild(newCanvas, canvas);
|
|
1414
|
+
canvas = newCanvas;
|
|
1415
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1416
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1417
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1418
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1419
|
+
const containerWidth = container.clientWidth || 900;
|
|
1420
|
+
const containerHeight = container.clientHeight || 700;
|
|
1421
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1422
|
+
const availWidth = Math.max(100, containerWidth - 48);
|
|
1423
|
+
const availHeight = Math.max(100, containerHeight - 88);
|
|
1424
|
+
const scaleW = availWidth / unscaledVp.width;
|
|
1425
|
+
const scaleH = availHeight / unscaledVp.height;
|
|
1426
|
+
const fitScale = Math.min(scaleW, scaleH);
|
|
1427
|
+
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1428
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1429
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1430
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1431
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1432
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1433
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1434
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1435
|
+
if (!canvasCtx) return;
|
|
1436
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1437
|
+
currentRenderTask = page.render({
|
|
1438
|
+
canvasContext: canvasCtx,
|
|
1439
|
+
viewport
|
|
1440
|
+
});
|
|
1441
|
+
try {
|
|
1442
|
+
await currentRenderTask.promise;
|
|
1443
|
+
} catch (err) {
|
|
1444
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1445
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1446
|
+
}
|
|
1447
|
+
} finally {
|
|
1448
|
+
currentRenderTask = null;
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1451
|
+
await renderPage(1);
|
|
1280
1452
|
const cleanup = () => {
|
|
1281
|
-
|
|
1282
|
-
|
|
1453
|
+
if (currentRenderTask) {
|
|
1454
|
+
try {
|
|
1455
|
+
currentRenderTask.cancel();
|
|
1456
|
+
} catch {
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
try {
|
|
1460
|
+
pdfDoc.destroy();
|
|
1461
|
+
} catch {
|
|
1462
|
+
}
|
|
1463
|
+
container.remove();
|
|
1283
1464
|
ctx.container.innerHTML = "";
|
|
1284
1465
|
};
|
|
1285
1466
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1286
|
-
|
|
1467
|
+
const instance = {
|
|
1287
1468
|
destroy: cleanup,
|
|
1288
1469
|
zoomIn: () => {
|
|
1289
|
-
|
|
1290
|
-
|
|
1470
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1471
|
+
renderPage(currentPage);
|
|
1291
1472
|
},
|
|
1292
1473
|
zoomOut: () => {
|
|
1293
|
-
|
|
1294
|
-
|
|
1474
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1475
|
+
renderPage(currentPage);
|
|
1295
1476
|
},
|
|
1296
|
-
getZoom: () =>
|
|
1477
|
+
getZoom: () => zoomScale,
|
|
1297
1478
|
setZoom: (level) => {
|
|
1298
|
-
|
|
1299
|
-
|
|
1479
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1480
|
+
renderPage(currentPage);
|
|
1300
1481
|
},
|
|
1301
1482
|
fitToPage: () => {
|
|
1302
|
-
|
|
1303
|
-
|
|
1483
|
+
zoomScale = 1;
|
|
1484
|
+
rotation = 0;
|
|
1485
|
+
renderPage(currentPage);
|
|
1304
1486
|
},
|
|
1305
1487
|
rotateCW: () => {
|
|
1306
1488
|
rotation = (rotation + 90) % 360;
|
|
1307
|
-
|
|
1489
|
+
renderPage(currentPage);
|
|
1308
1490
|
},
|
|
1309
1491
|
rotateCCW: () => {
|
|
1310
1492
|
rotation = (rotation - 90 + 360) % 360;
|
|
1311
|
-
|
|
1493
|
+
renderPage(currentPage);
|
|
1312
1494
|
},
|
|
1313
1495
|
getRotation: () => rotation,
|
|
1496
|
+
getPageCount: () => totalPages,
|
|
1497
|
+
getCurrentPage: () => currentPage,
|
|
1314
1498
|
goToPage: (page) => {
|
|
1315
|
-
|
|
1316
|
-
iframe.src = `${url}#page=${page}`;
|
|
1499
|
+
renderPage(page);
|
|
1317
1500
|
},
|
|
1318
|
-
getCurrentPage: () => currentPage,
|
|
1319
1501
|
download: () => {
|
|
1502
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1503
|
+
const url = URL.createObjectURL(blob);
|
|
1320
1504
|
const a = document.createElement("a");
|
|
1321
1505
|
a.href = url;
|
|
1322
1506
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1323
1507
|
a.click();
|
|
1508
|
+
URL.revokeObjectURL(url);
|
|
1324
1509
|
},
|
|
1325
1510
|
print: () => {
|
|
1326
|
-
|
|
1511
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1512
|
+
const url = URL.createObjectURL(blob);
|
|
1513
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1514
|
+
hiddenIframe.style.position = "fixed";
|
|
1515
|
+
hiddenIframe.style.right = "0";
|
|
1516
|
+
hiddenIframe.style.bottom = "0";
|
|
1517
|
+
hiddenIframe.style.width = "0";
|
|
1518
|
+
hiddenIframe.style.height = "0";
|
|
1519
|
+
hiddenIframe.style.border = "0";
|
|
1520
|
+
document.body.appendChild(hiddenIframe);
|
|
1521
|
+
hiddenIframe.src = url;
|
|
1522
|
+
hiddenIframe.onload = () => {
|
|
1523
|
+
setTimeout(() => {
|
|
1524
|
+
hiddenIframe.contentWindow?.print();
|
|
1525
|
+
setTimeout(() => {
|
|
1526
|
+
hiddenIframe.remove();
|
|
1527
|
+
URL.revokeObjectURL(url);
|
|
1528
|
+
}, 1e3);
|
|
1529
|
+
}, 300);
|
|
1530
|
+
};
|
|
1327
1531
|
},
|
|
1328
1532
|
getThumbnails: async () => {
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1533
|
+
const thumbnails = [];
|
|
1534
|
+
const count = Math.min(totalPages, 50);
|
|
1535
|
+
for (let i = 1; i <= count; i++) {
|
|
1536
|
+
thumbnails.push({
|
|
1537
|
+
index: i,
|
|
1538
|
+
label: `Page ${i}`,
|
|
1539
|
+
render: async (thumbCanvas) => {
|
|
1540
|
+
try {
|
|
1541
|
+
const p = await pdfDoc.getPage(i);
|
|
1542
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1543
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1544
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1545
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1546
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1547
|
+
if (tCtx) {
|
|
1548
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1549
|
+
}
|
|
1550
|
+
} catch (e) {
|
|
1551
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1341
1552
|
}
|
|
1342
1553
|
}
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
return thumbnails;
|
|
1345
1557
|
}
|
|
1346
1558
|
};
|
|
1559
|
+
return instance;
|
|
1347
1560
|
}
|
|
1348
1561
|
};
|
|
1349
1562
|
function pdfPlugin() {
|
|
@@ -1670,7 +1883,31 @@ var DocxPlugin = class {
|
|
|
1670
1883
|
return this.mimeTypes.includes(mime || "");
|
|
1671
1884
|
}
|
|
1672
1885
|
getToolbarActions(instance) {
|
|
1673
|
-
|
|
1886
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1887
|
+
const actions = [];
|
|
1888
|
+
if (totalPages > 1) {
|
|
1889
|
+
actions.push({
|
|
1890
|
+
id: "page-nav",
|
|
1891
|
+
icon: "",
|
|
1892
|
+
label: "Page Navigation",
|
|
1893
|
+
type: "page-nav",
|
|
1894
|
+
group: "navigation",
|
|
1895
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1896
|
+
max: totalPages,
|
|
1897
|
+
execute: (action, page) => {
|
|
1898
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1899
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1900
|
+
if (action === "prev") {
|
|
1901
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1902
|
+
} else if (action === "next") {
|
|
1903
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1904
|
+
} else if (typeof page === "number") {
|
|
1905
|
+
instance.goToPage?.(page);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
actions.push(
|
|
1674
1911
|
{
|
|
1675
1912
|
id: "zoom-out",
|
|
1676
1913
|
icon: "zoom-out",
|
|
@@ -1695,6 +1932,14 @@ var DocxPlugin = class {
|
|
|
1695
1932
|
group: "zoom",
|
|
1696
1933
|
execute: () => instance.fitToPage?.()
|
|
1697
1934
|
},
|
|
1935
|
+
{
|
|
1936
|
+
id: "rotate-cw",
|
|
1937
|
+
icon: "rotate-cw",
|
|
1938
|
+
label: "Rotate",
|
|
1939
|
+
type: "button",
|
|
1940
|
+
group: "view",
|
|
1941
|
+
execute: () => instance.rotateCW?.()
|
|
1942
|
+
},
|
|
1698
1943
|
{
|
|
1699
1944
|
id: "download",
|
|
1700
1945
|
icon: "download",
|
|
@@ -1711,7 +1956,8 @@ var DocxPlugin = class {
|
|
|
1711
1956
|
group: "actions",
|
|
1712
1957
|
execute: () => instance.print?.()
|
|
1713
1958
|
}
|
|
1714
|
-
|
|
1959
|
+
);
|
|
1960
|
+
return actions;
|
|
1715
1961
|
}
|
|
1716
1962
|
async render(ctx) {
|
|
1717
1963
|
const wrapper = document.createElement("div");
|
|
@@ -1787,7 +2033,71 @@ var DocxPlugin = class {
|
|
|
1787
2033
|
}
|
|
1788
2034
|
}
|
|
1789
2035
|
}
|
|
2036
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2037
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2038
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2039
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2040
|
+
let currentPage = 1;
|
|
2041
|
+
let indicator = null;
|
|
2042
|
+
if (totalPages > 1) {
|
|
2043
|
+
indicator = document.createElement("div");
|
|
2044
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2045
|
+
indicator.style.position = "sticky";
|
|
2046
|
+
indicator.style.bottom = "16px";
|
|
2047
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2048
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2049
|
+
indicator.style.color = "#f8fafc";
|
|
2050
|
+
indicator.style.fontSize = "12px";
|
|
2051
|
+
indicator.style.fontWeight = "600";
|
|
2052
|
+
indicator.style.padding = "5px 14px";
|
|
2053
|
+
indicator.style.borderRadius = "20px";
|
|
2054
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2055
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2056
|
+
indicator.style.zIndex = "10";
|
|
2057
|
+
indicator.style.userSelect = "none";
|
|
2058
|
+
indicator.style.pointerEvents = "none";
|
|
2059
|
+
indicator.style.textAlign = "center";
|
|
2060
|
+
indicator.style.width = "fit-content";
|
|
2061
|
+
indicator.style.margin = "16px auto 0";
|
|
2062
|
+
ctx.container.appendChild(indicator);
|
|
2063
|
+
}
|
|
2064
|
+
const showPage = (pageNum) => {
|
|
2065
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2066
|
+
if (pageElements.length > 1) {
|
|
2067
|
+
pageElements.forEach((sec, idx) => {
|
|
2068
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2069
|
+
});
|
|
2070
|
+
}
|
|
2071
|
+
if (indicator) {
|
|
2072
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2073
|
+
}
|
|
2074
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2075
|
+
};
|
|
2076
|
+
if (totalPages > 1) {
|
|
2077
|
+
showPage(1);
|
|
2078
|
+
}
|
|
2079
|
+
scale = 1;
|
|
2080
|
+
let rotation = 0;
|
|
2081
|
+
const calculateFitScale = () => {
|
|
2082
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2083
|
+
const elW = activeEl.offsetWidth || 816;
|
|
2084
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2085
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
2086
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
2087
|
+
const sW = availW / elW;
|
|
2088
|
+
const sH = availH / elH;
|
|
2089
|
+
return Math.min(1.1, Math.min(sW, sH));
|
|
2090
|
+
};
|
|
2091
|
+
const applyTransform = () => {
|
|
2092
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2093
|
+
wrapper.style.transformOrigin = "top center";
|
|
2094
|
+
};
|
|
2095
|
+
setTimeout(() => {
|
|
2096
|
+
scale = calculateFitScale();
|
|
2097
|
+
applyTransform();
|
|
2098
|
+
}, 60);
|
|
1790
2099
|
const cleanup = () => {
|
|
2100
|
+
indicator?.remove();
|
|
1791
2101
|
for (const url of createdBlobUrls) {
|
|
1792
2102
|
URL.revokeObjectURL(url);
|
|
1793
2103
|
}
|
|
@@ -1798,22 +2108,36 @@ var DocxPlugin = class {
|
|
|
1798
2108
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1799
2109
|
return {
|
|
1800
2110
|
destroy: cleanup,
|
|
2111
|
+
getPageCount: () => totalPages,
|
|
2112
|
+
getCurrentPage: () => currentPage,
|
|
2113
|
+
goToPage: (page) => {
|
|
2114
|
+
showPage(page);
|
|
2115
|
+
},
|
|
1801
2116
|
zoomIn: () => {
|
|
1802
|
-
scale += 0.
|
|
1803
|
-
|
|
2117
|
+
scale += 0.15;
|
|
2118
|
+
applyTransform();
|
|
1804
2119
|
},
|
|
1805
2120
|
zoomOut: () => {
|
|
1806
|
-
scale = Math.max(0.2, scale - 0.
|
|
1807
|
-
|
|
2121
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2122
|
+
applyTransform();
|
|
1808
2123
|
},
|
|
1809
2124
|
getZoom: () => scale,
|
|
1810
2125
|
setZoom: (level) => {
|
|
1811
2126
|
scale = level;
|
|
1812
|
-
|
|
2127
|
+
applyTransform();
|
|
1813
2128
|
},
|
|
1814
2129
|
fitToPage: () => {
|
|
1815
|
-
scale =
|
|
1816
|
-
|
|
2130
|
+
scale = calculateFitScale();
|
|
2131
|
+
rotation = 0;
|
|
2132
|
+
applyTransform();
|
|
2133
|
+
},
|
|
2134
|
+
rotateCW: () => {
|
|
2135
|
+
rotation = (rotation + 90) % 360;
|
|
2136
|
+
applyTransform();
|
|
2137
|
+
},
|
|
2138
|
+
rotateCCW: () => {
|
|
2139
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2140
|
+
applyTransform();
|
|
1817
2141
|
},
|
|
1818
2142
|
download: () => {
|
|
1819
2143
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
@@ -2062,7 +2386,31 @@ var ExcelPlugin = class {
|
|
|
2062
2386
|
return this.mimeTypes.includes(mime || "");
|
|
2063
2387
|
}
|
|
2064
2388
|
getToolbarActions(instance) {
|
|
2065
|
-
|
|
2389
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2390
|
+
const actions = [];
|
|
2391
|
+
if (totalSheets > 1) {
|
|
2392
|
+
actions.push({
|
|
2393
|
+
id: "page-nav",
|
|
2394
|
+
icon: "",
|
|
2395
|
+
label: "Sheet Navigation",
|
|
2396
|
+
type: "page-nav",
|
|
2397
|
+
group: "navigation",
|
|
2398
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2399
|
+
max: totalSheets,
|
|
2400
|
+
execute: (action, sheet) => {
|
|
2401
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2402
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2403
|
+
if (action === "prev") {
|
|
2404
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2405
|
+
} else if (action === "next") {
|
|
2406
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2407
|
+
} else if (typeof sheet === "number") {
|
|
2408
|
+
instance.goToPage?.(sheet);
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
});
|
|
2412
|
+
}
|
|
2413
|
+
actions.push(
|
|
2066
2414
|
{
|
|
2067
2415
|
id: "zoom-out",
|
|
2068
2416
|
icon: "zoom-out",
|
|
@@ -2084,13 +2432,23 @@ var ExcelPlugin = class {
|
|
|
2084
2432
|
}
|
|
2085
2433
|
},
|
|
2086
2434
|
{
|
|
2087
|
-
id: "page
|
|
2088
|
-
icon: "page
|
|
2089
|
-
label: "
|
|
2090
|
-
type: "
|
|
2091
|
-
group: "
|
|
2092
|
-
execute: (
|
|
2093
|
-
|
|
2435
|
+
id: "fit-page",
|
|
2436
|
+
icon: "fit-page",
|
|
2437
|
+
label: "Fit to View",
|
|
2438
|
+
type: "button",
|
|
2439
|
+
group: "zoom",
|
|
2440
|
+
execute: () => {
|
|
2441
|
+
instance.fitToPage?.();
|
|
2442
|
+
}
|
|
2443
|
+
},
|
|
2444
|
+
{
|
|
2445
|
+
id: "rotate-cw",
|
|
2446
|
+
icon: "rotate-cw",
|
|
2447
|
+
label: "Rotate",
|
|
2448
|
+
type: "button",
|
|
2449
|
+
group: "view",
|
|
2450
|
+
execute: () => {
|
|
2451
|
+
instance.rotateCW?.();
|
|
2094
2452
|
}
|
|
2095
2453
|
},
|
|
2096
2454
|
{
|
|
@@ -2113,7 +2471,8 @@ var ExcelPlugin = class {
|
|
|
2113
2471
|
instance.print?.();
|
|
2114
2472
|
}
|
|
2115
2473
|
}
|
|
2116
|
-
|
|
2474
|
+
);
|
|
2475
|
+
return actions;
|
|
2117
2476
|
}
|
|
2118
2477
|
async render(ctx) {
|
|
2119
2478
|
const container = document.createElement("div");
|
|
@@ -2142,9 +2501,23 @@ var ExcelPlugin = class {
|
|
|
2142
2501
|
container.appendChild(tabsArea);
|
|
2143
2502
|
ctx.container.appendChild(container);
|
|
2144
2503
|
let scale = 1;
|
|
2504
|
+
let rotation = 0;
|
|
2145
2505
|
let currentSheetIndex = 1;
|
|
2146
2506
|
let sheetNames = [];
|
|
2147
2507
|
let wb = null;
|
|
2508
|
+
const applyTransform = () => {
|
|
2509
|
+
contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2510
|
+
contentArea.style.transformOrigin = "top left";
|
|
2511
|
+
};
|
|
2512
|
+
const calculateFitScale = () => {
|
|
2513
|
+
const table = contentArea.querySelector("table");
|
|
2514
|
+
if (!table) return 1;
|
|
2515
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
2516
|
+
const availH = Math.max(200, container.clientHeight - 80);
|
|
2517
|
+
const tW = table.offsetWidth || 800;
|
|
2518
|
+
const tH = table.offsetHeight || 600;
|
|
2519
|
+
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2520
|
+
};
|
|
2148
2521
|
try {
|
|
2149
2522
|
wb = XLSX.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
2150
2523
|
sheetNames = wb.SheetNames || [];
|
|
@@ -2197,6 +2570,7 @@ var ExcelPlugin = class {
|
|
|
2197
2570
|
b.style.fontWeight = "normal";
|
|
2198
2571
|
}
|
|
2199
2572
|
});
|
|
2573
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2200
2574
|
};
|
|
2201
2575
|
if (sheetNames.length > 0) {
|
|
2202
2576
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2231,17 +2605,30 @@ var ExcelPlugin = class {
|
|
|
2231
2605
|
return {
|
|
2232
2606
|
destroy: cleanup,
|
|
2233
2607
|
zoomIn: () => {
|
|
2234
|
-
scale += 0.
|
|
2235
|
-
|
|
2608
|
+
scale += 0.15;
|
|
2609
|
+
applyTransform();
|
|
2236
2610
|
},
|
|
2237
2611
|
zoomOut: () => {
|
|
2238
|
-
scale = Math.max(0.2, scale - 0.
|
|
2239
|
-
|
|
2612
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2613
|
+
applyTransform();
|
|
2240
2614
|
},
|
|
2241
2615
|
getZoom: () => scale,
|
|
2242
2616
|
setZoom: (level) => {
|
|
2243
2617
|
scale = level;
|
|
2244
|
-
|
|
2618
|
+
applyTransform();
|
|
2619
|
+
},
|
|
2620
|
+
fitToPage: () => {
|
|
2621
|
+
scale = calculateFitScale();
|
|
2622
|
+
rotation = 0;
|
|
2623
|
+
applyTransform();
|
|
2624
|
+
},
|
|
2625
|
+
rotateCW: () => {
|
|
2626
|
+
rotation = (rotation + 90) % 360;
|
|
2627
|
+
applyTransform();
|
|
2628
|
+
},
|
|
2629
|
+
rotateCCW: () => {
|
|
2630
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2631
|
+
applyTransform();
|
|
2245
2632
|
},
|
|
2246
2633
|
goToPage: (page) => {
|
|
2247
2634
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -2446,7 +2833,31 @@ var CodePlugin = class {
|
|
|
2446
2833
|
return false;
|
|
2447
2834
|
}
|
|
2448
2835
|
getToolbarActions(instance) {
|
|
2449
|
-
|
|
2836
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2837
|
+
const actions = [];
|
|
2838
|
+
if (totalPages > 1) {
|
|
2839
|
+
actions.push({
|
|
2840
|
+
id: "page-nav",
|
|
2841
|
+
icon: "",
|
|
2842
|
+
label: "Page Navigation",
|
|
2843
|
+
type: "page-nav",
|
|
2844
|
+
group: "navigation",
|
|
2845
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2846
|
+
max: totalPages,
|
|
2847
|
+
execute: (action, page) => {
|
|
2848
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2849
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2850
|
+
if (action === "prev") {
|
|
2851
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2852
|
+
} else if (action === "next") {
|
|
2853
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2854
|
+
} else if (typeof page === "number") {
|
|
2855
|
+
instance.goToPage?.(page);
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
});
|
|
2859
|
+
}
|
|
2860
|
+
actions.push(
|
|
2450
2861
|
{
|
|
2451
2862
|
id: "zoom-out",
|
|
2452
2863
|
icon: "zoom-out",
|
|
@@ -2467,6 +2878,26 @@ var CodePlugin = class {
|
|
|
2467
2878
|
instance.zoomIn?.();
|
|
2468
2879
|
}
|
|
2469
2880
|
},
|
|
2881
|
+
{
|
|
2882
|
+
id: "fit-page",
|
|
2883
|
+
icon: "fit-page",
|
|
2884
|
+
label: "Fit to View",
|
|
2885
|
+
type: "button",
|
|
2886
|
+
group: "zoom",
|
|
2887
|
+
execute: () => {
|
|
2888
|
+
instance.fitToPage?.();
|
|
2889
|
+
}
|
|
2890
|
+
},
|
|
2891
|
+
{
|
|
2892
|
+
id: "rotate-cw",
|
|
2893
|
+
icon: "rotate-cw",
|
|
2894
|
+
label: "Rotate",
|
|
2895
|
+
type: "button",
|
|
2896
|
+
group: "view",
|
|
2897
|
+
execute: () => {
|
|
2898
|
+
instance.rotateCW?.();
|
|
2899
|
+
}
|
|
2900
|
+
},
|
|
2470
2901
|
{
|
|
2471
2902
|
id: "copy",
|
|
2472
2903
|
icon: "copy",
|
|
@@ -2497,11 +2928,16 @@ var CodePlugin = class {
|
|
|
2497
2928
|
instance.print?.();
|
|
2498
2929
|
}
|
|
2499
2930
|
}
|
|
2500
|
-
|
|
2931
|
+
);
|
|
2932
|
+
return actions;
|
|
2501
2933
|
}
|
|
2502
2934
|
async render(ctx) {
|
|
2503
2935
|
const decoder = new TextDecoder("utf-8");
|
|
2504
|
-
const
|
|
2936
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
2937
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
2938
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2939
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
2940
|
+
let currentPage = 1;
|
|
2505
2941
|
const container = document.createElement("div");
|
|
2506
2942
|
container.style.width = "100%";
|
|
2507
2943
|
container.style.height = "100%";
|
|
@@ -2511,6 +2947,7 @@ var CodePlugin = class {
|
|
|
2511
2947
|
container.style.padding = "16px";
|
|
2512
2948
|
container.style.boxSizing = "border-box";
|
|
2513
2949
|
let fontSize = 13;
|
|
2950
|
+
let rotation = 0;
|
|
2514
2951
|
const pre = document.createElement("pre");
|
|
2515
2952
|
pre.style.margin = "0";
|
|
2516
2953
|
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
@@ -2520,25 +2957,66 @@ var CodePlugin = class {
|
|
|
2520
2957
|
pre.style.wordBreak = "break-all";
|
|
2521
2958
|
const code = document.createElement("code");
|
|
2522
2959
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2960
|
+
const renderCodePage = (text) => {
|
|
2961
|
+
try {
|
|
2962
|
+
if (ext && hljs.getLanguage(ext)) {
|
|
2963
|
+
code.innerHTML = hljs.highlight(text, { language: ext }).value;
|
|
2964
|
+
} else {
|
|
2965
|
+
code.innerHTML = hljs.highlightAuto(text).value;
|
|
2966
|
+
}
|
|
2967
|
+
} catch {
|
|
2968
|
+
code.textContent = text;
|
|
2528
2969
|
}
|
|
2529
|
-
}
|
|
2530
|
-
|
|
2531
|
-
}
|
|
2970
|
+
};
|
|
2971
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2532
2972
|
pre.appendChild(code);
|
|
2533
2973
|
container.appendChild(pre);
|
|
2974
|
+
let indicator = null;
|
|
2975
|
+
if (totalPages > 1) {
|
|
2976
|
+
indicator = document.createElement("div");
|
|
2977
|
+
indicator.className = "fp-code-page-indicator";
|
|
2978
|
+
indicator.style.position = "sticky";
|
|
2979
|
+
indicator.style.bottom = "16px";
|
|
2980
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2981
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2982
|
+
indicator.style.color = "#f8fafc";
|
|
2983
|
+
indicator.style.fontSize = "12px";
|
|
2984
|
+
indicator.style.fontWeight = "600";
|
|
2985
|
+
indicator.style.padding = "5px 14px";
|
|
2986
|
+
indicator.style.borderRadius = "20px";
|
|
2987
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2988
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2989
|
+
indicator.style.zIndex = "10";
|
|
2990
|
+
indicator.style.userSelect = "none";
|
|
2991
|
+
indicator.style.pointerEvents = "none";
|
|
2992
|
+
indicator.style.textAlign = "center";
|
|
2993
|
+
indicator.style.width = "fit-content";
|
|
2994
|
+
indicator.style.margin = "16px auto 0";
|
|
2995
|
+
container.appendChild(indicator);
|
|
2996
|
+
}
|
|
2997
|
+
const showPage = (pageNum) => {
|
|
2998
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2999
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3000
|
+
if (indicator) {
|
|
3001
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3002
|
+
}
|
|
3003
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3004
|
+
};
|
|
3005
|
+
if (totalPages > 1) {
|
|
3006
|
+
showPage(1);
|
|
3007
|
+
}
|
|
2534
3008
|
ctx.container.appendChild(container);
|
|
2535
3009
|
const cleanup = () => {
|
|
3010
|
+
indicator?.remove();
|
|
2536
3011
|
container.remove();
|
|
2537
3012
|
ctx.container.innerHTML = "";
|
|
2538
3013
|
};
|
|
2539
3014
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2540
3015
|
return {
|
|
2541
3016
|
destroy: cleanup,
|
|
3017
|
+
getPageCount: () => totalPages,
|
|
3018
|
+
getCurrentPage: () => currentPage,
|
|
3019
|
+
goToPage: (page) => showPage(page),
|
|
2542
3020
|
zoomIn: () => {
|
|
2543
3021
|
fontSize = Math.min(32, fontSize + 2);
|
|
2544
3022
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2552,6 +3030,22 @@ var CodePlugin = class {
|
|
|
2552
3030
|
fontSize = Math.round(13 * level);
|
|
2553
3031
|
pre.style.fontSize = `${fontSize}px`;
|
|
2554
3032
|
},
|
|
3033
|
+
fitToPage: () => {
|
|
3034
|
+
fontSize = 13;
|
|
3035
|
+
rotation = 0;
|
|
3036
|
+
pre.style.fontSize = "13px";
|
|
3037
|
+
pre.style.transform = "none";
|
|
3038
|
+
},
|
|
3039
|
+
rotateCW: () => {
|
|
3040
|
+
rotation = (rotation + 90) % 360;
|
|
3041
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3042
|
+
pre.style.transformOrigin = "top left";
|
|
3043
|
+
},
|
|
3044
|
+
rotateCCW: () => {
|
|
3045
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3046
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3047
|
+
pre.style.transformOrigin = "top left";
|
|
3048
|
+
},
|
|
2555
3049
|
download: () => {
|
|
2556
3050
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
2557
3051
|
const blob = new Blob([ctx.buffer], { type: mimeType });
|
|
@@ -2566,7 +3060,7 @@ var CodePlugin = class {
|
|
|
2566
3060
|
window.print();
|
|
2567
3061
|
},
|
|
2568
3062
|
copy: () => {
|
|
2569
|
-
navigator.clipboard?.writeText(
|
|
3063
|
+
navigator.clipboard?.writeText(fullText);
|
|
2570
3064
|
}
|
|
2571
3065
|
};
|
|
2572
3066
|
}
|
|
@@ -3063,6 +3557,14 @@ var PptxPlugin = class {
|
|
|
3063
3557
|
group: "zoom",
|
|
3064
3558
|
execute: () => instance.fitToPage?.()
|
|
3065
3559
|
},
|
|
3560
|
+
{
|
|
3561
|
+
id: "rotate-cw",
|
|
3562
|
+
icon: "rotate-cw",
|
|
3563
|
+
label: "Rotate",
|
|
3564
|
+
type: "button",
|
|
3565
|
+
group: "view",
|
|
3566
|
+
execute: () => instance.rotateCW?.()
|
|
3567
|
+
},
|
|
3066
3568
|
{
|
|
3067
3569
|
id: "download",
|
|
3068
3570
|
icon: "download",
|
|
@@ -3087,6 +3589,7 @@ var PptxPlugin = class {
|
|
|
3087
3589
|
const slideCount = renderer.slidePaths?.length || 1;
|
|
3088
3590
|
let currentSlide = 1;
|
|
3089
3591
|
let scale = 1;
|
|
3592
|
+
let rotation = 0;
|
|
3090
3593
|
const wrapper = document.createElement("div");
|
|
3091
3594
|
wrapper.className = "fp-pptx-wrapper";
|
|
3092
3595
|
wrapper.style.cssText = `
|
|
@@ -3109,6 +3612,8 @@ var PptxPlugin = class {
|
|
|
3109
3612
|
background: #ffffff;
|
|
3110
3613
|
transform-origin: top center;
|
|
3111
3614
|
transition: transform 0.2s ease;
|
|
3615
|
+
max-width: calc(100% - 32px);
|
|
3616
|
+
max-height: calc(100% - 48px);
|
|
3112
3617
|
`;
|
|
3113
3618
|
const canvas = document.createElement("canvas");
|
|
3114
3619
|
slideContainer.appendChild(canvas);
|
|
@@ -3116,10 +3621,22 @@ var PptxPlugin = class {
|
|
|
3116
3621
|
ctx.container.innerHTML = "";
|
|
3117
3622
|
ctx.container.style.overflow = "auto";
|
|
3118
3623
|
ctx.container.appendChild(wrapper);
|
|
3624
|
+
const calculateFitScale = () => {
|
|
3625
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
3626
|
+
const availH = Math.max(200, ctx.container.clientHeight - 72);
|
|
3627
|
+
const cW = canvas.offsetWidth || 1280;
|
|
3628
|
+
const cH = canvas.offsetHeight || 720;
|
|
3629
|
+
return Math.min(1, Math.min(availW / cW, availH / cH));
|
|
3630
|
+
};
|
|
3631
|
+
const applyTransform = () => {
|
|
3632
|
+
slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
3633
|
+
};
|
|
3119
3634
|
const renderCurrentSlide = async () => {
|
|
3120
3635
|
try {
|
|
3121
3636
|
await renderer.renderSlide(currentSlide - 1, canvas, 1280);
|
|
3122
3637
|
ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
|
|
3638
|
+
scale = calculateFitScale();
|
|
3639
|
+
applyTransform();
|
|
3123
3640
|
} catch (err) {
|
|
3124
3641
|
console.error("[PptxPlugin] Failed to render slide:", err);
|
|
3125
3642
|
}
|
|
@@ -3142,21 +3659,30 @@ var PptxPlugin = class {
|
|
|
3142
3659
|
getPageCount: () => slideCount,
|
|
3143
3660
|
getCurrentPage: () => currentSlide,
|
|
3144
3661
|
zoomIn: () => {
|
|
3145
|
-
scale += 0.
|
|
3146
|
-
|
|
3662
|
+
scale += 0.15;
|
|
3663
|
+
applyTransform();
|
|
3147
3664
|
},
|
|
3148
3665
|
zoomOut: () => {
|
|
3149
|
-
scale = Math.max(0.2, scale - 0.
|
|
3150
|
-
|
|
3666
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
3667
|
+
applyTransform();
|
|
3151
3668
|
},
|
|
3152
3669
|
getZoom: () => scale,
|
|
3153
3670
|
setZoom: (level) => {
|
|
3154
3671
|
scale = level;
|
|
3155
|
-
|
|
3672
|
+
applyTransform();
|
|
3156
3673
|
},
|
|
3157
3674
|
fitToPage: () => {
|
|
3158
|
-
scale =
|
|
3159
|
-
|
|
3675
|
+
scale = calculateFitScale();
|
|
3676
|
+
rotation = 0;
|
|
3677
|
+
applyTransform();
|
|
3678
|
+
},
|
|
3679
|
+
rotateCW: () => {
|
|
3680
|
+
rotation = (rotation + 90) % 360;
|
|
3681
|
+
applyTransform();
|
|
3682
|
+
},
|
|
3683
|
+
rotateCCW: () => {
|
|
3684
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3685
|
+
applyTransform();
|
|
3160
3686
|
},
|
|
3161
3687
|
getThumbnails: () => {
|
|
3162
3688
|
const list = [];
|
|
@@ -3388,7 +3914,31 @@ var RtfPlugin = class {
|
|
|
3388
3914
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3389
3915
|
}
|
|
3390
3916
|
getToolbarActions(instance) {
|
|
3391
|
-
|
|
3917
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3918
|
+
const actions = [];
|
|
3919
|
+
if (totalPages > 1) {
|
|
3920
|
+
actions.push({
|
|
3921
|
+
id: "page-nav",
|
|
3922
|
+
icon: "",
|
|
3923
|
+
label: "Page Navigation",
|
|
3924
|
+
type: "page-nav",
|
|
3925
|
+
group: "navigation",
|
|
3926
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3927
|
+
max: totalPages,
|
|
3928
|
+
execute: (action, page) => {
|
|
3929
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3930
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3931
|
+
if (action === "prev") {
|
|
3932
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3933
|
+
} else if (action === "next") {
|
|
3934
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3935
|
+
} else if (typeof page === "number") {
|
|
3936
|
+
instance.goToPage?.(page);
|
|
3937
|
+
}
|
|
3938
|
+
}
|
|
3939
|
+
});
|
|
3940
|
+
}
|
|
3941
|
+
actions.push(
|
|
3392
3942
|
{
|
|
3393
3943
|
id: "zoom-out",
|
|
3394
3944
|
icon: "zoom-out",
|
|
@@ -3413,6 +3963,14 @@ var RtfPlugin = class {
|
|
|
3413
3963
|
group: "zoom",
|
|
3414
3964
|
execute: () => instance.fitToPage?.()
|
|
3415
3965
|
},
|
|
3966
|
+
{
|
|
3967
|
+
id: "rotate-cw",
|
|
3968
|
+
icon: "rotate-cw",
|
|
3969
|
+
label: "Rotate",
|
|
3970
|
+
type: "button",
|
|
3971
|
+
group: "view",
|
|
3972
|
+
execute: () => instance.rotateCW?.()
|
|
3973
|
+
},
|
|
3416
3974
|
{
|
|
3417
3975
|
id: "download",
|
|
3418
3976
|
icon: "download",
|
|
@@ -3429,7 +3987,8 @@ var RtfPlugin = class {
|
|
|
3429
3987
|
group: "actions",
|
|
3430
3988
|
execute: () => instance.print?.()
|
|
3431
3989
|
}
|
|
3432
|
-
|
|
3990
|
+
);
|
|
3991
|
+
return actions;
|
|
3433
3992
|
}
|
|
3434
3993
|
async render(ctx) {
|
|
3435
3994
|
const wrapper = document.createElement("div");
|
|
@@ -3448,44 +4007,124 @@ var RtfPlugin = class {
|
|
|
3448
4007
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3449
4008
|
ctx.container.appendChild(wrapper);
|
|
3450
4009
|
let scale = 1;
|
|
4010
|
+
let rotation = 0;
|
|
4011
|
+
let pageElements = [];
|
|
4012
|
+
const calculateFitScale = () => {
|
|
4013
|
+
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4014
|
+
const elW = activeEl.offsetWidth || 850;
|
|
4015
|
+
const elH = activeEl.offsetHeight || 1e3;
|
|
4016
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4017
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4018
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4019
|
+
};
|
|
4020
|
+
const applyTransform = () => {
|
|
4021
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4022
|
+
wrapper.style.transformOrigin = "top center";
|
|
4023
|
+
};
|
|
4024
|
+
setTimeout(() => {
|
|
4025
|
+
scale = calculateFitScale();
|
|
4026
|
+
applyTransform();
|
|
4027
|
+
}, 60);
|
|
3451
4028
|
try {
|
|
3452
4029
|
if (typeof RTFJS.loggingEnabled === "function") {
|
|
3453
4030
|
RTFJS.loggingEnabled(false);
|
|
3454
4031
|
}
|
|
3455
4032
|
const doc = new RTFJS.Document(ctx.buffer, {});
|
|
3456
4033
|
const htmlElements = await doc.render();
|
|
3457
|
-
|
|
4034
|
+
pageElements = htmlElements;
|
|
4035
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
4036
|
+
const el = htmlElements[i];
|
|
4037
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3458
4038
|
wrapper.appendChild(el);
|
|
3459
4039
|
}
|
|
3460
4040
|
} catch (err) {
|
|
3461
4041
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3462
4042
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3463
4043
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3464
|
-
|
|
4044
|
+
const pre = document.createElement("pre");
|
|
4045
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
4046
|
+
pre.style.fontFamily = "serif";
|
|
4047
|
+
pre.style.color = "#333";
|
|
4048
|
+
pre.textContent = clean;
|
|
4049
|
+
wrapper.appendChild(pre);
|
|
4050
|
+
pageElements = [pre];
|
|
4051
|
+
}
|
|
4052
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
4053
|
+
let currentPage = 1;
|
|
4054
|
+
let indicator = null;
|
|
4055
|
+
if (totalPages > 1) {
|
|
4056
|
+
indicator = document.createElement("div");
|
|
4057
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
4058
|
+
indicator.style.position = "sticky";
|
|
4059
|
+
indicator.style.bottom = "16px";
|
|
4060
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4061
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4062
|
+
indicator.style.color = "#f8fafc";
|
|
4063
|
+
indicator.style.fontSize = "12px";
|
|
4064
|
+
indicator.style.fontWeight = "600";
|
|
4065
|
+
indicator.style.padding = "5px 14px";
|
|
4066
|
+
indicator.style.borderRadius = "20px";
|
|
4067
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4068
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4069
|
+
indicator.style.zIndex = "10";
|
|
4070
|
+
indicator.style.userSelect = "none";
|
|
4071
|
+
indicator.style.pointerEvents = "none";
|
|
4072
|
+
indicator.style.textAlign = "center";
|
|
4073
|
+
indicator.style.width = "fit-content";
|
|
4074
|
+
indicator.style.margin = "16px auto 0";
|
|
4075
|
+
ctx.container.appendChild(indicator);
|
|
4076
|
+
}
|
|
4077
|
+
const showPage = (pageNum) => {
|
|
4078
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4079
|
+
if (totalPages > 1) {
|
|
4080
|
+
pageElements.forEach((el, idx) => {
|
|
4081
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4082
|
+
});
|
|
4083
|
+
}
|
|
4084
|
+
if (indicator) {
|
|
4085
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4086
|
+
}
|
|
4087
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4088
|
+
};
|
|
4089
|
+
if (totalPages > 1) {
|
|
4090
|
+
showPage(1);
|
|
3465
4091
|
}
|
|
3466
4092
|
const cleanup = () => {
|
|
4093
|
+
indicator?.remove();
|
|
3467
4094
|
wrapper.remove();
|
|
3468
4095
|
ctx.container.innerHTML = "";
|
|
3469
4096
|
};
|
|
3470
4097
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3471
4098
|
return {
|
|
3472
4099
|
destroy: cleanup,
|
|
4100
|
+
getPageCount: () => totalPages,
|
|
4101
|
+
getCurrentPage: () => currentPage,
|
|
4102
|
+
goToPage: (page) => showPage(page),
|
|
3473
4103
|
zoomIn: () => {
|
|
3474
|
-
scale += 0.
|
|
3475
|
-
|
|
4104
|
+
scale += 0.15;
|
|
4105
|
+
applyTransform();
|
|
3476
4106
|
},
|
|
3477
4107
|
zoomOut: () => {
|
|
3478
|
-
scale = Math.max(0.2, scale - 0.
|
|
3479
|
-
|
|
4108
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4109
|
+
applyTransform();
|
|
3480
4110
|
},
|
|
3481
4111
|
getZoom: () => scale,
|
|
3482
4112
|
setZoom: (level) => {
|
|
3483
4113
|
scale = level;
|
|
3484
|
-
|
|
4114
|
+
applyTransform();
|
|
3485
4115
|
},
|
|
3486
4116
|
fitToPage: () => {
|
|
3487
|
-
scale =
|
|
3488
|
-
|
|
4117
|
+
scale = calculateFitScale();
|
|
4118
|
+
rotation = 0;
|
|
4119
|
+
applyTransform();
|
|
4120
|
+
},
|
|
4121
|
+
rotateCW: () => {
|
|
4122
|
+
rotation = (rotation + 90) % 360;
|
|
4123
|
+
applyTransform();
|
|
4124
|
+
},
|
|
4125
|
+
rotateCCW: () => {
|
|
4126
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4127
|
+
applyTransform();
|
|
3489
4128
|
},
|
|
3490
4129
|
download: () => {
|
|
3491
4130
|
const blob = new Blob([ctx.buffer], { type: "application/rtf" });
|
|
@@ -3657,41 +4296,41 @@ var OpenDocumentPlugin = class {
|
|
|
3657
4296
|
}
|
|
3658
4297
|
getToolbarActions(instance) {
|
|
3659
4298
|
const isPresentation = instance.isPresentation;
|
|
4299
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3660
4300
|
const actions = [];
|
|
3661
|
-
if (isPresentation) {
|
|
3662
|
-
|
|
3663
|
-
{
|
|
4301
|
+
if (isPresentation || totalPages > 1) {
|
|
4302
|
+
if (isPresentation) {
|
|
4303
|
+
actions.push({
|
|
3664
4304
|
id: "thumbnails",
|
|
3665
4305
|
icon: "thumbnails",
|
|
3666
4306
|
label: "Slide Thumbnails",
|
|
3667
4307
|
type: "button",
|
|
3668
4308
|
group: "navigation",
|
|
3669
4309
|
execute: () => instance.toggleThumbnails?.()
|
|
3670
|
-
}
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
}
|
|
4310
|
+
});
|
|
4311
|
+
}
|
|
4312
|
+
actions.push({
|
|
4313
|
+
id: "page-nav",
|
|
4314
|
+
icon: "",
|
|
4315
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4316
|
+
type: "page-nav",
|
|
4317
|
+
group: "navigation",
|
|
4318
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4319
|
+
max: totalPages,
|
|
4320
|
+
execute: (action, page) => {
|
|
4321
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4322
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4323
|
+
if (action === "prev") {
|
|
4324
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4325
|
+
} else if (action === "next") {
|
|
4326
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4327
|
+
} else if (typeof page === "number") {
|
|
4328
|
+
instance.goToPage?.(page);
|
|
4329
|
+
} else if (typeof action === "number") {
|
|
4330
|
+
instance.goToPage?.(action);
|
|
3692
4331
|
}
|
|
3693
4332
|
}
|
|
3694
|
-
);
|
|
4333
|
+
});
|
|
3695
4334
|
}
|
|
3696
4335
|
actions.push(
|
|
3697
4336
|
{
|
|
@@ -3713,11 +4352,19 @@ var OpenDocumentPlugin = class {
|
|
|
3713
4352
|
{
|
|
3714
4353
|
id: "fit-page",
|
|
3715
4354
|
icon: "fit-page",
|
|
3716
|
-
label: "Fit to Page",
|
|
4355
|
+
label: isPresentation ? "Fit to Slide" : "Fit to Page",
|
|
3717
4356
|
type: "button",
|
|
3718
4357
|
group: "zoom",
|
|
3719
4358
|
execute: () => instance.fitToPage?.()
|
|
3720
4359
|
},
|
|
4360
|
+
{
|
|
4361
|
+
id: "rotate-cw",
|
|
4362
|
+
icon: "rotate-cw",
|
|
4363
|
+
label: "Rotate",
|
|
4364
|
+
type: "button",
|
|
4365
|
+
group: "view",
|
|
4366
|
+
execute: () => instance.rotateCW?.()
|
|
4367
|
+
},
|
|
3721
4368
|
{
|
|
3722
4369
|
id: "download",
|
|
3723
4370
|
icon: "download",
|
|
@@ -3781,6 +4428,22 @@ var OpenDocumentPlugin = class {
|
|
|
3781
4428
|
container.appendChild(wrapper);
|
|
3782
4429
|
ctx.container.appendChild(container);
|
|
3783
4430
|
let scale = 1;
|
|
4431
|
+
let rotation = 0;
|
|
4432
|
+
const calculateFitScale = () => {
|
|
4433
|
+
const elW = wrapper.offsetWidth || 850;
|
|
4434
|
+
const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
|
|
4435
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4436
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4437
|
+
return Math.min(1, Math.min(availW / elW, availH / elH));
|
|
4438
|
+
};
|
|
4439
|
+
const applyTransform = () => {
|
|
4440
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4441
|
+
wrapper.style.transformOrigin = "top center";
|
|
4442
|
+
};
|
|
4443
|
+
setTimeout(() => {
|
|
4444
|
+
scale = calculateFitScale();
|
|
4445
|
+
applyTransform();
|
|
4446
|
+
}, 60);
|
|
3784
4447
|
let currentPage = 1;
|
|
3785
4448
|
let totalPages = 1;
|
|
3786
4449
|
let slides = [];
|
|
@@ -3839,21 +4502,30 @@ var OpenDocumentPlugin = class {
|
|
|
3839
4502
|
destroy: cleanup,
|
|
3840
4503
|
isPresentation,
|
|
3841
4504
|
zoomIn: () => {
|
|
3842
|
-
scale += 0.
|
|
3843
|
-
|
|
4505
|
+
scale += 0.15;
|
|
4506
|
+
applyTransform();
|
|
3844
4507
|
},
|
|
3845
4508
|
zoomOut: () => {
|
|
3846
|
-
scale = Math.max(0.2, scale - 0.
|
|
3847
|
-
|
|
4509
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4510
|
+
applyTransform();
|
|
3848
4511
|
},
|
|
3849
4512
|
getZoom: () => scale,
|
|
3850
4513
|
setZoom: (level) => {
|
|
3851
4514
|
scale = level;
|
|
3852
|
-
|
|
4515
|
+
applyTransform();
|
|
3853
4516
|
},
|
|
3854
4517
|
fitToPage: () => {
|
|
3855
|
-
scale =
|
|
3856
|
-
|
|
4518
|
+
scale = calculateFitScale();
|
|
4519
|
+
rotation = 0;
|
|
4520
|
+
applyTransform();
|
|
4521
|
+
},
|
|
4522
|
+
rotateCW: () => {
|
|
4523
|
+
rotation = (rotation + 90) % 360;
|
|
4524
|
+
applyTransform();
|
|
4525
|
+
},
|
|
4526
|
+
rotateCCW: () => {
|
|
4527
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4528
|
+
applyTransform();
|
|
3857
4529
|
},
|
|
3858
4530
|
goToPage,
|
|
3859
4531
|
getPageCount: () => totalPages,
|
|
@@ -4074,7 +4746,31 @@ var DocPlugin = class {
|
|
|
4074
4746
|
return this.mimeTypes.includes(mime || "");
|
|
4075
4747
|
}
|
|
4076
4748
|
getToolbarActions(instance) {
|
|
4077
|
-
|
|
4749
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4750
|
+
const actions = [];
|
|
4751
|
+
if (totalPages > 1) {
|
|
4752
|
+
actions.push({
|
|
4753
|
+
id: "page-nav",
|
|
4754
|
+
icon: "",
|
|
4755
|
+
label: "Page Navigation",
|
|
4756
|
+
type: "page-nav",
|
|
4757
|
+
group: "navigation",
|
|
4758
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4759
|
+
max: totalPages,
|
|
4760
|
+
execute: (action, page) => {
|
|
4761
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4762
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4763
|
+
if (action === "prev") {
|
|
4764
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4765
|
+
} else if (action === "next") {
|
|
4766
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4767
|
+
} else if (typeof page === "number") {
|
|
4768
|
+
instance.goToPage?.(page);
|
|
4769
|
+
}
|
|
4770
|
+
}
|
|
4771
|
+
});
|
|
4772
|
+
}
|
|
4773
|
+
actions.push(
|
|
4078
4774
|
{
|
|
4079
4775
|
id: "zoom-out",
|
|
4080
4776
|
icon: "zoom-out",
|
|
@@ -4099,6 +4795,14 @@ var DocPlugin = class {
|
|
|
4099
4795
|
group: "zoom",
|
|
4100
4796
|
execute: () => instance.fitToPage?.()
|
|
4101
4797
|
},
|
|
4798
|
+
{
|
|
4799
|
+
id: "rotate-cw",
|
|
4800
|
+
icon: "rotate-cw",
|
|
4801
|
+
label: "Rotate",
|
|
4802
|
+
type: "button",
|
|
4803
|
+
group: "view",
|
|
4804
|
+
execute: () => instance.rotateCW?.()
|
|
4805
|
+
},
|
|
4102
4806
|
{
|
|
4103
4807
|
id: "copy",
|
|
4104
4808
|
icon: "copy",
|
|
@@ -4123,7 +4827,8 @@ var DocPlugin = class {
|
|
|
4123
4827
|
group: "actions",
|
|
4124
4828
|
execute: () => instance.print?.()
|
|
4125
4829
|
}
|
|
4126
|
-
|
|
4830
|
+
);
|
|
4831
|
+
return actions;
|
|
4127
4832
|
}
|
|
4128
4833
|
async render(ctx) {
|
|
4129
4834
|
const container = document.createElement("div");
|
|
@@ -4150,6 +4855,7 @@ var DocPlugin = class {
|
|
|
4150
4855
|
ctx.container.appendChild(container);
|
|
4151
4856
|
let scale = 1;
|
|
4152
4857
|
let extractedRawText = "";
|
|
4858
|
+
let isFallback = false;
|
|
4153
4859
|
try {
|
|
4154
4860
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4155
4861
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4163,42 +4869,131 @@ var DocPlugin = class {
|
|
|
4163
4869
|
const tableStream = cfbf.readStream(tableName);
|
|
4164
4870
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4165
4871
|
extractedRawText = text;
|
|
4166
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4167
4872
|
} catch (err) {
|
|
4168
4873
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4169
4874
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4170
4875
|
extractedRawText = fallback;
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4876
|
+
isFallback = true;
|
|
4877
|
+
}
|
|
4878
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4879
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4880
|
+
let currentPage = 1;
|
|
4881
|
+
wrapper.innerHTML = "";
|
|
4882
|
+
const pageCards = [];
|
|
4883
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4884
|
+
const pageCard = document.createElement("div");
|
|
4885
|
+
pageCard.className = "fp-doc-page-card";
|
|
4886
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4887
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4888
|
+
pageCard.style.borderRadius = "4px";
|
|
4889
|
+
pageCard.style.padding = "56px 48px";
|
|
4890
|
+
pageCard.style.minHeight = "100%";
|
|
4891
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4892
|
+
if (isFallback && i === 0) {
|
|
4893
|
+
pageCard.innerHTML = `
|
|
4894
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4895
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4896
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4897
|
+
</div>
|
|
4898
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4899
|
+
`;
|
|
4900
|
+
} else {
|
|
4901
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4902
|
+
}
|
|
4903
|
+
wrapper.appendChild(pageCard);
|
|
4904
|
+
pageCards.push(pageCard);
|
|
4905
|
+
}
|
|
4906
|
+
let indicator = null;
|
|
4907
|
+
if (totalPages > 1) {
|
|
4908
|
+
indicator = document.createElement("div");
|
|
4909
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4910
|
+
indicator.style.position = "sticky";
|
|
4911
|
+
indicator.style.bottom = "16px";
|
|
4912
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4913
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4914
|
+
indicator.style.color = "#f8fafc";
|
|
4915
|
+
indicator.style.fontSize = "12px";
|
|
4916
|
+
indicator.style.fontWeight = "600";
|
|
4917
|
+
indicator.style.padding = "5px 14px";
|
|
4918
|
+
indicator.style.borderRadius = "20px";
|
|
4919
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4920
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4921
|
+
indicator.style.zIndex = "10";
|
|
4922
|
+
indicator.style.userSelect = "none";
|
|
4923
|
+
indicator.style.pointerEvents = "none";
|
|
4924
|
+
indicator.style.textAlign = "center";
|
|
4925
|
+
indicator.style.width = "fit-content";
|
|
4926
|
+
indicator.style.margin = "16px auto 0";
|
|
4927
|
+
container.appendChild(indicator);
|
|
4928
|
+
}
|
|
4929
|
+
const showPage = (pageNum) => {
|
|
4930
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4931
|
+
if (totalPages > 1) {
|
|
4932
|
+
pageCards.forEach((card, idx) => {
|
|
4933
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4934
|
+
});
|
|
4935
|
+
}
|
|
4936
|
+
if (indicator) {
|
|
4937
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4938
|
+
}
|
|
4939
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4940
|
+
};
|
|
4941
|
+
if (totalPages > 1) {
|
|
4942
|
+
showPage(1);
|
|
4178
4943
|
}
|
|
4944
|
+
let rotation = 0;
|
|
4945
|
+
const calculateFitScale = () => {
|
|
4946
|
+
const activeCard = pageCards[currentPage - 1] || wrapper;
|
|
4947
|
+
const elW = activeCard.offsetWidth || 850;
|
|
4948
|
+
const elH = activeCard.offsetHeight || 1e3;
|
|
4949
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4950
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4951
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4952
|
+
};
|
|
4953
|
+
const applyTransform = () => {
|
|
4954
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4955
|
+
wrapper.style.transformOrigin = "top center";
|
|
4956
|
+
};
|
|
4957
|
+
setTimeout(() => {
|
|
4958
|
+
scale = calculateFitScale();
|
|
4959
|
+
applyTransform();
|
|
4960
|
+
}, 60);
|
|
4179
4961
|
const cleanup = () => {
|
|
4962
|
+
indicator?.remove();
|
|
4180
4963
|
container.remove();
|
|
4181
4964
|
ctx.container.innerHTML = "";
|
|
4182
4965
|
};
|
|
4183
4966
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4184
4967
|
return {
|
|
4185
4968
|
destroy: cleanup,
|
|
4969
|
+
getPageCount: () => totalPages,
|
|
4970
|
+
getCurrentPage: () => currentPage,
|
|
4971
|
+
goToPage: (page) => showPage(page),
|
|
4186
4972
|
zoomIn: () => {
|
|
4187
|
-
scale += 0.
|
|
4188
|
-
|
|
4973
|
+
scale += 0.15;
|
|
4974
|
+
applyTransform();
|
|
4189
4975
|
},
|
|
4190
4976
|
zoomOut: () => {
|
|
4191
|
-
scale = Math.max(0.2, scale - 0.
|
|
4192
|
-
|
|
4977
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4978
|
+
applyTransform();
|
|
4193
4979
|
},
|
|
4194
4980
|
getZoom: () => scale,
|
|
4195
4981
|
setZoom: (level) => {
|
|
4196
4982
|
scale = level;
|
|
4197
|
-
|
|
4983
|
+
applyTransform();
|
|
4198
4984
|
},
|
|
4199
4985
|
fitToPage: () => {
|
|
4200
|
-
scale =
|
|
4201
|
-
|
|
4986
|
+
scale = calculateFitScale();
|
|
4987
|
+
rotation = 0;
|
|
4988
|
+
applyTransform();
|
|
4989
|
+
},
|
|
4990
|
+
rotateCW: () => {
|
|
4991
|
+
rotation = (rotation + 90) % 360;
|
|
4992
|
+
applyTransform();
|
|
4993
|
+
},
|
|
4994
|
+
rotateCCW: () => {
|
|
4995
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4996
|
+
applyTransform();
|
|
4202
4997
|
},
|
|
4203
4998
|
copy: () => {
|
|
4204
4999
|
navigator.clipboard.writeText(extractedRawText);
|
|
@@ -4314,11 +5109,16 @@ var DocPlugin = class {
|
|
|
4314
5109
|
heuristicTextExtraction(buffer) {
|
|
4315
5110
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4316
5111
|
}
|
|
5112
|
+
splitIntoPages(text) {
|
|
5113
|
+
if (!text) return [""];
|
|
5114
|
+
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);
|
|
5115
|
+
return parts.length > 0 ? parts : [text];
|
|
5116
|
+
}
|
|
4317
5117
|
/**
|
|
4318
5118
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4319
5119
|
*/
|
|
4320
5120
|
formatDocToHtml(text, filename) {
|
|
4321
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
5121
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4322
5122
|
let html = "";
|
|
4323
5123
|
let inList = false;
|
|
4324
5124
|
for (const rawLine of lines) {
|
|
@@ -4433,6 +5233,14 @@ var PptPlugin = class {
|
|
|
4433
5233
|
group: "zoom",
|
|
4434
5234
|
execute: () => instance.fitToPage?.()
|
|
4435
5235
|
},
|
|
5236
|
+
{
|
|
5237
|
+
id: "rotate-cw",
|
|
5238
|
+
icon: "rotate-cw",
|
|
5239
|
+
label: "Rotate",
|
|
5240
|
+
type: "button",
|
|
5241
|
+
group: "view",
|
|
5242
|
+
execute: () => instance.rotateCW?.()
|
|
5243
|
+
},
|
|
4436
5244
|
{
|
|
4437
5245
|
id: "download",
|
|
4438
5246
|
icon: "download",
|
|
@@ -4466,22 +5274,36 @@ var PptPlugin = class {
|
|
|
4466
5274
|
const slideCard = document.createElement("div");
|
|
4467
5275
|
slideCard.className = "fp-ppt-slide-card";
|
|
4468
5276
|
slideCard.style.width = "960px";
|
|
4469
|
-
slideCard.style.maxWidth = "
|
|
5277
|
+
slideCard.style.maxWidth = "calc(100% - 32px)";
|
|
5278
|
+
slideCard.style.maxHeight = "calc(100% - 48px)";
|
|
4470
5279
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4471
5280
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4472
5281
|
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4473
5282
|
slideCard.style.borderRadius = "8px";
|
|
4474
5283
|
slideCard.style.boxSizing = "border-box";
|
|
4475
5284
|
slideCard.style.position = "relative";
|
|
4476
|
-
slideCard.style.overflow = "hidden";
|
|
4477
|
-
slideCard.style.transformOrigin = "center center";
|
|
4478
5285
|
slideCard.style.transition = "transform 0.2s ease";
|
|
5286
|
+
slideCard.style.transformOrigin = "center center";
|
|
5287
|
+
slideCard.style.flexShrink = "0";
|
|
4479
5288
|
container.appendChild(slideCard);
|
|
4480
5289
|
ctx.container.appendChild(container);
|
|
4481
5290
|
let scale = 1;
|
|
5291
|
+
let rotation = 0;
|
|
4482
5292
|
let currentSlide = 1;
|
|
4483
5293
|
let slides = [];
|
|
4484
5294
|
const createdBlobUrls = [];
|
|
5295
|
+
const calculateFitScale = () => {
|
|
5296
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
5297
|
+
const availH = Math.max(200, container.clientHeight - 72);
|
|
5298
|
+
return Math.min(1, Math.min(availW / 960, availH / 540));
|
|
5299
|
+
};
|
|
5300
|
+
const applyTransform = () => {
|
|
5301
|
+
slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5302
|
+
};
|
|
5303
|
+
setTimeout(() => {
|
|
5304
|
+
scale = calculateFitScale();
|
|
5305
|
+
applyTransform();
|
|
5306
|
+
}, 60);
|
|
4485
5307
|
try {
|
|
4486
5308
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4487
5309
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
@@ -4582,21 +5404,30 @@ var PptPlugin = class {
|
|
|
4582
5404
|
return {
|
|
4583
5405
|
destroy: cleanup,
|
|
4584
5406
|
zoomIn: () => {
|
|
4585
|
-
scale += 0.
|
|
4586
|
-
|
|
5407
|
+
scale += 0.15;
|
|
5408
|
+
applyTransform();
|
|
4587
5409
|
},
|
|
4588
5410
|
zoomOut: () => {
|
|
4589
|
-
scale = Math.max(0.
|
|
4590
|
-
|
|
5411
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5412
|
+
applyTransform();
|
|
4591
5413
|
},
|
|
4592
5414
|
getZoom: () => scale,
|
|
4593
5415
|
setZoom: (level) => {
|
|
4594
5416
|
scale = level;
|
|
4595
|
-
|
|
5417
|
+
applyTransform();
|
|
4596
5418
|
},
|
|
4597
5419
|
fitToPage: () => {
|
|
4598
|
-
scale =
|
|
4599
|
-
|
|
5420
|
+
scale = calculateFitScale();
|
|
5421
|
+
rotation = 0;
|
|
5422
|
+
applyTransform();
|
|
5423
|
+
},
|
|
5424
|
+
rotateCW: () => {
|
|
5425
|
+
rotation = (rotation + 90) % 360;
|
|
5426
|
+
applyTransform();
|
|
5427
|
+
},
|
|
5428
|
+
rotateCCW: () => {
|
|
5429
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5430
|
+
applyTransform();
|
|
4600
5431
|
},
|
|
4601
5432
|
goToPage: (page) => {
|
|
4602
5433
|
if (page >= 1 && page <= totalSlides) {
|