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