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