@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.cjs
CHANGED
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var DOMPurify2 = require('dompurify');
|
|
7
|
+
var pdfjsLib = require('pdfjs-dist');
|
|
7
8
|
var docx = require('docx-preview');
|
|
8
9
|
var fflate = require('fflate');
|
|
9
10
|
var XLSX = require('xlsx');
|
|
@@ -38,6 +39,7 @@ function _interopNamespace(e) {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
var DOMPurify2__default = /*#__PURE__*/_interopDefault(DOMPurify2);
|
|
42
|
+
var pdfjsLib__namespace = /*#__PURE__*/_interopNamespace(pdfjsLib);
|
|
41
43
|
var docx__namespace = /*#__PURE__*/_interopNamespace(docx);
|
|
42
44
|
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
43
45
|
var hljs__default = /*#__PURE__*/_interopDefault(hljs);
|
|
@@ -511,11 +513,21 @@ var ToolbarController = class {
|
|
|
511
513
|
el;
|
|
512
514
|
toolbarEl;
|
|
513
515
|
actions = [];
|
|
516
|
+
pageInputEl = null;
|
|
517
|
+
pageLabelEl = null;
|
|
514
518
|
constructor(container) {
|
|
515
519
|
this.el = container;
|
|
516
520
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
517
521
|
this.el.appendChild(this.toolbarEl);
|
|
518
522
|
}
|
|
523
|
+
setPage(page, max) {
|
|
524
|
+
if (this.pageInputEl) {
|
|
525
|
+
this.pageInputEl.value = page.toString();
|
|
526
|
+
}
|
|
527
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
528
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
519
531
|
update(actions) {
|
|
520
532
|
this.actions = actions;
|
|
521
533
|
this.render();
|
|
@@ -558,6 +570,7 @@ var ToolbarController = class {
|
|
|
558
570
|
if (action.type === "separator") {
|
|
559
571
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
560
572
|
} else if (action.type === "page-nav") {
|
|
573
|
+
const max = action.max ?? 1;
|
|
561
574
|
const prevBtn = this.createButton(
|
|
562
575
|
"prev",
|
|
563
576
|
ICON_PAGE_PREV,
|
|
@@ -576,7 +589,6 @@ var ToolbarController = class {
|
|
|
576
589
|
"Next Page",
|
|
577
590
|
() => {
|
|
578
591
|
const cur = parseInt(input.value, 10) || 1;
|
|
579
|
-
const max = action.max ?? 1;
|
|
580
592
|
if (cur < max) {
|
|
581
593
|
input.value = (cur + 1).toString();
|
|
582
594
|
action.execute("next", cur + 1);
|
|
@@ -588,15 +600,18 @@ var ToolbarController = class {
|
|
|
588
600
|
type: "number",
|
|
589
601
|
value: (action.value ?? 1).toString(),
|
|
590
602
|
min: "1",
|
|
591
|
-
max:
|
|
603
|
+
max: max.toString()
|
|
592
604
|
});
|
|
593
605
|
input.addEventListener("change", () => {
|
|
594
|
-
|
|
595
|
-
if (
|
|
596
|
-
|
|
597
|
-
|
|
606
|
+
let val = parseInt(input.value, 10);
|
|
607
|
+
if (isNaN(val)) val = 1;
|
|
608
|
+
val = Math.max(1, Math.min(max, val));
|
|
609
|
+
input.value = val.toString();
|
|
610
|
+
action.execute("go", val);
|
|
598
611
|
});
|
|
599
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
612
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
613
|
+
this.pageInputEl = input;
|
|
614
|
+
this.pageLabelEl = label;
|
|
600
615
|
groupEl.appendChild(prevBtn);
|
|
601
616
|
groupEl.appendChild(input);
|
|
602
617
|
groupEl.appendChild(label);
|
|
@@ -723,6 +738,8 @@ var FilePreviewViewer = class {
|
|
|
723
738
|
keyHandler = null;
|
|
724
739
|
currentContainer = null;
|
|
725
740
|
currentOptions = {};
|
|
741
|
+
resizeObserver = null;
|
|
742
|
+
fullscreenHandler = null;
|
|
726
743
|
/**
|
|
727
744
|
* Register a preview plugin.
|
|
728
745
|
*/
|
|
@@ -774,7 +791,13 @@ var FilePreviewViewer = class {
|
|
|
774
791
|
buffer,
|
|
775
792
|
options,
|
|
776
793
|
signal,
|
|
777
|
-
emit: (event, payload) =>
|
|
794
|
+
emit: (event, payload) => {
|
|
795
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
796
|
+
const total = payload.total ?? payload.totalPages;
|
|
797
|
+
this.toolbar?.setPage(payload.page, total);
|
|
798
|
+
}
|
|
799
|
+
this.eventEmitter.emit(event, payload);
|
|
800
|
+
}
|
|
778
801
|
});
|
|
779
802
|
this.activeInstance = instance;
|
|
780
803
|
this.hideLoading();
|
|
@@ -789,12 +812,31 @@ var FilePreviewViewer = class {
|
|
|
789
812
|
label: "Toggle Fullscreen",
|
|
790
813
|
type: "button",
|
|
791
814
|
group: "view",
|
|
792
|
-
execute: () => {
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
815
|
+
execute: async () => {
|
|
816
|
+
try {
|
|
817
|
+
const isNativeFs = !!document.fullscreenElement;
|
|
818
|
+
const isCssFs = this.wrapperEl?.classList.contains("fp-fullscreen-active");
|
|
819
|
+
if (!isNativeFs && !isCssFs) {
|
|
820
|
+
if (this.wrapperEl?.requestFullscreen) {
|
|
821
|
+
await this.wrapperEl.requestFullscreen().catch(() => {
|
|
822
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
823
|
+
});
|
|
824
|
+
} else {
|
|
825
|
+
this.wrapperEl?.classList.add("fp-fullscreen-active");
|
|
826
|
+
}
|
|
827
|
+
} else {
|
|
828
|
+
if (document.fullscreenElement) {
|
|
829
|
+
await document.exitFullscreen().catch(() => {
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
this.wrapperEl?.classList.remove("fp-fullscreen-active");
|
|
833
|
+
}
|
|
834
|
+
} catch {
|
|
835
|
+
this.wrapperEl?.classList.toggle("fp-fullscreen-active");
|
|
797
836
|
}
|
|
837
|
+
setTimeout(() => {
|
|
838
|
+
this.activeInstance?.fitToPage?.();
|
|
839
|
+
}, 120);
|
|
798
840
|
}
|
|
799
841
|
});
|
|
800
842
|
}
|
|
@@ -808,6 +850,7 @@ var FilePreviewViewer = class {
|
|
|
808
850
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
809
851
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
810
852
|
instance.goToPage?.(index + 1);
|
|
853
|
+
this.toolbar?.setPage(index + 1);
|
|
811
854
|
});
|
|
812
855
|
if (options.showThumbnails) {
|
|
813
856
|
this.thumbnailPanel.show();
|
|
@@ -843,6 +886,15 @@ var FilePreviewViewer = class {
|
|
|
843
886
|
window.removeEventListener("keydown", this.keyHandler);
|
|
844
887
|
this.keyHandler = null;
|
|
845
888
|
}
|
|
889
|
+
if (this.resizeObserver) {
|
|
890
|
+
this.resizeObserver.disconnect();
|
|
891
|
+
this.resizeObserver = null;
|
|
892
|
+
}
|
|
893
|
+
if (this.fullscreenHandler) {
|
|
894
|
+
document.removeEventListener("fullscreenchange", this.fullscreenHandler);
|
|
895
|
+
document.removeEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
896
|
+
this.fullscreenHandler = null;
|
|
897
|
+
}
|
|
846
898
|
this.abort();
|
|
847
899
|
this.destroyInstance();
|
|
848
900
|
this.toolbar?.destroy();
|
|
@@ -922,6 +974,25 @@ var FilePreviewViewer = class {
|
|
|
922
974
|
this.thumbnailPanel = new ThumbnailPanel(thumbnailEl);
|
|
923
975
|
this.setupKeyboardShortcuts();
|
|
924
976
|
this.setupDragAndDrop(container, options);
|
|
977
|
+
this.setupResizeAndFullscreenListeners();
|
|
978
|
+
}
|
|
979
|
+
setupResizeAndFullscreenListeners() {
|
|
980
|
+
if (this.fullscreenHandler) return;
|
|
981
|
+
this.fullscreenHandler = () => {
|
|
982
|
+
setTimeout(() => {
|
|
983
|
+
this.activeInstance?.fitToPage?.();
|
|
984
|
+
}, 100);
|
|
985
|
+
};
|
|
986
|
+
document.addEventListener("fullscreenchange", this.fullscreenHandler);
|
|
987
|
+
document.addEventListener("webkitfullscreenchange", this.fullscreenHandler);
|
|
988
|
+
if (typeof ResizeObserver !== "undefined" && this.contentEl) {
|
|
989
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
990
|
+
if (this.activeInstance && (!this.activeInstance.getZoom || Math.abs((this.activeInstance.getZoom?.() ?? 1) - 1) < 0.05)) {
|
|
991
|
+
this.activeInstance.fitToPage?.();
|
|
992
|
+
}
|
|
993
|
+
});
|
|
994
|
+
this.resizeObserver.observe(this.contentEl);
|
|
995
|
+
}
|
|
925
996
|
}
|
|
926
997
|
setupKeyboardShortcuts() {
|
|
927
998
|
if (this.keyHandler) return;
|
|
@@ -933,9 +1004,13 @@ var FilePreviewViewer = class {
|
|
|
933
1004
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
934
1005
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
935
1006
|
this.activeInstance.goToPage?.(cur + 1);
|
|
1007
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
1008
|
+
this.toolbar?.setPage(nextCur);
|
|
936
1009
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
937
1010
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
938
1011
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
1012
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
1013
|
+
this.toolbar?.setPage(prevCur);
|
|
939
1014
|
} else if (e.key === "+" || e.key === "=") {
|
|
940
1015
|
this.activeInstance.zoomIn?.();
|
|
941
1016
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1201,30 +1276,62 @@ var CfbfReader = class {
|
|
|
1201
1276
|
return result.subarray(0, targetSize);
|
|
1202
1277
|
}
|
|
1203
1278
|
};
|
|
1204
|
-
|
|
1205
|
-
|
|
1279
|
+
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1280
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1281
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1206
1284
|
var PdfPlugin = class {
|
|
1207
1285
|
id = "pdf";
|
|
1208
|
-
name = "PDF Preview";
|
|
1286
|
+
name = "PDF Document Preview";
|
|
1209
1287
|
extensions = [".pdf"];
|
|
1210
1288
|
mimeTypes = ["application/pdf"];
|
|
1211
1289
|
weight = 100;
|
|
1212
1290
|
supports(file) {
|
|
1213
1291
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1214
1292
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1215
|
-
|
|
1293
|
+
if (ext) return this.extensions.includes(ext);
|
|
1294
|
+
return this.mimeTypes.includes(mime || "");
|
|
1216
1295
|
}
|
|
1217
1296
|
getToolbarActions(instance) {
|
|
1297
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1298
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1218
1299
|
return [
|
|
1300
|
+
{
|
|
1301
|
+
id: "thumbnails",
|
|
1302
|
+
icon: "thumbnails",
|
|
1303
|
+
label: "Page Thumbnails",
|
|
1304
|
+
type: "button",
|
|
1305
|
+
group: "navigation",
|
|
1306
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1307
|
+
},
|
|
1308
|
+
{
|
|
1309
|
+
id: "page-nav",
|
|
1310
|
+
icon: "",
|
|
1311
|
+
label: "Page Navigation",
|
|
1312
|
+
type: "page-nav",
|
|
1313
|
+
group: "navigation",
|
|
1314
|
+
value: curPage,
|
|
1315
|
+
max: totalPages,
|
|
1316
|
+
execute: (action, page) => {
|
|
1317
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1318
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1319
|
+
if (action === "prev") {
|
|
1320
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1321
|
+
} else if (action === "next") {
|
|
1322
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1323
|
+
} else if (typeof page === "number") {
|
|
1324
|
+
instance.goToPage?.(page);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
},
|
|
1219
1328
|
{
|
|
1220
1329
|
id: "zoom-out",
|
|
1221
1330
|
icon: "zoom-out",
|
|
1222
1331
|
label: "Zoom Out",
|
|
1223
1332
|
type: "button",
|
|
1224
1333
|
group: "zoom",
|
|
1225
|
-
execute: () =>
|
|
1226
|
-
instance.zoomOut?.();
|
|
1227
|
-
}
|
|
1334
|
+
execute: () => instance.zoomOut?.()
|
|
1228
1335
|
},
|
|
1229
1336
|
{
|
|
1230
1337
|
id: "zoom-in",
|
|
@@ -1232,9 +1339,7 @@ var PdfPlugin = class {
|
|
|
1232
1339
|
label: "Zoom In",
|
|
1233
1340
|
type: "button",
|
|
1234
1341
|
group: "zoom",
|
|
1235
|
-
execute: () =>
|
|
1236
|
-
instance.zoomIn?.();
|
|
1237
|
-
}
|
|
1342
|
+
execute: () => instance.zoomIn?.()
|
|
1238
1343
|
},
|
|
1239
1344
|
{
|
|
1240
1345
|
id: "fit-page",
|
|
@@ -1242,39 +1347,23 @@ var PdfPlugin = class {
|
|
|
1242
1347
|
label: "Fit to Page",
|
|
1243
1348
|
type: "button",
|
|
1244
1349
|
group: "zoom",
|
|
1245
|
-
execute: () =>
|
|
1246
|
-
instance.fitToPage?.();
|
|
1247
|
-
}
|
|
1350
|
+
execute: () => instance.fitToPage?.()
|
|
1248
1351
|
},
|
|
1249
1352
|
{
|
|
1250
1353
|
id: "rotate-cw",
|
|
1251
1354
|
icon: "rotate-cw",
|
|
1252
|
-
label: "Rotate",
|
|
1355
|
+
label: "Rotate Clockwise",
|
|
1253
1356
|
type: "button",
|
|
1254
1357
|
group: "view",
|
|
1255
|
-
execute: () =>
|
|
1256
|
-
instance.rotateCW?.();
|
|
1257
|
-
}
|
|
1258
|
-
},
|
|
1259
|
-
{
|
|
1260
|
-
id: "page-nav",
|
|
1261
|
-
icon: "page-nav",
|
|
1262
|
-
label: "Page Navigation",
|
|
1263
|
-
type: "page-nav",
|
|
1264
|
-
group: "navigation",
|
|
1265
|
-
execute: (page) => {
|
|
1266
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1267
|
-
}
|
|
1358
|
+
execute: () => instance.rotateCW?.()
|
|
1268
1359
|
},
|
|
1269
1360
|
{
|
|
1270
1361
|
id: "download",
|
|
1271
1362
|
icon: "download",
|
|
1272
|
-
label: "Download",
|
|
1363
|
+
label: "Download PDF",
|
|
1273
1364
|
type: "button",
|
|
1274
1365
|
group: "actions",
|
|
1275
|
-
execute: () =>
|
|
1276
|
-
instance.download?.();
|
|
1277
|
-
}
|
|
1366
|
+
execute: () => instance.download?.()
|
|
1278
1367
|
},
|
|
1279
1368
|
{
|
|
1280
1369
|
id: "print",
|
|
@@ -1282,99 +1371,224 @@ var PdfPlugin = class {
|
|
|
1282
1371
|
label: "Print",
|
|
1283
1372
|
type: "button",
|
|
1284
1373
|
group: "actions",
|
|
1285
|
-
execute: () =>
|
|
1286
|
-
instance.print?.();
|
|
1287
|
-
}
|
|
1374
|
+
execute: () => instance.print?.()
|
|
1288
1375
|
}
|
|
1289
1376
|
];
|
|
1290
1377
|
}
|
|
1291
1378
|
async render(ctx) {
|
|
1292
|
-
const
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1379
|
+
const container = document.createElement("div");
|
|
1380
|
+
container.className = "fp-pdf-container";
|
|
1381
|
+
container.style.width = "100%";
|
|
1382
|
+
container.style.height = "100%";
|
|
1383
|
+
container.style.overflow = "auto";
|
|
1384
|
+
container.style.display = "flex";
|
|
1385
|
+
container.style.flexDirection = "column";
|
|
1386
|
+
container.style.alignItems = "center";
|
|
1387
|
+
container.style.justifyContent = "flex-start";
|
|
1388
|
+
container.style.padding = "20px 16px";
|
|
1389
|
+
container.style.backgroundColor = "#0f172a";
|
|
1390
|
+
container.style.boxSizing = "border-box";
|
|
1391
|
+
container.style.position = "relative";
|
|
1392
|
+
const pageCard = document.createElement("div");
|
|
1393
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1394
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1395
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1396
|
+
pageCard.style.borderRadius = "4px";
|
|
1397
|
+
pageCard.style.overflow = "hidden";
|
|
1398
|
+
pageCard.style.lineHeight = "0";
|
|
1399
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1400
|
+
pageCard.style.position = "relative";
|
|
1401
|
+
pageCard.style.flexShrink = "0";
|
|
1402
|
+
let canvas = document.createElement("canvas");
|
|
1403
|
+
pageCard.appendChild(canvas);
|
|
1404
|
+
container.appendChild(pageCard);
|
|
1405
|
+
const indicator = document.createElement("div");
|
|
1406
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1407
|
+
indicator.style.position = "sticky";
|
|
1408
|
+
indicator.style.bottom = "16px";
|
|
1409
|
+
indicator.style.marginTop = "16px";
|
|
1410
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1411
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1412
|
+
indicator.style.color = "#f8fafc";
|
|
1413
|
+
indicator.style.fontSize = "12px";
|
|
1414
|
+
indicator.style.fontWeight = "600";
|
|
1415
|
+
indicator.style.padding = "5px 14px";
|
|
1416
|
+
indicator.style.borderRadius = "20px";
|
|
1417
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1418
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1419
|
+
indicator.style.zIndex = "10";
|
|
1420
|
+
indicator.style.userSelect = "none";
|
|
1421
|
+
indicator.style.pointerEvents = "none";
|
|
1422
|
+
container.appendChild(indicator);
|
|
1423
|
+
ctx.container.appendChild(container);
|
|
1424
|
+
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1425
|
+
data: new Uint8Array(ctx.buffer),
|
|
1426
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/cmaps/`,
|
|
1427
|
+
cMapPacked: true,
|
|
1428
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/standard_fonts/`
|
|
1429
|
+
});
|
|
1430
|
+
const pdfDoc = await loadingTask.promise;
|
|
1431
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1308
1432
|
let currentPage = 1;
|
|
1309
|
-
let
|
|
1433
|
+
let zoomScale = 1;
|
|
1310
1434
|
let rotation = 0;
|
|
1435
|
+
let currentRenderTask = null;
|
|
1436
|
+
const renderPage = async (pageNum) => {
|
|
1437
|
+
if (currentRenderTask) {
|
|
1438
|
+
try {
|
|
1439
|
+
currentRenderTask.cancel();
|
|
1440
|
+
} catch {
|
|
1441
|
+
}
|
|
1442
|
+
currentRenderTask = null;
|
|
1443
|
+
}
|
|
1444
|
+
const newCanvas = document.createElement("canvas");
|
|
1445
|
+
pageCard.replaceChild(newCanvas, canvas);
|
|
1446
|
+
canvas = newCanvas;
|
|
1447
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1448
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1449
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1450
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1451
|
+
const containerWidth = container.clientWidth || 900;
|
|
1452
|
+
const containerHeight = container.clientHeight || 700;
|
|
1453
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1454
|
+
const availWidth = Math.max(100, containerWidth - 48);
|
|
1455
|
+
const availHeight = Math.max(100, containerHeight - 88);
|
|
1456
|
+
const scaleW = availWidth / unscaledVp.width;
|
|
1457
|
+
const scaleH = availHeight / unscaledVp.height;
|
|
1458
|
+
const fitScale = Math.min(scaleW, scaleH);
|
|
1459
|
+
const effectiveScale = (fitScale > 0 ? fitScale : 1) * zoomScale;
|
|
1460
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1461
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1462
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1463
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1464
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1465
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1466
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1467
|
+
if (!canvasCtx) return;
|
|
1468
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1469
|
+
currentRenderTask = page.render({
|
|
1470
|
+
canvasContext: canvasCtx,
|
|
1471
|
+
viewport
|
|
1472
|
+
});
|
|
1473
|
+
try {
|
|
1474
|
+
await currentRenderTask.promise;
|
|
1475
|
+
} catch (err) {
|
|
1476
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1477
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1478
|
+
}
|
|
1479
|
+
} finally {
|
|
1480
|
+
currentRenderTask = null;
|
|
1481
|
+
}
|
|
1482
|
+
};
|
|
1483
|
+
await renderPage(1);
|
|
1311
1484
|
const cleanup = () => {
|
|
1312
|
-
|
|
1313
|
-
|
|
1485
|
+
if (currentRenderTask) {
|
|
1486
|
+
try {
|
|
1487
|
+
currentRenderTask.cancel();
|
|
1488
|
+
} catch {
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
try {
|
|
1492
|
+
pdfDoc.destroy();
|
|
1493
|
+
} catch {
|
|
1494
|
+
}
|
|
1495
|
+
container.remove();
|
|
1314
1496
|
ctx.container.innerHTML = "";
|
|
1315
1497
|
};
|
|
1316
1498
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1317
|
-
|
|
1499
|
+
const instance = {
|
|
1318
1500
|
destroy: cleanup,
|
|
1319
1501
|
zoomIn: () => {
|
|
1320
|
-
|
|
1321
|
-
|
|
1502
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1503
|
+
renderPage(currentPage);
|
|
1322
1504
|
},
|
|
1323
1505
|
zoomOut: () => {
|
|
1324
|
-
|
|
1325
|
-
|
|
1506
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1507
|
+
renderPage(currentPage);
|
|
1326
1508
|
},
|
|
1327
|
-
getZoom: () =>
|
|
1509
|
+
getZoom: () => zoomScale,
|
|
1328
1510
|
setZoom: (level) => {
|
|
1329
|
-
|
|
1330
|
-
|
|
1511
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1512
|
+
renderPage(currentPage);
|
|
1331
1513
|
},
|
|
1332
1514
|
fitToPage: () => {
|
|
1333
|
-
|
|
1334
|
-
|
|
1515
|
+
zoomScale = 1;
|
|
1516
|
+
rotation = 0;
|
|
1517
|
+
renderPage(currentPage);
|
|
1335
1518
|
},
|
|
1336
1519
|
rotateCW: () => {
|
|
1337
1520
|
rotation = (rotation + 90) % 360;
|
|
1338
|
-
|
|
1521
|
+
renderPage(currentPage);
|
|
1339
1522
|
},
|
|
1340
1523
|
rotateCCW: () => {
|
|
1341
1524
|
rotation = (rotation - 90 + 360) % 360;
|
|
1342
|
-
|
|
1525
|
+
renderPage(currentPage);
|
|
1343
1526
|
},
|
|
1344
1527
|
getRotation: () => rotation,
|
|
1528
|
+
getPageCount: () => totalPages,
|
|
1529
|
+
getCurrentPage: () => currentPage,
|
|
1345
1530
|
goToPage: (page) => {
|
|
1346
|
-
|
|
1347
|
-
iframe.src = `${url}#page=${page}`;
|
|
1531
|
+
renderPage(page);
|
|
1348
1532
|
},
|
|
1349
|
-
getCurrentPage: () => currentPage,
|
|
1350
1533
|
download: () => {
|
|
1534
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1535
|
+
const url = URL.createObjectURL(blob);
|
|
1351
1536
|
const a = document.createElement("a");
|
|
1352
1537
|
a.href = url;
|
|
1353
1538
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1354
1539
|
a.click();
|
|
1540
|
+
URL.revokeObjectURL(url);
|
|
1355
1541
|
},
|
|
1356
1542
|
print: () => {
|
|
1357
|
-
|
|
1543
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1544
|
+
const url = URL.createObjectURL(blob);
|
|
1545
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1546
|
+
hiddenIframe.style.position = "fixed";
|
|
1547
|
+
hiddenIframe.style.right = "0";
|
|
1548
|
+
hiddenIframe.style.bottom = "0";
|
|
1549
|
+
hiddenIframe.style.width = "0";
|
|
1550
|
+
hiddenIframe.style.height = "0";
|
|
1551
|
+
hiddenIframe.style.border = "0";
|
|
1552
|
+
document.body.appendChild(hiddenIframe);
|
|
1553
|
+
hiddenIframe.src = url;
|
|
1554
|
+
hiddenIframe.onload = () => {
|
|
1555
|
+
setTimeout(() => {
|
|
1556
|
+
hiddenIframe.contentWindow?.print();
|
|
1557
|
+
setTimeout(() => {
|
|
1558
|
+
hiddenIframe.remove();
|
|
1559
|
+
URL.revokeObjectURL(url);
|
|
1560
|
+
}, 1e3);
|
|
1561
|
+
}, 300);
|
|
1562
|
+
};
|
|
1358
1563
|
},
|
|
1359
1564
|
getThumbnails: async () => {
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1565
|
+
const thumbnails = [];
|
|
1566
|
+
const count = Math.min(totalPages, 50);
|
|
1567
|
+
for (let i = 1; i <= count; i++) {
|
|
1568
|
+
thumbnails.push({
|
|
1569
|
+
index: i,
|
|
1570
|
+
label: `Page ${i}`,
|
|
1571
|
+
render: async (thumbCanvas) => {
|
|
1572
|
+
try {
|
|
1573
|
+
const p = await pdfDoc.getPage(i);
|
|
1574
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1575
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1576
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1577
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1578
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1579
|
+
if (tCtx) {
|
|
1580
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1581
|
+
}
|
|
1582
|
+
} catch (e) {
|
|
1583
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1372
1584
|
}
|
|
1373
1585
|
}
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
return thumbnails;
|
|
1376
1589
|
}
|
|
1377
1590
|
};
|
|
1591
|
+
return instance;
|
|
1378
1592
|
}
|
|
1379
1593
|
};
|
|
1380
1594
|
function pdfPlugin() {
|
|
@@ -1701,7 +1915,31 @@ var DocxPlugin = class {
|
|
|
1701
1915
|
return this.mimeTypes.includes(mime || "");
|
|
1702
1916
|
}
|
|
1703
1917
|
getToolbarActions(instance) {
|
|
1704
|
-
|
|
1918
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1919
|
+
const actions = [];
|
|
1920
|
+
if (totalPages > 1) {
|
|
1921
|
+
actions.push({
|
|
1922
|
+
id: "page-nav",
|
|
1923
|
+
icon: "",
|
|
1924
|
+
label: "Page Navigation",
|
|
1925
|
+
type: "page-nav",
|
|
1926
|
+
group: "navigation",
|
|
1927
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1928
|
+
max: totalPages,
|
|
1929
|
+
execute: (action, page) => {
|
|
1930
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1931
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1932
|
+
if (action === "prev") {
|
|
1933
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1934
|
+
} else if (action === "next") {
|
|
1935
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1936
|
+
} else if (typeof page === "number") {
|
|
1937
|
+
instance.goToPage?.(page);
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
actions.push(
|
|
1705
1943
|
{
|
|
1706
1944
|
id: "zoom-out",
|
|
1707
1945
|
icon: "zoom-out",
|
|
@@ -1726,6 +1964,14 @@ var DocxPlugin = class {
|
|
|
1726
1964
|
group: "zoom",
|
|
1727
1965
|
execute: () => instance.fitToPage?.()
|
|
1728
1966
|
},
|
|
1967
|
+
{
|
|
1968
|
+
id: "rotate-cw",
|
|
1969
|
+
icon: "rotate-cw",
|
|
1970
|
+
label: "Rotate",
|
|
1971
|
+
type: "button",
|
|
1972
|
+
group: "view",
|
|
1973
|
+
execute: () => instance.rotateCW?.()
|
|
1974
|
+
},
|
|
1729
1975
|
{
|
|
1730
1976
|
id: "download",
|
|
1731
1977
|
icon: "download",
|
|
@@ -1742,7 +1988,8 @@ var DocxPlugin = class {
|
|
|
1742
1988
|
group: "actions",
|
|
1743
1989
|
execute: () => instance.print?.()
|
|
1744
1990
|
}
|
|
1745
|
-
|
|
1991
|
+
);
|
|
1992
|
+
return actions;
|
|
1746
1993
|
}
|
|
1747
1994
|
async render(ctx) {
|
|
1748
1995
|
const wrapper = document.createElement("div");
|
|
@@ -1818,7 +2065,71 @@ var DocxPlugin = class {
|
|
|
1818
2065
|
}
|
|
1819
2066
|
}
|
|
1820
2067
|
}
|
|
2068
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2069
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2070
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2071
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2072
|
+
let currentPage = 1;
|
|
2073
|
+
let indicator = null;
|
|
2074
|
+
if (totalPages > 1) {
|
|
2075
|
+
indicator = document.createElement("div");
|
|
2076
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2077
|
+
indicator.style.position = "sticky";
|
|
2078
|
+
indicator.style.bottom = "16px";
|
|
2079
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2080
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2081
|
+
indicator.style.color = "#f8fafc";
|
|
2082
|
+
indicator.style.fontSize = "12px";
|
|
2083
|
+
indicator.style.fontWeight = "600";
|
|
2084
|
+
indicator.style.padding = "5px 14px";
|
|
2085
|
+
indicator.style.borderRadius = "20px";
|
|
2086
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2087
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2088
|
+
indicator.style.zIndex = "10";
|
|
2089
|
+
indicator.style.userSelect = "none";
|
|
2090
|
+
indicator.style.pointerEvents = "none";
|
|
2091
|
+
indicator.style.textAlign = "center";
|
|
2092
|
+
indicator.style.width = "fit-content";
|
|
2093
|
+
indicator.style.margin = "16px auto 0";
|
|
2094
|
+
ctx.container.appendChild(indicator);
|
|
2095
|
+
}
|
|
2096
|
+
const showPage = (pageNum) => {
|
|
2097
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2098
|
+
if (pageElements.length > 1) {
|
|
2099
|
+
pageElements.forEach((sec, idx) => {
|
|
2100
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2101
|
+
});
|
|
2102
|
+
}
|
|
2103
|
+
if (indicator) {
|
|
2104
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2105
|
+
}
|
|
2106
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2107
|
+
};
|
|
2108
|
+
if (totalPages > 1) {
|
|
2109
|
+
showPage(1);
|
|
2110
|
+
}
|
|
2111
|
+
scale = 1;
|
|
2112
|
+
let rotation = 0;
|
|
2113
|
+
const calculateFitScale = () => {
|
|
2114
|
+
const activeEl = pageElements[currentPage - 1] || wrapper.firstElementChild || wrapper;
|
|
2115
|
+
const elW = activeEl.offsetWidth || 816;
|
|
2116
|
+
const elH = activeEl.offsetHeight || 1056;
|
|
2117
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
2118
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
2119
|
+
const sW = availW / elW;
|
|
2120
|
+
const sH = availH / elH;
|
|
2121
|
+
return Math.min(1.1, Math.min(sW, sH));
|
|
2122
|
+
};
|
|
2123
|
+
const applyTransform = () => {
|
|
2124
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2125
|
+
wrapper.style.transformOrigin = "top center";
|
|
2126
|
+
};
|
|
2127
|
+
setTimeout(() => {
|
|
2128
|
+
scale = calculateFitScale();
|
|
2129
|
+
applyTransform();
|
|
2130
|
+
}, 60);
|
|
1821
2131
|
const cleanup = () => {
|
|
2132
|
+
indicator?.remove();
|
|
1822
2133
|
for (const url of createdBlobUrls) {
|
|
1823
2134
|
URL.revokeObjectURL(url);
|
|
1824
2135
|
}
|
|
@@ -1829,22 +2140,36 @@ var DocxPlugin = class {
|
|
|
1829
2140
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1830
2141
|
return {
|
|
1831
2142
|
destroy: cleanup,
|
|
2143
|
+
getPageCount: () => totalPages,
|
|
2144
|
+
getCurrentPage: () => currentPage,
|
|
2145
|
+
goToPage: (page) => {
|
|
2146
|
+
showPage(page);
|
|
2147
|
+
},
|
|
1832
2148
|
zoomIn: () => {
|
|
1833
|
-
scale += 0.
|
|
1834
|
-
|
|
2149
|
+
scale += 0.15;
|
|
2150
|
+
applyTransform();
|
|
1835
2151
|
},
|
|
1836
2152
|
zoomOut: () => {
|
|
1837
|
-
scale = Math.max(0.2, scale - 0.
|
|
1838
|
-
|
|
2153
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2154
|
+
applyTransform();
|
|
1839
2155
|
},
|
|
1840
2156
|
getZoom: () => scale,
|
|
1841
2157
|
setZoom: (level) => {
|
|
1842
2158
|
scale = level;
|
|
1843
|
-
|
|
2159
|
+
applyTransform();
|
|
1844
2160
|
},
|
|
1845
2161
|
fitToPage: () => {
|
|
1846
|
-
scale =
|
|
1847
|
-
|
|
2162
|
+
scale = calculateFitScale();
|
|
2163
|
+
rotation = 0;
|
|
2164
|
+
applyTransform();
|
|
2165
|
+
},
|
|
2166
|
+
rotateCW: () => {
|
|
2167
|
+
rotation = (rotation + 90) % 360;
|
|
2168
|
+
applyTransform();
|
|
2169
|
+
},
|
|
2170
|
+
rotateCCW: () => {
|
|
2171
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2172
|
+
applyTransform();
|
|
1848
2173
|
},
|
|
1849
2174
|
download: () => {
|
|
1850
2175
|
const blob = new Blob([ctx.buffer], { type: this.mimeTypes[0] });
|
|
@@ -2093,7 +2418,31 @@ var ExcelPlugin = class {
|
|
|
2093
2418
|
return this.mimeTypes.includes(mime || "");
|
|
2094
2419
|
}
|
|
2095
2420
|
getToolbarActions(instance) {
|
|
2096
|
-
|
|
2421
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2422
|
+
const actions = [];
|
|
2423
|
+
if (totalSheets > 1) {
|
|
2424
|
+
actions.push({
|
|
2425
|
+
id: "page-nav",
|
|
2426
|
+
icon: "",
|
|
2427
|
+
label: "Sheet Navigation",
|
|
2428
|
+
type: "page-nav",
|
|
2429
|
+
group: "navigation",
|
|
2430
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2431
|
+
max: totalSheets,
|
|
2432
|
+
execute: (action, sheet) => {
|
|
2433
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2434
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2435
|
+
if (action === "prev") {
|
|
2436
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2437
|
+
} else if (action === "next") {
|
|
2438
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2439
|
+
} else if (typeof sheet === "number") {
|
|
2440
|
+
instance.goToPage?.(sheet);
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
});
|
|
2444
|
+
}
|
|
2445
|
+
actions.push(
|
|
2097
2446
|
{
|
|
2098
2447
|
id: "zoom-out",
|
|
2099
2448
|
icon: "zoom-out",
|
|
@@ -2115,13 +2464,23 @@ var ExcelPlugin = class {
|
|
|
2115
2464
|
}
|
|
2116
2465
|
},
|
|
2117
2466
|
{
|
|
2118
|
-
id: "page
|
|
2119
|
-
icon: "page
|
|
2120
|
-
label: "
|
|
2121
|
-
type: "
|
|
2122
|
-
group: "
|
|
2123
|
-
execute: (
|
|
2124
|
-
|
|
2467
|
+
id: "fit-page",
|
|
2468
|
+
icon: "fit-page",
|
|
2469
|
+
label: "Fit to View",
|
|
2470
|
+
type: "button",
|
|
2471
|
+
group: "zoom",
|
|
2472
|
+
execute: () => {
|
|
2473
|
+
instance.fitToPage?.();
|
|
2474
|
+
}
|
|
2475
|
+
},
|
|
2476
|
+
{
|
|
2477
|
+
id: "rotate-cw",
|
|
2478
|
+
icon: "rotate-cw",
|
|
2479
|
+
label: "Rotate",
|
|
2480
|
+
type: "button",
|
|
2481
|
+
group: "view",
|
|
2482
|
+
execute: () => {
|
|
2483
|
+
instance.rotateCW?.();
|
|
2125
2484
|
}
|
|
2126
2485
|
},
|
|
2127
2486
|
{
|
|
@@ -2144,7 +2503,8 @@ var ExcelPlugin = class {
|
|
|
2144
2503
|
instance.print?.();
|
|
2145
2504
|
}
|
|
2146
2505
|
}
|
|
2147
|
-
|
|
2506
|
+
);
|
|
2507
|
+
return actions;
|
|
2148
2508
|
}
|
|
2149
2509
|
async render(ctx) {
|
|
2150
2510
|
const container = document.createElement("div");
|
|
@@ -2173,9 +2533,23 @@ var ExcelPlugin = class {
|
|
|
2173
2533
|
container.appendChild(tabsArea);
|
|
2174
2534
|
ctx.container.appendChild(container);
|
|
2175
2535
|
let scale = 1;
|
|
2536
|
+
let rotation = 0;
|
|
2176
2537
|
let currentSheetIndex = 1;
|
|
2177
2538
|
let sheetNames = [];
|
|
2178
2539
|
let wb = null;
|
|
2540
|
+
const applyTransform = () => {
|
|
2541
|
+
contentArea.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
2542
|
+
contentArea.style.transformOrigin = "top left";
|
|
2543
|
+
};
|
|
2544
|
+
const calculateFitScale = () => {
|
|
2545
|
+
const table = contentArea.querySelector("table");
|
|
2546
|
+
if (!table) return 1;
|
|
2547
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
2548
|
+
const availH = Math.max(200, container.clientHeight - 80);
|
|
2549
|
+
const tW = table.offsetWidth || 800;
|
|
2550
|
+
const tH = table.offsetHeight || 600;
|
|
2551
|
+
return Math.min(1, Math.min(availW / tW, availH / tH));
|
|
2552
|
+
};
|
|
2179
2553
|
try {
|
|
2180
2554
|
wb = XLSX__namespace.read(new Uint8Array(ctx.buffer), { type: "array", cellDates: true });
|
|
2181
2555
|
sheetNames = wb.SheetNames || [];
|
|
@@ -2228,6 +2602,7 @@ var ExcelPlugin = class {
|
|
|
2228
2602
|
b.style.fontWeight = "normal";
|
|
2229
2603
|
}
|
|
2230
2604
|
});
|
|
2605
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2231
2606
|
};
|
|
2232
2607
|
if (sheetNames.length > 0) {
|
|
2233
2608
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2262,17 +2637,30 @@ var ExcelPlugin = class {
|
|
|
2262
2637
|
return {
|
|
2263
2638
|
destroy: cleanup,
|
|
2264
2639
|
zoomIn: () => {
|
|
2265
|
-
scale += 0.
|
|
2266
|
-
|
|
2640
|
+
scale += 0.15;
|
|
2641
|
+
applyTransform();
|
|
2267
2642
|
},
|
|
2268
2643
|
zoomOut: () => {
|
|
2269
|
-
scale = Math.max(0.2, scale - 0.
|
|
2270
|
-
|
|
2644
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
2645
|
+
applyTransform();
|
|
2271
2646
|
},
|
|
2272
2647
|
getZoom: () => scale,
|
|
2273
2648
|
setZoom: (level) => {
|
|
2274
2649
|
scale = level;
|
|
2275
|
-
|
|
2650
|
+
applyTransform();
|
|
2651
|
+
},
|
|
2652
|
+
fitToPage: () => {
|
|
2653
|
+
scale = calculateFitScale();
|
|
2654
|
+
rotation = 0;
|
|
2655
|
+
applyTransform();
|
|
2656
|
+
},
|
|
2657
|
+
rotateCW: () => {
|
|
2658
|
+
rotation = (rotation + 90) % 360;
|
|
2659
|
+
applyTransform();
|
|
2660
|
+
},
|
|
2661
|
+
rotateCCW: () => {
|
|
2662
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
2663
|
+
applyTransform();
|
|
2276
2664
|
},
|
|
2277
2665
|
goToPage: (page) => {
|
|
2278
2666
|
if (page > 0 && page <= sheetNames.length) {
|
|
@@ -2477,7 +2865,31 @@ var CodePlugin = class {
|
|
|
2477
2865
|
return false;
|
|
2478
2866
|
}
|
|
2479
2867
|
getToolbarActions(instance) {
|
|
2480
|
-
|
|
2868
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2869
|
+
const actions = [];
|
|
2870
|
+
if (totalPages > 1) {
|
|
2871
|
+
actions.push({
|
|
2872
|
+
id: "page-nav",
|
|
2873
|
+
icon: "",
|
|
2874
|
+
label: "Page Navigation",
|
|
2875
|
+
type: "page-nav",
|
|
2876
|
+
group: "navigation",
|
|
2877
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2878
|
+
max: totalPages,
|
|
2879
|
+
execute: (action, page) => {
|
|
2880
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2881
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2882
|
+
if (action === "prev") {
|
|
2883
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2884
|
+
} else if (action === "next") {
|
|
2885
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2886
|
+
} else if (typeof page === "number") {
|
|
2887
|
+
instance.goToPage?.(page);
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
});
|
|
2891
|
+
}
|
|
2892
|
+
actions.push(
|
|
2481
2893
|
{
|
|
2482
2894
|
id: "zoom-out",
|
|
2483
2895
|
icon: "zoom-out",
|
|
@@ -2498,6 +2910,26 @@ var CodePlugin = class {
|
|
|
2498
2910
|
instance.zoomIn?.();
|
|
2499
2911
|
}
|
|
2500
2912
|
},
|
|
2913
|
+
{
|
|
2914
|
+
id: "fit-page",
|
|
2915
|
+
icon: "fit-page",
|
|
2916
|
+
label: "Fit to View",
|
|
2917
|
+
type: "button",
|
|
2918
|
+
group: "zoom",
|
|
2919
|
+
execute: () => {
|
|
2920
|
+
instance.fitToPage?.();
|
|
2921
|
+
}
|
|
2922
|
+
},
|
|
2923
|
+
{
|
|
2924
|
+
id: "rotate-cw",
|
|
2925
|
+
icon: "rotate-cw",
|
|
2926
|
+
label: "Rotate",
|
|
2927
|
+
type: "button",
|
|
2928
|
+
group: "view",
|
|
2929
|
+
execute: () => {
|
|
2930
|
+
instance.rotateCW?.();
|
|
2931
|
+
}
|
|
2932
|
+
},
|
|
2501
2933
|
{
|
|
2502
2934
|
id: "copy",
|
|
2503
2935
|
icon: "copy",
|
|
@@ -2528,11 +2960,16 @@ var CodePlugin = class {
|
|
|
2528
2960
|
instance.print?.();
|
|
2529
2961
|
}
|
|
2530
2962
|
}
|
|
2531
|
-
|
|
2963
|
+
);
|
|
2964
|
+
return actions;
|
|
2532
2965
|
}
|
|
2533
2966
|
async render(ctx) {
|
|
2534
2967
|
const decoder = new TextDecoder("utf-8");
|
|
2535
|
-
const
|
|
2968
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
2969
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
2970
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2971
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
2972
|
+
let currentPage = 1;
|
|
2536
2973
|
const container = document.createElement("div");
|
|
2537
2974
|
container.style.width = "100%";
|
|
2538
2975
|
container.style.height = "100%";
|
|
@@ -2542,6 +2979,7 @@ var CodePlugin = class {
|
|
|
2542
2979
|
container.style.padding = "16px";
|
|
2543
2980
|
container.style.boxSizing = "border-box";
|
|
2544
2981
|
let fontSize = 13;
|
|
2982
|
+
let rotation = 0;
|
|
2545
2983
|
const pre = document.createElement("pre");
|
|
2546
2984
|
pre.style.margin = "0";
|
|
2547
2985
|
pre.style.fontFamily = "Consolas, Menlo, Monaco, monospace";
|
|
@@ -2551,25 +2989,66 @@ var CodePlugin = class {
|
|
|
2551
2989
|
pre.style.wordBreak = "break-all";
|
|
2552
2990
|
const code = document.createElement("code");
|
|
2553
2991
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2992
|
+
const renderCodePage = (text) => {
|
|
2993
|
+
try {
|
|
2994
|
+
if (ext && hljs__default.default.getLanguage(ext)) {
|
|
2995
|
+
code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
|
|
2996
|
+
} else {
|
|
2997
|
+
code.innerHTML = hljs__default.default.highlightAuto(text).value;
|
|
2998
|
+
}
|
|
2999
|
+
} catch {
|
|
3000
|
+
code.textContent = text;
|
|
2559
3001
|
}
|
|
2560
|
-
}
|
|
2561
|
-
|
|
2562
|
-
}
|
|
3002
|
+
};
|
|
3003
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2563
3004
|
pre.appendChild(code);
|
|
2564
3005
|
container.appendChild(pre);
|
|
3006
|
+
let indicator = null;
|
|
3007
|
+
if (totalPages > 1) {
|
|
3008
|
+
indicator = document.createElement("div");
|
|
3009
|
+
indicator.className = "fp-code-page-indicator";
|
|
3010
|
+
indicator.style.position = "sticky";
|
|
3011
|
+
indicator.style.bottom = "16px";
|
|
3012
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3013
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3014
|
+
indicator.style.color = "#f8fafc";
|
|
3015
|
+
indicator.style.fontSize = "12px";
|
|
3016
|
+
indicator.style.fontWeight = "600";
|
|
3017
|
+
indicator.style.padding = "5px 14px";
|
|
3018
|
+
indicator.style.borderRadius = "20px";
|
|
3019
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3020
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3021
|
+
indicator.style.zIndex = "10";
|
|
3022
|
+
indicator.style.userSelect = "none";
|
|
3023
|
+
indicator.style.pointerEvents = "none";
|
|
3024
|
+
indicator.style.textAlign = "center";
|
|
3025
|
+
indicator.style.width = "fit-content";
|
|
3026
|
+
indicator.style.margin = "16px auto 0";
|
|
3027
|
+
container.appendChild(indicator);
|
|
3028
|
+
}
|
|
3029
|
+
const showPage = (pageNum) => {
|
|
3030
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3031
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
3032
|
+
if (indicator) {
|
|
3033
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3034
|
+
}
|
|
3035
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3036
|
+
};
|
|
3037
|
+
if (totalPages > 1) {
|
|
3038
|
+
showPage(1);
|
|
3039
|
+
}
|
|
2565
3040
|
ctx.container.appendChild(container);
|
|
2566
3041
|
const cleanup = () => {
|
|
3042
|
+
indicator?.remove();
|
|
2567
3043
|
container.remove();
|
|
2568
3044
|
ctx.container.innerHTML = "";
|
|
2569
3045
|
};
|
|
2570
3046
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2571
3047
|
return {
|
|
2572
3048
|
destroy: cleanup,
|
|
3049
|
+
getPageCount: () => totalPages,
|
|
3050
|
+
getCurrentPage: () => currentPage,
|
|
3051
|
+
goToPage: (page) => showPage(page),
|
|
2573
3052
|
zoomIn: () => {
|
|
2574
3053
|
fontSize = Math.min(32, fontSize + 2);
|
|
2575
3054
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2583,6 +3062,22 @@ var CodePlugin = class {
|
|
|
2583
3062
|
fontSize = Math.round(13 * level);
|
|
2584
3063
|
pre.style.fontSize = `${fontSize}px`;
|
|
2585
3064
|
},
|
|
3065
|
+
fitToPage: () => {
|
|
3066
|
+
fontSize = 13;
|
|
3067
|
+
rotation = 0;
|
|
3068
|
+
pre.style.fontSize = "13px";
|
|
3069
|
+
pre.style.transform = "none";
|
|
3070
|
+
},
|
|
3071
|
+
rotateCW: () => {
|
|
3072
|
+
rotation = (rotation + 90) % 360;
|
|
3073
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3074
|
+
pre.style.transformOrigin = "top left";
|
|
3075
|
+
},
|
|
3076
|
+
rotateCCW: () => {
|
|
3077
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3078
|
+
pre.style.transform = `rotate(${rotation}deg)`;
|
|
3079
|
+
pre.style.transformOrigin = "top left";
|
|
3080
|
+
},
|
|
2586
3081
|
download: () => {
|
|
2587
3082
|
const mimeType = ctx.metadata.mimeType || "text/plain";
|
|
2588
3083
|
const blob = new Blob([ctx.buffer], { type: mimeType });
|
|
@@ -2597,7 +3092,7 @@ var CodePlugin = class {
|
|
|
2597
3092
|
window.print();
|
|
2598
3093
|
},
|
|
2599
3094
|
copy: () => {
|
|
2600
|
-
navigator.clipboard?.writeText(
|
|
3095
|
+
navigator.clipboard?.writeText(fullText);
|
|
2601
3096
|
}
|
|
2602
3097
|
};
|
|
2603
3098
|
}
|
|
@@ -3094,6 +3589,14 @@ var PptxPlugin = class {
|
|
|
3094
3589
|
group: "zoom",
|
|
3095
3590
|
execute: () => instance.fitToPage?.()
|
|
3096
3591
|
},
|
|
3592
|
+
{
|
|
3593
|
+
id: "rotate-cw",
|
|
3594
|
+
icon: "rotate-cw",
|
|
3595
|
+
label: "Rotate",
|
|
3596
|
+
type: "button",
|
|
3597
|
+
group: "view",
|
|
3598
|
+
execute: () => instance.rotateCW?.()
|
|
3599
|
+
},
|
|
3097
3600
|
{
|
|
3098
3601
|
id: "download",
|
|
3099
3602
|
icon: "download",
|
|
@@ -3118,6 +3621,7 @@ var PptxPlugin = class {
|
|
|
3118
3621
|
const slideCount = renderer.slidePaths?.length || 1;
|
|
3119
3622
|
let currentSlide = 1;
|
|
3120
3623
|
let scale = 1;
|
|
3624
|
+
let rotation = 0;
|
|
3121
3625
|
const wrapper = document.createElement("div");
|
|
3122
3626
|
wrapper.className = "fp-pptx-wrapper";
|
|
3123
3627
|
wrapper.style.cssText = `
|
|
@@ -3140,6 +3644,8 @@ var PptxPlugin = class {
|
|
|
3140
3644
|
background: #ffffff;
|
|
3141
3645
|
transform-origin: top center;
|
|
3142
3646
|
transition: transform 0.2s ease;
|
|
3647
|
+
max-width: calc(100% - 32px);
|
|
3648
|
+
max-height: calc(100% - 48px);
|
|
3143
3649
|
`;
|
|
3144
3650
|
const canvas = document.createElement("canvas");
|
|
3145
3651
|
slideContainer.appendChild(canvas);
|
|
@@ -3147,10 +3653,22 @@ var PptxPlugin = class {
|
|
|
3147
3653
|
ctx.container.innerHTML = "";
|
|
3148
3654
|
ctx.container.style.overflow = "auto";
|
|
3149
3655
|
ctx.container.appendChild(wrapper);
|
|
3656
|
+
const calculateFitScale = () => {
|
|
3657
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
3658
|
+
const availH = Math.max(200, ctx.container.clientHeight - 72);
|
|
3659
|
+
const cW = canvas.offsetWidth || 1280;
|
|
3660
|
+
const cH = canvas.offsetHeight || 720;
|
|
3661
|
+
return Math.min(1, Math.min(availW / cW, availH / cH));
|
|
3662
|
+
};
|
|
3663
|
+
const applyTransform = () => {
|
|
3664
|
+
slideContainer.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
3665
|
+
};
|
|
3150
3666
|
const renderCurrentSlide = async () => {
|
|
3151
3667
|
try {
|
|
3152
3668
|
await renderer.renderSlide(currentSlide - 1, canvas, 1280);
|
|
3153
3669
|
ctx.emit("page-change", { page: currentSlide, totalPages: slideCount });
|
|
3670
|
+
scale = calculateFitScale();
|
|
3671
|
+
applyTransform();
|
|
3154
3672
|
} catch (err) {
|
|
3155
3673
|
console.error("[PptxPlugin] Failed to render slide:", err);
|
|
3156
3674
|
}
|
|
@@ -3173,21 +3691,30 @@ var PptxPlugin = class {
|
|
|
3173
3691
|
getPageCount: () => slideCount,
|
|
3174
3692
|
getCurrentPage: () => currentSlide,
|
|
3175
3693
|
zoomIn: () => {
|
|
3176
|
-
scale += 0.
|
|
3177
|
-
|
|
3694
|
+
scale += 0.15;
|
|
3695
|
+
applyTransform();
|
|
3178
3696
|
},
|
|
3179
3697
|
zoomOut: () => {
|
|
3180
|
-
scale = Math.max(0.2, scale - 0.
|
|
3181
|
-
|
|
3698
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
3699
|
+
applyTransform();
|
|
3182
3700
|
},
|
|
3183
3701
|
getZoom: () => scale,
|
|
3184
3702
|
setZoom: (level) => {
|
|
3185
3703
|
scale = level;
|
|
3186
|
-
|
|
3704
|
+
applyTransform();
|
|
3187
3705
|
},
|
|
3188
3706
|
fitToPage: () => {
|
|
3189
|
-
scale =
|
|
3190
|
-
|
|
3707
|
+
scale = calculateFitScale();
|
|
3708
|
+
rotation = 0;
|
|
3709
|
+
applyTransform();
|
|
3710
|
+
},
|
|
3711
|
+
rotateCW: () => {
|
|
3712
|
+
rotation = (rotation + 90) % 360;
|
|
3713
|
+
applyTransform();
|
|
3714
|
+
},
|
|
3715
|
+
rotateCCW: () => {
|
|
3716
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
3717
|
+
applyTransform();
|
|
3191
3718
|
},
|
|
3192
3719
|
getThumbnails: () => {
|
|
3193
3720
|
const list = [];
|
|
@@ -3419,7 +3946,31 @@ var RtfPlugin = class {
|
|
|
3419
3946
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3420
3947
|
}
|
|
3421
3948
|
getToolbarActions(instance) {
|
|
3422
|
-
|
|
3949
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3950
|
+
const actions = [];
|
|
3951
|
+
if (totalPages > 1) {
|
|
3952
|
+
actions.push({
|
|
3953
|
+
id: "page-nav",
|
|
3954
|
+
icon: "",
|
|
3955
|
+
label: "Page Navigation",
|
|
3956
|
+
type: "page-nav",
|
|
3957
|
+
group: "navigation",
|
|
3958
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3959
|
+
max: totalPages,
|
|
3960
|
+
execute: (action, page) => {
|
|
3961
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3962
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3963
|
+
if (action === "prev") {
|
|
3964
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3965
|
+
} else if (action === "next") {
|
|
3966
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3967
|
+
} else if (typeof page === "number") {
|
|
3968
|
+
instance.goToPage?.(page);
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
});
|
|
3972
|
+
}
|
|
3973
|
+
actions.push(
|
|
3423
3974
|
{
|
|
3424
3975
|
id: "zoom-out",
|
|
3425
3976
|
icon: "zoom-out",
|
|
@@ -3444,6 +3995,14 @@ var RtfPlugin = class {
|
|
|
3444
3995
|
group: "zoom",
|
|
3445
3996
|
execute: () => instance.fitToPage?.()
|
|
3446
3997
|
},
|
|
3998
|
+
{
|
|
3999
|
+
id: "rotate-cw",
|
|
4000
|
+
icon: "rotate-cw",
|
|
4001
|
+
label: "Rotate",
|
|
4002
|
+
type: "button",
|
|
4003
|
+
group: "view",
|
|
4004
|
+
execute: () => instance.rotateCW?.()
|
|
4005
|
+
},
|
|
3447
4006
|
{
|
|
3448
4007
|
id: "download",
|
|
3449
4008
|
icon: "download",
|
|
@@ -3460,7 +4019,8 @@ var RtfPlugin = class {
|
|
|
3460
4019
|
group: "actions",
|
|
3461
4020
|
execute: () => instance.print?.()
|
|
3462
4021
|
}
|
|
3463
|
-
|
|
4022
|
+
);
|
|
4023
|
+
return actions;
|
|
3464
4024
|
}
|
|
3465
4025
|
async render(ctx) {
|
|
3466
4026
|
const wrapper = document.createElement("div");
|
|
@@ -3479,44 +4039,124 @@ var RtfPlugin = class {
|
|
|
3479
4039
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3480
4040
|
ctx.container.appendChild(wrapper);
|
|
3481
4041
|
let scale = 1;
|
|
4042
|
+
let rotation = 0;
|
|
4043
|
+
let pageElements = [];
|
|
4044
|
+
const calculateFitScale = () => {
|
|
4045
|
+
const activeEl = pageElements[currentPage - 1] || wrapper;
|
|
4046
|
+
const elW = activeEl.offsetWidth || 850;
|
|
4047
|
+
const elH = activeEl.offsetHeight || 1e3;
|
|
4048
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4049
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4050
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4051
|
+
};
|
|
4052
|
+
const applyTransform = () => {
|
|
4053
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4054
|
+
wrapper.style.transformOrigin = "top center";
|
|
4055
|
+
};
|
|
4056
|
+
setTimeout(() => {
|
|
4057
|
+
scale = calculateFitScale();
|
|
4058
|
+
applyTransform();
|
|
4059
|
+
}, 60);
|
|
3482
4060
|
try {
|
|
3483
4061
|
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3484
4062
|
RTFJS__namespace.loggingEnabled(false);
|
|
3485
4063
|
}
|
|
3486
4064
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3487
4065
|
const htmlElements = await doc.render();
|
|
3488
|
-
|
|
4066
|
+
pageElements = htmlElements;
|
|
4067
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
4068
|
+
const el = htmlElements[i];
|
|
4069
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3489
4070
|
wrapper.appendChild(el);
|
|
3490
4071
|
}
|
|
3491
4072
|
} catch (err) {
|
|
3492
4073
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3493
4074
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3494
4075
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3495
|
-
|
|
4076
|
+
const pre = document.createElement("pre");
|
|
4077
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
4078
|
+
pre.style.fontFamily = "serif";
|
|
4079
|
+
pre.style.color = "#333";
|
|
4080
|
+
pre.textContent = clean;
|
|
4081
|
+
wrapper.appendChild(pre);
|
|
4082
|
+
pageElements = [pre];
|
|
4083
|
+
}
|
|
4084
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
4085
|
+
let currentPage = 1;
|
|
4086
|
+
let indicator = null;
|
|
4087
|
+
if (totalPages > 1) {
|
|
4088
|
+
indicator = document.createElement("div");
|
|
4089
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
4090
|
+
indicator.style.position = "sticky";
|
|
4091
|
+
indicator.style.bottom = "16px";
|
|
4092
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4093
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4094
|
+
indicator.style.color = "#f8fafc";
|
|
4095
|
+
indicator.style.fontSize = "12px";
|
|
4096
|
+
indicator.style.fontWeight = "600";
|
|
4097
|
+
indicator.style.padding = "5px 14px";
|
|
4098
|
+
indicator.style.borderRadius = "20px";
|
|
4099
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4100
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4101
|
+
indicator.style.zIndex = "10";
|
|
4102
|
+
indicator.style.userSelect = "none";
|
|
4103
|
+
indicator.style.pointerEvents = "none";
|
|
4104
|
+
indicator.style.textAlign = "center";
|
|
4105
|
+
indicator.style.width = "fit-content";
|
|
4106
|
+
indicator.style.margin = "16px auto 0";
|
|
4107
|
+
ctx.container.appendChild(indicator);
|
|
4108
|
+
}
|
|
4109
|
+
const showPage = (pageNum) => {
|
|
4110
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4111
|
+
if (totalPages > 1) {
|
|
4112
|
+
pageElements.forEach((el, idx) => {
|
|
4113
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4114
|
+
});
|
|
4115
|
+
}
|
|
4116
|
+
if (indicator) {
|
|
4117
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4118
|
+
}
|
|
4119
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4120
|
+
};
|
|
4121
|
+
if (totalPages > 1) {
|
|
4122
|
+
showPage(1);
|
|
3496
4123
|
}
|
|
3497
4124
|
const cleanup = () => {
|
|
4125
|
+
indicator?.remove();
|
|
3498
4126
|
wrapper.remove();
|
|
3499
4127
|
ctx.container.innerHTML = "";
|
|
3500
4128
|
};
|
|
3501
4129
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3502
4130
|
return {
|
|
3503
4131
|
destroy: cleanup,
|
|
4132
|
+
getPageCount: () => totalPages,
|
|
4133
|
+
getCurrentPage: () => currentPage,
|
|
4134
|
+
goToPage: (page) => showPage(page),
|
|
3504
4135
|
zoomIn: () => {
|
|
3505
|
-
scale += 0.
|
|
3506
|
-
|
|
4136
|
+
scale += 0.15;
|
|
4137
|
+
applyTransform();
|
|
3507
4138
|
},
|
|
3508
4139
|
zoomOut: () => {
|
|
3509
|
-
scale = Math.max(0.2, scale - 0.
|
|
3510
|
-
|
|
4140
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4141
|
+
applyTransform();
|
|
3511
4142
|
},
|
|
3512
4143
|
getZoom: () => scale,
|
|
3513
4144
|
setZoom: (level) => {
|
|
3514
4145
|
scale = level;
|
|
3515
|
-
|
|
4146
|
+
applyTransform();
|
|
3516
4147
|
},
|
|
3517
4148
|
fitToPage: () => {
|
|
3518
|
-
scale =
|
|
3519
|
-
|
|
4149
|
+
scale = calculateFitScale();
|
|
4150
|
+
rotation = 0;
|
|
4151
|
+
applyTransform();
|
|
4152
|
+
},
|
|
4153
|
+
rotateCW: () => {
|
|
4154
|
+
rotation = (rotation + 90) % 360;
|
|
4155
|
+
applyTransform();
|
|
4156
|
+
},
|
|
4157
|
+
rotateCCW: () => {
|
|
4158
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4159
|
+
applyTransform();
|
|
3520
4160
|
},
|
|
3521
4161
|
download: () => {
|
|
3522
4162
|
const blob = new Blob([ctx.buffer], { type: "application/rtf" });
|
|
@@ -3688,41 +4328,41 @@ var OpenDocumentPlugin = class {
|
|
|
3688
4328
|
}
|
|
3689
4329
|
getToolbarActions(instance) {
|
|
3690
4330
|
const isPresentation = instance.isPresentation;
|
|
4331
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3691
4332
|
const actions = [];
|
|
3692
|
-
if (isPresentation) {
|
|
3693
|
-
|
|
3694
|
-
{
|
|
4333
|
+
if (isPresentation || totalPages > 1) {
|
|
4334
|
+
if (isPresentation) {
|
|
4335
|
+
actions.push({
|
|
3695
4336
|
id: "thumbnails",
|
|
3696
4337
|
icon: "thumbnails",
|
|
3697
4338
|
label: "Slide Thumbnails",
|
|
3698
4339
|
type: "button",
|
|
3699
4340
|
group: "navigation",
|
|
3700
4341
|
execute: () => instance.toggleThumbnails?.()
|
|
3701
|
-
}
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
}
|
|
4342
|
+
});
|
|
4343
|
+
}
|
|
4344
|
+
actions.push({
|
|
4345
|
+
id: "page-nav",
|
|
4346
|
+
icon: "",
|
|
4347
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4348
|
+
type: "page-nav",
|
|
4349
|
+
group: "navigation",
|
|
4350
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4351
|
+
max: totalPages,
|
|
4352
|
+
execute: (action, page) => {
|
|
4353
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4354
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4355
|
+
if (action === "prev") {
|
|
4356
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4357
|
+
} else if (action === "next") {
|
|
4358
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4359
|
+
} else if (typeof page === "number") {
|
|
4360
|
+
instance.goToPage?.(page);
|
|
4361
|
+
} else if (typeof action === "number") {
|
|
4362
|
+
instance.goToPage?.(action);
|
|
3723
4363
|
}
|
|
3724
4364
|
}
|
|
3725
|
-
);
|
|
4365
|
+
});
|
|
3726
4366
|
}
|
|
3727
4367
|
actions.push(
|
|
3728
4368
|
{
|
|
@@ -3744,11 +4384,19 @@ var OpenDocumentPlugin = class {
|
|
|
3744
4384
|
{
|
|
3745
4385
|
id: "fit-page",
|
|
3746
4386
|
icon: "fit-page",
|
|
3747
|
-
label: "Fit to Page",
|
|
4387
|
+
label: isPresentation ? "Fit to Slide" : "Fit to Page",
|
|
3748
4388
|
type: "button",
|
|
3749
4389
|
group: "zoom",
|
|
3750
4390
|
execute: () => instance.fitToPage?.()
|
|
3751
4391
|
},
|
|
4392
|
+
{
|
|
4393
|
+
id: "rotate-cw",
|
|
4394
|
+
icon: "rotate-cw",
|
|
4395
|
+
label: "Rotate",
|
|
4396
|
+
type: "button",
|
|
4397
|
+
group: "view",
|
|
4398
|
+
execute: () => instance.rotateCW?.()
|
|
4399
|
+
},
|
|
3752
4400
|
{
|
|
3753
4401
|
id: "download",
|
|
3754
4402
|
icon: "download",
|
|
@@ -3812,6 +4460,22 @@ var OpenDocumentPlugin = class {
|
|
|
3812
4460
|
container.appendChild(wrapper);
|
|
3813
4461
|
ctx.container.appendChild(container);
|
|
3814
4462
|
let scale = 1;
|
|
4463
|
+
let rotation = 0;
|
|
4464
|
+
const calculateFitScale = () => {
|
|
4465
|
+
const elW = wrapper.offsetWidth || 850;
|
|
4466
|
+
const elH = wrapper.offsetHeight || (isPresentation ? 540 : 1e3);
|
|
4467
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4468
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4469
|
+
return Math.min(1, Math.min(availW / elW, availH / elH));
|
|
4470
|
+
};
|
|
4471
|
+
const applyTransform = () => {
|
|
4472
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4473
|
+
wrapper.style.transformOrigin = "top center";
|
|
4474
|
+
};
|
|
4475
|
+
setTimeout(() => {
|
|
4476
|
+
scale = calculateFitScale();
|
|
4477
|
+
applyTransform();
|
|
4478
|
+
}, 60);
|
|
3815
4479
|
let currentPage = 1;
|
|
3816
4480
|
let totalPages = 1;
|
|
3817
4481
|
let slides = [];
|
|
@@ -3870,21 +4534,30 @@ var OpenDocumentPlugin = class {
|
|
|
3870
4534
|
destroy: cleanup,
|
|
3871
4535
|
isPresentation,
|
|
3872
4536
|
zoomIn: () => {
|
|
3873
|
-
scale += 0.
|
|
3874
|
-
|
|
4537
|
+
scale += 0.15;
|
|
4538
|
+
applyTransform();
|
|
3875
4539
|
},
|
|
3876
4540
|
zoomOut: () => {
|
|
3877
|
-
scale = Math.max(0.2, scale - 0.
|
|
3878
|
-
|
|
4541
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
4542
|
+
applyTransform();
|
|
3879
4543
|
},
|
|
3880
4544
|
getZoom: () => scale,
|
|
3881
4545
|
setZoom: (level) => {
|
|
3882
4546
|
scale = level;
|
|
3883
|
-
|
|
4547
|
+
applyTransform();
|
|
3884
4548
|
},
|
|
3885
4549
|
fitToPage: () => {
|
|
3886
|
-
scale =
|
|
3887
|
-
|
|
4550
|
+
scale = calculateFitScale();
|
|
4551
|
+
rotation = 0;
|
|
4552
|
+
applyTransform();
|
|
4553
|
+
},
|
|
4554
|
+
rotateCW: () => {
|
|
4555
|
+
rotation = (rotation + 90) % 360;
|
|
4556
|
+
applyTransform();
|
|
4557
|
+
},
|
|
4558
|
+
rotateCCW: () => {
|
|
4559
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
4560
|
+
applyTransform();
|
|
3888
4561
|
},
|
|
3889
4562
|
goToPage,
|
|
3890
4563
|
getPageCount: () => totalPages,
|
|
@@ -4105,7 +4778,31 @@ var DocPlugin = class {
|
|
|
4105
4778
|
return this.mimeTypes.includes(mime || "");
|
|
4106
4779
|
}
|
|
4107
4780
|
getToolbarActions(instance) {
|
|
4108
|
-
|
|
4781
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4782
|
+
const actions = [];
|
|
4783
|
+
if (totalPages > 1) {
|
|
4784
|
+
actions.push({
|
|
4785
|
+
id: "page-nav",
|
|
4786
|
+
icon: "",
|
|
4787
|
+
label: "Page Navigation",
|
|
4788
|
+
type: "page-nav",
|
|
4789
|
+
group: "navigation",
|
|
4790
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4791
|
+
max: totalPages,
|
|
4792
|
+
execute: (action, page) => {
|
|
4793
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4794
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4795
|
+
if (action === "prev") {
|
|
4796
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4797
|
+
} else if (action === "next") {
|
|
4798
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4799
|
+
} else if (typeof page === "number") {
|
|
4800
|
+
instance.goToPage?.(page);
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
});
|
|
4804
|
+
}
|
|
4805
|
+
actions.push(
|
|
4109
4806
|
{
|
|
4110
4807
|
id: "zoom-out",
|
|
4111
4808
|
icon: "zoom-out",
|
|
@@ -4130,6 +4827,14 @@ var DocPlugin = class {
|
|
|
4130
4827
|
group: "zoom",
|
|
4131
4828
|
execute: () => instance.fitToPage?.()
|
|
4132
4829
|
},
|
|
4830
|
+
{
|
|
4831
|
+
id: "rotate-cw",
|
|
4832
|
+
icon: "rotate-cw",
|
|
4833
|
+
label: "Rotate",
|
|
4834
|
+
type: "button",
|
|
4835
|
+
group: "view",
|
|
4836
|
+
execute: () => instance.rotateCW?.()
|
|
4837
|
+
},
|
|
4133
4838
|
{
|
|
4134
4839
|
id: "copy",
|
|
4135
4840
|
icon: "copy",
|
|
@@ -4154,7 +4859,8 @@ var DocPlugin = class {
|
|
|
4154
4859
|
group: "actions",
|
|
4155
4860
|
execute: () => instance.print?.()
|
|
4156
4861
|
}
|
|
4157
|
-
|
|
4862
|
+
);
|
|
4863
|
+
return actions;
|
|
4158
4864
|
}
|
|
4159
4865
|
async render(ctx) {
|
|
4160
4866
|
const container = document.createElement("div");
|
|
@@ -4181,6 +4887,7 @@ var DocPlugin = class {
|
|
|
4181
4887
|
ctx.container.appendChild(container);
|
|
4182
4888
|
let scale = 1;
|
|
4183
4889
|
let extractedRawText = "";
|
|
4890
|
+
let isFallback = false;
|
|
4184
4891
|
try {
|
|
4185
4892
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4186
4893
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4194,42 +4901,131 @@ var DocPlugin = class {
|
|
|
4194
4901
|
const tableStream = cfbf.readStream(tableName);
|
|
4195
4902
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4196
4903
|
extractedRawText = text;
|
|
4197
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4198
4904
|
} catch (err) {
|
|
4199
4905
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4200
4906
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4201
4907
|
extractedRawText = fallback;
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4908
|
+
isFallback = true;
|
|
4909
|
+
}
|
|
4910
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4911
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4912
|
+
let currentPage = 1;
|
|
4913
|
+
wrapper.innerHTML = "";
|
|
4914
|
+
const pageCards = [];
|
|
4915
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4916
|
+
const pageCard = document.createElement("div");
|
|
4917
|
+
pageCard.className = "fp-doc-page-card";
|
|
4918
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4919
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4920
|
+
pageCard.style.borderRadius = "4px";
|
|
4921
|
+
pageCard.style.padding = "56px 48px";
|
|
4922
|
+
pageCard.style.minHeight = "100%";
|
|
4923
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4924
|
+
if (isFallback && i === 0) {
|
|
4925
|
+
pageCard.innerHTML = `
|
|
4926
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4927
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4928
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4929
|
+
</div>
|
|
4930
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4931
|
+
`;
|
|
4932
|
+
} else {
|
|
4933
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4934
|
+
}
|
|
4935
|
+
wrapper.appendChild(pageCard);
|
|
4936
|
+
pageCards.push(pageCard);
|
|
4937
|
+
}
|
|
4938
|
+
let indicator = null;
|
|
4939
|
+
if (totalPages > 1) {
|
|
4940
|
+
indicator = document.createElement("div");
|
|
4941
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4942
|
+
indicator.style.position = "sticky";
|
|
4943
|
+
indicator.style.bottom = "16px";
|
|
4944
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4945
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4946
|
+
indicator.style.color = "#f8fafc";
|
|
4947
|
+
indicator.style.fontSize = "12px";
|
|
4948
|
+
indicator.style.fontWeight = "600";
|
|
4949
|
+
indicator.style.padding = "5px 14px";
|
|
4950
|
+
indicator.style.borderRadius = "20px";
|
|
4951
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4952
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4953
|
+
indicator.style.zIndex = "10";
|
|
4954
|
+
indicator.style.userSelect = "none";
|
|
4955
|
+
indicator.style.pointerEvents = "none";
|
|
4956
|
+
indicator.style.textAlign = "center";
|
|
4957
|
+
indicator.style.width = "fit-content";
|
|
4958
|
+
indicator.style.margin = "16px auto 0";
|
|
4959
|
+
container.appendChild(indicator);
|
|
4960
|
+
}
|
|
4961
|
+
const showPage = (pageNum) => {
|
|
4962
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4963
|
+
if (totalPages > 1) {
|
|
4964
|
+
pageCards.forEach((card, idx) => {
|
|
4965
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4966
|
+
});
|
|
4967
|
+
}
|
|
4968
|
+
if (indicator) {
|
|
4969
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4970
|
+
}
|
|
4971
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4972
|
+
};
|
|
4973
|
+
if (totalPages > 1) {
|
|
4974
|
+
showPage(1);
|
|
4209
4975
|
}
|
|
4976
|
+
let rotation = 0;
|
|
4977
|
+
const calculateFitScale = () => {
|
|
4978
|
+
const activeCard = pageCards[currentPage - 1] || wrapper;
|
|
4979
|
+
const elW = activeCard.offsetWidth || 850;
|
|
4980
|
+
const elH = activeCard.offsetHeight || 1e3;
|
|
4981
|
+
const availW = Math.max(200, ctx.container.clientWidth - 48);
|
|
4982
|
+
const availH = Math.max(200, ctx.container.clientHeight - 80);
|
|
4983
|
+
return Math.min(1.1, Math.min(availW / elW, availH / elH));
|
|
4984
|
+
};
|
|
4985
|
+
const applyTransform = () => {
|
|
4986
|
+
wrapper.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
4987
|
+
wrapper.style.transformOrigin = "top center";
|
|
4988
|
+
};
|
|
4989
|
+
setTimeout(() => {
|
|
4990
|
+
scale = calculateFitScale();
|
|
4991
|
+
applyTransform();
|
|
4992
|
+
}, 60);
|
|
4210
4993
|
const cleanup = () => {
|
|
4994
|
+
indicator?.remove();
|
|
4211
4995
|
container.remove();
|
|
4212
4996
|
ctx.container.innerHTML = "";
|
|
4213
4997
|
};
|
|
4214
4998
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4215
4999
|
return {
|
|
4216
5000
|
destroy: cleanup,
|
|
5001
|
+
getPageCount: () => totalPages,
|
|
5002
|
+
getCurrentPage: () => currentPage,
|
|
5003
|
+
goToPage: (page) => showPage(page),
|
|
4217
5004
|
zoomIn: () => {
|
|
4218
|
-
scale += 0.
|
|
4219
|
-
|
|
5005
|
+
scale += 0.15;
|
|
5006
|
+
applyTransform();
|
|
4220
5007
|
},
|
|
4221
5008
|
zoomOut: () => {
|
|
4222
|
-
scale = Math.max(0.2, scale - 0.
|
|
4223
|
-
|
|
5009
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5010
|
+
applyTransform();
|
|
4224
5011
|
},
|
|
4225
5012
|
getZoom: () => scale,
|
|
4226
5013
|
setZoom: (level) => {
|
|
4227
5014
|
scale = level;
|
|
4228
|
-
|
|
5015
|
+
applyTransform();
|
|
4229
5016
|
},
|
|
4230
5017
|
fitToPage: () => {
|
|
4231
|
-
scale =
|
|
4232
|
-
|
|
5018
|
+
scale = calculateFitScale();
|
|
5019
|
+
rotation = 0;
|
|
5020
|
+
applyTransform();
|
|
5021
|
+
},
|
|
5022
|
+
rotateCW: () => {
|
|
5023
|
+
rotation = (rotation + 90) % 360;
|
|
5024
|
+
applyTransform();
|
|
5025
|
+
},
|
|
5026
|
+
rotateCCW: () => {
|
|
5027
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5028
|
+
applyTransform();
|
|
4233
5029
|
},
|
|
4234
5030
|
copy: () => {
|
|
4235
5031
|
navigator.clipboard.writeText(extractedRawText);
|
|
@@ -4345,11 +5141,16 @@ var DocPlugin = class {
|
|
|
4345
5141
|
heuristicTextExtraction(buffer) {
|
|
4346
5142
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4347
5143
|
}
|
|
5144
|
+
splitIntoPages(text) {
|
|
5145
|
+
if (!text) return [""];
|
|
5146
|
+
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);
|
|
5147
|
+
return parts.length > 0 ? parts : [text];
|
|
5148
|
+
}
|
|
4348
5149
|
/**
|
|
4349
5150
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4350
5151
|
*/
|
|
4351
5152
|
formatDocToHtml(text, filename) {
|
|
4352
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
5153
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4353
5154
|
let html = "";
|
|
4354
5155
|
let inList = false;
|
|
4355
5156
|
for (const rawLine of lines) {
|
|
@@ -4464,6 +5265,14 @@ var PptPlugin = class {
|
|
|
4464
5265
|
group: "zoom",
|
|
4465
5266
|
execute: () => instance.fitToPage?.()
|
|
4466
5267
|
},
|
|
5268
|
+
{
|
|
5269
|
+
id: "rotate-cw",
|
|
5270
|
+
icon: "rotate-cw",
|
|
5271
|
+
label: "Rotate",
|
|
5272
|
+
type: "button",
|
|
5273
|
+
group: "view",
|
|
5274
|
+
execute: () => instance.rotateCW?.()
|
|
5275
|
+
},
|
|
4467
5276
|
{
|
|
4468
5277
|
id: "download",
|
|
4469
5278
|
icon: "download",
|
|
@@ -4497,22 +5306,36 @@ var PptPlugin = class {
|
|
|
4497
5306
|
const slideCard = document.createElement("div");
|
|
4498
5307
|
slideCard.className = "fp-ppt-slide-card";
|
|
4499
5308
|
slideCard.style.width = "960px";
|
|
4500
|
-
slideCard.style.maxWidth = "
|
|
5309
|
+
slideCard.style.maxWidth = "calc(100% - 32px)";
|
|
5310
|
+
slideCard.style.maxHeight = "calc(100% - 48px)";
|
|
4501
5311
|
slideCard.style.aspectRatio = "16 / 9";
|
|
4502
5312
|
slideCard.style.backgroundColor = "#ffffff";
|
|
4503
5313
|
slideCard.style.boxShadow = "0 12px 40px rgba(0,0,0,0.35)";
|
|
4504
5314
|
slideCard.style.borderRadius = "8px";
|
|
4505
5315
|
slideCard.style.boxSizing = "border-box";
|
|
4506
5316
|
slideCard.style.position = "relative";
|
|
4507
|
-
slideCard.style.overflow = "hidden";
|
|
4508
|
-
slideCard.style.transformOrigin = "center center";
|
|
4509
5317
|
slideCard.style.transition = "transform 0.2s ease";
|
|
5318
|
+
slideCard.style.transformOrigin = "center center";
|
|
5319
|
+
slideCard.style.flexShrink = "0";
|
|
4510
5320
|
container.appendChild(slideCard);
|
|
4511
5321
|
ctx.container.appendChild(container);
|
|
4512
5322
|
let scale = 1;
|
|
5323
|
+
let rotation = 0;
|
|
4513
5324
|
let currentSlide = 1;
|
|
4514
5325
|
let slides = [];
|
|
4515
5326
|
const createdBlobUrls = [];
|
|
5327
|
+
const calculateFitScale = () => {
|
|
5328
|
+
const availW = Math.max(200, container.clientWidth - 48);
|
|
5329
|
+
const availH = Math.max(200, container.clientHeight - 72);
|
|
5330
|
+
return Math.min(1, Math.min(availW / 960, availH / 540));
|
|
5331
|
+
};
|
|
5332
|
+
const applyTransform = () => {
|
|
5333
|
+
slideCard.style.transform = `scale(${scale}) rotate(${rotation}deg)`;
|
|
5334
|
+
};
|
|
5335
|
+
setTimeout(() => {
|
|
5336
|
+
scale = calculateFitScale();
|
|
5337
|
+
applyTransform();
|
|
5338
|
+
}, 60);
|
|
4516
5339
|
try {
|
|
4517
5340
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4518
5341
|
const pptStream = cfbf.readStream("PowerPoint Document");
|
|
@@ -4613,21 +5436,30 @@ var PptPlugin = class {
|
|
|
4613
5436
|
return {
|
|
4614
5437
|
destroy: cleanup,
|
|
4615
5438
|
zoomIn: () => {
|
|
4616
|
-
scale += 0.
|
|
4617
|
-
|
|
5439
|
+
scale += 0.15;
|
|
5440
|
+
applyTransform();
|
|
4618
5441
|
},
|
|
4619
5442
|
zoomOut: () => {
|
|
4620
|
-
scale = Math.max(0.
|
|
4621
|
-
|
|
5443
|
+
scale = Math.max(0.2, scale - 0.15);
|
|
5444
|
+
applyTransform();
|
|
4622
5445
|
},
|
|
4623
5446
|
getZoom: () => scale,
|
|
4624
5447
|
setZoom: (level) => {
|
|
4625
5448
|
scale = level;
|
|
4626
|
-
|
|
5449
|
+
applyTransform();
|
|
4627
5450
|
},
|
|
4628
5451
|
fitToPage: () => {
|
|
4629
|
-
scale =
|
|
4630
|
-
|
|
5452
|
+
scale = calculateFitScale();
|
|
5453
|
+
rotation = 0;
|
|
5454
|
+
applyTransform();
|
|
5455
|
+
},
|
|
5456
|
+
rotateCW: () => {
|
|
5457
|
+
rotation = (rotation + 90) % 360;
|
|
5458
|
+
applyTransform();
|
|
5459
|
+
},
|
|
5460
|
+
rotateCCW: () => {
|
|
5461
|
+
rotation = (rotation - 90 + 360) % 360;
|
|
5462
|
+
applyTransform();
|
|
4631
5463
|
},
|
|
4632
5464
|
goToPage: (page) => {
|
|
4633
5465
|
if (page >= 1 && page <= totalSlides) {
|