@files-preview-app/preview-file 1.2.4 → 1.2.5
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 +645 -158
- package/dist/angular.cjs.map +1 -1
- package/dist/angular.js +644 -158
- package/dist/angular.js.map +1 -1
- package/dist/index.cjs +645 -158
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +644 -158
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +645 -158
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +644 -158
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +645 -158
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.js +644 -158
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
package/dist/angular.cjs
CHANGED
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var core = require('@angular/core');
|
|
6
6
|
var common = require('@angular/common');
|
|
7
7
|
var DOMPurify2 = require('dompurify');
|
|
8
|
+
var pdfjsLib = require('pdfjs-dist');
|
|
8
9
|
var docx = require('docx-preview');
|
|
9
10
|
var fflate = require('fflate');
|
|
10
11
|
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);
|
|
@@ -558,11 +560,21 @@ var ToolbarController = class {
|
|
|
558
560
|
el;
|
|
559
561
|
toolbarEl;
|
|
560
562
|
actions = [];
|
|
563
|
+
pageInputEl = null;
|
|
564
|
+
pageLabelEl = null;
|
|
561
565
|
constructor(container) {
|
|
562
566
|
this.el = container;
|
|
563
567
|
this.toolbarEl = createElement("div", { className: "fp-toolbar" });
|
|
564
568
|
this.el.appendChild(this.toolbarEl);
|
|
565
569
|
}
|
|
570
|
+
setPage(page, max) {
|
|
571
|
+
if (this.pageInputEl) {
|
|
572
|
+
this.pageInputEl.value = page.toString();
|
|
573
|
+
}
|
|
574
|
+
if (max !== void 0 && this.pageLabelEl) {
|
|
575
|
+
this.pageLabelEl.textContent = ` / ${max}`;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
566
578
|
update(actions) {
|
|
567
579
|
this.actions = actions;
|
|
568
580
|
this.render();
|
|
@@ -605,6 +617,7 @@ var ToolbarController = class {
|
|
|
605
617
|
if (action.type === "separator") {
|
|
606
618
|
groupEl.appendChild(createElement("div", { className: "fp-toolbar-separator" }));
|
|
607
619
|
} else if (action.type === "page-nav") {
|
|
620
|
+
const max = action.max ?? 1;
|
|
608
621
|
const prevBtn = this.createButton(
|
|
609
622
|
"prev",
|
|
610
623
|
ICON_PAGE_PREV,
|
|
@@ -623,7 +636,6 @@ var ToolbarController = class {
|
|
|
623
636
|
"Next Page",
|
|
624
637
|
() => {
|
|
625
638
|
const cur = parseInt(input.value, 10) || 1;
|
|
626
|
-
const max = action.max ?? 1;
|
|
627
639
|
if (cur < max) {
|
|
628
640
|
input.value = (cur + 1).toString();
|
|
629
641
|
action.execute("next", cur + 1);
|
|
@@ -635,15 +647,18 @@ var ToolbarController = class {
|
|
|
635
647
|
type: "number",
|
|
636
648
|
value: (action.value ?? 1).toString(),
|
|
637
649
|
min: "1",
|
|
638
|
-
max:
|
|
650
|
+
max: max.toString()
|
|
639
651
|
});
|
|
640
652
|
input.addEventListener("change", () => {
|
|
641
|
-
|
|
642
|
-
if (
|
|
643
|
-
|
|
644
|
-
|
|
653
|
+
let val = parseInt(input.value, 10);
|
|
654
|
+
if (isNaN(val)) val = 1;
|
|
655
|
+
val = Math.max(1, Math.min(max, val));
|
|
656
|
+
input.value = val.toString();
|
|
657
|
+
action.execute("go", val);
|
|
645
658
|
});
|
|
646
|
-
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${
|
|
659
|
+
const label = createElement("span", { className: "fp-toolbar-label" }, ` / ${max}`);
|
|
660
|
+
this.pageInputEl = input;
|
|
661
|
+
this.pageLabelEl = label;
|
|
647
662
|
groupEl.appendChild(prevBtn);
|
|
648
663
|
groupEl.appendChild(input);
|
|
649
664
|
groupEl.appendChild(label);
|
|
@@ -821,7 +836,13 @@ var FilePreviewViewer = class {
|
|
|
821
836
|
buffer,
|
|
822
837
|
options,
|
|
823
838
|
signal,
|
|
824
|
-
emit: (event, payload) =>
|
|
839
|
+
emit: (event, payload) => {
|
|
840
|
+
if (event === "page-change" && payload && typeof payload.page === "number") {
|
|
841
|
+
const total = payload.total ?? payload.totalPages;
|
|
842
|
+
this.toolbar?.setPage(payload.page, total);
|
|
843
|
+
}
|
|
844
|
+
this.eventEmitter.emit(event, payload);
|
|
845
|
+
}
|
|
825
846
|
});
|
|
826
847
|
this.activeInstance = instance;
|
|
827
848
|
this.hideLoading();
|
|
@@ -855,6 +876,7 @@ var FilePreviewViewer = class {
|
|
|
855
876
|
if (thumbnails && thumbnails.length > 0 && this.thumbnailPanel) {
|
|
856
877
|
this.thumbnailPanel.update(thumbnails, (index) => {
|
|
857
878
|
instance.goToPage?.(index + 1);
|
|
879
|
+
this.toolbar?.setPage(index + 1);
|
|
858
880
|
});
|
|
859
881
|
if (options.showThumbnails) {
|
|
860
882
|
this.thumbnailPanel.show();
|
|
@@ -980,9 +1002,13 @@ var FilePreviewViewer = class {
|
|
|
980
1002
|
if (e.key === "ArrowRight" || e.key === "PageDown") {
|
|
981
1003
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
982
1004
|
this.activeInstance.goToPage?.(cur + 1);
|
|
1005
|
+
const nextCur = this.activeInstance.getCurrentPage?.() ?? cur + 1;
|
|
1006
|
+
this.toolbar?.setPage(nextCur);
|
|
983
1007
|
} else if (e.key === "ArrowLeft" || e.key === "PageUp") {
|
|
984
1008
|
const cur = this.activeInstance.getCurrentPage?.() ?? 1;
|
|
985
1009
|
this.activeInstance.goToPage?.(Math.max(1, cur - 1));
|
|
1010
|
+
const prevCur = this.activeInstance.getCurrentPage?.() ?? Math.max(1, cur - 1);
|
|
1011
|
+
this.toolbar?.setPage(prevCur);
|
|
986
1012
|
} else if (e.key === "+" || e.key === "=") {
|
|
987
1013
|
this.activeInstance.zoomIn?.();
|
|
988
1014
|
} else if (e.key === "-" || e.key === "_") {
|
|
@@ -1248,30 +1274,62 @@ var CfbfReader = class {
|
|
|
1248
1274
|
return result.subarray(0, targetSize);
|
|
1249
1275
|
}
|
|
1250
1276
|
};
|
|
1251
|
-
|
|
1252
|
-
|
|
1277
|
+
if (typeof window !== "undefined" && pdfjsLib__namespace.GlobalWorkerOptions) {
|
|
1278
|
+
if (!pdfjsLib__namespace.GlobalWorkerOptions.workerSrc) {
|
|
1279
|
+
pdfjsLib__namespace.GlobalWorkerOptions.workerSrc = `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/build/pdf.worker.min.mjs`;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1253
1282
|
var PdfPlugin = class {
|
|
1254
1283
|
id = "pdf";
|
|
1255
|
-
name = "PDF Preview";
|
|
1284
|
+
name = "PDF Document Preview";
|
|
1256
1285
|
extensions = [".pdf"];
|
|
1257
1286
|
mimeTypes = ["application/pdf"];
|
|
1258
1287
|
weight = 100;
|
|
1259
1288
|
supports(file) {
|
|
1260
1289
|
const ext = file.metadata.extension?.toLowerCase();
|
|
1261
1290
|
const mime = file.metadata.mimeType?.toLowerCase();
|
|
1262
|
-
|
|
1291
|
+
if (ext) return this.extensions.includes(ext);
|
|
1292
|
+
return this.mimeTypes.includes(mime || "");
|
|
1263
1293
|
}
|
|
1264
1294
|
getToolbarActions(instance) {
|
|
1295
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1296
|
+
const curPage = instance.getCurrentPage?.() ?? 1;
|
|
1265
1297
|
return [
|
|
1298
|
+
{
|
|
1299
|
+
id: "thumbnails",
|
|
1300
|
+
icon: "thumbnails",
|
|
1301
|
+
label: "Page Thumbnails",
|
|
1302
|
+
type: "button",
|
|
1303
|
+
group: "navigation",
|
|
1304
|
+
execute: () => instance.toggleThumbnails?.()
|
|
1305
|
+
},
|
|
1306
|
+
{
|
|
1307
|
+
id: "page-nav",
|
|
1308
|
+
icon: "",
|
|
1309
|
+
label: "Page Navigation",
|
|
1310
|
+
type: "page-nav",
|
|
1311
|
+
group: "navigation",
|
|
1312
|
+
value: curPage,
|
|
1313
|
+
max: totalPages,
|
|
1314
|
+
execute: (action, page) => {
|
|
1315
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1316
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1317
|
+
if (action === "prev") {
|
|
1318
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1319
|
+
} else if (action === "next") {
|
|
1320
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1321
|
+
} else if (typeof page === "number") {
|
|
1322
|
+
instance.goToPage?.(page);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
},
|
|
1266
1326
|
{
|
|
1267
1327
|
id: "zoom-out",
|
|
1268
1328
|
icon: "zoom-out",
|
|
1269
1329
|
label: "Zoom Out",
|
|
1270
1330
|
type: "button",
|
|
1271
1331
|
group: "zoom",
|
|
1272
|
-
execute: () =>
|
|
1273
|
-
instance.zoomOut?.();
|
|
1274
|
-
}
|
|
1332
|
+
execute: () => instance.zoomOut?.()
|
|
1275
1333
|
},
|
|
1276
1334
|
{
|
|
1277
1335
|
id: "zoom-in",
|
|
@@ -1279,9 +1337,7 @@ var PdfPlugin = class {
|
|
|
1279
1337
|
label: "Zoom In",
|
|
1280
1338
|
type: "button",
|
|
1281
1339
|
group: "zoom",
|
|
1282
|
-
execute: () =>
|
|
1283
|
-
instance.zoomIn?.();
|
|
1284
|
-
}
|
|
1340
|
+
execute: () => instance.zoomIn?.()
|
|
1285
1341
|
},
|
|
1286
1342
|
{
|
|
1287
1343
|
id: "fit-page",
|
|
@@ -1289,39 +1345,23 @@ var PdfPlugin = class {
|
|
|
1289
1345
|
label: "Fit to Page",
|
|
1290
1346
|
type: "button",
|
|
1291
1347
|
group: "zoom",
|
|
1292
|
-
execute: () =>
|
|
1293
|
-
instance.fitToPage?.();
|
|
1294
|
-
}
|
|
1348
|
+
execute: () => instance.fitToPage?.()
|
|
1295
1349
|
},
|
|
1296
1350
|
{
|
|
1297
1351
|
id: "rotate-cw",
|
|
1298
1352
|
icon: "rotate-cw",
|
|
1299
|
-
label: "Rotate",
|
|
1353
|
+
label: "Rotate Clockwise",
|
|
1300
1354
|
type: "button",
|
|
1301
1355
|
group: "view",
|
|
1302
|
-
execute: () =>
|
|
1303
|
-
instance.rotateCW?.();
|
|
1304
|
-
}
|
|
1305
|
-
},
|
|
1306
|
-
{
|
|
1307
|
-
id: "page-nav",
|
|
1308
|
-
icon: "page-nav",
|
|
1309
|
-
label: "Page Navigation",
|
|
1310
|
-
type: "page-nav",
|
|
1311
|
-
group: "navigation",
|
|
1312
|
-
execute: (page) => {
|
|
1313
|
-
if (typeof page === "number") instance.goToPage?.(page);
|
|
1314
|
-
}
|
|
1356
|
+
execute: () => instance.rotateCW?.()
|
|
1315
1357
|
},
|
|
1316
1358
|
{
|
|
1317
1359
|
id: "download",
|
|
1318
1360
|
icon: "download",
|
|
1319
|
-
label: "Download",
|
|
1361
|
+
label: "Download PDF",
|
|
1320
1362
|
type: "button",
|
|
1321
1363
|
group: "actions",
|
|
1322
|
-
execute: () =>
|
|
1323
|
-
instance.download?.();
|
|
1324
|
-
}
|
|
1364
|
+
execute: () => instance.download?.()
|
|
1325
1365
|
},
|
|
1326
1366
|
{
|
|
1327
1367
|
id: "print",
|
|
@@ -1329,99 +1369,213 @@ var PdfPlugin = class {
|
|
|
1329
1369
|
label: "Print",
|
|
1330
1370
|
type: "button",
|
|
1331
1371
|
group: "actions",
|
|
1332
|
-
execute: () =>
|
|
1333
|
-
instance.print?.();
|
|
1334
|
-
}
|
|
1372
|
+
execute: () => instance.print?.()
|
|
1335
1373
|
}
|
|
1336
1374
|
];
|
|
1337
1375
|
}
|
|
1338
1376
|
async render(ctx) {
|
|
1339
|
-
const
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1377
|
+
const container = document.createElement("div");
|
|
1378
|
+
container.className = "fp-pdf-container";
|
|
1379
|
+
container.style.width = "100%";
|
|
1380
|
+
container.style.height = "100%";
|
|
1381
|
+
container.style.overflow = "auto";
|
|
1382
|
+
container.style.display = "flex";
|
|
1383
|
+
container.style.flexDirection = "column";
|
|
1384
|
+
container.style.alignItems = "center";
|
|
1385
|
+
container.style.padding = "24px 16px";
|
|
1386
|
+
container.style.backgroundColor = "#0f172a";
|
|
1387
|
+
container.style.boxSizing = "border-box";
|
|
1388
|
+
container.style.position = "relative";
|
|
1389
|
+
const pageCard = document.createElement("div");
|
|
1390
|
+
pageCard.className = "fp-pdf-page-card";
|
|
1391
|
+
pageCard.style.boxShadow = "0 10px 35px rgba(0, 0, 0, 0.5)";
|
|
1392
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
1393
|
+
pageCard.style.borderRadius = "4px";
|
|
1394
|
+
pageCard.style.overflow = "hidden";
|
|
1395
|
+
pageCard.style.lineHeight = "0";
|
|
1396
|
+
pageCard.style.transition = "transform 0.15s ease";
|
|
1397
|
+
pageCard.style.position = "relative";
|
|
1398
|
+
const canvas = document.createElement("canvas");
|
|
1399
|
+
pageCard.appendChild(canvas);
|
|
1400
|
+
container.appendChild(pageCard);
|
|
1401
|
+
const indicator = document.createElement("div");
|
|
1402
|
+
indicator.className = "fp-pdf-page-indicator";
|
|
1403
|
+
indicator.style.position = "sticky";
|
|
1404
|
+
indicator.style.bottom = "16px";
|
|
1405
|
+
indicator.style.marginTop = "16px";
|
|
1406
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
1407
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
1408
|
+
indicator.style.color = "#f8fafc";
|
|
1409
|
+
indicator.style.fontSize = "12px";
|
|
1410
|
+
indicator.style.fontWeight = "600";
|
|
1411
|
+
indicator.style.padding = "5px 14px";
|
|
1412
|
+
indicator.style.borderRadius = "20px";
|
|
1413
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
1414
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
1415
|
+
indicator.style.zIndex = "10";
|
|
1416
|
+
indicator.style.userSelect = "none";
|
|
1417
|
+
indicator.style.pointerEvents = "none";
|
|
1418
|
+
container.appendChild(indicator);
|
|
1419
|
+
ctx.container.appendChild(container);
|
|
1420
|
+
const loadingTask = pdfjsLib__namespace.getDocument({
|
|
1421
|
+
data: new Uint8Array(ctx.buffer),
|
|
1422
|
+
cMapUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/cmaps/`,
|
|
1423
|
+
cMapPacked: true,
|
|
1424
|
+
standardFontDataUrl: `https://unpkg.com/pdfjs-dist@${pdfjsLib__namespace.version || "4.10.38"}/standard_fonts/`
|
|
1425
|
+
});
|
|
1426
|
+
const pdfDoc = await loadingTask.promise;
|
|
1427
|
+
const totalPages = Math.max(1, pdfDoc.numPages);
|
|
1355
1428
|
let currentPage = 1;
|
|
1356
|
-
let
|
|
1429
|
+
let zoomScale = 1;
|
|
1357
1430
|
let rotation = 0;
|
|
1431
|
+
let currentRenderTask = null;
|
|
1432
|
+
const renderPage = async (pageNum) => {
|
|
1433
|
+
if (currentRenderTask) {
|
|
1434
|
+
try {
|
|
1435
|
+
currentRenderTask.cancel();
|
|
1436
|
+
} catch {
|
|
1437
|
+
}
|
|
1438
|
+
currentRenderTask = null;
|
|
1439
|
+
}
|
|
1440
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
1441
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
1442
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
1443
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
1444
|
+
const containerWidth = container.clientWidth || 900;
|
|
1445
|
+
const unscaledVp = page.getViewport({ scale: 1, rotation });
|
|
1446
|
+
const baseScale = Math.min((containerWidth - 64) / unscaledVp.width, 1.6);
|
|
1447
|
+
const effectiveScale = (baseScale > 0 ? baseScale : 1) * zoomScale;
|
|
1448
|
+
const pixelRatio = window.devicePixelRatio || 1;
|
|
1449
|
+
const viewport = page.getViewport({ scale: effectiveScale, rotation });
|
|
1450
|
+
canvas.width = Math.floor(viewport.width * pixelRatio);
|
|
1451
|
+
canvas.height = Math.floor(viewport.height * pixelRatio);
|
|
1452
|
+
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
|
1453
|
+
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
|
1454
|
+
const canvasCtx = canvas.getContext("2d");
|
|
1455
|
+
if (!canvasCtx) return;
|
|
1456
|
+
canvasCtx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
|
|
1457
|
+
currentRenderTask = page.render({
|
|
1458
|
+
canvasContext: canvasCtx,
|
|
1459
|
+
viewport
|
|
1460
|
+
});
|
|
1461
|
+
try {
|
|
1462
|
+
await currentRenderTask.promise;
|
|
1463
|
+
} catch (err) {
|
|
1464
|
+
if (err?.name !== "RenderingCancelledException") {
|
|
1465
|
+
console.warn("[PdfPlugin] Page render warning:", err);
|
|
1466
|
+
}
|
|
1467
|
+
} finally {
|
|
1468
|
+
currentRenderTask = null;
|
|
1469
|
+
}
|
|
1470
|
+
};
|
|
1471
|
+
await renderPage(1);
|
|
1358
1472
|
const cleanup = () => {
|
|
1359
|
-
|
|
1360
|
-
|
|
1473
|
+
if (currentRenderTask) {
|
|
1474
|
+
try {
|
|
1475
|
+
currentRenderTask.cancel();
|
|
1476
|
+
} catch {
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
try {
|
|
1480
|
+
pdfDoc.destroy();
|
|
1481
|
+
} catch {
|
|
1482
|
+
}
|
|
1483
|
+
container.remove();
|
|
1361
1484
|
ctx.container.innerHTML = "";
|
|
1362
1485
|
};
|
|
1363
1486
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1364
|
-
|
|
1487
|
+
const instance = {
|
|
1365
1488
|
destroy: cleanup,
|
|
1366
1489
|
zoomIn: () => {
|
|
1367
|
-
|
|
1368
|
-
|
|
1490
|
+
zoomScale = Math.min(3.5, zoomScale + 0.2);
|
|
1491
|
+
renderPage(currentPage);
|
|
1369
1492
|
},
|
|
1370
1493
|
zoomOut: () => {
|
|
1371
|
-
|
|
1372
|
-
|
|
1494
|
+
zoomScale = Math.max(0.3, zoomScale - 0.2);
|
|
1495
|
+
renderPage(currentPage);
|
|
1373
1496
|
},
|
|
1374
|
-
getZoom: () =>
|
|
1497
|
+
getZoom: () => zoomScale,
|
|
1375
1498
|
setZoom: (level) => {
|
|
1376
|
-
|
|
1377
|
-
|
|
1499
|
+
zoomScale = Math.max(0.3, Math.min(3.5, level));
|
|
1500
|
+
renderPage(currentPage);
|
|
1378
1501
|
},
|
|
1379
1502
|
fitToPage: () => {
|
|
1380
|
-
|
|
1381
|
-
|
|
1503
|
+
zoomScale = 1;
|
|
1504
|
+
renderPage(currentPage);
|
|
1382
1505
|
},
|
|
1383
1506
|
rotateCW: () => {
|
|
1384
1507
|
rotation = (rotation + 90) % 360;
|
|
1385
|
-
|
|
1508
|
+
renderPage(currentPage);
|
|
1386
1509
|
},
|
|
1387
1510
|
rotateCCW: () => {
|
|
1388
1511
|
rotation = (rotation - 90 + 360) % 360;
|
|
1389
|
-
|
|
1512
|
+
renderPage(currentPage);
|
|
1390
1513
|
},
|
|
1391
1514
|
getRotation: () => rotation,
|
|
1515
|
+
getPageCount: () => totalPages,
|
|
1516
|
+
getCurrentPage: () => currentPage,
|
|
1392
1517
|
goToPage: (page) => {
|
|
1393
|
-
|
|
1394
|
-
iframe.src = `${url}#page=${page}`;
|
|
1518
|
+
renderPage(page);
|
|
1395
1519
|
},
|
|
1396
|
-
getCurrentPage: () => currentPage,
|
|
1397
1520
|
download: () => {
|
|
1521
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1522
|
+
const url = URL.createObjectURL(blob);
|
|
1398
1523
|
const a = document.createElement("a");
|
|
1399
1524
|
a.href = url;
|
|
1400
1525
|
a.download = ctx.metadata.name || "document.pdf";
|
|
1401
1526
|
a.click();
|
|
1527
|
+
URL.revokeObjectURL(url);
|
|
1402
1528
|
},
|
|
1403
1529
|
print: () => {
|
|
1404
|
-
|
|
1530
|
+
const blob = new Blob([ctx.buffer], { type: "application/pdf" });
|
|
1531
|
+
const url = URL.createObjectURL(blob);
|
|
1532
|
+
const hiddenIframe = document.createElement("iframe");
|
|
1533
|
+
hiddenIframe.style.position = "fixed";
|
|
1534
|
+
hiddenIframe.style.right = "0";
|
|
1535
|
+
hiddenIframe.style.bottom = "0";
|
|
1536
|
+
hiddenIframe.style.width = "0";
|
|
1537
|
+
hiddenIframe.style.height = "0";
|
|
1538
|
+
hiddenIframe.style.border = "0";
|
|
1539
|
+
document.body.appendChild(hiddenIframe);
|
|
1540
|
+
hiddenIframe.src = url;
|
|
1541
|
+
hiddenIframe.onload = () => {
|
|
1542
|
+
setTimeout(() => {
|
|
1543
|
+
hiddenIframe.contentWindow?.print();
|
|
1544
|
+
setTimeout(() => {
|
|
1545
|
+
hiddenIframe.remove();
|
|
1546
|
+
URL.revokeObjectURL(url);
|
|
1547
|
+
}, 1e3);
|
|
1548
|
+
}, 300);
|
|
1549
|
+
};
|
|
1405
1550
|
},
|
|
1406
1551
|
getThumbnails: async () => {
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1552
|
+
const thumbnails = [];
|
|
1553
|
+
const count = Math.min(totalPages, 50);
|
|
1554
|
+
for (let i = 1; i <= count; i++) {
|
|
1555
|
+
thumbnails.push({
|
|
1556
|
+
index: i,
|
|
1557
|
+
label: `Page ${i}`,
|
|
1558
|
+
render: async (thumbCanvas) => {
|
|
1559
|
+
try {
|
|
1560
|
+
const p = await pdfDoc.getPage(i);
|
|
1561
|
+
const baseVp = p.getViewport({ scale: 1 });
|
|
1562
|
+
const thumbScale = (thumbCanvas.width || 120) / baseVp.width;
|
|
1563
|
+
const thumbVp = p.getViewport({ scale: thumbScale });
|
|
1564
|
+
thumbCanvas.height = Math.floor(thumbVp.height);
|
|
1565
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
1566
|
+
if (tCtx) {
|
|
1567
|
+
await p.render({ canvasContext: tCtx, viewport: thumbVp }).promise;
|
|
1568
|
+
}
|
|
1569
|
+
} catch (e) {
|
|
1570
|
+
console.warn(`[PdfPlugin] Error generating thumbnail for page ${i}:`, e);
|
|
1419
1571
|
}
|
|
1420
1572
|
}
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1573
|
+
});
|
|
1574
|
+
}
|
|
1575
|
+
return thumbnails;
|
|
1423
1576
|
}
|
|
1424
1577
|
};
|
|
1578
|
+
return instance;
|
|
1425
1579
|
}
|
|
1426
1580
|
};
|
|
1427
1581
|
function pdfPlugin() {
|
|
@@ -1748,7 +1902,31 @@ var DocxPlugin = class {
|
|
|
1748
1902
|
return this.mimeTypes.includes(mime || "");
|
|
1749
1903
|
}
|
|
1750
1904
|
getToolbarActions(instance) {
|
|
1751
|
-
|
|
1905
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
1906
|
+
const actions = [];
|
|
1907
|
+
if (totalPages > 1) {
|
|
1908
|
+
actions.push({
|
|
1909
|
+
id: "page-nav",
|
|
1910
|
+
icon: "",
|
|
1911
|
+
label: "Page Navigation",
|
|
1912
|
+
type: "page-nav",
|
|
1913
|
+
group: "navigation",
|
|
1914
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
1915
|
+
max: totalPages,
|
|
1916
|
+
execute: (action, page) => {
|
|
1917
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
1918
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
1919
|
+
if (action === "prev") {
|
|
1920
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
1921
|
+
} else if (action === "next") {
|
|
1922
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
1923
|
+
} else if (typeof page === "number") {
|
|
1924
|
+
instance.goToPage?.(page);
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
actions.push(
|
|
1752
1930
|
{
|
|
1753
1931
|
id: "zoom-out",
|
|
1754
1932
|
icon: "zoom-out",
|
|
@@ -1789,7 +1967,8 @@ var DocxPlugin = class {
|
|
|
1789
1967
|
group: "actions",
|
|
1790
1968
|
execute: () => instance.print?.()
|
|
1791
1969
|
}
|
|
1792
|
-
|
|
1970
|
+
);
|
|
1971
|
+
return actions;
|
|
1793
1972
|
}
|
|
1794
1973
|
async render(ctx) {
|
|
1795
1974
|
const wrapper = document.createElement("div");
|
|
@@ -1865,7 +2044,51 @@ var DocxPlugin = class {
|
|
|
1865
2044
|
}
|
|
1866
2045
|
}
|
|
1867
2046
|
}
|
|
2047
|
+
const sections = wrapper.querySelectorAll("section.docx");
|
|
2048
|
+
const cards = wrapper.querySelectorAll(".fp-docx-page-card");
|
|
2049
|
+
const pageElements = sections.length > 0 ? sections : cards;
|
|
2050
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
2051
|
+
let currentPage = 1;
|
|
2052
|
+
let indicator = null;
|
|
2053
|
+
if (totalPages > 1) {
|
|
2054
|
+
indicator = document.createElement("div");
|
|
2055
|
+
indicator.className = "fp-docx-page-indicator";
|
|
2056
|
+
indicator.style.position = "sticky";
|
|
2057
|
+
indicator.style.bottom = "16px";
|
|
2058
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2059
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2060
|
+
indicator.style.color = "#f8fafc";
|
|
2061
|
+
indicator.style.fontSize = "12px";
|
|
2062
|
+
indicator.style.fontWeight = "600";
|
|
2063
|
+
indicator.style.padding = "5px 14px";
|
|
2064
|
+
indicator.style.borderRadius = "20px";
|
|
2065
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2066
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2067
|
+
indicator.style.zIndex = "10";
|
|
2068
|
+
indicator.style.userSelect = "none";
|
|
2069
|
+
indicator.style.pointerEvents = "none";
|
|
2070
|
+
indicator.style.textAlign = "center";
|
|
2071
|
+
indicator.style.width = "fit-content";
|
|
2072
|
+
indicator.style.margin = "16px auto 0";
|
|
2073
|
+
ctx.container.appendChild(indicator);
|
|
2074
|
+
}
|
|
2075
|
+
const showPage = (pageNum) => {
|
|
2076
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2077
|
+
if (pageElements.length > 1) {
|
|
2078
|
+
pageElements.forEach((sec, idx) => {
|
|
2079
|
+
sec.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
2080
|
+
});
|
|
2081
|
+
}
|
|
2082
|
+
if (indicator) {
|
|
2083
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2084
|
+
}
|
|
2085
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2086
|
+
};
|
|
2087
|
+
if (totalPages > 1) {
|
|
2088
|
+
showPage(1);
|
|
2089
|
+
}
|
|
1868
2090
|
const cleanup = () => {
|
|
2091
|
+
indicator?.remove();
|
|
1869
2092
|
for (const url of createdBlobUrls) {
|
|
1870
2093
|
URL.revokeObjectURL(url);
|
|
1871
2094
|
}
|
|
@@ -1876,6 +2099,11 @@ var DocxPlugin = class {
|
|
|
1876
2099
|
ctx.signal.addEventListener("abort", cleanup);
|
|
1877
2100
|
return {
|
|
1878
2101
|
destroy: cleanup,
|
|
2102
|
+
getPageCount: () => totalPages,
|
|
2103
|
+
getCurrentPage: () => currentPage,
|
|
2104
|
+
goToPage: (page) => {
|
|
2105
|
+
showPage(page);
|
|
2106
|
+
},
|
|
1879
2107
|
zoomIn: () => {
|
|
1880
2108
|
scale += 0.1;
|
|
1881
2109
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -2140,7 +2368,31 @@ var ExcelPlugin = class {
|
|
|
2140
2368
|
return this.mimeTypes.includes(mime || "");
|
|
2141
2369
|
}
|
|
2142
2370
|
getToolbarActions(instance) {
|
|
2143
|
-
|
|
2371
|
+
const totalSheets = instance.getPageCount?.() ?? 1;
|
|
2372
|
+
const actions = [];
|
|
2373
|
+
if (totalSheets > 1) {
|
|
2374
|
+
actions.push({
|
|
2375
|
+
id: "page-nav",
|
|
2376
|
+
icon: "",
|
|
2377
|
+
label: "Sheet Navigation",
|
|
2378
|
+
type: "page-nav",
|
|
2379
|
+
group: "navigation",
|
|
2380
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2381
|
+
max: totalSheets,
|
|
2382
|
+
execute: (action, sheet) => {
|
|
2383
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2384
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2385
|
+
if (action === "prev") {
|
|
2386
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2387
|
+
} else if (action === "next") {
|
|
2388
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2389
|
+
} else if (typeof sheet === "number") {
|
|
2390
|
+
instance.goToPage?.(sheet);
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
});
|
|
2394
|
+
}
|
|
2395
|
+
actions.push(
|
|
2144
2396
|
{
|
|
2145
2397
|
id: "zoom-out",
|
|
2146
2398
|
icon: "zoom-out",
|
|
@@ -2161,16 +2413,6 @@ var ExcelPlugin = class {
|
|
|
2161
2413
|
instance.zoomIn?.();
|
|
2162
2414
|
}
|
|
2163
2415
|
},
|
|
2164
|
-
{
|
|
2165
|
-
id: "page-nav",
|
|
2166
|
-
icon: "page-nav",
|
|
2167
|
-
label: "Sheet Navigation",
|
|
2168
|
-
type: "page-nav",
|
|
2169
|
-
group: "navigation",
|
|
2170
|
-
execute: (sheet) => {
|
|
2171
|
-
if (typeof sheet === "number") instance.goToPage?.(sheet);
|
|
2172
|
-
}
|
|
2173
|
-
},
|
|
2174
2416
|
{
|
|
2175
2417
|
id: "download",
|
|
2176
2418
|
icon: "download",
|
|
@@ -2191,7 +2433,8 @@ var ExcelPlugin = class {
|
|
|
2191
2433
|
instance.print?.();
|
|
2192
2434
|
}
|
|
2193
2435
|
}
|
|
2194
|
-
|
|
2436
|
+
);
|
|
2437
|
+
return actions;
|
|
2195
2438
|
}
|
|
2196
2439
|
async render(ctx) {
|
|
2197
2440
|
const container = document.createElement("div");
|
|
@@ -2275,6 +2518,7 @@ var ExcelPlugin = class {
|
|
|
2275
2518
|
b.style.fontWeight = "normal";
|
|
2276
2519
|
}
|
|
2277
2520
|
});
|
|
2521
|
+
ctx.emit("page-change", { page: currentSheetIndex, total: sheetNames.length });
|
|
2278
2522
|
};
|
|
2279
2523
|
if (sheetNames.length > 0) {
|
|
2280
2524
|
sheetNames.forEach((name, idx) => {
|
|
@@ -2524,7 +2768,31 @@ var CodePlugin = class {
|
|
|
2524
2768
|
return false;
|
|
2525
2769
|
}
|
|
2526
2770
|
getToolbarActions(instance) {
|
|
2527
|
-
|
|
2771
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
2772
|
+
const actions = [];
|
|
2773
|
+
if (totalPages > 1) {
|
|
2774
|
+
actions.push({
|
|
2775
|
+
id: "page-nav",
|
|
2776
|
+
icon: "",
|
|
2777
|
+
label: "Page Navigation",
|
|
2778
|
+
type: "page-nav",
|
|
2779
|
+
group: "navigation",
|
|
2780
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
2781
|
+
max: totalPages,
|
|
2782
|
+
execute: (action, page) => {
|
|
2783
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
2784
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
2785
|
+
if (action === "prev") {
|
|
2786
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
2787
|
+
} else if (action === "next") {
|
|
2788
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
2789
|
+
} else if (typeof page === "number") {
|
|
2790
|
+
instance.goToPage?.(page);
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
});
|
|
2794
|
+
}
|
|
2795
|
+
actions.push(
|
|
2528
2796
|
{
|
|
2529
2797
|
id: "zoom-out",
|
|
2530
2798
|
icon: "zoom-out",
|
|
@@ -2575,11 +2843,16 @@ var CodePlugin = class {
|
|
|
2575
2843
|
instance.print?.();
|
|
2576
2844
|
}
|
|
2577
2845
|
}
|
|
2578
|
-
|
|
2846
|
+
);
|
|
2847
|
+
return actions;
|
|
2579
2848
|
}
|
|
2580
2849
|
async render(ctx) {
|
|
2581
2850
|
const decoder = new TextDecoder("utf-8");
|
|
2582
|
-
const
|
|
2851
|
+
const fullText = decoder.decode(ctx.buffer);
|
|
2852
|
+
const pageSplitRegex = /(?:\f|\x0C|(?:\r?\n|^)\s*[-=_]{3,}\s*(?:PAGE|Page|page break|Page Break)[\s\d\w-]*[-=_]{3,}\s*(?:\r?\n|$))/i;
|
|
2853
|
+
const rawPages = fullText.split(pageSplitRegex).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
2854
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
2855
|
+
let currentPage = 1;
|
|
2583
2856
|
const container = document.createElement("div");
|
|
2584
2857
|
container.style.width = "100%";
|
|
2585
2858
|
container.style.height = "100%";
|
|
@@ -2598,25 +2871,66 @@ var CodePlugin = class {
|
|
|
2598
2871
|
pre.style.wordBreak = "break-all";
|
|
2599
2872
|
const code = document.createElement("code");
|
|
2600
2873
|
const ext = (ctx.metadata.extension || "").replace(".", "");
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2874
|
+
const renderCodePage = (text) => {
|
|
2875
|
+
try {
|
|
2876
|
+
if (ext && hljs__default.default.getLanguage(ext)) {
|
|
2877
|
+
code.innerHTML = hljs__default.default.highlight(text, { language: ext }).value;
|
|
2878
|
+
} else {
|
|
2879
|
+
code.innerHTML = hljs__default.default.highlightAuto(text).value;
|
|
2880
|
+
}
|
|
2881
|
+
} catch {
|
|
2882
|
+
code.textContent = text;
|
|
2606
2883
|
}
|
|
2607
|
-
}
|
|
2608
|
-
|
|
2609
|
-
}
|
|
2884
|
+
};
|
|
2885
|
+
renderCodePage(rawPages[0] || fullText);
|
|
2610
2886
|
pre.appendChild(code);
|
|
2611
2887
|
container.appendChild(pre);
|
|
2888
|
+
let indicator = null;
|
|
2889
|
+
if (totalPages > 1) {
|
|
2890
|
+
indicator = document.createElement("div");
|
|
2891
|
+
indicator.className = "fp-code-page-indicator";
|
|
2892
|
+
indicator.style.position = "sticky";
|
|
2893
|
+
indicator.style.bottom = "16px";
|
|
2894
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
2895
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
2896
|
+
indicator.style.color = "#f8fafc";
|
|
2897
|
+
indicator.style.fontSize = "12px";
|
|
2898
|
+
indicator.style.fontWeight = "600";
|
|
2899
|
+
indicator.style.padding = "5px 14px";
|
|
2900
|
+
indicator.style.borderRadius = "20px";
|
|
2901
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
2902
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
2903
|
+
indicator.style.zIndex = "10";
|
|
2904
|
+
indicator.style.userSelect = "none";
|
|
2905
|
+
indicator.style.pointerEvents = "none";
|
|
2906
|
+
indicator.style.textAlign = "center";
|
|
2907
|
+
indicator.style.width = "fit-content";
|
|
2908
|
+
indicator.style.margin = "16px auto 0";
|
|
2909
|
+
container.appendChild(indicator);
|
|
2910
|
+
}
|
|
2911
|
+
const showPage = (pageNum) => {
|
|
2912
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
2913
|
+
renderCodePage(rawPages[currentPage - 1] || fullText);
|
|
2914
|
+
if (indicator) {
|
|
2915
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
2916
|
+
}
|
|
2917
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
2918
|
+
};
|
|
2919
|
+
if (totalPages > 1) {
|
|
2920
|
+
showPage(1);
|
|
2921
|
+
}
|
|
2612
2922
|
ctx.container.appendChild(container);
|
|
2613
2923
|
const cleanup = () => {
|
|
2924
|
+
indicator?.remove();
|
|
2614
2925
|
container.remove();
|
|
2615
2926
|
ctx.container.innerHTML = "";
|
|
2616
2927
|
};
|
|
2617
2928
|
ctx.signal.addEventListener("abort", cleanup);
|
|
2618
2929
|
return {
|
|
2619
2930
|
destroy: cleanup,
|
|
2931
|
+
getPageCount: () => totalPages,
|
|
2932
|
+
getCurrentPage: () => currentPage,
|
|
2933
|
+
goToPage: (page) => showPage(page),
|
|
2620
2934
|
zoomIn: () => {
|
|
2621
2935
|
fontSize = Math.min(32, fontSize + 2);
|
|
2622
2936
|
pre.style.fontSize = `${fontSize}px`;
|
|
@@ -2644,7 +2958,7 @@ var CodePlugin = class {
|
|
|
2644
2958
|
window.print();
|
|
2645
2959
|
},
|
|
2646
2960
|
copy: () => {
|
|
2647
|
-
navigator.clipboard?.writeText(
|
|
2961
|
+
navigator.clipboard?.writeText(fullText);
|
|
2648
2962
|
}
|
|
2649
2963
|
};
|
|
2650
2964
|
}
|
|
@@ -3466,7 +3780,31 @@ var RtfPlugin = class {
|
|
|
3466
3780
|
return this.extensions.includes(ext || "") || this.mimeTypes.includes(mime || "");
|
|
3467
3781
|
}
|
|
3468
3782
|
getToolbarActions(instance) {
|
|
3469
|
-
|
|
3783
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3784
|
+
const actions = [];
|
|
3785
|
+
if (totalPages > 1) {
|
|
3786
|
+
actions.push({
|
|
3787
|
+
id: "page-nav",
|
|
3788
|
+
icon: "",
|
|
3789
|
+
label: "Page Navigation",
|
|
3790
|
+
type: "page-nav",
|
|
3791
|
+
group: "navigation",
|
|
3792
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
3793
|
+
max: totalPages,
|
|
3794
|
+
execute: (action, page) => {
|
|
3795
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
3796
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
3797
|
+
if (action === "prev") {
|
|
3798
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
3799
|
+
} else if (action === "next") {
|
|
3800
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
3801
|
+
} else if (typeof page === "number") {
|
|
3802
|
+
instance.goToPage?.(page);
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
});
|
|
3806
|
+
}
|
|
3807
|
+
actions.push(
|
|
3470
3808
|
{
|
|
3471
3809
|
id: "zoom-out",
|
|
3472
3810
|
icon: "zoom-out",
|
|
@@ -3507,7 +3845,8 @@ var RtfPlugin = class {
|
|
|
3507
3845
|
group: "actions",
|
|
3508
3846
|
execute: () => instance.print?.()
|
|
3509
3847
|
}
|
|
3510
|
-
|
|
3848
|
+
);
|
|
3849
|
+
return actions;
|
|
3511
3850
|
}
|
|
3512
3851
|
async render(ctx) {
|
|
3513
3852
|
const wrapper = document.createElement("div");
|
|
@@ -3526,28 +3865,82 @@ var RtfPlugin = class {
|
|
|
3526
3865
|
ctx.container.style.backgroundColor = "#f1f5f9";
|
|
3527
3866
|
ctx.container.appendChild(wrapper);
|
|
3528
3867
|
let scale = 1;
|
|
3868
|
+
let pageElements = [];
|
|
3529
3869
|
try {
|
|
3530
3870
|
if (typeof RTFJS__namespace.loggingEnabled === "function") {
|
|
3531
3871
|
RTFJS__namespace.loggingEnabled(false);
|
|
3532
3872
|
}
|
|
3533
3873
|
const doc = new RTFJS__namespace.Document(ctx.buffer, {});
|
|
3534
3874
|
const htmlElements = await doc.render();
|
|
3535
|
-
|
|
3875
|
+
pageElements = htmlElements;
|
|
3876
|
+
for (let i = 0; i < htmlElements.length; i++) {
|
|
3877
|
+
const el = htmlElements[i];
|
|
3878
|
+
el.style.display = i === 0 ? "block" : "none";
|
|
3536
3879
|
wrapper.appendChild(el);
|
|
3537
3880
|
}
|
|
3538
3881
|
} catch (err) {
|
|
3539
3882
|
console.warn("[RtfPlugin] RTF render error, fallback text:", err);
|
|
3540
3883
|
const text = new TextDecoder("latin1").decode(ctx.buffer);
|
|
3541
3884
|
const clean = text.replace(/\\par[d]?/g, "\n").replace(/\\[a-zA-Z0-9\-]+/g, "").replace(/[{}]/g, "");
|
|
3542
|
-
|
|
3885
|
+
const pre = document.createElement("pre");
|
|
3886
|
+
pre.style.whiteSpace = "pre-wrap";
|
|
3887
|
+
pre.style.fontFamily = "serif";
|
|
3888
|
+
pre.style.color = "#333";
|
|
3889
|
+
pre.textContent = clean;
|
|
3890
|
+
wrapper.appendChild(pre);
|
|
3891
|
+
pageElements = [pre];
|
|
3892
|
+
}
|
|
3893
|
+
const totalPages = Math.max(1, pageElements.length);
|
|
3894
|
+
let currentPage = 1;
|
|
3895
|
+
let indicator = null;
|
|
3896
|
+
if (totalPages > 1) {
|
|
3897
|
+
indicator = document.createElement("div");
|
|
3898
|
+
indicator.className = "fp-rtf-page-indicator";
|
|
3899
|
+
indicator.style.position = "sticky";
|
|
3900
|
+
indicator.style.bottom = "16px";
|
|
3901
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
3902
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
3903
|
+
indicator.style.color = "#f8fafc";
|
|
3904
|
+
indicator.style.fontSize = "12px";
|
|
3905
|
+
indicator.style.fontWeight = "600";
|
|
3906
|
+
indicator.style.padding = "5px 14px";
|
|
3907
|
+
indicator.style.borderRadius = "20px";
|
|
3908
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
3909
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
3910
|
+
indicator.style.zIndex = "10";
|
|
3911
|
+
indicator.style.userSelect = "none";
|
|
3912
|
+
indicator.style.pointerEvents = "none";
|
|
3913
|
+
indicator.style.textAlign = "center";
|
|
3914
|
+
indicator.style.width = "fit-content";
|
|
3915
|
+
indicator.style.margin = "16px auto 0";
|
|
3916
|
+
ctx.container.appendChild(indicator);
|
|
3917
|
+
}
|
|
3918
|
+
const showPage = (pageNum) => {
|
|
3919
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
3920
|
+
if (totalPages > 1) {
|
|
3921
|
+
pageElements.forEach((el, idx) => {
|
|
3922
|
+
el.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
3923
|
+
});
|
|
3924
|
+
}
|
|
3925
|
+
if (indicator) {
|
|
3926
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
3927
|
+
}
|
|
3928
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
3929
|
+
};
|
|
3930
|
+
if (totalPages > 1) {
|
|
3931
|
+
showPage(1);
|
|
3543
3932
|
}
|
|
3544
3933
|
const cleanup = () => {
|
|
3934
|
+
indicator?.remove();
|
|
3545
3935
|
wrapper.remove();
|
|
3546
3936
|
ctx.container.innerHTML = "";
|
|
3547
3937
|
};
|
|
3548
3938
|
ctx.signal.addEventListener("abort", cleanup);
|
|
3549
3939
|
return {
|
|
3550
3940
|
destroy: cleanup,
|
|
3941
|
+
getPageCount: () => totalPages,
|
|
3942
|
+
getCurrentPage: () => currentPage,
|
|
3943
|
+
goToPage: (page) => showPage(page),
|
|
3551
3944
|
zoomIn: () => {
|
|
3552
3945
|
scale += 0.1;
|
|
3553
3946
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -3735,41 +4128,41 @@ var OpenDocumentPlugin = class {
|
|
|
3735
4128
|
}
|
|
3736
4129
|
getToolbarActions(instance) {
|
|
3737
4130
|
const isPresentation = instance.isPresentation;
|
|
4131
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
3738
4132
|
const actions = [];
|
|
3739
|
-
if (isPresentation) {
|
|
3740
|
-
|
|
3741
|
-
{
|
|
4133
|
+
if (isPresentation || totalPages > 1) {
|
|
4134
|
+
if (isPresentation) {
|
|
4135
|
+
actions.push({
|
|
3742
4136
|
id: "thumbnails",
|
|
3743
4137
|
icon: "thumbnails",
|
|
3744
4138
|
label: "Slide Thumbnails",
|
|
3745
4139
|
type: "button",
|
|
3746
4140
|
group: "navigation",
|
|
3747
4141
|
execute: () => instance.toggleThumbnails?.()
|
|
3748
|
-
}
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
}
|
|
4142
|
+
});
|
|
4143
|
+
}
|
|
4144
|
+
actions.push({
|
|
4145
|
+
id: "page-nav",
|
|
4146
|
+
icon: "",
|
|
4147
|
+
label: isPresentation ? "Slide Navigation" : "Page Navigation",
|
|
4148
|
+
type: "page-nav",
|
|
4149
|
+
group: "navigation",
|
|
4150
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4151
|
+
max: totalPages,
|
|
4152
|
+
execute: (action, page) => {
|
|
4153
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4154
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4155
|
+
if (action === "prev") {
|
|
4156
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4157
|
+
} else if (action === "next") {
|
|
4158
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4159
|
+
} else if (typeof page === "number") {
|
|
4160
|
+
instance.goToPage?.(page);
|
|
4161
|
+
} else if (typeof action === "number") {
|
|
4162
|
+
instance.goToPage?.(action);
|
|
3770
4163
|
}
|
|
3771
4164
|
}
|
|
3772
|
-
);
|
|
4165
|
+
});
|
|
3773
4166
|
}
|
|
3774
4167
|
actions.push(
|
|
3775
4168
|
{
|
|
@@ -4152,7 +4545,31 @@ var DocPlugin = class {
|
|
|
4152
4545
|
return this.mimeTypes.includes(mime || "");
|
|
4153
4546
|
}
|
|
4154
4547
|
getToolbarActions(instance) {
|
|
4155
|
-
|
|
4548
|
+
const totalPages = instance.getPageCount?.() ?? 1;
|
|
4549
|
+
const actions = [];
|
|
4550
|
+
if (totalPages > 1) {
|
|
4551
|
+
actions.push({
|
|
4552
|
+
id: "page-nav",
|
|
4553
|
+
icon: "",
|
|
4554
|
+
label: "Page Navigation",
|
|
4555
|
+
type: "page-nav",
|
|
4556
|
+
group: "navigation",
|
|
4557
|
+
value: instance.getCurrentPage?.() ?? 1,
|
|
4558
|
+
max: totalPages,
|
|
4559
|
+
execute: (action, page) => {
|
|
4560
|
+
const cur = instance.getCurrentPage?.() ?? 1;
|
|
4561
|
+
const max = instance.getPageCount?.() ?? 1;
|
|
4562
|
+
if (action === "prev") {
|
|
4563
|
+
if (cur > 1) instance.goToPage?.(cur - 1);
|
|
4564
|
+
} else if (action === "next") {
|
|
4565
|
+
if (cur < max) instance.goToPage?.(cur + 1);
|
|
4566
|
+
} else if (typeof page === "number") {
|
|
4567
|
+
instance.goToPage?.(page);
|
|
4568
|
+
}
|
|
4569
|
+
}
|
|
4570
|
+
});
|
|
4571
|
+
}
|
|
4572
|
+
actions.push(
|
|
4156
4573
|
{
|
|
4157
4574
|
id: "zoom-out",
|
|
4158
4575
|
icon: "zoom-out",
|
|
@@ -4201,7 +4618,8 @@ var DocPlugin = class {
|
|
|
4201
4618
|
group: "actions",
|
|
4202
4619
|
execute: () => instance.print?.()
|
|
4203
4620
|
}
|
|
4204
|
-
|
|
4621
|
+
);
|
|
4622
|
+
return actions;
|
|
4205
4623
|
}
|
|
4206
4624
|
async render(ctx) {
|
|
4207
4625
|
const container = document.createElement("div");
|
|
@@ -4228,6 +4646,7 @@ var DocPlugin = class {
|
|
|
4228
4646
|
ctx.container.appendChild(container);
|
|
4229
4647
|
let scale = 1;
|
|
4230
4648
|
let extractedRawText = "";
|
|
4649
|
+
let isFallback = false;
|
|
4231
4650
|
try {
|
|
4232
4651
|
const cfbf = new CfbfReader(ctx.buffer);
|
|
4233
4652
|
const wordDocStream = cfbf.readStream("WordDocument");
|
|
@@ -4241,26 +4660,89 @@ var DocPlugin = class {
|
|
|
4241
4660
|
const tableStream = cfbf.readStream(tableName);
|
|
4242
4661
|
const text = this.extractDocText(wordDocStream, tableStream);
|
|
4243
4662
|
extractedRawText = text;
|
|
4244
|
-
wrapper.innerHTML = this.formatDocToHtml(text, ctx.metadata.name || "Document");
|
|
4245
4663
|
} catch (err) {
|
|
4246
4664
|
console.warn("[DocPlugin] Binary parsing error, fallback text:", err);
|
|
4247
4665
|
const fallback = this.heuristicTextExtraction(ctx.buffer);
|
|
4248
4666
|
extractedRawText = fallback;
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4667
|
+
isFallback = true;
|
|
4668
|
+
}
|
|
4669
|
+
const rawPages = this.splitIntoPages(extractedRawText);
|
|
4670
|
+
const totalPages = Math.max(1, rawPages.length);
|
|
4671
|
+
let currentPage = 1;
|
|
4672
|
+
wrapper.innerHTML = "";
|
|
4673
|
+
const pageCards = [];
|
|
4674
|
+
for (let i = 0; i < totalPages; i++) {
|
|
4675
|
+
const pageCard = document.createElement("div");
|
|
4676
|
+
pageCard.className = "fp-doc-page-card";
|
|
4677
|
+
pageCard.style.backgroundColor = "#ffffff";
|
|
4678
|
+
pageCard.style.boxShadow = "0 2px 12px rgba(0,0,0,0.08)";
|
|
4679
|
+
pageCard.style.borderRadius = "4px";
|
|
4680
|
+
pageCard.style.padding = "56px 48px";
|
|
4681
|
+
pageCard.style.minHeight = "100%";
|
|
4682
|
+
pageCard.style.display = i === 0 ? "block" : "none";
|
|
4683
|
+
if (isFallback && i === 0) {
|
|
4684
|
+
pageCard.innerHTML = `
|
|
4685
|
+
<div style="border-bottom: 1px solid #e2e8f0; padding-bottom: 12px; margin-bottom: 24px;">
|
|
4686
|
+
<h2 style="margin: 0 0 6px; font-size: 20px; color: #334155;">${DOMPurify2__default.default.sanitize(ctx.metadata.name || "Word Document (.doc)")}</h2>
|
|
4687
|
+
<span style="font-size: 12px; color: #64748b; background: #f1f5f9; padding: 2px 8px; border-radius: 4px;">Legacy Word 97-2003 Binary Preview</span>
|
|
4688
|
+
</div>
|
|
4689
|
+
${this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document")}
|
|
4690
|
+
`;
|
|
4691
|
+
} else {
|
|
4692
|
+
pageCard.innerHTML = this.formatDocToHtml(rawPages[i], ctx.metadata.name || "Document");
|
|
4693
|
+
}
|
|
4694
|
+
wrapper.appendChild(pageCard);
|
|
4695
|
+
pageCards.push(pageCard);
|
|
4696
|
+
}
|
|
4697
|
+
let indicator = null;
|
|
4698
|
+
if (totalPages > 1) {
|
|
4699
|
+
indicator = document.createElement("div");
|
|
4700
|
+
indicator.className = "fp-doc-page-indicator";
|
|
4701
|
+
indicator.style.position = "sticky";
|
|
4702
|
+
indicator.style.bottom = "16px";
|
|
4703
|
+
indicator.style.backgroundColor = "rgba(15, 23, 42, 0.85)";
|
|
4704
|
+
indicator.style.backdropFilter = "blur(8px)";
|
|
4705
|
+
indicator.style.color = "#f8fafc";
|
|
4706
|
+
indicator.style.fontSize = "12px";
|
|
4707
|
+
indicator.style.fontWeight = "600";
|
|
4708
|
+
indicator.style.padding = "5px 14px";
|
|
4709
|
+
indicator.style.borderRadius = "20px";
|
|
4710
|
+
indicator.style.border = "1px solid rgba(255, 255, 255, 0.15)";
|
|
4711
|
+
indicator.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.3)";
|
|
4712
|
+
indicator.style.zIndex = "10";
|
|
4713
|
+
indicator.style.userSelect = "none";
|
|
4714
|
+
indicator.style.pointerEvents = "none";
|
|
4715
|
+
indicator.style.textAlign = "center";
|
|
4716
|
+
indicator.style.width = "fit-content";
|
|
4717
|
+
indicator.style.margin = "16px auto 0";
|
|
4718
|
+
container.appendChild(indicator);
|
|
4719
|
+
}
|
|
4720
|
+
const showPage = (pageNum) => {
|
|
4721
|
+
currentPage = Math.max(1, Math.min(totalPages, pageNum));
|
|
4722
|
+
if (totalPages > 1) {
|
|
4723
|
+
pageCards.forEach((card, idx) => {
|
|
4724
|
+
card.style.display = idx + 1 === currentPage ? "block" : "none";
|
|
4725
|
+
});
|
|
4726
|
+
}
|
|
4727
|
+
if (indicator) {
|
|
4728
|
+
indicator.textContent = `Page ${currentPage} of ${totalPages}`;
|
|
4729
|
+
}
|
|
4730
|
+
ctx.emit("page-change", { page: currentPage, total: totalPages });
|
|
4731
|
+
};
|
|
4732
|
+
if (totalPages > 1) {
|
|
4733
|
+
showPage(1);
|
|
4256
4734
|
}
|
|
4257
4735
|
const cleanup = () => {
|
|
4736
|
+
indicator?.remove();
|
|
4258
4737
|
container.remove();
|
|
4259
4738
|
ctx.container.innerHTML = "";
|
|
4260
4739
|
};
|
|
4261
4740
|
ctx.signal.addEventListener("abort", cleanup);
|
|
4262
4741
|
return {
|
|
4263
4742
|
destroy: cleanup,
|
|
4743
|
+
getPageCount: () => totalPages,
|
|
4744
|
+
getCurrentPage: () => currentPage,
|
|
4745
|
+
goToPage: (page) => showPage(page),
|
|
4264
4746
|
zoomIn: () => {
|
|
4265
4747
|
scale += 0.1;
|
|
4266
4748
|
wrapper.style.transform = `scale(${scale})`;
|
|
@@ -4392,11 +4874,16 @@ var DocPlugin = class {
|
|
|
4392
4874
|
heuristicTextExtraction(buffer) {
|
|
4393
4875
|
return this.extractStringsFromBytes(new Uint8Array(buffer));
|
|
4394
4876
|
}
|
|
4877
|
+
splitIntoPages(text) {
|
|
4878
|
+
if (!text) return [""];
|
|
4879
|
+
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);
|
|
4880
|
+
return parts.length > 0 ? parts : [text];
|
|
4881
|
+
}
|
|
4395
4882
|
/**
|
|
4396
4883
|
* Format cleaned extracted text into attractive HTML paragraphs, headings, and lists
|
|
4397
4884
|
*/
|
|
4398
4885
|
formatDocToHtml(text, filename) {
|
|
4399
|
-
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").
|
|
4886
|
+
const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\x0B/g, "\n").split("\n");
|
|
4400
4887
|
let html = "";
|
|
4401
4888
|
let inList = false;
|
|
4402
4889
|
for (const rawLine of lines) {
|